qemu/crypto/cipher-builtin.c.inc
<<
>>
Prefs
   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
  23typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
  24struct QCryptoCipherBuiltinAESContext {
  25    AES_KEY enc;
  26    AES_KEY dec;
  27};
  28
  29typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
  30struct QCryptoCipherBuiltinAES {
  31    QCryptoCipher base;
  32    QCryptoCipherBuiltinAESContext key;
  33    uint8_t iv[AES_BLOCK_SIZE];
  34};
  35
  36
  37static 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
  48static void qcrypto_cipher_ctx_free(QCryptoCipher *cipher)
  49{
  50    g_free(cipher);
  51}
  52
  53static 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
  61static 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
  77static 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
  93static 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
 115static 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
 138static 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
 152static 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
 166static 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
 180static 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
 194static 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
 210static 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
 217static 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
 224bool 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
 244static 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}
 304