Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(10141)

Unified Diff: content/renderer/webcrypto/webcrypto_impl_nss.cc

Issue 118623002: [webcrypto] Add raw symmetric key AES-KW wrap/unwrap for NSS. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: fixes for eroman Created 7 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: content/renderer/webcrypto/webcrypto_impl_nss.cc
diff --git a/content/renderer/webcrypto/webcrypto_impl_nss.cc b/content/renderer/webcrypto/webcrypto_impl_nss.cc
index fb9c275b70e650ac1d559583efce3e45420b3712..a476adf960f02ef9d2603b6647b5e6bdc1c600a0 100644
--- a/content/renderer/webcrypto/webcrypto_impl_nss.cc
+++ b/content/renderer/webcrypto/webcrypto_impl_nss.cc
@@ -181,6 +181,125 @@ bool AesCbcEncryptDecrypt(
return true;
}
+// Constants for RFC 3394 AES Key Wrap / Unwrap.
+const CK_MECHANISM_TYPE kAesKwMechanism = CKM_NSS_AES_KEY_WRAP;
+// The Default IV. See http://www.ietf.org/rfc/rfc3394.txt Section 2.2.3.1.
+const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
+
+// Performs RFC 3394 AES Key Wrap (encryption) of the input data.
+bool AesKwEncrypt(
+ const blink::WebCryptoKey& key,
+ const unsigned char* data,
+ unsigned data_size,
+ blink::WebArrayBuffer* buffer) {
+ DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id());
+ DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ DCHECK(blink::WebCryptoKeyUsageWrapKey & key.usages());
+
+ // The data size must be at least 16 bytes and a multiple of 8 bytes.
+ if (data_size < 16 || data_size % 8)
+ return false;
+ DCHECK(data);
+
+ SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv),
+ arraysize(kAesIv)};
+ crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item));
+ DCHECK(param_item);
+
+ // Turn the data to be wrapped into a PK11SymKey in order to use the NSS
+ // PK11_WrapSymKey() API. Create the PK11SymKey by importing the data as a
+ // generic secret blob, since we can't be certain what it is at this point.
Bryan Eyler 2014/01/15 19:30:17 Will we be hitting any issues with unwrapping a no
padolph 2014/01/15 22:58:52 Good point. I don't think using an asym key as an
eroman 2014/01/15 23:45:03 I have asked rsleevi to comment on this, hopefully
+ SECItem data_item = {siBuffer, const_cast<unsigned char*>(data), data_size};
+ crypto::ScopedPK11SymKey key_to_be_wrapped(
+ PK11_ImportSymKey(PK11_GetInternalSlot(),
+ CKK_GENERIC_SECRET,
+ PK11_OriginGenerated,
+ CKA_ENCRYPT,
+ &data_item,
+ 0));
+ if (!key_to_be_wrapped)
+ return false;
+
+ // AES Key Wrap always adds 8 bytes to the input data size. RFC 3394 does not
+ // specify a maximum allowed data length, but since we are only wrapping keys,
+ // which are usually small, a reasonable max size is whatever will fit into an
+ // unsigned.
+ if (data_size > UINT_MAX - 8)
+ return false;
+ const unsigned int output_length = data_size + 8;
+
+ *buffer = blink::WebArrayBuffer::create(output_length, 1);
+ unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
+ SECItem wrapped_key_item = {siBuffer, buffer_data, output_length};
+
+ SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle());
+
+ if (SECSuccess != PK11_WrapSymKey(kAesKwMechanism,
+ param_item.get(),
+ wrapping_key->key(),
+ key_to_be_wrapped.get(),
+ &wrapped_key_item)) {
+ return false;
+ }
+ if (output_length != wrapped_key_item.len) {
+ buffer->reset();
+ return false;
+ }
+
+ return true;
+}
+
+// Performs RFC 3394 AES Key Unwrap (decryption) of the input data.
+bool AesKwDecrypt(
+ const blink::WebCryptoKey& key,
+ const unsigned char* data,
+ unsigned data_size,
+ blink::WebArrayBuffer* buffer) {
+ DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id());
+ DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
+ DCHECK(blink::WebCryptoKeyUsageUnwrapKey & key.usages());
+
+ // The ciphertext data size must be at least 24 bytes and a multiple of
+ // 8 bytes.
+ if (data_size < 24 || data_size % 8 != 0)
+ return false;
+ DCHECK(data);
+
+ SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle());
+
+ SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv),
+ arraysize(kAesIv)};
+ crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item));
+ DCHECK(param_item);
+
+ SECItem cipher_text = {siBuffer, const_cast<unsigned char*>(data), data_size};
+
+ // The plaintext length is always 64 bits less than the data size.
+ const unsigned int plaintext_length = data_size - 8;
+
+ crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(
+ wrapping_key->key(),
+ kAesKwMechanism,
+ param_item.get(),
+ &cipher_text,
+ CKK_GENERIC_SECRET, // Import the key material without knowing its kind.
+ CKA_ENCRYPT, // A safe value since all we're doing is exporting the key.
+ plaintext_length));
+ if (!unwrapped_key)
+ return false;
+
+ if (PK11_ExtractKeyValue(unwrapped_key.get()) != SECSuccess)
+ return false;
+
+ const SECItem* key_data = PK11_GetKeyData(unwrapped_key.get());
+ if (!key_data || key_data->len != plaintext_length)
+ return false;
+
+ *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len);
+
+ return true;
+}
+
CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism(
const blink::WebCryptoAlgorithm& algorithm) {
switch (algorithm.id()) {
@@ -502,9 +621,12 @@ bool WebCryptoImpl::EncryptInternal(
DCHECK(key.handle());
DCHECK(buffer);
+ // TODO(padolph): Convert to switch statement.
if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) {
return AesCbcEncryptDecrypt(
CKA_ENCRYPT, algorithm, key, data, data_size, buffer);
+ } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) {
+ return AesKwEncrypt(key, data, data_size, buffer);
} else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) {
// RSAES encryption does not support empty input
@@ -554,9 +676,12 @@ bool WebCryptoImpl::DecryptInternal(
DCHECK(key.handle());
DCHECK(buffer);
+ // TODO(padolph): Convert to switch statement.
if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) {
return AesCbcEncryptDecrypt(
CKA_DECRYPT, algorithm, key, data, data_size, buffer);
+ } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) {
+ return AesKwDecrypt(key, data, data_size, buffer);
} else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) {
// RSAES decryption does not support empty input
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698