qemu/crypto/cipher-gcrypt.c
<<
>>
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 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/xts.h"
  23
  24#include <gcrypt.h>
  25
  26
  27bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg,
  28                             QCryptoCipherMode mode)
  29{
  30    switch (alg) {
  31    case QCRYPTO_CIPHER_ALG_DES_RFB:
  32    case QCRYPTO_CIPHER_ALG_AES_128:
  33    case QCRYPTO_CIPHER_ALG_AES_192:
  34    case QCRYPTO_CIPHER_ALG_AES_256:
  35    case QCRYPTO_CIPHER_ALG_CAST5_128:
  36    case QCRYPTO_CIPHER_ALG_SERPENT_128:
  37    case QCRYPTO_CIPHER_ALG_SERPENT_192:
  38    case QCRYPTO_CIPHER_ALG_SERPENT_256:
  39    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
  40    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
  41        break;
  42    default:
  43        return false;
  44    }
  45
  46    switch (mode) {
  47    case QCRYPTO_CIPHER_MODE_ECB:
  48    case QCRYPTO_CIPHER_MODE_CBC:
  49    case QCRYPTO_CIPHER_MODE_XTS:
  50    case QCRYPTO_CIPHER_MODE_CTR:
  51        return true;
  52    default:
  53        return false;
  54    }
  55}
  56
  57typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
  58struct QCryptoCipherGcrypt {
  59    gcry_cipher_hd_t handle;
  60    gcry_cipher_hd_t tweakhandle;
  61    size_t blocksize;
  62    /* Initialization vector or Counter */
  63    uint8_t *iv;
  64};
  65
  66QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
  67                                  QCryptoCipherMode mode,
  68                                  const uint8_t *key, size_t nkey,
  69                                  Error **errp)
  70{
  71    QCryptoCipher *cipher;
  72    QCryptoCipherGcrypt *ctx;
  73    gcry_error_t err;
  74    int gcryalg, gcrymode;
  75
  76    switch (mode) {
  77    case QCRYPTO_CIPHER_MODE_ECB:
  78    case QCRYPTO_CIPHER_MODE_XTS:
  79        gcrymode = GCRY_CIPHER_MODE_ECB;
  80        break;
  81    case QCRYPTO_CIPHER_MODE_CBC:
  82        gcrymode = GCRY_CIPHER_MODE_CBC;
  83        break;
  84    case QCRYPTO_CIPHER_MODE_CTR:
  85        gcrymode = GCRY_CIPHER_MODE_CTR;
  86        break;
  87    default:
  88        error_setg(errp, "Unsupported cipher mode %s",
  89                   QCryptoCipherMode_lookup[mode]);
  90        return NULL;
  91    }
  92
  93    if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
  94        return NULL;
  95    }
  96
  97    switch (alg) {
  98    case QCRYPTO_CIPHER_ALG_DES_RFB:
  99        gcryalg = GCRY_CIPHER_DES;
 100        break;
 101
 102    case QCRYPTO_CIPHER_ALG_AES_128:
 103        gcryalg = GCRY_CIPHER_AES128;
 104        break;
 105
 106    case QCRYPTO_CIPHER_ALG_AES_192:
 107        gcryalg = GCRY_CIPHER_AES192;
 108        break;
 109
 110    case QCRYPTO_CIPHER_ALG_AES_256:
 111        gcryalg = GCRY_CIPHER_AES256;
 112        break;
 113
 114    case QCRYPTO_CIPHER_ALG_CAST5_128:
 115        gcryalg = GCRY_CIPHER_CAST5;
 116        break;
 117
 118    case QCRYPTO_CIPHER_ALG_SERPENT_128:
 119        gcryalg = GCRY_CIPHER_SERPENT128;
 120        break;
 121
 122    case QCRYPTO_CIPHER_ALG_SERPENT_192:
 123        gcryalg = GCRY_CIPHER_SERPENT192;
 124        break;
 125
 126    case QCRYPTO_CIPHER_ALG_SERPENT_256:
 127        gcryalg = GCRY_CIPHER_SERPENT256;
 128        break;
 129
 130    case QCRYPTO_CIPHER_ALG_TWOFISH_128:
 131        gcryalg = GCRY_CIPHER_TWOFISH128;
 132        break;
 133
 134    case QCRYPTO_CIPHER_ALG_TWOFISH_256:
 135        gcryalg = GCRY_CIPHER_TWOFISH;
 136        break;
 137
 138    default:
 139        error_setg(errp, "Unsupported cipher algorithm %s",
 140                   QCryptoCipherAlgorithm_lookup[alg]);
 141        return NULL;
 142    }
 143
 144    cipher = g_new0(QCryptoCipher, 1);
 145    cipher->alg = alg;
 146    cipher->mode = mode;
 147
 148    ctx = g_new0(QCryptoCipherGcrypt, 1);
 149
 150    err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
 151    if (err != 0) {
 152        error_setg(errp, "Cannot initialize cipher: %s",
 153                   gcry_strerror(err));
 154        goto error;
 155    }
 156    if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
 157        err = gcry_cipher_open(&ctx->tweakhandle, gcryalg, gcrymode, 0);
 158        if (err != 0) {
 159            error_setg(errp, "Cannot initialize cipher: %s",
 160                       gcry_strerror(err));
 161            goto error;
 162        }
 163    }
 164
 165    if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
 166        /* We're using standard DES cipher from gcrypt, so we need
 167         * to munge the key so that the results are the same as the
 168         * bizarre RFB variant of DES :-)
 169         */
 170        uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
 171        err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
 172        g_free(rfbkey);
 173        ctx->blocksize = 8;
 174    } else {
 175        if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
 176            nkey /= 2;
 177            err = gcry_cipher_setkey(ctx->handle, key, nkey);
 178            if (err != 0) {
 179                error_setg(errp, "Cannot set key: %s",
 180                           gcry_strerror(err));
 181                goto error;
 182            }
 183            err = gcry_cipher_setkey(ctx->tweakhandle, key + nkey, nkey);
 184        } else {
 185            err = gcry_cipher_setkey(ctx->handle, key, nkey);
 186        }
 187        if (err != 0) {
 188            error_setg(errp, "Cannot set key: %s",
 189                       gcry_strerror(err));
 190            goto error;
 191        }
 192        switch (cipher->alg) {
 193        case QCRYPTO_CIPHER_ALG_AES_128:
 194        case QCRYPTO_CIPHER_ALG_AES_192:
 195        case QCRYPTO_CIPHER_ALG_AES_256:
 196        case QCRYPTO_CIPHER_ALG_SERPENT_128:
 197        case QCRYPTO_CIPHER_ALG_SERPENT_192:
 198        case QCRYPTO_CIPHER_ALG_SERPENT_256:
 199        case QCRYPTO_CIPHER_ALG_TWOFISH_128:
 200        case QCRYPTO_CIPHER_ALG_TWOFISH_256:
 201            ctx->blocksize = 16;
 202            break;
 203        case QCRYPTO_CIPHER_ALG_CAST5_128:
 204            ctx->blocksize = 8;
 205            break;
 206        default:
 207            g_assert_not_reached();
 208        }
 209    }
 210
 211    if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
 212        if (ctx->blocksize != XTS_BLOCK_SIZE) {
 213            error_setg(errp,
 214                       "Cipher block size %zu must equal XTS block size %d",
 215                       ctx->blocksize, XTS_BLOCK_SIZE);
 216            goto error;
 217        }
 218        ctx->iv = g_new0(uint8_t, ctx->blocksize);
 219    }
 220
 221    cipher->opaque = ctx;
 222    return cipher;
 223
 224 error:
 225    gcry_cipher_close(ctx->handle);
 226    if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
 227        gcry_cipher_close(ctx->tweakhandle);
 228    }
 229    g_free(ctx);
 230    g_free(cipher);
 231    return NULL;
 232}
 233
 234
 235void qcrypto_cipher_free(QCryptoCipher *cipher)
 236{
 237    QCryptoCipherGcrypt *ctx;
 238    if (!cipher) {
 239        return;
 240    }
 241    ctx = cipher->opaque;
 242    gcry_cipher_close(ctx->handle);
 243    if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
 244        gcry_cipher_close(ctx->tweakhandle);
 245    }
 246    g_free(ctx->iv);
 247    g_free(ctx);
 248    g_free(cipher);
 249}
 250
 251
 252static void qcrypto_gcrypt_xts_encrypt(const void *ctx,
 253                                       size_t length,
 254                                       uint8_t *dst,
 255                                       const uint8_t *src)
 256{
 257    gcry_error_t err;
 258    err = gcry_cipher_encrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
 259    g_assert(err == 0);
 260}
 261
 262static void qcrypto_gcrypt_xts_decrypt(const void *ctx,
 263                                       size_t length,
 264                                       uint8_t *dst,
 265                                       const uint8_t *src)
 266{
 267    gcry_error_t err;
 268    err = gcry_cipher_decrypt((gcry_cipher_hd_t)ctx, dst, length, src, length);
 269    g_assert(err == 0);
 270}
 271
 272int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
 273                           const void *in,
 274                           void *out,
 275                           size_t len,
 276                           Error **errp)
 277{
 278    QCryptoCipherGcrypt *ctx = cipher->opaque;
 279    gcry_error_t err;
 280
 281    if (len % ctx->blocksize) {
 282        error_setg(errp, "Length %zu must be a multiple of block size %zu",
 283                   len, ctx->blocksize);
 284        return -1;
 285    }
 286
 287    if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
 288        xts_encrypt(ctx->handle, ctx->tweakhandle,
 289                    qcrypto_gcrypt_xts_encrypt,
 290                    qcrypto_gcrypt_xts_decrypt,
 291                    ctx->iv, len, out, in);
 292    } else {
 293        err = gcry_cipher_encrypt(ctx->handle,
 294                                  out, len,
 295                                  in, len);
 296        if (err != 0) {
 297            error_setg(errp, "Cannot encrypt data: %s",
 298                       gcry_strerror(err));
 299            return -1;
 300        }
 301    }
 302
 303    return 0;
 304}
 305
 306
 307int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
 308                           const void *in,
 309                           void *out,
 310                           size_t len,
 311                           Error **errp)
 312{
 313    QCryptoCipherGcrypt *ctx = cipher->opaque;
 314    gcry_error_t err;
 315
 316    if (len % ctx->blocksize) {
 317        error_setg(errp, "Length %zu must be a multiple of block size %zu",
 318                   len, ctx->blocksize);
 319        return -1;
 320    }
 321
 322    if (cipher->mode == QCRYPTO_CIPHER_MODE_XTS) {
 323        xts_decrypt(ctx->handle, ctx->tweakhandle,
 324                    qcrypto_gcrypt_xts_encrypt,
 325                    qcrypto_gcrypt_xts_decrypt,
 326                    ctx->iv, len, out, in);
 327    } else {
 328        err = gcry_cipher_decrypt(ctx->handle,
 329                                  out, len,
 330                                  in, len);
 331        if (err != 0) {
 332            error_setg(errp, "Cannot decrypt data: %s",
 333                       gcry_strerror(err));
 334            return -1;
 335        }
 336    }
 337
 338    return 0;
 339}
 340
 341int qcrypto_cipher_setiv(QCryptoCipher *cipher,
 342                         const uint8_t *iv, size_t niv,
 343                         Error **errp)
 344{
 345    QCryptoCipherGcrypt *ctx = cipher->opaque;
 346    gcry_error_t err;
 347
 348    if (niv != ctx->blocksize) {
 349        error_setg(errp, "Expected IV size %zu not %zu",
 350                   ctx->blocksize, niv);
 351        return -1;
 352    }
 353
 354    if (ctx->iv) {
 355        memcpy(ctx->iv, iv, niv);
 356    } else {
 357        if (cipher->mode == QCRYPTO_CIPHER_MODE_CTR) {
 358            err = gcry_cipher_setctr(ctx->handle, iv, niv);
 359            if (err != 0) {
 360                error_setg(errp, "Cannot set Counter: %s",
 361                       gcry_strerror(err));
 362                return -1;
 363            }
 364        } else {
 365            gcry_cipher_reset(ctx->handle);
 366            err = gcry_cipher_setiv(ctx->handle, iv, niv);
 367            if (err != 0) {
 368                error_setg(errp, "Cannot set IV: %s",
 369                       gcry_strerror(err));
 370                return -1;
 371            }
 372        }
 373    }
 374
 375    return 0;
 376}
 377