1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/gcm_driver/crypto/gcm_message_cryptographer.h"
7 #include "base/base64.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/string_util.h"
10 #include "crypto/random.h"
11 #include "crypto/symmetric_key.h"
12 #include "testing/gtest/include/gtest/gtest.h"
18 // The number of bits of the key in AEAD_AES_128_GCM.
19 const size_t kKeySizeBits
= 128;
21 // Example plaintext data to use in the tests.
22 const char kExamplePlaintext
[] = "Example plaintext";
24 // A test vector contains the information necessary to either encrypt or decrypt
25 // a message. These vectors were created using a JavaScript implementation of
26 // the same RFCs that the GCMMessageCryptographer implements.
28 const char* const input
;
29 const char* const key
;
30 const char* const salt
;
32 const char* const output
;
35 const TestVector kEncryptionTestVectors
[] = {
38 "AhA6n2oFYPWIh+cXwyv1m2C0JvmjHB4ZkXj8QylESXU=",
39 "tsJYqAGvFDk6lDEv7daecw==",
41 "KNXRqBR9VKhtajeMaeKR/rHYIiORcyeFpUwWFGyS"
45 "lMyvTong4VR053jfCpWmMDGW5dEDAqiTZUIU+inhTjU=",
46 "wH3uvZqcN6oey9whiGpn1A==",
48 "Mnfr+AU5o7D30gjFdVOTFtw="
50 // Message with an invalid salt size.
52 "CcdxzkR6z1EY9vSrM7/IxYVxDxu46hV638EZQTPd7XI=",
55 nullptr // expected to fail
59 const TestVector kDecryptionTestVectors
[] = {
61 { "avAFNhdbQohzizu+ORbU4XHhHSaXzw9lTN7UzB/j",
62 "47ZytAw9qHlm+Q8g+7rH81rUPzaCgGcoFvlS1qxQtQk=",
63 "EuR7EVetcaWpndXd/dKeyA==",
67 // Simple message with 16 bytes of padding.
68 { "0198n7ZJ/ZPMnl4ZU2l9Lma5ktKbuzXCiJEXyYtROmWTP8RSiZd8sUd48xpk6Q==",
69 "MYSsNybwrTzRIzQYUq/yFPc6ugcTrJdEZJDM4NswvUg=",
70 "8sEAMQYnufo2UkKl80cUGQ==",
75 { "g+ACk32a4gK2dS2xllKXn4c=",
76 "S3+Ki/+XtzR66gUp/zR75CC5JXO62pyr5fWfneTYwFE=",
77 "4RM6s19jJHdmqiVEJDp9jg==",
81 // Message with an invalid salt size.
82 { "rt4OiodS087DAQo6e24wA55k0hRPAHgz7OX7m+nj",
83 "wW3Iy5ma803lLd+ysPdHUe2NB3HqXbY0XhCCdG5Y1Gw=",
86 nullptr // expected to fail
88 // Message with an invalid record size.
89 { "AsuoRkFtqLE1c0mGCae4OvgZSCSHWCoeRL9mXKjY",
90 "omxWz7tse3lgDpxUP+e7u14Dp1irvV3BdzXTcZOtsHs=",
91 "vKJD3bexto1hY64KVzS7ug==",
93 nullptr // expected to fail
96 { "AGr4BfZSXW9txWkAG8pjg7IuRWWm1Mo8bDli/PSv",
97 "kR5BMfqMKOD1yrLKE2giObXHI7merrMtnoO2oqneqXA=",
98 "SQeJSPrqHvTdSfAMF8bBzQ==",
100 nullptr // expected to fail
102 // Message with multiple (2) records.
103 { "H2ujfPbpRbVSy+adIG2NRe4VxkX4V0r/zl6e9xnMSF6LSutblGdWLrwQc82Xh7DXAQlihW0q3"
105 "W3W4gx7sqcfmBnvNNdO9d4MBCC1bvJkvsNjZOGD+CCg=",
106 "xG0TPGi9aIcxjpXKmaYBBQ==",
108 nullptr // expected to fail
114 class GCMMessageCryptographerTest
: public ::testing::Test
{
116 void SetUp() override
{
117 scoped_ptr
<crypto::SymmetricKey
> random_key(
118 crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES
,
121 ASSERT_TRUE(random_key
->GetRawKey(&key_
));
125 // Generates a cryptographically secure random salt of 16-octets in size, the
126 // required length as expected by the HKDF.
127 std::string
GenerateRandomSalt() {
128 const size_t kSaltSize
= 16;
132 crypto::RandBytes(base::WriteInto(&salt
, kSaltSize
+ 1), kSaltSize
);
136 GCMMessageCryptographer
* cryptographer() { return &cryptographer_
; }
138 base::StringPiece
key() const { return key_
; }
141 GCMMessageCryptographer cryptographer_
;
146 TEST_F(GCMMessageCryptographerTest
, RoundTrip
) {
147 const std::string salt
= GenerateRandomSalt();
149 size_t record_size
= 0;
151 std::string ciphertext
, plaintext
;
152 ASSERT_TRUE(cryptographer()->Encrypt(kExamplePlaintext
, key(), salt
,
153 &record_size
, &ciphertext
));
155 EXPECT_GT(record_size
, ciphertext
.size() - 16);
156 EXPECT_GT(ciphertext
.size(), 0u);
158 ASSERT_TRUE(cryptographer()->Decrypt(ciphertext
, key(), salt
, record_size
,
161 EXPECT_EQ(kExamplePlaintext
, plaintext
);
164 TEST_F(GCMMessageCryptographerTest
, RoundTripEmptyMessage
) {
165 const std::string salt
= GenerateRandomSalt();
166 const std::string message
= "";
168 size_t record_size
= 0;
170 std::string ciphertext
, plaintext
;
171 ASSERT_TRUE(cryptographer()->Encrypt(message
, key(), salt
, &record_size
,
174 EXPECT_GT(record_size
, ciphertext
.size() - 16);
175 EXPECT_GT(ciphertext
.size(), 0u);
177 ASSERT_TRUE(cryptographer()->Decrypt(ciphertext
, key(), salt
, record_size
,
180 EXPECT_EQ(message
, plaintext
);
183 TEST_F(GCMMessageCryptographerTest
, InvalidRecordSize
) {
184 const std::string salt
= GenerateRandomSalt();
186 size_t record_size
= 0;
188 std::string ciphertext
, plaintext
;
189 EXPECT_TRUE(cryptographer()->Encrypt(kExamplePlaintext
, key(), salt
,
190 &record_size
, &ciphertext
));
192 EXPECT_GT(record_size
, ciphertext
.size() - 16);
193 EXPECT_FALSE(cryptographer()->Decrypt(ciphertext
, key(), salt
,
194 0 /* record_size */, &plaintext
));
196 EXPECT_FALSE(cryptographer()->Decrypt(ciphertext
, key(), salt
,
197 ciphertext
.size() - 17, &plaintext
));
199 EXPECT_TRUE(cryptographer()->Decrypt(ciphertext
, key(), salt
,
200 ciphertext
.size() - 16, &plaintext
));
203 TEST_F(GCMMessageCryptographerTest
, InvalidRecordPadding
) {
204 std::string message
= std::string(1, '\0') + kExamplePlaintext
;
206 const std::string salt
= GenerateRandomSalt();
208 const std::string nonce
= cryptographer()->DeriveNonce(key(), salt
);
209 const std::string content_encryption_key
=
210 cryptographer()->DeriveContentEncryptionKey(key(), salt
);
212 ASSERT_GT(message
.size(), 1u);
213 const size_t record_size
= message
.size() + 1;
215 std::string ciphertext
, plaintext
;
216 ASSERT_TRUE(cryptographer()->EncryptDecryptRecordInternal(
217 GCMMessageCryptographer::ENCRYPT
, message
, content_encryption_key
, nonce
,
220 ASSERT_TRUE(cryptographer()->Decrypt(ciphertext
, key(), salt
, record_size
,
223 // Note that GCMMessageCryptographer::Decrypt removes the padding.
224 EXPECT_EQ(kExamplePlaintext
, plaintext
);
226 // Now run the same steps again, but say that there are four padding octets.
227 // This should be rejected because the padding will not be all zeros.
230 ASSERT_TRUE(cryptographer()->EncryptDecryptRecordInternal(
231 GCMMessageCryptographer::ENCRYPT
, message
, content_encryption_key
, nonce
,
234 ASSERT_FALSE(cryptographer()->Decrypt(ciphertext
, key(), salt
, record_size
,
237 // Run the same steps again, but say that there are more padding octets than
238 // the length of the message.
241 EXPECT_GT(static_cast<size_t>(message
[0]), message
.size());
242 ASSERT_TRUE(cryptographer()->EncryptDecryptRecordInternal(
243 GCMMessageCryptographer::ENCRYPT
, message
, content_encryption_key
, nonce
,
246 ASSERT_FALSE(cryptographer()->Decrypt(ciphertext
, key(), salt
, record_size
,
250 TEST_F(GCMMessageCryptographerTest
, EncryptionTestVectors
) {
251 std::string key
, salt
, output
, ciphertext
;
252 size_t record_size
= 0;
254 for (size_t i
= 0; i
< arraysize(kEncryptionTestVectors
); ++i
) {
257 ASSERT_TRUE(base::Base64Decode(kEncryptionTestVectors
[i
].key
, &key
));
258 ASSERT_TRUE(base::Base64Decode(kEncryptionTestVectors
[i
].salt
, &salt
));
260 const bool has_output
= kEncryptionTestVectors
[i
].output
;
261 const bool result
= cryptographer()->Encrypt(
262 kEncryptionTestVectors
[i
].input
, key
, salt
, &record_size
, &ciphertext
);
265 EXPECT_FALSE(result
);
270 ASSERT_TRUE(base::Base64Decode(kEncryptionTestVectors
[i
].output
,
273 EXPECT_EQ(kEncryptionTestVectors
[i
].record_size
, record_size
);
274 EXPECT_EQ(output
, ciphertext
);
278 TEST_F(GCMMessageCryptographerTest
, DecryptionTestVectors
) {
279 std::string input
, key
, salt
, plaintext
;
280 for (size_t i
= 0; i
< arraysize(kDecryptionTestVectors
); ++i
) {
283 ASSERT_TRUE(base::Base64Decode(kDecryptionTestVectors
[i
].input
, &input
));
284 ASSERT_TRUE(base::Base64Decode(kDecryptionTestVectors
[i
].key
, &key
));
285 ASSERT_TRUE(base::Base64Decode(kDecryptionTestVectors
[i
].salt
, &salt
));
287 const bool has_output
= kDecryptionTestVectors
[i
].output
;
288 const bool result
= cryptographer()->Decrypt(
289 input
, key
, salt
, kDecryptionTestVectors
[i
].record_size
, &plaintext
);
292 EXPECT_FALSE(result
);
297 EXPECT_EQ(kDecryptionTestVectors
[i
].output
, plaintext
);