Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(200)

Side by Side Diff: components/gcm_driver/crypto/gcm_message_cryptographer_unittest.cc

Issue 1453503002: [NOT FOR REVIEW] Ensure contributory behaviour for Web Push encryption. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@push-renames
Patch Set: Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "components/gcm_driver/crypto/gcm_message_cryptographer.h" 5 #include "components/gcm_driver/crypto/gcm_message_cryptographer.h"
6 6
7 #include "base/base64.h" 7 #include "base/base64.h"
8 #include "base/base64url.h"
8 #include "base/memory/scoped_ptr.h" 9 #include "base/memory/scoped_ptr.h"
9 #include "base/strings/string_util.h" 10 #include "base/strings/string_util.h"
11 #include "components/gcm_driver/crypto/p256_key_util.h"
10 #include "crypto/random.h" 12 #include "crypto/random.h"
11 #include "crypto/symmetric_key.h" 13 #include "crypto/symmetric_key.h"
12 #include "testing/gtest/include/gtest/gtest.h" 14 #include "testing/gtest/include/gtest/gtest.h"
13 15
16 #include "crypto/ec_private_key.h"
17 #include "crypto/scoped_openssl_types.h"
18 #include <openssl/ec.h>
19 #include <openssl/pkcs12.h>
20 #include <openssl/x509.h>
21
14 namespace gcm { 22 namespace gcm {
15 23
16 namespace { 24 namespace {
17 25
18 // The number of bits of the key in AEAD_AES_128_GCM. 26 // The number of bits of the key in AEAD_AES_128_GCM.
19 const size_t kKeySizeBits = 128; 27 const size_t kKeySizeBits = 128;
20 28
21 // Example plaintext data to use in the tests. 29 // Example plaintext data to use in the tests.
22 const char kExamplePlaintext[] = "Example plaintext"; 30 const char kExamplePlaintext[] = "Example plaintext";
23 31
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 // Message with multiple (2) records. 110 // Message with multiple (2) records.
103 { "H2ujfPbpRbVSy+adIG2NRe4VxkX4V0r/zl6e9xnMSF6LSutblGdWLrwQc82Xh7DXAQlihW0q3" 111 { "H2ujfPbpRbVSy+adIG2NRe4VxkX4V0r/zl6e9xnMSF6LSutblGdWLrwQc82Xh7DXAQlihW0q3"
104 "IQzHP+LIxuAiA==", 112 "IQzHP+LIxuAiA==",
105 "W3W4gx7sqcfmBnvNNdO9d4MBCC1bvJkvsNjZOGD+CCg=", 113 "W3W4gx7sqcfmBnvNNdO9d4MBCC1bvJkvsNjZOGD+CCg=",
106 "xG0TPGi9aIcxjpXKmaYBBQ==", 114 "xG0TPGi9aIcxjpXKmaYBBQ==",
107 7, 115 7,
108 nullptr // expected to fail 116 nullptr // expected to fail
109 } 117 }
110 }; 118 };
111 119
120 // -----------------------------------------------------------------------------
121
122 using ScopedPKCS8_PRIV_KEY_INFO =
123 crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>;
124 using ScopedX509_SIG = crypto::ScopedOpenSSL<X509_SIG, X509_SIG_free>;
125
126 // Takes a private key in X.509 SubjectPublicKeyInfo block format and converts
127 // it to an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo, as is accepted by
128 // the ECPrivateKey infrastructure.
129 std::string ConvertRawPrivateKeyToPKCS8EncryptedPrivateKeyInfo(
130 const base::StringPiece& raw_private_key,
131 const base::StringPiece& public_key) {
132 const uint8_t* raw_private_key_ptr =
133 reinterpret_cast<const uint8_t*>(raw_private_key.data());
134 const uint8_t* public_key_ptr =
135 reinterpret_cast<const uint8_t*>(public_key.data());
136
137 crypto::ScopedEC_GROUP p256(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
138 crypto::ScopedEC_KEY key(EC_KEY_new());
139 DCHECK(p256 && key);
140
141 // Import the |raw_private_key| to the |key| through a BIGNUM.
142 crypto::ScopedBIGNUM bignum(
143 BN_bin2bn(raw_private_key_ptr, raw_private_key.size(), nullptr));
144 if (!bignum) {
145 LOG(ERROR) << "Unable to initialize the ScopedBIGNUM";
146 return std::string();
147 }
148
149 if (!EC_KEY_set_private_key(key.get(), bignum.get())) {
150 LOG(ERROR) << "Unable to set the private key";
151 return std::string();
152 }
153
154 // Import the |public_key| to the |key| by assembling an EC point. Because the
155 // |public_key| is an uncompressed EC point, we can access the data directly.
156 crypto::ScopedEC_POINT point(EC_POINT_new(p256.get()));
157 crypto::ScopedBIGNUM x(BN_new()), y(BN_new());
158 DCHECK(point && x && y);
159
160 if (BN_bin2bn(public_key_ptr + 1 + 0, 32, x.get()) == nullptr ||
161 BN_bin2bn(public_key_ptr + 1 + 32, 32, y.get()) == nullptr) {
162 LOG(ERROR) << "Unable to create BIGNUMs for the public point's x/y";
163 return std::string();
164 }
165
166 if (!EC_POINT_set_affine_coordinates_GFp(p256.get(), point.get(), x.get(),
167 y.get(), nullptr)) {
168 LOG(ERROR) << "Unable to set the coordinates of the public point";
169 return std::string();
170 }
171
172 if (!EC_KEY_set_group(key.get(), p256.get()) ||
173 !EC_KEY_set_public_key(key.get(), point.get())) {
174 LOG(ERROR) << "Unable to set the public key";
175 return std::string();
176 }
177
178 // Verify that the created EC_KEY is valid. Crashes might occur if it's not.
179 if (!EC_KEY_check_key(key.get())) {
180 LOG(ERROR) << "Unable to verify validity of the key";
181 return std::string();
182 }
183
184 // Create a EVP_PKEY from the EC_KEY pair that was created.
185 crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new());
186 if (!pkey || !EVP_PKEY_set1_EC_KEY(pkey.get(), key.get())) {
187 LOG(ERROR) << "Unable to create the private key";
188 return std::string();
189 }
190
191 std::vector<uint8_t> encrypted_private_key_buf;
192 scoped_ptr<crypto::ECPrivateKey> ec_private_key(
193 crypto::ECPrivateKey::Create());
194 ec_private_key->key_ = pkey.release();
195
196 // Export the EVP_PKEY as an ASN.1-encoded PKCS #8 EncryptedPrivateKeyInfo
197 // block, as expected by the ECPrivateKey import routines.
198 if (!ec_private_key->ExportEncryptedPrivateKey("" /* password */,
199 1 /* iterations */,
200 &encrypted_private_key_buf)) {
201 LOG(ERROR) << "Unable to export the encrypted private key";
202 return std::string();
203 }
204
205 return std::string(reinterpret_cast<char*>(encrypted_private_key_buf.data()),
206 encrypted_private_key_buf.size());
207
208 /**
209 std::string raw_public_key, raw_public_key_rep;
210 DCHECK(ec_private_key->ExportRawPublicKey(&raw_public_key));
211
212 raw_public_key_rep = "\04" + raw_public_key;
213
214 LOG(INFO) << "r_p_k: (" << raw_public_key_rep.size() << ")";
215 LOG(INFO) << "p_k: (" << raw_public_key_rep.size() << ")";
216
217 LOG(INFO) << (raw_public_key_rep == public_key);
218
219 return std::string();
220
221
222 int public_key_len = i2d_PublicKey(pkey.get(), nullptr);
223 if (public_key_len != 65)
224 return std::string();
225
226 uint8_t public_key_buffer[public_key_len];
227
228 uint8_t* public_key_buffer_ptr = public_key_buffer;
229 if (i2d_PublicKey(pkey.get(), &public_key_buffer_ptr) != public_key_len)
230 return std::string();
231
232 std::string regenerated_public_key(
233 reinterpret_cast<char*>(public_key_buffer), public_key_len);
234
235 LOG(INFO) << (regenerated_public_key == public_key);
236
237 ScopedPKCS8_PRIV_KEY_INFO pkcs8(EVP_PKEY2PKCS8(pkey.get()));
238 if (!pkcs8) {
239 LOG(ERROR) << "Unable to initialize the PKCS8_PRIV_KEY_INFO";
240 return std::string();
241 }
242
243 ScopedX509_SIG encrypted(PKCS8_encrypt_pbe(
244 NID_pbe_WithSHA1And3_Key_TripleDES_CBC,
245 nullptr,
246 nullptr,
247 0,
248 nullptr,
249 0,
250 1,
251 pkcs8.get()));
252 if (!encrypted) {
253 LOG(ERROR) << "Unable to encrypt the PKCS8_PRIV_KEY_INFO";
254 return std::string();
255 }
256
257 crypto::ScopedBIO bio(BIO_new(BIO_s_mem()));
258 if (!i2d_PKCS8_bio(bio.get(), encrypted.get())) {
259 LOG(ERROR) << "Unable to convert PKCS8 to a PKI ScopedBIO (#1)";
260 return std::string();
261 }
262
263 char* bio_data = nullptr;
264 long bio_length = BIO_get_mem_data(bio.get(), &bio_data);
265 if (!bio_data || bio_length < 0) {
266 LOG(ERROR) << "Unable to convert PKCS8 to a PKI ScopedBIO (#2)";
267 return std::string();
268 }
269
270 std::string key_string = std::string(bio_data, bio_data + bio_length);
271
272 std::string encoded_string;
273 base::Base64UrlEncode(key_string, base::Base64UrlEncodePolicy::OMIT_PADDING,
274 &encoded_string);
275 LOG(INFO) << "Encrypted key: [" << encoded_string << "]";
276
277 // TODO: Get a X.509 SubjectPublicKeyInfo
278
279 return key_string;
280 **/
281 }
282
112 } // namespace 283 } // namespace
113 284
114 class GCMMessageCryptographerTest : public ::testing::Test { 285 class GCMMessageCryptographerTest : public ::testing::Test {
115 public: 286 public:
116 void SetUp() override { 287 void SetUp() override {
117 scoped_ptr<crypto::SymmetricKey> random_key( 288 scoped_ptr<crypto::SymmetricKey> random_key(
118 crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES, 289 crypto::SymmetricKey::GenerateRandomKey(crypto::SymmetricKey::AES,
119 kKeySizeBits)); 290 kKeySizeBits));
120 291
121 ASSERT_TRUE(random_key->GetRawKey(&key_)); 292 ASSERT_TRUE(random_key->GetRawKey(&key_));
293
294 std::string local_public_key, local_public_key_x509, local_private_key;
295 std::string peer_public_key, peer_public_key_x509, peer_private_key;
296
297 ASSERT_TRUE(CreateP256KeyPair(&local_private_key, &local_public_key_x509,
298 &local_public_key));
299 ASSERT_TRUE(CreateP256KeyPair(&peer_private_key, &peer_public_key_x509,
300 &peer_public_key));
301
302 cryptographer_.reset(
303 new GCMMessageCryptographer(local_public_key, peer_public_key));
122 } 304 }
123 305
124 protected: 306 protected:
125 // Generates a cryptographically secure random salt of 16-octets in size, the 307 // Generates a cryptographically secure random salt of 16-octets in size, the
126 // required length as expected by the HKDF. 308 // required length as expected by the HKDF.
127 std::string GenerateRandomSalt() { 309 std::string GenerateRandomSalt() {
128 const size_t kSaltSize = 16; 310 const size_t kSaltSize = 16;
129 311
130 std::string salt; 312 std::string salt;
131 313
132 crypto::RandBytes(base::WriteInto(&salt, kSaltSize + 1), kSaltSize); 314 crypto::RandBytes(base::WriteInto(&salt, kSaltSize + 1), kSaltSize);
133 return salt; 315 return salt;
134 } 316 }
135 317
136 GCMMessageCryptographer* cryptographer() { return &cryptographer_; } 318 GCMMessageCryptographer* cryptographer() { return cryptographer_.get(); }
137 319
138 base::StringPiece key() const { return key_; } 320 base::StringPiece key() const { return key_; }
139 321
140 private: 322 private:
141 GCMMessageCryptographer cryptographer_; 323 scoped_ptr<GCMMessageCryptographer> cryptographer_;
142 324
143 std::string key_; 325 std::string key_;
144 }; 326 };
145 327
146 TEST_F(GCMMessageCryptographerTest, RoundTrip) { 328 TEST_F(GCMMessageCryptographerTest, RoundTrip) {
147 const std::string salt = GenerateRandomSalt(); 329 const std::string salt = GenerateRandomSalt();
148 330
149 size_t record_size = 0; 331 size_t record_size = 0;
150 332
151 std::string ciphertext, plaintext; 333 std::string ciphertext, plaintext;
(...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after
291 if (!has_output) { 473 if (!has_output) {
292 EXPECT_FALSE(result); 474 EXPECT_FALSE(result);
293 continue; 475 continue;
294 } 476 }
295 477
296 EXPECT_TRUE(result); 478 EXPECT_TRUE(result);
297 EXPECT_EQ(kDecryptionTestVectors[i].output, plaintext); 479 EXPECT_EQ(kDecryptionTestVectors[i].output, plaintext);
298 } 480 }
299 } 481 }
300 482
483 template <typename I> std::string n2hexstr(I w, size_t hex_len = sizeof(I)<<1) {
484 static const char* digits = "0123456789ABCDEF";
485 std::string rc(hex_len,'0');
486 for (size_t i=0, j=(hex_len-1)*4 ; i<hex_len; ++i,j-=4)
487 rc[i] = digits[(w>>j) & 0x0f];
488 return rc;
489 }
490
491 TEST_F(GCMMessageCryptographerTest, ReferenceTest) {
492 // This test verifies Chrome's implementation against the reference vector
493 // given in the draft-thomson-http-encryption examples.
494 const char kSalt[] = "Qg61ZJRva_XBE9IEUelU3A";
495 const char kPayload[] = "G6j_sfKg0qebO62yXpTCayN2KV24QitNiTvLgcFiEj0";
496
497 const char kLocalPrivateKey[] = "9FWl15_QUQAWDaD3k3l50ZBZQJ4au27F1V4F0uLSD_M";
498 const char kLocalPublicKey[] =
499 "BCEkBjzL8Z3C-oi2Q7oE5t2Np-p7osjGLg93qUP0wvqRT21EEWyf0cQDQcakQMqz4hQKYOQ3"
500 "il2nNZct4HgAUQU";
501
502 // Note: X.509 SubjectPublicKeyInfo representation of |kLocalPublicKey|.
503 const char kLocalPublicKeyX509[] = ""; // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXX
504
505 const char kPeerPrivateKey[] = "vG7TmzUX9NfVR4XUGBkLAFu8iDyQe-q_165JkkN0Vlw";
506 const char kPeerPublicKey[] =
507 "BDgpRKok2GZZDmS4r63vbJSUtcQx4Fq1V58-6-3NbZzSTlZsQiCEDTQy3CZ0ZMsqeqsEb7qW"
508 "2blQHA4S48fynTk";
509
510 const char kExpectedOutput[] = "I am the walrus";
511
512 std::string salt;
513 ASSERT_TRUE(base::Base64UrlDecode(
514 kSalt, base::Base64UrlDecodePolicy::IGNORE_PADDING, &salt));
515
516 std::string payload;
517 ASSERT_TRUE(base::Base64UrlDecode(
518 kPayload, base::Base64UrlDecodePolicy::IGNORE_PADDING, &payload));
519
520 std::string local_private_key, local_public_key, local_public_key_x509;
521 ASSERT_TRUE(base::Base64UrlDecode(kLocalPrivateKey,
522 base::Base64UrlDecodePolicy::IGNORE_PADDING,
523 &local_private_key));
524 ASSERT_TRUE(base::Base64UrlDecode(kLocalPublicKey,
525 base::Base64UrlDecodePolicy::IGNORE_PADDING,
526 &local_public_key));
527 ASSERT_TRUE(base::Base64UrlDecode(kLocalPublicKeyX509,
528 base::Base64UrlDecodePolicy::IGNORE_PADDING,
529 &local_public_key_x509));
530
531 std::string peer_private_key, peer_public_key;
532 ASSERT_TRUE(base::Base64UrlDecode(kPeerPrivateKey,
533 base::Base64UrlDecodePolicy::IGNORE_PADDING,
534 &peer_private_key));
535 ASSERT_TRUE(base::Base64UrlDecode(kPeerPublicKey,
536 base::Base64UrlDecodePolicy::IGNORE_PADDING,
537 &peer_public_key));
538
539 std::string local_output, peer_output;
540 for (size_t i = 0; i < local_public_key.size(); ++i)
541 local_output += "0x" + n2hexstr(local_public_key[i]) + " ";
542
543 for (size_t i = 0; i < peer_public_key.size(); ++i)
544 peer_output += " " + std::to_string(static_cast<int>(peer_public_key[i]));
545
546 LOG(INFO) << "Local private: (" << local_public_key.size() << ") [" << local_o utput << "]";
547 //LOG(INFO) << "Peer public: (" << peer_public_key.size() << ") [" << peer_out put << "]";
548
549 std::string encrypted_private_key =
550 ConvertRawPrivateKeyToPKCS8EncryptedPrivateKeyInfo(local_private_key,
551 local_public_key);
552
553 std::string shared_secret;
554 ASSERT_TRUE(ComputeSharedP256Secret(encrypted_private_key, local_public_key_x5 09,
555 peer_public_key, &shared_secret));
556
557 std::string plaintext;
558
559 GCMMessageCryptographer cryptographer(local_public_key, peer_public_key);
560 ASSERT_TRUE(cryptographer.Decrypt(payload, shared_secret, salt, 4096,
561 &plaintext));
562
563 EXPECT_EQ(kExpectedOutput, plaintext);
564 }
565
301 } // namespace gcm 566 } // namespace gcm
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698