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 "components/webcrypto/algorithm_dispatch.h"
8 #include "components/webcrypto/crypto_data.h"
9 #include "components/webcrypto/jwk.h"
10 #include "components/webcrypto/status.h"
11 #include "components/webcrypto/test/test_helpers.h"
12 #include "components/webcrypto/webcrypto_util.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
15 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
21 // Creates an RSA-OAEP algorithm
22 blink::WebCryptoAlgorithm
CreateRsaOaepAlgorithm(
23 const std::vector
<uint8_t>& label
) {
24 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
25 blink::WebCryptoAlgorithmIdRsaOaep
,
26 new blink::WebCryptoRsaOaepParams(
27 !label
.empty(), vector_as_array(&label
),
28 static_cast<unsigned int>(label
.size())));
31 scoped_ptr
<base::DictionaryValue
> CreatePublicKeyJwkDict() {
32 scoped_ptr
<base::DictionaryValue
> jwk(new base::DictionaryValue());
33 jwk
->SetString("kty", "RSA");
35 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyModulusHex
)));
37 Base64EncodeUrlSafe(HexStringToBytes(kPublicKeyExponentHex
)));
41 class WebCryptoRsaOaepTest
: public WebCryptoTestBase
{};
43 // Import a PKCS#8 private key that uses RSAPrivateKey with the
44 // id-rsaEncryption OID.
45 TEST_F(WebCryptoRsaOaepTest
, ImportPkcs8WithRsaEncryption
) {
46 if (!SupportsRsaOaep()) {
47 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
51 blink::WebCryptoKey private_key
;
52 ASSERT_EQ(Status::Success(),
53 ImportKey(blink::WebCryptoKeyFormatPkcs8
,
54 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex
)),
55 CreateRsaHashedImportAlgorithm(
56 blink::WebCryptoAlgorithmIdRsaOaep
,
57 blink::WebCryptoAlgorithmIdSha1
),
58 true, blink::WebCryptoKeyUsageDecrypt
, &private_key
));
61 TEST_F(WebCryptoRsaOaepTest
, ImportPublicJwkWithNoAlg
) {
62 if (!SupportsRsaOaep()) {
63 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
67 scoped_ptr
<base::DictionaryValue
> jwk(CreatePublicKeyJwkDict());
69 blink::WebCryptoKey public_key
;
72 ImportKeyJwkFromDict(*jwk
.get(), CreateRsaHashedImportAlgorithm(
73 blink::WebCryptoAlgorithmIdRsaOaep
,
74 blink::WebCryptoAlgorithmIdSha1
),
75 true, blink::WebCryptoKeyUsageEncrypt
, &public_key
));
78 TEST_F(WebCryptoRsaOaepTest
, ImportPublicJwkWithMatchingAlg
) {
79 if (!SupportsRsaOaep()) {
80 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
84 scoped_ptr
<base::DictionaryValue
> jwk(CreatePublicKeyJwkDict());
85 jwk
->SetString("alg", "RSA-OAEP");
87 blink::WebCryptoKey public_key
;
90 ImportKeyJwkFromDict(*jwk
.get(), CreateRsaHashedImportAlgorithm(
91 blink::WebCryptoAlgorithmIdRsaOaep
,
92 blink::WebCryptoAlgorithmIdSha1
),
93 true, blink::WebCryptoKeyUsageEncrypt
, &public_key
));
96 TEST_F(WebCryptoRsaOaepTest
, ImportPublicJwkWithMismatchedAlgFails
) {
97 if (!SupportsRsaOaep()) {
98 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
102 scoped_ptr
<base::DictionaryValue
> jwk(CreatePublicKeyJwkDict());
103 jwk
->SetString("alg", "RSA-OAEP-512");
105 blink::WebCryptoKey public_key
;
107 Status::ErrorJwkAlgorithmInconsistent(),
108 ImportKeyJwkFromDict(*jwk
.get(), CreateRsaHashedImportAlgorithm(
109 blink::WebCryptoAlgorithmIdRsaOaep
,
110 blink::WebCryptoAlgorithmIdSha1
),
111 true, blink::WebCryptoKeyUsageEncrypt
, &public_key
));
114 TEST_F(WebCryptoRsaOaepTest
, ImportPublicJwkWithMismatchedTypeFails
) {
115 if (!SupportsRsaOaep()) {
116 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
120 scoped_ptr
<base::DictionaryValue
> jwk(CreatePublicKeyJwkDict());
121 jwk
->SetString("kty", "oct");
122 jwk
->SetString("alg", "RSA-OAEP");
124 blink::WebCryptoKey public_key
;
126 Status::ErrorJwkUnexpectedKty("RSA"),
127 ImportKeyJwkFromDict(*jwk
.get(), CreateRsaHashedImportAlgorithm(
128 blink::WebCryptoAlgorithmIdRsaOaep
,
129 blink::WebCryptoAlgorithmIdSha1
),
130 true, blink::WebCryptoKeyUsageEncrypt
, &public_key
));
133 TEST_F(WebCryptoRsaOaepTest
, ExportPublicJwk
) {
134 if (!SupportsRsaOaep()) {
135 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
140 blink::WebCryptoAlgorithmId hash_alg
;
141 const char* expected_jwk_alg
;
142 } kTestData
[] = {{blink::WebCryptoAlgorithmIdSha1
, "RSA-OAEP"},
143 {blink::WebCryptoAlgorithmIdSha256
, "RSA-OAEP-256"},
144 {blink::WebCryptoAlgorithmIdSha384
, "RSA-OAEP-384"},
145 {blink::WebCryptoAlgorithmIdSha512
, "RSA-OAEP-512"}};
146 for (size_t i
= 0; i
< arraysize(kTestData
); ++i
) {
147 const TestData
& test_data
= kTestData
[i
];
148 SCOPED_TRACE(test_data
.expected_jwk_alg
);
150 scoped_ptr
<base::DictionaryValue
> jwk(CreatePublicKeyJwkDict());
151 jwk
->SetString("alg", test_data
.expected_jwk_alg
);
153 // Import the key in a known-good format
154 blink::WebCryptoKey public_key
;
155 ASSERT_EQ(Status::Success(),
156 ImportKeyJwkFromDict(
158 CreateRsaHashedImportAlgorithm(
159 blink::WebCryptoAlgorithmIdRsaOaep
, test_data
.hash_alg
),
160 true, blink::WebCryptoKeyUsageEncrypt
, &public_key
));
162 // Now export the key as JWK and verify its contents
163 std::vector
<uint8_t> jwk_data
;
164 ASSERT_EQ(Status::Success(),
165 ExportKey(blink::WebCryptoKeyFormatJwk
, public_key
, &jwk_data
));
166 EXPECT_TRUE(VerifyPublicJwk(jwk_data
, test_data
.expected_jwk_alg
,
167 kPublicKeyModulusHex
, kPublicKeyExponentHex
,
168 blink::WebCryptoKeyUsageEncrypt
));
172 TEST_F(WebCryptoRsaOaepTest
, EncryptDecryptKnownAnswerTest
) {
173 if (!SupportsRsaOaep()) {
174 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
178 scoped_ptr
<base::ListValue
> tests
;
179 ASSERT_TRUE(ReadJsonTestFileToList("rsa_oaep.json", &tests
));
181 for (size_t test_index
= 0; test_index
< tests
->GetSize(); ++test_index
) {
182 SCOPED_TRACE(test_index
);
184 base::DictionaryValue
* test
= NULL
;
185 ASSERT_TRUE(tests
->GetDictionary(test_index
, &test
));
187 blink::WebCryptoAlgorithm digest_algorithm
=
188 GetDigestAlgorithm(test
, "hash");
189 ASSERT_FALSE(digest_algorithm
.isNull());
190 std::vector
<uint8_t> public_key_der
=
191 GetBytesFromHexString(test
, "public_key");
192 std::vector
<uint8_t> private_key_der
=
193 GetBytesFromHexString(test
, "private_key");
194 std::vector
<uint8_t> ciphertext
= GetBytesFromHexString(test
, "ciphertext");
195 std::vector
<uint8_t> plaintext
= GetBytesFromHexString(test
, "plaintext");
196 std::vector
<uint8_t> label
= GetBytesFromHexString(test
, "label");
198 blink::WebCryptoAlgorithm import_algorithm
= CreateRsaHashedImportAlgorithm(
199 blink::WebCryptoAlgorithmIdRsaOaep
, digest_algorithm
.id());
200 blink::WebCryptoKey public_key
;
201 blink::WebCryptoKey private_key
;
203 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
204 public_key_der
, private_key_der
, import_algorithm
, false,
205 blink::WebCryptoKeyUsageEncrypt
, blink::WebCryptoKeyUsageDecrypt
,
206 &public_key
, &private_key
));
208 blink::WebCryptoAlgorithm op_algorithm
= CreateRsaOaepAlgorithm(label
);
209 std::vector
<uint8_t> decrypted_data
;
210 ASSERT_EQ(Status::Success(),
211 Decrypt(op_algorithm
, private_key
, CryptoData(ciphertext
),
213 EXPECT_BYTES_EQ(plaintext
, decrypted_data
);
214 std::vector
<uint8_t> encrypted_data
;
215 ASSERT_EQ(Status::Success(),
216 Encrypt(op_algorithm
, public_key
, CryptoData(plaintext
),
218 std::vector
<uint8_t> redecrypted_data
;
219 ASSERT_EQ(Status::Success(),
220 Decrypt(op_algorithm
, private_key
, CryptoData(encrypted_data
),
222 EXPECT_BYTES_EQ(plaintext
, redecrypted_data
);
226 TEST_F(WebCryptoRsaOaepTest
, EncryptWithLargeMessageFails
) {
227 if (!SupportsRsaOaep()) {
228 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
232 const blink::WebCryptoAlgorithmId kHash
= blink::WebCryptoAlgorithmIdSha1
;
233 const size_t kHashSize
= 20;
235 scoped_ptr
<base::DictionaryValue
> jwk(CreatePublicKeyJwkDict());
237 blink::WebCryptoKey public_key
;
238 ASSERT_EQ(Status::Success(),
239 ImportKeyJwkFromDict(
240 *jwk
.get(), CreateRsaHashedImportAlgorithm(
241 blink::WebCryptoAlgorithmIdRsaOaep
, kHash
),
242 true, blink::WebCryptoKeyUsageEncrypt
, &public_key
));
244 // The maximum size of an encrypted message is:
246 // - 1 (leading octet)
247 // - hash size (maskedSeed)
248 // - hash size (lHash portion of maskedDB)
249 // - 1 (at least one octet for the padding string)
250 size_t kMaxMessageSize
= (kModulusLengthBits
/ 8) - 2 - (2 * kHashSize
);
252 // The label has no influence on the maximum message size. For simplicity,
253 // use the empty string.
254 std::vector
<uint8_t> label
;
255 blink::WebCryptoAlgorithm op_algorithm
= CreateRsaOaepAlgorithm(label
);
257 // Test that a message just before the boundary succeeds.
258 std::string large_message
;
259 large_message
.resize(kMaxMessageSize
- 1, 'A');
261 std::vector
<uint8_t> ciphertext
;
262 ASSERT_EQ(Status::Success(), Encrypt(op_algorithm
, public_key
,
263 CryptoData(large_message
), &ciphertext
));
265 // Test that a message at the boundary succeeds.
266 large_message
.resize(kMaxMessageSize
, 'A');
269 ASSERT_EQ(Status::Success(), Encrypt(op_algorithm
, public_key
,
270 CryptoData(large_message
), &ciphertext
));
272 // Test that a message greater than the largest size fails.
273 large_message
.resize(kMaxMessageSize
+ 1, 'A');
276 ASSERT_EQ(Status::OperationError(),
277 Encrypt(op_algorithm
, public_key
, CryptoData(large_message
),
281 // Ensures that if the selected hash algorithm for the RSA-OAEP message is too
282 // large, then it is rejected, independent of the actual message to be
284 // For example, a 1024-bit RSA key is too small to accomodate a message that
285 // uses OAEP with SHA-512, since it requires 1040 bits to encode
286 // (2 * hash size + 2 padding bytes).
287 TEST_F(WebCryptoRsaOaepTest
, EncryptWithLargeDigestFails
) {
288 if (!SupportsRsaOaep()) {
289 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
293 const blink::WebCryptoAlgorithmId kHash
= blink::WebCryptoAlgorithmIdSha512
;
295 scoped_ptr
<base::DictionaryValue
> jwk(CreatePublicKeyJwkDict());
297 blink::WebCryptoKey public_key
;
298 ASSERT_EQ(Status::Success(),
299 ImportKeyJwkFromDict(
300 *jwk
.get(), CreateRsaHashedImportAlgorithm(
301 blink::WebCryptoAlgorithmIdRsaOaep
, kHash
),
302 true, blink::WebCryptoKeyUsageEncrypt
, &public_key
));
304 // The label has no influence on the maximum message size. For simplicity,
305 // use the empty string.
306 std::vector
<uint8_t> label
;
307 blink::WebCryptoAlgorithm op_algorithm
= CreateRsaOaepAlgorithm(label
);
309 std::string
small_message("A");
310 std::vector
<uint8_t> ciphertext
;
311 // This is an operation error, as the internal consistency checking of the
312 // algorithm parameters is up to the implementation.
313 ASSERT_EQ(Status::OperationError(),
314 Encrypt(op_algorithm
, public_key
, CryptoData(small_message
),
318 TEST_F(WebCryptoRsaOaepTest
, DecryptWithLargeMessageFails
) {
319 if (!SupportsRsaOaep()) {
320 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
324 blink::WebCryptoKey private_key
;
325 ASSERT_EQ(Status::Success(),
326 ImportKey(blink::WebCryptoKeyFormatPkcs8
,
327 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex
)),
328 CreateRsaHashedImportAlgorithm(
329 blink::WebCryptoAlgorithmIdRsaOaep
,
330 blink::WebCryptoAlgorithmIdSha1
),
331 true, blink::WebCryptoKeyUsageDecrypt
, &private_key
));
333 // The label has no influence on the maximum message size. For simplicity,
334 // use the empty string.
335 std::vector
<uint8_t> label
;
336 blink::WebCryptoAlgorithm op_algorithm
= CreateRsaOaepAlgorithm(label
);
338 std::string
large_dummy_message(kModulusLengthBits
/ 8, 'A');
339 std::vector
<uint8_t> plaintext
;
341 ASSERT_EQ(Status::OperationError(),
342 Decrypt(op_algorithm
, private_key
, CryptoData(large_dummy_message
),
346 TEST_F(WebCryptoRsaOaepTest
, WrapUnwrapRawKey
) {
347 if (!SupportsRsaOaep()) {
348 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
352 blink::WebCryptoAlgorithm import_algorithm
= CreateRsaHashedImportAlgorithm(
353 blink::WebCryptoAlgorithmIdRsaOaep
, blink::WebCryptoAlgorithmIdSha1
);
354 blink::WebCryptoKey public_key
;
355 blink::WebCryptoKey private_key
;
357 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
358 HexStringToBytes(kPublicKeySpkiDerHex
),
359 HexStringToBytes(kPrivateKeyPkcs8DerHex
), import_algorithm
, false,
360 blink::WebCryptoKeyUsageEncrypt
| blink::WebCryptoKeyUsageWrapKey
,
361 blink::WebCryptoKeyUsageDecrypt
| blink::WebCryptoKeyUsageUnwrapKey
,
362 &public_key
, &private_key
));
364 std::vector
<uint8_t> label
;
365 blink::WebCryptoAlgorithm wrapping_algorithm
= CreateRsaOaepAlgorithm(label
);
367 const std::string key_hex
= "000102030405060708090A0B0C0D0E0F";
368 const blink::WebCryptoAlgorithm key_algorithm
=
369 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc
);
371 blink::WebCryptoKey key
=
372 ImportSecretKeyFromRaw(HexStringToBytes(key_hex
), key_algorithm
,
373 blink::WebCryptoKeyUsageEncrypt
);
374 ASSERT_FALSE(key
.isNull());
376 std::vector
<uint8_t> wrapped_key
;
377 ASSERT_EQ(Status::Success(),
378 WrapKey(blink::WebCryptoKeyFormatRaw
, key
, public_key
,
379 wrapping_algorithm
, &wrapped_key
));
381 // Verify that |wrapped_key| can be decrypted and yields the key data.
382 // Because |private_key| supports both decrypt and unwrap, this is valid.
383 std::vector
<uint8_t> decrypted_key
;
384 ASSERT_EQ(Status::Success(),
385 Decrypt(wrapping_algorithm
, private_key
, CryptoData(wrapped_key
),
387 EXPECT_BYTES_EQ_HEX(key_hex
, decrypted_key
);
389 // Now attempt to unwrap the key, which should also decrypt the data.
390 blink::WebCryptoKey unwrapped_key
;
391 ASSERT_EQ(Status::Success(),
392 UnwrapKey(blink::WebCryptoKeyFormatRaw
, CryptoData(wrapped_key
),
393 private_key
, wrapping_algorithm
, key_algorithm
, true,
394 blink::WebCryptoKeyUsageEncrypt
, &unwrapped_key
));
395 ASSERT_FALSE(unwrapped_key
.isNull());
397 std::vector
<uint8_t> raw_key
;
398 ASSERT_EQ(Status::Success(),
399 ExportKey(blink::WebCryptoKeyFormatRaw
, unwrapped_key
, &raw_key
));
400 EXPECT_BYTES_EQ_HEX(key_hex
, raw_key
);
403 TEST_F(WebCryptoRsaOaepTest
, WrapUnwrapJwkSymKey
) {
404 if (!SupportsRsaOaep()) {
405 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
409 // The public and private portions of a 2048-bit RSA key with the
410 // id-rsaEncryption OID
411 const char kPublicKey2048SpkiDerHex
[] =
412 "30820122300d06092a864886f70d01010105000382010f003082010a0282010100c5d8ce"
413 "137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b300c6a6c9764"
414 "f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448e7183a3a68"
415 "e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872458d1b1e2f"
416 "7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34ba17bc5d08"
417 "a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea9893652d02fc606"
418 "36f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d733711c89ca"
419 "749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b557c16615d"
421 const char kPrivateKey2048Pkcs8DerHex
[] =
422 "308204bd020100300d06092a864886f70d0101010500048204a7308204a3020100028201"
423 "0100c5d8ce137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b30"
424 "0c6a6c9764f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448"
425 "e7183a3a68e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872"
426 "458d1b1e2f7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34"
427 "ba17bc5d08a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea98936"
428 "52d02fc60636f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d7"
429 "33711c89ca749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b"
430 "557c16615d5d02030100010282010074b70feb41a0b0fcbc207670400556c9450042ede3"
431 "d4383fb1ce8f3558a6d4641d26dd4c333fa4db842d2b9cf9d2354d3e16ad027a9f682d8c"
432 "f4145a1ad97b9edcd8a41c402bd9d8db10f62f43df854cdccbbb2100834f083f53ed6d42"
433 "b1b729a59072b004a4e945fc027db15e9c121d1251464d320d4774d5732df6b3dbf751f4"
434 "9b19c9db201e19989c883bbaad5333db47f64f6f7a95b8d4936b10d945aa3f794cfaab62"
435 "e7d47686129358914f3b8085f03698a650ab5b8c7e45813f2b0515ec05b6e5195b6a7c2a"
436 "0d36969745f431ded4fd059f6aa361a4649541016d356297362b778e90f077d48815b339"
437 "ec6f43aba345df93e67fcb6c2cb5b4544e9be902818100e9c90abe5f9f32468c5b6d630c"
438 "54a4d7d75e29a72cf792f21e242aac78fd7995c42dfd4ae871d2619ff7096cb05baa78e3"
439 "23ecab338401a8059adf7a0d8be3b21edc9a9c82c5605634a2ec81ec053271721351868a"
440 "4c2e50c689d7cef94e31ff23658af5843366e2b289c5bf81d72756a7b93487dd8770d69c"
441 "1f4e089d6d89f302818100d8a58a727c4e209132afd9933b98c89aca862a01cc0be74133"
442 "bee517909e5c379e526895ac4af11780c1fe91194c777c9670b6423f0f5a32fd7691a622"
443 "113eef4bed2ef863363a335fd55b0e75088c582437237d7f3ed3f0a643950237bc6e6277"
444 "ccd0d0a1b4170aa1047aa7ffa7c8c54be10e8c7327ae2e0885663963817f6f02818100e5"
445 "aed9ba4d71b7502e6748a1ce247ecb7bd10c352d6d9256031cdf3c11a65e44b0b7ca2945"
446 "134671195af84c6b3bb3d10ebf65ae916f38bd5dbc59a0ad1c69b8beaf57cb3a8335f19b"
447 "c7117b576987b48331cd9fd3d1a293436b7bb5e1a35c6560de4b5688ea834367cb0997eb"
448 "b578f59ed4cb724c47dba94d3b484c1876dcd70281807f15bc7d2406007cac2b138a96af"
449 "2d1e00276b84da593132c253fcb73212732dfd25824c2a615bc3d9b7f2c8d2fa542d3562"
450 "b0c7738e61eeff580a6056239fb367ea9e5efe73d4f846033602e90c36a78db6fa8ea792"
451 "0769675ec58e237bd994d189c8045a96f5dd3a4f12547257ce224e3c9af830a4da3c0eab"
452 "9227a0035ae9028180067caea877e0b23090fc689322b71fbcce63d6596e66ab5fcdbaa0"
453 "0d49e93aba8effb4518c2da637f209028401a68f344865b4956b032c69acde51d29177ca"
454 "3db99fdbf5e74848ed4fa7bdfc2ebb60e2aaa5354770a763e1399ab7a2099762d525fea0"
455 "37f3e1972c45a477e66db95c9609bb27f862700ef93379930786cf751b";
456 blink::WebCryptoAlgorithm import_algorithm
= CreateRsaHashedImportAlgorithm(
457 blink::WebCryptoAlgorithmIdRsaOaep
, blink::WebCryptoAlgorithmIdSha1
);
458 blink::WebCryptoKey public_key
;
459 blink::WebCryptoKey private_key
;
461 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair(
462 HexStringToBytes(kPublicKey2048SpkiDerHex
),
463 HexStringToBytes(kPrivateKey2048Pkcs8DerHex
), import_algorithm
, false,
464 blink::WebCryptoKeyUsageEncrypt
| blink::WebCryptoKeyUsageWrapKey
,
465 blink::WebCryptoKeyUsageDecrypt
| blink::WebCryptoKeyUsageUnwrapKey
,
466 &public_key
, &private_key
));
468 std::vector
<uint8_t> label
;
469 blink::WebCryptoAlgorithm wrapping_algorithm
= CreateRsaOaepAlgorithm(label
);
471 const std::string key_hex
= "000102030405060708090a0b0c0d0e0f";
472 const blink::WebCryptoAlgorithm key_algorithm
=
473 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc
);
475 blink::WebCryptoKey key
=
476 ImportSecretKeyFromRaw(HexStringToBytes(key_hex
), key_algorithm
,
477 blink::WebCryptoKeyUsageEncrypt
);
478 ASSERT_FALSE(key
.isNull());
480 std::vector
<uint8_t> wrapped_key
;
481 ASSERT_EQ(Status::Success(),
482 WrapKey(blink::WebCryptoKeyFormatJwk
, key
, public_key
,
483 wrapping_algorithm
, &wrapped_key
));
485 // Verify that |wrapped_key| can be decrypted and yields a valid JWK object.
486 // Because |private_key| supports both decrypt and unwrap, this is valid.
487 std::vector
<uint8_t> decrypted_jwk
;
488 ASSERT_EQ(Status::Success(),
489 Decrypt(wrapping_algorithm
, private_key
, CryptoData(wrapped_key
),
491 EXPECT_TRUE(VerifySecretJwk(decrypted_jwk
, "A128CBC", key_hex
,
492 blink::WebCryptoKeyUsageEncrypt
));
494 // Now attempt to unwrap the key, which should also decrypt the data.
495 blink::WebCryptoKey unwrapped_key
;
496 ASSERT_EQ(Status::Success(),
497 UnwrapKey(blink::WebCryptoKeyFormatJwk
, CryptoData(wrapped_key
),
498 private_key
, wrapping_algorithm
, key_algorithm
, true,
499 blink::WebCryptoKeyUsageEncrypt
, &unwrapped_key
));
500 ASSERT_FALSE(unwrapped_key
.isNull());
502 std::vector
<uint8_t> raw_key
;
503 ASSERT_EQ(Status::Success(),
504 ExportKey(blink::WebCryptoKeyFormatRaw
, unwrapped_key
, &raw_key
));
505 EXPECT_BYTES_EQ_HEX(key_hex
, raw_key
);
508 TEST_F(WebCryptoRsaOaepTest
, ImportExportJwkRsaPublicKey
) {
509 if (!SupportsRsaOaep()) {
510 LOG(WARNING
) << "RSA-OAEP support not present; skipping.";
515 const blink::WebCryptoAlgorithmId hash
;
516 const blink::WebCryptoKeyUsageMask usage
;
517 const char* const jwk_alg
;
519 const TestCase kTests
[] = {{blink::WebCryptoAlgorithmIdSha1
,
520 blink::WebCryptoKeyUsageEncrypt
,
522 {blink::WebCryptoAlgorithmIdSha256
,
523 blink::WebCryptoKeyUsageEncrypt
,
525 {blink::WebCryptoAlgorithmIdSha384
,
526 blink::WebCryptoKeyUsageEncrypt
,
528 {blink::WebCryptoAlgorithmIdSha512
,
529 blink::WebCryptoKeyUsageEncrypt
,
532 for (size_t test_index
= 0; test_index
< arraysize(kTests
); ++test_index
) {
533 SCOPED_TRACE(test_index
);
534 const TestCase
& test
= kTests
[test_index
];
536 const blink::WebCryptoAlgorithm import_algorithm
=
537 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep
,
540 // Import the spki to create a public key
541 blink::WebCryptoKey public_key
;
542 ASSERT_EQ(Status::Success(),
543 ImportKey(blink::WebCryptoKeyFormatSpki
,
544 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex
)),
545 import_algorithm
, true, test
.usage
, &public_key
));
547 // Export the public key as JWK and verify its contents
548 std::vector
<uint8_t> jwk
;
549 ASSERT_EQ(Status::Success(),
550 ExportKey(blink::WebCryptoKeyFormatJwk
, public_key
, &jwk
));
551 EXPECT_TRUE(VerifyPublicJwk(jwk
, test
.jwk_alg
, kPublicKeyModulusHex
,
552 kPublicKeyExponentHex
, test
.usage
));
554 // Import the JWK back in to create a new key
555 blink::WebCryptoKey public_key2
;
556 ASSERT_EQ(Status::Success(),
557 ImportKey(blink::WebCryptoKeyFormatJwk
, CryptoData(jwk
),
558 import_algorithm
, true, test
.usage
, &public_key2
));
559 ASSERT_TRUE(public_key2
.handle());
560 EXPECT_EQ(blink::WebCryptoKeyTypePublic
, public_key2
.type());
561 EXPECT_TRUE(public_key2
.extractable());
562 EXPECT_EQ(import_algorithm
.id(), public_key2
.algorithm().id());
564 // TODO(eroman): Export the SPKI and verify matches.
570 } // namespace webcrypto