134 lines
4.5 KiB
C++
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
|