xref: /openbmc/qemu/crypto/cipher-builtin.c.inc (revision b8eada54b2ad8a7d98d93d5ab4d3e888c5880097)
16d92bdf4SRichard Henderson/*
26d92bdf4SRichard Henderson * QEMU Crypto cipher built-in algorithms
36d92bdf4SRichard Henderson *
46d92bdf4SRichard Henderson * Copyright (c) 2015 Red Hat, Inc.
56d92bdf4SRichard Henderson *
66d92bdf4SRichard Henderson * This library is free software; you can redistribute it and/or
76d92bdf4SRichard Henderson * modify it under the terms of the GNU Lesser General Public
86d92bdf4SRichard Henderson * License as published by the Free Software Foundation; either
96d92bdf4SRichard Henderson * version 2.1 of the License, or (at your option) any later version.
106d92bdf4SRichard Henderson *
116d92bdf4SRichard Henderson * This library is distributed in the hope that it will be useful,
126d92bdf4SRichard Henderson * but WITHOUT ANY WARRANTY; without even the implied warranty of
136d92bdf4SRichard Henderson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
146d92bdf4SRichard Henderson * Lesser General Public License for more details.
156d92bdf4SRichard Henderson *
166d92bdf4SRichard Henderson * You should have received a copy of the GNU Lesser General Public
176d92bdf4SRichard Henderson * License along with this library; if not, see <http://www.gnu.org/licenses/>.
186d92bdf4SRichard Henderson *
196d92bdf4SRichard Henderson */
206d92bdf4SRichard Henderson
216d92bdf4SRichard Henderson#include "crypto/aes.h"
226d92bdf4SRichard Henderson
236d92bdf4SRichard Hendersontypedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
246d92bdf4SRichard Hendersonstruct QCryptoCipherBuiltinAESContext {
256d92bdf4SRichard Henderson    AES_KEY enc;
266d92bdf4SRichard Henderson    AES_KEY dec;
276d92bdf4SRichard Henderson};
28a3db31b8SRichard Henderson
296d92bdf4SRichard Hendersontypedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
306d92bdf4SRichard Hendersonstruct QCryptoCipherBuiltinAES {
31a3db31b8SRichard Henderson    QCryptoCipher base;
326d92bdf4SRichard Henderson    QCryptoCipherBuiltinAESContext key;
336d92bdf4SRichard Henderson    uint8_t iv[AES_BLOCK_SIZE];
346d92bdf4SRichard Henderson};
356d92bdf4SRichard Henderson
366d92bdf4SRichard Henderson
37a3db31b8SRichard Hendersonstatic inline bool qcrypto_length_check(size_t len, size_t blocksize,
38a3db31b8SRichard Henderson                                        Error **errp)
39a3db31b8SRichard Henderson{
40a3db31b8SRichard Henderson    if (unlikely(len & (blocksize - 1))) {
41a3db31b8SRichard Henderson        error_setg(errp, "Length %zu must be a multiple of block size %zu",
42a3db31b8SRichard Henderson                   len, blocksize);
43a3db31b8SRichard Henderson        return false;
44a3db31b8SRichard Henderson    }
45a3db31b8SRichard Henderson    return true;
46a3db31b8SRichard Henderson}
47a3db31b8SRichard Henderson
48a3db31b8SRichard Hendersonstatic void qcrypto_cipher_ctx_free(QCryptoCipher *cipher)
496d92bdf4SRichard Henderson{
503eedf5ccSRichard Henderson    g_free(cipher);
516d92bdf4SRichard Henderson}
526d92bdf4SRichard Henderson
53a3db31b8SRichard Hendersonstatic int qcrypto_cipher_no_setiv(QCryptoCipher *cipher,
54a3db31b8SRichard Henderson                                   const uint8_t *iv, size_t niv,
55a3db31b8SRichard Henderson                                   Error **errp)
56a3db31b8SRichard Henderson{
57a3db31b8SRichard Henderson    error_setg(errp, "Setting IV is not supported");
58a3db31b8SRichard Henderson    return -1;
59a3db31b8SRichard Henderson}
60a3db31b8SRichard Henderson
618ee47cddSRichard Hendersonstatic void do_aes_encrypt_ecb(const void *vctx,
628ee47cddSRichard Henderson                               size_t len,
638ee47cddSRichard Henderson                               uint8_t *out,
648ee47cddSRichard Henderson                               const uint8_t *in)
656d92bdf4SRichard Henderson{
668ee47cddSRichard Henderson    const QCryptoCipherBuiltinAESContext *ctx = vctx;
67838e4631SRichard Henderson
68838e4631SRichard Henderson    /* We have already verified that len % AES_BLOCK_SIZE == 0. */
696d92bdf4SRichard Henderson    while (len) {
708ee47cddSRichard Henderson        AES_encrypt(in, out, &ctx->enc);
718ee47cddSRichard Henderson        in += AES_BLOCK_SIZE;
728ee47cddSRichard Henderson        out += AES_BLOCK_SIZE;
736d92bdf4SRichard Henderson        len -= AES_BLOCK_SIZE;
746d92bdf4SRichard Henderson    }
756d92bdf4SRichard Henderson}
766d92bdf4SRichard Henderson
778ee47cddSRichard Hendersonstatic void do_aes_decrypt_ecb(const void *vctx,
788ee47cddSRichard Henderson                               size_t len,
798ee47cddSRichard Henderson                               uint8_t *out,
808ee47cddSRichard Henderson                               const uint8_t *in)
816d92bdf4SRichard Henderson{
828ee47cddSRichard Henderson    const QCryptoCipherBuiltinAESContext *ctx = vctx;
83838e4631SRichard Henderson
84838e4631SRichard Henderson    /* We have already verified that len % AES_BLOCK_SIZE == 0. */
856d92bdf4SRichard Henderson    while (len) {
868ee47cddSRichard Henderson        AES_decrypt(in, out, &ctx->dec);
878ee47cddSRichard Henderson        in += AES_BLOCK_SIZE;
888ee47cddSRichard Henderson        out += AES_BLOCK_SIZE;
896d92bdf4SRichard Henderson        len -= AES_BLOCK_SIZE;
906d92bdf4SRichard Henderson    }
916d92bdf4SRichard Henderson}
926d92bdf4SRichard Henderson
93ef186f4bSRichard Hendersonstatic void do_aes_encrypt_cbc(const AES_KEY *key,
94ef186f4bSRichard Henderson                               size_t len,
95ef186f4bSRichard Henderson                               uint8_t *out,
96ef186f4bSRichard Henderson                               const uint8_t *in,
97ef186f4bSRichard Henderson                               uint8_t *ivec)
98a2d76b6bSRichard Henderson{
99ef186f4bSRichard Henderson    uint8_t tmp[AES_BLOCK_SIZE];
100ef186f4bSRichard Henderson    size_t n;
101a2d76b6bSRichard Henderson
102ef186f4bSRichard Henderson    /* We have already verified that len % AES_BLOCK_SIZE == 0. */
103ef186f4bSRichard Henderson    while (len) {
104a2d76b6bSRichard Henderson        for (n = 0; n < AES_BLOCK_SIZE; ++n) {
105a2d76b6bSRichard Henderson            tmp[n] = in[n] ^ ivec[n];
106a2d76b6bSRichard Henderson        }
107a2d76b6bSRichard Henderson        AES_encrypt(tmp, out, key);
108a2d76b6bSRichard Henderson        memcpy(ivec, out, AES_BLOCK_SIZE);
109a2d76b6bSRichard Henderson        len -= AES_BLOCK_SIZE;
110a2d76b6bSRichard Henderson        in += AES_BLOCK_SIZE;
111a2d76b6bSRichard Henderson        out += AES_BLOCK_SIZE;
112a2d76b6bSRichard Henderson    }
113a2d76b6bSRichard Henderson}
114ef186f4bSRichard Henderson
115ef186f4bSRichard Hendersonstatic void do_aes_decrypt_cbc(const AES_KEY *key,
116ef186f4bSRichard Henderson                               size_t len,
117ef186f4bSRichard Henderson                               uint8_t *out,
118ef186f4bSRichard Henderson                               const uint8_t *in,
119ef186f4bSRichard Henderson                               uint8_t *ivec)
120ef186f4bSRichard Henderson{
121ef186f4bSRichard Henderson    uint8_t tmp[AES_BLOCK_SIZE];
122ef186f4bSRichard Henderson    size_t n;
123ef186f4bSRichard Henderson
124ef186f4bSRichard Henderson    /* We have already verified that len % AES_BLOCK_SIZE == 0. */
125ef186f4bSRichard Henderson    while (len) {
126a2d76b6bSRichard Henderson        memcpy(tmp, in, AES_BLOCK_SIZE);
127a2d76b6bSRichard Henderson        AES_decrypt(in, out, key);
128a2d76b6bSRichard Henderson        for (n = 0; n < AES_BLOCK_SIZE; ++n) {
129a2d76b6bSRichard Henderson            out[n] ^= ivec[n];
130a2d76b6bSRichard Henderson        }
131a2d76b6bSRichard Henderson        memcpy(ivec, tmp, AES_BLOCK_SIZE);
132a2d76b6bSRichard Henderson        len -= AES_BLOCK_SIZE;
133a2d76b6bSRichard Henderson        in += AES_BLOCK_SIZE;
134a2d76b6bSRichard Henderson        out += AES_BLOCK_SIZE;
135a2d76b6bSRichard Henderson    }
136a2d76b6bSRichard Henderson}
137a2d76b6bSRichard Henderson
138a3db31b8SRichard Hendersonstatic int qcrypto_cipher_aes_encrypt_ecb(QCryptoCipher *cipher,
139a3db31b8SRichard Henderson                                          const void *in, void *out,
140a3db31b8SRichard Henderson                                          size_t len, Error **errp)
1416d92bdf4SRichard Henderson{
142a3db31b8SRichard Henderson    QCryptoCipherBuiltinAES *ctx
143a3db31b8SRichard Henderson        = container_of(cipher, QCryptoCipherBuiltinAES, base);
1446d92bdf4SRichard Henderson
145a3db31b8SRichard Henderson    if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
146a3db31b8SRichard Henderson        return -1;
147a3db31b8SRichard Henderson    }
148a3db31b8SRichard Henderson    do_aes_encrypt_ecb(&ctx->key, len, out, in);
149a3db31b8SRichard Henderson    return 0;
1506d92bdf4SRichard Henderson}
1516d92bdf4SRichard Henderson
152a3db31b8SRichard Hendersonstatic int qcrypto_cipher_aes_decrypt_ecb(QCryptoCipher *cipher,
153a3db31b8SRichard Henderson                                          const void *in, void *out,
154a3db31b8SRichard Henderson                                          size_t len, Error **errp)
155a3db31b8SRichard Henderson{
156a3db31b8SRichard Henderson    QCryptoCipherBuiltinAES *ctx
157a3db31b8SRichard Henderson        = container_of(cipher, QCryptoCipherBuiltinAES, base);
158a3db31b8SRichard Henderson
159a3db31b8SRichard Henderson    if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
160a3db31b8SRichard Henderson        return -1;
161a3db31b8SRichard Henderson    }
162a3db31b8SRichard Henderson    do_aes_decrypt_ecb(&ctx->key, len, out, in);
163a3db31b8SRichard Henderson    return 0;
164a3db31b8SRichard Henderson}
165a3db31b8SRichard Henderson
166a3db31b8SRichard Hendersonstatic int qcrypto_cipher_aes_encrypt_cbc(QCryptoCipher *cipher,
167a3db31b8SRichard Henderson                                          const void *in, void *out,
168a3db31b8SRichard Henderson                                          size_t len, Error **errp)
169a3db31b8SRichard Henderson{
170a3db31b8SRichard Henderson    QCryptoCipherBuiltinAES *ctx
171a3db31b8SRichard Henderson        = container_of(cipher, QCryptoCipherBuiltinAES, base);
172a3db31b8SRichard Henderson
173a3db31b8SRichard Henderson    if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
174a3db31b8SRichard Henderson        return -1;
175a3db31b8SRichard Henderson    }
176a3db31b8SRichard Henderson    do_aes_encrypt_cbc(&ctx->key.enc, len, out, in, ctx->iv);
177a3db31b8SRichard Henderson    return 0;
178a3db31b8SRichard Henderson}
179a3db31b8SRichard Henderson
180a3db31b8SRichard Hendersonstatic int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher,
181a3db31b8SRichard Henderson                                          const void *in, void *out,
182a3db31b8SRichard Henderson                                          size_t len, Error **errp)
183a3db31b8SRichard Henderson{
184a3db31b8SRichard Henderson    QCryptoCipherBuiltinAES *ctx
185a3db31b8SRichard Henderson        = container_of(cipher, QCryptoCipherBuiltinAES, base);
186a3db31b8SRichard Henderson
187a3db31b8SRichard Henderson    if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
188a3db31b8SRichard Henderson        return -1;
189a3db31b8SRichard Henderson    }
190a3db31b8SRichard Henderson    do_aes_decrypt_cbc(&ctx->key.dec, len, out, in, ctx->iv);
191a3db31b8SRichard Henderson    return 0;
192a3db31b8SRichard Henderson}
193a3db31b8SRichard Henderson
194a3db31b8SRichard Hendersonstatic int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv,
195a3db31b8SRichard Henderson                             size_t niv, Error **errp)
1966d92bdf4SRichard Henderson{
197a3db31b8SRichard Henderson    QCryptoCipherBuiltinAES *ctx
198a3db31b8SRichard Henderson        = container_of(cipher, QCryptoCipherBuiltinAES, base);
1993eedf5ccSRichard Henderson
2006d92bdf4SRichard Henderson    if (niv != AES_BLOCK_SIZE) {
2016d92bdf4SRichard Henderson        error_setg(errp, "IV must be %d bytes not %zu",
2026d92bdf4SRichard Henderson                   AES_BLOCK_SIZE, niv);
2036d92bdf4SRichard Henderson        return -1;
2046d92bdf4SRichard Henderson    }
2056d92bdf4SRichard Henderson
206a3db31b8SRichard Henderson    memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
2076d92bdf4SRichard Henderson    return 0;
2086d92bdf4SRichard Henderson}
2096d92bdf4SRichard Henderson
210a3db31b8SRichard Hendersonstatic const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_ecb = {
211a3db31b8SRichard Henderson    .cipher_encrypt = qcrypto_cipher_aes_encrypt_ecb,
212a3db31b8SRichard Henderson    .cipher_decrypt = qcrypto_cipher_aes_decrypt_ecb,
213a3db31b8SRichard Henderson    .cipher_setiv = qcrypto_cipher_no_setiv,
214a3db31b8SRichard Henderson    .cipher_free = qcrypto_cipher_ctx_free,
215a3db31b8SRichard Henderson};
216a3db31b8SRichard Henderson
217a3db31b8SRichard Hendersonstatic const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = {
218a3db31b8SRichard Henderson    .cipher_encrypt = qcrypto_cipher_aes_encrypt_cbc,
219a3db31b8SRichard Henderson    .cipher_decrypt = qcrypto_cipher_aes_decrypt_cbc,
220a3db31b8SRichard Henderson    .cipher_setiv = qcrypto_cipher_aes_setiv,
221a3db31b8SRichard Henderson    .cipher_free = qcrypto_cipher_ctx_free,
222a3db31b8SRichard Henderson};
223a3db31b8SRichard Henderson
224*a092c513SMarkus Armbrusterbool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
2256d92bdf4SRichard Henderson                             QCryptoCipherMode mode)
2266d92bdf4SRichard Henderson{
2276d92bdf4SRichard Henderson    switch (alg) {
228*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_128:
229*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_192:
230*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_256:
2316d92bdf4SRichard Henderson        switch (mode) {
2326d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_MODE_ECB:
2336d92bdf4SRichard Henderson        case QCRYPTO_CIPHER_MODE_CBC:
2346d92bdf4SRichard Henderson            return true;
235a3db31b8SRichard Henderson        default:
2366d92bdf4SRichard Henderson            return false;
237a3db31b8SRichard Henderson        }
238a3db31b8SRichard Henderson        break;
2396d92bdf4SRichard Henderson    default:
2406d92bdf4SRichard Henderson        return false;
2416d92bdf4SRichard Henderson    }
2426d92bdf4SRichard Henderson}
2436d92bdf4SRichard Henderson
244*a092c513SMarkus Armbrusterstatic QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
2456d92bdf4SRichard Henderson                                             QCryptoCipherMode mode,
2466d92bdf4SRichard Henderson                                             const uint8_t *key,
2476d92bdf4SRichard Henderson                                             size_t nkey,
2486d92bdf4SRichard Henderson                                             Error **errp)
2496d92bdf4SRichard Henderson{
2506d92bdf4SRichard Henderson    if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
2516d92bdf4SRichard Henderson        return NULL;
2526d92bdf4SRichard Henderson    }
2536d92bdf4SRichard Henderson
2546d92bdf4SRichard Henderson    switch (alg) {
255*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_128:
256*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_192:
257*a092c513SMarkus Armbruster    case QCRYPTO_CIPHER_ALGO_AES_256:
258a3db31b8SRichard Henderson        {
259a3db31b8SRichard Henderson            QCryptoCipherBuiltinAES *ctx;
260a3db31b8SRichard Henderson            const QCryptoCipherDriver *drv;
261a3db31b8SRichard Henderson
262a3db31b8SRichard Henderson            switch (mode) {
263a3db31b8SRichard Henderson            case QCRYPTO_CIPHER_MODE_ECB:
264a3db31b8SRichard Henderson                drv = &qcrypto_cipher_aes_driver_ecb;
265a3db31b8SRichard Henderson                break;
266a3db31b8SRichard Henderson            case QCRYPTO_CIPHER_MODE_CBC:
267a3db31b8SRichard Henderson                drv = &qcrypto_cipher_aes_driver_cbc;
268a3db31b8SRichard Henderson                break;
269a3db31b8SRichard Henderson            default:
270a3db31b8SRichard Henderson                goto bad_mode;
271a3db31b8SRichard Henderson            }
272a3db31b8SRichard Henderson
273a3db31b8SRichard Henderson            ctx = g_new0(QCryptoCipherBuiltinAES, 1);
274a3db31b8SRichard Henderson            ctx->base.driver = drv;
275a3db31b8SRichard Henderson
276a3db31b8SRichard Henderson            if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) {
277a3db31b8SRichard Henderson                error_setg(errp, "Failed to set encryption key");
278a3db31b8SRichard Henderson                goto error;
279a3db31b8SRichard Henderson            }
280a3db31b8SRichard Henderson            if (AES_set_decrypt_key(key, nkey * 8, &ctx->key.dec)) {
281a3db31b8SRichard Henderson                error_setg(errp, "Failed to set decryption key");
282a3db31b8SRichard Henderson                goto error;
283a3db31b8SRichard Henderson            }
284a3db31b8SRichard Henderson
285a3db31b8SRichard Henderson            return &ctx->base;
286a3db31b8SRichard Henderson
287a3db31b8SRichard Henderson        error:
288a3db31b8SRichard Henderson            g_free(ctx);
289a3db31b8SRichard Henderson            return NULL;
290a3db31b8SRichard Henderson        }
291a3db31b8SRichard Henderson
2926d92bdf4SRichard Henderson    default:
2936d92bdf4SRichard Henderson        error_setg(errp,
2946d92bdf4SRichard Henderson                   "Unsupported cipher algorithm %s",
295*a092c513SMarkus Armbruster                   QCryptoCipherAlgo_str(alg));
2966d92bdf4SRichard Henderson        return NULL;
2976d92bdf4SRichard Henderson    }
298a3db31b8SRichard Henderson
299a3db31b8SRichard Henderson bad_mode:
300a3db31b8SRichard Henderson    error_setg(errp, "Unsupported cipher mode %s",
301a3db31b8SRichard Henderson               QCryptoCipherMode_str(mode));
302a3db31b8SRichard Henderson    return NULL;
3036d92bdf4SRichard Henderson}
304