Updating trunk VERSION from 2139.0 to 2140.0
[chromium-blink-merge.git] / content / child / webcrypto / test / rsa_oaep_unittest.cc
blobb7f3e39d18e9957e9978f5c858023c295403ea67
1 // Copyright 2014 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 "base/logging.h"
6 #include "base/stl_util.h"
7 #include "content/child/webcrypto/algorithm_dispatch.h"
8 #include "content/child/webcrypto/crypto_data.h"
9 #include "content/child/webcrypto/status.h"
10 #include "content/child/webcrypto/test/test_helpers.h"
11 #include "content/child/webcrypto/webcrypto_util.h"
12 #include "testing/gtest/include/gtest/gtest.h"
13 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
16 namespace content {
18 namespace webcrypto {
20 namespace {
22 // Creates an RSA-OAEP algorithm
23 blink::WebCryptoAlgorithm CreateRsaOaepAlgorithm(
24 const std::vector<uint8_t>& label) {
25 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
26 blink::WebCryptoAlgorithmIdRsaOaep,
27 new blink::WebCryptoRsaOaepParams(
28 !label.empty(), vector_as_array(&label), label.size()));
31 scoped_ptr<base::DictionaryValue> CreatePublicKeyJwkDict() {
32 scoped_ptr<base::DictionaryValue> jwk(new base::DictionaryValue());
33 jwk->SetString("kty", "RSA");
34 jwk->SetString("n",
35 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyModulusHex)));
36 jwk->SetString("e",
37 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyExponentHex)));
38 return jwk.Pass();
41 // Import a PKCS#8 private key that uses RSAPrivateKey with the
42 // id-rsaEncryption OID.
43 TEST(WebCryptoRsaOaepTest, ImportPkcs8WithRsaEncryption) {
44 if (!SupportsRsaOaep()) {
45 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
46 return;
49 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
50 ASSERT_EQ(Status::Success(),
51 ImportKey(blink::WebCryptoKeyFormatPkcs8,
52 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
53 CreateRsaHashedImportAlgorithm(
54 blink::WebCryptoAlgorithmIdRsaOaep,
55 blink::WebCryptoAlgorithmIdSha1),
56 true,
57 blink::WebCryptoKeyUsageDecrypt,
58 &private_key));
61 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithNoAlg) {
62 if (!SupportsRsaOaep()) {
63 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
64 return;
67 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
69 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
70 ASSERT_EQ(Status::Success(),
71 ImportKeyJwkFromDict(*jwk.get(),
72 CreateRsaHashedImportAlgorithm(
73 blink::WebCryptoAlgorithmIdRsaOaep,
74 blink::WebCryptoAlgorithmIdSha1),
75 true,
76 blink::WebCryptoKeyUsageEncrypt,
77 &public_key));
80 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMatchingAlg) {
81 if (!SupportsRsaOaep()) {
82 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
83 return;
86 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
87 jwk->SetString("alg", "RSA-OAEP");
89 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
90 ASSERT_EQ(Status::Success(),
91 ImportKeyJwkFromDict(*jwk.get(),
92 CreateRsaHashedImportAlgorithm(
93 blink::WebCryptoAlgorithmIdRsaOaep,
94 blink::WebCryptoAlgorithmIdSha1),
95 true,
96 blink::WebCryptoKeyUsageEncrypt,
97 &public_key));
100 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedAlgFails) {
101 if (!SupportsRsaOaep()) {
102 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
103 return;
106 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
107 jwk->SetString("alg", "RSA-OAEP-512");
109 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
110 ASSERT_EQ(Status::ErrorJwkAlgorithmInconsistent(),
111 ImportKeyJwkFromDict(*jwk.get(),
112 CreateRsaHashedImportAlgorithm(
113 blink::WebCryptoAlgorithmIdRsaOaep,
114 blink::WebCryptoAlgorithmIdSha1),
115 true,
116 blink::WebCryptoKeyUsageEncrypt,
117 &public_key));
120 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedTypeFails) {
121 if (!SupportsRsaOaep()) {
122 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
123 return;
126 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
127 jwk->SetString("kty", "oct");
128 jwk->SetString("alg", "RSA-OAEP");
130 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
131 ASSERT_EQ(Status::ErrorJwkUnexpectedKty("RSA"),
132 ImportKeyJwkFromDict(*jwk.get(),
133 CreateRsaHashedImportAlgorithm(
134 blink::WebCryptoAlgorithmIdRsaOaep,
135 blink::WebCryptoAlgorithmIdSha1),
136 true,
137 blink::WebCryptoKeyUsageEncrypt,
138 &public_key));
141 TEST(WebCryptoRsaOaepTest, ExportPublicJwk) {
142 if (!SupportsRsaOaep()) {
143 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
144 return;
147 struct TestData {
148 blink::WebCryptoAlgorithmId hash_alg;
149 const char* expected_jwk_alg;
150 } kTestData[] = {{blink::WebCryptoAlgorithmIdSha1, "RSA-OAEP"},
151 {blink::WebCryptoAlgorithmIdSha256, "RSA-OAEP-256"},
152 {blink::WebCryptoAlgorithmIdSha384, "RSA-OAEP-384"},
153 {blink::WebCryptoAlgorithmIdSha512, "RSA-OAEP-512"}};
154 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kTestData); ++i) {
155 const TestData& test_data = kTestData[i];
156 SCOPED_TRACE(test_data.expected_jwk_alg);
158 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
159 jwk->SetString("alg", test_data.expected_jwk_alg);
161 // Import the key in a known-good format
162 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
163 ASSERT_EQ(Status::Success(),
164 ImportKeyJwkFromDict(
165 *jwk.get(),
166 CreateRsaHashedImportAlgorithm(
167 blink::WebCryptoAlgorithmIdRsaOaep, test_data.hash_alg),
168 true,
169 blink::WebCryptoKeyUsageEncrypt,
170 &public_key));
172 // Now export the key as JWK and verify its contents
173 std::vector<uint8_t> jwk_data;
174 ASSERT_EQ(Status::Success(),
175 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk_data));
176 EXPECT_TRUE(VerifyPublicJwk(jwk_data,
177 test_data.expected_jwk_alg,
178 kPublicKeyModulusHex,
179 kPublicKeyExponentHex,
180 blink::WebCryptoKeyUsageEncrypt));
184 TEST(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) {
185 if (!SupportsRsaOaep()) {
186 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
187 return;
190 scoped_ptr<base::ListValue> tests;
191 ASSERT_TRUE(ReadJsonTestFileToList("rsa_oaep.json", &tests));
193 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) {
194 SCOPED_TRACE(test_index);
196 base::DictionaryValue* test = NULL;
197 ASSERT_TRUE(tests->GetDictionary(test_index, &test));
199 blink::WebCryptoAlgorithm digest_algorithm =
200 GetDigestAlgorithm(test, "hash");
201 ASSERT_FALSE(digest_algorithm.isNull());
202 std::vector<uint8_t> public_key_der =
203 GetBytesFromHexString(test, "public_key");
204 std::vector<uint8_t> private_key_der =
205 GetBytesFromHexString(test, "private_key");
206 std::vector<uint8_t> ciphertext = GetBytesFromHexString(test, "ciphertext");
207 std::vector<uint8_t> plaintext = GetBytesFromHexString(test, "plaintext");
208 std::vector<uint8_t> label = GetBytesFromHexString(test, "label");
210 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
211 blink::WebCryptoAlgorithmIdRsaOaep, digest_algorithm.id());
212 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
213 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
215 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(public_key_der,
216 private_key_der,
217 import_algorithm,
218 false,
219 blink::WebCryptoKeyUsageEncrypt,
220 blink::WebCryptoKeyUsageDecrypt,
221 &public_key,
222 &private_key));
224 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
225 std::vector<uint8_t> decrypted_data;
226 ASSERT_EQ(Status::Success(),
227 Decrypt(op_algorithm,
228 private_key,
229 CryptoData(ciphertext),
230 &decrypted_data));
231 EXPECT_BYTES_EQ(plaintext, decrypted_data);
232 std::vector<uint8_t> encrypted_data;
233 ASSERT_EQ(
234 Status::Success(),
235 Encrypt(
236 op_algorithm, public_key, CryptoData(plaintext), &encrypted_data));
237 std::vector<uint8_t> redecrypted_data;
238 ASSERT_EQ(Status::Success(),
239 Decrypt(op_algorithm,
240 private_key,
241 CryptoData(encrypted_data),
242 &redecrypted_data));
243 EXPECT_BYTES_EQ(plaintext, redecrypted_data);
247 TEST(WebCryptoRsaOaepTest, EncryptWithLargeMessageFails) {
248 if (!SupportsRsaOaep()) {
249 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
250 return;
253 const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha1;
254 const size_t kHashSize = 20;
256 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
258 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
259 ASSERT_EQ(Status::Success(),
260 ImportKeyJwkFromDict(*jwk.get(),
261 CreateRsaHashedImportAlgorithm(
262 blink::WebCryptoAlgorithmIdRsaOaep, kHash),
263 true,
264 blink::WebCryptoKeyUsageEncrypt,
265 &public_key));
267 // The maximum size of an encrypted message is:
268 // modulus length
269 // - 1 (leading octet)
270 // - hash size (maskedSeed)
271 // - hash size (lHash portion of maskedDB)
272 // - 1 (at least one octet for the padding string)
273 size_t kMaxMessageSize = (kModulusLengthBits / 8) - 2 - (2 * kHashSize);
275 // The label has no influence on the maximum message size. For simplicity,
276 // use the empty string.
277 std::vector<uint8_t> label;
278 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
280 // Test that a message just before the boundary succeeds.
281 std::string large_message;
282 large_message.resize(kMaxMessageSize - 1, 'A');
284 std::vector<uint8_t> ciphertext;
285 ASSERT_EQ(
286 Status::Success(),
287 Encrypt(
288 op_algorithm, public_key, CryptoData(large_message), &ciphertext));
290 // Test that a message at the boundary succeeds.
291 large_message.resize(kMaxMessageSize, 'A');
292 ciphertext.clear();
294 ASSERT_EQ(
295 Status::Success(),
296 Encrypt(
297 op_algorithm, public_key, CryptoData(large_message), &ciphertext));
299 // Test that a message greater than the largest size fails.
300 large_message.resize(kMaxMessageSize + 1, 'A');
301 ciphertext.clear();
303 ASSERT_EQ(
304 Status::OperationError(),
305 Encrypt(
306 op_algorithm, public_key, CryptoData(large_message), &ciphertext));
309 // Ensures that if the selected hash algorithm for the RSA-OAEP message is too
310 // large, then it is rejected, independent of the actual message to be
311 // encrypted.
312 // For example, a 1024-bit RSA key is too small to accomodate a message that
313 // uses OAEP with SHA-512, since it requires 1040 bits to encode
314 // (2 * hash size + 2 padding bytes).
315 TEST(WebCryptoRsaOaepTest, EncryptWithLargeDigestFails) {
316 if (!SupportsRsaOaep()) {
317 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
318 return;
321 const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha512;
323 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict());
325 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
326 ASSERT_EQ(Status::Success(),
327 ImportKeyJwkFromDict(*jwk.get(),
328 CreateRsaHashedImportAlgorithm(
329 blink::WebCryptoAlgorithmIdRsaOaep, kHash),
330 true,
331 blink::WebCryptoKeyUsageEncrypt,
332 &public_key));
334 // The label has no influence on the maximum message size. For simplicity,
335 // use the empty string.
336 std::vector<uint8_t> label;
337 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
339 std::string small_message("A");
340 std::vector<uint8_t> ciphertext;
341 // This is an operation error, as the internal consistency checking of the
342 // algorithm parameters is up to the implementation.
343 ASSERT_EQ(
344 Status::OperationError(),
345 Encrypt(
346 op_algorithm, public_key, CryptoData(small_message), &ciphertext));
349 TEST(WebCryptoRsaOaepTest, DecryptWithLargeMessageFails) {
350 if (!SupportsRsaOaep()) {
351 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
352 return;
355 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
356 ASSERT_EQ(Status::Success(),
357 ImportKey(blink::WebCryptoKeyFormatPkcs8,
358 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)),
359 CreateRsaHashedImportAlgorithm(
360 blink::WebCryptoAlgorithmIdRsaOaep,
361 blink::WebCryptoAlgorithmIdSha1),
362 true,
363 blink::WebCryptoKeyUsageDecrypt,
364 &private_key));
366 // The label has no influence on the maximum message size. For simplicity,
367 // use the empty string.
368 std::vector<uint8_t> label;
369 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label);
371 std::string large_dummy_message(kModulusLengthBits / 8, 'A');
372 std::vector<uint8_t> plaintext;
374 ASSERT_EQ(Status::OperationError(),
375 Decrypt(op_algorithm,
376 private_key,
377 CryptoData(large_dummy_message),
378 &plaintext));
381 TEST(WebCryptoRsaOaepTest, WrapUnwrapRawKey) {
382 if (!SupportsRsaOaep()) {
383 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
384 return;
387 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
388 blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1);
389 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
390 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
392 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
393 HexStringToBytes(kPublicKeySpkiDerHex),
394 HexStringToBytes(kPrivateKeyPkcs8DerHex),
395 import_algorithm,
396 false,
397 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
398 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey,
399 &public_key,
400 &private_key));
402 std::vector<uint8_t> label;
403 blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label);
405 const std::string key_hex = "000102030405060708090A0B0C0D0E0F";
406 const blink::WebCryptoAlgorithm key_algorithm =
407 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
409 blink::WebCryptoKey key =
410 ImportSecretKeyFromRaw(HexStringToBytes(key_hex),
411 key_algorithm,
412 blink::WebCryptoKeyUsageEncrypt);
413 ASSERT_FALSE(key.isNull());
415 std::vector<uint8_t> wrapped_key;
416 ASSERT_EQ(Status::Success(),
417 WrapKey(blink::WebCryptoKeyFormatRaw,
418 key,
419 public_key,
420 wrapping_algorithm,
421 &wrapped_key));
423 // Verify that |wrapped_key| can be decrypted and yields the key data.
424 // Because |private_key| supports both decrypt and unwrap, this is valid.
425 std::vector<uint8_t> decrypted_key;
426 ASSERT_EQ(Status::Success(),
427 Decrypt(wrapping_algorithm,
428 private_key,
429 CryptoData(wrapped_key),
430 &decrypted_key));
431 EXPECT_BYTES_EQ_HEX(key_hex, decrypted_key);
433 // Now attempt to unwrap the key, which should also decrypt the data.
434 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull();
435 ASSERT_EQ(Status::Success(),
436 UnwrapKey(blink::WebCryptoKeyFormatRaw,
437 CryptoData(wrapped_key),
438 private_key,
439 wrapping_algorithm,
440 key_algorithm,
441 true,
442 blink::WebCryptoKeyUsageEncrypt,
443 &unwrapped_key));
444 ASSERT_FALSE(unwrapped_key.isNull());
446 std::vector<uint8_t> raw_key;
447 ASSERT_EQ(Status::Success(),
448 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
449 EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
452 TEST(WebCryptoRsaOaepTest, WrapUnwrapJwkSymKey) {
453 if (!SupportsRsaOaep()) {
454 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
455 return;
458 // The public and private portions of a 2048-bit RSA key with the
459 // id-rsaEncryption OID
460 const char kPublicKey2048SpkiDerHex[] =
461 "30820122300d06092a864886f70d01010105000382010f003082010a0282010100c5d8ce"
462 "137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b300c6a6c9764"
463 "f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448e7183a3a68"
464 "e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872458d1b1e2f"
465 "7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34ba17bc5d08"
466 "a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea9893652d02fc606"
467 "36f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d733711c89ca"
468 "749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b557c16615d"
469 "5d0203010001";
470 const char kPrivateKey2048Pkcs8DerHex[] =
471 "308204bd020100300d06092a864886f70d0101010500048204a7308204a3020100028201"
472 "0100c5d8ce137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b30"
473 "0c6a6c9764f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448"
474 "e7183a3a68e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872"
475 "458d1b1e2f7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34"
476 "ba17bc5d08a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea98936"
477 "52d02fc60636f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d7"
478 "33711c89ca749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b"
479 "557c16615d5d02030100010282010074b70feb41a0b0fcbc207670400556c9450042ede3"
480 "d4383fb1ce8f3558a6d4641d26dd4c333fa4db842d2b9cf9d2354d3e16ad027a9f682d8c"
481 "f4145a1ad97b9edcd8a41c402bd9d8db10f62f43df854cdccbbb2100834f083f53ed6d42"
482 "b1b729a59072b004a4e945fc027db15e9c121d1251464d320d4774d5732df6b3dbf751f4"
483 "9b19c9db201e19989c883bbaad5333db47f64f6f7a95b8d4936b10d945aa3f794cfaab62"
484 "e7d47686129358914f3b8085f03698a650ab5b8c7e45813f2b0515ec05b6e5195b6a7c2a"
485 "0d36969745f431ded4fd059f6aa361a4649541016d356297362b778e90f077d48815b339"
486 "ec6f43aba345df93e67fcb6c2cb5b4544e9be902818100e9c90abe5f9f32468c5b6d630c"
487 "54a4d7d75e29a72cf792f21e242aac78fd7995c42dfd4ae871d2619ff7096cb05baa78e3"
488 "23ecab338401a8059adf7a0d8be3b21edc9a9c82c5605634a2ec81ec053271721351868a"
489 "4c2e50c689d7cef94e31ff23658af5843366e2b289c5bf81d72756a7b93487dd8770d69c"
490 "1f4e089d6d89f302818100d8a58a727c4e209132afd9933b98c89aca862a01cc0be74133"
491 "bee517909e5c379e526895ac4af11780c1fe91194c777c9670b6423f0f5a32fd7691a622"
492 "113eef4bed2ef863363a335fd55b0e75088c582437237d7f3ed3f0a643950237bc6e6277"
493 "ccd0d0a1b4170aa1047aa7ffa7c8c54be10e8c7327ae2e0885663963817f6f02818100e5"
494 "aed9ba4d71b7502e6748a1ce247ecb7bd10c352d6d9256031cdf3c11a65e44b0b7ca2945"
495 "134671195af84c6b3bb3d10ebf65ae916f38bd5dbc59a0ad1c69b8beaf57cb3a8335f19b"
496 "c7117b576987b48331cd9fd3d1a293436b7bb5e1a35c6560de4b5688ea834367cb0997eb"
497 "b578f59ed4cb724c47dba94d3b484c1876dcd70281807f15bc7d2406007cac2b138a96af"
498 "2d1e00276b84da593132c253fcb73212732dfd25824c2a615bc3d9b7f2c8d2fa542d3562"
499 "b0c7738e61eeff580a6056239fb367ea9e5efe73d4f846033602e90c36a78db6fa8ea792"
500 "0769675ec58e237bd994d189c8045a96f5dd3a4f12547257ce224e3c9af830a4da3c0eab"
501 "9227a0035ae9028180067caea877e0b23090fc689322b71fbcce63d6596e66ab5fcdbaa0"
502 "0d49e93aba8effb4518c2da637f209028401a68f344865b4956b032c69acde51d29177ca"
503 "3db99fdbf5e74848ed4fa7bdfc2ebb60e2aaa5354770a763e1399ab7a2099762d525fea0"
504 "37f3e1972c45a477e66db95c9609bb27f862700ef93379930786cf751b";
505 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm(
506 blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1);
507 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
508 blink::WebCryptoKey private_key = blink::WebCryptoKey::createNull();
510 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
511 HexStringToBytes(kPublicKey2048SpkiDerHex),
512 HexStringToBytes(kPrivateKey2048Pkcs8DerHex),
513 import_algorithm,
514 false,
515 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey,
516 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey,
517 &public_key,
518 &private_key));
520 std::vector<uint8_t> label;
521 blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label);
523 const std::string key_hex = "000102030405060708090a0b0c0d0e0f";
524 const blink::WebCryptoAlgorithm key_algorithm =
525 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc);
527 blink::WebCryptoKey key =
528 ImportSecretKeyFromRaw(HexStringToBytes(key_hex),
529 key_algorithm,
530 blink::WebCryptoKeyUsageEncrypt);
531 ASSERT_FALSE(key.isNull());
533 std::vector<uint8_t> wrapped_key;
534 ASSERT_EQ(Status::Success(),
535 WrapKey(blink::WebCryptoKeyFormatJwk,
536 key,
537 public_key,
538 wrapping_algorithm,
539 &wrapped_key));
541 // Verify that |wrapped_key| can be decrypted and yields a valid JWK object.
542 // Because |private_key| supports both decrypt and unwrap, this is valid.
543 std::vector<uint8_t> decrypted_jwk;
544 ASSERT_EQ(Status::Success(),
545 Decrypt(wrapping_algorithm,
546 private_key,
547 CryptoData(wrapped_key),
548 &decrypted_jwk));
549 EXPECT_TRUE(VerifySecretJwk(
550 decrypted_jwk, "A128CBC", key_hex, blink::WebCryptoKeyUsageEncrypt));
552 // Now attempt to unwrap the key, which should also decrypt the data.
553 blink::WebCryptoKey unwrapped_key = blink::WebCryptoKey::createNull();
554 ASSERT_EQ(Status::Success(),
555 UnwrapKey(blink::WebCryptoKeyFormatJwk,
556 CryptoData(wrapped_key),
557 private_key,
558 wrapping_algorithm,
559 key_algorithm,
560 true,
561 blink::WebCryptoKeyUsageEncrypt,
562 &unwrapped_key));
563 ASSERT_FALSE(unwrapped_key.isNull());
565 std::vector<uint8_t> raw_key;
566 ASSERT_EQ(Status::Success(),
567 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key));
568 EXPECT_BYTES_EQ_HEX(key_hex, raw_key);
571 TEST(WebCryptoRsaOaepTest, ImportExportJwkRsaPublicKey) {
572 if (!SupportsRsaOaep()) {
573 LOG(WARNING) << "RSA-OAEP support not present; skipping.";
574 return;
577 struct TestCase {
578 const blink::WebCryptoAlgorithmId hash;
579 const blink::WebCryptoKeyUsageMask usage;
580 const char* const jwk_alg;
582 const TestCase kTests[] = {{blink::WebCryptoAlgorithmIdSha1,
583 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP"},
584 {blink::WebCryptoAlgorithmIdSha256,
585 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP-256"},
586 {blink::WebCryptoAlgorithmIdSha384,
587 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP-384"},
588 {blink::WebCryptoAlgorithmIdSha512,
589 blink::WebCryptoKeyUsageEncrypt, "RSA-OAEP-512"}};
591 for (size_t test_index = 0; test_index < ARRAYSIZE_UNSAFE(kTests);
592 ++test_index) {
593 SCOPED_TRACE(test_index);
594 const TestCase& test = kTests[test_index];
596 const blink::WebCryptoAlgorithm import_algorithm =
597 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep,
598 test.hash);
600 // Import the spki to create a public key
601 blink::WebCryptoKey public_key = blink::WebCryptoKey::createNull();
602 ASSERT_EQ(Status::Success(),
603 ImportKey(blink::WebCryptoKeyFormatSpki,
604 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)),
605 import_algorithm,
606 true,
607 test.usage,
608 &public_key));
610 // Export the public key as JWK and verify its contents
611 std::vector<uint8_t> jwk;
612 ASSERT_EQ(Status::Success(),
613 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk));
614 EXPECT_TRUE(VerifyPublicJwk(jwk,
615 test.jwk_alg,
616 kPublicKeyModulusHex,
617 kPublicKeyExponentHex,
618 test.usage));
620 // Import the JWK back in to create a new key
621 blink::WebCryptoKey public_key2 = blink::WebCryptoKey::createNull();
622 ASSERT_EQ(Status::Success(),
623 ImportKey(blink::WebCryptoKeyFormatJwk,
624 CryptoData(jwk),
625 import_algorithm,
626 true,
627 test.usage,
628 &public_key2));
629 ASSERT_TRUE(public_key2.handle());
630 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type());
631 EXPECT_TRUE(public_key2.extractable());
632 EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id());
634 // TODO(eroman): Export the SPKI and verify matches.
638 } // namespace
640 } // namespace webcrypto
642 } // namespace content