]>
Commit | Line | Data |
---|---|---|
ca38a4cc DB |
1 | /* |
2 | * QEMU Crypto cipher built-in algorithms | |
3 | * | |
4 | * Copyright (c) 2015 Red Hat, Inc. | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Lesser General Public | |
8 | * License as published by the Free Software Foundation; either | |
b7cbb874 | 9 | * version 2.1 of the License, or (at your option) any later version. |
ca38a4cc DB |
10 | * |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Lesser General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Lesser General Public | |
17 | * License along with this library; if not, see <http://www.gnu.org/licenses/>. | |
18 | * | |
19 | */ | |
20 | ||
21 | #include "crypto/aes.h" | |
ca38a4cc | 22 | |
e3ba0b67 DB |
23 | typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext; |
24 | struct QCryptoCipherBuiltinAESContext { | |
25 | AES_KEY enc; | |
26 | AES_KEY dec; | |
27 | }; | |
a3db31b8 | 28 | |
ca38a4cc DB |
29 | typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES; |
30 | struct QCryptoCipherBuiltinAES { | |
a3db31b8 | 31 | QCryptoCipher base; |
e3ba0b67 | 32 | QCryptoCipherBuiltinAESContext key; |
eb2a770b | 33 | uint8_t iv[AES_BLOCK_SIZE]; |
ca38a4cc | 34 | }; |
ca38a4cc | 35 | |
ca38a4cc | 36 | |
a3db31b8 RH |
37 | static inline bool qcrypto_length_check(size_t len, size_t blocksize, |
38 | Error **errp) | |
39 | { | |
40 | if (unlikely(len & (blocksize - 1))) { | |
41 | error_setg(errp, "Length %zu must be a multiple of block size %zu", | |
42 | len, blocksize); | |
43 | return false; | |
44 | } | |
45 | return true; | |
46 | } | |
ca38a4cc | 47 | |
a3db31b8 | 48 | static void qcrypto_cipher_ctx_free(QCryptoCipher *cipher) |
ca38a4cc | 49 | { |
3eedf5cc | 50 | g_free(cipher); |
ca38a4cc DB |
51 | } |
52 | ||
a3db31b8 RH |
53 | static int qcrypto_cipher_no_setiv(QCryptoCipher *cipher, |
54 | const uint8_t *iv, size_t niv, | |
55 | Error **errp) | |
56 | { | |
57 | error_setg(errp, "Setting IV is not supported"); | |
58 | return -1; | |
59 | } | |
60 | ||
8ee47cdd RH |
61 | static void do_aes_encrypt_ecb(const void *vctx, |
62 | size_t len, | |
63 | uint8_t *out, | |
64 | const uint8_t *in) | |
e3ba0b67 | 65 | { |
8ee47cdd | 66 | const QCryptoCipherBuiltinAESContext *ctx = vctx; |
838e4631 RH |
67 | |
68 | /* We have already verified that len % AES_BLOCK_SIZE == 0. */ | |
e3ba0b67 | 69 | while (len) { |
8ee47cdd RH |
70 | AES_encrypt(in, out, &ctx->enc); |
71 | in += AES_BLOCK_SIZE; | |
72 | out += AES_BLOCK_SIZE; | |
838e4631 | 73 | len -= AES_BLOCK_SIZE; |
e3ba0b67 DB |
74 | } |
75 | } | |
76 | ||
8ee47cdd RH |
77 | static void do_aes_decrypt_ecb(const void *vctx, |
78 | size_t len, | |
79 | uint8_t *out, | |
80 | const uint8_t *in) | |
e3ba0b67 | 81 | { |
8ee47cdd | 82 | const QCryptoCipherBuiltinAESContext *ctx = vctx; |
838e4631 RH |
83 | |
84 | /* We have already verified that len % AES_BLOCK_SIZE == 0. */ | |
e3ba0b67 | 85 | while (len) { |
8ee47cdd RH |
86 | AES_decrypt(in, out, &ctx->dec); |
87 | in += AES_BLOCK_SIZE; | |
88 | out += AES_BLOCK_SIZE; | |
838e4631 | 89 | len -= AES_BLOCK_SIZE; |
e3ba0b67 DB |
90 | } |
91 | } | |
92 | ||
ef186f4b RH |
93 | static void do_aes_encrypt_cbc(const AES_KEY *key, |
94 | size_t len, | |
95 | uint8_t *out, | |
96 | const uint8_t *in, | |
97 | uint8_t *ivec) | |
a2d76b6b | 98 | { |
ef186f4b RH |
99 | uint8_t tmp[AES_BLOCK_SIZE]; |
100 | size_t n; | |
101 | ||
102 | /* We have already verified that len % AES_BLOCK_SIZE == 0. */ | |
103 | while (len) { | |
104 | for (n = 0; n < AES_BLOCK_SIZE; ++n) { | |
105 | tmp[n] = in[n] ^ ivec[n]; | |
a2d76b6b | 106 | } |
ef186f4b RH |
107 | AES_encrypt(tmp, out, key); |
108 | memcpy(ivec, out, AES_BLOCK_SIZE); | |
109 | len -= AES_BLOCK_SIZE; | |
110 | in += AES_BLOCK_SIZE; | |
111 | out += AES_BLOCK_SIZE; | |
a2d76b6b RH |
112 | } |
113 | } | |
114 | ||
ef186f4b RH |
115 | static void do_aes_decrypt_cbc(const AES_KEY *key, |
116 | size_t len, | |
117 | uint8_t *out, | |
118 | const uint8_t *in, | |
119 | uint8_t *ivec) | |
120 | { | |
121 | uint8_t tmp[AES_BLOCK_SIZE]; | |
122 | size_t n; | |
123 | ||
124 | /* We have already verified that len % AES_BLOCK_SIZE == 0. */ | |
125 | while (len) { | |
126 | memcpy(tmp, in, AES_BLOCK_SIZE); | |
127 | AES_decrypt(in, out, key); | |
128 | for (n = 0; n < AES_BLOCK_SIZE; ++n) { | |
129 | out[n] ^= ivec[n]; | |
130 | } | |
131 | memcpy(ivec, tmp, AES_BLOCK_SIZE); | |
132 | len -= AES_BLOCK_SIZE; | |
133 | in += AES_BLOCK_SIZE; | |
134 | out += AES_BLOCK_SIZE; | |
135 | } | |
136 | } | |
a2d76b6b | 137 | |
a3db31b8 RH |
138 | static int qcrypto_cipher_aes_encrypt_ecb(QCryptoCipher *cipher, |
139 | const void *in, void *out, | |
140 | size_t len, Error **errp) | |
ca38a4cc | 141 | { |
a3db31b8 RH |
142 | QCryptoCipherBuiltinAES *ctx |
143 | = container_of(cipher, QCryptoCipherBuiltinAES, base); | |
ca38a4cc | 144 | |
a3db31b8 RH |
145 | if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) { |
146 | return -1; | |
ca38a4cc | 147 | } |
a3db31b8 | 148 | do_aes_encrypt_ecb(&ctx->key, len, out, in); |
ca38a4cc DB |
149 | return 0; |
150 | } | |
151 | ||
a3db31b8 RH |
152 | static int qcrypto_cipher_aes_decrypt_ecb(QCryptoCipher *cipher, |
153 | const void *in, void *out, | |
154 | size_t len, Error **errp) | |
ca38a4cc | 155 | { |
a3db31b8 RH |
156 | QCryptoCipherBuiltinAES *ctx |
157 | = container_of(cipher, QCryptoCipherBuiltinAES, base); | |
ca38a4cc | 158 | |
a3db31b8 RH |
159 | if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) { |
160 | return -1; | |
ca38a4cc | 161 | } |
a3db31b8 | 162 | do_aes_decrypt_ecb(&ctx->key, len, out, in); |
ca38a4cc DB |
163 | return 0; |
164 | } | |
165 | ||
a3db31b8 RH |
166 | static int qcrypto_cipher_aes_encrypt_cbc(QCryptoCipher *cipher, |
167 | const void *in, void *out, | |
168 | size_t len, Error **errp) | |
ca38a4cc | 169 | { |
a3db31b8 RH |
170 | QCryptoCipherBuiltinAES *ctx |
171 | = container_of(cipher, QCryptoCipherBuiltinAES, base); | |
3eedf5cc | 172 | |
a3db31b8 | 173 | if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) { |
ca38a4cc DB |
174 | return -1; |
175 | } | |
a3db31b8 | 176 | do_aes_encrypt_cbc(&ctx->key.enc, len, out, in, ctx->iv); |
ca38a4cc DB |
177 | return 0; |
178 | } | |
179 | ||
a3db31b8 RH |
180 | static int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher, |
181 | const void *in, void *out, | |
182 | size_t len, Error **errp) | |
183 | { | |
184 | QCryptoCipherBuiltinAES *ctx | |
185 | = container_of(cipher, QCryptoCipherBuiltinAES, base); | |
ca38a4cc | 186 | |
a3db31b8 RH |
187 | if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) { |
188 | return -1; | |
189 | } | |
190 | do_aes_decrypt_cbc(&ctx->key.dec, len, out, in, ctx->iv); | |
191 | return 0; | |
192 | } | |
ca38a4cc | 193 | |
a3db31b8 RH |
194 | static int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv, |
195 | size_t niv, Error **errp) | |
196 | { | |
197 | QCryptoCipherBuiltinAES *ctx | |
198 | = container_of(cipher, QCryptoCipherBuiltinAES, base); | |
eaec903c | 199 | |
a3db31b8 RH |
200 | if (niv != AES_BLOCK_SIZE) { |
201 | error_setg(errp, "IV must be %d bytes not %zu", | |
202 | AES_BLOCK_SIZE, niv); | |
203 | return -1; | |
ca38a4cc DB |
204 | } |
205 | ||
a3db31b8 RH |
206 | memcpy(ctx->iv, iv, AES_BLOCK_SIZE); |
207 | return 0; | |
208 | } | |
ca38a4cc | 209 | |
a3db31b8 RH |
210 | static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_ecb = { |
211 | .cipher_encrypt = qcrypto_cipher_aes_encrypt_ecb, | |
212 | .cipher_decrypt = qcrypto_cipher_aes_decrypt_ecb, | |
213 | .cipher_setiv = qcrypto_cipher_no_setiv, | |
214 | .cipher_free = qcrypto_cipher_ctx_free, | |
215 | }; | |
ca38a4cc | 216 | |
a3db31b8 RH |
217 | static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = { |
218 | .cipher_encrypt = qcrypto_cipher_aes_encrypt_cbc, | |
219 | .cipher_decrypt = qcrypto_cipher_aes_decrypt_cbc, | |
220 | .cipher_setiv = qcrypto_cipher_aes_setiv, | |
221 | .cipher_free = qcrypto_cipher_ctx_free, | |
222 | }; | |
ca38a4cc | 223 | |
f844836d GA |
224 | bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg, |
225 | QCryptoCipherMode mode) | |
ca38a4cc DB |
226 | { |
227 | switch (alg) { | |
ca38a4cc DB |
228 | case QCRYPTO_CIPHER_ALG_AES_128: |
229 | case QCRYPTO_CIPHER_ALG_AES_192: | |
230 | case QCRYPTO_CIPHER_ALG_AES_256: | |
a3db31b8 RH |
231 | switch (mode) { |
232 | case QCRYPTO_CIPHER_MODE_ECB: | |
233 | case QCRYPTO_CIPHER_MODE_CBC: | |
a3db31b8 RH |
234 | return true; |
235 | default: | |
236 | return false; | |
237 | } | |
f844836d GA |
238 | break; |
239 | default: | |
240 | return false; | |
241 | } | |
ca38a4cc DB |
242 | } |
243 | ||
3eedf5cc RH |
244 | static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg, |
245 | QCryptoCipherMode mode, | |
246 | const uint8_t *key, | |
247 | size_t nkey, | |
248 | Error **errp) | |
ca38a4cc | 249 | { |
eaec903c | 250 | if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) { |
d962c626 | 251 | return NULL; |
ca38a4cc DB |
252 | } |
253 | ||
d962c626 | 254 | switch (alg) { |
ca38a4cc DB |
255 | case QCRYPTO_CIPHER_ALG_AES_128: |
256 | case QCRYPTO_CIPHER_ALG_AES_192: | |
257 | case QCRYPTO_CIPHER_ALG_AES_256: | |
a3db31b8 RH |
258 | { |
259 | QCryptoCipherBuiltinAES *ctx; | |
260 | const QCryptoCipherDriver *drv; | |
261 | ||
262 | switch (mode) { | |
263 | case QCRYPTO_CIPHER_MODE_ECB: | |
264 | drv = &qcrypto_cipher_aes_driver_ecb; | |
265 | break; | |
266 | case QCRYPTO_CIPHER_MODE_CBC: | |
267 | drv = &qcrypto_cipher_aes_driver_cbc; | |
268 | break; | |
a3db31b8 RH |
269 | default: |
270 | goto bad_mode; | |
271 | } | |
272 | ||
273 | ctx = g_new0(QCryptoCipherBuiltinAES, 1); | |
274 | ctx->base.driver = drv; | |
275 | ||
a3db31b8 RH |
276 | if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) { |
277 | error_setg(errp, "Failed to set encryption key"); | |
278 | goto error; | |
279 | } | |
280 | if (AES_set_decrypt_key(key, nkey * 8, &ctx->key.dec)) { | |
281 | error_setg(errp, "Failed to set decryption key"); | |
282 | goto error; | |
283 | } | |
284 | ||
285 | return &ctx->base; | |
286 | ||
287 | error: | |
288 | g_free(ctx); | |
289 | return NULL; | |
290 | } | |
291 | ||
ca38a4cc DB |
292 | default: |
293 | error_setg(errp, | |
90d6f60d | 294 | "Unsupported cipher algorithm %s", |
977c736f | 295 | QCryptoCipherAlgorithm_str(alg)); |
d962c626 | 296 | return NULL; |
ca38a4cc | 297 | } |
ca38a4cc | 298 | |
a3db31b8 RH |
299 | bad_mode: |
300 | error_setg(errp, "Unsupported cipher mode %s", | |
301 | QCryptoCipherMode_str(mode)); | |
302 | return NULL; | |
ca38a4cc | 303 | } |