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.
5 #include "content/renderer/webcrypto/webcrypto_util.h"
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"
16 bool Status::IsError() const {
17 return type_ == TYPE_ERROR;
20 bool Status::IsSuccess() const {
21 return type_ == TYPE_SUCCESS;
24 bool Status::HasErrorDetails() const {
25 return !error_details_.empty();
28 std::string Status::ToString() const {
29 return IsSuccess() ? "Success" : error_details_;
32 Status Status::Success() {
33 return Status(TYPE_SUCCESS);
36 Status Status::Error() {
37 return Status(TYPE_ERROR);
40 Status Status::ErrorJwkNotDictionary() {
41 return Status("JWK input could not be parsed to a JSON dictionary");
44 Status Status::ErrorJwkPropertyMissing(const std::string& property) {
45 return Status("The required JWK property \"" + property + "\" was missing");
48 Status Status::ErrorJwkPropertyWrongType(const std::string& property,
49 const std::string& expected_type) {
50 return Status("The JWK property \"" + property + "\" must be a " +
54 Status Status::ErrorJwkBase64Decode(const std::string& property) {
55 return Status("The JWK property \"" + property +
56 "\" could not be base64 decoded");
59 Status Status::ErrorJwkExtractableInconsistent() {
60 return Status("The \"extractable\" property of the JWK dictionary is "
61 "inconsistent what that specified by the Web Crypto call");
64 Status Status::ErrorJwkUnrecognizedAlgorithm() {
65 return Status("The JWK \"alg\" property was not recognized");
68 Status Status::ErrorJwkAlgorithmInconsistent() {
69 return Status("The JWK \"alg\" property was inconsistent with that specified "
70 "by the Web Crypto call");
73 Status Status::ErrorJwkAlgorithmMissing() {
74 return Status("The JWK optional \"alg\" property is missing or not a string, "
75 "and one wasn't specified by the Web Crypto call");
78 Status Status::ErrorJwkUnrecognizedUsage() {
79 return Status("The JWK \"use\" property could not be parsed");
82 Status Status::ErrorJwkUsageInconsistent() {
83 return Status("The JWK \"use\" property was inconsistent with that specified "
84 "by the Web Crypto call. The JWK usage must be a superset of "
88 Status Status::ErrorJwkRsaPrivateKeyUnsupported() {
89 return Status("JWK RSA key contained \"d\" property: Private key import is "
93 Status Status::ErrorJwkUnrecognizedKty() {
94 return Status("The JWK \"kty\" property was unrecognized");
97 Status Status::ErrorJwkIncorrectKeyLength() {
98 return Status("The JWK \"k\" property did not include the right length "
99 "of key data for the given algorithm.");
102 Status Status::ErrorImportEmptyKeyData() {
103 return Status("No key data was provided");
106 Status Status::ErrorUnexpectedKeyType() {
107 return Status("The key is not of the expected type");
110 Status Status::ErrorIncorrectSizeAesCbcIv() {
111 return Status("The \"iv\" has an unexpected length -- must be 16 bytes");
114 Status Status::ErrorDataTooLarge() {
115 return Status("The provided data is too large");
118 Status Status::ErrorUnsupported() {
119 return Status("The requested operation is unsupported");
122 Status Status::ErrorUnexpected() {
123 return Status("Something unexpected happened...");
126 Status Status::ErrorInvalidAesGcmTagLength() {
127 return Status("The tag length is invalid: either too large or not a multiple "
131 Status Status::ErrorGenerateKeyPublicExponent() {
132 return Status("The \"publicExponent\" is either empty, zero, or too large");
135 Status Status::ErrorMissingAlgorithmImportRawKey() {
136 return Status("The key's algorithm must be specified when importing "
137 "raw-formatted key.");
140 Status Status::ErrorImportRsaEmptyModulus() {
141 return Status("The modulus is empty");
144 Status Status::ErrorGenerateRsaZeroModulus() {
145 return Status("The modulus bit length cannot be zero");
148 Status Status::ErrorImportRsaEmptyExponent() {
149 return Status("No bytes for the exponent were provided");
152 Status Status::ErrorKeyNotExtractable() {
153 return Status("They key is not extractable");
156 Status Status::ErrorGenerateKeyLength() {
157 return Status("Invalid key length: it is either zero or not a multiple of 8 "
161 Status::Status(const std::string& error_details_utf8)
162 : type_(TYPE_ERROR), error_details_(error_details_utf8) {}
164 Status::Status(Type type) : type_(type) {}
166 const uint8* Uint8VectorStart(const std::vector<uint8>& data) {
172 void ShrinkBuffer(blink::WebArrayBuffer* buffer, unsigned int new_size) {
173 DCHECK_LE(new_size, buffer->byteLength());
175 if (new_size == buffer->byteLength())
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;
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);
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
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);
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;
214 blink::WebCryptoAlgorithm GetInnerHashAlgorithm(
215 const blink::WebCryptoAlgorithm& algorithm) {
216 DCHECK(!algorithm.isNull());
217 switch (algorithm.id()) {
218 case blink::WebCryptoAlgorithmIdHmac:
219 if (algorithm.hmacParams())
220 return algorithm.hmacParams()->hash();
221 else if (algorithm.hmacKeyParams())
222 return algorithm.hmacKeyParams()->hash();
224 case blink::WebCryptoAlgorithmIdRsaOaep:
225 if (algorithm.rsaOaepParams())
226 return algorithm.rsaOaepParams()->hash();
228 case blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
229 if (algorithm.rsaSsaParams())
230 return algorithm.rsaSsaParams()->hash();
235 return blink::WebCryptoAlgorithm::createNull();
238 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
239 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
242 blink::WebCryptoAlgorithm CreateHmacAlgorithmByHashId(
243 blink::WebCryptoAlgorithmId hash_id) {
244 DCHECK(IsHashAlgorithm(hash_id));
245 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
246 blink::WebCryptoAlgorithmIdHmac,
247 new blink::WebCryptoHmacParams(CreateAlgorithm(hash_id)));
250 blink::WebCryptoAlgorithm CreateHmacKeyGenAlgorithm(
251 blink::WebCryptoAlgorithmId hash_id,
252 unsigned int key_length_bytes) {
253 DCHECK(IsHashAlgorithm(hash_id));
254 // key_length_bytes == 0 means unspecified
255 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
256 blink::WebCryptoAlgorithmIdHmac,
257 new blink::WebCryptoHmacKeyParams(
258 CreateAlgorithm(hash_id), (key_length_bytes != 0), key_length_bytes));
261 blink::WebCryptoAlgorithm CreateRsaSsaAlgorithm(
262 blink::WebCryptoAlgorithmId hash_id) {
263 DCHECK(IsHashAlgorithm(hash_id));
264 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
265 blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5,
266 new blink::WebCryptoRsaSsaParams(CreateAlgorithm(hash_id)));
269 blink::WebCryptoAlgorithm CreateRsaOaepAlgorithm(
270 blink::WebCryptoAlgorithmId hash_id) {
271 DCHECK(IsHashAlgorithm(hash_id));
272 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
273 blink::WebCryptoAlgorithmIdRsaOaep,
274 new blink::WebCryptoRsaOaepParams(
275 CreateAlgorithm(hash_id), false, NULL, 0));
278 blink::WebCryptoAlgorithm CreateRsaKeyGenAlgorithm(
279 blink::WebCryptoAlgorithmId algorithm_id,
280 unsigned int modulus_length,
281 const std::vector<uint8>& public_exponent) {
282 DCHECK(algorithm_id == blink::WebCryptoAlgorithmIdRsaEsPkcs1v1_5 ||
283 algorithm_id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
284 algorithm_id == blink::WebCryptoAlgorithmIdRsaOaep);
285 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
287 new blink::WebCryptoRsaKeyGenParams(
289 webcrypto::Uint8VectorStart(public_exponent),
290 public_exponent.size()));
293 blink::WebCryptoAlgorithm CreateAesCbcAlgorithm(const std::vector<uint8>& iv) {
294 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
295 blink::WebCryptoAlgorithmIdAesCbc,
296 new blink::WebCryptoAesCbcParams(Uint8VectorStart(iv), iv.size()));
299 blink::WebCryptoAlgorithm CreateAesGcmAlgorithm(
300 const std::vector<uint8>& iv,
301 const std::vector<uint8>& additional_data,
302 uint8 tag_length_bytes) {
303 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
304 blink::WebCryptoAlgorithmIdAesCbc,
305 new blink::WebCryptoAesGcmParams(Uint8VectorStart(iv),
307 additional_data.size() != 0,
308 Uint8VectorStart(additional_data),
309 additional_data.size(),
310 tag_length_bytes != 0,
314 unsigned int ShaBlockSizeBytes(blink::WebCryptoAlgorithmId hash_id) {
316 case blink::WebCryptoAlgorithmIdSha1:
317 case blink::WebCryptoAlgorithmIdSha224:
318 case blink::WebCryptoAlgorithmIdSha256:
320 case blink::WebCryptoAlgorithmIdSha384:
321 case blink::WebCryptoAlgorithmIdSha512:
329 } // namespace webcrypto
331 } // namespace content