001b06e74a07c60f2a21c9dbfdeab4a92c1c7320
[WebKit-https.git] / Source / WebCore / crypto / mac / CryptoAlgorithmAES_CBCMac.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 "CryptoKeyAES.h"
34 #include "ExceptionCode.h"
35 #include "ScriptExecutionContext.h"
36 #include <CommonCrypto/CommonCrypto.h>
37
38 namespace WebCore {
39
40 // FIXME: We should change iv and data to Vector<uint8_t> type once WebKitSubtleCrypto is deprecated.
41 // https://bugs.webkit.org/show_bug.cgi?id=164939
42 static ExceptionOr<Vector<uint8_t>> transformAES_CBC(CCOperation operation, const uint8_t* iv, const Vector<uint8_t>& key, const uint8_t* data, size_t dataLength)
43 {
44     size_t keyLengthInBytes = key.size();
45     CCCryptorRef cryptor;
46 #if PLATFORM(COCOA)
47     CCAlgorithm aesAlgorithm = kCCAlgorithmAES;
48 #else
49     CCAlgorithm aesAlgorithm = kCCAlgorithmAES128;
50 #endif
51     CCCryptorStatus status = CCCryptorCreate(operation, aesAlgorithm, kCCOptionPKCS7Padding, key.data(), keyLengthInBytes, iv, &cryptor);
52     if (status)
53         return Exception { OperationError };
54
55     Vector<uint8_t> result(CCCryptorGetOutputLength(cryptor, dataLength, true));
56
57     size_t bytesWritten;
58     status = CCCryptorUpdate(cryptor, data, dataLength, result.data(), result.size(), &bytesWritten);
59     if (status)
60         return Exception { OperationError };
61
62     uint8_t* p = result.data() + bytesWritten;
63     status = CCCryptorFinal(cryptor, p, result.end() - p, &bytesWritten);
64     p += bytesWritten;
65     if (status)
66         return Exception { OperationError };
67
68     ASSERT(p <= result.end());
69     result.shrink(p - result.begin());
70
71     CCCryptorRelease(cryptor);
72
73     return WTFMove(result);
74 }
75
76 void CryptoAlgorithmAES_CBC::platformEncrypt(std::unique_ptr<CryptoAlgorithmParameters>&& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& plainText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
77 {
78     context.ref();
79     workQueue.dispatch([parameters = WTFMove(parameters), key = WTFMove(key), plainText = WTFMove(plainText), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
80         auto& aesParameters = downcast<CryptoAlgorithmAesCbcParams>(*parameters);
81         auto& aesKey = downcast<CryptoKeyAES>(key.get());
82         ASSERT(aesParameters.ivVector().size() == kCCBlockSizeAES128);
83         auto result = transformAES_CBC(kCCEncrypt, aesParameters.ivVector().data(), aesKey.key(), plainText.data(), plainText.size());
84         if (result.hasException()) {
85             context.postTask([exceptionCallback = WTFMove(exceptionCallback), ec = result.releaseException().code()](ScriptExecutionContext& context) {
86                 exceptionCallback(ec);
87                 context.deref();
88             });
89             return;
90         }
91         context.postTask([callback = WTFMove(callback), result = result.releaseReturnValue()](ScriptExecutionContext& context) {
92             callback(result);
93             context.deref();
94         });
95     });
96 }
97
98 void CryptoAlgorithmAES_CBC::platformDecrypt(std::unique_ptr<CryptoAlgorithmParameters>&& parameters, Ref<CryptoKey>&& key, Vector<uint8_t>&& cipherText, VectorCallback&& callback, ExceptionCallback&& exceptionCallback, ScriptExecutionContext& context, WorkQueue& workQueue)
99 {
100     context.ref();
101     workQueue.dispatch([parameters = WTFMove(parameters), key = WTFMove(key), cipherText = WTFMove(cipherText), callback = WTFMove(callback), exceptionCallback = WTFMove(exceptionCallback), &context]() mutable {
102         auto& aesParameters = downcast<CryptoAlgorithmAesCbcParams>(*parameters);
103         auto& aesKey = downcast<CryptoKeyAES>(key.get());
104         assert(aesParameters.ivVector().size() == kCCBlockSizeAES128);
105         auto result = transformAES_CBC(kCCDecrypt, aesParameters.ivVector().data(), aesKey.key(), cipherText.data(), cipherText.size());
106         if (result.hasException()) {
107             context.postTask([exceptionCallback = WTFMove(exceptionCallback), ec = result.releaseException().code()](ScriptExecutionContext& context) {
108                 exceptionCallback(ec);
109                 context.deref();
110             });
111             return;
112         }
113         context.postTask([callback = WTFMove(callback), result = result.releaseReturnValue()](ScriptExecutionContext& context) {
114             callback(result);
115             context.deref();
116         });
117     });
118 }
119
120 ExceptionOr<void> CryptoAlgorithmAES_CBC::platformEncrypt(const CryptoAlgorithmAesCbcParamsDeprecated& parameters, const CryptoKeyAES& key, const CryptoOperationData& data, VectorCallback&& callback, VoidCallback&& failureCallback)
121 {
122     ASSERT(sizeof(parameters.iv) == kCCBlockSizeAES128);
123     auto result = transformAES_CBC(kCCEncrypt, parameters.iv.data(), key.key(), data.first, data.second);
124     if (result.hasException()) {
125         failureCallback();
126         return { };
127     }
128     callback(result.releaseReturnValue());
129     return { };
130 }
131
132 ExceptionOr<void> CryptoAlgorithmAES_CBC::platformDecrypt(const CryptoAlgorithmAesCbcParamsDeprecated& parameters, const CryptoKeyAES& key, const CryptoOperationData& data, VectorCallback&& callback, VoidCallback&& failureCallback)
133 {
134     ASSERT(sizeof(parameters.iv) == kCCBlockSizeAES128);
135     auto result = transformAES_CBC(kCCDecrypt, parameters.iv.data(), key.key(), data.first, data.second);
136     if (result.hasException()) {
137         failureCallback();
138         return { };
139     }
140     callback(result.releaseReturnValue());
141     return { };
142 }
143
144 } // namespace WebCore
145
146 #endif // ENABLE(SUBTLE_CRYPTO)