1 | /* |
2 | * Copyright (C) 2017 Metrological Group B.V. |
3 | * Copyright (C) 2017 Igalia S.L. |
4 | * |
5 | * Redistribution and use in source and binary forms, with or without |
6 | * modification, are permitted provided that the following conditions |
7 | * are met: |
8 | * 1. Redistributions of source code must retain the above copyright |
9 | * notice, this list of conditions and the following disclaimer. |
10 | * 2. Redistributions in binary form must reproduce the above copyright |
11 | * notice, this list of conditions and the following disclaimer in the |
12 | * documentation and/or other materials provided with the distribution. |
13 | * |
14 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
16 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
18 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
24 | * THE POSSIBILITY OF SUCH DAMAGE. |
25 | */ |
26 | |
27 | #include "config.h" |
28 | #include "CryptoAlgorithmAES_KW.h" |
29 | |
30 | #if ENABLE(WEB_CRYPTO) |
31 | |
32 | #include "CryptoKeyAES.h" |
33 | #include <pal/crypto/gcrypt/Handle.h> |
34 | #include <pal/crypto/gcrypt/Utilities.h> |
35 | |
36 | namespace WebCore { |
37 | |
38 | static Optional<Vector<uint8_t>> gcryptWrapKey(const Vector<uint8_t>& key, const Vector<uint8_t>& data) |
39 | { |
40 | // Determine the AES algorithm for the given key size. |
41 | auto algorithm = PAL::GCrypt::aesAlgorithmForKeySize(key.size() * 8); |
42 | if (!algorithm) |
43 | return WTF::nullopt; |
44 | |
45 | // Create a new GCrypt cipher object for the AES algorithm and the AES-Wrap cipher mode. |
46 | PAL::GCrypt::Handle<gcry_cipher_hd_t> handle; |
47 | gcry_error_t error = gcry_cipher_open(&handle, *algorithm, GCRY_CIPHER_MODE_AESWRAP, 0); |
48 | if (error != GPG_ERR_NO_ERROR) { |
49 | PAL::GCrypt::logError(error); |
50 | return WTF::nullopt; |
51 | } |
52 | |
53 | // Use the given key for this cipher object. |
54 | error = gcry_cipher_setkey(handle, key.data(), key.size()); |
55 | if (error != GPG_ERR_NO_ERROR) { |
56 | PAL::GCrypt::logError(error); |
57 | return WTF::nullopt; |
58 | } |
59 | |
60 | // Finalize the cipher object before performing the encryption. |
61 | error = gcry_cipher_final(handle); |
62 | if (error != GPG_ERR_NO_ERROR) { |
63 | PAL::GCrypt::logError(error); |
64 | return WTF::nullopt; |
65 | } |
66 | |
67 | // Perform the encryption. The provided output buffer must be 64 bits larger than the input buffer. |
68 | Vector<uint8_t> output(data.size() + 8); |
69 | error = gcry_cipher_encrypt(handle, output.data(), output.size(), data.data(), data.size()); |
70 | if (error != GPG_ERR_NO_ERROR) { |
71 | PAL::GCrypt::logError(error); |
72 | return WTF::nullopt; |
73 | } |
74 | |
75 | return output; |
76 | } |
77 | |
78 | static Optional<Vector<uint8_t>> gcryptUnwrapKey(const Vector<uint8_t>& key, const Vector<uint8_t>& data) |
79 | { |
80 | // Determine the AES algorithm for the given key size. |
81 | auto algorithm = PAL::GCrypt::aesAlgorithmForKeySize(key.size() * 8); |
82 | if (!algorithm) |
83 | return WTF::nullopt; |
84 | |
85 | // Create a new GCrypt cipher object for the AES algorithm and the AES-Wrap cipher mode. |
86 | PAL::GCrypt::Handle<gcry_cipher_hd_t> handle; |
87 | gcry_error_t error = gcry_cipher_open(&handle, *algorithm, GCRY_CIPHER_MODE_AESWRAP, 0); |
88 | if (error != GPG_ERR_NO_ERROR) { |
89 | PAL::GCrypt::logError(error); |
90 | return WTF::nullopt; |
91 | } |
92 | |
93 | // Use the given key for this cipher object. |
94 | error = gcry_cipher_setkey(handle, key.data(), key.size()); |
95 | if (error != GPG_ERR_NO_ERROR) { |
96 | PAL::GCrypt::logError(error); |
97 | return WTF::nullopt; |
98 | } |
99 | |
100 | // Finalize the cipher object before performing the encryption. |
101 | error = gcry_cipher_final(handle); |
102 | if (error != GPG_ERR_NO_ERROR) { |
103 | PAL::GCrypt::logError(error); |
104 | return WTF::nullopt; |
105 | } |
106 | |
107 | // Perform the decryption. The output buffer may be specified 64 bits shorter than the input buffer. |
108 | Vector<uint8_t> output(data.size() - 8); |
109 | error = gcry_cipher_decrypt(handle, output.data(), output.size(), data.data(), data.size()); |
110 | if (error != GPG_ERR_NO_ERROR) { |
111 | PAL::GCrypt::logError(error); |
112 | return WTF::nullopt; |
113 | } |
114 | |
115 | return output; |
116 | } |
117 | |
118 | ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_KW::platformWrapKey(const CryptoKeyAES& key, const Vector<uint8_t>& data) |
119 | { |
120 | auto output = gcryptWrapKey(key.key(), data); |
121 | if (!output) |
122 | return Exception { OperationError }; |
123 | return WTFMove(*output); |
124 | } |
125 | |
126 | ExceptionOr<Vector<uint8_t>> CryptoAlgorithmAES_KW::platformUnwrapKey(const CryptoKeyAES& key, const Vector<uint8_t>& data) |
127 | { |
128 | auto output = gcryptUnwrapKey(key.key(), data); |
129 | if (!output) |
130 | return Exception { OperationError }; |
131 | return WTFMove(*output); |
132 | } |
133 | |
134 | } // namespace WebCore |
135 | |
136 | #endif // ENABLE(WEB_CRYPTO) |
137 | |