OEMCrypto v16.2

Merge from Widevine repo of http://go/wvgerrit/93404

This is the unit tests, reference code, and documentation for
OEMCrypto v16.2. Backwards compatibility should work for a v15
OEMCrypto.

Some review comments will be addressed in future CLs.

Bug: 141247171
Test: Unit tests
Test: Media GTS tests on bonito
Change-Id: I9d427c07580e180c0a4cfdc4a68f538d351c0ddd
This commit is contained in:
Fred Gylys-Colwell
2020-01-18 10:18:50 -08:00
parent 7665614b2e
commit db2050dff1
62 changed files with 2947 additions and 2286 deletions

View File

@@ -42,11 +42,15 @@ CryptoEngine::~CryptoEngine() {
}
bool CryptoEngine::Initialize() {
std::string file_path = GetUsageTimeFileFullPath();
LoadOfflineTimeInfo(file_path);
usage_table_.reset(MakeUsageTable());
return true;
}
void CryptoEngine::Terminate() {
std::string file_path = GetUsageTimeFileFullPath();
SaveOfflineTimeInfo(file_path);
std::unique_lock<std::mutex> lock(session_table_lock_);
ActiveSessions::iterator it;
for (it = sessions_.begin(); it != sessions_.end(); ++it) {
@@ -102,44 +106,53 @@ int64_t CryptoEngine::OnlineTime() {
}
int64_t CryptoEngine::RollbackCorrectedOfflineTime() {
struct TimeInfo {
// The max time recorded through this function call.
int64_t previous_time;
// If the wall time is rollbacked to before the previous_time, this member
// is updated to reflect the offset.
int64_t rollback_offset;
// Pad the struct so that TimeInfo is a multiple of 16.
uint8_t padding[16 - (2 * sizeof(time_t)) % 16];
};
// Add any time offsets in the past to the current time.
int64_t current_time = OnlineTime() + offline_time_info_.rollback_offset;
// Write time info to disk if kTimeInfoUpdateWindowInSeconds has elapsed since
// last write.
if (current_time - offline_time_info_.previous_time >
kTimeInfoUpdateWindowInSeconds) {
std::string file_path = GetUsageTimeFileFullPath();
SaveOfflineTimeInfo(file_path);
}
return current_time;
}
std::vector<uint8_t> encrypted_buffer(sizeof(TimeInfo));
std::vector<uint8_t> clear_buffer(sizeof(TimeInfo));
TimeInfo time_info;
memset(&time_info, 0, sizeof(time_info));
// Use the device key for encrypt/decrypt.
const std::vector<uint8_t>& key = DeviceRootKey();
std::unique_ptr<wvcdm::File> file;
std::string path;
// Note: this path is OK for a real implementation, but using security level 1
// would be better.
std::string CryptoEngine::GetUsageTimeFileFullPath() const {
std::string file_path;
// Note: file path is OK for a real implementation, but using security
// level 1 would be better.
// TODO(fredgc, jfore): Address how this property is presented to the ref.
// For now, the path is empty.
// For now, the file path is empty.
/*if (!wvcdm::Properties::GetDeviceFilesBasePath(wvcdm::kSecurityLevelL3,
&path)) {
LOGE("RollbackCorrectedOfflineTime: Unable to get base path");
&file_path)) {
LOGE("RollbackCorrectedOfflineTime: Unable to get base path");
}*/
std::string filename = path + "StoredUsageTime.dat";
return file_path + kStoredUsageTimeFileName;
}
bool CryptoEngine::LoadOfflineTimeInfo(const std::string& file_path) {
memset(&offline_time_info_, 0, sizeof(TimeInfo));
wvcdm::FileSystem* file_system = file_system_.get();
if (file_system->Exists(filename)) {
// Load time info from previous call to this function.
file = file_system->Open(filename, wvcdm::FileSystem::kReadOnly);
if (file_system->Exists(file_path)) {
std::vector<uint8_t> encrypted_buffer(sizeof(TimeInfo));
std::vector<uint8_t> clear_buffer(sizeof(TimeInfo));
KeyboxError error_code = ValidateKeybox();
if (error_code != NO_ERROR) {
LOGE("Keybox is invalid: %d", error_code);
return false;
}
// Use the device key for encrypt/decrypt.
const std::vector<uint8_t>& key = DeviceRootKey();
std::unique_ptr<wvcdm::File> file =
file_system->Open(file_path, wvcdm::FileSystem::kReadOnly);
if (!file) {
LOGE("RollbackCorrectedOfflineTime: File open failed: %s",
filename.c_str());
return OnlineTime();
file_path.c_str());
return false;
}
// Load time info from previous call.
file->Read(reinterpret_cast<char*>(&encrypted_buffer[0]), sizeof(TimeInfo));
// Decrypt the encrypted TimeInfo buffer.
AES_KEY aes_key;
@@ -147,42 +160,65 @@ int64_t CryptoEngine::RollbackCorrectedOfflineTime() {
std::vector<uint8_t> iv(wvoec::KEY_IV_SIZE, 0);
AES_cbc_encrypt(&encrypted_buffer[0], &clear_buffer[0], sizeof(TimeInfo),
&aes_key, iv.data(), AES_DECRYPT);
memcpy(&time_info, &clear_buffer[0], sizeof(TimeInfo));
}
memcpy(&offline_time_info_, &clear_buffer[0], sizeof(TimeInfo));
int64_t current_time;
// Add any time offsets in the past to the current time.
current_time = OnlineTime() + time_info.rollback_offset;
if (time_info.previous_time > current_time) {
// Time has been rolled back.
// Update the rollback offset.
time_info.rollback_offset += time_info.previous_time - current_time;
// Keep current time at previous recorded time.
current_time = time_info.previous_time;
// Detect offline time rollback after loading from disk.
// Add any time offsets in the past to the current time.
int64_t current_time = OnlineTime() + offline_time_info_.rollback_offset;
if (offline_time_info_.previous_time > current_time) {
// Current time is earlier than the previously saved time. Time has been
// rolled back. Update the rollback offset.
offline_time_info_.rollback_offset +=
offline_time_info_.previous_time - current_time;
// Keep current time at previous recorded time.
current_time = offline_time_info_.previous_time;
}
// The new previous_time will either stay the same or move forward.
offline_time_info_.previous_time = current_time;
}
return true;
}
bool CryptoEngine::SaveOfflineTimeInfo(const std::string& file_path) {
// Add any time offsets in the past to the current time. If there was an
// earlier offline rollback, the rollback offset will be updated in
// LoadOfflineTimeInfo(). It guarantees that the current time to be saved
// will never go back.
int64_t current_time = OnlineTime() + offline_time_info_.rollback_offset;
// The new previous_time will either stay the same or move forward.
time_info.previous_time = current_time;
if (current_time > offline_time_info_.previous_time)
offline_time_info_.previous_time = current_time;
KeyboxError error_code = ValidateKeybox();
if (error_code != NO_ERROR) {
LOGE("Keybox is invalid: %d", error_code);
return false;
}
// Use the device key for encrypt/decrypt.
const std::vector<uint8_t>& key = DeviceRootKey();
std::vector<uint8_t> encrypted_buffer(sizeof(TimeInfo));
std::vector<uint8_t> clear_buffer(sizeof(TimeInfo));
// Copy updated data and encrypt the buffer.
memcpy(&clear_buffer[0], &time_info, sizeof(TimeInfo));
memcpy(&clear_buffer[0], &offline_time_info_, sizeof(TimeInfo));
AES_KEY aes_key;
AES_set_encrypt_key(&key[0], 128, &aes_key);
std::vector<uint8_t> iv(wvoec::KEY_IV_SIZE, 0);
AES_cbc_encrypt(&clear_buffer[0], &encrypted_buffer[0], sizeof(TimeInfo),
&aes_key, iv.data(), AES_ENCRYPT);
std::unique_ptr<wvcdm::File> file;
wvcdm::FileSystem* file_system = file_system_.get();
// Write the encrypted buffer to disk.
file = file_system->Open(
filename, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
file_path, wvcdm::FileSystem::kCreate | wvcdm::FileSystem::kTruncate);
if (!file) {
LOGE("RollbackCorrectedOfflineTime: File open failed: %s",
filename.c_str());
return OnlineTime();
file_path.c_str());
return false;
}
file->Write(reinterpret_cast<char*>(&encrypted_buffer[0]), sizeof(TimeInfo));
// Return time with offset.
return current_time;
return true;
}
bool CryptoEngine::NonceCollision(uint32_t nonce) {