]> Git Repo - qemu.git/blame - crypto/cipher-gcrypt.c
crypto: add support for the cast5-128 cipher algorithm
[qemu.git] / crypto / cipher-gcrypt.c
CommitLineData
62893b67
DB
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 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
42f7a448 21#include "qemu/osdep.h"
62893b67
DB
22#include <gcrypt.h>
23
24
25bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
26{
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:
084a85ee 32 case QCRYPTO_CIPHER_ALG_CAST5_128:
62893b67
DB
33 return true;
34 default:
35 return false;
36 }
37}
38
3a661f1e
DB
39typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt;
40struct QCryptoCipherGcrypt {
41 gcry_cipher_hd_t handle;
42 size_t blocksize;
43};
62893b67
DB
44
45QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
46 QCryptoCipherMode mode,
47 const uint8_t *key, size_t nkey,
48 Error **errp)
49{
50 QCryptoCipher *cipher;
3a661f1e 51 QCryptoCipherGcrypt *ctx;
62893b67
DB
52 gcry_error_t err;
53 int gcryalg, gcrymode;
54
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;
65 }
66
67 if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
68 return NULL;
69 }
70
71 switch (alg) {
72 case QCRYPTO_CIPHER_ALG_DES_RFB:
73 gcryalg = GCRY_CIPHER_DES;
74 break;
75
76 case QCRYPTO_CIPHER_ALG_AES_128:
77 gcryalg = GCRY_CIPHER_AES128;
78 break;
79
80 case QCRYPTO_CIPHER_ALG_AES_192:
81 gcryalg = GCRY_CIPHER_AES192;
82 break;
83
84 case QCRYPTO_CIPHER_ALG_AES_256:
85 gcryalg = GCRY_CIPHER_AES256;
86 break;
87
084a85ee
DB
88 case QCRYPTO_CIPHER_ALG_CAST5_128:
89 gcryalg = GCRY_CIPHER_CAST5;
90 break;
91
62893b67
DB
92 default:
93 error_setg(errp, "Unsupported cipher algorithm %d", alg);
94 return NULL;
95 }
96
97 cipher = g_new0(QCryptoCipher, 1);
98 cipher->alg = alg;
99 cipher->mode = mode;
100
3a661f1e
DB
101 ctx = g_new0(QCryptoCipherGcrypt, 1);
102
103 err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0);
62893b67
DB
104 if (err != 0) {
105 error_setg(errp, "Cannot initialize cipher: %s",
106 gcry_strerror(err));
107 goto error;
108 }
109
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 :-)
114 */
115 uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
3a661f1e 116 err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey);
62893b67 117 g_free(rfbkey);
3a661f1e 118 ctx->blocksize = 8;
62893b67 119 } else {
3a661f1e 120 err = gcry_cipher_setkey(ctx->handle, key, nkey);
084a85ee
DB
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();
132 }
62893b67
DB
133 }
134 if (err != 0) {
135 error_setg(errp, "Cannot set key: %s",
136 gcry_strerror(err));
137 goto error;
138 }
139
3a661f1e 140 cipher->opaque = ctx;
62893b67
DB
141 return cipher;
142
143 error:
3a661f1e
DB
144 gcry_cipher_close(ctx->handle);
145 g_free(ctx);
62893b67
DB
146 g_free(cipher);
147 return NULL;
148}
149
150
151void qcrypto_cipher_free(QCryptoCipher *cipher)
152{
3a661f1e 153 QCryptoCipherGcrypt *ctx;
62893b67
DB
154 if (!cipher) {
155 return;
156 }
3a661f1e
DB
157 ctx = cipher->opaque;
158 gcry_cipher_close(ctx->handle);
159 g_free(ctx);
62893b67
DB
160 g_free(cipher);
161}
162
163
164int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
165 const void *in,
166 void *out,
167 size_t len,
168 Error **errp)
169{
3a661f1e 170 QCryptoCipherGcrypt *ctx = cipher->opaque;
62893b67
DB
171 gcry_error_t err;
172
3a661f1e
DB
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;
177 }
178
179 err = gcry_cipher_encrypt(ctx->handle,
62893b67
DB
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;
186 }
187
188 return 0;
189}
190
191
192int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
193 const void *in,
194 void *out,
195 size_t len,
196 Error **errp)
197{
3a661f1e 198 QCryptoCipherGcrypt *ctx = cipher->opaque;
62893b67
DB
199 gcry_error_t err;
200
3a661f1e
DB
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;
205 }
206
207 err = gcry_cipher_decrypt(ctx->handle,
62893b67
DB
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;
214 }
215
216 return 0;
217}
218
219int qcrypto_cipher_setiv(QCryptoCipher *cipher,
220 const uint8_t *iv, size_t niv,
221 Error **errp)
222{
3a661f1e 223 QCryptoCipherGcrypt *ctx = cipher->opaque;
62893b67
DB
224 gcry_error_t err;
225
3a661f1e
DB
226 if (niv != ctx->blocksize) {
227 error_setg(errp, "Expected IV size %zu not %zu",
228 ctx->blocksize, niv);
229 return -1;
230 }
231
232 gcry_cipher_reset(ctx->handle);
233 err = gcry_cipher_setiv(ctx->handle, iv, niv);
62893b67
DB
234 if (err != 0) {
235 error_setg(errp, "Cannot set IV: %s",
236 gcry_strerror(err));
237 return -1;
238 }
239
240 return 0;
241}
This page took 0.071376 seconds and 4 git commands to generate.