// Copyright 2022 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine License // Agreement. // // Reference implementation utilities of OEMCrypto APIs // #include "hmac.h" #include #include #include #include "log.h" #include "string_conversions.h" namespace wvoec { namespace util { namespace { constexpr bool kHmacSha256 = true; constexpr bool kHmacSha1 = false; const std::vector kEmptyVector; // Assumes all parameters are valid. inline bool HmacShaInternal(const uint8_t* key, size_t key_length, const uint8_t* message, size_t message_length, uint8_t* signature, bool sha256) { return HMAC(sha256 ? EVP_sha256() : EVP_sha1(), key, static_cast(key_length), message, message_length, signature, nullptr) != nullptr; } OEMCryptoResult GenerateSignatureInternal(const uint8_t* key, size_t key_length, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length, bool sha256) { if (key == nullptr || key_length == 0) { LOGE("Input |key| is %s", key_length == 0 ? "empty" : "null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } if (message == nullptr || message_length == 0) { LOGE("Input |message| is %s", message_length == 0 ? "empty" : "null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } if (signature_length == nullptr) { LOGE("Input/output |signature_length| is null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } if (signature == nullptr && *signature_length > 0) { LOGE("Output |signature| is null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } const size_t required_signature_size = sha256 ? kHmacSha256SignatureSize : kHmacSha1SignatureSize; if (*signature_length < required_signature_size) { *signature_length = required_signature_size; return OEMCrypto_ERROR_SHORT_BUFFER; } if (!HmacShaInternal(key, key_length, message, message_length, signature, sha256)) { LOGE("Failed to generate signature"); return OEMCrypto_ERROR_UNKNOWN_FAILURE; } *signature_length = required_signature_size; return OEMCrypto_SUCCESS; } bool GenerateSignatureInternal(const uint8_t* key, size_t key_length, const uint8_t* message, size_t message_length, std::vector* signature, bool sha256) { if (signature == nullptr) { LOGE("Output |signature| is null"); return false; } size_t signature_length = sha256 ? kHmacSha256SignatureSize : kHmacSha1SignatureSize; signature->resize(signature_length); const OEMCryptoResult res = GenerateSignatureInternal(key, key_length, message, message_length, signature->data(), &signature_length, sha256); if (res != OEMCrypto_SUCCESS) { signature->clear(); return false; } return true; } // Assumes signature pointers are valid. inline bool CompareSignatures(const uint8_t* signature_a, const uint8_t* signature_b, bool sha256) { const size_t signature_size = sha256 ? kHmacSha256SignatureSize : kHmacSha1SignatureSize; return CRYPTO_memcmp(signature_a, signature_b, signature_size) == 0; } OEMCryptoResult VerifySignatureInternal(const uint8_t* key, size_t key_length, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length, bool sha256) { if (signature == nullptr && signature_length > 0) { LOGE("Input |signature| is null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } size_t expected_signature_length = sha256 ? kHmacSha256SignatureSize : kHmacSha1SignatureSize; if (signature_length != expected_signature_length) { LOGE("Invalid signature length: expected = %zu, actual = %zu", expected_signature_length, signature_length); return OEMCrypto_ERROR_SIGNATURE_FAILURE; } // Allocate for the larger of the two. uint8_t expected_signature[kHmacSha256SignatureSize]; const OEMCryptoResult res = GenerateSignatureInternal( key, key_length, message, message_length, expected_signature, &expected_signature_length, sha256); if (res != OEMCrypto_SUCCESS) return res; if (!CompareSignatures(signature, expected_signature, sha256)) { LOGD("Signatures do not match: type = HMAC-SHA-%s", sha256 ? "256" : "1"); LOGD("provided = %s", wvutil::HexEncode(signature, signature_length).c_str()); LOGD("expected = %s", wvutil::HexEncode(expected_signature, expected_signature_length) .c_str()); return OEMCrypto_ERROR_SIGNATURE_FAILURE; } return OEMCrypto_SUCCESS; } } // namespace OEMCryptoResult HmacSha1(const uint8_t* key, size_t key_length, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length) { return GenerateSignatureInternal(key, key_length, message, message_length, signature, signature_length, kHmacSha1); } OEMCryptoResult HmacSha1(const std::vector& key, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length) { return GenerateSignatureInternal(key.data(), key.size(), message, message_length, signature, signature_length, kHmacSha1); } std::vector HmacSha1(const std::vector& key, const std::vector& message) { std::vector signature; const bool res = GenerateSignatureInternal(key.data(), key.size(), message.data(), message.size(), &signature, kHmacSha1); return res ? signature : kEmptyVector; } OEMCryptoResult HmacSha256(const uint8_t* key, size_t key_length, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length) { return GenerateSignatureInternal(key, key_length, message, message_length, signature, signature_length, kHmacSha256); } OEMCryptoResult HmacSha256(const std::vector& key, const uint8_t* message, size_t message_length, uint8_t* signature, size_t* signature_length) { return GenerateSignatureInternal(key.data(), key.size(), message, message_length, signature, signature_length, kHmacSha256); } bool HmacSha256(const std::vector& key, const std::vector& message, std::vector* signature) { return GenerateSignatureInternal(key.data(), key.size(), message.data(), message.size(), signature, kHmacSha256); } bool HmacSha256(const std::vector& key, const std::string& message, std::vector* signature) { return GenerateSignatureInternal( key.data(), key.size(), reinterpret_cast(message.data()), message.size(), signature, kHmacSha256); } std::vector HmacSha256(const std::vector& key, const uint8_t* message, size_t message_length) { std::vector signature; const bool res = GenerateSignatureInternal( key.data(), key.size(), message, message_length, &signature, kHmacSha256); return res ? signature : kEmptyVector; } std::vector HmacSha256(const std::vector& key, const std::vector& message) { std::vector signature; const bool res = GenerateSignatureInternal(key.data(), key.size(), message.data(), message.size(), &signature, kHmacSha256); return res ? signature : kEmptyVector; } std::vector HmacSha256(const std::vector& key, const std::string& message) { std::vector signature; const bool res = GenerateSignatureInternal( key.data(), key.size(), reinterpret_cast(message.data()), message.size(), &signature, kHmacSha256); return res ? signature : kEmptyVector; } OEMCryptoResult HmacSha1Verify(const uint8_t* key, size_t key_length, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length) { return VerifySignatureInternal(key, key_length, message, message_length, signature, signature_length, kHmacSha1); } OEMCryptoResult HmacSha1Verify(const std::vector& key, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length) { return VerifySignatureInternal(key.data(), key.size(), message, message_length, signature, signature_length, kHmacSha1); } OEMCryptoResult HmacSha1Verify(const std::vector& key, const std::vector& message, const std::vector& signature) { return VerifySignatureInternal(key.data(), key.size(), message.data(), message.size(), signature.data(), signature.size(), kHmacSha1); } OEMCryptoResult HmacSha256Verify(const uint8_t* key, size_t key_length, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length) { return VerifySignatureInternal(key, key_length, message, message_length, signature, signature_length, kHmacSha256); } OEMCryptoResult HmacSha256Verify(const std::vector& key, const uint8_t* message, size_t message_length, const uint8_t* signature, size_t signature_length) { return VerifySignatureInternal(key.data(), key.size(), message, message_length, signature, signature_length, kHmacSha256); } OEMCryptoResult HmacSha256Verify(const std::vector& key, const std::vector& message, const std::vector& signature) { return VerifySignatureInternal(key.data(), key.size(), message.data(), message.size(), signature.data(), signature.size(), kHmacSha256); } OEMCryptoResult HmacSha256Verify(const std::vector& key, const std::string& message, const std::vector& signature) { return VerifySignatureInternal( key.data(), key.size(), reinterpret_cast(message.data()), message.size(), signature.data(), signature.size(), kHmacSha256); } } // namespace util } // namespace wvoec