Update version for v7.1.0-rc2 release
[qemu.git] / crypto / cipher-builtin.c.inc
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
9  * version 2.1 of the License, or (at your option) any later version.
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"
22
23 typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
24 struct QCryptoCipherBuiltinAESContext {
25     AES_KEY enc;
26     AES_KEY dec;
27 };
28
29 typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
30 struct QCryptoCipherBuiltinAES {
31     QCryptoCipher base;
32     QCryptoCipherBuiltinAESContext key;
33     uint8_t iv[AES_BLOCK_SIZE];
34 };
35
36
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 }
47
48 static void qcrypto_cipher_ctx_free(QCryptoCipher *cipher)
49 {
50     g_free(cipher);
51 }
52
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
61 static void do_aes_encrypt_ecb(const void *vctx,
62                                size_t len,
63                                uint8_t *out,
64                                const uint8_t *in)
65 {
66     const QCryptoCipherBuiltinAESContext *ctx = vctx;
67
68     /* We have already verified that len % AES_BLOCK_SIZE == 0. */
69     while (len) {
70         AES_encrypt(in, out, &ctx->enc);
71         in += AES_BLOCK_SIZE;
72         out += AES_BLOCK_SIZE;
73         len -= AES_BLOCK_SIZE;
74     }
75 }
76
77 static void do_aes_decrypt_ecb(const void *vctx,
78                                size_t len,
79                                uint8_t *out,
80                                const uint8_t *in)
81 {
82     const QCryptoCipherBuiltinAESContext *ctx = vctx;
83
84     /* We have already verified that len % AES_BLOCK_SIZE == 0. */
85     while (len) {
86         AES_decrypt(in, out, &ctx->dec);
87         in += AES_BLOCK_SIZE;
88         out += AES_BLOCK_SIZE;
89         len -= AES_BLOCK_SIZE;
90     }
91 }
92
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)
98 {
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];
106         }
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;
112     }
113 }
114
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 }
137
138 static int qcrypto_cipher_aes_encrypt_ecb(QCryptoCipher *cipher,
139                                           const void *in, void *out,
140                                           size_t len, Error **errp)
141 {
142     QCryptoCipherBuiltinAES *ctx
143         = container_of(cipher, QCryptoCipherBuiltinAES, base);
144
145     if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
146         return -1;
147     }
148     do_aes_encrypt_ecb(&ctx->key, len, out, in);
149     return 0;
150 }
151
152 static int qcrypto_cipher_aes_decrypt_ecb(QCryptoCipher *cipher,
153                                           const void *in, void *out,
154                                           size_t len, Error **errp)
155 {
156     QCryptoCipherBuiltinAES *ctx
157         = container_of(cipher, QCryptoCipherBuiltinAES, base);
158
159     if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
160         return -1;
161     }
162     do_aes_decrypt_ecb(&ctx->key, len, out, in);
163     return 0;
164 }
165
166 static int qcrypto_cipher_aes_encrypt_cbc(QCryptoCipher *cipher,
167                                           const void *in, void *out,
168                                           size_t len, Error **errp)
169 {
170     QCryptoCipherBuiltinAES *ctx
171         = container_of(cipher, QCryptoCipherBuiltinAES, base);
172
173     if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
174         return -1;
175     }
176     do_aes_encrypt_cbc(&ctx->key.enc, len, out, in, ctx->iv);
177     return 0;
178 }
179
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);
186
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 }
193
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);
199
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;
204     }
205
206     memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
207     return 0;
208 }
209
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 };
216
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 };
223
224 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
225                              QCryptoCipherMode mode)
226 {
227     switch (alg) {
228     case QCRYPTO_CIPHER_ALG_AES_128:
229     case QCRYPTO_CIPHER_ALG_AES_192:
230     case QCRYPTO_CIPHER_ALG_AES_256:
231         switch (mode) {
232         case QCRYPTO_CIPHER_MODE_ECB:
233         case QCRYPTO_CIPHER_MODE_CBC:
234             return true;
235         default:
236             return false;
237         }
238         break;
239     default:
240         return false;
241     }
242 }
243
244 static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
245                                              QCryptoCipherMode mode,
246                                              const uint8_t *key,
247                                              size_t nkey,
248                                              Error **errp)
249 {
250     if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
251         return NULL;
252     }
253
254     switch (alg) {
255     case QCRYPTO_CIPHER_ALG_AES_128:
256     case QCRYPTO_CIPHER_ALG_AES_192:
257     case QCRYPTO_CIPHER_ALG_AES_256:
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;
269             default:
270                 goto bad_mode;
271             }
272
273             ctx = g_new0(QCryptoCipherBuiltinAES, 1);
274             ctx->base.driver = drv;
275
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
292     default:
293         error_setg(errp,
294                    "Unsupported cipher algorithm %s",
295                    QCryptoCipherAlgorithm_str(alg));
296         return NULL;
297     }
298
299  bad_mode:
300     error_setg(errp, "Unsupported cipher mode %s",
301                QCryptoCipherMode_str(mode));
302     return NULL;
303 }