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_siv_boringssl.h"
18
19 #include <memory>
20 #include <string>
21 #include <utility>
22 #include <vector>
23
24 #include "gtest/gtest.h"
25 #include "absl/status/status.h"
26 #include "tink/config/tink_fips.h"
27 #include "tink/subtle/wycheproof_util.h"
28 #include "tink/util/secret_data.h"
29 #include "tink/util/statusor.h"
30 #include "tink/util/test_matchers.h"
31 #include "tink/util/test_util.h"
32
33 namespace crypto {
34 namespace tink {
35 namespace subtle {
36 namespace {
37
38 using ::crypto::tink::test::StatusIs;
39
TEST(AesSivBoringSslTest,testCarryComputation)40 TEST(AesSivBoringSslTest, testCarryComputation) {
41 if (IsFipsModeEnabled()) {
42 GTEST_SKIP() << "Not supported in FIPS-only mode";
43 }
44 uint8_t value = 0;
45 for (int i = 0; i < 256; i++) {
46 uint8_t carry = *reinterpret_cast<int8_t*>(&value) >> 7;
47 if (i < 128) {
48 EXPECT_EQ(carry, 0x00);
49 } else {
50 EXPECT_EQ(carry, 0xff);
51 }
52 value++;
53 }
54 }
55
TEST(AesSivBoringSslTest,testEncryptDecrypt)56 TEST(AesSivBoringSslTest, testEncryptDecrypt) {
57 if (IsFipsModeEnabled()) {
58 GTEST_SKIP() << "Not supported in FIPS-only mode";
59 }
60 util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
61 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
62 "00112233445566778899aabbccddeefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
63 auto res = AesSivBoringSsl::New(key);
64 EXPECT_TRUE(res.ok()) << res.status();
65 auto cipher = std::move(res.value());
66 std::string associated_data = "Associated data";
67 std::string message = "Some data to encrypt.";
68 auto ct = cipher->EncryptDeterministically(message, associated_data);
69 EXPECT_TRUE(ct.ok()) << ct.status();
70 auto pt = cipher->DecryptDeterministically(ct.value(), associated_data);
71 EXPECT_TRUE(pt.ok()) << pt.status();
72 EXPECT_EQ(pt.value(), message);
73 }
74
TEST(AesSivBoringSslTest,testNullPtrStringView)75 TEST(AesSivBoringSslTest, testNullPtrStringView) {
76 if (IsFipsModeEnabled()) {
77 GTEST_SKIP() << "Not supported in FIPS-only mode";
78 }
79 util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
80 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
81 "00112233445566778899aabbccddeefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
82 auto res = AesSivBoringSsl::New(key);
83 EXPECT_TRUE(res.ok()) << res.status();
84 // Checks that a default constructed string_view works.
85 auto cipher = std::move(res.value());
86 absl::string_view null;
87 auto ct = cipher->EncryptDeterministically(null, null);
88 EXPECT_TRUE(ct.ok()) << ct.status();
89 auto pt = cipher->DecryptDeterministically(ct.value(), null);
90 EXPECT_TRUE(pt.ok()) << pt.status();
91 EXPECT_EQ("", pt.value());
92 // Decryption with ct == null should return an appropriate status.
93 pt = cipher->DecryptDeterministically(null, "");
94 EXPECT_FALSE(pt.ok());
95 // Associated data with an empty string view is the same an empty string.
96 std::string message("123456789abcdefghijklmnop");
97 ct = cipher->EncryptDeterministically(message, null);
98 pt = cipher->DecryptDeterministically(ct.value(), "");
99 EXPECT_TRUE(pt.ok()) << pt.status();
100 EXPECT_EQ(message, pt.value());
101 ct = cipher->EncryptDeterministically(message, "");
102 pt = cipher->DecryptDeterministically(ct.value(), null);
103 EXPECT_TRUE(pt.ok()) << pt.status();
104 EXPECT_EQ(message, pt.value());
105 }
106
107 // Only 64 byte key sizes are supported.
TEST(AesSivBoringSslTest,testEncryptDecryptKeySizes)108 TEST(AesSivBoringSslTest, testEncryptDecryptKeySizes) {
109 if (IsFipsModeEnabled()) {
110 GTEST_SKIP() << "Not supported in FIPS-only mode";
111 }
112 util::SecretData keymaterial =
113 util::SecretDataFromStringView(test::HexDecodeOrDie(
114 "198371900187498172316311acf81d238ff7619873a61983d619c87b63a1987f"
115 "987131819803719b847126381cd763871638aa71638176328761287361231321"
116 "812731321de508761437195ff231765aa4913219873ac6918639816312130011"
117 "abc900bba11400187984719827431246bbab1231eb4145215ff7141436616beb"
118 "9817298148712fed3aab61000ff123313e"));
119 for (int keysize = 0; keysize < keymaterial.size(); ++keysize){
120 util::SecretData key(&keymaterial[0], &keymaterial[keysize]);
121 auto cipher = AesSivBoringSsl::New(key);
122 if (keysize == 64) {
123 EXPECT_TRUE(cipher.ok());
124 } else {
125 EXPECT_FALSE(cipher.ok()) << "Accepted invalid key size:" << keysize;
126 }
127 }
128 }
129
130 // Checks a range of message sizes.
TEST(AesSivBoringSslTest,testEncryptDecryptMessageSize)131 TEST(AesSivBoringSslTest, testEncryptDecryptMessageSize) {
132 if (IsFipsModeEnabled()) {
133 GTEST_SKIP() << "Not supported in FIPS-only mode";
134 }
135 util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
136 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
137 "00112233445566778899aabbccddeefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
138 auto res = AesSivBoringSsl::New(key);
139 EXPECT_TRUE(res.ok()) << res.status();
140 auto cipher = std::move(res.value());
141 std::string associated_data = "Associated data";
142 for (int i = 0; i < 1024; ++i) {
143 std::string message = std::string(i, 'a');
144 auto ct = cipher->EncryptDeterministically(message, associated_data);
145 EXPECT_TRUE(ct.ok()) << ct.status();
146 auto pt = cipher->DecryptDeterministically(ct.value(), associated_data);
147 EXPECT_TRUE(pt.ok()) << pt.status();
148 EXPECT_EQ(pt.value(), message);
149 }
150 for (int i = 1024; i < 100000; i+= 5000) {
151 std::string message = std::string(i, 'a');
152 auto ct = cipher->EncryptDeterministically(message, associated_data);
153 EXPECT_TRUE(ct.ok()) << ct.status();
154 auto pt = cipher->DecryptDeterministically(ct.value(), associated_data);
155 EXPECT_TRUE(pt.ok()) << pt.status();
156 EXPECT_EQ(pt.value(), message);
157 }
158 }
159
160 // Checks a range of associated_data sizes.
TEST(AesSivBoringSslTest,testEncryptDecryptAssociatedDataSize)161 TEST(AesSivBoringSslTest, testEncryptDecryptAssociatedDataSize) {
162 if (IsFipsModeEnabled()) {
163 GTEST_SKIP() << "Not supported in FIPS-only mode";
164 }
165 util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
166 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
167 "00112233445566778899aabbccddeefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
168 auto res = AesSivBoringSsl::New(key);
169 EXPECT_TRUE(res.ok()) << res.status();
170 auto cipher = std::move(res.value());
171 std::string message = "Some plaintext";
172 for (int i = 0; i < 1028; ++i) {
173 std::string associated_data = std::string(i, 'a');
174 auto ct = cipher->EncryptDeterministically(message, associated_data);
175 EXPECT_TRUE(ct.ok()) << ct.status();
176 auto pt = cipher->DecryptDeterministically(ct.value(), associated_data);
177 EXPECT_TRUE(pt.ok()) << pt.status();
178 EXPECT_EQ(pt.value(), message);
179 }
180 }
181
TEST(AesSivBoringSslTest,testDecryptModification)182 TEST(AesSivBoringSslTest, testDecryptModification) {
183 if (IsFipsModeEnabled()) {
184 GTEST_SKIP() << "Not supported in FIPS-only mode";
185 }
186 util::SecretData key = util::SecretDataFromStringView(test::HexDecodeOrDie(
187 "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
188 "00112233445566778899aabbccddeefff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"));
189 auto res = AesSivBoringSsl::New(key);
190 EXPECT_TRUE(res.ok()) << res.status();
191 auto cipher = std::move(res.value());
192 std::string associated_data = "Associated data";
193 for (int i = 0; i < 50; ++i) {
194 std::string message = std::string(i, 'a');
195 auto ct = cipher->EncryptDeterministically(message, associated_data);
196 EXPECT_TRUE(ct.ok()) << ct.status();
197 std::string ciphertext = ct.value();
198 for (size_t b = 0; b < ciphertext.size(); ++b) {
199 for (int bit = 0; bit < 8; ++bit) {
200 std::string modified = ciphertext;
201 modified[b] ^= (1 << bit);
202 auto pt = cipher->DecryptDeterministically(modified, associated_data);
203 EXPECT_FALSE(pt.ok())
204 << "Modified ciphertext decrypted."
205 << " byte:" << b
206 << " bit:" << bit;
207 }
208 }
209 }
210 }
211
212 // Test with test vectors from project Wycheproof.
WycheproofTest(const rapidjson::Document & root)213 void WycheproofTest(const rapidjson::Document &root) {
214 for (const rapidjson::Value& test_group : root["testGroups"].GetArray()) {
215 const size_t key_size = test_group["keySize"].GetInt();
216 if (!AesSivBoringSsl::IsValidKeySizeInBytes(key_size / 8)) {
217 // Currently the key size is restricted to two 256-bit AES keys.
218 continue;
219 }
220 for (const rapidjson::Value& test : test_group["tests"].GetArray()) {
221 std::string comment = test["comment"].GetString();
222 util::SecretData key =
223 util::SecretDataFromStringView(WycheproofUtil::GetBytes(test["key"]));
224 std::string msg = WycheproofUtil::GetBytes(test["msg"]);
225 std::string ct = WycheproofUtil::GetBytes(test["ct"]);
226 std::string associated_data = WycheproofUtil::GetBytes(test["aad"]);
227 int id = test["tcId"].GetInt();
228 std::string result = test["result"].GetString();
229 auto cipher = std::move(AesSivBoringSsl::New(key).value());
230
231 // Test encryption.
232 // Encryption should always succeed since msg and aad are valid inputs.
233 std::string encrypted =
234 cipher->EncryptDeterministically(msg, associated_data).value();
235 std::string encrypted_hex = test::HexEncode(encrypted);
236 std::string ct_hex = test::HexEncode(ct);
237 if (result == "valid" || result == "acceptable") {
238 EXPECT_EQ(ct_hex, encrypted_hex)
239 << "incorrect encryption: " << id << " " << comment;
240 } else {
241 EXPECT_NE(ct_hex, encrypted_hex)
242 << "invalid encryption: " << id << " " << comment;
243 }
244
245 // Test decryption
246 auto decrypted = cipher->DecryptDeterministically(ct, associated_data);
247 if (decrypted.ok()) {
248 if (result == "invalid") {
249 ADD_FAILURE() << "decrypted invalid ciphertext:" << id;
250 } else {
251 EXPECT_EQ(test::HexEncode(msg), test::HexEncode(decrypted.value()))
252 << "incorrect decryption: " << id << " " << comment;
253 }
254 } else {
255 EXPECT_NE(result, "valid")
256 << "failed to decrypt: " << id << " " << comment;
257 }
258 }
259 }
260 }
261
TEST(AesSivBoringSslTest,TestVectors)262 TEST(AesSivBoringSslTest, TestVectors) {
263 if (IsFipsModeEnabled()) {
264 GTEST_SKIP() << "Not supported in FIPS-only mode";
265 }
266 std::unique_ptr<rapidjson::Document> root =
267 WycheproofUtil::ReadTestVectors("aes_siv_cmac_test.json");
268 WycheproofTest(*root);
269 }
270
TEST(AesEaxBoringSslTest,TestFipsOnly)271 TEST(AesEaxBoringSslTest, TestFipsOnly) {
272 if (!IsFipsModeEnabled()) {
273 GTEST_SKIP() << "Only supported in FIPS-only mode";
274 }
275
276 util::SecretData key128 = util::SecretDataFromStringView(
277 test::HexDecodeOrDie("000102030405060708090a0b0c0d0e0f"));
278 util::SecretData key256 = util::SecretDataFromStringView(test::HexDecodeOrDie(
279 "000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"));
280
281 EXPECT_THAT(subtle::AesSivBoringSsl::New(key128).status(),
282 StatusIs(absl::StatusCode::kInternal));
283 EXPECT_THAT(subtle::AesSivBoringSsl::New(key256).status(),
284 StatusIs(absl::StatusCode::kInternal));
285 }
286
287 } // namespace
288 } // namespace subtle
289 } // namespace tink
290 } // namespace crypto
291