Update SubtleCrypto::encrypt to match the latest spec
[WebKit-https.git] / Source / WebCore / crypto / algorithms / CryptoAlgorithmAES_CBC.cpp
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(SUBTLE_CRYPTO)
30
31 #include "CryptoAlgorithmAesCbcParams.h"
32 #include "CryptoAlgorithmAesCbcParamsDeprecated.h"
33 #include "CryptoAlgorithmAesKeyGenParams.h"
34 #include "CryptoAlgorithmAesKeyGenParamsDeprecated.h"
35 #include "CryptoKeyAES.h"
36 #include "CryptoKeyDataOctetSequence.h"
37 #include "ExceptionCode.h"
38
39 namespace WebCore {
40
41 static const char* const ALG128 = "A128CBC";
42 static const char* const ALG192 = "A192CBC";
43 static const char* const ALG256 = "A256CBC";
44 static const size_t IVSIZE = 16;
45
46 static inline bool usagesAreInvalidForCryptoAlgorithmAES_CBC(CryptoKeyUsageBitmap usages)
47 {
48     return usages & (CryptoKeyUsageSign | CryptoKeyUsageVerify | CryptoKeyUsageDeriveKey | CryptoKeyUsageDeriveBits);
49 }
50
51 Ref<CryptoAlgorithm> CryptoAlgorithmAES_CBC::create()
52 {
53     return adoptRef(*new CryptoAlgorithmAES_CBC);
54 }
55
56 CryptoAlgorithmIdentifier CryptoAlgorithmAES_CBC::identifier() const
57 {
58     return s_identifier;
59 }
60
61 bool CryptoAlgorithmAES_CBC::keyAlgorithmMatches(const CryptoAlgorithmAesCbcParamsDeprecated&, const CryptoKey& key) const
62 {
63     if (key.algorithmIdentifier() != s_identifier)
64         return false;
65     ASSERT(is<CryptoKeyAES>(key));
66     return true;
67 }
68
69 void CryptoAlgorithmAES_CBC::encrypt(std::unique_ptr<CryptoAlgorithmParameters>&& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& plainText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
70 {
71     ASSERT(parameters);
72     auto& aesParameters = downcast<CryptoAlgorithmAesCbcParams>(*parameters);
73     if (aesParameters.ivVector().size() != IVSIZE) {
74         exceptionCallback(OperationError);
75         return;
76     }
77     platformEncrypt(WTFMove(parameters), WTFMove(key), WTFMove(plainText), WTFMove(callback), WTFMove(exceptionCallback), context, workQueue);
78 }
79
80 void CryptoAlgorithmAES_CBC::generateKey(const std::unique_ptr<CryptoAlgorithmParameters>&& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyOrKeyPairCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext&)
81 {
82     ASSERT(parameters);
83     auto& aesParameters = downcast<CryptoAlgorithmAesKeyGenParams>(*parameters);
84
85     if (usagesAreInvalidForCryptoAlgorithmAES_CBC(usages)) {
86         exceptionCallback(SYNTAX_ERR);
87         return;
88     }
89
90     auto result = CryptoKeyAES::generate(CryptoAlgorithmIdentifier::AES_CBC, aesParameters.length, extractable, usages);
91     if (!result) {
92         exceptionCallback(OperationError);
93         return;
94     }
95
96     callback(result.get(), nullptr);
97 }
98
99 void CryptoAlgorithmAES_CBC::importKey(SubtleCrypto::KeyFormat format, KeyData&& data, const std::unique_ptr<CryptoAlgorithmParameters>&& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyCallback&& callback, ExceptionCallback&& exceptionCallback)
100 {
101     ASSERT(parameters);
102     if (usagesAreInvalidForCryptoAlgorithmAES_CBC(usages)) {
103         exceptionCallback(SYNTAX_ERR);
104         return;
105     }
106
107     RefPtr<CryptoKeyAES> result;
108     switch (format) {
109     case SubtleCrypto::KeyFormat::Raw:
110         result = CryptoKeyAES::importRaw(parameters->identifier, WTFMove(WTF::get<Vector<uint8_t>>(data)), extractable, usages);
111         break;
112     case SubtleCrypto::KeyFormat::Jwk: {
113         auto checkAlgCallback = [](size_t length, const Optional<String>& alg) -> bool {
114             switch (length) {
115             case CryptoKeyAES::s_length128:
116                 return !alg || alg.value() == ALG128;
117             case CryptoKeyAES::s_length192:
118                 return !alg || alg.value() == ALG192;
119             case CryptoKeyAES::s_length256:
120                 return !alg || alg.value() == ALG256;
121             }
122             return false;
123         };
124         result = CryptoKeyAES::importJwk(parameters->identifier, WTFMove(WTF::get<JsonWebKey>(data)), extractable, usages, WTFMove(checkAlgCallback));
125         break;
126     }
127     default:
128         exceptionCallback(NOT_SUPPORTED_ERR);
129         return;
130     }
131     if (!result) {
132         exceptionCallback(DataError);
133         return;
134     }
135
136     callback(*result);
137 }
138
139 void CryptoAlgorithmAES_CBC::exportKey(SubtleCrypto::KeyFormat format, Ref<CryptoKey>&& key, KeyDataCallback&& callback, ExceptionCallback&& exceptionCallback)
140 {
141     const auto& aesKey = downcast<CryptoKeyAES>(key.get());
142
143     if (aesKey.key().isEmpty()) {
144         exceptionCallback(OperationError);
145         return;
146     }
147
148     KeyData result;
149     switch (format) {
150     case SubtleCrypto::KeyFormat::Raw:
151         result = Vector<uint8_t>(aesKey.key());
152         break;
153     case SubtleCrypto::KeyFormat::Jwk: {
154         JsonWebKey jwk = aesKey.exportJwk();
155         switch (aesKey.key().size() * 8) {
156         case CryptoKeyAES::s_length128:
157             jwk.alg = String(ALG128);
158             break;
159         case CryptoKeyAES::s_length192:
160             jwk.alg = String(ALG192);
161             break;
162         case CryptoKeyAES::s_length256:
163             jwk.alg = String(ALG256);
164             break;
165         default:
166             ASSERT_NOT_REACHED();
167         }
168         result = WTFMove(jwk);
169         break;
170     }
171     default:
172         exceptionCallback(NOT_SUPPORTED_ERR);
173         return;
174     }
175
176     callback(format, WTFMove(result));
177 }
178
179 ExceptionOr<void> CryptoAlgorithmAES_CBC::encrypt(const CryptoAlgorithmParametersDeprecated& parameters, const CryptoKey& key, const CryptoOperationData& data, VectorCallback&& callback, VoidCallback&& failureCallback)
180 {
181     auto& aesCBCParameters = downcast<CryptoAlgorithmAesCbcParamsDeprecated>(parameters);
182     if (!keyAlgorithmMatches(aesCBCParameters, key))
183         return Exception { NOT_SUPPORTED_ERR };
184     return platformEncrypt(aesCBCParameters, downcast<CryptoKeyAES>(key), data, WTFMove(callback), WTFMove(failureCallback));
185 }
186
187 ExceptionOr<void> CryptoAlgorithmAES_CBC::decrypt(const CryptoAlgorithmParametersDeprecated& parameters, const CryptoKey& key, const CryptoOperationData& data, VectorCallback&& callback, VoidCallback&& failureCallback)
188 {
189     auto& aesCBCParameters = downcast<CryptoAlgorithmAesCbcParamsDeprecated>(parameters);
190     if (!keyAlgorithmMatches(aesCBCParameters, key))
191         return Exception { NOT_SUPPORTED_ERR };
192     return platformDecrypt(aesCBCParameters, downcast<CryptoKeyAES>(key), data, WTFMove(callback), WTFMove(failureCallback));
193 }
194
195 ExceptionOr<void> CryptoAlgorithmAES_CBC::generateKey(const CryptoAlgorithmParametersDeprecated& parameters, bool extractable, CryptoKeyUsageBitmap usages, KeyOrKeyPairCallback&& callback, VoidCallback&& failureCallback, ScriptExecutionContext&)
196 {
197     auto& aesParameters = downcast<CryptoAlgorithmAesKeyGenParamsDeprecated>(parameters);
198
199     auto result = CryptoKeyAES::generate(CryptoAlgorithmIdentifier::AES_CBC, aesParameters.length, extractable, usages);
200     if (!result) {
201         failureCallback();
202         return { };
203     }
204
205     callback(result.get(), nullptr);
206     return { };
207 }
208
209 ExceptionOr<void> CryptoAlgorithmAES_CBC::importKey(const CryptoAlgorithmParametersDeprecated&, const CryptoKeyData& keyData, bool extractable, CryptoKeyUsageBitmap usage, KeyCallback&& callback, VoidCallback&&)
210 {
211     if (!is<CryptoKeyDataOctetSequence>(keyData))
212         return Exception { NOT_SUPPORTED_ERR };
213     auto& keyDataOctetSequence = downcast<CryptoKeyDataOctetSequence>(keyData);
214     callback(CryptoKeyAES::create(CryptoAlgorithmIdentifier::AES_CBC, keyDataOctetSequence.octetSequence(), extractable, usage));
215     return { };
216 }
217
218 }
219
220 #endif // ENABLE(SUBTLE_CRYPTO)