Files
whitebox/whitebox/reference/impl/license_parser.cc
2023-09-05 16:54:39 +00:00

134 lines
4.5 KiB
C++

// Copyright 2021 Google LLC. All Rights Reserved.
#include "reference/impl/license_parser.h"
#include "base/check.h"
#include "base/check_op.h"
#include "base/logging.h"
#include "crypto_utils/aes_cbc_decryptor.h"
#include "crypto_utils/crypto_util.h"
namespace widevine {
bool LicenseParser::Decrypt(const std::string& key,
const std::string& iv,
const std::string& encrypted,
std::string* decrypted) {
CHECK_EQ(key.size(), 16u);
CHECK_EQ(iv.size(), 16u);
CHECK(decrypted);
decrypted->resize(encrypted.size());
AesCbcDecryptor decryptor;
CHECK(decryptor.SetKey(reinterpret_cast<const uint8_t*>(key.data()),
key.size()));
return decryptor.Decrypt(
reinterpret_cast<const uint8_t*>(iv.data()), iv.size(),
reinterpret_cast<const uint8_t*>(encrypted.data()), encrypted.size(),
reinterpret_cast<uint8_t*>(&decrypted->front()));
}
bool LicenseParser::UnwrapKey(
KeyType key_type,
const std::string& wrapped_key,
const std::vector<ProviderKey>& provider_keys,
size_t provider_key_id,
const std::string& key_decryption_key,
const std::string& key_decryption_key_iv,
std::string* unwrapped_key) {
// provider keys are only applied on content keys.
const bool provider_key_id_valid =
(provider_key_id >= 1 && provider_key_id <= provider_keys.size() &&
key_type == KeyType::kContentKey);
// If |provider_key_id| is used and valid, then start by unmasking it.
std::string key = wrapped_key;
if (provider_key_id_valid) {
const auto& mask = provider_keys[provider_key_id - 1].mask;
for (size_t i = 0; i < key.size(); ++i)
key[i] ^= mask.at(i);
}
// Now decrypt the key using the Key Encryption Key.
std::string intermediate_key;
if (!Decrypt(key_decryption_key, key_decryption_key_iv, key,
&intermediate_key)) {
DVLOG(1) << "Failed to decrypt content key using KEK.";
return false;
}
// If |provider_key_id| not used, simply return the key decrypted so far.
if (!provider_key_id_valid) {
unwrapped_key->swap(intermediate_key);
return true;
}
// |provider_key_id| is used, so decrypt the unwrapped key using the
// appropriate provider key.
std::string final_key;
const auto& provider_key = provider_keys[provider_key_id - 1].key;
const std::string no_iv(16, 0);
if (!Decrypt(provider_key, no_iv, intermediate_key, &final_key)) {
DVLOG(1) << "Failed to decrypt content key using Provider Key.";
return false;
}
unwrapped_key->swap(final_key);
return true;
}
WB_KeyStatus LicenseParser::GetKeyStatus(
video_widevine::License_KeyContainer_SecurityLevel level,
bool is_hw_verified) {
// If the device is hardware verified, then we can override the status to
// allow masked decrypt and decrypt.
if (is_hw_verified) {
return WB_KEY_STATUS_CONTENT_KEY_DECRYPT;
}
switch (level) {
case video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_CRYPTO:
return WB_KEY_STATUS_CONTENT_KEY_DECRYPT;
case video_widevine::License_KeyContainer_SecurityLevel_SW_SECURE_DECODE:
#ifdef ALWAYS_DECRYPT_TO_CLEAR
return WB_KEY_STATUS_CONTENT_KEY_DECRYPT;
#else
return WB_KEY_STATUS_CONTENT_KEY_MASKED_DECRYPT;
#endif
default:
// For example, this could be a hardware key - a valid key but can't be
// used by the CDM. However, this may get override later if the device is
// hardware verified.
return WB_KEY_STATUS_CONTENT_KEY_VALID;
}
}
InternalKey LicenseParser::CreateInternalKey(
KeyType key_type, video_widevine::License_KeyContainer_SecurityLevel level,
bool is_hw_verified, const std::string& key, uint32_t kcb_flags) {
CHECK((kcb_flags & WB_KCB_FLAGS_GENERIC_MASK) == 0 ||
key_type == KeyType::kGenericCryptoKey);
InternalKey internal_key;
internal_key.type = key_type;
if (key_type == KeyType::kGenericCryptoKey)
internal_key.status = WB_KEY_STATUS_CONTENT_KEY_VALID;
else
internal_key.status = GetKeyStatus(level, is_hw_verified);
internal_key.kcb_flags = kcb_flags;
// Unless we are going to use the key, we don't want to save this key as it
// will only risk exposing it. We only have an entry for it so we can handle
// errors correctly.
if (key_type == KeyType::kGenericCryptoKey || internal_key.can_decrypt() ||
internal_key.can_masked_decrypt()) {
CHECK_LE(key.size(), internal_key.key.size());
std::copy(key.begin(), key.end(), internal_key.key.begin());
}
return internal_key;
}
} // namespace widevine