// See the file "COPYING" in the main distribution directory for copyright. /** * Wrapper and helper functions for MD5/SHA digest algorithms. */ #include "zeek/digest.h" #include #include #include #include "zeek/Reporter.h" #if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER) #define EVP_MD_CTX_new EVP_MD_CTX_create #define EVP_MD_CTX_free EVP_MD_CTX_destroy #endif static_assert(ZEEK_MD5_DIGEST_LENGTH == MD5_DIGEST_LENGTH); static_assert(ZEEK_SHA_DIGEST_LENGTH == SHA_DIGEST_LENGTH); static_assert(ZEEK_SHA224_DIGEST_LENGTH == SHA224_DIGEST_LENGTH); static_assert(ZEEK_SHA256_DIGEST_LENGTH == SHA256_DIGEST_LENGTH); static_assert(ZEEK_SHA384_DIGEST_LENGTH == SHA384_DIGEST_LENGTH); static_assert(ZEEK_SHA512_DIGEST_LENGTH == SHA512_DIGEST_LENGTH); namespace zeek::detail { namespace { auto* to_native_ptr(HashDigestState* ptr) { return reinterpret_cast(ptr); } auto* to_native_ptr(const HashDigestState* ptr) { return reinterpret_cast(ptr); } auto* to_opaque_ptr(EVP_MD_CTX* ptr) { return reinterpret_cast(ptr); } } // namespace HashDigestState* hash_init(HashAlgorithm alg) { EVP_MD_CTX* c = EVP_MD_CTX_new(); const EVP_MD* md; switch ( alg ) { case Hash_MD5: #ifdef EVP_MD_CTX_FLAG_NON_FIPS_ALLOW /* Allow this to work even if FIPS disables it */ EVP_MD_CTX_set_flags(c, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); #endif md = EVP_md5(); break; case Hash_SHA1: md = EVP_sha1(); break; case Hash_SHA224: md = EVP_sha224(); break; case Hash_SHA256: md = EVP_sha256(); break; case Hash_SHA384: md = EVP_sha384(); break; case Hash_SHA512: md = EVP_sha512(); break; default: reporter->InternalError("Unknown hash algorithm passed to hash_init"); } if ( ! EVP_DigestInit_ex(c, md, nullptr) ) reporter->InternalError("EVP_DigestInit failed"); return to_opaque_ptr(c); } void hash_update(HashDigestState* c, const void* data, unsigned long len) { if ( ! EVP_DigestUpdate(to_native_ptr(c), data, len) ) reporter->InternalError("EVP_DigestUpdate failed"); } void hash_final(HashDigestState* c, u_char* md) { hash_final_no_free(c, md); EVP_MD_CTX_free(to_native_ptr(c)); } void hash_final_no_free(HashDigestState* c, u_char* md) { if ( ! EVP_DigestFinal(to_native_ptr(c), md, nullptr) ) reporter->InternalError("EVP_DigestFinal failed"); } void hash_state_free(HashDigestState* c) { if ( c != nullptr ) EVP_MD_CTX_free(to_native_ptr(c)); } void hash_copy(HashDigestState* out, const HashDigestState* in) { EVP_MD_CTX_copy_ex(to_native_ptr(out), to_native_ptr(in)); } unsigned char* internal_md5(const unsigned char* data, unsigned long len, unsigned char* out) { return calculate_digest(Hash_MD5, data, len, out); } unsigned char* calculate_digest(HashAlgorithm alg, const unsigned char* data, uint64_t len, unsigned char* out) { // maximum possible length for supported hashes static unsigned char static_out[SHA512_DIGEST_LENGTH]; if ( ! out ) out = static_out; // use static array for return, see OpenSSL man page auto* c = hash_init(alg); hash_update(c, data, len); hash_final(c, out); return out; } } // namespace zeek::detail