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