1 /*
2 * Copyright 2018 Google LLC
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "fcp/secagg/shared/aes_gcm_encryption.h"
18
19 #include <cstdint>
20 #include <string>
21
22 #include "fcp/base/monitoring.h"
23 #include "fcp/secagg/shared/aes_key.h"
24 #include "fcp/secagg/shared/prng.h"
25 #include "openssl/cipher.h"
26 #include "openssl/evp.h"
27 #include "openssl/rand.h"
28
29 namespace fcp {
30 namespace secagg {
31
32 constexpr int kIvSize = 12;
33 constexpr int kTagSize = 16;
34
AesGcmEncryption()35 AesGcmEncryption::AesGcmEncryption() {}
36
Encrypt(const AesKey & key,const std::string & plaintext)37 std::string AesGcmEncryption::Encrypt(const AesKey& key,
38 const std::string& plaintext) {
39 FCP_CHECK(key.size() != 0) << "Encrypt called with blank key.";
40 FCP_CHECK(key.size() == AesKey::kSize)
41 << "Encrypt called with key of " << key.size()
42 << " bytes, but 32 bytes are required.";
43 std::vector<uint8_t> ciphertext_buffer;
44 ciphertext_buffer.resize(kIvSize + plaintext.length() + kTagSize);
45 FCP_CHECK(RAND_bytes(ciphertext_buffer.data(), kIvSize));
46
47 // ScopedEVP_AEAD_CTX will automatically call EVP_AEAD_CTX_cleanup when going
48 // out of scope.
49 bssl::ScopedEVP_AEAD_CTX ctx;
50 FCP_CHECK(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_256_gcm(),
51 const_cast<uint8_t*>(key.data()), key.size(),
52 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr) == 1);
53 size_t len;
54 FCP_CHECK(EVP_AEAD_CTX_seal(
55 ctx.get(), ciphertext_buffer.data() + kIvSize, &len,
56 plaintext.size() + kTagSize, ciphertext_buffer.data(), kIvSize,
57 reinterpret_cast<const uint8_t*>(plaintext.c_str()),
58 plaintext.size(), nullptr, 0) == 1);
59 return std::string(ciphertext_buffer.begin(), ciphertext_buffer.end());
60 }
61
Decrypt(const AesKey & key,const std::string & ciphertext)62 StatusOr<std::string> AesGcmEncryption::Decrypt(const AesKey& key,
63 const std::string& ciphertext) {
64 FCP_CHECK(key.size() != 0) << "Decrypt called with blank key.";
65 FCP_CHECK(key.size() == AesKey::kSize)
66 << "Decrypt called with key of " << key.size()
67 << " bytes, but 32 bytes are required.";
68 if (ciphertext.size() < kIvSize + kTagSize) {
69 return FCP_STATUS(DATA_LOSS) << "Ciphertext is too short.";
70 }
71 size_t len;
72 std::vector<uint8_t> plaintext_buffer;
73 plaintext_buffer.resize(ciphertext.size() - kIvSize - kTagSize);
74
75 // ScopedEVP_AEAD_CTX will automatically call EVP_AEAD_CTX_cleanup when going
76 // out of scope.
77 bssl::ScopedEVP_AEAD_CTX ctx;
78 FCP_CHECK(EVP_AEAD_CTX_init(ctx.get(), EVP_aead_aes_256_gcm(),
79 const_cast<uint8_t*>(key.data()), key.size(),
80 EVP_AEAD_DEFAULT_TAG_LENGTH, nullptr) == 1);
81 if (EVP_AEAD_CTX_open(
82 ctx.get(), plaintext_buffer.data(), &len, plaintext_buffer.size(),
83 reinterpret_cast<const uint8_t*>(ciphertext.data()), kIvSize,
84 reinterpret_cast<const uint8_t*>(ciphertext.data() + kIvSize),
85 ciphertext.size() - kIvSize, nullptr, 0) != 1) {
86 return FCP_STATUS(DATA_LOSS) << "Verification of ciphertext failed.";
87 }
88 return std::string(plaintext_buffer.begin(), plaintext_buffer.end());
89 }
90
91 } // namespace secagg
92 } // namespace fcp
93