270 lines
12 KiB
C++
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
|