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

Side by Side 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 6 years, 12 months 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 unified diff | Download patch
« no previous file with comments | « no previous file | content/renderer/webcrypto/webcrypto_impl_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 buffer_data + output_len, 174 buffer_data + output_len,
175 &final_output_chunk_len, 175 &final_output_chunk_len,
176 output_max_len - output_len)) { 176 output_max_len - output_len)) {
177 return false; 177 return false;
178 } 178 }
179 179
180 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len); 180 webcrypto::ShrinkBuffer(buffer, final_output_chunk_len + output_len);
181 return true; 181 return true;
182 } 182 }
183 183
184 // Constants for RFC 3394 AES Key Wrap / Unwrap.
185 const CK_MECHANISM_TYPE kAesKwMechanism = CKM_NSS_AES_KEY_WRAP;
186 // The Default IV. See http://www.ietf.org/rfc/rfc3394.txt Section 2.2.3.1.
187 const unsigned char kAesIv[] = {0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6, 0xA6};
188
189 // Performs RFC 3394 AES Key Wrap (encryption) of the input data.
190 bool AesKwEncrypt(
191 const blink::WebCryptoKey& key,
192 const unsigned char* data,
193 unsigned data_size,
194 blink::WebArrayBuffer* buffer) {
195 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id());
196 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
197 DCHECK(blink::WebCryptoKeyUsageWrapKey & key.usages());
198
199 // The data size must be at least 16 bytes and a multiple of 8 bytes.
200 if (data_size < 16 || data_size % 8)
201 return false;
202 DCHECK(data);
203
204 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv),
205 arraysize(kAesIv)};
206 crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item));
207 DCHECK(param_item);
208
209 // Turn the data to be wrapped into a PK11SymKey in order to use the NSS
210 // PK11_WrapSymKey() API. Create the PK11SymKey by importing the data as a
211 // 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
212 SECItem data_item = {siBuffer, const_cast<unsigned char*>(data), data_size};
213 crypto::ScopedPK11SymKey key_to_be_wrapped(
214 PK11_ImportSymKey(PK11_GetInternalSlot(),
215 CKK_GENERIC_SECRET,
216 PK11_OriginGenerated,
217 CKA_ENCRYPT,
218 &data_item,
219 0));
220 if (!key_to_be_wrapped)
221 return false;
222
223 // AES Key Wrap always adds 8 bytes to the input data size. RFC 3394 does not
224 // specify a maximum allowed data length, but since we are only wrapping keys,
225 // which are usually small, a reasonable max size is whatever will fit into an
226 // unsigned.
227 if (data_size > UINT_MAX - 8)
228 return false;
229 const unsigned int output_length = data_size + 8;
230
231 *buffer = blink::WebArrayBuffer::create(output_length, 1);
232 unsigned char* buffer_data = reinterpret_cast<unsigned char*>(buffer->data());
233 SECItem wrapped_key_item = {siBuffer, buffer_data, output_length};
234
235 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle());
236
237 if (SECSuccess != PK11_WrapSymKey(kAesKwMechanism,
238 param_item.get(),
239 wrapping_key->key(),
240 key_to_be_wrapped.get(),
241 &wrapped_key_item)) {
242 return false;
243 }
244 if (output_length != wrapped_key_item.len) {
245 buffer->reset();
246 return false;
247 }
248
249 return true;
250 }
251
252 // Performs RFC 3394 AES Key Unwrap (decryption) of the input data.
253 bool AesKwDecrypt(
254 const blink::WebCryptoKey& key,
255 const unsigned char* data,
256 unsigned data_size,
257 blink::WebArrayBuffer* buffer) {
258 DCHECK_EQ(blink::WebCryptoAlgorithmIdAesKw, key.algorithm().id());
259 DCHECK_EQ(blink::WebCryptoKeyTypeSecret, key.type());
260 DCHECK(blink::WebCryptoKeyUsageUnwrapKey & key.usages());
261
262 // The ciphertext data size must be at least 24 bytes and a multiple of
263 // 8 bytes.
264 if (data_size < 24 || data_size % 8 != 0)
265 return false;
266 DCHECK(data);
267
268 SymKeyHandle* wrapping_key = reinterpret_cast<SymKeyHandle*>(key.handle());
269
270 SECItem iv_item = {siBuffer, const_cast<unsigned char*>(kAesIv),
271 arraysize(kAesIv)};
272 crypto::ScopedSECItem param_item(PK11_ParamFromIV(kAesKwMechanism, &iv_item));
273 DCHECK(param_item);
274
275 SECItem cipher_text = {siBuffer, const_cast<unsigned char*>(data), data_size};
276
277 // The plaintext length is always 64 bits less than the data size.
278 const unsigned int plaintext_length = data_size - 8;
279
280 crypto::ScopedPK11SymKey unwrapped_key(PK11_UnwrapSymKey(
281 wrapping_key->key(),
282 kAesKwMechanism,
283 param_item.get(),
284 &cipher_text,
285 CKK_GENERIC_SECRET, // Import the key material without knowing its kind.
286 CKA_ENCRYPT, // A safe value since all we're doing is exporting the key.
287 plaintext_length));
288 if (!unwrapped_key)
289 return false;
290
291 if (PK11_ExtractKeyValue(unwrapped_key.get()) != SECSuccess)
292 return false;
293
294 const SECItem* key_data = PK11_GetKeyData(unwrapped_key.get());
295 if (!key_data || key_data->len != plaintext_length)
296 return false;
297
298 *buffer = webcrypto::CreateArrayBuffer(key_data->data, key_data->len);
299
300 return true;
301 }
302
184 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism( 303 CK_MECHANISM_TYPE WebCryptoAlgorithmToGenMechanism(
185 const blink::WebCryptoAlgorithm& algorithm) { 304 const blink::WebCryptoAlgorithm& algorithm) {
186 switch (algorithm.id()) { 305 switch (algorithm.id()) {
187 case blink::WebCryptoAlgorithmIdAesCbc: 306 case blink::WebCryptoAlgorithmIdAesCbc:
188 case blink::WebCryptoAlgorithmIdAesGcm: 307 case blink::WebCryptoAlgorithmIdAesGcm:
189 case blink::WebCryptoAlgorithmIdAesKw: 308 case blink::WebCryptoAlgorithmIdAesKw:
190 return CKM_AES_KEY_GEN; 309 return CKM_AES_KEY_GEN;
191 case blink::WebCryptoAlgorithmIdHmac: 310 case blink::WebCryptoAlgorithmIdHmac:
192 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash()); 311 return WebCryptoHashToHMACMechanism(algorithm.hmacKeyParams()->hash());
193 default: 312 default:
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after
495 const blink::WebCryptoAlgorithm& algorithm, 614 const blink::WebCryptoAlgorithm& algorithm,
496 const blink::WebCryptoKey& key, 615 const blink::WebCryptoKey& key,
497 const unsigned char* data, 616 const unsigned char* data,
498 unsigned data_size, 617 unsigned data_size,
499 blink::WebArrayBuffer* buffer) { 618 blink::WebArrayBuffer* buffer) {
500 619
501 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 620 DCHECK_EQ(algorithm.id(), key.algorithm().id());
502 DCHECK(key.handle()); 621 DCHECK(key.handle());
503 DCHECK(buffer); 622 DCHECK(buffer);
504 623
624 // TODO(padolph): Convert to switch statement.
505 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { 625 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) {
506 return AesCbcEncryptDecrypt( 626 return AesCbcEncryptDecrypt(
507 CKA_ENCRYPT, algorithm, key, data, data_size, buffer); 627 CKA_ENCRYPT, algorithm, key, data, data_size, buffer);
628 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) {
629 return AesKwEncrypt(key, data, data_size, buffer);
508 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { 630 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) {
509 631
510 // RSAES encryption does not support empty input 632 // RSAES encryption does not support empty input
511 if (!data_size) 633 if (!data_size)
512 return false; 634 return false;
513 DCHECK(data); 635 DCHECK(data);
514 636
515 if (key.type() != blink::WebCryptoKeyTypePublic) 637 if (key.type() != blink::WebCryptoKeyTypePublic)
516 return false; 638 return false;
517 639
(...skipping 29 matching lines...) Expand all
547 const blink::WebCryptoAlgorithm& algorithm, 669 const blink::WebCryptoAlgorithm& algorithm,
548 const blink::WebCryptoKey& key, 670 const blink::WebCryptoKey& key,
549 const unsigned char* data, 671 const unsigned char* data,
550 unsigned data_size, 672 unsigned data_size,
551 blink::WebArrayBuffer* buffer) { 673 blink::WebArrayBuffer* buffer) {
552 674
553 DCHECK_EQ(algorithm.id(), key.algorithm().id()); 675 DCHECK_EQ(algorithm.id(), key.algorithm().id());
554 DCHECK(key.handle()); 676 DCHECK(key.handle());
555 DCHECK(buffer); 677 DCHECK(buffer);
556 678
679 // TODO(padolph): Convert to switch statement.
557 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) { 680 if (algorithm.id() == blink::WebCryptoAlgorithmIdAesCbc) {
558 return AesCbcEncryptDecrypt( 681 return AesCbcEncryptDecrypt(
559 CKA_DECRYPT, algorithm, key, data, data_size, buffer); 682 CKA_DECRYPT, algorithm, key, data, data_size, buffer);
683 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdAesKw) {
684 return AesKwDecrypt(key, data, data_size, buffer);
560 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) { 685 } else if (algorithm.id() == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5) {
561 686
562 // RSAES decryption does not support empty input 687 // RSAES decryption does not support empty input
563 if (!data_size) 688 if (!data_size)
564 return false; 689 return false;
565 DCHECK(data); 690 DCHECK(data);
566 691
567 if (key.type() != blink::WebCryptoKeyTypePrivate) 692 if (key.type() != blink::WebCryptoKeyTypePrivate)
568 return false; 693 return false;
569 694
(...skipping 422 matching lines...) Expand 10 before | Expand all | Expand 10 after
992 1117
993 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()), 1118 *key = blink::WebCryptoKey::create(new PublicKeyHandle(pubkey.Pass()),
994 blink::WebCryptoKeyTypePublic, 1119 blink::WebCryptoKeyTypePublic,
995 extractable, 1120 extractable,
996 algorithm, 1121 algorithm,
997 usage_mask); 1122 usage_mask);
998 return true; 1123 return true;
999 } 1124 }
1000 1125
1001 } // namespace content 1126 } // namespace content
OLDNEW
« 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