1 // Copyright 2017 Google Inc.
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
17 #include "tink/subtle/aes_gcm_hkdf_stream_segment_encrypter.h"
18
19 #include <string>
20 #include <utility>
21 #include <vector>
22
23 #include "gmock/gmock.h"
24 #include "gtest/gtest.h"
25 #include "absl/status/status.h"
26 #include "absl/strings/str_cat.h"
27 #include "tink/subtle/random.h"
28 #include "tink/util/status.h"
29 #include "tink/util/statusor.h"
30 #include "tink/util/test_util.h"
31
32
33 namespace crypto {
34 namespace tink {
35 namespace subtle {
36 namespace {
37
38 using ::testing::HasSubstr;
39
TEST(AesGcmHkdfStreamSegmentEncrypterTest,testBasic)40 TEST(AesGcmHkdfStreamSegmentEncrypterTest, testBasic) {
41 for (int key_size : {16, 32}) {
42 for (int ciphertext_offset : {0, 5, 10}) {
43 for (int ct_segment_size : {80, 128, 200}) {
44 SCOPED_TRACE(absl::StrCat(
45 "key_size = ", key_size,
46 ", ciphertext_offset = ", ciphertext_offset,
47 ", ciphertext_segment_size = ", ct_segment_size));
48
49 // Construct an encrypter.
50 AesGcmHkdfStreamSegmentEncrypter::Params params;
51 params.key = Random::GetRandomKeyBytes(key_size);
52 params.salt = Random::GetRandomBytes(key_size);
53 params.ciphertext_offset = ciphertext_offset;
54 params.ciphertext_segment_size = ct_segment_size;
55 auto result = AesGcmHkdfStreamSegmentEncrypter::New(params);
56 EXPECT_TRUE(result.ok()) << result.status();
57
58 // Use the Constructed encrypter.
59 auto enc = std::move(result.value());
60 EXPECT_EQ(0, enc->get_segment_number());
61 int header_size = key_size + /* nonce_prefix_size = */ 7 + 1;
62 EXPECT_EQ(header_size, enc->get_header().size());
63 EXPECT_EQ(header_size, enc->get_header()[0]);
64 EXPECT_EQ(params.salt, std::string(reinterpret_cast<const char*>(
65 enc->get_header().data() + 1),
66 key_size));
67 EXPECT_EQ(ct_segment_size, enc->get_ciphertext_segment_size());
68 EXPECT_EQ(ct_segment_size - /* tag_size = */ 16,
69 enc->get_plaintext_segment_size());
70 EXPECT_EQ(ciphertext_offset, enc->get_ciphertext_offset());
71 int segment_number = 0;
72 for (int pt_size : {1, 10, enc->get_plaintext_segment_size()}) {
73 for (bool is_last_segment : {false, true}) {
74 SCOPED_TRACE(absl::StrCat(
75 "plaintext_size = ", pt_size,
76 ", is_last_segment = ", is_last_segment));
77 std::vector<uint8_t> pt(pt_size, 'p');
78 std::vector<uint8_t> ct;
79 auto status = enc->EncryptSegment(pt, is_last_segment, &ct);
80 EXPECT_TRUE(status.ok()) << status;
81 EXPECT_EQ(pt_size + /* tag_size = */ 16, ct.size());
82 segment_number++;
83 EXPECT_EQ(segment_number, enc->get_segment_number());
84 }
85 }
86
87 // Try encryption with wrong params.
88 std::vector<uint8_t> pt(enc->get_plaintext_segment_size() + 1, 'p');
89 auto status = enc->EncryptSegment(pt, true, nullptr);
90 EXPECT_FALSE(status.ok());
91 EXPECT_THAT(std::string(status.message()),
92 HasSubstr("plaintext too long"));
93 pt.resize(enc->get_plaintext_segment_size());
94 status = enc->EncryptSegment(pt, true, nullptr);
95 EXPECT_FALSE(status.ok());
96 EXPECT_THAT(std::string(status.message()),
97 HasSubstr("must be non-null"));
98 }
99 }
100 }
101 }
102
TEST(AesGcmHkdfStreamSegmentEncrypterTest,testWrongKeySize)103 TEST(AesGcmHkdfStreamSegmentEncrypterTest, testWrongKeySize) {
104 for (int key_size : {12, 24, 64}) {
105 for (int ciphertext_offset : {0, 5, 10}) {
106 for (int ct_segment_size : {128, 200}) {
107 SCOPED_TRACE(absl::StrCat(
108 "key_size = ", key_size,
109 ", ciphertext_offset = ", ciphertext_offset,
110 ", ciphertext_segment_size = ", ct_segment_size));
111 AesGcmHkdfStreamSegmentEncrypter::Params params;
112 params.key = Random::GetRandomKeyBytes(key_size);
113 params.salt = Random::GetRandomBytes(key_size);
114 params.ciphertext_offset = ciphertext_offset;
115 params.ciphertext_segment_size = ct_segment_size;
116 auto result = AesGcmHkdfStreamSegmentEncrypter::New(params);
117 EXPECT_FALSE(result.ok());
118 EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
119 EXPECT_THAT(std::string(result.status().message()),
120 HasSubstr("must have 16 or 32 bytes"));
121 }
122 }
123 }
124 }
125
TEST(AesGcmHkdfStreamSegmentEncrypterTest,testWrongSaltSize)126 TEST(AesGcmHkdfStreamSegmentEncrypterTest, testWrongSaltSize) {
127 for (int key_size : {16, 32}) {
128 for (int salt_size_delta : {-3, -1, 1, 5, 16}) {
129 SCOPED_TRACE(absl::StrCat(
130 "key_size = ", key_size,
131 ", salt_size = ", key_size + salt_size_delta));
132 AesGcmHkdfStreamSegmentEncrypter::Params params;
133 params.key = Random::GetRandomKeyBytes(key_size);
134 params.salt = Random::GetRandomBytes(key_size + salt_size_delta);
135 params.ciphertext_offset = 0;
136 params.ciphertext_segment_size = 128;
137 auto result = AesGcmHkdfStreamSegmentEncrypter::New(params);
138 EXPECT_FALSE(result.ok());
139 EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
140 EXPECT_THAT(std::string(result.status().message()),
141 HasSubstr("same size as the key"));
142 }
143 }
144 }
145
TEST(AesGcmHkdfStreamSegmentEncrypterTest,testWrongCiphertextOffset)146 TEST(AesGcmHkdfStreamSegmentEncrypterTest, testWrongCiphertextOffset) {
147 for (int key_size : {16, 32}) {
148 for (int ciphertext_offset : {-16, -10, -3, -1}) {
149 SCOPED_TRACE(absl::StrCat(
150 "key_size = ", key_size,
151 ", ciphertext_offset = ", ciphertext_offset));
152 AesGcmHkdfStreamSegmentEncrypter::Params params;
153 params.key = Random::GetRandomKeyBytes(key_size);
154 params.salt = Random::GetRandomBytes(key_size);
155 params.ciphertext_offset = ciphertext_offset;
156 params.ciphertext_segment_size = 128;
157 auto result = AesGcmHkdfStreamSegmentEncrypter::New(params);
158 EXPECT_FALSE(result.ok());
159 EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
160 EXPECT_THAT(std::string(result.status().message()),
161 HasSubstr("must be non-negative"));
162 }
163 }
164 }
165
TEST(AesGcmHkdfStreamSegmentEncrypterTest,testWrongCiphertextSegmentSize)166 TEST(AesGcmHkdfStreamSegmentEncrypterTest, testWrongCiphertextSegmentSize) {
167 for (int key_size : {16, 32}) {
168 for (int ciphertext_offset : {0, 1, 5, 10}) {
169 int min_ct_segment_size = key_size + ciphertext_offset +
170 8 + // nonce_prefix_size + 1
171 16 + // tag_size
172 1;
173 for (int ct_segment_size : {min_ct_segment_size - 5,
174 min_ct_segment_size - 1, min_ct_segment_size,
175 min_ct_segment_size + 1, min_ct_segment_size + 10}) {
176 SCOPED_TRACE(absl::StrCat(
177 "key_size = ", key_size,
178 ", ciphertext_offset = ", ciphertext_offset,
179 ", ciphertext_segment_size = ", ct_segment_size));
180 AesGcmHkdfStreamSegmentEncrypter::Params params;
181 params.key = Random::GetRandomKeyBytes(key_size);
182 params.salt = Random::GetRandomBytes(key_size);
183 params.ciphertext_offset = ciphertext_offset;
184 params.ciphertext_segment_size = ct_segment_size;
185 auto result = AesGcmHkdfStreamSegmentEncrypter::New(params);
186 if (ct_segment_size < min_ct_segment_size) {
187 EXPECT_FALSE(result.ok());
188 EXPECT_EQ(absl::StatusCode::kInvalidArgument, result.status().code());
189 EXPECT_THAT(std::string(result.status().message()),
190 HasSubstr("too small"));
191 } else {
192 EXPECT_TRUE(result.ok()) << result.status();
193 }
194 }
195 }
196 }
197 }
198
199 } // namespace
200 } // namespace subtle
201 } // namespace tink
202 } // namespace crypto
203