Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 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 <openssl/evp.h> | 5 #include <openssl/aes.h> |
| 6 #include <stddef.h> | 6 #include <stddef.h> |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <vector> | 9 #include <vector> |
| 10 | 10 |
| 11 #include "base/logging.h" | |
| 12 #include "base/memory/ptr_util.h" | 11 #include "base/memory/ptr_util.h" |
| 13 #include "base/numerics/safe_math.h" | 12 #include "base/numerics/safe_math.h" |
| 14 #include "base/stl_util.h" | |
| 15 #include "components/webcrypto/algorithms/aes.h" | 13 #include "components/webcrypto/algorithms/aes.h" |
| 16 #include "components/webcrypto/algorithms/util.h" | |
| 17 #include "components/webcrypto/blink_key_handle.h" | 14 #include "components/webcrypto/blink_key_handle.h" |
| 18 #include "components/webcrypto/crypto_data.h" | 15 #include "components/webcrypto/crypto_data.h" |
| 19 #include "components/webcrypto/status.h" | 16 #include "components/webcrypto/status.h" |
| 20 #include "crypto/openssl_util.h" | |
| 21 #include "crypto/scoped_openssl_types.h" | |
| 22 | 17 |
| 23 namespace webcrypto { | 18 namespace webcrypto { |
| 24 | 19 |
| 25 namespace { | 20 namespace { |
| 26 | 21 |
| 27 const EVP_AEAD* GetAesKwAlgorithmFromKeySize(size_t key_size_bytes) { | |
| 28 switch (key_size_bytes) { | |
| 29 case 16: | |
| 30 return EVP_aead_aes_128_key_wrap(); | |
| 31 case 32: | |
| 32 return EVP_aead_aes_256_key_wrap(); | |
| 33 default: | |
| 34 return NULL; | |
| 35 } | |
| 36 } | |
| 37 | |
| 38 Status AesKwEncryptDecrypt(EncryptOrDecrypt mode, | |
| 39 const blink::WebCryptoAlgorithm& algorithm, | |
| 40 const blink::WebCryptoKey& key, | |
| 41 const CryptoData& data, | |
| 42 std::vector<uint8_t>* buffer) { | |
| 43 // These length checks are done in order to give a more specific error. These | |
| 44 // are not required for correctness. | |
| 45 if ((mode == ENCRYPT && data.byte_length() < 16) || | |
| 46 (mode == DECRYPT && data.byte_length() < 24)) { | |
| 47 return Status::ErrorDataTooSmall(); | |
| 48 } | |
| 49 if (data.byte_length() % 8) | |
| 50 return Status::ErrorInvalidAesKwDataLength(); | |
| 51 | |
| 52 const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(key); | |
| 53 | |
| 54 return AeadEncryptDecrypt(mode, raw_key, data, | |
| 55 8, // tag_length_bytes | |
| 56 CryptoData(), // iv | |
| 57 CryptoData(), // additional_data | |
| 58 GetAesKwAlgorithmFromKeySize(raw_key.size()), | |
| 59 buffer); | |
| 60 } | |
| 61 | |
| 62 class AesKwImplementation : public AesAlgorithm { | 22 class AesKwImplementation : public AesAlgorithm { |
| 63 public: | 23 public: |
| 64 AesKwImplementation() | 24 AesKwImplementation() |
| 65 : AesAlgorithm( | 25 : AesAlgorithm( |
| 66 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey, | 26 blink::WebCryptoKeyUsageWrapKey | blink::WebCryptoKeyUsageUnwrapKey, |
| 67 "KW") {} | 27 "KW") {} |
| 68 | 28 |
| 69 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, | 29 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm, |
| 70 const blink::WebCryptoKey& key, | 30 const blink::WebCryptoKey& key, |
| 71 const CryptoData& data, | 31 const CryptoData& data, |
| 72 std::vector<uint8_t>* buffer) const override { | 32 std::vector<uint8_t>* buffer) const override { |
| 73 return AesKwEncryptDecrypt(ENCRYPT, algorithm, key, data, buffer); | 33 // These length checks are done in order to give a more specific |
|
eroman
2016/10/10 20:27:59
crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE
davidben
2016/10/10 23:49:54
Done. aes.h actually does not touch the error queu
| |
| 34 // error. These are not required for correctness. | |
| 35 if (data.byte_length() < 16) | |
| 36 return Status::ErrorDataTooSmall(); | |
| 37 if (data.byte_length() % 8) | |
| 38 return Status::ErrorInvalidAesKwDataLength(); | |
| 39 | |
| 40 const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(key); | |
| 41 if (raw_key.size() != 16 && raw_key.size() != 32) | |
|
eroman
2016/10/10 20:27:59
Can you remove this check? (key import enforces th
davidben
2016/10/10 23:49:54
Done.
| |
| 42 return Status::ErrorUnexpected(); | |
| 43 AES_KEY aes_key; | |
| 44 if (AES_set_encrypt_key(raw_key.data(), | |
| 45 static_cast<unsigned>(raw_key.size() * 8), | |
| 46 &aes_key) < 0) { | |
| 47 return Status::OperationError(); | |
| 48 } | |
| 49 | |
| 50 // Key wrap's overhead is 8 bytes. | |
| 51 base::CheckedNumeric<size_t> length(data.byte_length()); | |
|
eroman
2016/10/10 20:27:59
Should this be an |int| instead ? Although the API
davidben
2016/10/10 23:49:54
Well, it's also more fundamentally constrained by
| |
| 52 length += 8; | |
| 53 if (!length.IsValid()) | |
| 54 return Status::ErrorDataTooLarge(); | |
| 55 | |
| 56 buffer->resize(length.ValueOrDie()); | |
| 57 if (AES_wrap_key(&aes_key, nullptr /* default IV */, buffer->data(), | |
| 58 data.bytes(), data.byte_length()) < 0) { | |
| 59 return Status::OperationError(); | |
| 60 } | |
| 61 | |
| 62 return Status::Success(); | |
| 74 } | 63 } |
| 75 | 64 |
| 76 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, | 65 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm, |
| 77 const blink::WebCryptoKey& key, | 66 const blink::WebCryptoKey& key, |
| 78 const CryptoData& data, | 67 const CryptoData& data, |
| 79 std::vector<uint8_t>* buffer) const override { | 68 std::vector<uint8_t>* buffer) const override { |
| 80 return AesKwEncryptDecrypt(DECRYPT, algorithm, key, data, buffer); | 69 // These length checks are done in order to give a more specific |
|
eroman
2016/10/10 20:27:59
crypto::OpenSSLErrStackTracer ?
davidben
2016/10/10 23:49:54
Done.
| |
| 70 // error. These are not required for correctness. | |
| 71 if (data.byte_length() < 24) | |
| 72 return Status::ErrorDataTooSmall(); | |
| 73 if (data.byte_length() % 8) | |
| 74 return Status::ErrorInvalidAesKwDataLength(); | |
| 75 | |
| 76 const std::vector<uint8_t>& raw_key = GetSymmetricKeyData(key); | |
| 77 if (raw_key.size() != 16 && raw_key.size() != 32) | |
|
eroman
2016/10/10 20:27:59
Same comment as above -- we can forego this check
davidben
2016/10/10 23:49:54
Done.
| |
| 78 return Status::ErrorUnexpected(); | |
| 79 AES_KEY aes_key; | |
| 80 if (AES_set_decrypt_key(raw_key.data(), | |
| 81 static_cast<unsigned>(raw_key.size() * 8), | |
| 82 &aes_key) < 0) { | |
| 83 return Status::OperationError(); | |
| 84 } | |
| 85 | |
| 86 // Key wrap's overhead is 8 bytes. | |
| 87 buffer->resize(data.byte_length() - 8); | |
| 88 | |
| 89 if (AES_unwrap_key(&aes_key, nullptr /* default IV */, buffer->data(), | |
| 90 data.bytes(), data.byte_length()) < 0) { | |
| 91 return Status::OperationError(); | |
| 92 } | |
| 93 | |
| 94 return Status::Success(); | |
| 81 } | 95 } |
| 82 }; | 96 }; |
| 83 | 97 |
| 84 } // namespace | 98 } // namespace |
| 85 | 99 |
| 86 std::unique_ptr<AlgorithmImplementation> CreateAesKwImplementation() { | 100 std::unique_ptr<AlgorithmImplementation> CreateAesKwImplementation() { |
| 87 return base::WrapUnique(new AesKwImplementation); | 101 return base::WrapUnique(new AesKwImplementation); |
| 88 } | 102 } |
| 89 | 103 |
| 90 } // namespace webcrypto | 104 } // namespace webcrypto |
| OLD | NEW |