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