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 <gcrypt.h>
  22
  23
  24bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
  25{
  26    switch (alg) {
  27    case QCRYPTO_CIPHER_ALG_DES_RFB:
  28    case QCRYPTO_CIPHER_ALG_AES_128:
  29    case QCRYPTO_CIPHER_ALG_AES_192:
  30    case QCRYPTO_CIPHER_ALG_AES_256:
  31        return true;
  32    default:
  33        return false;
  34    }
  35}
  36
  37
  38QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
  39                                  QCryptoCipherMode mode,
  40                                  const uint8_t *key, size_t nkey,
  41                                  Error **errp)
  42{
  43    QCryptoCipher *cipher;
  44    gcry_cipher_hd_t handle;
  45    gcry_error_t err;
  46    int gcryalg, gcrymode;
  47
  48    switch (mode) {
  49    case QCRYPTO_CIPHER_MODE_ECB:
  50        gcrymode = GCRY_CIPHER_MODE_ECB;
  51        break;
  52    case QCRYPTO_CIPHER_MODE_CBC:
  53        gcrymode = GCRY_CIPHER_MODE_CBC;
  54        break;
  55    default:
  56        error_setg(errp, "Unsupported cipher mode %d", mode);
  57        return NULL;
  58    }
  59
  60    if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
  61        return NULL;
  62    }
  63
  64    switch (alg) {
  65    case QCRYPTO_CIPHER_ALG_DES_RFB:
  66        gcryalg = GCRY_CIPHER_DES;
  67        break;
  68
  69    case QCRYPTO_CIPHER_ALG_AES_128:
  70        gcryalg = GCRY_CIPHER_AES128;
  71        break;
  72
  73    case QCRYPTO_CIPHER_ALG_AES_192:
  74        gcryalg = GCRY_CIPHER_AES192;
  75        break;
  76
  77    case QCRYPTO_CIPHER_ALG_AES_256:
  78        gcryalg = GCRY_CIPHER_AES256;
  79        break;
  80
  81    default:
  82        error_setg(errp, "Unsupported cipher algorithm %d", alg);
  83        return NULL;
  84    }
  85
  86    cipher = g_new0(QCryptoCipher, 1);
  87    cipher->alg = alg;
  88    cipher->mode = mode;
  89
  90    err = gcry_cipher_open(&handle, gcryalg, gcrymode, 0);
  91    if (err != 0) {
  92        error_setg(errp, "Cannot initialize cipher: %s",
  93                   gcry_strerror(err));
  94        goto error;
  95    }
  96
  97    if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
  98        /* We're using standard DES cipher from gcrypt, so we need
  99         * to munge the key so that the results are the same as the
 100         * bizarre RFB variant of DES :-)
 101         */
 102        uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
 103        err = gcry_cipher_setkey(handle, rfbkey, nkey);
 104        g_free(rfbkey);
 105    } else {
 106        err = gcry_cipher_setkey(handle, key, nkey);
 107    }
 108    if (err != 0) {
 109        error_setg(errp, "Cannot set key: %s",
 110                   gcry_strerror(err));
 111        goto error;
 112    }
 113
 114    cipher->opaque = handle;
 115    return cipher;
 116
 117 error:
 118    gcry_cipher_close(handle);
 119    g_free(cipher);
 120    return NULL;
 121}
 122
 123
 124void qcrypto_cipher_free(QCryptoCipher *cipher)
 125{
 126    gcry_cipher_hd_t handle;
 127    if (!cipher) {
 128        return;
 129    }
 130    handle = cipher->opaque;
 131    gcry_cipher_close(handle);
 132    g_free(cipher);
 133}
 134
 135
 136int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
 137                           const void *in,
 138                           void *out,
 139                           size_t len,
 140                           Error **errp)
 141{
 142    gcry_cipher_hd_t handle = cipher->opaque;
 143    gcry_error_t err;
 144
 145    err = gcry_cipher_encrypt(handle,
 146                              out, len,
 147                              in, len);
 148    if (err != 0) {
 149        error_setg(errp, "Cannot encrypt data: %s",
 150                   gcry_strerror(err));
 151        return -1;
 152    }
 153
 154    return 0;
 155}
 156
 157
 158int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
 159                           const void *in,
 160                           void *out,
 161                           size_t len,
 162                           Error **errp)
 163{
 164    gcry_cipher_hd_t handle = cipher->opaque;
 165    gcry_error_t err;
 166
 167    err = gcry_cipher_decrypt(handle,
 168                              out, len,
 169                              in, len);
 170    if (err != 0) {
 171        error_setg(errp, "Cannot decrypt data: %s",
 172                   gcry_strerror(err));
 173        return -1;
 174    }
 175
 176    return 0;
 177}
 178
 179int qcrypto_cipher_setiv(QCryptoCipher *cipher,
 180                         const uint8_t *iv, size_t niv,
 181                         Error **errp)
 182{
 183    gcry_cipher_hd_t handle = cipher->opaque;
 184    gcry_error_t err;
 185
 186    gcry_cipher_reset(handle);
 187    err = gcry_cipher_setiv(handle, iv, niv);
 188    if (err != 0) {
 189        error_setg(errp, "Cannot set IV: %s",
 190                   gcry_strerror(err));
 191        return -1;
 192    }
 193
 194    return 0;
 195}
 196