/* */ #include "MessageDigestImpl.h" #include #include "fmt.h" #include "DlAbortEx.h" #include "LogFactory.h" namespace { using namespace aria2; class Context { private: HCRYPTPROV provider_; public: Context() { if (!::CryptAcquireContext(&provider_, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { if (!::CryptAcquireContext(&provider_, nullptr, nullptr, PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) { throw DL_ABORT_EX("Failed to get cryptographic provider"); } } } ~Context() { ::CryptReleaseContext(provider_, 0); } HCRYPTPROV get() { return provider_; } }; // XXX static OK? static Context context_; inline size_t getAlgLength(ALG_ID id) { Context context; HCRYPTHASH hash; if (!::CryptCreateHash(context.get(), id, 0, 0, &hash)) { throw DL_ABORT_EX(fmt("Failed to initialize hash %d", id)); } DWORD rv = 0; DWORD len = sizeof(rv); if (!::CryptGetHashParam(hash, HP_HASHSIZE, reinterpret_cast(&rv), &len, 0)) { throw DL_ABORT_EX("Failed to initialize hash(2)"); } ::CryptDestroyHash(hash); return rv; } } // namespace namespace aria2 { template class MessageDigestBase : public MessageDigestImpl { private: HCRYPTHASH hash_; DWORD len_; void destroy() { if (hash_) { ::CryptDestroyHash(hash_); hash_ = 0; } } public: MessageDigestBase() : hash_(0), len_(0) { reset(); } virtual ~MessageDigestBase() { destroy(); } static size_t length() { MessageDigestBase rv; return rv.getDigestLength(); } virtual size_t getDigestLength() const CXX11_OVERRIDE { return len_; } virtual void reset() CXX11_OVERRIDE { destroy(); if (!::CryptCreateHash(context_.get(), id, 0, 0, &hash_)) { throw DL_ABORT_EX("Failed to create hash"); } DWORD len = sizeof(len_); if (!::CryptGetHashParam(hash_, HP_HASHSIZE, reinterpret_cast(&len_), &len, 0)) { throw DL_ABORT_EX("Failed to initialize hash"); } } virtual void update(const void* data, size_t length) CXX11_OVERRIDE { auto bytes = reinterpret_cast(data); while (length) { DWORD l = std::min(length, (size_t)std::numeric_limits::max()); if (!::CryptHashData(hash_, bytes, l, 0)) { throw DL_ABORT_EX("Failed to update hash"); } length -= l; bytes += l; } } virtual void digest(unsigned char* md) CXX11_OVERRIDE { DWORD len = len_; if (!::CryptGetHashParam(hash_, HP_HASHVAL, md, &len, 0)) { throw DL_ABORT_EX("Failed to create hash digest"); } } }; typedef MessageDigestBase MessageDigestMD5; typedef MessageDigestBase MessageDigestSHA1; typedef MessageDigestBase MessageDigestSHA256; typedef MessageDigestBase MessageDigestSHA384; typedef MessageDigestBase MessageDigestSHA512; std::unique_ptr MessageDigestImpl::sha1() { return std::unique_ptr(new MessageDigestSHA1()); } namespace { MessageDigestImpl::hashes_t initialize() { MessageDigestImpl::hashes_t rv = { { "sha-1", MessageDigestImpl::make_hi() }, { "md5", MessageDigestImpl::make_hi() }, }; try { rv.insert({ "sha-256", MessageDigestImpl::make_hi() }); } catch (RecoverableException &ex) { printf("SHA-256 is not supported on this machine"); } try { rv.insert({ "sha-384", MessageDigestImpl::make_hi() }); } catch (RecoverableException &ex) { printf("SHA-384 is not supported on this machine"); } try { rv.insert({ "sha-512", MessageDigestImpl::make_hi() }); } catch (RecoverableException &ex) { printf("SHA-512 is not supported on this machine"); } return rv; }; } // namespace MessageDigestImpl::hashes_t MessageDigestImpl::hashes = initialize(); } // namespace aria2