//////////////////////////////////////////////////////////////////////////////// // Copyright 2016 Google LLC. // // This software is licensed under the terms defined in the Widevine Master // License Agreement. For a copy of this agreement, please contact // widevine-licensing@google.com. //////////////////////////////////////////////////////////////////////////////// // Implementation of ecb crypto routines used by Widevine services. #include "common/ecb_util.h" #include "glog/logging.h" #include "absl/strings/string_view.h" #include "openssl/aes.h" #include "openssl/des.h" namespace widevine { namespace crypto_util { const int kWvmDESKeySizeBytes = 16; static bool EncryptOrDecrypt3DesCbc(absl::string_view key, absl::string_view src, std::string* dst, bool encrypt) { CHECK(dst); if (key.size() != kWvmDESKeySizeBytes) { LOG(WARNING) << "Invalid 3DES key size (" << key.size() << "!=16)."; dst->clear(); return false; } const int data_size = src.size(); if (data_size % DES_KEY_SZ != 0) { // Data must be a multiple of block size LOG(WARNING) << "3DES data is not a multiple of 8 bytes."; dst->clear(); return false; } const int data_size_blocks = data_size / DES_KEY_SZ; DES_key_schedule schedule[2]; // const_DES_cblock (the type of the first argument to DES_ecb3_encrypt) isn't // actually const, so we have to cast away const. DES_cblock* keyblock = const_cast(reinterpret_cast(key.data())); DES_set_key(keyblock + 0, schedule + 1); DES_set_key(keyblock + 1, schedule + 0); DES_cblock* srcblock = const_cast(reinterpret_cast(src.data())); dst->resize(data_size); DES_cblock* dstblock = reinterpret_cast(&*dst->begin()); for (int i = 0; i < data_size_blocks; i++) { DES_ecb3_encrypt(srcblock + i, dstblock + i, schedule + 0, schedule + 1, schedule + 0, encrypt); } return true; } bool Encrypt3DesEcb(absl::string_view key, absl::string_view src, std::string* dst) { return EncryptOrDecrypt3DesCbc(key, src, dst, DES_ENCRYPT); } bool Decrypt3DesEcb(absl::string_view key, absl::string_view src, std::string* dst) { return EncryptOrDecrypt3DesCbc(key, src, dst, DES_DECRYPT); } bool EncryptAesEcb(absl::string_view key, absl::string_view src, std::string* dst) { CHECK(dst); dst->clear(); if (src.size() % 16 != 0) { LOG(WARNING) << "AES-ECB data is not a multiple of 16 bytes."; return false; } int num_bits = key.size() * 8; AES_KEY aes_key; int aes_result = AES_set_encrypt_key( reinterpret_cast(key.data()), num_bits, &aes_key); if (aes_result != 0) { LOG(WARNING) << "AES result is not zero."; return false; } dst->resize(src.size()); for (int i = 0; i < src.size(); i += AES_BLOCK_SIZE) { AES_encrypt(reinterpret_cast(src.data() + i), reinterpret_cast(&(*dst)[i]), &aes_key); } return true; } bool DecryptAesEcb(absl::string_view key, absl::string_view src, std::string* dst) { CHECK(dst); dst->clear(); if (src.size() % 16 != 0) { LOG(WARNING) << "AES-ECB data is not a multiple of 16 bytes."; return false; } int num_bits = key.size() * 8; AES_KEY aes_key; int aes_result = AES_set_decrypt_key( reinterpret_cast(key.data()), num_bits, &aes_key); if (aes_result != 0) { LOG(WARNING) << "AES result is not zero."; return false; } dst->resize(src.size()); for (int i = 0; i < src.size(); i += AES_BLOCK_SIZE) { AES_decrypt(reinterpret_cast(src.data() + i), reinterpret_cast(&(*dst)[i]), &aes_key); } return true; } } // namespace crypto_util } // namespace widevine