1/*
2 * Copyright (C) 2013 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_CBC.h"
28
29#if ENABLE(WEB_CRYPTO)
30
31#include "CryptoAlgorithmAesCbcCfbParams.h"
32#include "CryptoAlgorithmAesKeyParams.h"
33#include "CryptoKeyAES.h"
34#include <wtf/CrossThreadCopier.h>
35
36namespace WebCore {
37
38namespace CryptoAlgorithmAES_CBCInternal {
39static const char* const ALG128 = "A128CBC";
40static const char* const ALG192 = "A192CBC";
41static const char* const ALG256 = "A256CBC";
42static const size_t IVSIZE = 16;
43}
44
45static inline bool usagesAreInvalidForCryptoAlgorithmAES_CBC(CryptoKeyUsageBitmap usages)
46{
47 return usages & (CryptoKeyUsageSign | CryptoKeyUsageVerify | CryptoKeyUsageDeriveKey | CryptoKeyUsageDeriveBits);
48}
49
50Ref<CryptoAlgorithm> CryptoAlgorithmAES_CBC::create()
51{
52 return adoptRef(*new CryptoAlgorithmAES_CBC);
53}
54
55CryptoAlgorithmIdentifier CryptoAlgorithmAES_CBC::identifier() const
56{
57 return s_identifier;
58}
59
60void CryptoAlgorithmAES_CBC::encrypt(const CryptoAlgorithmParameters& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& plainText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
61{
62 using namespace CryptoAlgorithmAES_CBCInternal;
63
64 auto& aesParameters = downcast<CryptoAlgorithmAesCbcCfbParams>(parameters);
65 if (aesParameters.ivVector().size() != IVSIZE) {
66 exceptionCallback(OperationError);
67 return;
68 }
69
70 dispatchOperationInWorkQueue(workQueue, context, WTFMove(callback), WTFMove(exceptionCallback),
71 [parameters = crossThreadCopy(aesParameters), key = WTFMove(key), plainText = WTFMove(plainText)] {
72 return platformEncrypt(parameters, downcast<CryptoKeyAES>(key.get()), plainText);
73 });
74}
75
76void CryptoAlgorithmAES_CBC::decrypt(const CryptoAlgorithmParameters& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& cipherText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
77{
78 using namespace CryptoAlgorithmAES_CBCInternal;
79
80 auto& aesParameters = downcast<CryptoAlgorithmAesCbcCfbParams>(parameters);
81 if (aesParameters.ivVector().size() != IVSIZE) {
82 exceptionCallback(OperationError);
83 return;
84 }
85
86 dispatchOperationInWorkQueue(workQueue, context, WTFMove(callback), WTFMove(exceptionCallback),
87 [parameters = crossThreadCopy(aesParameters), key = WTFMove(key), cipherText = WTFMove(cipherText)] {
88 return platformDecrypt(parameters, downcast<CryptoKeyAES>(key.get()), cipherText);
89 });
90}
91
92void CryptoAlgorithmAES_CBC::generateKey(const CryptoAlgorithmParameters& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyOrKeyPairCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext&)
93{
94 const auto& aesParameters = downcast<CryptoAlgorithmAesKeyParams>(parameters);
95
96 if (usagesAreInvalidForCryptoAlgorithmAES_CBC(usages)) {
97 exceptionCallback(SyntaxError);
98 return;
99 }
100
101 auto result = CryptoKeyAES::generate(CryptoAlgorithmIdentifier::AES_CBC, aesParameters.length, extractable, usages);
102 if (!result) {
103 exceptionCallback(OperationError);
104 return;
105 }
106
107 callback(WTFMove(result));
108}
109
110void CryptoAlgorithmAES_CBC::importKey(CryptoKeyFormat format, KeyData&& data, const CryptoAlgorithmParameters& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyCallback&& callback, ExceptionCallback&& exceptionCallback)
111{
112 using namespace CryptoAlgorithmAES_CBCInternal;
113
114 if (usagesAreInvalidForCryptoAlgorithmAES_CBC(usages)) {
115 exceptionCallback(SyntaxError);
116 return;
117 }
118
119 RefPtr<CryptoKeyAES> result;
120 switch (format) {
121 case CryptoKeyFormat::Raw:
122 result = CryptoKeyAES::importRaw(parameters.identifier, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages);
123 break;
124 case CryptoKeyFormat::Jwk: {
125 auto checkAlgCallback = [](size_t length, const String& alg) -> bool {
126 switch (length) {
127 case CryptoKeyAES::s_length128:
128 return alg.isNull() || alg == ALG128;
129 case CryptoKeyAES::s_length192:
130 return alg.isNull() || alg == ALG192;
131 case CryptoKeyAES::s_length256:
132 return alg.isNull() || alg == ALG256;
133 }
134 return false;
135 };
136 result = CryptoKeyAES::importJwk(parameters.identifier, WTFMove(WTF::get<JsonWebKey>(data)), extractable, usages, WTFMove(checkAlgCallback));
137 break;
138 }
139 default:
140 exceptionCallback(NotSupportedError);
141 return;
142 }
143 if (!result) {
144 exceptionCallback(DataError);
145 return;
146 }
147
148 callback(*result);
149}
150
151void CryptoAlgorithmAES_CBC::exportKey(CryptoKeyFormat format, Ref<CryptoKey>&& key, KeyDataCallback&& callback, ExceptionCallback&& exceptionCallback)
152{
153 using namespace CryptoAlgorithmAES_CBCInternal;
154 const auto& aesKey = downcast<CryptoKeyAES>(key.get());
155
156 if (aesKey.key().isEmpty()) {
157 exceptionCallback(OperationError);
158 return;
159 }
160
161 KeyData result;
162 switch (format) {
163 case CryptoKeyFormat::Raw:
164 result = Vector<uint8_t>(aesKey.key());
165 break;
166 case CryptoKeyFormat::Jwk: {
167 JsonWebKey jwk = aesKey.exportJwk();
168 switch (aesKey.key().size() * 8) {
169 case CryptoKeyAES::s_length128:
170 jwk.alg = String(ALG128);
171 break;
172 case CryptoKeyAES::s_length192:
173 jwk.alg = String(ALG192);
174 break;
175 case CryptoKeyAES::s_length256:
176 jwk.alg = String(ALG256);
177 break;
178 default:
179 ASSERT_NOT_REACHED();
180 }
181 result = WTFMove(jwk);
182 break;
183 }
184 default:
185 exceptionCallback(NotSupportedError);
186 return;
187 }
188
189 callback(format, WTFMove(result));
190}
191
192ExceptionOr<size_t> CryptoAlgorithmAES_CBC::getKeyLength(const CryptoAlgorithmParameters& parameters)
193{
194 return CryptoKeyAES::getKeyLength(parameters);
195}
196
197}
198
199#endif // ENABLE(WEB_CRYPTO)
200