qemu/crypto/cipher-gcrypt.c.inc
<<
>>
Prefs
   1/*
   2 * QEMU Crypto cipher libgcrypt 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 <gcrypt.h>
  22
  23bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
  24                             QCryptoCipherMode mode)
  25{
  26    switch (alg) {
  27    case QCRYPTO_CIPHER_ALG_DES:
  28    case QCRYPTO_CIPHER_ALG_3DES:
  29    case QCRYPTO_CIPHER_ALG_AES_128:
  30    case QCRYPTO_CIPHER_ALG_AES_192:
  31    case QCRYPTO_CIPHER_ALG_AES_256:
  32    case QCRYPTO_CIPHER_ALG_CAST5_128:
  33    case QCRYPTO_CIPHER_ALG_SERPENT_128:
  34    case QCRYPTO_CIPHER_ALG_SERPENT_192:
  35    case QCRYPTO_CIPHER_ALG_SERPENT_256:
  36    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
  37    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
  38        break;
  39    default:
  40        return false;
  41    }
  42
  43    switch (mode) {
  44    case QCRYPTO_CIPHER_MODE_ECB:
  45    case QCRYPTO_CIPHER_MODE_CBC:
  46    case QCRYPTO_CIPHER_MODE_XTS:
  47    case QCRYPTO_CIPHER_MODE_CTR:
  48        return true;
  49    default:
  50        return false;
  51    }
  52}
  53
  54typedef struct QCryptoCipherGcrypt {
  55    QCryptoCipher base;
  56    gcry_cipher_hd_t handle;
  57    size_t blocksize;
  58} QCryptoCipherGcrypt;
  59
  60
  61static void qcrypto_gcrypt_ctx_free(QCryptoCipher *cipher)
  62{
  63    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
  64
  65    gcry_cipher_close(ctx->handle);
  66    g_free(ctx);
  67}
  68
  69static int qcrypto_gcrypt_encrypt(QCryptoCipher *cipher, const void *in,
  70                                  void *out, size_t len, Error **errp)
  71{
  72    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
  73    gcry_error_t err;
  74
  75    if (len & (ctx->blocksize - 1)) {
  76        error_setg(errp, "Length %zu must be a multiple of block size %zu",
  77                   len, ctx->blocksize);
  78        return -1;
  79    }
  80
  81    err = gcry_cipher_encrypt(ctx->handle, out, len, in, len);
  82    if (err != 0) {
  83        error_setg(errp, "Cannot encrypt data: %s", gcry_strerror(err));
  84        return -1;
  85    }
  86
  87    return 0;
  88}
  89
  90
  91static int qcrypto_gcrypt_decrypt(QCryptoCipher *cipher, const void *in,
  92                                  void *out, size_t len, Error **errp)
  93{
  94    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
  95    gcry_error_t err;
  96
  97    if (len & (ctx->blocksize - 1)) {
  98        error_setg(errp, "Length %zu must be a multiple of block size %zu",
  99                   len, ctx->blocksize);
 100        return -1;
 101    }
 102
 103    err = gcry_cipher_decrypt(ctx->handle, out, len, in, len);
 104    if (err != 0) {
 105        error_setg(errp, "Cannot decrypt data: %s",
 106                   gcry_strerror(err));
 107        return -1;
 108    }
 109
 110    return 0;
 111}
 112
 113static int qcrypto_gcrypt_setiv(QCryptoCipher *cipher,
 114                                const uint8_t *iv, size_t niv,
 115                                Error **errp)
 116{
 117    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
 118    gcry_error_t err;
 119
 120    if (niv != ctx->blocksize) {
 121        error_setg(errp, "Expected IV size %zu not %zu",
 122                   ctx->blocksize, niv);
 123        return -1;
 124    }
 125
 126    gcry_cipher_reset(ctx->handle);
 127    err = gcry_cipher_setiv(ctx->handle, iv, niv);
 128    if (err != 0) {
 129        error_setg(errp, "Cannot set IV: %s", gcry_strerror(err));
 130        return -1;
 131    }
 132
 133    return 0;
 134}
 135
 136static int qcrypto_gcrypt_ctr_setiv(QCryptoCipher *cipher,
 137                                    const uint8_t *iv, size_t niv,
 138                                    Error **errp)
 139{
 140    QCryptoCipherGcrypt *ctx = container_of(cipher, QCryptoCipherGcrypt, base);
 141    gcry_error_t err;
 142
 143    if (niv != ctx->blocksize) {
 144        error_setg(errp, "Expected IV size %zu not %zu",
 145                   ctx->blocksize, niv);
 146        return -1;
 147    }
 148
 149    err = gcry_cipher_setctr(ctx->handle, iv, niv);
 150    if (err != 0) {
 151        error_setg(errp, "Cannot set Counter: %s", gcry_strerror(err));
 152        return -1;
 153    }
 154
 155    return 0;
 156}
 157
 158
 159static const struct QCryptoCipherDriver qcrypto_gcrypt_driver = {
 160    .cipher_encrypt = qcrypto_gcrypt_encrypt,
 161    .cipher_decrypt = qcrypto_gcrypt_decrypt,
 162    .cipher_setiv = qcrypto_gcrypt_setiv,
 163    .cipher_free = qcrypto_gcrypt_ctx_free,
 164};
 165
 166static const struct QCryptoCipherDriver qcrypto_gcrypt_ctr_driver = {
 167    .cipher_encrypt = qcrypto_gcrypt_encrypt,
 168    .cipher_decrypt = qcrypto_gcrypt_decrypt,
 169    .cipher_setiv = qcrypto_gcrypt_ctr_setiv,
 170    .cipher_free = qcrypto_gcrypt_ctx_free,
 171};
 172
 173static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgorithm alg,
 174                                             QCryptoCipherMode mode,
 175                                             const uint8_t *key,
 176                                             size_t nkey,
 177                                             Error **errp)
 178{
 179    QCryptoCipherGcrypt *ctx;
 180    const QCryptoCipherDriver *drv;
 181    gcry_error_t err;
 182    int gcryalg, gcrymode;
 183
 184    if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
 185        return NULL;
 186    }
 187
 188    switch (alg) {
 189    case QCRYPTO_CIPHER_ALG_DES:
 190        gcryalg = GCRY_CIPHER_DES;
 191        break;
 192    case QCRYPTO_CIPHER_ALG_3DES:
 193        gcryalg = GCRY_CIPHER_3DES;
 194        break;
 195    case QCRYPTO_CIPHER_ALG_AES_128:
 196        gcryalg = GCRY_CIPHER_AES128;
 197        break;
 198    case QCRYPTO_CIPHER_ALG_AES_192:
 199        gcryalg = GCRY_CIPHER_AES192;
 200        break;
 201    case QCRYPTO_CIPHER_ALG_AES_256:
 202        gcryalg = GCRY_CIPHER_AES256;
 203        break;
 204    case QCRYPTO_CIPHER_ALG_CAST5_128:
 205        gcryalg = GCRY_CIPHER_CAST5;
 206        break;
 207    case QCRYPTO_CIPHER_ALG_SERPENT_128:
 208        gcryalg = GCRY_CIPHER_SERPENT128;
 209        break;
 210    case QCRYPTO_CIPHER_ALG_SERPENT_192:
 211        gcryalg = GCRY_CIPHER_SERPENT192;
 212        break;
 213    case QCRYPTO_CIPHER_ALG_SERPENT_256:
 214        gcryalg = GCRY_CIPHER_SERPENT256;
 215        break;
 216    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
 217        gcryalg = GCRY_CIPHER_TWOFISH128;
 218        break;
 219    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
 220        gcryalg = GCRY_CIPHER_TWOFISH;
 221        break;
 222    default:
 223        error_setg(errp, "Unsupported cipher algorithm %s",
 224                   QCryptoCipherAlgorithm_str(alg));
 225        return NULL;
 226    }
 227
 228    drv = &qcrypto_gcrypt_driver;
 229    switch (mode) {
 230    case QCRYPTO_CIPHER_MODE_ECB:
 231        gcrymode = GCRY_CIPHER_MODE_ECB;
 232        break;
 233    case QCRYPTO_CIPHER_MODE_XTS:
 234        gcrymode = GCRY_CIPHER_MODE_XTS;
 235        break;
 236    case QCRYPTO_CIPHER_MODE_CBC:
 237        gcrymode = GCRY_CIPHER_MODE_CBC;
 238        break;
 239    case QCRYPTO_CIPHER_MODE_CTR:
 240        drv = &qcrypto_gcrypt_ctr_driver;
 241        gcrymode = GCRY_CIPHER_MODE_CTR;
 242        break;
 243    default:
 244        error_setg(errp, "Unsupported cipher mode %s",
 245                   QCryptoCipherMode_str(mode));
 246        return NULL;
 247    }
 248
 249    ctx = g_new0(QCryptoCipherGcrypt, 1);
 250    ctx->base.driver = drv;
 251
 252    err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
 253    if (err != 0) {
 254        error_setg(errp, "Cannot initialize cipher: %s",
 255                   gcry_strerror(err));
 256        goto error;
 257    }
 258    ctx->blocksize = gcry_cipher_get_algo_blklen(gcryalg);
 259
 260    err = gcry_cipher_setkey(ctx->handle, key, nkey);
 261    if (err != 0) {
 262        error_setg(errp, "Cannot set key: %s", gcry_strerror(err));
 263        goto error;
 264    }
 265
 266    return &ctx->base;
 267
 268 error:
 269    gcry_cipher_close(ctx->handle);
 270    g_free(ctx);
 271    return NULL;
 272}
 273