2 * QEMU Crypto cipher built-in algorithms
4 * Copyright (c) 2015 Red Hat, Inc.
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.
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.
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/>.
21 #include "crypto/aes.h"
23 typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
24 struct QCryptoCipherBuiltinAESContext {
29 typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
30 struct QCryptoCipherBuiltinAES {
32 QCryptoCipherBuiltinAESContext key;
33 uint8_t iv[AES_BLOCK_SIZE];
37 static inline bool qcrypto_length_check(size_t len, size_t blocksize,
40 if (unlikely(len & (blocksize - 1))) {
41 error_setg(errp, "Length %zu must be a multiple of block size %zu",
48 static void qcrypto_cipher_ctx_free(QCryptoCipher *cipher)
53 static int qcrypto_cipher_no_setiv(QCryptoCipher *cipher,
54 const uint8_t *iv, size_t niv,
57 error_setg(errp, "Setting IV is not supported");
61 static void do_aes_encrypt_ecb(const void *vctx,
66 const QCryptoCipherBuiltinAESContext *ctx = vctx;
68 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
70 AES_encrypt(in, out, &ctx->enc);
72 out += AES_BLOCK_SIZE;
73 len -= AES_BLOCK_SIZE;
77 static void do_aes_decrypt_ecb(const void *vctx,
82 const QCryptoCipherBuiltinAESContext *ctx = vctx;
84 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
86 AES_decrypt(in, out, &ctx->dec);
88 out += AES_BLOCK_SIZE;
89 len -= AES_BLOCK_SIZE;
93 static void do_aes_encrypt_cbc(const AES_KEY *key,
99 uint8_t tmp[AES_BLOCK_SIZE];
102 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
104 for (n = 0; n < AES_BLOCK_SIZE; ++n) {
105 tmp[n] = in[n] ^ ivec[n];
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;
115 static void do_aes_decrypt_cbc(const AES_KEY *key,
121 uint8_t tmp[AES_BLOCK_SIZE];
124 /* We have already verified that len % AES_BLOCK_SIZE == 0. */
126 memcpy(tmp, in, AES_BLOCK_SIZE);
127 AES_decrypt(in, out, key);
128 for (n = 0; n < AES_BLOCK_SIZE; ++n) {
131 memcpy(ivec, tmp, AES_BLOCK_SIZE);
132 len -= AES_BLOCK_SIZE;
133 in += AES_BLOCK_SIZE;
134 out += AES_BLOCK_SIZE;
138 static int qcrypto_cipher_aes_encrypt_ecb(QCryptoCipher *cipher,
139 const void *in, void *out,
140 size_t len, Error **errp)
142 QCryptoCipherBuiltinAES *ctx
143 = container_of(cipher, QCryptoCipherBuiltinAES, base);
145 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
148 do_aes_encrypt_ecb(&ctx->key, len, out, in);
152 static int qcrypto_cipher_aes_decrypt_ecb(QCryptoCipher *cipher,
153 const void *in, void *out,
154 size_t len, Error **errp)
156 QCryptoCipherBuiltinAES *ctx
157 = container_of(cipher, QCryptoCipherBuiltinAES, base);
159 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
162 do_aes_decrypt_ecb(&ctx->key, len, out, in);
166 static int qcrypto_cipher_aes_encrypt_cbc(QCryptoCipher *cipher,
167 const void *in, void *out,
168 size_t len, Error **errp)
170 QCryptoCipherBuiltinAES *ctx
171 = container_of(cipher, QCryptoCipherBuiltinAES, base);
173 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
176 do_aes_encrypt_cbc(&ctx->key.enc, len, out, in, ctx->iv);
180 static int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher,
181 const void *in, void *out,
182 size_t len, Error **errp)
184 QCryptoCipherBuiltinAES *ctx
185 = container_of(cipher, QCryptoCipherBuiltinAES, base);
187 if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
190 do_aes_decrypt_cbc(&ctx->key.dec, len, out, in, ctx->iv);
194 static int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv,
195 size_t niv, Error **errp)
197 QCryptoCipherBuiltinAES *ctx
198 = container_of(cipher, QCryptoCipherBuiltinAES, base);
200 if (niv != AES_BLOCK_SIZE) {
201 error_setg(errp, "IV must be %d bytes not %zu",
202 AES_BLOCK_SIZE, niv);
206 memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
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,
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,
224 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
225 QCryptoCipherMode mode)
228 case QCRYPTO_CIPHER_ALG_AES_128:
229 case QCRYPTO_CIPHER_ALG_AES_192:
230 case QCRYPTO_CIPHER_ALG_AES_256:
232 case QCRYPTO_CIPHER_MODE_ECB:
233 case QCRYPTO_CIPHER_MODE_CBC:
244 static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
245 QCryptoCipherMode mode,
250 if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
255 case QCRYPTO_CIPHER_ALG_AES_128:
256 case QCRYPTO_CIPHER_ALG_AES_192:
257 case QCRYPTO_CIPHER_ALG_AES_256:
259 QCryptoCipherBuiltinAES *ctx;
260 const QCryptoCipherDriver *drv;
263 case QCRYPTO_CIPHER_MODE_ECB:
264 drv = &qcrypto_cipher_aes_driver_ecb;
266 case QCRYPTO_CIPHER_MODE_CBC:
267 drv = &qcrypto_cipher_aes_driver_cbc;
273 ctx = g_new0(QCryptoCipherBuiltinAES, 1);
274 ctx->base.driver = drv;
276 if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) {
277 error_setg(errp, "Failed to set encryption key");
280 if (AES_set_decrypt_key(key, nkey * 8, &ctx->key.dec)) {
281 error_setg(errp, "Failed to set decryption key");
294 "Unsupported cipher algorithm %s",
295 QCryptoCipherAlgorithm_str(alg));
300 error_setg(errp, "Unsupported cipher mode %s",
301 QCryptoCipherMode_str(mode));