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