1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "crypto/aes_cbc.h"
6
7 #include "crypto/openssl_util.h"
8 #include "third_party/boringssl/src/include/openssl/aes.h"
9 #include "third_party/boringssl/src/include/openssl/evp.h"
10
11 namespace crypto::aes_cbc {
12
Encrypt(base::span<const uint8_t> key,base::span<const uint8_t,kBlockSize> iv,base::span<const uint8_t> plaintext)13 std::vector<uint8_t> Encrypt(base::span<const uint8_t> key,
14 base::span<const uint8_t, kBlockSize> iv,
15 base::span<const uint8_t> plaintext) {
16 const EVP_CIPHER* cipher =
17 key.size() == 32 ? EVP_aes_256_cbc() : EVP_aes_128_cbc();
18
19 CHECK_EQ(EVP_CIPHER_key_length(cipher), key.size());
20
21 OpenSSLErrStackTracer err_tracer(FROM_HERE);
22 bssl::ScopedEVP_CIPHER_CTX ctx;
23 CHECK(EVP_EncryptInit_ex(ctx.get(), cipher, nullptr, key.data(), iv.data()));
24
25 std::vector<uint8_t> ciphertext(plaintext.size() + kBlockSize);
26
27 int out_len;
28 CHECK(EVP_EncryptUpdate(ctx.get(), ciphertext.data(), &out_len,
29 plaintext.data(), plaintext.size()));
30
31 int tail_len;
32 CHECK(EVP_EncryptFinal_ex(ctx.get(),
33 // SAFETY: boringssl guarantees out_len is still
34 // inside ciphertext.
35 UNSAFE_BUFFERS(ciphertext.data() + out_len),
36 &tail_len));
37 ciphertext.resize(out_len + tail_len);
38 return ciphertext;
39 }
40
Decrypt(base::span<const uint8_t> key,base::span<const uint8_t,kBlockSize> iv,base::span<const uint8_t> ciphertext)41 std::optional<std::vector<uint8_t>> Decrypt(
42 base::span<const uint8_t> key,
43 base::span<const uint8_t, kBlockSize> iv,
44 base::span<const uint8_t> ciphertext) {
45 const EVP_CIPHER* cipher =
46 key.size() == 32 ? EVP_aes_256_cbc() : EVP_aes_128_cbc();
47 OpenSSLErrStackTracer err_tracer(FROM_HERE);
48 bssl::ScopedEVP_CIPHER_CTX ctx;
49 CHECK(EVP_DecryptInit_ex(ctx.get(), cipher, nullptr, key.data(), iv.data()));
50
51 std::vector<uint8_t> plaintext(ciphertext.size());
52
53 int out_len;
54 CHECK(EVP_DecryptUpdate(ctx.get(), plaintext.data(), &out_len,
55 ciphertext.data(), ciphertext.size()));
56
57 int tail_len;
58 if (!EVP_DecryptFinal_ex(ctx.get(),
59 // SAFETY: boringssl guarantees out_len is still
60 // inside ciphertext.
61 UNSAFE_BUFFERS(plaintext.data() + out_len),
62 &tail_len)) {
63 return std::nullopt;
64 }
65
66 plaintext.resize(out_len + tail_len);
67 return plaintext;
68 }
69
70 } // namespace crypto::aes_cbc
71