| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 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" | |
| 16 | |
| 17 namespace webcrypto { | |
| 18 | |
| 19 namespace { | |
| 20 | |
| 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()))); | |
| 29 } | |
| 30 | |
| 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(); | |
| 39 } | |
| 40 | |
| 41 // Import a PKCS#8 private key that uses RSAPrivateKey with the | |
| 42 // id-rsaEncryption OID. | |
| 43 TEST(WebCryptoRsaOaepTest, ImportPkcs8WithRsaEncryption) { | |
| 44 blink::WebCryptoKey private_key; | |
| 45 ASSERT_EQ(Status::Success(), | |
| 46 ImportKey(blink::WebCryptoKeyFormatPkcs8, | |
| 47 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)), | |
| 48 CreateRsaHashedImportAlgorithm( | |
| 49 blink::WebCryptoAlgorithmIdRsaOaep, | |
| 50 blink::WebCryptoAlgorithmIdSha1), | |
| 51 true, blink::WebCryptoKeyUsageDecrypt, &private_key)); | |
| 52 } | |
| 53 | |
| 54 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithNoAlg) { | |
| 55 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
| 56 | |
| 57 blink::WebCryptoKey public_key; | |
| 58 ASSERT_EQ( | |
| 59 Status::Success(), | |
| 60 ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm( | |
| 61 blink::WebCryptoAlgorithmIdRsaOaep, | |
| 62 blink::WebCryptoAlgorithmIdSha1), | |
| 63 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
| 64 } | |
| 65 | |
| 66 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMatchingAlg) { | |
| 67 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
| 68 jwk->SetString("alg", "RSA-OAEP"); | |
| 69 | |
| 70 blink::WebCryptoKey public_key; | |
| 71 ASSERT_EQ( | |
| 72 Status::Success(), | |
| 73 ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm( | |
| 74 blink::WebCryptoAlgorithmIdRsaOaep, | |
| 75 blink::WebCryptoAlgorithmIdSha1), | |
| 76 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
| 77 } | |
| 78 | |
| 79 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedAlgFails) { | |
| 80 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
| 81 jwk->SetString("alg", "RSA-OAEP-512"); | |
| 82 | |
| 83 blink::WebCryptoKey public_key; | |
| 84 ASSERT_EQ( | |
| 85 Status::ErrorJwkAlgorithmInconsistent(), | |
| 86 ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm( | |
| 87 blink::WebCryptoAlgorithmIdRsaOaep, | |
| 88 blink::WebCryptoAlgorithmIdSha1), | |
| 89 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
| 90 } | |
| 91 | |
| 92 TEST(WebCryptoRsaOaepTest, ImportPublicJwkWithMismatchedTypeFails) { | |
| 93 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
| 94 jwk->SetString("kty", "oct"); | |
| 95 jwk->SetString("alg", "RSA-OAEP"); | |
| 96 | |
| 97 blink::WebCryptoKey public_key; | |
| 98 ASSERT_EQ( | |
| 99 Status::ErrorJwkUnexpectedKty("RSA"), | |
| 100 ImportKeyJwkFromDict(*jwk.get(), CreateRsaHashedImportAlgorithm( | |
| 101 blink::WebCryptoAlgorithmIdRsaOaep, | |
| 102 blink::WebCryptoAlgorithmIdSha1), | |
| 103 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
| 104 } | |
| 105 | |
| 106 TEST(WebCryptoRsaOaepTest, ExportPublicJwk) { | |
| 107 struct TestData { | |
| 108 blink::WebCryptoAlgorithmId hash_alg; | |
| 109 const char* expected_jwk_alg; | |
| 110 } kTestData[] = {{blink::WebCryptoAlgorithmIdSha1, "RSA-OAEP"}, | |
| 111 {blink::WebCryptoAlgorithmIdSha256, "RSA-OAEP-256"}, | |
| 112 {blink::WebCryptoAlgorithmIdSha384, "RSA-OAEP-384"}, | |
| 113 {blink::WebCryptoAlgorithmIdSha512, "RSA-OAEP-512"}}; | |
| 114 for (size_t i = 0; i < arraysize(kTestData); ++i) { | |
| 115 const TestData& test_data = kTestData[i]; | |
| 116 SCOPED_TRACE(test_data.expected_jwk_alg); | |
| 117 | |
| 118 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
| 119 jwk->SetString("alg", test_data.expected_jwk_alg); | |
| 120 | |
| 121 // Import the key in a known-good format | |
| 122 blink::WebCryptoKey public_key; | |
| 123 ASSERT_EQ(Status::Success(), | |
| 124 ImportKeyJwkFromDict( | |
| 125 *jwk.get(), | |
| 126 CreateRsaHashedImportAlgorithm( | |
| 127 blink::WebCryptoAlgorithmIdRsaOaep, test_data.hash_alg), | |
| 128 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
| 129 | |
| 130 // Now export the key as JWK and verify its contents | |
| 131 std::vector<uint8_t> jwk_data; | |
| 132 ASSERT_EQ(Status::Success(), | |
| 133 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk_data)); | |
| 134 EXPECT_TRUE(VerifyPublicJwk(jwk_data, test_data.expected_jwk_alg, | |
| 135 kPublicKeyModulusHex, kPublicKeyExponentHex, | |
| 136 blink::WebCryptoKeyUsageEncrypt)); | |
| 137 } | |
| 138 } | |
| 139 | |
| 140 TEST(WebCryptoRsaOaepTest, EncryptDecryptKnownAnswerTest) { | |
| 141 scoped_ptr<base::ListValue> tests; | |
| 142 ASSERT_TRUE(ReadJsonTestFileToList("rsa_oaep.json", &tests)); | |
| 143 | |
| 144 for (size_t test_index = 0; test_index < tests->GetSize(); ++test_index) { | |
| 145 SCOPED_TRACE(test_index); | |
| 146 | |
| 147 base::DictionaryValue* test = NULL; | |
| 148 ASSERT_TRUE(tests->GetDictionary(test_index, &test)); | |
| 149 | |
| 150 blink::WebCryptoAlgorithm digest_algorithm = | |
| 151 GetDigestAlgorithm(test, "hash"); | |
| 152 ASSERT_FALSE(digest_algorithm.isNull()); | |
| 153 std::vector<uint8_t> public_key_der = | |
| 154 GetBytesFromHexString(test, "public_key"); | |
| 155 std::vector<uint8_t> private_key_der = | |
| 156 GetBytesFromHexString(test, "private_key"); | |
| 157 std::vector<uint8_t> ciphertext = GetBytesFromHexString(test, "ciphertext"); | |
| 158 std::vector<uint8_t> plaintext = GetBytesFromHexString(test, "plaintext"); | |
| 159 std::vector<uint8_t> label = GetBytesFromHexString(test, "label"); | |
| 160 | |
| 161 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( | |
| 162 blink::WebCryptoAlgorithmIdRsaOaep, digest_algorithm.id()); | |
| 163 blink::WebCryptoKey public_key; | |
| 164 blink::WebCryptoKey private_key; | |
| 165 | |
| 166 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair( | |
| 167 public_key_der, private_key_der, import_algorithm, false, | |
| 168 blink::WebCryptoKeyUsageEncrypt, blink::WebCryptoKeyUsageDecrypt, | |
| 169 &public_key, &private_key)); | |
| 170 | |
| 171 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); | |
| 172 std::vector<uint8_t> decrypted_data; | |
| 173 ASSERT_EQ(Status::Success(), | |
| 174 Decrypt(op_algorithm, private_key, CryptoData(ciphertext), | |
| 175 &decrypted_data)); | |
| 176 EXPECT_BYTES_EQ(plaintext, decrypted_data); | |
| 177 std::vector<uint8_t> encrypted_data; | |
| 178 ASSERT_EQ(Status::Success(), | |
| 179 Encrypt(op_algorithm, public_key, CryptoData(plaintext), | |
| 180 &encrypted_data)); | |
| 181 std::vector<uint8_t> redecrypted_data; | |
| 182 ASSERT_EQ(Status::Success(), | |
| 183 Decrypt(op_algorithm, private_key, CryptoData(encrypted_data), | |
| 184 &redecrypted_data)); | |
| 185 EXPECT_BYTES_EQ(plaintext, redecrypted_data); | |
| 186 } | |
| 187 } | |
| 188 | |
| 189 TEST(WebCryptoRsaOaepTest, EncryptWithLargeMessageFails) { | |
| 190 const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha1; | |
| 191 const size_t kHashSize = 20; | |
| 192 | |
| 193 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
| 194 | |
| 195 blink::WebCryptoKey public_key; | |
| 196 ASSERT_EQ(Status::Success(), | |
| 197 ImportKeyJwkFromDict( | |
| 198 *jwk.get(), CreateRsaHashedImportAlgorithm( | |
| 199 blink::WebCryptoAlgorithmIdRsaOaep, kHash), | |
| 200 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
| 201 | |
| 202 // The maximum size of an encrypted message is: | |
| 203 // modulus length | |
| 204 // - 1 (leading octet) | |
| 205 // - hash size (maskedSeed) | |
| 206 // - hash size (lHash portion of maskedDB) | |
| 207 // - 1 (at least one octet for the padding string) | |
| 208 size_t kMaxMessageSize = (kModulusLengthBits / 8) - 2 - (2 * kHashSize); | |
| 209 | |
| 210 // The label has no influence on the maximum message size. For simplicity, | |
| 211 // use the empty string. | |
| 212 std::vector<uint8_t> label; | |
| 213 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); | |
| 214 | |
| 215 // Test that a message just before the boundary succeeds. | |
| 216 std::string large_message; | |
| 217 large_message.resize(kMaxMessageSize - 1, 'A'); | |
| 218 | |
| 219 std::vector<uint8_t> ciphertext; | |
| 220 ASSERT_EQ(Status::Success(), Encrypt(op_algorithm, public_key, | |
| 221 CryptoData(large_message), &ciphertext)); | |
| 222 | |
| 223 // Test that a message at the boundary succeeds. | |
| 224 large_message.resize(kMaxMessageSize, 'A'); | |
| 225 ciphertext.clear(); | |
| 226 | |
| 227 ASSERT_EQ(Status::Success(), Encrypt(op_algorithm, public_key, | |
| 228 CryptoData(large_message), &ciphertext)); | |
| 229 | |
| 230 // Test that a message greater than the largest size fails. | |
| 231 large_message.resize(kMaxMessageSize + 1, 'A'); | |
| 232 ciphertext.clear(); | |
| 233 | |
| 234 ASSERT_EQ(Status::OperationError(), | |
| 235 Encrypt(op_algorithm, public_key, CryptoData(large_message), | |
| 236 &ciphertext)); | |
| 237 } | |
| 238 | |
| 239 // Ensures that if the selected hash algorithm for the RSA-OAEP message is too | |
| 240 // large, then it is rejected, independent of the actual message to be | |
| 241 // encrypted. | |
| 242 // For example, a 1024-bit RSA key is too small to accomodate a message that | |
| 243 // uses OAEP with SHA-512, since it requires 1040 bits to encode | |
| 244 // (2 * hash size + 2 padding bytes). | |
| 245 TEST(WebCryptoRsaOaepTest, EncryptWithLargeDigestFails) { | |
| 246 const blink::WebCryptoAlgorithmId kHash = blink::WebCryptoAlgorithmIdSha512; | |
| 247 | |
| 248 scoped_ptr<base::DictionaryValue> jwk(CreatePublicKeyJwkDict()); | |
| 249 | |
| 250 blink::WebCryptoKey public_key; | |
| 251 ASSERT_EQ(Status::Success(), | |
| 252 ImportKeyJwkFromDict( | |
| 253 *jwk.get(), CreateRsaHashedImportAlgorithm( | |
| 254 blink::WebCryptoAlgorithmIdRsaOaep, kHash), | |
| 255 true, blink::WebCryptoKeyUsageEncrypt, &public_key)); | |
| 256 | |
| 257 // The label has no influence on the maximum message size. For simplicity, | |
| 258 // use the empty string. | |
| 259 std::vector<uint8_t> label; | |
| 260 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); | |
| 261 | |
| 262 std::string small_message("A"); | |
| 263 std::vector<uint8_t> ciphertext; | |
| 264 // This is an operation error, as the internal consistency checking of the | |
| 265 // algorithm parameters is up to the implementation. | |
| 266 ASSERT_EQ(Status::OperationError(), | |
| 267 Encrypt(op_algorithm, public_key, CryptoData(small_message), | |
| 268 &ciphertext)); | |
| 269 } | |
| 270 | |
| 271 TEST(WebCryptoRsaOaepTest, DecryptWithLargeMessageFails) { | |
| 272 blink::WebCryptoKey private_key; | |
| 273 ASSERT_EQ(Status::Success(), | |
| 274 ImportKey(blink::WebCryptoKeyFormatPkcs8, | |
| 275 CryptoData(HexStringToBytes(kPrivateKeyPkcs8DerHex)), | |
| 276 CreateRsaHashedImportAlgorithm( | |
| 277 blink::WebCryptoAlgorithmIdRsaOaep, | |
| 278 blink::WebCryptoAlgorithmIdSha1), | |
| 279 true, blink::WebCryptoKeyUsageDecrypt, &private_key)); | |
| 280 | |
| 281 // The label has no influence on the maximum message size. For simplicity, | |
| 282 // use the empty string. | |
| 283 std::vector<uint8_t> label; | |
| 284 blink::WebCryptoAlgorithm op_algorithm = CreateRsaOaepAlgorithm(label); | |
| 285 | |
| 286 std::string large_dummy_message(kModulusLengthBits / 8, 'A'); | |
| 287 std::vector<uint8_t> plaintext; | |
| 288 | |
| 289 ASSERT_EQ(Status::OperationError(), | |
| 290 Decrypt(op_algorithm, private_key, CryptoData(large_dummy_message), | |
| 291 &plaintext)); | |
| 292 } | |
| 293 | |
| 294 TEST(WebCryptoRsaOaepTest, WrapUnwrapRawKey) { | |
| 295 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( | |
| 296 blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1); | |
| 297 blink::WebCryptoKey public_key; | |
| 298 blink::WebCryptoKey private_key; | |
| 299 | |
| 300 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair( | |
| 301 HexStringToBytes(kPublicKeySpkiDerHex), | |
| 302 HexStringToBytes(kPrivateKeyPkcs8DerHex), import_algorithm, false, | |
| 303 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey, | |
| 304 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey, | |
| 305 &public_key, &private_key)); | |
| 306 | |
| 307 std::vector<uint8_t> label; | |
| 308 blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label); | |
| 309 | |
| 310 const std::string key_hex = "000102030405060708090A0B0C0D0E0F"; | |
| 311 const blink::WebCryptoAlgorithm key_algorithm = | |
| 312 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc); | |
| 313 | |
| 314 blink::WebCryptoKey key = | |
| 315 ImportSecretKeyFromRaw(HexStringToBytes(key_hex), key_algorithm, | |
| 316 blink::WebCryptoKeyUsageEncrypt); | |
| 317 ASSERT_FALSE(key.isNull()); | |
| 318 | |
| 319 std::vector<uint8_t> wrapped_key; | |
| 320 ASSERT_EQ(Status::Success(), | |
| 321 WrapKey(blink::WebCryptoKeyFormatRaw, key, public_key, | |
| 322 wrapping_algorithm, &wrapped_key)); | |
| 323 | |
| 324 // Verify that |wrapped_key| can be decrypted and yields the key data. | |
| 325 // Because |private_key| supports both decrypt and unwrap, this is valid. | |
| 326 std::vector<uint8_t> decrypted_key; | |
| 327 ASSERT_EQ(Status::Success(), | |
| 328 Decrypt(wrapping_algorithm, private_key, CryptoData(wrapped_key), | |
| 329 &decrypted_key)); | |
| 330 EXPECT_BYTES_EQ_HEX(key_hex, decrypted_key); | |
| 331 | |
| 332 // Now attempt to unwrap the key, which should also decrypt the data. | |
| 333 blink::WebCryptoKey unwrapped_key; | |
| 334 ASSERT_EQ(Status::Success(), | |
| 335 UnwrapKey(blink::WebCryptoKeyFormatRaw, CryptoData(wrapped_key), | |
| 336 private_key, wrapping_algorithm, key_algorithm, true, | |
| 337 blink::WebCryptoKeyUsageEncrypt, &unwrapped_key)); | |
| 338 ASSERT_FALSE(unwrapped_key.isNull()); | |
| 339 | |
| 340 std::vector<uint8_t> raw_key; | |
| 341 ASSERT_EQ(Status::Success(), | |
| 342 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key)); | |
| 343 EXPECT_BYTES_EQ_HEX(key_hex, raw_key); | |
| 344 } | |
| 345 | |
| 346 TEST(WebCryptoRsaOaepTest, WrapUnwrapJwkSymKey) { | |
| 347 // The public and private portions of a 2048-bit RSA key with the | |
| 348 // id-rsaEncryption OID | |
| 349 const char kPublicKey2048SpkiDerHex[] = | |
| 350 "30820122300d06092a864886f70d01010105000382010f003082010a0282010100c5d8ce" | |
| 351 "137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b300c6a6c9764" | |
| 352 "f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448e7183a3a68" | |
| 353 "e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872458d1b1e2f" | |
| 354 "7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34ba17bc5d08" | |
| 355 "a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea9893652d02fc606" | |
| 356 "36f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d733711c89ca" | |
| 357 "749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b557c16615d" | |
| 358 "5d0203010001"; | |
| 359 const char kPrivateKey2048Pkcs8DerHex[] = | |
| 360 "308204bd020100300d06092a864886f70d0101010500048204a7308204a3020100028201" | |
| 361 "0100c5d8ce137a38168c8ab70229cfa5accc640567159750a312ce2e7d54b6e2fdd59b30" | |
| 362 "0c6a6c9764f8de6f00519cdb90111453d273a967462786480621f9e7cee5b73d63358448" | |
| 363 "e7183a3a68e991186359f26aa88fbca5f53e673e502e4c5a2ba5068aeba60c9d0c44d872" | |
| 364 "458d1b1e2f7f339f986076d516e93dc750f0b7680b6f5f02bc0d5590495be04c4ae59d34" | |
| 365 "ba17bc5d08a93c75cfda2828f4a55b153af912038438276cb4a14f8116ca94db0ea98936" | |
| 366 "52d02fc60636f19975e3d79a4d8ea8bfed6f8e0a24b63d243b08ea70a086ad56dd6341d7" | |
| 367 "33711c89ca749d4a80b3e6ecd2f8e53731eadeac2ea77788ee55d7b4b47c0f2523fbd61b" | |
| 368 "557c16615d5d02030100010282010074b70feb41a0b0fcbc207670400556c9450042ede3" | |
| 369 "d4383fb1ce8f3558a6d4641d26dd4c333fa4db842d2b9cf9d2354d3e16ad027a9f682d8c" | |
| 370 "f4145a1ad97b9edcd8a41c402bd9d8db10f62f43df854cdccbbb2100834f083f53ed6d42" | |
| 371 "b1b729a59072b004a4e945fc027db15e9c121d1251464d320d4774d5732df6b3dbf751f4" | |
| 372 "9b19c9db201e19989c883bbaad5333db47f64f6f7a95b8d4936b10d945aa3f794cfaab62" | |
| 373 "e7d47686129358914f3b8085f03698a650ab5b8c7e45813f2b0515ec05b6e5195b6a7c2a" | |
| 374 "0d36969745f431ded4fd059f6aa361a4649541016d356297362b778e90f077d48815b339" | |
| 375 "ec6f43aba345df93e67fcb6c2cb5b4544e9be902818100e9c90abe5f9f32468c5b6d630c" | |
| 376 "54a4d7d75e29a72cf792f21e242aac78fd7995c42dfd4ae871d2619ff7096cb05baa78e3" | |
| 377 "23ecab338401a8059adf7a0d8be3b21edc9a9c82c5605634a2ec81ec053271721351868a" | |
| 378 "4c2e50c689d7cef94e31ff23658af5843366e2b289c5bf81d72756a7b93487dd8770d69c" | |
| 379 "1f4e089d6d89f302818100d8a58a727c4e209132afd9933b98c89aca862a01cc0be74133" | |
| 380 "bee517909e5c379e526895ac4af11780c1fe91194c777c9670b6423f0f5a32fd7691a622" | |
| 381 "113eef4bed2ef863363a335fd55b0e75088c582437237d7f3ed3f0a643950237bc6e6277" | |
| 382 "ccd0d0a1b4170aa1047aa7ffa7c8c54be10e8c7327ae2e0885663963817f6f02818100e5" | |
| 383 "aed9ba4d71b7502e6748a1ce247ecb7bd10c352d6d9256031cdf3c11a65e44b0b7ca2945" | |
| 384 "134671195af84c6b3bb3d10ebf65ae916f38bd5dbc59a0ad1c69b8beaf57cb3a8335f19b" | |
| 385 "c7117b576987b48331cd9fd3d1a293436b7bb5e1a35c6560de4b5688ea834367cb0997eb" | |
| 386 "b578f59ed4cb724c47dba94d3b484c1876dcd70281807f15bc7d2406007cac2b138a96af" | |
| 387 "2d1e00276b84da593132c253fcb73212732dfd25824c2a615bc3d9b7f2c8d2fa542d3562" | |
| 388 "b0c7738e61eeff580a6056239fb367ea9e5efe73d4f846033602e90c36a78db6fa8ea792" | |
| 389 "0769675ec58e237bd994d189c8045a96f5dd3a4f12547257ce224e3c9af830a4da3c0eab" | |
| 390 "9227a0035ae9028180067caea877e0b23090fc689322b71fbcce63d6596e66ab5fcdbaa0" | |
| 391 "0d49e93aba8effb4518c2da637f209028401a68f344865b4956b032c69acde51d29177ca" | |
| 392 "3db99fdbf5e74848ed4fa7bdfc2ebb60e2aaa5354770a763e1399ab7a2099762d525fea0" | |
| 393 "37f3e1972c45a477e66db95c9609bb27f862700ef93379930786cf751b"; | |
| 394 blink::WebCryptoAlgorithm import_algorithm = CreateRsaHashedImportAlgorithm( | |
| 395 blink::WebCryptoAlgorithmIdRsaOaep, blink::WebCryptoAlgorithmIdSha1); | |
| 396 blink::WebCryptoKey public_key; | |
| 397 blink::WebCryptoKey private_key; | |
| 398 | |
| 399 ASSERT_NO_FATAL_FAILURE(ImportRsaKeyPair( | |
| 400 HexStringToBytes(kPublicKey2048SpkiDerHex), | |
| 401 HexStringToBytes(kPrivateKey2048Pkcs8DerHex), import_algorithm, false, | |
| 402 blink::WebCryptoKeyUsageEncrypt | blink::WebCryptoKeyUsageWrapKey, | |
| 403 blink::WebCryptoKeyUsageDecrypt | blink::WebCryptoKeyUsageUnwrapKey, | |
| 404 &public_key, &private_key)); | |
| 405 | |
| 406 std::vector<uint8_t> label; | |
| 407 blink::WebCryptoAlgorithm wrapping_algorithm = CreateRsaOaepAlgorithm(label); | |
| 408 | |
| 409 const std::string key_hex = "000102030405060708090a0b0c0d0e0f"; | |
| 410 const blink::WebCryptoAlgorithm key_algorithm = | |
| 411 CreateAlgorithm(blink::WebCryptoAlgorithmIdAesCbc); | |
| 412 | |
| 413 blink::WebCryptoKey key = | |
| 414 ImportSecretKeyFromRaw(HexStringToBytes(key_hex), key_algorithm, | |
| 415 blink::WebCryptoKeyUsageEncrypt); | |
| 416 ASSERT_FALSE(key.isNull()); | |
| 417 | |
| 418 std::vector<uint8_t> wrapped_key; | |
| 419 ASSERT_EQ(Status::Success(), | |
| 420 WrapKey(blink::WebCryptoKeyFormatJwk, key, public_key, | |
| 421 wrapping_algorithm, &wrapped_key)); | |
| 422 | |
| 423 // Verify that |wrapped_key| can be decrypted and yields a valid JWK object. | |
| 424 // Because |private_key| supports both decrypt and unwrap, this is valid. | |
| 425 std::vector<uint8_t> decrypted_jwk; | |
| 426 ASSERT_EQ(Status::Success(), | |
| 427 Decrypt(wrapping_algorithm, private_key, CryptoData(wrapped_key), | |
| 428 &decrypted_jwk)); | |
| 429 EXPECT_TRUE(VerifySecretJwk(decrypted_jwk, "A128CBC", key_hex, | |
| 430 blink::WebCryptoKeyUsageEncrypt)); | |
| 431 | |
| 432 // Now attempt to unwrap the key, which should also decrypt the data. | |
| 433 blink::WebCryptoKey unwrapped_key; | |
| 434 ASSERT_EQ(Status::Success(), | |
| 435 UnwrapKey(blink::WebCryptoKeyFormatJwk, CryptoData(wrapped_key), | |
| 436 private_key, wrapping_algorithm, key_algorithm, true, | |
| 437 blink::WebCryptoKeyUsageEncrypt, &unwrapped_key)); | |
| 438 ASSERT_FALSE(unwrapped_key.isNull()); | |
| 439 | |
| 440 std::vector<uint8_t> raw_key; | |
| 441 ASSERT_EQ(Status::Success(), | |
| 442 ExportKey(blink::WebCryptoKeyFormatRaw, unwrapped_key, &raw_key)); | |
| 443 EXPECT_BYTES_EQ_HEX(key_hex, raw_key); | |
| 444 } | |
| 445 | |
| 446 TEST(WebCryptoRsaOaepTest, ImportExportJwkRsaPublicKey) { | |
| 447 struct TestCase { | |
| 448 const blink::WebCryptoAlgorithmId hash; | |
| 449 const blink::WebCryptoKeyUsageMask usage; | |
| 450 const char* const jwk_alg; | |
| 451 }; | |
| 452 const TestCase kTests[] = {{blink::WebCryptoAlgorithmIdSha1, | |
| 453 blink::WebCryptoKeyUsageEncrypt, | |
| 454 "RSA-OAEP"}, | |
| 455 {blink::WebCryptoAlgorithmIdSha256, | |
| 456 blink::WebCryptoKeyUsageEncrypt, | |
| 457 "RSA-OAEP-256"}, | |
| 458 {blink::WebCryptoAlgorithmIdSha384, | |
| 459 blink::WebCryptoKeyUsageEncrypt, | |
| 460 "RSA-OAEP-384"}, | |
| 461 {blink::WebCryptoAlgorithmIdSha512, | |
| 462 blink::WebCryptoKeyUsageEncrypt, | |
| 463 "RSA-OAEP-512"}}; | |
| 464 | |
| 465 for (size_t test_index = 0; test_index < arraysize(kTests); ++test_index) { | |
| 466 SCOPED_TRACE(test_index); | |
| 467 const TestCase& test = kTests[test_index]; | |
| 468 | |
| 469 const blink::WebCryptoAlgorithm import_algorithm = | |
| 470 CreateRsaHashedImportAlgorithm(blink::WebCryptoAlgorithmIdRsaOaep, | |
| 471 test.hash); | |
| 472 | |
| 473 // Import the spki to create a public key | |
| 474 blink::WebCryptoKey public_key; | |
| 475 ASSERT_EQ(Status::Success(), | |
| 476 ImportKey(blink::WebCryptoKeyFormatSpki, | |
| 477 CryptoData(HexStringToBytes(kPublicKeySpkiDerHex)), | |
| 478 import_algorithm, true, test.usage, &public_key)); | |
| 479 | |
| 480 // Export the public key as JWK and verify its contents | |
| 481 std::vector<uint8_t> jwk; | |
| 482 ASSERT_EQ(Status::Success(), | |
| 483 ExportKey(blink::WebCryptoKeyFormatJwk, public_key, &jwk)); | |
| 484 EXPECT_TRUE(VerifyPublicJwk(jwk, test.jwk_alg, kPublicKeyModulusHex, | |
| 485 kPublicKeyExponentHex, test.usage)); | |
| 486 | |
| 487 // Import the JWK back in to create a new key | |
| 488 blink::WebCryptoKey public_key2; | |
| 489 ASSERT_EQ(Status::Success(), | |
| 490 ImportKey(blink::WebCryptoKeyFormatJwk, CryptoData(jwk), | |
| 491 import_algorithm, true, test.usage, &public_key2)); | |
| 492 ASSERT_TRUE(public_key2.handle()); | |
| 493 EXPECT_EQ(blink::WebCryptoKeyTypePublic, public_key2.type()); | |
| 494 EXPECT_TRUE(public_key2.extractable()); | |
| 495 EXPECT_EQ(import_algorithm.id(), public_key2.algorithm().id()); | |
| 496 | |
| 497 // TODO(eroman): Export the SPKI and verify matches. | |
| 498 } | |
| 499 } | |
| 500 | |
| 501 } // namespace | |
| 502 | |
| 503 } // namespace webcrypto | |
| OLD | NEW |