xref: /aosp_15_r20/external/tink/cc/internal/aes_util_test.cc (revision e7b1675dde1b92d52ec075b0a92829627f2c52a5)
1 // Copyright 2021 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 ///////////////////////////////////////////////////////////////////////////////
16 #include "tink/internal/aes_util.h"
17 
18 #include <algorithm>
19 #include <cstdint>
20 #include <string>
21 
22 #include "gmock/gmock.h"
23 #include "gtest/gtest.h"
24 #include "absl/status/status.h"
25 #include "absl/strings/escaping.h"
26 #include "absl/strings/string_view.h"
27 #include "absl/types/span.h"
28 #include "openssl/aes.h"
29 #include "openssl/evp.h"
30 #include "tink/subtle/subtle_util.h"
31 #include "tink/util/secret_data.h"
32 #include "tink/util/status.h"
33 #include "tink/util/statusor.h"
34 #include "tink/util/test_matchers.h"
35 
36 namespace crypto {
37 namespace tink {
38 namespace internal {
39 namespace {
40 
41 using ::crypto::tink::test::IsOk;
42 using ::crypto::tink::test::IsOkAndHolds;
43 using ::crypto::tink::test::StatusIs;
44 using ::testing::HasSubstr;
45 using ::testing::Not;
46 
47 struct NistAesCtrTestVector {
48   std::string iv;
49   std::string key;
50   std::string plaintext;
51   std::string ciphertext;
52 };
53 
54 class AesCtrTest : public testing::Test {
55  protected:
AesCtrTest()56   AesCtrTest() : aes_key_(util::MakeSecretUniquePtr<AES_KEY>()) {}
57 
SetUp()58   void SetUp() override {
59     ASSERT_EQ(AES_set_encrypt_key(
60                   reinterpret_cast<const uint8_t*>(test_vector_.key.data()),
61                   /*bits=*/test_vector_.key.size() * 8, aes_key_.get()),
62               0);
63   }
64 
65   // Test vector from NIST SP 800-38A.
66   NistAesCtrTestVector test_vector_ = {
67       /*iv=*/absl::HexStringToBytes("f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"),
68       /*key=*/absl::HexStringToBytes("2b7e151628aed2a6abf7158809cf4f3c"),
69       /*plaintext=*/
70       absl::HexStringToBytes(
71           "6bc1bee22e409f96e93d7e117393172aae2d8a571e03ac9c9eb76fac45af8e5130c8"
72           "1c46a35ce411e5fbc1191a0a52eff69f2445df4f9b17ad2b417be66c3710"),
73       /*ciphertext=*/
74       absl::HexStringToBytes(
75           "874d6191b620e3261bef6864990db6ce9806f66b7970fdff8617187bb9fffdff5ae4"
76           "df3edbd5d35e5b4f09020db03eab1e031dda2fbe03d1792170a0f3009cee"),
77   };
78   const util::SecretUniquePtr<AES_KEY> aes_key_;
79 };
80 
81 // Check that AesCtr128Crypt fails when out buffer is too small.
TEST_F(AesCtrTest,AesCtrInvalidOutSize)82 TEST_F(AesCtrTest, AesCtrInvalidOutSize) {
83   std::string out;
84   for (int size = 0; size < test_vector_.plaintext.size(); size++) {
85     subtle::ResizeStringUninitialized(&out, size);
86     EXPECT_THAT(AesCtr128Crypt(test_vector_.plaintext,
87                                reinterpret_cast<uint8_t*>(&test_vector_.iv[0]),
88                                aes_key_.get(), absl::MakeSpan(out)),
89                 Not(IsOk()));
90   }
91 }
92 
93 // Partial overlap of buffers of the right size is not allowed.
TEST_F(AesCtrTest,AesCtrPartiallyOverlappingFails)94 TEST_F(AesCtrTest, AesCtrPartiallyOverlappingFails) {
95   std::string out;
96   subtle::ResizeStringUninitialized(&out, 2 * test_vector_.plaintext.size());
97   const int kStartIndex = test_vector_.plaintext.size() / 2;
98   std::copy(test_vector_.plaintext.begin(), test_vector_.plaintext.end(),
99             out.begin() + kStartIndex);
100   auto plaintext =
101       absl::string_view(out).substr(kStartIndex, test_vector_.plaintext.size());
102   util::Status res = AesCtr128Crypt(
103       plaintext, reinterpret_cast<uint8_t*>(&test_vector_.iv[0]),
104       aes_key_.get(), absl::MakeSpan(out).subspan(0, plaintext.size()));
105   // Checking the message to disambiguate from the kInvalidArgumentError that is
106   // returned in case of wrong size of the output buffer.
107   EXPECT_THAT(
108       res, StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("overlap")));
109   res = AesCtr128Crypt(
110       plaintext, reinterpret_cast<uint8_t*>(&test_vector_.iv[0]),
111       aes_key_.get(),
112       absl::MakeSpan(out).subspan(plaintext.size(), plaintext.size()));
113   EXPECT_THAT(
114       res, StatusIs(absl::StatusCode::kInvalidArgument, HasSubstr("overlap")));
115 }
116 
TEST_F(AesCtrTest,AesCtrEncrypt)117 TEST_F(AesCtrTest, AesCtrEncrypt) {
118   std::string out;
119   subtle::ResizeStringUninitialized(&out, test_vector_.plaintext.size());
120   ASSERT_THAT(AesCtr128Crypt(test_vector_.plaintext,
121                              reinterpret_cast<uint8_t*>(&test_vector_.iv[0]),
122                              aes_key_.get(), absl::MakeSpan(out)),
123               IsOk());
124   EXPECT_EQ(out, test_vector_.ciphertext);
125 }
126 
TEST_F(AesCtrTest,AesCtrEncryptInPlace)127 TEST_F(AesCtrTest, AesCtrEncryptInPlace) {
128   std::string inout = test_vector_.plaintext;
129   ASSERT_THAT(
130       AesCtr128Crypt(inout, reinterpret_cast<uint8_t*>(&test_vector_.iv[0]),
131                      aes_key_.get(), absl::MakeSpan(inout)),
132       IsOk());
133   EXPECT_EQ(inout, test_vector_.ciphertext);
134 }
135 
TEST_F(AesCtrTest,AesCtrDecrypt)136 TEST_F(AesCtrTest, AesCtrDecrypt) {
137   std::string out;
138   subtle::ResizeStringUninitialized(&out, test_vector_.ciphertext.size());
139   ASSERT_THAT(AesCtr128Crypt(test_vector_.ciphertext,
140                              reinterpret_cast<uint8_t*>(&test_vector_.iv[0]),
141                              aes_key_.get(), absl::MakeSpan(out)),
142               IsOk());
143   EXPECT_EQ(out, test_vector_.plaintext);
144 }
145 
TEST_F(AesCtrTest,AesCtrDecryptInPlace)146 TEST_F(AesCtrTest, AesCtrDecryptInPlace) {
147   std::string inout = test_vector_.ciphertext;
148   ASSERT_THAT(
149       AesCtr128Crypt(inout, reinterpret_cast<uint8_t*>(&test_vector_.iv[0]),
150                      aes_key_.get(), absl::MakeSpan(inout)),
151       IsOk());
152   EXPECT_EQ(inout, test_vector_.plaintext);
153 }
154 
TEST(AesUtilTest,GetAesCtrCipherForKeySize)155 TEST(AesUtilTest, GetAesCtrCipherForKeySize) {
156   for (int i = 0; i < 64; i++) {
157     util::StatusOr<const EVP_CIPHER*> cipher = GetAesCtrCipherForKeySize(i);
158     if (i == 16) {
159       EXPECT_THAT(cipher, IsOkAndHolds(EVP_aes_128_ctr()));
160     } else if (i == 32) {
161       EXPECT_THAT(cipher, IsOkAndHolds(EVP_aes_256_ctr()));
162     } else {
163       EXPECT_THAT(cipher, Not(IsOk()));
164     }
165   }
166 }
167 
TEST(AesUtilTest,GetAesCbcCipherForKeySize)168 TEST(AesUtilTest, GetAesCbcCipherForKeySize) {
169   for (int i = 0; i < 64; i++) {
170     util::StatusOr<const EVP_CIPHER*> cipher = GetAesCbcCipherForKeySize(i);
171     if (i == 16) {
172       EXPECT_THAT(cipher, IsOkAndHolds(EVP_aes_128_cbc()));
173     } else if (i == 32) {
174       EXPECT_THAT(cipher, IsOkAndHolds(EVP_aes_256_cbc()));
175     } else {
176       EXPECT_THAT(cipher, Not(IsOk()));
177     }
178   }
179 }
180 
181 }  // namespace
182 }  // namespace internal
183 }  // namespace tink
184 }  // namespace crypto
185