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.
5 #include "components/webcrypto/algorithm_dispatch.h"
7 #include "base/logging.h"
8 #include "components/webcrypto/algorithm_implementation.h"
9 #include "components/webcrypto/algorithm_registry.h"
10 #include "components/webcrypto/crypto_data.h"
11 #include "components/webcrypto/generate_key_result.h"
12 #include "components/webcrypto/platform_crypto.h"
13 #include "components/webcrypto/status.h"
14 #include "components/webcrypto/webcrypto_util.h"
15 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
21 Status
DecryptDontCheckKeyUsage(const blink::WebCryptoAlgorithm
& algorithm
,
22 const blink::WebCryptoKey
& key
,
23 const CryptoData
& data
,
24 std::vector
<uint8_t>* buffer
) {
25 if (algorithm
.id() != key
.algorithm().id())
26 return Status::ErrorUnexpected();
28 const AlgorithmImplementation
* impl
= NULL
;
29 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
33 return impl
->Decrypt(algorithm
, key
, data
, buffer
);
36 Status
EncryptDontCheckUsage(const blink::WebCryptoAlgorithm
& algorithm
,
37 const blink::WebCryptoKey
& key
,
38 const CryptoData
& data
,
39 std::vector
<uint8_t>* buffer
) {
40 if (algorithm
.id() != key
.algorithm().id())
41 return Status::ErrorUnexpected();
43 const AlgorithmImplementation
* impl
= NULL
;
44 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
48 return impl
->Encrypt(algorithm
, key
, data
, buffer
);
51 Status
ExportKeyDontCheckExtractability(blink::WebCryptoKeyFormat format
,
52 const blink::WebCryptoKey
& key
,
53 std::vector
<uint8_t>* buffer
) {
54 const AlgorithmImplementation
* impl
= NULL
;
55 Status status
= GetAlgorithmImplementation(key
.algorithm().id(), &impl
);
59 return impl
->ExportKey(format
, key
, buffer
);
64 Status
Encrypt(const blink::WebCryptoAlgorithm
& algorithm
,
65 const blink::WebCryptoKey
& key
,
66 const CryptoData
& data
,
67 std::vector
<uint8_t>* buffer
) {
68 if (!KeyUsageAllows(key
, blink::WebCryptoKeyUsageEncrypt
))
69 return Status::ErrorUnexpected();
70 return EncryptDontCheckUsage(algorithm
, key
, data
, buffer
);
73 Status
Decrypt(const blink::WebCryptoAlgorithm
& algorithm
,
74 const blink::WebCryptoKey
& key
,
75 const CryptoData
& data
,
76 std::vector
<uint8_t>* buffer
) {
77 if (!KeyUsageAllows(key
, blink::WebCryptoKeyUsageDecrypt
))
78 return Status::ErrorUnexpected();
79 return DecryptDontCheckKeyUsage(algorithm
, key
, data
, buffer
);
82 Status
Digest(const blink::WebCryptoAlgorithm
& algorithm
,
83 const CryptoData
& data
,
84 std::vector
<uint8_t>* buffer
) {
85 const AlgorithmImplementation
* impl
= NULL
;
86 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
90 return impl
->Digest(algorithm
, data
, buffer
);
93 Status
GenerateKey(const blink::WebCryptoAlgorithm
& algorithm
,
95 blink::WebCryptoKeyUsageMask usages
,
96 GenerateKeyResult
* result
) {
97 const AlgorithmImplementation
* impl
= NULL
;
98 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
102 status
= impl
->GenerateKey(algorithm
, extractable
, usages
, result
);
103 if (status
.IsError())
106 const blink::WebCryptoKey
* key
= NULL
;
107 if (result
->type() == GenerateKeyResult::TYPE_SECRET_KEY
)
108 key
= &result
->secret_key();
109 if (result
->type() == GenerateKeyResult::TYPE_PUBLIC_PRIVATE_KEY_PAIR
)
110 key
= &result
->private_key();
112 return Status::ErrorUnexpected();
114 // This should only fail if an algorithm is implemented incorrectly and
115 // does not do its own check of the usages.
116 if (key
->usages() == 0) {
117 DCHECK(false) << "Key usages for generateKey() must not be empty";
118 return Status::ErrorCreateKeyEmptyUsages();
123 Status
ImportKey(blink::WebCryptoKeyFormat format
,
124 const CryptoData
& key_data
,
125 const blink::WebCryptoAlgorithm
& algorithm
,
127 blink::WebCryptoKeyUsageMask usages
,
128 blink::WebCryptoKey
* key
) {
129 const AlgorithmImplementation
* impl
= NULL
;
130 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
131 if (status
.IsError())
134 status
= impl
->VerifyKeyUsagesBeforeImportKey(format
, usages
);
135 if (status
.IsError())
138 return impl
->ImportKey(format
, key_data
, algorithm
, extractable
, usages
, key
);
141 Status
ExportKey(blink::WebCryptoKeyFormat format
,
142 const blink::WebCryptoKey
& key
,
143 std::vector
<uint8_t>* buffer
) {
144 if (!key
.extractable())
145 return Status::ErrorKeyNotExtractable();
146 return ExportKeyDontCheckExtractability(format
, key
, buffer
);
149 Status
Sign(const blink::WebCryptoAlgorithm
& algorithm
,
150 const blink::WebCryptoKey
& key
,
151 const CryptoData
& data
,
152 std::vector
<uint8_t>* buffer
) {
153 if (!KeyUsageAllows(key
, blink::WebCryptoKeyUsageSign
))
154 return Status::ErrorUnexpected();
155 if (algorithm
.id() != key
.algorithm().id())
156 return Status::ErrorUnexpected();
158 const AlgorithmImplementation
* impl
= NULL
;
159 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
160 if (status
.IsError())
163 return impl
->Sign(algorithm
, key
, data
, buffer
);
166 Status
Verify(const blink::WebCryptoAlgorithm
& algorithm
,
167 const blink::WebCryptoKey
& key
,
168 const CryptoData
& signature
,
169 const CryptoData
& data
,
170 bool* signature_match
) {
171 if (!KeyUsageAllows(key
, blink::WebCryptoKeyUsageVerify
))
172 return Status::ErrorUnexpected();
173 if (algorithm
.id() != key
.algorithm().id())
174 return Status::ErrorUnexpected();
176 const AlgorithmImplementation
* impl
= NULL
;
177 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
178 if (status
.IsError())
181 return impl
->Verify(algorithm
, key
, signature
, data
, signature_match
);
184 Status
WrapKey(blink::WebCryptoKeyFormat format
,
185 const blink::WebCryptoKey
& key_to_wrap
,
186 const blink::WebCryptoKey
& wrapping_key
,
187 const blink::WebCryptoAlgorithm
& wrapping_algorithm
,
188 std::vector
<uint8_t>* buffer
) {
189 if (!KeyUsageAllows(wrapping_key
, blink::WebCryptoKeyUsageWrapKey
))
190 return Status::ErrorUnexpected();
192 std::vector
<uint8_t> exported_data
;
193 Status status
= ExportKey(format
, key_to_wrap
, &exported_data
);
194 if (status
.IsError())
196 return EncryptDontCheckUsage(wrapping_algorithm
, wrapping_key
,
197 CryptoData(exported_data
), buffer
);
200 Status
UnwrapKey(blink::WebCryptoKeyFormat format
,
201 const CryptoData
& wrapped_key_data
,
202 const blink::WebCryptoKey
& wrapping_key
,
203 const blink::WebCryptoAlgorithm
& wrapping_algorithm
,
204 const blink::WebCryptoAlgorithm
& algorithm
,
206 blink::WebCryptoKeyUsageMask usages
,
207 blink::WebCryptoKey
* key
) {
208 if (!KeyUsageAllows(wrapping_key
, blink::WebCryptoKeyUsageUnwrapKey
))
209 return Status::ErrorUnexpected();
210 if (wrapping_algorithm
.id() != wrapping_key
.algorithm().id())
211 return Status::ErrorUnexpected();
213 // Fail fast if the import is doomed to fail.
214 const AlgorithmImplementation
* import_impl
= NULL
;
215 Status status
= GetAlgorithmImplementation(algorithm
.id(), &import_impl
);
216 if (status
.IsError())
219 status
= import_impl
->VerifyKeyUsagesBeforeImportKey(format
, usages
);
220 if (status
.IsError())
223 std::vector
<uint8_t> buffer
;
224 status
= DecryptDontCheckKeyUsage(wrapping_algorithm
, wrapping_key
,
225 wrapped_key_data
, &buffer
);
226 if (status
.IsError())
229 // NOTE that returning the details of ImportKey() failures may leak
230 // information about the plaintext of the encrypted key (for instance the JWK
231 // key_ops). As long as the ImportKey error messages don't describe actual
232 // key bytes however this should be OK. For more discussion see
233 // http://crubg.com/372040
234 return ImportKey(format
, CryptoData(buffer
), algorithm
, extractable
, usages
,
238 Status
DeriveBits(const blink::WebCryptoAlgorithm
& algorithm
,
239 const blink::WebCryptoKey
& base_key
,
240 unsigned int length_bits
,
241 std::vector
<uint8_t>* derived_bytes
) {
242 if (!KeyUsageAllows(base_key
, blink::WebCryptoKeyUsageDeriveBits
))
243 return Status::ErrorUnexpected();
245 if (algorithm
.id() != base_key
.algorithm().id())
246 return Status::ErrorUnexpected();
248 const AlgorithmImplementation
* impl
= NULL
;
249 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
250 if (status
.IsError())
253 return impl
->DeriveBits(algorithm
, base_key
, true, length_bits
,
257 Status
DeriveKey(const blink::WebCryptoAlgorithm
& algorithm
,
258 const blink::WebCryptoKey
& base_key
,
259 const blink::WebCryptoAlgorithm
& import_algorithm
,
260 const blink::WebCryptoAlgorithm
& key_length_algorithm
,
262 blink::WebCryptoKeyUsageMask usages
,
263 blink::WebCryptoKey
* derived_key
) {
264 if (!KeyUsageAllows(base_key
, blink::WebCryptoKeyUsageDeriveKey
))
265 return Status::ErrorUnexpected();
267 if (algorithm
.id() != base_key
.algorithm().id())
268 return Status::ErrorUnexpected();
270 if (import_algorithm
.id() != key_length_algorithm
.id())
271 return Status::ErrorUnexpected();
273 const AlgorithmImplementation
* import_impl
= NULL
;
275 GetAlgorithmImplementation(import_algorithm
.id(), &import_impl
);
276 if (status
.IsError())
279 // Fail fast if the requested key usages are incorect.
280 status
= import_impl
->VerifyKeyUsagesBeforeImportKey(
281 blink::WebCryptoKeyFormatRaw
, usages
);
282 if (status
.IsError())
285 // Determine how many bits long the derived key should be.
286 unsigned int length_bits
= 0;
287 bool has_length_bits
= false;
288 status
= import_impl
->GetKeyLength(key_length_algorithm
, &has_length_bits
,
290 if (status
.IsError())
293 // Derive the key bytes.
294 const AlgorithmImplementation
* derive_impl
= NULL
;
295 status
= GetAlgorithmImplementation(algorithm
.id(), &derive_impl
);
296 if (status
.IsError())
299 std::vector
<uint8_t> derived_bytes
;
300 status
= derive_impl
->DeriveBits(algorithm
, base_key
, has_length_bits
,
301 length_bits
, &derived_bytes
);
302 if (status
.IsError())
305 // Create the key using the derived bytes.
306 return ImportKey(blink::WebCryptoKeyFormatRaw
, CryptoData(derived_bytes
),
307 import_algorithm
, extractable
, usages
, derived_key
);
310 scoped_ptr
<blink::WebCryptoDigestor
> CreateDigestor(
311 blink::WebCryptoAlgorithmId algorithm
) {
313 return CreatePlatformDigestor(algorithm
);
316 bool SerializeKeyForClone(const blink::WebCryptoKey
& key
,
317 blink::WebVector
<uint8_t>* key_data
) {
318 const AlgorithmImplementation
* impl
= NULL
;
319 Status status
= GetAlgorithmImplementation(key
.algorithm().id(), &impl
);
320 if (status
.IsError())
323 status
= impl
->SerializeKeyForClone(key
, key_data
);
324 return status
.IsSuccess();
327 bool DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm
& algorithm
,
328 blink::WebCryptoKeyType type
,
330 blink::WebCryptoKeyUsageMask usages
,
331 const CryptoData
& key_data
,
332 blink::WebCryptoKey
* key
) {
333 const AlgorithmImplementation
* impl
= NULL
;
334 Status status
= GetAlgorithmImplementation(algorithm
.id(), &impl
);
335 if (status
.IsError())
338 status
= impl
->DeserializeKeyForClone(algorithm
, type
, extractable
, usages
,
340 return status
.IsSuccess();
343 } // namespace webcrypto