crypto: remove crypto/encryptor
This interface is now fully unused, replaced by crypto/aes_cbc and crypto/aes_ctr. All clients are gone and the remaining references are some stray includes. Bug: 372283556 Change-Id: I1d98abafa434f67e2ce3280d7adf8e5e19cb0d70 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6191987 Reviewed-by: Nick Harper <nharper@chromium.org> Reviewed-by: Mark Foltz <mfoltz@chromium.org> Reviewed-by: Kyle Horimoto <khorimoto@chromium.org> Reviewed-by: Lei Zhang <thestig@chromium.org> Commit-Queue: Elly FJ <ellyjones@chromium.org> Cr-Commit-Position: refs/heads/main@{#1434946}
This commit is contained in:
chrome/browser
enterprise
connectors
device_trust
attestation
browser
nearby_sharing
certificates
chromeos/ash/components/network/onc
components
error_page
common
alt_game_images
os_crypt
crypto
media/filters
@ -12,10 +12,8 @@
|
||||
#include "base/containers/span.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/signature_verifier.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
#include "third_party/boringssl/src/include/openssl/bn.h"
|
||||
#include "third_party/boringssl/src/include/openssl/bytestring.h"
|
||||
#include "third_party/boringssl/src/include/openssl/evp.h"
|
||||
|
@ -9,10 +9,8 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "crypto/hkdf.h"
|
||||
#include "crypto/sha2.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
|
||||
bool IsNearbyShareCertificateExpired(base::Time current_time,
|
||||
base::Time not_after,
|
||||
|
@ -45,9 +45,7 @@
|
||||
#include "components/url_formatter/url_fixer.h"
|
||||
#include "components/user_manager/user.h"
|
||||
#include "components/user_manager/user_manager.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "crypto/hmac.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
#include "net/base/host_port_pair.h"
|
||||
#include "net/base/proxy_server.h"
|
||||
#include "net/base/proxy_string_util.h"
|
||||
|
@ -14,8 +14,6 @@
|
||||
#include "base/logging.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
|
||||
namespace error_page {
|
||||
namespace {
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include "base/strings/string_util.h"
|
||||
#include "components/dbus/thread_linux/dbus_thread_linux.h"
|
||||
#include "components/os_crypt/async/common/algorithm.mojom.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "crypto/kdf.h"
|
||||
#include "dbus/message.h"
|
||||
#include "dbus/object_path.h"
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include "components/dbus/utils/check_for_service_and_start.h"
|
||||
#include "components/dbus/utils/name_has_owner.h"
|
||||
#include "components/os_crypt/async/browser/key_provider.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "dbus/bus.h"
|
||||
#include "dbus/object_path.h"
|
||||
#include "dbus/object_proxy.h"
|
||||
|
@ -15,7 +15,6 @@
|
||||
#include "build/branding_buildflags.h"
|
||||
#include "components/dbus/properties/types.h"
|
||||
#include "components/dbus/utils/name_has_owner.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "dbus/message.h"
|
||||
#include "dbus/mock_bus.h"
|
||||
#include "dbus/mock_object_proxy.h"
|
||||
|
@ -22,9 +22,7 @@
|
||||
#include "components/os_crypt/sync/key_storage_linux.h"
|
||||
#include "components/os_crypt/sync/os_crypt_metrics.h"
|
||||
#include "crypto/aes_cbc.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "crypto/kdf.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
|
||||
namespace {
|
||||
|
||||
|
@ -28,8 +28,6 @@ component("crypto") {
|
||||
"ec_signature_creator.h",
|
||||
"ec_signature_creator_impl.cc",
|
||||
"ec_signature_creator_impl.h",
|
||||
"encryptor.cc",
|
||||
"encryptor.h",
|
||||
"features.cc",
|
||||
"features.h",
|
||||
"hash.cc",
|
||||
@ -179,7 +177,6 @@ test("crypto_unittests") {
|
||||
"aes_ctr_unittest.cc",
|
||||
"ec_private_key_unittest.cc",
|
||||
"ec_signature_creator_unittest.cc",
|
||||
"encryptor_unittest.cc",
|
||||
"hash_unittest.cc",
|
||||
"hmac_unittest.cc",
|
||||
"kdf_unittest.cc",
|
||||
|
@ -1,203 +0,0 @@
|
||||
// Copyright 2012 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifdef UNSAFE_BUFFERS_BUILD
|
||||
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
|
||||
#pragma allow_unsafe_buffers
|
||||
#endif
|
||||
|
||||
#include "crypto/encryptor.h"
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "crypto/openssl_util.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
#include "third_party/boringssl/src/include/openssl/aes.h"
|
||||
#include "third_party/boringssl/src/include/openssl/evp.h"
|
||||
|
||||
namespace crypto {
|
||||
|
||||
namespace {
|
||||
|
||||
const EVP_CIPHER* GetCipherForKey(const SymmetricKey* key) {
|
||||
switch (key->key().length()) {
|
||||
case 16: return EVP_aes_128_cbc();
|
||||
case 32: return EVP_aes_256_cbc();
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
// Encryptor Implementation.
|
||||
|
||||
Encryptor::Encryptor() : key_(nullptr), mode_(CBC) {}
|
||||
|
||||
Encryptor::~Encryptor() = default;
|
||||
|
||||
bool Encryptor::Init(const SymmetricKey* key, Mode mode, std::string_view iv) {
|
||||
return Init(key, mode, base::as_byte_span(iv));
|
||||
}
|
||||
|
||||
bool Encryptor::Init(const SymmetricKey* key,
|
||||
Mode mode,
|
||||
base::span<const uint8_t> iv) {
|
||||
DCHECK(key);
|
||||
DCHECK(mode == CBC || mode == CTR);
|
||||
|
||||
if (mode == CBC && iv.size() != AES_BLOCK_SIZE)
|
||||
return false;
|
||||
// CTR mode passes the starting counter separately, via SetCounter().
|
||||
if (mode == CTR && !iv.empty())
|
||||
return false;
|
||||
|
||||
if (GetCipherForKey(key) == nullptr)
|
||||
return false;
|
||||
|
||||
key_ = key;
|
||||
mode_ = mode;
|
||||
iv_.assign(iv.begin(), iv.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Encryptor::Encrypt(std::string_view plaintext, std::string* ciphertext) {
|
||||
return CryptString(/*do_encrypt=*/true, plaintext, ciphertext);
|
||||
}
|
||||
|
||||
bool Encryptor::Encrypt(base::span<const uint8_t> plaintext,
|
||||
std::vector<uint8_t>* ciphertext) {
|
||||
return CryptBytes(/*do_encrypt=*/true, plaintext, ciphertext);
|
||||
}
|
||||
|
||||
bool Encryptor::Decrypt(std::string_view ciphertext, std::string* plaintext) {
|
||||
return CryptString(/*do_encrypt=*/false, ciphertext, plaintext);
|
||||
}
|
||||
|
||||
bool Encryptor::Decrypt(base::span<const uint8_t> ciphertext,
|
||||
std::vector<uint8_t>* plaintext) {
|
||||
return CryptBytes(/*do_encrypt=*/false, ciphertext, plaintext);
|
||||
}
|
||||
|
||||
bool Encryptor::SetCounter(std::string_view counter) {
|
||||
return SetCounter(base::as_byte_span(counter));
|
||||
}
|
||||
|
||||
bool Encryptor::SetCounter(base::span<const uint8_t> counter) {
|
||||
if (mode_ != CTR)
|
||||
return false;
|
||||
if (counter.size() != 16u)
|
||||
return false;
|
||||
|
||||
iv_.assign(counter.begin(), counter.end());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Encryptor::CryptString(bool do_encrypt,
|
||||
std::string_view input,
|
||||
std::string* output) {
|
||||
std::string result(MaxOutput(do_encrypt, input.size()), '\0');
|
||||
std::optional<size_t> len =
|
||||
(mode_ == CTR) ? CryptCTR(do_encrypt, base::as_byte_span(input),
|
||||
base::as_writable_byte_span(result))
|
||||
: Crypt(do_encrypt, base::as_byte_span(input),
|
||||
base::as_writable_byte_span(result));
|
||||
if (!len)
|
||||
return false;
|
||||
|
||||
result.resize(*len);
|
||||
*output = std::move(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Encryptor::CryptBytes(bool do_encrypt,
|
||||
base::span<const uint8_t> input,
|
||||
std::vector<uint8_t>* output) {
|
||||
std::vector<uint8_t> result(MaxOutput(do_encrypt, input.size()));
|
||||
std::optional<size_t> len = (mode_ == CTR)
|
||||
? CryptCTR(do_encrypt, input, result)
|
||||
: Crypt(do_encrypt, input, result);
|
||||
if (!len)
|
||||
return false;
|
||||
|
||||
result.resize(*len);
|
||||
*output = std::move(result);
|
||||
return true;
|
||||
}
|
||||
|
||||
size_t Encryptor::MaxOutput(bool do_encrypt, size_t length) {
|
||||
size_t result = length + ((do_encrypt && mode_ == CBC) ? 16 : 0);
|
||||
CHECK_GE(result, length); // Overflow
|
||||
return result;
|
||||
}
|
||||
|
||||
std::optional<size_t> Encryptor::Crypt(bool do_encrypt,
|
||||
base::span<const uint8_t> input,
|
||||
base::span<uint8_t> output) {
|
||||
DCHECK(key_); // Must call Init() before En/De-crypt.
|
||||
|
||||
const EVP_CIPHER* cipher = GetCipherForKey(key_);
|
||||
DCHECK(cipher); // Already handled in Init();
|
||||
|
||||
const std::string& key = key_->key();
|
||||
DCHECK_EQ(EVP_CIPHER_iv_length(cipher), iv_.size());
|
||||
DCHECK_EQ(EVP_CIPHER_key_length(cipher), key.size());
|
||||
|
||||
OpenSSLErrStackTracer err_tracer(FROM_HERE);
|
||||
bssl::ScopedEVP_CIPHER_CTX ctx;
|
||||
if (!EVP_CipherInit_ex(ctx.get(), cipher, nullptr,
|
||||
reinterpret_cast<const uint8_t*>(key.data()),
|
||||
iv_.data(), do_encrypt)) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
// Encrypting needs a block size of space to allow for any padding.
|
||||
CHECK_GE(output.size(), input.size() + (do_encrypt ? iv_.size() : 0));
|
||||
int out_len;
|
||||
if (!EVP_CipherUpdate(ctx.get(), output.data(), &out_len, input.data(),
|
||||
input.size()))
|
||||
return std::nullopt;
|
||||
|
||||
// Write out the final block plus padding (if any) to the end of the data
|
||||
// just written.
|
||||
int tail_len;
|
||||
if (!EVP_CipherFinal_ex(ctx.get(), output.data() + out_len, &tail_len))
|
||||
return std::nullopt;
|
||||
|
||||
out_len += tail_len;
|
||||
DCHECK_LE(out_len, static_cast<int>(output.size()));
|
||||
return out_len;
|
||||
}
|
||||
|
||||
std::optional<size_t> Encryptor::CryptCTR(bool do_encrypt,
|
||||
base::span<const uint8_t> input,
|
||||
base::span<uint8_t> output) {
|
||||
if (iv_.size() != AES_BLOCK_SIZE) {
|
||||
LOG(ERROR) << "Counter value not set in CTR mode.";
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
AES_KEY aes_key;
|
||||
if (AES_set_encrypt_key(reinterpret_cast<const uint8_t*>(key_->key().data()),
|
||||
key_->key().size() * 8, &aes_key) != 0) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
uint8_t ecount_buf[AES_BLOCK_SIZE] = { 0 };
|
||||
unsigned int block_offset = 0;
|
||||
|
||||
// |output| must have room for |input|.
|
||||
CHECK_GE(output.size(), input.size());
|
||||
// Note AES_ctr128_encrypt() will update |iv_|. However, this method discards
|
||||
// |ecount_buf| and |block_offset|, so this is not quite a streaming API.
|
||||
AES_ctr128_encrypt(input.data(), output.data(), input.size(), &aes_key,
|
||||
iv_.data(), ecount_buf, &block_offset);
|
||||
return input.size();
|
||||
}
|
||||
|
||||
} // namespace crypto
|
@ -1,103 +0,0 @@
|
||||
// Copyright 2012 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef CRYPTO_ENCRYPTOR_H_
|
||||
#define CRYPTO_ENCRYPTOR_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "build/build_config.h"
|
||||
#include "crypto/crypto_export.h"
|
||||
|
||||
namespace crypto {
|
||||
|
||||
class SymmetricKey;
|
||||
|
||||
// This class implements encryption without authentication, which is usually
|
||||
// unsafe. Prefer crypto::Aead for new code. If using this class, prefer the
|
||||
// base::span and std::vector overloads over the std::string_view and
|
||||
// std::string overloads.
|
||||
class CRYPTO_EXPORT Encryptor {
|
||||
public:
|
||||
enum Mode {
|
||||
CBC,
|
||||
CTR,
|
||||
};
|
||||
|
||||
Encryptor();
|
||||
~Encryptor();
|
||||
|
||||
// Initializes the encryptor using |key| and |iv|. Returns false if either the
|
||||
// key or the initialization vector cannot be used.
|
||||
//
|
||||
// If |mode| is CBC, |iv| must not be empty; if it is CTR, then |iv| must be
|
||||
// empty.
|
||||
bool Init(const SymmetricKey* key, Mode mode, std::string_view iv);
|
||||
bool Init(const SymmetricKey* key, Mode mode, base::span<const uint8_t> iv);
|
||||
|
||||
// Encrypts |plaintext| into |ciphertext|. |plaintext| may only be empty if
|
||||
// the mode is CBC.
|
||||
bool Encrypt(std::string_view plaintext, std::string* ciphertext);
|
||||
bool Encrypt(base::span<const uint8_t> plaintext,
|
||||
std::vector<uint8_t>* ciphertext);
|
||||
|
||||
// Decrypts |ciphertext| into |plaintext|. |ciphertext| must not be empty.
|
||||
//
|
||||
// WARNING: In CBC mode, Decrypt() returns false if it detects the padding
|
||||
// in the decrypted plaintext is wrong. Padding errors can result from
|
||||
// tampered ciphertext or a wrong decryption key. But successful decryption
|
||||
// does not imply the authenticity of the data. The caller of Decrypt()
|
||||
// must either authenticate the ciphertext before decrypting it, or take
|
||||
// care to not report decryption failure. Otherwise it could inadvertently
|
||||
// be used as a padding oracle to attack the cryptosystem.
|
||||
bool Decrypt(std::string_view ciphertext, std::string* plaintext);
|
||||
bool Decrypt(base::span<const uint8_t> ciphertext,
|
||||
std::vector<uint8_t>* plaintext);
|
||||
|
||||
// Sets the counter value when in CTR mode. Currently only 128-bits
|
||||
// counter value is supported.
|
||||
//
|
||||
// Returns true only if update was successful.
|
||||
bool SetCounter(std::string_view counter);
|
||||
bool SetCounter(base::span<const uint8_t> counter);
|
||||
|
||||
// TODO(albertb): Support streaming encryption.
|
||||
|
||||
private:
|
||||
raw_ptr<const SymmetricKey, DanglingUntriaged> key_;
|
||||
Mode mode_;
|
||||
|
||||
bool CryptString(bool do_encrypt,
|
||||
std::string_view input,
|
||||
std::string* output);
|
||||
bool CryptBytes(bool do_encrypt,
|
||||
base::span<const uint8_t> input,
|
||||
std::vector<uint8_t>* output);
|
||||
|
||||
// On success, these helper functions return the number of bytes written to
|
||||
// |output|.
|
||||
size_t MaxOutput(bool do_encrypt, size_t length);
|
||||
std::optional<size_t> Crypt(bool do_encrypt,
|
||||
base::span<const uint8_t> input,
|
||||
base::span<uint8_t> output);
|
||||
std::optional<size_t> CryptCTR(bool do_encrypt,
|
||||
base::span<const uint8_t> input,
|
||||
base::span<uint8_t> output);
|
||||
|
||||
// In CBC mode, the IV passed to Init(). In CTR mode, the counter value passed
|
||||
// to SetCounter().
|
||||
std::vector<uint8_t> iv_;
|
||||
};
|
||||
|
||||
} // namespace crypto
|
||||
|
||||
#endif // CRYPTO_ENCRYPTOR_H_
|
@ -1,584 +0,0 @@
|
||||
// Copyright 2012 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifdef UNSAFE_BUFFERS_BUILD
|
||||
// TODO(crbug.com/351564777): Remove this and convert code to safer constructs.
|
||||
#pragma allow_unsafe_buffers
|
||||
#endif
|
||||
|
||||
#include "crypto/encryptor.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/containers/heap_array.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
#include "testing/gtest/include/gtest/gtest.h"
|
||||
|
||||
// PBKDF2-HMAC-SHA1("password", "saltiest", 1000 iterations)
|
||||
constexpr auto kTestKey = std::to_array<uint8_t>({
|
||||
0xd9, 0xb7, 0x6d, 0x65, 0x3b, 0x0b, 0x25, 0xd7, 0xa8, 0xce, 0xed,
|
||||
0xba, 0x98, 0xee, 0xe5, 0x09, 0x53, 0x2a, 0xa7, 0x84, 0xe4, 0x44,
|
||||
0x72, 0x30, 0x03, 0x99, 0x34, 0x51, 0xa9, 0x8a, 0x74, 0x53,
|
||||
});
|
||||
|
||||
TEST(EncryptorTest, EncryptDecrypt) {
|
||||
crypto::Encryptor encryptor;
|
||||
// The IV must be exactly as long as the cipher block size.
|
||||
std::string iv("the iv: 16 bytes");
|
||||
EXPECT_EQ(16U, iv.size());
|
||||
crypto::SymmetricKey key(kTestKey);
|
||||
EXPECT_TRUE(encryptor.Init(&key, crypto::Encryptor::CBC, iv));
|
||||
|
||||
std::string plaintext("this is the plaintext");
|
||||
std::string ciphertext;
|
||||
EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext));
|
||||
EXPECT_LT(0U, ciphertext.size());
|
||||
|
||||
std::string decrypted;
|
||||
EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted));
|
||||
EXPECT_EQ(plaintext, decrypted);
|
||||
|
||||
// Repeat the test with the bytes API.
|
||||
std::vector<uint8_t> plaintext_vec(plaintext.begin(), plaintext.end());
|
||||
std::vector<uint8_t> ciphertext_vec;
|
||||
EXPECT_TRUE(encryptor.Encrypt(plaintext_vec, &ciphertext_vec));
|
||||
EXPECT_LT(0U, ciphertext_vec.size());
|
||||
|
||||
std::vector<uint8_t> decrypted_vec;
|
||||
EXPECT_TRUE(encryptor.Decrypt(ciphertext_vec, &decrypted_vec));
|
||||
EXPECT_EQ(plaintext_vec, decrypted_vec);
|
||||
}
|
||||
|
||||
TEST(EncryptorTest, DecryptWrongKey) {
|
||||
crypto::SymmetricKey key(kTestKey);
|
||||
|
||||
// A wrong key that can be detected by implementations that validate every
|
||||
// byte in the padding.
|
||||
// PBKDF2-HMAC-SHA1("wrongword", "sweetest", 1000 iterations)
|
||||
constexpr auto kWrongKey = std::to_array<uint8_t>({
|
||||
0x88, 0xea, 0x6c, 0x27, 0xbd, 0xcc, 0x56, 0xde, 0x31, 0xb6, 0x68,
|
||||
0x85, 0x61, 0x5a, 0xd8, 0xdb, 0xe4, 0x82, 0xfc, 0xa9, 0xfa, 0x5b,
|
||||
0x1b, 0xb1, 0x4f, 0x31, 0xb9, 0xe3, 0x04, 0xd4, 0x67, 0x58,
|
||||
});
|
||||
crypto::SymmetricKey wrong_key(kWrongKey);
|
||||
|
||||
// A wrong key that can't be detected by any implementation. The password
|
||||
// "wrongword;" would also work.
|
||||
// PBKDF2-HMAC-SHA1("wrongword+", "sweetest", 1000 iterations)
|
||||
constexpr auto kWrongKey2 = std::to_array<uint8_t>({
|
||||
0x3b, 0x5c, 0x1e, 0x70, 0x7f, 0x31, 0xbf, 0x8e, 0xc8, 0x45, 0xd3,
|
||||
0x04, 0x20, 0xa4, 0x21, 0xfb, 0xd2, 0x21, 0x11, 0x44, 0x7b, 0xca,
|
||||
0x48, 0xf5, 0xeb, 0xf4, 0xd7, 0xca, 0xa8, 0x18, 0xfc, 0x37,
|
||||
});
|
||||
crypto::SymmetricKey wrong_key2(kWrongKey2);
|
||||
|
||||
// A wrong key that can be detected by all implementations.
|
||||
// PBKDF2-HMAC-SHA1("wrongwordx", "sweetest", 1000 iterations)
|
||||
constexpr auto kWrongKey3 = std::to_array<uint8_t>({
|
||||
0x37, 0xde, 0x34, 0x4b, 0x76, 0xf2, 0x52, 0x3e, 0xde, 0xd0, 0x4b,
|
||||
0xc9, 0x5a, 0x83, 0x51, 0xc0, 0x5a, 0xf5, 0x37, 0xfa, 0xce, 0x7d,
|
||||
0x51, 0xa8, 0xd8, 0xae, 0xfc, 0x1c, 0x0b, 0xb7, 0xe9, 0x3f,
|
||||
});
|
||||
crypto::SymmetricKey wrong_key3(kWrongKey3);
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
// The IV must be exactly as long as the cipher block size.
|
||||
std::string iv("the iv: 16 bytes");
|
||||
EXPECT_EQ(16U, iv.size());
|
||||
EXPECT_TRUE(encryptor.Init(&key, crypto::Encryptor::CBC, iv));
|
||||
|
||||
std::string plaintext("this is the plaintext");
|
||||
std::string ciphertext;
|
||||
EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext));
|
||||
|
||||
static const auto expected_ciphertext = std::to_array<unsigned char>({
|
||||
0x7D, 0x67, 0x5B, 0x53, 0xE6, 0xD8, 0x0F, 0x27, 0x74, 0xB1, 0x90,
|
||||
0xFE, 0x6E, 0x58, 0x4A, 0xA0, 0x0E, 0x35, 0xE3, 0x01, 0xC0, 0xFE,
|
||||
0x9A, 0xD8, 0x48, 0x1D, 0x42, 0xB0, 0xBA, 0x21, 0xB2, 0x0C,
|
||||
});
|
||||
|
||||
ASSERT_EQ(std::size(expected_ciphertext), ciphertext.size());
|
||||
for (size_t i = 0; i < ciphertext.size(); ++i) {
|
||||
ASSERT_EQ(expected_ciphertext[i],
|
||||
static_cast<unsigned char>(ciphertext[i]));
|
||||
}
|
||||
|
||||
std::string decrypted;
|
||||
|
||||
// This wrong key causes the last padding byte to be 5, which is a valid
|
||||
// padding length, and the second to last padding byte to be 137, which is
|
||||
// invalid. If an implementation simply uses the last padding byte to
|
||||
// determine the padding length without checking every padding byte,
|
||||
// Encryptor::Decrypt() will still return true. This is the case for NSS
|
||||
// (crbug.com/124434).
|
||||
crypto::Encryptor decryptor;
|
||||
EXPECT_TRUE(decryptor.Init(&wrong_key, crypto::Encryptor::CBC, iv));
|
||||
EXPECT_FALSE(decryptor.Decrypt(ciphertext, &decrypted));
|
||||
|
||||
// This demonstrates that not all wrong keys can be detected by padding
|
||||
// error. This wrong key causes the last padding byte to be 1, which is
|
||||
// a valid padding block of length 1.
|
||||
crypto::Encryptor decryptor2;
|
||||
EXPECT_TRUE(decryptor2.Init(&wrong_key2, crypto::Encryptor::CBC, iv));
|
||||
EXPECT_TRUE(decryptor2.Decrypt(ciphertext, &decrypted));
|
||||
|
||||
// This wrong key causes the last padding byte to be 253, which should be
|
||||
// rejected by all implementations.
|
||||
crypto::Encryptor decryptor3;
|
||||
EXPECT_TRUE(decryptor3.Init(&wrong_key3, crypto::Encryptor::CBC, iv));
|
||||
EXPECT_FALSE(decryptor3.Decrypt(ciphertext, &decrypted));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
// From NIST SP 800-38a test cast:
|
||||
// - F.5.1 CTR-AES128.Encrypt
|
||||
// - F.5.6 CTR-AES256.Encrypt
|
||||
// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
|
||||
const unsigned char kAES128CTRKey[] = {
|
||||
0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
|
||||
0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
|
||||
};
|
||||
|
||||
const unsigned char kAES256CTRKey[] = {
|
||||
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe,
|
||||
0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
|
||||
0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7,
|
||||
0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4
|
||||
};
|
||||
|
||||
const unsigned char kAESCTRInitCounter[] = {
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
|
||||
0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
|
||||
};
|
||||
|
||||
const unsigned char kAESCTRPlaintext[] = {
|
||||
// Block #1
|
||||
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
|
||||
0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
|
||||
// Block #2
|
||||
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
|
||||
0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
|
||||
// Block #3
|
||||
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
|
||||
0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
|
||||
// Block #4
|
||||
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
|
||||
0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10
|
||||
};
|
||||
|
||||
const unsigned char kAES128CTRCiphertext[] = {
|
||||
// Block #1
|
||||
0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26,
|
||||
0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
|
||||
// Block #2
|
||||
0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff,
|
||||
0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
|
||||
// Block #3
|
||||
0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e,
|
||||
0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
|
||||
// Block #4
|
||||
0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1,
|
||||
0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee
|
||||
};
|
||||
|
||||
const unsigned char kAES256CTRCiphertext[] = {
|
||||
// Block #1
|
||||
0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5,
|
||||
0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
|
||||
// Block #2
|
||||
0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a,
|
||||
0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
|
||||
// Block #3
|
||||
0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c,
|
||||
0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
|
||||
// Block #4
|
||||
0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6,
|
||||
0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6
|
||||
};
|
||||
|
||||
void TestAESCTREncrypt(
|
||||
const unsigned char* key, size_t key_size,
|
||||
const unsigned char* init_counter, size_t init_counter_size,
|
||||
const unsigned char* plaintext, size_t plaintext_size,
|
||||
const unsigned char* ciphertext, size_t ciphertext_size) {
|
||||
std::string key_str(reinterpret_cast<const char*>(key), key_size);
|
||||
std::unique_ptr<crypto::SymmetricKey> sym_key(
|
||||
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key_str));
|
||||
ASSERT_TRUE(sym_key.get());
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CTR, ""));
|
||||
|
||||
std::string_view init_counter_str(reinterpret_cast<const char*>(init_counter),
|
||||
init_counter_size);
|
||||
std::string_view plaintext_str(reinterpret_cast<const char*>(plaintext),
|
||||
plaintext_size);
|
||||
|
||||
EXPECT_TRUE(encryptor.SetCounter(init_counter_str));
|
||||
std::string encrypted;
|
||||
EXPECT_TRUE(encryptor.Encrypt(plaintext_str, &encrypted));
|
||||
|
||||
EXPECT_EQ(ciphertext_size, encrypted.size());
|
||||
EXPECT_EQ(0, memcmp(encrypted.data(), ciphertext, encrypted.size()));
|
||||
|
||||
std::string decrypted;
|
||||
EXPECT_TRUE(encryptor.SetCounter(init_counter_str));
|
||||
EXPECT_TRUE(encryptor.Decrypt(encrypted, &decrypted));
|
||||
|
||||
EXPECT_EQ(plaintext_str, decrypted);
|
||||
|
||||
// Repeat the test with the bytes API.
|
||||
EXPECT_TRUE(
|
||||
encryptor.SetCounter(base::span(init_counter, init_counter_size)));
|
||||
std::vector<uint8_t> encrypted_vec;
|
||||
EXPECT_TRUE(
|
||||
encryptor.Encrypt(base::span(plaintext, plaintext_size), &encrypted_vec));
|
||||
|
||||
EXPECT_EQ(ciphertext_size, encrypted_vec.size());
|
||||
EXPECT_EQ(0, memcmp(encrypted_vec.data(), ciphertext, encrypted_vec.size()));
|
||||
|
||||
std::vector<uint8_t> decrypted_vec;
|
||||
EXPECT_TRUE(
|
||||
encryptor.SetCounter(base::span(init_counter, init_counter_size)));
|
||||
EXPECT_TRUE(encryptor.Decrypt(encrypted_vec, &decrypted_vec));
|
||||
|
||||
EXPECT_EQ(std::vector<uint8_t>(plaintext, plaintext + plaintext_size),
|
||||
decrypted_vec);
|
||||
}
|
||||
|
||||
void TestAESCTRMultipleDecrypt(
|
||||
const unsigned char* key, size_t key_size,
|
||||
const unsigned char* init_counter, size_t init_counter_size,
|
||||
const unsigned char* plaintext, size_t plaintext_size,
|
||||
const unsigned char* ciphertext, size_t ciphertext_size) {
|
||||
std::string key_str(reinterpret_cast<const char*>(key), key_size);
|
||||
std::unique_ptr<crypto::SymmetricKey> sym_key(
|
||||
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key_str));
|
||||
ASSERT_TRUE(sym_key.get());
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CTR, ""));
|
||||
|
||||
// Counter is set only once.
|
||||
EXPECT_TRUE(encryptor.SetCounter(std::string_view(
|
||||
reinterpret_cast<const char*>(init_counter), init_counter_size)));
|
||||
|
||||
std::string ciphertext_str(reinterpret_cast<const char*>(ciphertext),
|
||||
ciphertext_size);
|
||||
|
||||
auto kTestDecryptSizes = std::to_array<int>({32, 16, 8});
|
||||
|
||||
int offset = 0;
|
||||
for (size_t i = 0; i < std::size(kTestDecryptSizes); ++i) {
|
||||
std::string decrypted;
|
||||
size_t len = kTestDecryptSizes[i];
|
||||
EXPECT_TRUE(
|
||||
encryptor.Decrypt(ciphertext_str.substr(offset, len), &decrypted));
|
||||
EXPECT_EQ(len, decrypted.size());
|
||||
EXPECT_EQ(0, memcmp(decrypted.data(), plaintext + offset, len));
|
||||
offset += len;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(EncryptorTest, EncryptAES128CTR) {
|
||||
TestAESCTREncrypt(kAES128CTRKey, std::size(kAES128CTRKey), kAESCTRInitCounter,
|
||||
std::size(kAESCTRInitCounter), kAESCTRPlaintext,
|
||||
std::size(kAESCTRPlaintext), kAES128CTRCiphertext,
|
||||
std::size(kAES128CTRCiphertext));
|
||||
}
|
||||
|
||||
TEST(EncryptorTest, EncryptAES256CTR) {
|
||||
TestAESCTREncrypt(kAES256CTRKey, std::size(kAES256CTRKey), kAESCTRInitCounter,
|
||||
std::size(kAESCTRInitCounter), kAESCTRPlaintext,
|
||||
std::size(kAESCTRPlaintext), kAES256CTRCiphertext,
|
||||
std::size(kAES256CTRCiphertext));
|
||||
}
|
||||
|
||||
TEST(EncryptorTest, EncryptAES128CTR_MultipleDecrypt) {
|
||||
TestAESCTRMultipleDecrypt(kAES128CTRKey, std::size(kAES128CTRKey),
|
||||
kAESCTRInitCounter, std::size(kAESCTRInitCounter),
|
||||
kAESCTRPlaintext, std::size(kAESCTRPlaintext),
|
||||
kAES128CTRCiphertext,
|
||||
std::size(kAES128CTRCiphertext));
|
||||
}
|
||||
|
||||
TEST(EncryptorTest, EncryptAES256CTR_MultipleDecrypt) {
|
||||
TestAESCTRMultipleDecrypt(kAES256CTRKey, std::size(kAES256CTRKey),
|
||||
kAESCTRInitCounter, std::size(kAESCTRInitCounter),
|
||||
kAESCTRPlaintext, std::size(kAESCTRPlaintext),
|
||||
kAES256CTRCiphertext,
|
||||
std::size(kAES256CTRCiphertext));
|
||||
}
|
||||
|
||||
TEST(EncryptorTest, EncryptDecryptCTR) {
|
||||
std::unique_ptr<crypto::SymmetricKey> key(
|
||||
crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 128));
|
||||
|
||||
EXPECT_TRUE(key.get());
|
||||
const std::string kInitialCounter = "0000000000000000";
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
EXPECT_TRUE(encryptor.Init(key.get(), crypto::Encryptor::CTR, ""));
|
||||
EXPECT_TRUE(encryptor.SetCounter(kInitialCounter));
|
||||
|
||||
std::string plaintext("normal plaintext of random length");
|
||||
std::string ciphertext;
|
||||
EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext));
|
||||
EXPECT_LT(0U, ciphertext.size());
|
||||
|
||||
std::string decrypted;
|
||||
EXPECT_TRUE(encryptor.SetCounter(kInitialCounter));
|
||||
EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted));
|
||||
EXPECT_EQ(plaintext, decrypted);
|
||||
|
||||
plaintext = "0123456789012345";
|
||||
EXPECT_TRUE(encryptor.SetCounter(kInitialCounter));
|
||||
EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext));
|
||||
EXPECT_LT(0U, ciphertext.size());
|
||||
|
||||
EXPECT_TRUE(encryptor.SetCounter(kInitialCounter));
|
||||
EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted));
|
||||
EXPECT_EQ(plaintext, decrypted);
|
||||
}
|
||||
|
||||
// TODO(wtc): add more known-answer tests. Test vectors are available from
|
||||
// http://www.ietf.org/rfc/rfc3602
|
||||
// http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf
|
||||
// http://gladman.plushost.co.uk/oldsite/AES/index.php
|
||||
// http://csrc.nist.gov/groups/STM/cavp/documents/aes/KAT_AES.zip
|
||||
|
||||
// NIST SP 800-38A test vector F.2.5 CBC-AES256.Encrypt.
|
||||
TEST(EncryptorTest, EncryptAES256CBC) {
|
||||
// From NIST SP 800-38a test cast F.2.5 CBC-AES256.Encrypt.
|
||||
static const auto kRawKey = std::to_array<unsigned char>({
|
||||
0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae,
|
||||
0xf0, 0x85, 0x7d, 0x77, 0x81, 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61,
|
||||
0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
|
||||
});
|
||||
static const auto kRawIv = std::to_array<unsigned char>(
|
||||
{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0c, 0x0d, 0x0e, 0x0f});
|
||||
static const auto kRawPlaintext = std::to_array<unsigned char>(
|
||||
{// Block #1
|
||||
0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11,
|
||||
0x73, 0x93, 0x17, 0x2a,
|
||||
// Block #2
|
||||
0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac,
|
||||
0x45, 0xaf, 0x8e, 0x51,
|
||||
// Block #3
|
||||
0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19,
|
||||
0x1a, 0x0a, 0x52, 0xef,
|
||||
// Block #4
|
||||
0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b,
|
||||
0xe6, 0x6c, 0x37, 0x10});
|
||||
static const auto kRawCiphertext = std::to_array<unsigned char>(
|
||||
{// Block #1
|
||||
0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb,
|
||||
0x5f, 0x7b, 0xfb, 0xd6,
|
||||
// Block #2
|
||||
0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b,
|
||||
0xc6, 0x70, 0x2c, 0x7d,
|
||||
// Block #3
|
||||
0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63,
|
||||
0x04, 0x23, 0x14, 0x61,
|
||||
// Block #4
|
||||
0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07,
|
||||
0x8c, 0x6a, 0x9d, 0x1b,
|
||||
// PKCS #5 padding, encrypted.
|
||||
0x3f, 0x46, 0x17, 0x96, 0xd6, 0xb0, 0xd6, 0xb2, 0xe0, 0xc2, 0xa7, 0x2b,
|
||||
0x4d, 0x80, 0xe6, 0x44});
|
||||
|
||||
std::string key(reinterpret_cast<const char*>(kRawKey.data()),
|
||||
sizeof(kRawKey));
|
||||
std::unique_ptr<crypto::SymmetricKey> sym_key(
|
||||
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key));
|
||||
ASSERT_TRUE(sym_key.get());
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
// The IV must be exactly as long a the cipher block size.
|
||||
std::string iv(reinterpret_cast<const char*>(kRawIv.data()), sizeof(kRawIv));
|
||||
EXPECT_EQ(16U, iv.size());
|
||||
EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv));
|
||||
|
||||
std::string plaintext(reinterpret_cast<const char*>(kRawPlaintext.data()),
|
||||
sizeof(kRawPlaintext));
|
||||
std::string ciphertext;
|
||||
EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext));
|
||||
|
||||
EXPECT_EQ(sizeof(kRawCiphertext), ciphertext.size());
|
||||
EXPECT_EQ(
|
||||
0, memcmp(ciphertext.data(), kRawCiphertext.data(), ciphertext.size()));
|
||||
|
||||
std::string decrypted;
|
||||
EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted));
|
||||
|
||||
EXPECT_EQ(plaintext, decrypted);
|
||||
}
|
||||
|
||||
// Expected output derived from the NSS implementation.
|
||||
TEST(EncryptorTest, EncryptAES128CBCRegression) {
|
||||
std::string key = "128=SixteenBytes";
|
||||
std::string iv = "Sweet Sixteen IV";
|
||||
std::string plaintext = "Plain text with a g-clef U+1D11E \360\235\204\236";
|
||||
std::string expected_ciphertext_hex =
|
||||
"D4A67A0BA33C30F207344D81D1E944BBE65587C3D7D9939A"
|
||||
"C070C62B9C15A3EA312EA4AD1BC7929F4D3C16B03AD5ADA8";
|
||||
|
||||
std::unique_ptr<crypto::SymmetricKey> sym_key(
|
||||
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key));
|
||||
ASSERT_TRUE(sym_key.get());
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
// The IV must be exactly as long a the cipher block size.
|
||||
EXPECT_EQ(16U, iv.size());
|
||||
EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv));
|
||||
|
||||
std::string ciphertext;
|
||||
EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext));
|
||||
EXPECT_EQ(expected_ciphertext_hex, base::HexEncode(ciphertext));
|
||||
|
||||
std::string decrypted;
|
||||
EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted));
|
||||
EXPECT_EQ(plaintext, decrypted);
|
||||
}
|
||||
|
||||
// Symmetric keys with an unsupported size should be rejected. Whether they are
|
||||
// rejected by SymmetricKey::Import or Encryptor::Init depends on the platform.
|
||||
TEST(EncryptorTest, UnsupportedKeySize) {
|
||||
std::string key = "7 = bad";
|
||||
std::string iv = "Sweet Sixteen IV";
|
||||
std::unique_ptr<crypto::SymmetricKey> sym_key(
|
||||
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key));
|
||||
if (!sym_key.get())
|
||||
return;
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
// The IV must be exactly as long as the cipher block size.
|
||||
EXPECT_EQ(16U, iv.size());
|
||||
EXPECT_FALSE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv));
|
||||
}
|
||||
|
||||
TEST(EncryptorTest, UnsupportedIV) {
|
||||
std::string key = "128=SixteenBytes";
|
||||
std::string iv = "OnlyForteen :(";
|
||||
std::unique_ptr<crypto::SymmetricKey> sym_key(
|
||||
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key));
|
||||
ASSERT_TRUE(sym_key.get());
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
EXPECT_FALSE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv));
|
||||
}
|
||||
|
||||
TEST(EncryptorTest, EmptyEncryptCBC) {
|
||||
std::string key = "128=SixteenBytes";
|
||||
std::string iv = "Sweet Sixteen IV";
|
||||
std::string plaintext;
|
||||
std::string expected_ciphertext_hex = "8518B8878D34E7185E300D0FCC426396";
|
||||
|
||||
std::unique_ptr<crypto::SymmetricKey> sym_key(
|
||||
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key));
|
||||
ASSERT_TRUE(sym_key.get());
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
// The IV must be exactly as long as the cipher block size.
|
||||
EXPECT_EQ(16U, iv.size());
|
||||
EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv));
|
||||
|
||||
std::string ciphertext;
|
||||
EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext));
|
||||
EXPECT_EQ(expected_ciphertext_hex, base::HexEncode(ciphertext));
|
||||
|
||||
std::string decrypted;
|
||||
EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted));
|
||||
EXPECT_EQ(decrypted, plaintext);
|
||||
|
||||
// Decrypting the empty string should fail. Our formulation of CBC expects a
|
||||
// full block of padding for CBC.
|
||||
EXPECT_FALSE(encryptor.Decrypt(std::string(), &decrypted));
|
||||
|
||||
// Repeat the test with the byte-based API.
|
||||
EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv));
|
||||
std::vector<uint8_t> ciphertext_bytes;
|
||||
EXPECT_TRUE(
|
||||
encryptor.Encrypt(base::span<const uint8_t>(), &ciphertext_bytes));
|
||||
EXPECT_EQ(expected_ciphertext_hex, base::HexEncode(ciphertext_bytes));
|
||||
|
||||
std::vector<uint8_t> decrypted_bytes;
|
||||
EXPECT_TRUE(encryptor.Decrypt(ciphertext_bytes, &decrypted_bytes));
|
||||
EXPECT_EQ(decrypted_bytes.size(), 0u);
|
||||
|
||||
// Decrypting the empty string should fail. Our formulation of CBC expects a
|
||||
// full block of padding for CBC.
|
||||
EXPECT_FALSE(
|
||||
encryptor.Decrypt(base::span<const uint8_t>(), &decrypted_bytes));
|
||||
}
|
||||
|
||||
TEST(EncryptorTest, EmptyEncryptCTR) {
|
||||
std::string key = "128=SixteenBytes";
|
||||
std::string iv = "Sweet Sixteen IV";
|
||||
std::string plaintext;
|
||||
std::string expected_ciphertext;
|
||||
|
||||
std::unique_ptr<crypto::SymmetricKey> sym_key(
|
||||
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key));
|
||||
ASSERT_TRUE(sym_key.get());
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CTR, ""));
|
||||
ASSERT_TRUE(encryptor.SetCounter(iv));
|
||||
|
||||
std::string ciphertext;
|
||||
EXPECT_TRUE(encryptor.Encrypt(plaintext, &ciphertext));
|
||||
EXPECT_EQ(expected_ciphertext, ciphertext);
|
||||
|
||||
std::string decrypted;
|
||||
EXPECT_TRUE(encryptor.Decrypt(ciphertext, &decrypted));
|
||||
EXPECT_EQ(decrypted, plaintext);
|
||||
|
||||
// Repeat the test with the byte-based API.
|
||||
ASSERT_TRUE(encryptor.SetCounter(iv));
|
||||
std::vector<uint8_t> ciphertext_bytes;
|
||||
EXPECT_TRUE(
|
||||
encryptor.Encrypt(base::span<const uint8_t>(), &ciphertext_bytes));
|
||||
EXPECT_EQ(ciphertext_bytes.size(), 0u);
|
||||
|
||||
std::vector<uint8_t> decrypted_bytes;
|
||||
EXPECT_TRUE(encryptor.Decrypt(base::span<const uint8_t>(), &decrypted_bytes));
|
||||
EXPECT_EQ(decrypted_bytes.size(), 0u);
|
||||
}
|
||||
|
||||
TEST(EncryptorTest, CipherTextNotMultipleOfBlockSize) {
|
||||
std::string key = "128=SixteenBytes";
|
||||
std::string iv = "Sweet Sixteen IV";
|
||||
|
||||
std::unique_ptr<crypto::SymmetricKey> sym_key(
|
||||
crypto::SymmetricKey::Import(crypto::SymmetricKey::AES, key));
|
||||
ASSERT_TRUE(sym_key.get());
|
||||
|
||||
crypto::Encryptor encryptor;
|
||||
// The IV must be exactly as long a the cipher block size.
|
||||
EXPECT_EQ(16U, iv.size());
|
||||
EXPECT_TRUE(encryptor.Init(sym_key.get(), crypto::Encryptor::CBC, iv));
|
||||
|
||||
// Use a separately allocated array to improve the odds of the memory tools
|
||||
// catching invalid accesses.
|
||||
//
|
||||
// Otherwise when using std::string as the other tests do, accesses several
|
||||
// bytes off the end of the buffer may fall inside the reservation of
|
||||
// the string and not be detected.
|
||||
auto ciphertext = base::HeapArray<char>::Uninit(1);
|
||||
|
||||
std::string plaintext;
|
||||
EXPECT_FALSE(
|
||||
encryptor.Decrypt(base::as_string_view(ciphertext), &plaintext));
|
||||
}
|
@ -26,8 +26,7 @@ namespace crypto {
|
||||
// TODO(https://issues.chromium.org/issues/370724578): get rid of this.
|
||||
class CRYPTO_EXPORT SymmetricKey {
|
||||
public:
|
||||
// Defines the algorithm that a key will be used with. See also
|
||||
// class Encryptor.
|
||||
// Defines the algorithm that a key will be used with.
|
||||
enum Algorithm {
|
||||
AES,
|
||||
};
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "base/task/sequenced_task_runner.h"
|
||||
#include "base/threading/sequence_bound.h"
|
||||
#include "base/time/time.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "media/base/media_export.h"
|
||||
#include "media/base/media_log.h"
|
||||
#include "media/base/media_track.h"
|
||||
|
Reference in New Issue
Block a user