qemu/crypto/cipher-builtin.c
<<
>>
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 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 "qemu/osdep.h"
  22#include "crypto/aes.h"
  23#include "crypto/desrfb.h"
  24#include "crypto/xts.h"
  25
  26typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
  27struct QCryptoCipherBuiltinAESContext {
  28    AES_KEY enc;
  29    AES_KEY dec;
  30};
  31typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
  32struct QCryptoCipherBuiltinAES {
  33    QCryptoCipherBuiltinAESContext key;
  34    QCryptoCipherBuiltinAESContext key_tweak;
  35    uint8_t iv[AES_BLOCK_SIZE];
  36};
  37typedef struct QCryptoCipherBuiltinDESRFB QCryptoCipherBuiltinDESRFB;
  38struct QCryptoCipherBuiltinDESRFB {
  39    uint8_t *key;
  40    size_t nkey;
  41};
  42
  43typedef struct QCryptoCipherBuiltin QCryptoCipherBuiltin;
  44struct QCryptoCipherBuiltin {
  45    union {
  46        QCryptoCipherBuiltinAES aes;
  47        QCryptoCipherBuiltinDESRFB desrfb;
  48    } state;
  49    size_t blocksize;
  50    void (*free)(QCryptoCipher *cipher);
  51    int (*setiv)(QCryptoCipher *cipher,
  52                 const uint8_t *iv, size_t niv,
  53                 Error **errp);
  54    int (*encrypt)(QCryptoCipher *cipher,
  55                   const void *in,
  56                   void *out,
  57                   size_t len,
  58                   Error **errp);
  59    int (*decrypt)(QCryptoCipher *cipher,
  60                   const void *in,
  61                   void *out,
  62                   size_t len,
  63                   Error **errp);
  64};
  65
  66
  67static void qcrypto_cipher_free_aes(QCryptoCipher *cipher)
  68{
  69    QCryptoCipherBuiltin *ctxt = cipher->opaque;
  70
  71    g_free(ctxt);
  72    cipher->opaque = NULL;
  73}
  74
  75
  76static void qcrypto_cipher_aes_ecb_encrypt(AES_KEY *key,
  77                                           const void *in,
  78                                           void *out,
  79                                           size_t len)
  80{
  81    const uint8_t *inptr = in;
  82    uint8_t *outptr = out;
  83    while (len) {
  84        if (len > AES_BLOCK_SIZE) {
  85            AES_encrypt(inptr, outptr, key);
  86            inptr += AES_BLOCK_SIZE;
  87            outptr += AES_BLOCK_SIZE;
  88            len -= AES_BLOCK_SIZE;
  89        } else {
  90            uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
  91            memcpy(tmp1, inptr, len);
  92            /* Fill with 0 to avoid valgrind uninitialized reads */
  93            memset(tmp1 + len, 0, sizeof(tmp1) - len);
  94            AES_encrypt(tmp1, tmp2, key);
  95            memcpy(outptr, tmp2, len);
  96            len = 0;
  97        }
  98    }
  99}
 100
 101
 102static void qcrypto_cipher_aes_ecb_decrypt(AES_KEY *key,
 103                                           const void *in,
 104                                           void *out,
 105                                           size_t len)
 106{
 107    const uint8_t *inptr = in;
 108    uint8_t *outptr = out;
 109    while (len) {
 110        if (len > AES_BLOCK_SIZE) {
 111            AES_decrypt(inptr, outptr, key);
 112            inptr += AES_BLOCK_SIZE;
 113            outptr += AES_BLOCK_SIZE;
 114            len -= AES_BLOCK_SIZE;
 115        } else {
 116            uint8_t tmp1[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
 117            memcpy(tmp1, inptr, len);
 118            /* Fill with 0 to avoid valgrind uninitialized reads */
 119            memset(tmp1 + len, 0, sizeof(tmp1) - len);
 120            AES_decrypt(tmp1, tmp2, key);
 121            memcpy(outptr, tmp2, len);
 122            len = 0;
 123        }
 124    }
 125}
 126
 127
 128static void qcrypto_cipher_aes_xts_encrypt(const void *ctx,
 129                                           size_t length,
 130                                           uint8_t *dst,
 131                                           const uint8_t *src)
 132{
 133    const QCryptoCipherBuiltinAESContext *aesctx = ctx;
 134
 135    qcrypto_cipher_aes_ecb_encrypt((AES_KEY *)&aesctx->enc,
 136                                   src, dst, length);
 137}
 138
 139
 140static void qcrypto_cipher_aes_xts_decrypt(const void *ctx,
 141                                           size_t length,
 142                                           uint8_t *dst,
 143                                           const uint8_t *src)
 144{
 145    const QCryptoCipherBuiltinAESContext *aesctx = ctx;
 146
 147    qcrypto_cipher_aes_ecb_decrypt((AES_KEY *)&aesctx->dec,
 148                                   src, dst, length);
 149}
 150
 151
 152static int qcrypto_cipher_encrypt_aes(QCryptoCipher *cipher,
 153                                      const void *in,
 154                                      void *out,
 155                                      size_t len,
 156                                      Error **errp)
 157{
 158    QCryptoCipherBuiltin *ctxt = cipher->opaque;
 159
 160    switch (cipher->mode) {
 161    case QCRYPTO_CIPHER_MODE_ECB:
 162        qcrypto_cipher_aes_ecb_encrypt(&ctxt->state.aes.key.enc,
 163                                       in, out, len);
 164        break;
 165    case QCRYPTO_CIPHER_MODE_CBC:
 166        AES_cbc_encrypt(in, out, len,
 167                        &ctxt->state.aes.key.enc,
 168                        ctxt->state.aes.iv, 1);
 169        break;
 170    case QCRYPTO_CIPHER_MODE_XTS:
 171        xts_encrypt(&ctxt->state.aes.key,
 172                    &ctxt->state.aes.key_tweak,
 173                    qcrypto_cipher_aes_xts_encrypt,
 174                    qcrypto_cipher_aes_xts_decrypt,
 175                    ctxt->state.aes.iv,
 176                    len, out, in);
 177        break;
 178    default:
 179        g_assert_not_reached();
 180    }
 181
 182    return 0;
 183}
 184
 185
 186static int qcrypto_cipher_decrypt_aes(QCryptoCipher *cipher,
 187                                      const void *in,
 188                                      void *out,
 189                                      size_t len,
 190                                      Error **errp)
 191{
 192    QCryptoCipherBuiltin *ctxt = cipher->opaque;
 193
 194    switch (cipher->mode) {
 195    case QCRYPTO_CIPHER_MODE_ECB:
 196        qcrypto_cipher_aes_ecb_decrypt(&ctxt->state.aes.key.dec,
 197                                       in, out, len);
 198        break;
 199    case QCRYPTO_CIPHER_MODE_CBC:
 200        AES_cbc_encrypt(in, out, len,
 201                        &ctxt->state.aes.key.dec,
 202                        ctxt->state.aes.iv, 0);
 203        break;
 204    case QCRYPTO_CIPHER_MODE_XTS:
 205        xts_decrypt(&ctxt->state.aes.key,
 206                    &ctxt->state.aes.key_tweak,
 207                    qcrypto_cipher_aes_xts_encrypt,
 208                    qcrypto_cipher_aes_xts_decrypt,
 209                    ctxt->state.aes.iv,
 210                    len, out, in);
 211        break;
 212    default:
 213        g_assert_not_reached();
 214    }
 215
 216    return 0;
 217}
 218
 219static int qcrypto_cipher_setiv_aes(QCryptoCipher *cipher,
 220                                     const uint8_t *iv, size_t niv,
 221                                     Error **errp)
 222{
 223    QCryptoCipherBuiltin *ctxt = cipher->opaque;
 224    if (niv != AES_BLOCK_SIZE) {
 225        error_setg(errp, "IV must be %d bytes not %zu",
 226                   AES_BLOCK_SIZE, niv);
 227        return -1;
 228    }
 229
 230    memcpy(ctxt->state.aes.iv, iv, AES_BLOCK_SIZE);
 231
 232    return 0;
 233}
 234
 235
 236
 237
 238static int qcrypto_cipher_init_aes(QCryptoCipher *cipher,
 239                                   const uint8_t *key, size_t nkey,
 240                                   Error **errp)
 241{
 242    QCryptoCipherBuiltin *ctxt;
 243
 244    if (cipher->mode != QCRYPTO_CIPHER_MODE_CBC &&
 245        cipher->mode != QCRYPTO_CIPHER_MODE_ECB &&
 246        cipher->mode != QCRYPTO_CIPHER_MODE_XTS) {
 247        error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
 248        return -1;
 249    }
 250
 251    ctxt = g_new0(QCryptoCipherBuiltin, 1);
 252
 253    if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
 254        if (AES_set_encrypt_key(key, nkey * 4, &ctxt->state.aes.key.enc) != 0) {
 255            error_setg(errp, "Failed to set encryption key");
 256            goto error;
 257        }
 258
 259        if (AES_set_decrypt_key(key, nkey * 4, &ctxt->state.aes.key.dec) != 0) {
 260            error_setg(errp, "Failed to set decryption key");
 261            goto error;
 262        }
 263
 264        if (AES_set_encrypt_key(key + (nkey / 2), nkey * 4,
 265                                &ctxt->state.aes.key_tweak.enc) != 0) {
 266            error_setg(errp, "Failed to set encryption key");
 267            goto error;
 268        }
 269
 270        if (AES_set_decrypt_key(key + (nkey / 2), nkey * 4,
 271                                &ctxt->state.aes.key_tweak.dec) != 0) {
 272            error_setg(errp, "Failed to set decryption key");
 273            goto error;
 274        }
 275    } else {
 276        if (AES_set_encrypt_key(key, nkey * 8, &ctxt->state.aes.key.enc) != 0) {
 277            error_setg(errp, "Failed to set encryption key");
 278            goto error;
 279        }
 280
 281        if (AES_set_decrypt_key(key, nkey * 8, &ctxt->state.aes.key.dec) != 0) {
 282            error_setg(errp, "Failed to set decryption key");
 283            goto error;
 284        }
 285    }
 286
 287    ctxt->blocksize = AES_BLOCK_SIZE;
 288    ctxt->free = qcrypto_cipher_free_aes;
 289    ctxt->setiv = qcrypto_cipher_setiv_aes;
 290    ctxt->encrypt = qcrypto_cipher_encrypt_aes;
 291    ctxt->decrypt = qcrypto_cipher_decrypt_aes;
 292
 293    cipher->opaque = ctxt;
 294
 295    return 0;
 296
 297 error:
 298    g_free(ctxt);
 299    return -1;
 300}
 301
 302
 303static void qcrypto_cipher_free_des_rfb(QCryptoCipher *cipher)
 304{
 305    QCryptoCipherBuiltin *ctxt = cipher->opaque;
 306
 307    g_free(ctxt->state.desrfb.key);
 308    g_free(ctxt);
 309    cipher->opaque = NULL;
 310}
 311
 312
 313static int qcrypto_cipher_encrypt_des_rfb(QCryptoCipher *cipher,
 314                                          const void *in,
 315                                          void *out,
 316                                          size_t len,
 317                                          Error **errp)
 318{
 319    QCryptoCipherBuiltin *ctxt = cipher->opaque;
 320    size_t i;
 321
 322    if (len % 8) {
 323        error_setg(errp, "Buffer size must be multiple of 8 not %zu",
 324                   len);
 325        return -1;
 326    }
 327
 328    deskey(ctxt->state.desrfb.key, EN0);
 329
 330    for (i = 0; i < len; i += 8) {
 331        des((void *)in + i, out + i);
 332    }
 333
 334    return 0;
 335}
 336
 337
 338static int qcrypto_cipher_decrypt_des_rfb(QCryptoCipher *cipher,
 339                                          const void *in,
 340                                          void *out,
 341                                          size_t len,
 342                                          Error **errp)
 343{
 344    QCryptoCipherBuiltin *ctxt = cipher->opaque;
 345    size_t i;
 346
 347    if (len % 8) {
 348        error_setg(errp, "Buffer size must be multiple of 8 not %zu",
 349                   len);
 350        return -1;
 351    }
 352
 353    deskey(ctxt->state.desrfb.key, DE1);
 354
 355    for (i = 0; i < len; i += 8) {
 356        des((void *)in + i, out + i);
 357    }
 358
 359    return 0;
 360}
 361
 362
 363static int qcrypto_cipher_setiv_des_rfb(QCryptoCipher *cipher,
 364                                        const uint8_t *iv, size_t niv,
 365                                        Error **errp)
 366{
 367    error_setg(errp, "Setting IV is not supported");
 368    return -1;
 369}
 370
 371
 372static int qcrypto_cipher_init_des_rfb(QCryptoCipher *cipher,
 373                                       const uint8_t *key, size_t nkey,
 374                                       Error **errp)
 375{
 376    QCryptoCipherBuiltin *ctxt;
 377
 378    if (cipher->mode != QCRYPTO_CIPHER_MODE_ECB) {
 379        error_setg(errp, "Unsupported cipher mode %d", cipher->mode);
 380        return -1;
 381    }
 382
 383    ctxt = g_new0(QCryptoCipherBuiltin, 1);
 384
 385    ctxt->state.desrfb.key = g_new0(uint8_t, nkey);
 386    memcpy(ctxt->state.desrfb.key, key, nkey);
 387    ctxt->state.desrfb.nkey = nkey;
 388
 389    ctxt->blocksize = 8;
 390    ctxt->free = qcrypto_cipher_free_des_rfb;
 391    ctxt->setiv = qcrypto_cipher_setiv_des_rfb;
 392    ctxt->encrypt = qcrypto_cipher_encrypt_des_rfb;
 393    ctxt->decrypt = qcrypto_cipher_decrypt_des_rfb;
 394
 395    cipher->opaque = ctxt;
 396
 397    return 0;
 398}
 399
 400
 401bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
 402{
 403    switch (alg) {
 404    case QCRYPTO_CIPHER_ALG_DES_RFB:
 405    case QCRYPTO_CIPHER_ALG_AES_128:
 406    case QCRYPTO_CIPHER_ALG_AES_192:
 407    case QCRYPTO_CIPHER_ALG_AES_256:
 408        return true;
 409    default:
 410        return false;
 411    }
 412}
 413
 414
 415QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
 416                                  QCryptoCipherMode mode,
 417                                  const uint8_t *key, size_t nkey,
 418                                  Error **errp)
 419{
 420    QCryptoCipher *cipher;
 421
 422    cipher = g_new0(QCryptoCipher, 1);
 423    cipher->alg = alg;
 424    cipher->mode = mode;
 425
 426    if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
 427        goto error;
 428    }
 429
 430    switch (cipher->alg) {
 431    case QCRYPTO_CIPHER_ALG_DES_RFB:
 432        if (qcrypto_cipher_init_des_rfb(cipher, key, nkey, errp) < 0) {
 433            goto error;
 434        }
 435        break;
 436    case QCRYPTO_CIPHER_ALG_AES_128:
 437    case QCRYPTO_CIPHER_ALG_AES_192:
 438    case QCRYPTO_CIPHER_ALG_AES_256:
 439        if (qcrypto_cipher_init_aes(cipher, key, nkey, errp) < 0) {
 440            goto error;
 441        }
 442        break;
 443    default:
 444        error_setg(errp,
 445                   "Unsupported cipher algorithm %d", cipher->alg);
 446        goto error;
 447    }
 448
 449    return cipher;
 450
 451 error:
 452    g_free(cipher);
 453    return NULL;
 454}
 455
 456void qcrypto_cipher_free(QCryptoCipher *cipher)
 457{
 458    QCryptoCipherBuiltin *ctxt;
 459
 460    if (!cipher) {
 461        return;
 462    }
 463
 464    ctxt = cipher->opaque;
 465    ctxt->free(cipher);
 466    g_free(cipher);
 467}
 468
 469
 470int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
 471                           const void *in,
 472                           void *out,
 473                           size_t len,
 474                           Error **errp)
 475{
 476    QCryptoCipherBuiltin *ctxt = cipher->opaque;
 477
 478    if (len % ctxt->blocksize) {
 479        error_setg(errp, "Length %zu must be a multiple of block size %zu",
 480                   len, ctxt->blocksize);
 481        return -1;
 482    }
 483
 484    return ctxt->encrypt(cipher, in, out, len, errp);
 485}
 486
 487
 488int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
 489                           const void *in,
 490                           void *out,
 491                           size_t len,
 492                           Error **errp)
 493{
 494    QCryptoCipherBuiltin *ctxt = cipher->opaque;
 495
 496    if (len % ctxt->blocksize) {
 497        error_setg(errp, "Length %zu must be a multiple of block size %zu",
 498                   len, ctxt->blocksize);
 499        return -1;
 500    }
 501
 502    return ctxt->decrypt(cipher, in, out, len, errp);
 503}
 504
 505
 506int qcrypto_cipher_setiv(QCryptoCipher *cipher,
 507                         const uint8_t *iv, size_t niv,
 508                         Error **errp)
 509{
 510    QCryptoCipherBuiltin *ctxt = cipher->opaque;
 511
 512    return ctxt->setiv(cipher, iv, niv, errp);
 513}
 514