1/*
2 * Copyright (C) 2017 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "CryptoAlgorithmAES_CTR.h"
28
29#if ENABLE(WEB_CRYPTO)
30
31#include "CryptoAlgorithmAesCtrParams.h"
32#include "CryptoAlgorithmAesKeyParams.h"
33#include "CryptoKeyAES.h"
34#include <wtf/CrossThreadCopier.h>
35
36namespace WebCore {
37
38namespace CryptoAlgorithmAES_CTRInternal {
39static const char* const ALG128 = "A128CTR";
40static const char* const ALG192 = "A192CTR";
41static const char* const ALG256 = "A256CTR";
42static const size_t CounterSize = 16;
43}
44
45static inline bool usagesAreInvalidForCryptoAlgorithmAES_CTR(CryptoKeyUsageBitmap usages)
46{
47 return usages & (CryptoKeyUsageSign | CryptoKeyUsageVerify | CryptoKeyUsageDeriveKey | CryptoKeyUsageDeriveBits);
48}
49
50static bool parametersAreValid(const CryptoAlgorithmAesCtrParams& parameters)
51{
52 using namespace CryptoAlgorithmAES_CTRInternal;
53 if (parameters.counterVector().size() != CounterSize)
54 return false;
55 if (!parameters.length || parameters.length > 128)
56 return false;
57 return true;
58}
59
60Ref<CryptoAlgorithm> CryptoAlgorithmAES_CTR::create()
61{
62 return adoptRef(*new CryptoAlgorithmAES_CTR);
63}
64
65CryptoAlgorithmIdentifier CryptoAlgorithmAES_CTR::identifier() const
66{
67 return s_identifier;
68}
69
70void CryptoAlgorithmAES_CTR::encrypt(const CryptoAlgorithmParameters& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& plainText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
71{
72 auto& aesParameters = downcast<CryptoAlgorithmAesCtrParams>(parameters);
73 if (!parametersAreValid(aesParameters)) {
74 exceptionCallback(OperationError);
75 return;
76 }
77
78 dispatchOperationInWorkQueue(workQueue, context, WTFMove(callback), WTFMove(exceptionCallback),
79 [parameters = crossThreadCopy(aesParameters), key = WTFMove(key), plainText = WTFMove(plainText)] {
80 return platformEncrypt(parameters, downcast<CryptoKeyAES>(key.get()), plainText);
81 });
82}
83
84void CryptoAlgorithmAES_CTR::decrypt(const CryptoAlgorithmParameters& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& cipherText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
85{
86 auto& aesParameters = downcast<CryptoAlgorithmAesCtrParams>(parameters);
87 if (!parametersAreValid(aesParameters)) {
88 exceptionCallback(OperationError);
89 return;
90 }
91
92 dispatchOperationInWorkQueue(workQueue, context, WTFMove(callback), WTFMove(exceptionCallback),
93 [parameters = crossThreadCopy(aesParameters), key = WTFMove(key), cipherText = WTFMove(cipherText)] {
94 return platformDecrypt(parameters, downcast<CryptoKeyAES>(key.get()), cipherText);
95 });
96}
97
98void CryptoAlgorithmAES_CTR::generateKey(const CryptoAlgorithmParameters& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyOrKeyPairCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext&)
99{
100 const auto& aesParameters = downcast<CryptoAlgorithmAesKeyParams>(parameters);
101
102 if (usagesAreInvalidForCryptoAlgorithmAES_CTR(usages)) {
103 exceptionCallback(SyntaxError);
104 return;
105 }
106
107 auto result = CryptoKeyAES::generate(CryptoAlgorithmIdentifier::AES_CTR, aesParameters.length, extractable, usages);
108 if (!result) {
109 exceptionCallback(OperationError);
110 return;
111 }
112
113 callback(WTFMove(result));
114}
115
116void CryptoAlgorithmAES_CTR::importKey(CryptoKeyFormat format, KeyData&& data, const CryptoAlgorithmParameters& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyCallback&& callback, ExceptionCallback&& exceptionCallback)
117{
118 using namespace CryptoAlgorithmAES_CTRInternal;
119
120 if (usagesAreInvalidForCryptoAlgorithmAES_CTR(usages)) {
121 exceptionCallback(SyntaxError);
122 return;
123 }
124
125 RefPtr<CryptoKeyAES> result;
126 switch (format) {
127 case CryptoKeyFormat::Raw:
128 result = CryptoKeyAES::importRaw(parameters.identifier, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages);
129 break;
130 case CryptoKeyFormat::Jwk: {
131 auto checkAlgCallback = [](size_t length, const String& alg) -> bool {
132 switch (length) {
133 case CryptoKeyAES::s_length128:
134 return alg.isNull() || alg == ALG128;
135 case CryptoKeyAES::s_length192:
136 return alg.isNull() || alg == ALG192;
137 case CryptoKeyAES::s_length256:
138 return alg.isNull() || alg == ALG256;
139 }
140 return false;
141 };
142 result = CryptoKeyAES::importJwk(parameters.identifier, WTFMove(WTF::get<JsonWebKey>(data)), extractable, usages, WTFMove(checkAlgCallback));
143 break;
144 }
145 default:
146 exceptionCallback(NotSupportedError);
147 return;
148 }
149 if (!result) {
150 exceptionCallback(DataError);
151 return;
152 }
153
154 callback(*result);
155}
156
157void CryptoAlgorithmAES_CTR::exportKey(CryptoKeyFormat format, Ref<CryptoKey>&& key, KeyDataCallback&& callback, ExceptionCallback&& exceptionCallback)
158{
159 using namespace CryptoAlgorithmAES_CTRInternal;
160 const auto& aesKey = downcast<CryptoKeyAES>(key.get());
161
162 if (aesKey.key().isEmpty()) {
163 exceptionCallback(OperationError);
164 return;
165 }
166
167 KeyData result;
168 switch (format) {
169 case CryptoKeyFormat::Raw:
170 result = Vector<uint8_t>(aesKey.key());
171 break;
172 case CryptoKeyFormat::Jwk: {
173 JsonWebKey jwk = aesKey.exportJwk();
174 switch (aesKey.key().size() * 8) {
175 case CryptoKeyAES::s_length128:
176 jwk.alg = String(ALG128);
177 break;
178 case CryptoKeyAES::s_length192:
179 jwk.alg = String(ALG192);
180 break;
181 case CryptoKeyAES::s_length256:
182 jwk.alg = String(ALG256);
183 break;
184 default:
185 ASSERT_NOT_REACHED();
186 }
187 result = WTFMove(jwk);
188 break;
189 }
190 default:
191 exceptionCallback(NotSupportedError);
192 return;
193 }
194
195 callback(format, WTFMove(result));
196}
197
198ExceptionOr<size_t> CryptoAlgorithmAES_CTR::getKeyLength(const CryptoAlgorithmParameters& parameters)
199{
200 return CryptoKeyAES::getKeyLength(parameters);
201}
202
203}
204
205#endif // ENABLE(WEB_CRYPTO)
206