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

Side by Side Diff: content/renderer/webcrypto/shared_crypto.cc

Issue 188203003: Move webcrypto to child/ and add support to worker_webkitplatformsupport. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fixes to gypis Created 6 years, 9 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 | Annotate | Revision Log
OLDNEW
(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 "content/renderer/webcrypto/shared_crypto.h"
6
7 #include "base/logging.h"
8 #include "content/renderer/webcrypto/crypto_data.h"
9 #include "content/renderer/webcrypto/platform_crypto.h"
10 #include "content/renderer/webcrypto/webcrypto_util.h"
11 #include "crypto/secure_util.h"
12 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
13 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
14 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
15 #include "third_party/WebKit/public/platform/WebCryptoKey.h"
16
17 namespace content {
18
19 namespace webcrypto {
20
21 namespace {
22
23 // TODO(eroman): Move this helper to WebCryptoKey.
24 bool KeyUsageAllows(const blink::WebCryptoKey& key,
25 const blink::WebCryptoKeyUsage usage) {
26 return ((key.usages() & usage) != 0);
27 }
28
29 bool IsValidAesKeyLengthBits(unsigned int length_bits) {
30 return length_bits == 128 || length_bits == 192 || length_bits == 256;
31 }
32
33 bool IsValidAesKeyLengthBytes(unsigned int length_bytes) {
34 return length_bytes == 16 || length_bytes == 24 || length_bytes == 32;
35 }
36
37 Status ToPlatformSymKey(const blink::WebCryptoKey& key,
38 platform::SymKey** out) {
39 *out = static_cast<platform::Key*>(key.handle())->AsSymKey();
40 if (!*out)
41 return Status::ErrorUnexpectedKeyType();
42 return Status::Success();
43 }
44
45 Status ToPlatformPublicKey(const blink::WebCryptoKey& key,
46 platform::PublicKey** out) {
47 *out = static_cast<platform::Key*>(key.handle())->AsPublicKey();
48 if (!*out)
49 return Status::ErrorUnexpectedKeyType();
50 return Status::Success();
51 }
52
53 Status ToPlatformPrivateKey(const blink::WebCryptoKey& key,
54 platform::PrivateKey** out) {
55 *out = static_cast<platform::Key*>(key.handle())->AsPrivateKey();
56 if (!*out)
57 return Status::ErrorUnexpectedKeyType();
58 return Status::Success();
59 }
60
61 const size_t kAesBlockSizeBytes = 16;
62
63 Status EncryptDecryptAesCbc(EncryptOrDecrypt mode,
64 const blink::WebCryptoAlgorithm& algorithm,
65 const blink::WebCryptoKey& key,
66 const CryptoData& data,
67 blink::WebArrayBuffer* buffer) {
68 platform::SymKey* sym_key;
69 Status status = ToPlatformSymKey(key, &sym_key);
70 if (status.IsError())
71 return status;
72
73 const blink::WebCryptoAesCbcParams* params = algorithm.aesCbcParams();
74 if (!params)
75 return Status::ErrorUnexpected();
76
77 CryptoData iv(params->iv().data(), params->iv().size());
78 if (iv.byte_length() != kAesBlockSizeBytes)
79 return Status::ErrorIncorrectSizeAesCbcIv();
80
81 return platform::EncryptDecryptAesCbc(mode, sym_key, data, iv, buffer);
82 }
83
84 Status EncryptDecryptAesGcm(EncryptOrDecrypt mode,
85 const blink::WebCryptoAlgorithm& algorithm,
86 const blink::WebCryptoKey& key,
87 const CryptoData& data,
88 blink::WebArrayBuffer* buffer) {
89 platform::SymKey* sym_key;
90 Status status = ToPlatformSymKey(key, &sym_key);
91 if (status.IsError())
92 return status;
93
94 const blink::WebCryptoAesGcmParams* params = algorithm.aesGcmParams();
95 if (!params)
96 return Status::ErrorUnexpected();
97
98 unsigned int tag_length_bits = 128;
99 if (params->hasTagLengthBits())
100 tag_length_bits = params->optionalTagLengthBits();
101
102 if (tag_length_bits != 32 && tag_length_bits != 64 && tag_length_bits != 96 &&
103 tag_length_bits != 104 && tag_length_bits != 112 &&
104 tag_length_bits != 120 && tag_length_bits != 128)
105 return Status::ErrorInvalidAesGcmTagLength();
106
107 return platform::EncryptDecryptAesGcm(
108 mode,
109 sym_key,
110 data,
111 CryptoData(params->iv()),
112 CryptoData(params->optionalAdditionalData()),
113 tag_length_bits,
114 buffer);
115 }
116
117 Status EncryptRsaEsPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
118 const blink::WebCryptoKey& key,
119 const CryptoData& data,
120 blink::WebArrayBuffer* buffer) {
121 platform::PublicKey* public_key;
122 Status status = ToPlatformPublicKey(key, &public_key);
123 if (status.IsError())
124 return status;
125
126 // RSAES encryption does not support empty input
127 if (!data.byte_length())
128 return Status::Error();
129
130 return platform::EncryptRsaEsPkcs1v1_5(public_key, data, buffer);
131 }
132
133 Status DecryptRsaEsPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
134 const blink::WebCryptoKey& key,
135 const CryptoData& data,
136 blink::WebArrayBuffer* buffer) {
137 platform::PrivateKey* private_key;
138 Status status = ToPlatformPrivateKey(key, &private_key);
139 if (status.IsError())
140 return status;
141
142 // RSAES decryption does not support empty input
143 if (!data.byte_length())
144 return Status::Error();
145
146 return platform::DecryptRsaEsPkcs1v1_5(private_key, data, buffer);
147 }
148
149 Status SignHmac(const blink::WebCryptoAlgorithm& algorithm,
150 const blink::WebCryptoKey& key,
151 const CryptoData& data,
152 blink::WebArrayBuffer* buffer) {
153 platform::SymKey* sym_key;
154 Status status = ToPlatformSymKey(key, &sym_key);
155 if (status.IsError())
156 return status;
157
158 return platform::SignHmac(
159 sym_key, key.algorithm().hmacParams()->hash(), data, buffer);
160 }
161
162 Status VerifyHmac(const blink::WebCryptoAlgorithm& algorithm,
163 const blink::WebCryptoKey& key,
164 const CryptoData& signature,
165 const CryptoData& data,
166 bool* signature_match) {
167 blink::WebArrayBuffer result;
168 Status status = SignHmac(algorithm, key, data, &result);
169 if (status.IsError())
170 return status;
171
172 // Do not allow verification of truncated MACs.
173 *signature_match =
174 result.byteLength() == signature.byte_length() &&
175 crypto::SecureMemEqual(
176 result.data(), signature.bytes(), signature.byte_length());
177
178 return Status::Success();
179 }
180
181 Status SignRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
182 const blink::WebCryptoKey& key,
183 const CryptoData& data,
184 blink::WebArrayBuffer* buffer) {
185 platform::PrivateKey* private_key;
186 Status status = ToPlatformPrivateKey(key, &private_key);
187 if (status.IsError())
188 return status;
189
190 return platform::SignRsaSsaPkcs1v1_5(
191 private_key, key.algorithm().rsaHashedParams()->hash(), data, buffer);
192 }
193
194 Status VerifyRsaSsaPkcs1v1_5(const blink::WebCryptoAlgorithm& algorithm,
195 const blink::WebCryptoKey& key,
196 const CryptoData& signature,
197 const CryptoData& data,
198 bool* signature_match) {
199 platform::PublicKey* public_key;
200 Status status = ToPlatformPublicKey(key, &public_key);
201 if (status.IsError())
202 return status;
203
204 return platform::VerifyRsaSsaPkcs1v1_5(
205 public_key,
206 key.algorithm().rsaHashedParams()->hash(),
207 signature,
208 data,
209 signature_match);
210 }
211
212 Status ImportKeyRaw(const CryptoData& key_data,
213 const blink::WebCryptoAlgorithm& algorithm_or_null,
214 bool extractable,
215 blink::WebCryptoKeyUsageMask usage_mask,
216 blink::WebCryptoKey* key) {
217 if (algorithm_or_null.isNull())
218 return Status::ErrorMissingAlgorithmImportRawKey();
219
220 switch (algorithm_or_null.id()) {
221 case blink::WebCryptoAlgorithmIdAesCtr:
222 case blink::WebCryptoAlgorithmIdAesCbc:
223 case blink::WebCryptoAlgorithmIdAesGcm:
224 case blink::WebCryptoAlgorithmIdAesKw:
225 if (!IsValidAesKeyLengthBytes(key_data.byte_length()))
226 return Status::Error();
227 // Fallthrough intentional!
228 case blink::WebCryptoAlgorithmIdHmac:
229 return platform::ImportKeyRaw(
230 algorithm_or_null, key_data, extractable, usage_mask, key);
231 default:
232 return Status::ErrorUnsupported();
233 }
234 }
235
236 } // namespace
237
238 void Init() { platform::Init(); }
239
240 Status Encrypt(const blink::WebCryptoAlgorithm& algorithm,
241 const blink::WebCryptoKey& key,
242 const CryptoData& data,
243 blink::WebArrayBuffer* buffer) {
244 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageEncrypt))
245 return Status::ErrorUnexpected();
246 if (algorithm.id() != key.algorithm().id())
247 return Status::ErrorUnexpected();
248
249 switch (algorithm.id()) {
250 case blink::WebCryptoAlgorithmIdAesCbc:
251 return EncryptDecryptAesCbc(ENCRYPT, algorithm, key, data, buffer);
252 case blink::WebCryptoAlgorithmIdAesGcm:
253 return EncryptDecryptAesGcm(ENCRYPT, algorithm, key, data, buffer);
254 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
255 return EncryptRsaEsPkcs1v1_5(algorithm, key, data, buffer);
256 default:
257 return Status::ErrorUnsupported();
258 }
259 }
260
261 Status Decrypt(const blink::WebCryptoAlgorithm& algorithm,
262 const blink::WebCryptoKey& key,
263 const CryptoData& data,
264 blink::WebArrayBuffer* buffer) {
265 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageDecrypt))
266 return Status::ErrorUnexpected();
267 if (algorithm.id() != key.algorithm().id())
268 return Status::ErrorUnexpected();
269
270 switch (algorithm.id()) {
271 case blink::WebCryptoAlgorithmIdAesCbc:
272 return EncryptDecryptAesCbc(DECRYPT, algorithm, key, data, buffer);
273 case blink::WebCryptoAlgorithmIdAesGcm:
274 return EncryptDecryptAesGcm(DECRYPT, algorithm, key, data, buffer);
275 case blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5:
276 return DecryptRsaEsPkcs1v1_5(algorithm, key, data, buffer);
277 default:
278 return Status::ErrorUnsupported();
279 }
280 }
281
282 Status Digest(const blink::WebCryptoAlgorithm& algorithm,
283 const CryptoData& data,
284 blink::WebArrayBuffer* buffer) {
285 switch (algorithm.id()) {
286 case blink::WebCryptoAlgorithmIdSha1:
287 case blink::WebCryptoAlgorithmIdSha224:
288 case blink::WebCryptoAlgorithmIdSha256:
289 case blink::WebCryptoAlgorithmIdSha384:
290 case blink::WebCryptoAlgorithmIdSha512:
291 return platform::DigestSha(algorithm.id(), data, buffer);
292 default:
293 return Status::ErrorUnsupported();
294 }
295 }
296
297 Status GenerateSecretKey(const blink::WebCryptoAlgorithm& algorithm,
298 bool extractable,
299 blink::WebCryptoKeyUsageMask usage_mask,
300 blink::WebCryptoKey* key) {
301 unsigned int keylen_bytes = 0;
302
303 // Get the secret key length in bytes from generation parameters.
304 // This resolves any defaults.
305 switch (algorithm.id()) {
306 case blink::WebCryptoAlgorithmIdAesCbc:
307 case blink::WebCryptoAlgorithmIdAesGcm:
308 case blink::WebCryptoAlgorithmIdAesKw: {
309 if (!IsValidAesKeyLengthBits(algorithm.aesKeyGenParams()->lengthBits()))
310 return Status::ErrorGenerateKeyLength();
311 keylen_bytes = algorithm.aesKeyGenParams()->lengthBits() / 8;
312 break;
313 }
314 case blink::WebCryptoAlgorithmIdHmac: {
315 const blink::WebCryptoHmacKeyGenParams* params =
316 algorithm.hmacKeyGenParams();
317 DCHECK(params);
318 if (params->hasLengthBytes()) {
319 keylen_bytes = params->optionalLengthBytes();
320 } else {
321 keylen_bytes = ShaBlockSizeBytes(params->hash().id());
322 if (keylen_bytes == 0)
323 return Status::ErrorUnsupported();
324 }
325 break;
326 }
327
328 default:
329 return Status::ErrorUnsupported();
330 }
331
332 // TODO(eroman): Is this correct? HMAC can import zero-length keys, so should
333 // probably be able to allowed to generate them too.
334 if (keylen_bytes == 0)
335 return Status::ErrorGenerateKeyLength();
336
337 return platform::GenerateSecretKey(
338 algorithm, extractable, usage_mask, keylen_bytes, key);
339 }
340
341 Status GenerateKeyPair(const blink::WebCryptoAlgorithm& algorithm,
342 bool extractable,
343 blink::WebCryptoKeyUsageMask usage_mask,
344 blink::WebCryptoKey* public_key,
345 blink::WebCryptoKey* private_key) {
346 // TODO(padolph): Handle other asymmetric algorithm key generation.
347 switch (algorithm.paramsType()) {
348 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams:
349 case blink::WebCryptoAlgorithmParamsTypeRsaKeyGenParams: {
350 const blink::WebCryptoRsaKeyGenParams* params = NULL;
351 blink::WebCryptoAlgorithm hash_or_null =
352 blink::WebCryptoAlgorithm::createNull();
353 if (algorithm.rsaHashedKeyGenParams()) {
354 params = algorithm.rsaHashedKeyGenParams();
355 hash_or_null = algorithm.rsaHashedKeyGenParams()->hash();
356 } else {
357 params = algorithm.rsaKeyGenParams();
358 }
359
360 if (!params->modulusLengthBits())
361 return Status::ErrorGenerateRsaZeroModulus();
362
363 CryptoData publicExponent(params->publicExponent());
364 if (!publicExponent.byte_length())
365 return Status::ErrorGenerateKeyPublicExponent();
366
367 return platform::GenerateRsaKeyPair(algorithm,
368 extractable,
369 usage_mask,
370 params->modulusLengthBits(),
371 publicExponent,
372 hash_or_null,
373 public_key,
374 private_key);
375 }
376 default:
377 return Status::ErrorUnsupported();
378 }
379 }
380
381 Status ImportKey(blink::WebCryptoKeyFormat format,
382 const CryptoData& key_data,
383 const blink::WebCryptoAlgorithm& algorithm_or_null,
384 bool extractable,
385 blink::WebCryptoKeyUsageMask usage_mask,
386 blink::WebCryptoKey* key) {
387 switch (format) {
388 case blink::WebCryptoKeyFormatRaw:
389 return ImportKeyRaw(
390 key_data, algorithm_or_null, extractable, usage_mask, key);
391 case blink::WebCryptoKeyFormatSpki:
392 return platform::ImportKeySpki(
393 algorithm_or_null, key_data, extractable, usage_mask, key);
394 case blink::WebCryptoKeyFormatPkcs8:
395 return platform::ImportKeyPkcs8(
396 algorithm_or_null, key_data, extractable, usage_mask, key);
397 case blink::WebCryptoKeyFormatJwk:
398 return ImportKeyJwk(
399 key_data, algorithm_or_null, extractable, usage_mask, key);
400 default:
401 return Status::ErrorUnsupported();
402 }
403 }
404
405 Status ExportKey(blink::WebCryptoKeyFormat format,
406 const blink::WebCryptoKey& key,
407 blink::WebArrayBuffer* buffer) {
408 if (!key.extractable())
409 return Status::ErrorKeyNotExtractable();
410
411 switch (format) {
412 case blink::WebCryptoKeyFormatRaw: {
413 platform::SymKey* sym_key;
414 Status status = ToPlatformSymKey(key, &sym_key);
415 if (status.IsError())
416 return status;
417 return platform::ExportKeyRaw(sym_key, buffer);
418 }
419 case blink::WebCryptoKeyFormatSpki: {
420 platform::PublicKey* public_key;
421 Status status = ToPlatformPublicKey(key, &public_key);
422 if (status.IsError())
423 return status;
424 return platform::ExportKeySpki(public_key, buffer);
425 }
426 case blink::WebCryptoKeyFormatPkcs8:
427 case blink::WebCryptoKeyFormatJwk:
428 // TODO(eroman):
429 return Status::ErrorUnsupported();
430 default:
431 return Status::ErrorUnsupported();
432 }
433 }
434
435 Status Sign(const blink::WebCryptoAlgorithm& algorithm,
436 const blink::WebCryptoKey& key,
437 const CryptoData& data,
438 blink::WebArrayBuffer* buffer) {
439 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageSign))
440 return Status::ErrorUnexpected();
441 if (algorithm.id() != key.algorithm().id())
442 return Status::ErrorUnexpected();
443
444 switch (algorithm.id()) {
445 case blink::WebCryptoAlgorithmIdHmac:
446 return SignHmac(algorithm, key, data, buffer);
447 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
448 return SignRsaSsaPkcs1v1_5(algorithm, key, data, buffer);
449 default:
450 return Status::ErrorUnsupported();
451 }
452 }
453
454 Status VerifySignature(const blink::WebCryptoAlgorithm& algorithm,
455 const blink::WebCryptoKey& key,
456 const CryptoData& signature,
457 const CryptoData& data,
458 bool* signature_match) {
459 if (!KeyUsageAllows(key, blink::WebCryptoKeyUsageVerify))
460 return Status::ErrorUnexpected();
461 if (algorithm.id() != key.algorithm().id())
462 return Status::ErrorUnexpected();
463
464 if (!signature.byte_length()) {
465 // None of the algorithms generate valid zero-length signatures so this
466 // will necessarily fail verification. Early return to protect
467 // implementations from dealing with a NULL signature pointer.
468 *signature_match = false;
469 return Status::Success();
470 }
471
472 switch (algorithm.id()) {
473 case blink::WebCryptoAlgorithmIdHmac:
474 return VerifyHmac(algorithm, key, signature, data, signature_match);
475 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
476 return VerifyRsaSsaPkcs1v1_5(
477 algorithm, key, signature, data, signature_match);
478 default:
479 return Status::ErrorUnsupported();
480 }
481 }
482
483 } // namespace webcrypto
484
485 } // namespace content
OLDNEW
« no previous file with comments | « content/renderer/webcrypto/shared_crypto.h ('k') | content/renderer/webcrypto/shared_crypto_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698