commit 258058688c09a819fd67761000ca6975d83598a6
parent 4594e1fe2021e5e506c0a881b9921c585f72f75b
Author: cfillion <cfillion@users.noreply.github.com>
Date: Wed, 5 Dec 2018 18:32:38 -0800
implement SHA256 on Windows
https://docs.microsoft.com/en-us/windows/desktop/seccng/creating-a-hash-with-cng
Diffstat:
3 files changed, 84 insertions(+), 13 deletions(-)
diff --git a/src/hash.cpp b/src/hash.cpp
@@ -3,35 +3,103 @@
#include <cstdio>
#include <vector>
-#ifdef __APPLE__
-# include <CommonCrypto/CommonDigest.h>
-# define CC(s) CC_##s
-#else
-# include <openssl/sha.h>
-# define CC(s) s
-#endif
+#ifdef _WIN32
+
+# include <windows.h>
+
+class Hash::CNGContext : public Hash::Context {
+public:
+ CNGContext(const Algorithm algo) : m_algo(), m_hash(), m_hashLength() {
+ const wchar_t *algoName;
+
+ switch(algo) {
+ case SHA256:
+ algoName = BCRYPT_SHA256_ALGORITHM;
+ break;
+ default:
+ return;
+ }
+
+ BCryptOpenAlgorithmProvider(&m_algo, algoName,
+ MS_PRIMITIVE_PROVIDER, 0);
+
+ unsigned long bytesWritten;
+ BCryptGetProperty(m_algo, BCRYPT_HASH_LENGTH,
+ reinterpret_cast<PUCHAR>(&m_hashLength), sizeof(m_hashLength),
+ &bytesWritten, 0);
+
+ BCryptCreateHash(m_algo, &m_hash, nullptr, 0, nullptr, 0, 0);
+ }
+
+ ~CNGContext() override {
+ if(m_algo)
+ BCryptCloseAlgorithmProvider(m_algo, 0);
+ if(m_hash)
+ BCryptDestroyHash(m_hash);
+ }
+
+ size_t hashSize() const override { return m_hashLength; }
+
+ void addData(const char *data, const size_t len) override {
+ BCryptHashData(m_hash,
+ reinterpret_cast<unsigned char *>(const_cast<char *>(data)),
+ static_cast<unsigned long>(len), 0);
+ }
+
+ void getHash(unsigned char *out) {
+ BCryptFinishHash(m_hash, out, m_hashLength, 0);
+ }
+
+private:
+ BCRYPT_ALG_HANDLE m_algo;
+ BCRYPT_HASH_HANDLE m_hash;
+ unsigned long m_hashLength;
+};
+
+#else // Unix systems
+
+# ifdef __APPLE__
+# include <CommonCrypto/CommonDigest.h>
+# define CC(s) CC_##s
+# else
+# include <openssl/sha.h>
+# define CC(s) s
+# endif
class Hash::SHA256Context : public Hash::Context {
public:
SHA256Context() { CC(SHA256_Init)(&m_context); }
- size_t hashSize() const { return CC(SHA256_DIGEST_LENGTH); }
- void addData(const char *data, const size_t len) {
+
+ size_t hashSize() const override {
+ return CC(SHA256_DIGEST_LENGTH);
+ }
+
+ void addData(const char *data, const size_t len) override {
CC(SHA256_Update)(&m_context, data, len);
}
- void getHash(unsigned char *out) { CC(SHA256_Final)(out, &m_context); }
+
+ void getHash(unsigned char *out) override {
+ CC(SHA256_Final)(out, &m_context);
+ }
private:
CC(SHA256_CTX) m_context;
};
+#endif
+
Hash::Hash(const Algorithm algo)
: m_algo(algo)
{
+#ifdef _WIN32
+ m_context = std::make_unique<CNGContext>(algo);
+#else
switch(algo) {
case SHA256:
m_context = std::make_unique<SHA256Context>();
break;
}
+#endif
}
void Hash::write(const char *data, const size_t len)
@@ -45,11 +113,13 @@ const std::string &Hash::digest()
if(!m_context || !m_value.empty())
return m_value;
+ // Assuming m_algo and hashSize can fit in one byte. We'll need to implement
+ // multihash's varint if we need larger values in the future.
const size_t hashSize = m_context->hashSize();
std::vector<unsigned char> multihash(2 + hashSize);
multihash[0] = m_algo;
- multihash[1] = hashSize;
+ multihash[1] = static_cast<unsigned char>(hashSize);
m_context->getHash(&multihash[2]);
m_value.resize(multihash.size() * 2);
diff --git a/src/hash.hpp b/src/hash.hpp
@@ -19,10 +19,11 @@ private:
public:
virtual ~Context() = default;
virtual size_t hashSize() const = 0;
- virtual void addData(const char *data, const size_t len) = 0;
+ virtual void addData(const char *data, size_t len) = 0;
virtual void getHash(unsigned char *out) = 0;
};
+ class CNGContext;
class SHA256Context;
Algorithm m_algo;
diff --git a/win32.tup b/win32.tup
@@ -15,7 +15,7 @@ CXXFLAGS += /DWDL_NO_DEFINE_MINMAX /DCURL_STATICLIB /DUNICODE /DNDEBUG
CXXFLAGS += /DREAPACK_FILE#\"$(REAPACK_FILE).dll\"
LD := $(WRAP) link
-LDFLAGS := /nologo User32.lib Shell32.lib Gdi32.lib Comdlg32.lib Comctl32.lib
+LDFLAGS := /nologo User32.lib Shell32.lib Gdi32.lib Comdlg32.lib Comctl32.lib Bcrypt.lib
LDFLAGS += $(VCPKG)/lib/libcurl.lib Ws2_32.lib Crypt32.lib Advapi32.lib
LDFLAGS += $(VCPKG)/lib/sqlite3.lib $(VCPKG)/lib/zlib.lib
LDFLAGS += $(TUP_VARIANTDIR)/src/resource.res