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