OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "content/renderer/webcrypto/webcrypto_impl.h" | 5 #include "content/renderer/webcrypto/webcrypto_impl.h" |
6 | 6 |
7 #include <cryptohi.h> | 7 #include <cryptohi.h> |
8 #include <pk11pub.h> | 8 #include <pk11pub.h> |
9 #include <sechash.h> | 9 #include <sechash.h> |
10 | 10 |
(...skipping 354 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
365 if (result != SECSuccess) | 365 if (result != SECSuccess) |
366 return false; | 366 return false; |
367 | 367 |
368 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug | 368 // Unfortunately the buffer needs to be shrunk for decryption (see the NSS bug |
369 // above). | 369 // above). |
370 webcrypto::ShrinkBuffer(buffer, output_len); | 370 webcrypto::ShrinkBuffer(buffer, output_len); |
371 | 371 |
372 return true; | 372 return true; |
373 } | 373 } |
374 | 374 |
375 // Constants for RFC 3394 AES Key Wrap / Unwrap. | |
376 const CK_MECHANISM_TYPE kAesKwMechanism = CKM_NSS_AES_KEY_WRAP; | |
Ryan Sleevi
2014/01/16 23:41:15
I don't see there being any benefit from adding th
padolph
2014/02/19 03:55:43
Done.
| |
377 // The Default IV. See http://www.ietf.org/rfc/rfc3394.txt Section 2.2.3.1. | |
378 const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6}; | |
Ryan Sleevi
2014/01/16 23:41:15
You can make this a function-local const.
padolph
2014/02/19 03:55:43
This is used in two separate functions. I don't wa
| |
379 | |
380 // Performs RFC 3394 AES Key Wrap (encryption) of the input data. | |
381 bool AesKwEncrypt( | |
382 const blink::WebCryptoKey& key, | |
383 const unsigned char* data, | |
384 unsigned data_size, | |
385 blink::WebArrayBuffer* buffer) { | |
Ryan Sleevi
2014/01/16 23:41:15
From an API design perspective, having the AES-KW
| |
386 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id()); | |
387 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
388 DCHECK(blink::WebCryptoKeyUsageWrapKey & key.usages()); | |
389 | |
390 // The data size must be at least 16 bytes and a multiple of 8 bytes. | |
391 if (data_size < 16 || data_size % 8) | |
392 return false; | |
393 DCHECK(data); | |
Ryan Sleevi
2014/01/16 23:41:15
Why not DCHECK on line 389?
padolph
2014/02/19 03:55:43
Eric prefers this pattern. You won't hit the check
| |
394 | |
395 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv), | |
396 arraysize(kAesIv)}; | |
397 crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item)); | |
398 DCHECK(param_item); | |
399 | |
400 // Turn the data to be wrapped into a PK11SymKey in order to use the NSS | |
401 // PK11_WrapSymKey() API. Create the PK11SymKey by importing the data as a | |
402 // generic secret blob, since we can't be certain what it is at this point. | |
Ryan Sleevi
2014/01/16 23:41:15
Pronouns considered harmful: https://groups.google
padolph
2014/02/19 03:55:43
Done.
| |
403 SECItem data_item = {siBuffer, const_cast<unsigned char*>(data), data_size}; | |
404 crypto::ScopedPK11SymKey key_to_be_wrapped( | |
405 PK11_ImportSymKey(PK11_GetInternalSlot(), | |
406 CKK_GENERIC_SECRET, | |
407 PK11_OriginGenerated, | |
408 CKA_ENCRYPT, | |
409 &data_item, | |
410 0)); | |
411 if (!key_to_be_wrapped) | |
412 return false; | |
413 | |
414 // AES Key Wrap always adds 8 bytes to the input data size. RFC 3394 does not | |
415 // specify a maximum allowed data length, but since we are only wrapping keys, | |
416 // which are usually small, a reasonable max size is whatever will fit into an | |
417 // unsigned. | |
418 if (data_size > UINT_MAX - 8) | |
419 return false; | |
420 const unsigned int output_length = data_size + 8; | |
421 | |
422 *buffer = blink::WebArrayBuffer::create(output_length, 1); | |
423 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data()); | |
424 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length}; | |
425 | |
426 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
427 | |
428 if (SECSuccess != PK11_WrapSymKey(kAesKwMechanism, | |
429 param_item.get(), | |
430 wrapping_key->key(), | |
431 key_to_be_wrapped.get(), | |
432 &wrapped_key_item)) { | |
433 return false; | |
434 } | |
435 if (output_length != wrapped_key_item.len) { | |
436 buffer->reset(); | |
437 return false; | |
438 } | |
439 | |
440 return true; | |
441 } | |
442 | |
443 // Performs RFC 3394 AES Key Unwrap (decryption) of the input data. | |
444 bool AesKwDecrypt( | |
445 const blink::WebCryptoKey& key, | |
446 const unsigned char* data, | |
447 unsigned data_size, | |
448 blink::WebArrayBuffer* buffer) { | |
449 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id()); | |
450 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type()); | |
451 DCHECK(blink::WebCryptoKeyUsageUnwrapKey & key.usages()); | |
452 | |
453 // The ciphertext data size must be at least 24 bytes and a multiple of | |
454 // 8 bytes. | |
455 if (data_size < 24 || data_size % 8 != 0) | |
456 return false; | |
457 DCHECK(data); | |
458 | |
459 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle()); | |
460 | |
461 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv), | |
462 arraysize(kAesIv)}; | |
463 crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item)); | |
464 DCHECK(param_item); | |
465 | |
466 SECItem cipher_text = {siBuffer, const_cast<unsigned char*>(data), data_size}; | |
467 | |
468 // The plaintext length is always 64 bits less than the data size. | |
469 const unsigned int plaintext_length = data_size - 8; | |
470 | |
471 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey( | |
472 wrapping_key->key(), | |
473 kAesKwMechanism, | |
474 param_item.get(), | |
475 &cipher_text, | |
476 CKK_GENERIC_SECRET, // Import the key material without knowing its kind. | |
477 CKA_ENCRYPT, // A safe value since all we're doing is exporting the key. | |
478 plaintext_length)); | |
479 if (!unwrapped_key) | |
480 return false; | |
481 | |
482 if (PK11_ExtractKeyValue(unwrapped_key.get()) != SECSuccess) | |
483 return false; | |
484 | |
485 const SECItem* key_data = PK11_GetKeyData(unwrapped_key.get()); | |
486 if (!key_data || key_data->len != plaintext_length) | |
487 return false; | |
488 | |
489 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len); | |
490 | |
491 return true; | |
492 } | |
493 | |
375 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( | 494 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( |
376 const blink::WebCryptoAlgorithm& algorithm) { | 495 const blink::WebCryptoAlgorithm& algorithm) { |
377 switch (algorithm.id()) { | 496 switch (algorithm.id()) { |
378 case blink::WebCryptoAlgorithmIdAesCbc: | 497 case blink::WebCryptoAlgorithmIdAesCbc: |
379 case blink::WebCryptoAlgorithmIdAesGcm: | 498 case blink::WebCryptoAlgorithmIdAesGcm: |
380 case blink::WebCryptoAlgorithmIdAesKw: | 499 case blink::WebCryptoAlgorithmIdAesKw: |
381 return CKM_AES_KEY_GEN; | 500 return CKM_AES_KEY_GEN; |
382 case blink::WebCryptoAlgorithmIdHmac: | 501 case blink::WebCryptoAlgorithmIdHmac: |
383 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash()); | 502 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash()); |
384 default: | 503 default: |
(...skipping 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
703 DCHECK(key.handle()); | 822 DCHECK(key.handle()); |
704 DCHECK(buffer); | 823 DCHECK(buffer); |
705 | 824 |
706 // TODO(eroman): Use a switch() statement. | 825 // TODO(eroman): Use a switch() statement. |
707 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 826 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
708 return AesCbcEncryptDecrypt( | 827 return AesCbcEncryptDecrypt( |
709 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); | 828 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); |
710 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) { | 829 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) { |
711 return AesGcmEncryptDecrypt( | 830 return AesGcmEncryptDecrypt( |
712 true, algorithm, key, data, data_size, buffer); | 831 true, algorithm, key, data, data_size, buffer); |
832 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) { | |
833 return AesKwEncrypt(key, data, data_size, buffer); | |
713 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { | 834 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { |
714 | 835 |
715 // RSAES encryption does not support empty input | 836 // RSAES encryption does not support empty input |
716 if (!data_size) | 837 if (!data_size) |
717 return false; | 838 return false; |
718 DCHECK(data); | 839 DCHECK(data); |
719 | 840 |
720 if (key.type() != blink::WebCryptoKeyTypePublic) | 841 if (key.type() != blink::WebCryptoKeyTypePublic) |
721 return false; | 842 return false; |
722 | 843 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
759 DCHECK(key.handle()); | 880 DCHECK(key.handle()); |
760 DCHECK(buffer); | 881 DCHECK(buffer); |
761 | 882 |
762 // TODO(eroman): Use a switch() statement. | 883 // TODO(eroman): Use a switch() statement. |
763 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { | 884 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { |
764 return AesCbcEncryptDecrypt( | 885 return AesCbcEncryptDecrypt( |
765 CKA_DECRYPT, algorithm, key, data, data_size, buffer); | 886 CKA_DECRYPT, algorithm, key, data, data_size, buffer); |
766 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) { | 887 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesGcm) { |
767 return AesGcmEncryptDecrypt( | 888 return AesGcmEncryptDecrypt( |
768 false, algorithm, key, data, data_size, buffer); | 889 false, algorithm, key, data, data_size, buffer); |
890 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) { | |
891 return AesKwDecrypt(key, data, data_size, buffer); | |
769 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { | 892 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { |
770 | 893 |
771 // RSAES decryption does not support empty input | 894 // RSAES decryption does not support empty input |
772 if (!data_size) | 895 if (!data_size) |
773 return false; | 896 return false; |
774 DCHECK(data); | 897 DCHECK(data); |
775 | 898 |
776 if (key.type() != blink::WebCryptoKeyTypePrivate) | 899 if (key.type() != blink::WebCryptoKeyTypePrivate) |
777 return false; | 900 return false; |
778 | 901 |
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1201 | 1324 |
1202 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), | 1325 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), |
1203 blink::WebCryptoKeyTypePublic, | 1326 blink::WebCryptoKeyTypePublic, |
1204 extractable, | 1327 extractable, |
1205 algorithm, | 1328 algorithm, |
1206 usage_mask); | 1329 usage_mask); |
1207 return true; | 1330 return true; |
1208 } | 1331 } |
1209 | 1332 |
1210 } // namespace content | 1333 } // namespace content |
OLD | NEW |