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 "content/child/webcrypto/webcrypto_util.h"
7 #include "base/base64.h"
8 #include "base/logging.h"
9 #include "base/strings/stringprintf.h"
10 #include "content/child/webcrypto/status.h"
11 #include "third_party/WebKit/public/platform/WebCryptoAlgorithm.h"
12 #include "third_party/WebKit/public/platform/WebCryptoAlgorithmParams.h"
13 #include "third_party/WebKit/public/platform/WebCryptoKeyAlgorithm.h"
19 const uint8* Uint8VectorStart(const std::vector<uint8>& data) {
25 void ShrinkBuffer(blink::WebArrayBuffer* buffer, unsigned int new_size) {
26 DCHECK_LE(new_size, buffer->byteLength());
28 if (new_size == buffer->byteLength())
31 blink::WebArrayBuffer new_buffer = blink::WebArrayBuffer::create(new_size, 1);
32 DCHECK(!new_buffer.isNull());
33 memcpy(new_buffer.data(), buffer->data(), new_size);
37 blink::WebArrayBuffer CreateArrayBuffer(const uint8* data,
38 unsigned int data_size) {
39 blink::WebArrayBuffer buffer = blink::WebArrayBuffer::create(data_size, 1);
40 DCHECK(!buffer.isNull());
41 if (data_size) // data_size == 0 might mean the data pointer is invalid
42 memcpy(buffer.data(), data, data_size);
46 // This function decodes unpadded 'base64url' encoded data, as described in
47 // RFC4648 (http://www.ietf.org/rfc/rfc4648.txt) Section 5. To do this, first
48 // change the incoming data to 'base64' encoding by applying the appropriate
49 // transformation including adding padding if required, and then call a base64
51 bool Base64DecodeUrlSafe(const std::string& input, std::string* output) {
52 std::string base64EncodedText(input);
53 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '-', '+');
54 std::replace(base64EncodedText.begin(), base64EncodedText.end(), '_', '/');
55 base64EncodedText.append((4 - base64EncodedText.size() % 4) % 4, '=');
56 return base::Base64Decode(base64EncodedText, output);
59 // Returns an unpadded 'base64url' encoding of the input data, using the
60 // inverse of the process above.
61 std::string Base64EncodeUrlSafe(const base::StringPiece& input) {
63 base::Base64Encode(input, &output);
64 std::replace(output.begin(), output.end(), '+', '-');
65 std::replace(output.begin(), output.end(), '/', '_');
66 output.erase(std::remove(output.begin(), output.end(), '='), output.end());
70 std::string Base64EncodeUrlSafe(const std::vector<uint8>& input) {
71 const base::StringPiece string_piece(
72 reinterpret_cast<const char*>(Uint8VectorStart(input)), input.size());
73 return Base64EncodeUrlSafe(string_piece);
76 struct JwkToWebCryptoUsage {
77 const char* const jwk_key_op;
78 const blink::WebCryptoKeyUsage webcrypto_usage;
81 const JwkToWebCryptoUsage kJwkWebCryptoUsageMap[] = {
82 {"encrypt", blink::WebCryptoKeyUsageEncrypt},
83 {"decrypt", blink::WebCryptoKeyUsageDecrypt},
84 {"deriveKey", blink::WebCryptoKeyUsageDeriveKey},
85 // TODO(padolph): Add 'deriveBits' once supported by Blink.
86 {"sign", blink::WebCryptoKeyUsageSign},
87 {"unwrapKey", blink::WebCryptoKeyUsageUnwrapKey},
88 {"verify", blink::WebCryptoKeyUsageVerify},
89 {"wrapKey", blink::WebCryptoKeyUsageWrapKey}};
91 // Modifies the input usage_mask by according to the key_op value.
92 bool JwkKeyOpToWebCryptoUsage(const std::string& key_op,
93 blink::WebCryptoKeyUsageMask* usage_mask) {
94 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) {
95 if (kJwkWebCryptoUsageMap[i].jwk_key_op == key_op) {
96 *usage_mask |= kJwkWebCryptoUsageMap[i].webcrypto_usage;
103 // Composes a Web Crypto usage mask from an array of JWK key_ops values.
104 Status GetWebCryptoUsagesFromJwkKeyOps(
105 const base::ListValue* jwk_key_ops_value,
106 blink::WebCryptoKeyUsageMask* usage_mask) {
108 for (size_t i = 0; i < jwk_key_ops_value->GetSize(); ++i) {
110 if (!jwk_key_ops_value->GetString(i, &key_op)) {
111 return Status::ErrorJwkPropertyWrongType(
112 base::StringPrintf("key_ops[%d]", static_cast<int>(i)), "string");
114 if (!JwkKeyOpToWebCryptoUsage(key_op, usage_mask))
115 return Status::ErrorJwkUnrecognizedKeyop();
117 return Status::Success();
120 // Composes a JWK key_ops List from a Web Crypto usage mask.
121 // Note: Caller must assume ownership of returned instance.
122 base::ListValue* CreateJwkKeyOpsFromWebCryptoUsages(
123 blink::WebCryptoKeyUsageMask usage_mask) {
124 base::ListValue* jwk_key_ops = new base::ListValue();
125 for (size_t i = 0; i < arraysize(kJwkWebCryptoUsageMap); ++i) {
126 if (usage_mask & kJwkWebCryptoUsageMap[i].webcrypto_usage)
127 jwk_key_ops->AppendString(kJwkWebCryptoUsageMap[i].jwk_key_op);
132 bool IsHashAlgorithm(blink::WebCryptoAlgorithmId alg_id) {
133 return alg_id == blink::WebCryptoAlgorithmIdSha1 ||
134 alg_id == blink::WebCryptoAlgorithmIdSha256 ||
135 alg_id == blink::WebCryptoAlgorithmIdSha384 ||
136 alg_id == blink::WebCryptoAlgorithmIdSha512;
139 blink::WebCryptoAlgorithm GetInnerHashAlgorithm(
140 const blink::WebCryptoAlgorithm& algorithm) {
141 DCHECK(!algorithm.isNull());
142 switch (algorithm.paramsType()) {
143 case blink::WebCryptoAlgorithmParamsTypeHmacImportParams:
144 return algorithm.hmacImportParams()->hash();
145 case blink::WebCryptoAlgorithmParamsTypeHmacKeyGenParams:
146 return algorithm.hmacKeyGenParams()->hash();
147 case blink::WebCryptoAlgorithmParamsTypeRsaHashedImportParams:
148 return algorithm.rsaHashedImportParams()->hash();
149 case blink::WebCryptoAlgorithmParamsTypeRsaHashedKeyGenParams:
150 return algorithm.rsaHashedKeyGenParams()->hash();
152 return blink::WebCryptoAlgorithm::createNull();
156 blink::WebCryptoAlgorithm CreateAlgorithm(blink::WebCryptoAlgorithmId id) {
157 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(id, NULL);
160 blink::WebCryptoAlgorithm CreateHmacImportAlgorithm(
161 blink::WebCryptoAlgorithmId hash_id) {
162 DCHECK(IsHashAlgorithm(hash_id));
163 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
164 blink::WebCryptoAlgorithmIdHmac,
165 new blink::WebCryptoHmacImportParams(CreateAlgorithm(hash_id)));
168 blink::WebCryptoAlgorithm CreateRsaHashedImportAlgorithm(
169 blink::WebCryptoAlgorithmId id,
170 blink::WebCryptoAlgorithmId hash_id) {
171 DCHECK(IsHashAlgorithm(hash_id));
172 DCHECK(id == blink::WebCryptoAlgorithmIdRsaSsaPkcs1v1_5 ||
173 id == blink::WebCryptoAlgorithmIdRsaOaep);
174 return blink::WebCryptoAlgorithm::adoptParamsAndCreate(
175 id, new blink::WebCryptoRsaHashedImportParams(CreateAlgorithm(hash_id)));
178 bool CreateSecretKeyAlgorithm(const blink::WebCryptoAlgorithm& algorithm,
179 unsigned int keylen_bytes,
180 blink::WebCryptoKeyAlgorithm* key_algorithm) {
181 switch (algorithm.id()) {
182 case blink::WebCryptoAlgorithmIdHmac: {
183 blink::WebCryptoAlgorithm hash = GetInnerHashAlgorithm(algorithm);
186 if (keylen_bytes > UINT_MAX / 8)
189 blink::WebCryptoKeyAlgorithm::createHmac(hash.id(), keylen_bytes * 8);
192 case blink::WebCryptoAlgorithmIdAesKw:
193 case blink::WebCryptoAlgorithmIdAesCbc:
194 case blink::WebCryptoAlgorithmIdAesCtr:
195 case blink::WebCryptoAlgorithmIdAesGcm:
196 *key_algorithm = blink::WebCryptoKeyAlgorithm::createAes(
197 algorithm.id(), keylen_bytes * 8);
204 } // namespace webcrypto
206 } // namespace content