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 "components/webcrypto/algorithms/aes.h"
6
7 #include <stddef.h>
8
9 #include "base/logging.h"
10 #include "components/webcrypto/algorithms/secret_key_util.h"
11 #include "components/webcrypto/algorithms/util.h"
12 #include "components/webcrypto/blink_key_handle.h"
13 #include "components/webcrypto/crypto_data.h"
14 #include "components/webcrypto/jwk.h"
15 #include "components/webcrypto/status.h"
16 #include "third_party/blink/public/platform/web_crypto_algorithm_params.h"
17 #include "third_party/blink/public/platform/web_crypto_key_algorithm.h"
18
19 namespace webcrypto {
20
21 namespace {
22
23 // Creates an AES algorithm name for the given key size (in bytes). For
24 // instance "A128CBC" is the result of suffix="CBC", keylen_bytes=16.
MakeJwkAesAlgorithmName(const std::string & suffix,size_t keylen_bytes)25 std::string MakeJwkAesAlgorithmName(const std::string& suffix,
26 size_t keylen_bytes) {
27 if (keylen_bytes == 16)
28 return std::string("A128") + suffix;
29 if (keylen_bytes == 24)
30 return std::string("A192") + suffix;
31 if (keylen_bytes == 32)
32 return std::string("A256") + suffix;
33 return std::string();
34 }
35
36 // Synthesizes an import algorithm given a key algorithm, so that
37 // deserialization can re-use the ImportKey*() methods.
SynthesizeImportAlgorithmForClone(const blink::WebCryptoKeyAlgorithm & algorithm)38 blink::WebCryptoAlgorithm SynthesizeImportAlgorithmForClone(
39 const blink::WebCryptoKeyAlgorithm& algorithm) {
40 return blink::WebCryptoAlgorithm::AdoptParamsAndCreate(algorithm.Id(),
41 nullptr);
42 }
43
44 } // namespace
45
AesAlgorithm(blink::WebCryptoKeyUsageMask all_key_usages,const std::string & jwk_suffix)46 AesAlgorithm::AesAlgorithm(blink::WebCryptoKeyUsageMask all_key_usages,
47 const std::string& jwk_suffix)
48 : all_key_usages_(all_key_usages), jwk_suffix_(jwk_suffix) {
49 }
50
AesAlgorithm(const std::string & jwk_suffix)51 AesAlgorithm::AesAlgorithm(const std::string& jwk_suffix)
52 : all_key_usages_(blink::kWebCryptoKeyUsageEncrypt |
53 blink::kWebCryptoKeyUsageDecrypt |
54 blink::kWebCryptoKeyUsageWrapKey |
55 blink::kWebCryptoKeyUsageUnwrapKey),
56 jwk_suffix_(jwk_suffix) {}
57
GenerateKey(const blink::WebCryptoAlgorithm & algorithm,bool extractable,blink::WebCryptoKeyUsageMask usages,GenerateKeyResult * result) const58 Status AesAlgorithm::GenerateKey(const blink::WebCryptoAlgorithm& algorithm,
59 bool extractable,
60 blink::WebCryptoKeyUsageMask usages,
61 GenerateKeyResult* result) const {
62 Status status = CheckKeyCreationUsages(all_key_usages_, usages);
63 if (status.IsError())
64 return status;
65
66 uint16_t keylen_bits = algorithm.AesKeyGenParams()->LengthBits();
67
68 // 192-bit AES is intentionally unsupported (http://crbug.com/533699).
69 if (keylen_bits == 192)
70 return Status::ErrorAes192BitUnsupported();
71
72 if (keylen_bits != 128 && keylen_bits != 256)
73 return Status::ErrorGenerateAesKeyLength();
74
75 return GenerateWebCryptoSecretKey(
76 blink::WebCryptoKeyAlgorithm::CreateAes(algorithm.Id(), keylen_bits),
77 extractable, usages, keylen_bits, result);
78 }
79
ImportKey(blink::WebCryptoKeyFormat format,const CryptoData & key_data,const blink::WebCryptoAlgorithm & algorithm,bool extractable,blink::WebCryptoKeyUsageMask usages,blink::WebCryptoKey * key) const80 Status AesAlgorithm::ImportKey(blink::WebCryptoKeyFormat format,
81 const CryptoData& key_data,
82 const blink::WebCryptoAlgorithm& algorithm,
83 bool extractable,
84 blink::WebCryptoKeyUsageMask usages,
85 blink::WebCryptoKey* key) const {
86 switch (format) {
87 case blink::kWebCryptoKeyFormatRaw:
88 return ImportKeyRaw(key_data, algorithm, extractable, usages, key);
89 case blink::kWebCryptoKeyFormatJwk:
90 return ImportKeyJwk(key_data, algorithm, extractable, usages, key);
91 default:
92 return Status::ErrorUnsupportedImportKeyFormat();
93 }
94 }
95
ExportKey(blink::WebCryptoKeyFormat format,const blink::WebCryptoKey & key,std::vector<uint8_t> * buffer) const96 Status AesAlgorithm::ExportKey(blink::WebCryptoKeyFormat format,
97 const blink::WebCryptoKey& key,
98 std::vector<uint8_t>* buffer) const {
99 switch (format) {
100 case blink::kWebCryptoKeyFormatRaw:
101 return ExportKeyRaw(key, buffer);
102 case blink::kWebCryptoKeyFormatJwk:
103 return ExportKeyJwk(key, buffer);
104 default:
105 return Status::ErrorUnsupportedExportKeyFormat();
106 }
107 }
108
ImportKeyRaw(const CryptoData & key_data,const blink::WebCryptoAlgorithm & algorithm,bool extractable,blink::WebCryptoKeyUsageMask usages,blink::WebCryptoKey * key) const109 Status AesAlgorithm::ImportKeyRaw(const CryptoData& key_data,
110 const blink::WebCryptoAlgorithm& algorithm,
111 bool extractable,
112 blink::WebCryptoKeyUsageMask usages,
113 blink::WebCryptoKey* key) const {
114 Status status = CheckKeyCreationUsages(all_key_usages_, usages);
115 if (status.IsError())
116 return status;
117
118 const unsigned int keylen_bytes = key_data.byte_length();
119
120 // 192-bit AES is intentionally unsupported (http://crbug.com/533699).
121 if (keylen_bytes == 24)
122 return Status::ErrorAes192BitUnsupported();
123
124 if (keylen_bytes != 16 && keylen_bytes != 32)
125 return Status::ErrorImportAesKeyLength();
126
127 // No possibility of overflow.
128 unsigned int keylen_bits = keylen_bytes * 8;
129
130 return CreateWebCryptoSecretKey(
131 key_data,
132 blink::WebCryptoKeyAlgorithm::CreateAes(algorithm.Id(), keylen_bits),
133 extractable, usages, key);
134 }
135
ImportKeyJwk(const CryptoData & key_data,const blink::WebCryptoAlgorithm & algorithm,bool extractable,blink::WebCryptoKeyUsageMask usages,blink::WebCryptoKey * key) const136 Status AesAlgorithm::ImportKeyJwk(const CryptoData& key_data,
137 const blink::WebCryptoAlgorithm& algorithm,
138 bool extractable,
139 blink::WebCryptoKeyUsageMask usages,
140 blink::WebCryptoKey* key) const {
141 Status status = CheckKeyCreationUsages(all_key_usages_, usages);
142 if (status.IsError())
143 return status;
144
145 std::vector<uint8_t> raw_data;
146 JwkReader jwk;
147 status = ReadSecretKeyNoExpectedAlgJwk(key_data, extractable, usages,
148 &raw_data, &jwk);
149 if (status.IsError())
150 return status;
151
152 bool has_jwk_alg;
153 std::string jwk_alg;
154 status = jwk.GetAlg(&jwk_alg, &has_jwk_alg);
155 if (status.IsError())
156 return status;
157
158 if (has_jwk_alg) {
159 std::string expected_algorithm_name =
160 MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size());
161
162 if (jwk_alg != expected_algorithm_name) {
163 // Give a different error message if the key length was wrong.
164 if (jwk_alg == MakeJwkAesAlgorithmName(jwk_suffix_, 16) ||
165 jwk_alg == MakeJwkAesAlgorithmName(jwk_suffix_, 24) ||
166 jwk_alg == MakeJwkAesAlgorithmName(jwk_suffix_, 32)) {
167 return Status::ErrorJwkIncorrectKeyLength();
168 }
169 return Status::ErrorJwkAlgorithmInconsistent();
170 }
171 }
172
173 return ImportKeyRaw(CryptoData(raw_data), algorithm, extractable, usages,
174 key);
175 }
176
ExportKeyRaw(const blink::WebCryptoKey & key,std::vector<uint8_t> * buffer) const177 Status AesAlgorithm::ExportKeyRaw(const blink::WebCryptoKey& key,
178 std::vector<uint8_t>* buffer) const {
179 *buffer = GetSymmetricKeyData(key);
180 return Status::Success();
181 }
182
ExportKeyJwk(const blink::WebCryptoKey & key,std::vector<uint8_t> * buffer) const183 Status AesAlgorithm::ExportKeyJwk(const blink::WebCryptoKey& key,
184 std::vector<uint8_t>* buffer) const {
185 const std::vector<uint8_t>& raw_data = GetSymmetricKeyData(key);
186
187 WriteSecretKeyJwk(CryptoData(raw_data),
188 MakeJwkAesAlgorithmName(jwk_suffix_, raw_data.size()),
189 key.Extractable(), key.Usages(), buffer);
190
191 return Status::Success();
192 }
193
DeserializeKeyForClone(const blink::WebCryptoKeyAlgorithm & algorithm,blink::WebCryptoKeyType type,bool extractable,blink::WebCryptoKeyUsageMask usages,const CryptoData & key_data,blink::WebCryptoKey * key) const194 Status AesAlgorithm::DeserializeKeyForClone(
195 const blink::WebCryptoKeyAlgorithm& algorithm,
196 blink::WebCryptoKeyType type,
197 bool extractable,
198 blink::WebCryptoKeyUsageMask usages,
199 const CryptoData& key_data,
200 blink::WebCryptoKey* key) const {
201 if (algorithm.ParamsType() != blink::kWebCryptoKeyAlgorithmParamsTypeAes ||
202 type != blink::kWebCryptoKeyTypeSecret)
203 return Status::ErrorUnexpected();
204
205 return ImportKeyRaw(key_data, SynthesizeImportAlgorithmForClone(algorithm),
206 extractable, usages, key);
207 }
208
GetKeyLength(const blink::WebCryptoAlgorithm & key_length_algorithm,bool * has_length_bits,unsigned int * length_bits) const209 Status AesAlgorithm::GetKeyLength(
210 const blink::WebCryptoAlgorithm& key_length_algorithm,
211 bool* has_length_bits,
212 unsigned int* length_bits) const {
213 *has_length_bits = true;
214 *length_bits = key_length_algorithm.AesDerivedKeyParams()->LengthBits();
215
216 if (*length_bits == 128 || *length_bits == 256)
217 return Status::Success();
218
219 // 192-bit AES is intentionally unsupported (http://crbug.com/533699).
220 if (*length_bits == 192)
221 return Status::ErrorAes192BitUnsupported();
222
223 return Status::ErrorGetAesKeyLength();
224 }
225
226 } // namespace webcrypto
227