qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

cipher-gcrypt.c.inc (7943B)


      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 
     23 bool 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 
     54 typedef struct QCryptoCipherGcrypt {
     55     QCryptoCipher base;
     56     gcry_cipher_hd_t handle;
     57     size_t blocksize;
     58 } QCryptoCipherGcrypt;
     59 
     60 
     61 static 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 
     69 static 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 
     91 static 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 
    113 static 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 
    136 static 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 
    159 static 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 
    166 static 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 
    173 static 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 }