|  | // Copyright 2018 The Fuchsia 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 "src/ledger/bin/encryption/primitives/encrypt.h" | 
|  |  | 
|  | #include <zircon/syscalls.h> | 
|  |  | 
|  | #include <openssl/aead.h> | 
|  |  | 
|  | #include "src/ledger/lib/rng/random.h" | 
|  | #include "third_party/abseil-cpp/absl/strings/string_view.h" | 
|  |  | 
|  | namespace encryption { | 
|  |  | 
|  | bool AES128GCMSIVEncrypt(ledger::Random* random, absl::string_view key, absl::string_view data, | 
|  | std::string* output) { | 
|  | if (key.size() != 16) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const EVP_AEAD* algorithm = EVP_aead_aes_128_gcm_siv(); | 
|  |  | 
|  | const size_t kNonceOffset = 0; | 
|  | const size_t kNonceSize = EVP_AEAD_nonce_length(algorithm); | 
|  | const size_t kTagOffset = kNonceOffset + kNonceSize; | 
|  | const size_t kTagSize = EVP_AEAD_max_tag_len(algorithm); | 
|  | const size_t kEncryptedDataOffset = kTagOffset + kTagSize; | 
|  |  | 
|  | bssl::ScopedEVP_AEAD_CTX ctx; | 
|  | if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), algorithm, | 
|  | reinterpret_cast<const uint8_t*>(key.data()), key.size(), | 
|  | EVP_AEAD_DEFAULT_TAG_LENGTH, evp_aead_seal)) { | 
|  | return false; | 
|  | } | 
|  | std::string result; | 
|  | result.resize(kEncryptedDataOffset + data.size() + EVP_AEAD_max_overhead(algorithm)); | 
|  | uint8_t* result_as_int8_ptr = reinterpret_cast<uint8_t*>(&result[0]); | 
|  |  | 
|  | // Generate seed. | 
|  | random->Draw(&result[0], EVP_AEAD_nonce_length(algorithm)); | 
|  |  | 
|  | size_t out_len; | 
|  | if (EVP_AEAD_CTX_seal(ctx.get(), &result_as_int8_ptr[kEncryptedDataOffset], &out_len, | 
|  | data.size() + EVP_AEAD_max_overhead(algorithm), | 
|  | &result_as_int8_ptr[kNonceOffset], kNonceSize, | 
|  | reinterpret_cast<const uint8_t*>(data.data()), data.size(), | 
|  | &result_as_int8_ptr[kTagOffset], kTagSize) == 0) { | 
|  | return false; | 
|  | } | 
|  | result.resize(kEncryptedDataOffset + out_len); | 
|  | output->swap(result); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool AES128GCMSIVDecrypt(absl::string_view key, absl::string_view encrypted_data, | 
|  | std::string* output) { | 
|  | if (key.size() != 16) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const EVP_AEAD* algorithm = EVP_aead_aes_128_gcm_siv(); | 
|  |  | 
|  | const size_t kNonceOffset = 0; | 
|  | const size_t kNonceSize = EVP_AEAD_nonce_length(algorithm); | 
|  | const size_t kTagOffset = kNonceOffset + kNonceSize; | 
|  | const size_t kTagSize = EVP_AEAD_max_tag_len(algorithm); | 
|  | const size_t kEncryptedDataOffset = kTagOffset + kTagSize; | 
|  | if (encrypted_data.size() < kEncryptedDataOffset) { | 
|  | return false; | 
|  | } | 
|  | const size_t kEncryptedDataSize = encrypted_data.size() - kEncryptedDataOffset; | 
|  |  | 
|  | bssl::ScopedEVP_AEAD_CTX ctx; | 
|  | if (!EVP_AEAD_CTX_init_with_direction(ctx.get(), algorithm, | 
|  | reinterpret_cast<const uint8_t*>(key.data()), key.size(), | 
|  | EVP_AEAD_DEFAULT_TAG_LENGTH, evp_aead_open)) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const uint8_t* encrypted_data_as_uint8_ptr = | 
|  | reinterpret_cast<const uint8_t*>(encrypted_data.data()); | 
|  |  | 
|  | std::string result; | 
|  | result.resize(kEncryptedDataSize); | 
|  |  | 
|  | size_t out_len; | 
|  | if (EVP_AEAD_CTX_open(ctx.get(), reinterpret_cast<uint8_t*>(&result[0]), &out_len, result.size(), | 
|  | &encrypted_data_as_uint8_ptr[kNonceOffset], kNonceSize, | 
|  | &encrypted_data_as_uint8_ptr[kEncryptedDataOffset], kEncryptedDataSize, | 
|  | &encrypted_data_as_uint8_ptr[kTagOffset], kTagSize) == 0) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | result.resize(out_len); | 
|  | output->swap(result); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | }  // namespace encryption |