blob: be6ea52b4519bb14f3cfaf6163a41fcfa2ec8387 [file] [log] [blame]
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "crypto/aead.h"
#include <stddef.h>
#include <stdint.h>
#include <string>
#include "base/strings/string_util.h"
#include "crypto/openssl_util.h"
#include "third_party/boringssl/src/include/openssl/aes.h"
#include "third_party/boringssl/src/include/openssl/evp.h"
namespace crypto {
Aead::Aead(AeadAlgorithm algorithm) : key_(nullptr) {
EnsureOpenSSLInit();
switch (algorithm) {
case AES_128_CTR_HMAC_SHA256:
aead_ = EVP_aead_aes_128_ctr_hmac_sha256();
break;
case AES_256_GCM:
aead_ = EVP_aead_aes_256_gcm();
break;
case AES_256_GCM_SIV:
aead_ = EVP_aead_aes_256_gcm_siv();
break;
}
}
Aead::~Aead() = default;
void Aead::Init(const std::string* key) {
DCHECK(!key_);
DCHECK_EQ(KeyLength(), key->size());
key_ = key;
}
bool Aead::Seal(base::StringPiece plaintext,
base::StringPiece nonce,
base::StringPiece additional_data,
std::string* ciphertext) const {
DCHECK(key_);
DCHECK_EQ(NonceLength(), nonce.size());
EVP_AEAD_CTX ctx;
if (!EVP_AEAD_CTX_init(&ctx, aead_,
reinterpret_cast<const uint8_t*>(key_->data()),
key_->size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) {
return false;
}
std::string result;
const size_t max_output_length =
EVP_AEAD_max_overhead(aead_) + plaintext.size();
size_t output_length;
uint8_t* out_ptr = reinterpret_cast<uint8_t*>(
base::WriteInto(&result, max_output_length + 1));
if (!EVP_AEAD_CTX_seal(
&ctx, out_ptr, &output_length, max_output_length,
reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(),
reinterpret_cast<const uint8_t*>(plaintext.data()), plaintext.size(),
reinterpret_cast<const uint8_t*>(additional_data.data()),
additional_data.size())) {
EVP_AEAD_CTX_cleanup(&ctx);
return false;
}
DCHECK_LE(output_length, max_output_length);
result.resize(output_length);
ciphertext->swap(result);
EVP_AEAD_CTX_cleanup(&ctx);
return true;
}
bool Aead::Open(base::StringPiece ciphertext,
base::StringPiece nonce,
base::StringPiece additional_data,
std::string* plaintext) const {
DCHECK(key_);
EVP_AEAD_CTX ctx;
if (!EVP_AEAD_CTX_init(&ctx, aead_,
reinterpret_cast<const uint8_t*>(key_->data()),
key_->size(), EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr)) {
return false;
}
std::string result;
const size_t max_output_length = ciphertext.size();
size_t output_length;
uint8_t* out_ptr = reinterpret_cast<uint8_t*>(
base::WriteInto(&result, max_output_length + 1));
if (!EVP_AEAD_CTX_open(
&ctx, out_ptr, &output_length, max_output_length,
reinterpret_cast<const uint8_t*>(nonce.data()), nonce.size(),
reinterpret_cast<const uint8_t*>(ciphertext.data()),
ciphertext.size(),
reinterpret_cast<const uint8_t*>(additional_data.data()),
additional_data.size())) {
EVP_AEAD_CTX_cleanup(&ctx);
return false;
}
DCHECK_LE(output_length, max_output_length);
result.resize(output_length);
plaintext->swap(result);
EVP_AEAD_CTX_cleanup(&ctx);
return true;
}
size_t Aead::KeyLength() const {
return EVP_AEAD_key_length(aead_);
}
size_t Aead::NonceLength() const {
return EVP_AEAD_nonce_length(aead_);
}
} // namespace crypto