OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "content/renderer/webcrypto/webcrypto_util.h" | |
6 | |
7 #include "base/base64.h" | |
8 #include "base/logging.h" | |
9 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h" | |
10 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h" | |
11 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h" | |
12 | |
13 namespace content { | |
14 | |
15 namespace webcrypto { | |
16 | |
17 bool Status::IsError() const { return type_ == TYPE_ERROR; } | |
18 | |
19 bool Status::IsSuccess() const { return type_ == TYPE_SUCCESS; } | |
20 | |
21 bool Status::HasErrorDetails() const { return !error_details_.empty(); } | |
22 | |
23 std::string Status::ToString() const { | |
24 return IsSuccess() ? "Success" : error_details_; | |
25 } | |
26 | |
27 Status Status::Success() { return Status(TYPE_SUCCESS); } | |
28 | |
29 Status Status::Error() { return Status(TYPE_ERROR); } | |
30 | |
31 Status Status::ErrorJwkNotDictionary() { | |
32 return Status("JWK input could not be parsed to a JSON dictionary"); | |
33 } | |
34 | |
35 Status Status::ErrorJwkPropertyMissing(const std::string& property) { | |
36 return Status("The required JWK property \"" + property + "\" was missing"); | |
37 } | |
38 | |
39 Status Status::ErrorJwkPropertyWrongType(const std::string& property, | |
40 const std::string& expected_type) { | |
41 return Status("The JWK property \"" + property + "\" must be a " + | |
42 expected_type); | |
43 } | |
44 | |
45 Status Status::ErrorJwkBase64Decode(const std::string& property) { | |
46 return Status("The JWK property \"" + property + | |
47 "\" could not be base64 decoded"); | |
48 } | |
49 | |
50 Status Status::ErrorJwkExtractableInconsistent() { | |
51 return Status( | |
52 "The \"extractable\" property of the JWK dictionary is " | |
53 "inconsistent what that specified by the Web Crypto call"); | |
54 } | |
55 | |
56 Status Status::ErrorJwkUnrecognizedAlgorithm() { | |
57 return Status("The JWK \"alg\" property was not recognized"); | |
58 } | |
59 | |
60 Status Status::ErrorJwkAlgorithmInconsistent() { | |
61 return Status( | |
62 "The JWK \"alg\" property was inconsistent with that specified " | |
63 "by the Web Crypto call"); | |
64 } | |
65 | |
66 Status Status::ErrorJwkAlgorithmMissing() { | |
67 return Status( | |
68 "The JWK optional \"alg\" property is missing or not a string, " | |
69 "and one wasn't specified by the Web Crypto call"); | |
70 } | |
71 | |
72 Status Status::ErrorJwkUnrecognizedUsage() { | |
73 return Status("The JWK \"use\" property could not be parsed"); | |
74 } | |
75 | |
76 Status Status::ErrorJwkUsageInconsistent() { | |
77 return Status( | |
78 "The JWK \"use\" property was inconsistent with that specified " | |
79 "by the Web Crypto call. The JWK usage must be a superset of " | |
80 "those requested"); | |
81 } | |
82 | |
83 Status Status::ErrorJwkRsaPrivateKeyUnsupported() { | |
84 return Status( | |
85 "JWK RSA key contained \"d\" property: Private key import is " | |
86 "not yet supported"); | |
87 } | |
88 | |
89 Status Status::ErrorJwkUnrecognizedKty() { | |
90 return Status("The JWK \"kty\" property was unrecognized"); | |
91 } | |
92 | |
93 Status Status::ErrorJwkIncorrectKeyLength() { | |
94 return Status( | |
95 "The JWK \"k\" property did not include the right length " | |
96 "of key data for the given algorithm."); | |
97 } | |
98 | |
99 Status Status::ErrorImportEmptyKeyData() { | |
100 return Status("No key data was provided"); | |
101 } | |
102 | |
103 Status Status::ErrorUnexpectedKeyType() { | |
104 return Status("The key is not of the expected type"); | |
105 } | |
106 | |
107 Status Status::ErrorIncorrectSizeAesCbcIv() { | |
108 return Status("The \"iv\" has an unexpected length -- must be 16 bytes"); | |
109 } | |
110 | |
111 Status Status::ErrorDataTooLarge() { | |
112 return Status("The provided data is too large"); | |
113 } | |
114 | |
115 Status Status::ErrorUnsupported() { | |
116 return Status("The requested operation is unsupported"); | |
117 } | |
118 | |
119 Status Status::ErrorUnexpected() { | |
120 return Status("Something unexpected happened..."); | |
121 } | |
122 | |
123 Status Status::ErrorInvalidAesGcmTagLength() { | |
124 return Status( | |
125 "The tag length is invalid: Must be 32, 64, 96, 104, 112, 120, or 128 " | |
126 "bits"); | |
127 } | |
128 | |
129 Status Status::ErrorGenerateKeyPublicExponent() { | |
130 return Status("The \"publicExponent\" is either empty, zero, or too large"); | |
131 } | |
132 | |
133 Status Status::ErrorMissingAlgorithmImportRawKey() { | |
134 return Status( | |
135 "The key's algorithm must be specified when importing " | |
136 "raw-formatted key."); | |
137 } | |
138 | |
139 Status Status::ErrorImportRsaEmptyModulus() { | |
140 return Status("The modulus is empty"); | |
141 } | |
142 | |
143 Status Status::ErrorGenerateRsaZeroModulus() { | |
144 return Status("The modulus bit length cannot be zero"); | |
145 } | |
146 | |
147 Status Status::ErrorImportRsaEmptyExponent() { | |
148 return Status("No bytes for the exponent were provided"); | |
149 } | |
150 | |
151 Status Status::ErrorKeyNotExtractable() { | |
152 return Status("They key is not extractable"); | |
153 } | |
154 | |
155 Status Status::ErrorGenerateKeyLength() { | |
156 return Status( | |
157 "Invalid key length: it is either zero or not a multiple of 8 " | |
158 "bits"); | |
159 } | |
160 | |
161 Status::Status(const std::string& error_details_utf8) | |
162 : type_(TYPE_ERROR), error_details_(error_details_utf8) {} | |
163 | |
164 Status::Status(Type type) : type_(type) {} | |
165 | |
166 const uint8* Uint8VectorStart(const std::vector<uint8>& data) { | |
167 if (data.empty()) | |
168 return NULL; | |
169 return &data[0]; | |
170 } | |
171 | |
172 void ShrinkBuffer(blink::WebArrayBuffer* buffer, unsigned int new_size) { | |
173 DCHECK_LE(new_size, buffer->byteLength()); | |
174 | |
175 if (new_size == buffer->byteLength()) | |
176 return; | |
177 | |
178 blink::WebArrayBuffer new_buffer = blink::WebArrayBuffer::create(new_size, 1); | |
179 DCHECK(!new_buffer.isNull()); | |
180 memcpy(new_buffer.data(), buffer->data(), new_size); | |
181 *buffer = new_buffer; | |
182 } | |
183 | |
184 blink::WebArrayBuffer CreateArrayBuffer(const uint8* data, | |
185 unsigned int data_size) { | |
186 blink::WebArrayBuffer buffer = blink::WebArrayBuffer::create(data_size, 1); | |
187 DCHECK(!buffer.isNull()); | |
188 if (data_size) // data_size == 0 might mean the data pointer is invalid | |
189 memcpy(buffer.data(), data, data_size); | |
190 return buffer; | |
191 } | |
192 | |
193 // This function decodes unpadded 'base64url' encoded data, as described in | |
194 // RFC4648 (http://www.ietf.org/rfc/rfc4648.txt) Section 5. To do this, first | |
195 // change the incoming data to 'base64' encoding by applying the appropriate | |
196 // transformation including adding padding if required, and then call a base64 | |
197 // decoder. | |
198 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) { | |
199 std::string base64EncodedText(input); | |
200 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '-', '+'); | |
201 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '_', '/'); | |
202 base64EncodedText.append((4 - base64EncodedText.size() % 4) % 4, '='); | |
203 return base::Base64Decode(base64EncodedText, output); | |
204 } | |
205 | |
206 bool IsHashAlgorithm(blink::WebCryptoAlgorithmId alg_id) { | |
207 return alg_id == blink::WebCryptoAlgorithmIdSha1 || | |
208 alg_id == blink::WebCryptoAlgorithmIdSha224 || | |
209 alg_id == blink::WebCryptoAlgorithmIdSha256 || | |
210 alg_id == blink::WebCryptoAlgorithmIdSha384 || | |
211 alg_id == blink::WebCryptoAlgorithmIdSha512; | |
212 } | |
213 | |
214 blink::WebCryptoAlgorithm GetInnerHashAlgorithm( | |
215 const blink::WebCryptoAlgorithm& algorithm) { | |
216 DCHECK(!algorithm.isNull()); | |
217 switch (algorithm.paramsType()) { | |
218 case blink::WebCryptoAlgorithmParamsTypeHmacImportParams: | |
219 return algorithm.hmacImportParams()->hash(); | |
220 case blink::WebCryptoAlgorithmParamsTypeHmacKeyGenParams: | |
221 return algorithm.hmacKeyGenParams()->hash(); | |
222 case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams: | |
223 return algorithm.rsaHashedImportParams()->hash(); | |
224 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams: | |
225 return algorithm.rsaHashedKeyGenParams()->hash(); | |
226 default: | |
227 return blink::WebCryptoAlgorithm::createNull(); | |
228 } | |
229 } | |
230 | |
231 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) { | |
232 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL); | |
233 } | |
234 | |
235 blink::WebCryptoAlgorithm CreateHmacImportAlgorithm( | |
236 blink::WebCryptoAlgorithmId hash_id) { | |
237 DCHECK(IsHashAlgorithm(hash_id)); | |
238 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
239 blink::WebCryptoAlgorithmIdHmac, | |
240 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id))); | |
241 } | |
242 | |
243 blink::WebCryptoAlgorithm CreateRsaSsaImportAlgorithm( | |
244 blink::WebCryptoAlgorithmId hash_id) { | |
245 DCHECK(IsHashAlgorithm(hash_id)); | |
246 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
247 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5, | |
248 new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id))); | |
249 } | |
250 | |
251 blink::WebCryptoAlgorithm CreateRsaOaepImportAlgorithm( | |
252 blink::WebCryptoAlgorithmId hash_id) { | |
253 DCHECK(IsHashAlgorithm(hash_id)); | |
254 return blink::WebCryptoAlgorithm::adoptParamsAndCreate( | |
255 blink::WebCryptoAlgorithmIdRsaOaep, | |
256 new blink::WebCryptoRsaHashedImportParams( | |
257 CreateAlgorithm(hash_id))); | |
258 } | |
259 | |
260 | |
261 unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id) { | |
262 switch (hash_id) { | |
263 case blink::WebCryptoAlgorithmIdSha1: | |
264 case blink::WebCryptoAlgorithmIdSha224: | |
265 case blink::WebCryptoAlgorithmIdSha256: | |
266 return 64; | |
267 case blink::WebCryptoAlgorithmIdSha384: | |
268 case blink::WebCryptoAlgorithmIdSha512: | |
269 return 128; | |
270 default: | |
271 NOTREACHED(); | |
272 return 0; | |
273 } | |
274 } | |
275 | |
276 bool CreateSecretKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm, | |
277 unsigned keylen_bytes, | |
278 blink::WebCryptoKeyAlgorithm* key_algorithm) { | |
279 switch (algorithm.id()) { | |
280 case blink::WebCryptoAlgorithmIdHmac: { | |
281 blink::WebCryptoAlgorithm hash = GetInnerHashAlgorithm(algorithm); | |
282 if (hash.isNull()) | |
283 return false; | |
284 *key_algorithm = blink::WebCryptoKeyAlgorithm::adoptParamsAndCreate( | |
285 algorithm.id(), | |
286 new blink::WebCryptoHmacKeyAlgorithmParams(hash)); | |
287 return true; | |
288 } | |
289 case blink::WebCryptoAlgorithmIdAesKw: | |
290 case blink::WebCryptoAlgorithmIdAesCbc: | |
291 case blink::WebCryptoAlgorithmIdAesCtr: | |
292 case blink::WebCryptoAlgorithmIdAesGcm: | |
293 *key_algorithm = blink::WebCryptoKeyAlgorithm::adoptParamsAndCreate( | |
294 algorithm.id(), | |
295 new blink::WebCryptoAesKeyAlgorithmParams(keylen_bytes * 8)); | |
296 return true; | |
297 default: | |
298 return false; | |
299 } | |
300 } | |
301 | |
302 } // namespace webcrypto | |
303 | |
304 } // namespace content | |
OLD | NEW |