crypto: add support for the cast5-128 cipher algorithm
[qemu/ar7.git] / crypto / cipher-gcrypt.c
blobaa1d8c58897f521b487f332c6f52706b285e6e14
1 /*
2 * QEMU Crypto cipher libgcrypt algorithms
4 * Copyright (c) 2015 Red Hat, Inc.
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.
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.
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/>.
21 #include "qemu/osdep.h"
22 #include <gcrypt.h>
25 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
27 switch (alg) {
28 case QCRYPTO_CIPHER_ALG_DES_RFB:
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 return true;
34 default:
35 return false;
39 typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
40 struct QCryptoCipherGcrypt {
41 gcry_cipher_hd_t handle;
42 size_t blocksize;
45 QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
46 QCryptoCipherMode mode,
47 const uint8_t *key, size_t nkey,
48 Error **errp)
50 QCryptoCipher *cipher;
51 QCryptoCipherGcrypt *ctx;
52 gcry_error_t err;
53 int gcryalg, gcrymode;
55 switch (mode) {
56 case QCRYPTO_CIPHER_MODE_ECB:
57 gcrymode = GCRY_CIPHER_MODE_ECB;
58 break;
59 case QCRYPTO_CIPHER_MODE_CBC:
60 gcrymode = GCRY_CIPHER_MODE_CBC;
61 break;
62 default:
63 error_setg(errp, "Unsupported cipher mode %d", mode);
64 return NULL;
67 if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
68 return NULL;
71 switch (alg) {
72 case QCRYPTO_CIPHER_ALG_DES_RFB:
73 gcryalg = GCRY_CIPHER_DES;
74 break;
76 case QCRYPTO_CIPHER_ALG_AES_128:
77 gcryalg = GCRY_CIPHER_AES128;
78 break;
80 case QCRYPTO_CIPHER_ALG_AES_192:
81 gcryalg = GCRY_CIPHER_AES192;
82 break;
84 case QCRYPTO_CIPHER_ALG_AES_256:
85 gcryalg = GCRY_CIPHER_AES256;
86 break;
88 case QCRYPTO_CIPHER_ALG_CAST5_128:
89 gcryalg = GCRY_CIPHER_CAST5;
90 break;
92 default:
93 error_setg(errp, "Unsupported cipher algorithm %d", alg);
94 return NULL;
97 cipher = g_new0(QCryptoCipher, 1);
98 cipher->alg = alg;
99 cipher->mode = mode;
101 ctx = g_new0(QCryptoCipherGcrypt, 1);
103 err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
104 if (err != 0) {
105 error_setg(errp, "Cannot initialize cipher: %s",
106 gcry_strerror(err));
107 goto error;
110 if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
111 /* We're using standard DES cipher from gcrypt, so we need
112 * to munge the key so that the results are the same as the
113 * bizarre RFB variant of DES :-)
115 uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
116 err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
117 g_free(rfbkey);
118 ctx->blocksize = 8;
119 } else {
120 err = gcry_cipher_setkey(ctx->handle, key, nkey);
121 switch (cipher->alg) {
122 case QCRYPTO_CIPHER_ALG_AES_128:
123 case QCRYPTO_CIPHER_ALG_AES_192:
124 case QCRYPTO_CIPHER_ALG_AES_256:
125 ctx->blocksize = 16;
126 break;
127 case QCRYPTO_CIPHER_ALG_CAST5_128:
128 ctx->blocksize = 8;
129 break;
130 default:
131 g_assert_not_reached();
134 if (err != 0) {
135 error_setg(errp, "Cannot set key: %s",
136 gcry_strerror(err));
137 goto error;
140 cipher->opaque = ctx;
141 return cipher;
143 error:
144 gcry_cipher_close(ctx->handle);
145 g_free(ctx);
146 g_free(cipher);
147 return NULL;
151 void qcrypto_cipher_free(QCryptoCipher *cipher)
153 QCryptoCipherGcrypt *ctx;
154 if (!cipher) {
155 return;
157 ctx = cipher->opaque;
158 gcry_cipher_close(ctx->handle);
159 g_free(ctx);
160 g_free(cipher);
164 int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
165 const void *in,
166 void *out,
167 size_t len,
168 Error **errp)
170 QCryptoCipherGcrypt *ctx = cipher->opaque;
171 gcry_error_t err;
173 if (len % ctx->blocksize) {
174 error_setg(errp, "Length %zu must be a multiple of block size %zu",
175 len, ctx->blocksize);
176 return -1;
179 err = gcry_cipher_encrypt(ctx->handle,
180 out, len,
181 in, len);
182 if (err != 0) {
183 error_setg(errp, "Cannot encrypt data: %s",
184 gcry_strerror(err));
185 return -1;
188 return 0;
192 int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
193 const void *in,
194 void *out,
195 size_t len,
196 Error **errp)
198 QCryptoCipherGcrypt *ctx = cipher->opaque;
199 gcry_error_t err;
201 if (len % ctx->blocksize) {
202 error_setg(errp, "Length %zu must be a multiple of block size %zu",
203 len, ctx->blocksize);
204 return -1;
207 err = gcry_cipher_decrypt(ctx->handle,
208 out, len,
209 in, len);
210 if (err != 0) {
211 error_setg(errp, "Cannot decrypt data: %s",
212 gcry_strerror(err));
213 return -1;
216 return 0;
219 int qcrypto_cipher_setiv(QCryptoCipher *cipher,
220 const uint8_t *iv, size_t niv,
221 Error **errp)
223 QCryptoCipherGcrypt *ctx = cipher->opaque;
224 gcry_error_t err;
226 if (niv != ctx->blocksize) {
227 error_setg(errp, "Expected IV size %zu not %zu",
228 ctx->blocksize, niv);
229 return -1;
232 gcry_cipher_reset(ctx->handle);
233 err = gcry_cipher_setiv(ctx->handle, iv, niv);
234 if (err != 0) {
235 error_setg(errp, "Cannot set IV: %s",
236 gcry_strerror(err));
237 return -1;
240 return 0;