Files
ce_cdm/oemcrypto/util/src/hmac.cpp
John "Juce" Bruce 694cf6fb25 Source release 17.1.0
2022-07-07 17:14:31 -07:00

270 lines
12 KiB
C++

// 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 <openssl/crypto.h>
#include <openssl/evp.h>
#include <openssl/hmac.h>
#include "log.h"
#include "string_conversions.h"
namespace wvoec {
namespace util {
namespace {
constexpr bool kHmacSha256 = true;
constexpr bool kHmacSha1 = false;
const std::vector<uint8_t> 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<int>(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<uint8_t>* 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<uint8_t>& 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<uint8_t> HmacSha1(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message) {
std::vector<uint8_t> 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<uint8_t>& 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<uint8_t>& key,
const std::vector<uint8_t>& message,
std::vector<uint8_t>* signature) {
return GenerateSignatureInternal(key.data(), key.size(), message.data(),
message.size(), signature, kHmacSha256);
}
bool HmacSha256(const std::vector<uint8_t>& key, const std::string& message,
std::vector<uint8_t>* signature) {
return GenerateSignatureInternal(
key.data(), key.size(), reinterpret_cast<const uint8_t*>(message.data()),
message.size(), signature, kHmacSha256);
}
std::vector<uint8_t> HmacSha256(const std::vector<uint8_t>& key,
const uint8_t* message, size_t message_length) {
std::vector<uint8_t> signature;
const bool res = GenerateSignatureInternal(
key.data(), key.size(), message, message_length, &signature, kHmacSha256);
return res ? signature : kEmptyVector;
}
std::vector<uint8_t> HmacSha256(const std::vector<uint8_t>& key,
const std::vector<uint8_t>& message) {
std::vector<uint8_t> signature;
const bool res =
GenerateSignatureInternal(key.data(), key.size(), message.data(),
message.size(), &signature, kHmacSha256);
return res ? signature : kEmptyVector;
}
std::vector<uint8_t> HmacSha256(const std::vector<uint8_t>& key,
const std::string& message) {
std::vector<uint8_t> signature;
const bool res = GenerateSignatureInternal(
key.data(), key.size(), reinterpret_cast<const uint8_t*>(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<uint8_t>& 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<uint8_t>& key,
const std::vector<uint8_t>& message,
const std::vector<uint8_t>& 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<uint8_t>& 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<uint8_t>& key,
const std::vector<uint8_t>& message,
const std::vector<uint8_t>& signature) {
return VerifySignatureInternal(key.data(), key.size(), message.data(),
message.size(), signature.data(),
signature.size(), kHmacSha256);
}
OEMCryptoResult HmacSha256Verify(const std::vector<uint8_t>& key,
const std::string& message,
const std::vector<uint8_t>& signature) {
return VerifySignatureInternal(
key.data(), key.size(), reinterpret_cast<const uint8_t*>(message.data()),
message.size(), signature.data(), signature.size(), kHmacSha256);
}
} // namespace util
} // namespace wvoec