// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine Master // License Agreement. // // Reference implementation of OEMCrypto APIs // #include "oemcrypto_keybox_ref.h" #include #include #include #include "log.h" #include "oemcrypto_types.h" #include "platform.h" #include "wvcrc32.h" namespace wvoec_ref { namespace { constexpr size_t kKeyboxSize = 128; constexpr size_t kDeviceIdSize = 32; constexpr size_t kKeyDataSize = 72; constexpr size_t kMagicOffset = 120; const uint8_t kMagic[4] = {'k', 'b', 'o', 'x'}; constexpr size_t kCrcKeyboxSize = 124; constexpr size_t kCrcOffset = 124; static_assert(sizeof(wvoec::WidevineKeybox) == kKeyboxSize, "Unexpected keybox size"); template std::vector ToVector(const uint8_t (&field)[N]) { return std::vector(field, &field[N]); } } // namespace // static OEMCryptoResult WvKeybox::ValidateData(const uint8_t* keybox, size_t keybox_length) { if (keybox == nullptr) { LOGE("Keybox data buffer is null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } if (keybox_length != kKeyboxSize) { LOGE("Invalid keybox length: length = %zu", keybox_length); return OEMCrypto_ERROR_KEYBOX_INVALID; } if (memcmp(&keybox[kMagicOffset], kMagic, sizeof(kMagic))) { LOGE("Invalid keybox magic"); return OEMCrypto_ERROR_BAD_MAGIC; } uint32_t crc_provided; memcpy(&crc_provided, &keybox[kCrcOffset], sizeof(crc_provided)); const uint32_t crc_computed = wvcrc32n(keybox, kCrcKeyboxSize); if (crc_provided != crc_computed) { LOGE("Invalid keybox CRC: provided = %08x, computed = %08x", crc_provided, crc_computed); return OEMCrypto_ERROR_BAD_CRC; } return OEMCrypto_SUCCESS; } // static std::unique_ptr WvKeybox::Create(const uint8_t* keybox_data, size_t keybox_length) { std::unique_ptr keybox; if (keybox_length != kKeyboxSize) { LOGE("Invalid keybox length: length = %zu", keybox_length); return keybox; } keybox.reset(new WvKeybox()); memcpy(reinterpret_cast(&keybox->raw_keybox_), keybox_data, kKeyboxSize); return keybox; } OEMCryptoResult WvKeybox::GetDeviceId(uint8_t* device_id, size_t* device_id_length) const { if (device_id_length == nullptr) { LOGE("Output device ID length buffer is null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } if (device_id == nullptr && *device_id_length > 0) { LOGE("Output device ID buffer is null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } if (*device_id_length < kDeviceIdSize) { *device_id_length = kDeviceIdSize; return OEMCrypto_ERROR_SHORT_BUFFER; } *device_id_length = kDeviceIdSize; memcpy(device_id, raw_keybox_.device_id_, kDeviceIdSize); return OEMCrypto_SUCCESS; } std::vector WvKeybox::DeviceId() const { return ToVector(raw_keybox_.device_id_); } std::vector WvKeybox::DeviceKey() const { return ToVector(raw_keybox_.device_key_); } OEMCryptoResult WvKeybox::GetKeyData(uint8_t* key_data, size_t* key_data_length) const { if (key_data_length == nullptr) { LOGE("Output key data length buffer is null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } if (key_data == nullptr && *key_data_length > 0) { LOGE("Output key data buffer is null"); return OEMCrypto_ERROR_INVALID_CONTEXT; } if (*key_data_length < kKeyDataSize) { *key_data_length = kKeyDataSize; return OEMCrypto_ERROR_SHORT_BUFFER; } *key_data_length = kKeyDataSize; memcpy(key_data, raw_keybox_.data_, kKeyDataSize); return OEMCrypto_SUCCESS; } OEMCryptoResult WvKeybox::IsKeyboxValid() const { return ValidateData(reinterpret_cast(&raw_keybox_), kKeyboxSize); } } // namespace wvoec_ref