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