diff options
author | Joshua Duong <joshuaduong@google.com> | 2020-03-23 11:01:25 -0700 |
---|---|---|
committer | Joshua Duong <joshuaduong@google.com> | 2020-03-26 02:14:48 +0000 |
commit | 94b85e133f203b6193ebe71e216ec34ca47a6d7b (patch) | |
tree | 2fa799acb1c23ecb37d29d836ffbbc241f45a483 /pairing_auth/aes_128_gcm.cpp | |
parent | de8af9bf71aadf95e7550d95a7b8091d716fc9ff (diff) | |
download | adb-94b85e133f203b6193ebe71e216ec34ca47a6d7b.tar.gz |
Fix pairing aes_128_gcm key initialization.
Bug: 150719467
Test: atest adb_pairing_auth_test
Test: check 'adb pair' command on all three platforms work
Change-Id: Idfc64fe7bed2d09f4da9d2f7df70f9d6ae4e8fa3
Exempt-From-Owner-Approval: approved in go/ag/10808153
Diffstat (limited to 'pairing_auth/aes_128_gcm.cpp')
-rw-r--r-- | pairing_auth/aes_128_gcm.cpp | 166 |
1 files changed, 37 insertions, 129 deletions
diff --git a/pairing_auth/aes_128_gcm.cpp b/pairing_auth/aes_128_gcm.cpp index 2978834d..51520d81 100644 --- a/pairing_auth/aes_128_gcm.cpp +++ b/pairing_auth/aes_128_gcm.cpp @@ -19,7 +19,6 @@ #include <android-base/endian.h> #include <android-base/logging.h> -#include <openssl/crypto.h> #include <openssl/evp.h> #include <openssl/hkdf.h> #include <openssl/rand.h> @@ -28,155 +27,64 @@ namespace adb { namespace pairing { namespace { -static const size_t kHkdfKeyLength = 256; - -struct Header { - uint32_t payload; - uint8_t iv[AES_128_GCM_IV_SIZE]; - uint8_t tag[AES_128_GCM_TAG_SIZE]; -} __attribute__((packed)); +// Size of AES-128-GCM key, in bytes +static constexpr size_t kHkdfKeyLength = 16; } // namespace -// static -const EVP_CIPHER* Aes128Gcm::cipher_ = EVP_aes_128_gcm(); - Aes128Gcm::Aes128Gcm(const uint8_t* key_material, size_t key_material_len) { CHECK(key_material); CHECK_NE(key_material_len, 0ul); - context_.reset(EVP_CIPHER_CTX_new()); - CHECK(context_.get()); - - // Start with a random number for our counter - CHECK_EQ(RAND_bytes(counter_.data(), counter_.size()), 1); - uint8_t key[kHkdfKeyLength] = {}; - uint8_t salt[64] = "this is the salt"; - uint8_t info[64] = "this is the info"; - CHECK_EQ(HKDF(key, sizeof(key), EVP_sha256(), key_material, key_material_len, salt, - sizeof(salt), info, sizeof(info)), + uint8_t key[kHkdfKeyLength]; + uint8_t info[] = "adb pairing_auth aes-128-gcm key"; + CHECK_EQ(HKDF(key, sizeof(key), EVP_sha256(), key_material, key_material_len, nullptr, 0, info, + sizeof(info) - 1), 1); - CHECK_EQ(AES_set_encrypt_key(key, sizeof(key), &aes_key_), 0); + CHECK(EVP_AEAD_CTX_init(context_.get(), EVP_aead_aes_128_gcm(), key, sizeof(key), + EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)); } -int Aes128Gcm::Encrypt(const uint8_t* in, size_t in_len, uint8_t* out, size_t out_len) { - if (out_len < EncryptedSize(in_len)) { - LOG(ERROR) << "out buffer size (sz=" << out_len - << ") not big enough (sz=" << EncryptedSize(in_len) << ")"; - return -1; - } - auto& header = *reinterpret_cast<Header*>(out); - // Place the IV in the header - memcpy(header.iv, counter_.data(), counter_.size()); - int status = EVP_EncryptInit_ex(context_.get(), cipher_, nullptr, - reinterpret_cast<const uint8_t*>(&aes_key_), counter_.data()); - counter_.Increase(); - if (status != 1) { - return -1; - } - - int cipherLen = 0; - out += sizeof(header); - status = EVP_EncryptUpdate(context_.get(), out, &cipherLen, in, in_len); - if (status != 1 || cipherLen < 0) { - return -1; +std::optional<size_t> Aes128Gcm::Encrypt(const uint8_t* in, size_t in_len, uint8_t* out, + size_t out_len) { + std::vector<uint8_t> nonce(EVP_AEAD_nonce_length(EVP_AEAD_CTX_aead(context_.get())), 0); + memcpy(nonce.data(), &enc_sequence_, sizeof(enc_sequence_)); + size_t written_sz; + if (!EVP_AEAD_CTX_seal(context_.get(), out, &written_sz, out_len, nonce.data(), nonce.size(), + in, in_len, nullptr, 0)) { + LOG(ERROR) << "Failed to encrypt (in_len=" << in_len << ", out_len=" << out_len + << ", out_len_needed=" << EncryptedSize(in_len) << ")"; + return std::nullopt; } - // Padding is enabled by default, so EVP_EncryptFinal_ex will pad any - // remaining partial data up to the block size. - int padding = 0; - status = EVP_EncryptFinal_ex(context_.get(), out + cipherLen, &padding); - if (status != 1 || padding < 0) { - return -1; - } - - // Place the tag in the header - status = EVP_CIPHER_CTX_ctrl(context_.get(), EVP_CTRL_GCM_GET_TAG, sizeof(header.tag), - header.tag); - if (status != 1) { - return -1; - } - // Place the payload size in the header - uint32_t totalLen = sizeof(header) + cipherLen + padding; - header.payload = htonl(static_cast<uint32_t>(cipherLen) + static_cast<uint32_t>(padding)); - return totalLen; + ++enc_sequence_; + return written_sz; } -int Aes128Gcm::Decrypt(const uint8_t* in, size_t in_len, uint8_t* out, size_t out_len) { - if (in_len < sizeof(Header)) { - return 0; - } - if (out_len < DecryptedSize(in, in_len)) { - return 0; - } - const auto& header = *reinterpret_cast<const Header*>(in); - uint32_t payload = ntohl(header.payload); - uint32_t expected_inlen = sizeof(Header) + payload; - if (in_len < expected_inlen) { - // Not enough data available - return 0; - } - // Initialized with expected IV from header - int status = EVP_DecryptInit_ex(context_.get(), cipher_, nullptr, - reinterpret_cast<const uint8_t*>(&aes_key_), header.iv); - if (status != 1) { - return -1; - } - - int decrypted_len = 0; - status = EVP_DecryptUpdate(context_.get(), out, &decrypted_len, in + sizeof(header), payload); - if (status != 1 || decrypted_len < 0) { - return -1; - } - - // Set expected tag from header - status = EVP_CIPHER_CTX_ctrl(context_.get(), EVP_CTRL_GCM_SET_TAG, sizeof(header.tag), - const_cast<uint8_t*>(header.tag)); - if (status != 1) { - return -1; +std::optional<size_t> Aes128Gcm::Decrypt(const uint8_t* in, size_t in_len, uint8_t* out, + size_t out_len) { + std::vector<uint8_t> nonce(EVP_AEAD_nonce_length(EVP_AEAD_CTX_aead(context_.get())), 0); + memcpy(nonce.data(), &dec_sequence_, sizeof(dec_sequence_)); + size_t written_sz; + if (!EVP_AEAD_CTX_open(context_.get(), out, &written_sz, out_len, nonce.data(), nonce.size(), + in, in_len, nullptr, 0)) { + LOG(ERROR) << "Failed to decrypt (in_len=" << in_len << ", out_len=" << out_len + << ", out_len_needed=" << DecryptedSize(in_len) << ")"; + return std::nullopt; } - // This is the padding. It can be ignored. - int len = 0; - status = EVP_DecryptFinal_ex(context_.get(), out + decrypted_len, &len); - if (status != 1) { - LOG(ERROR) << "EVP_DecryptFinal_ex failed. Tag mismatch"; - return -1; - } - - // Return the length without the padding. - return decrypted_len; + ++dec_sequence_; + return written_sz; } size_t Aes128Gcm::EncryptedSize(size_t size) { - // We need to account for block alignment of the encrypted data. - // According to openssl.org/docs/man1.0.2/man3/EVP_EncryptUpdate.html, - // "The amount of data written depends on the block alignment of the - // encrypted data ..." - // ".. the amount of data written may be anything from zero bytes to - // (inl + cipher_block_size - 1) ..." - const size_t cipher_block_size = EVP_CIPHER_block_size(cipher_); - size_t padding = cipher_block_size - (size % cipher_block_size); - if (padding != cipher_block_size) { - size += padding; - } - return size + sizeof(Header); + // https://commondatastorage.googleapis.com/chromium-boringssl-docs/aead.h.html#EVP_AEAD_CTX_seal + return size + EVP_AEAD_max_overhead(EVP_AEAD_CTX_aead(context_.get())); } -size_t Aes128Gcm::DecryptedSize(const uint8_t* encrypted_data, size_t encrypted_size) { - if (encrypted_size < sizeof(Header)) { - // Not enough data yet - return 0; - } - auto header = reinterpret_cast<const Header*>(encrypted_data); - uint32_t payload = ntohl(header->payload); - size_t total_size = payload + sizeof(Header); - if (encrypted_size < total_size) { - // There's enough data for the header but not enough data for the - // payload. Indicate that there's not enough data for now. - return 0; - } - return payload; +size_t Aes128Gcm::DecryptedSize(size_t size) { + // https://commondatastorage.googleapis.com/chromium-boringssl-docs/aead.h.html#EVP_AEAD_CTX_open + return size; } } // namespace pairing |