]>
Commit | Line | Data |
---|---|---|
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 | ||
25 | bool 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: |
94318522 DB |
33 | case QCRYPTO_CIPHER_ALG_SERPENT_128: |
34 | case QCRYPTO_CIPHER_ALG_SERPENT_192: | |
35 | case QCRYPTO_CIPHER_ALG_SERPENT_256: | |
50f6753e DB |
36 | case QCRYPTO_CIPHER_ALG_TWOFISH_128: |
37 | case QCRYPTO_CIPHER_ALG_TWOFISH_256: | |
62893b67 DB |
38 | return true; |
39 | default: | |
40 | return false; | |
41 | } | |
42 | } | |
43 | ||
3a661f1e DB |
44 | typedef struct QCryptoCipherGcrypt QCryptoCipherGcrypt; |
45 | struct QCryptoCipherGcrypt { | |
46 | gcry_cipher_hd_t handle; | |
47 | size_t blocksize; | |
48 | }; | |
62893b67 DB |
49 | |
50 | QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg, | |
51 | QCryptoCipherMode mode, | |
52 | const uint8_t *key, size_t nkey, | |
53 | Error **errp) | |
54 | { | |
55 | QCryptoCipher *cipher; | |
3a661f1e | 56 | QCryptoCipherGcrypt *ctx; |
62893b67 DB |
57 | gcry_error_t err; |
58 | int gcryalg, gcrymode; | |
59 | ||
60 | switch (mode) { | |
61 | case QCRYPTO_CIPHER_MODE_ECB: | |
62 | gcrymode = GCRY_CIPHER_MODE_ECB; | |
63 | break; | |
64 | case QCRYPTO_CIPHER_MODE_CBC: | |
65 | gcrymode = GCRY_CIPHER_MODE_CBC; | |
66 | break; | |
67 | default: | |
68 | error_setg(errp, "Unsupported cipher mode %d", mode); | |
69 | return NULL; | |
70 | } | |
71 | ||
72 | if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) { | |
73 | return NULL; | |
74 | } | |
75 | ||
76 | switch (alg) { | |
77 | case QCRYPTO_CIPHER_ALG_DES_RFB: | |
78 | gcryalg = GCRY_CIPHER_DES; | |
79 | break; | |
80 | ||
81 | case QCRYPTO_CIPHER_ALG_AES_128: | |
82 | gcryalg = GCRY_CIPHER_AES128; | |
83 | break; | |
84 | ||
85 | case QCRYPTO_CIPHER_ALG_AES_192: | |
86 | gcryalg = GCRY_CIPHER_AES192; | |
87 | break; | |
88 | ||
89 | case QCRYPTO_CIPHER_ALG_AES_256: | |
90 | gcryalg = GCRY_CIPHER_AES256; | |
91 | break; | |
92 | ||
084a85ee DB |
93 | case QCRYPTO_CIPHER_ALG_CAST5_128: |
94 | gcryalg = GCRY_CIPHER_CAST5; | |
95 | break; | |
96 | ||
94318522 DB |
97 | case QCRYPTO_CIPHER_ALG_SERPENT_128: |
98 | gcryalg = GCRY_CIPHER_SERPENT128; | |
99 | break; | |
100 | ||
101 | case QCRYPTO_CIPHER_ALG_SERPENT_192: | |
102 | gcryalg = GCRY_CIPHER_SERPENT192; | |
103 | break; | |
104 | ||
105 | case QCRYPTO_CIPHER_ALG_SERPENT_256: | |
106 | gcryalg = GCRY_CIPHER_SERPENT256; | |
107 | break; | |
108 | ||
50f6753e DB |
109 | case QCRYPTO_CIPHER_ALG_TWOFISH_128: |
110 | gcryalg = GCRY_CIPHER_TWOFISH128; | |
111 | break; | |
112 | ||
113 | case QCRYPTO_CIPHER_ALG_TWOFISH_256: | |
114 | gcryalg = GCRY_CIPHER_TWOFISH; | |
115 | break; | |
116 | ||
62893b67 DB |
117 | default: |
118 | error_setg(errp, "Unsupported cipher algorithm %d", alg); | |
119 | return NULL; | |
120 | } | |
121 | ||
122 | cipher = g_new0(QCryptoCipher, 1); | |
123 | cipher->alg = alg; | |
124 | cipher->mode = mode; | |
125 | ||
3a661f1e DB |
126 | ctx = g_new0(QCryptoCipherGcrypt, 1); |
127 | ||
128 | err = gcry_cipher_open(&ctx->handle, gcryalg, gcrymode, 0); | |
62893b67 DB |
129 | if (err != 0) { |
130 | error_setg(errp, "Cannot initialize cipher: %s", | |
131 | gcry_strerror(err)); | |
132 | goto error; | |
133 | } | |
134 | ||
135 | if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) { | |
136 | /* We're using standard DES cipher from gcrypt, so we need | |
137 | * to munge the key so that the results are the same as the | |
138 | * bizarre RFB variant of DES :-) | |
139 | */ | |
140 | uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey); | |
3a661f1e | 141 | err = gcry_cipher_setkey(ctx->handle, rfbkey, nkey); |
62893b67 | 142 | g_free(rfbkey); |
3a661f1e | 143 | ctx->blocksize = 8; |
62893b67 | 144 | } else { |
3a661f1e | 145 | err = gcry_cipher_setkey(ctx->handle, key, nkey); |
084a85ee DB |
146 | switch (cipher->alg) { |
147 | case QCRYPTO_CIPHER_ALG_AES_128: | |
148 | case QCRYPTO_CIPHER_ALG_AES_192: | |
149 | case QCRYPTO_CIPHER_ALG_AES_256: | |
94318522 DB |
150 | case QCRYPTO_CIPHER_ALG_SERPENT_128: |
151 | case QCRYPTO_CIPHER_ALG_SERPENT_192: | |
152 | case QCRYPTO_CIPHER_ALG_SERPENT_256: | |
50f6753e DB |
153 | case QCRYPTO_CIPHER_ALG_TWOFISH_128: |
154 | case QCRYPTO_CIPHER_ALG_TWOFISH_256: | |
084a85ee DB |
155 | ctx->blocksize = 16; |
156 | break; | |
157 | case QCRYPTO_CIPHER_ALG_CAST5_128: | |
158 | ctx->blocksize = 8; | |
159 | break; | |
160 | default: | |
161 | g_assert_not_reached(); | |
162 | } | |
62893b67 DB |
163 | } |
164 | if (err != 0) { | |
165 | error_setg(errp, "Cannot set key: %s", | |
166 | gcry_strerror(err)); | |
167 | goto error; | |
168 | } | |
169 | ||
3a661f1e | 170 | cipher->opaque = ctx; |
62893b67 DB |
171 | return cipher; |
172 | ||
173 | error: | |
3a661f1e DB |
174 | gcry_cipher_close(ctx->handle); |
175 | g_free(ctx); | |
62893b67 DB |
176 | g_free(cipher); |
177 | return NULL; | |
178 | } | |
179 | ||
180 | ||
181 | void qcrypto_cipher_free(QCryptoCipher *cipher) | |
182 | { | |
3a661f1e | 183 | QCryptoCipherGcrypt *ctx; |
62893b67 DB |
184 | if (!cipher) { |
185 | return; | |
186 | } | |
3a661f1e DB |
187 | ctx = cipher->opaque; |
188 | gcry_cipher_close(ctx->handle); | |
189 | g_free(ctx); | |
62893b67 DB |
190 | g_free(cipher); |
191 | } | |
192 | ||
193 | ||
194 | int qcrypto_cipher_encrypt(QCryptoCipher *cipher, | |
195 | const void *in, | |
196 | void *out, | |
197 | size_t len, | |
198 | Error **errp) | |
199 | { | |
3a661f1e | 200 | QCryptoCipherGcrypt *ctx = cipher->opaque; |
62893b67 DB |
201 | gcry_error_t err; |
202 | ||
3a661f1e DB |
203 | if (len % ctx->blocksize) { |
204 | error_setg(errp, "Length %zu must be a multiple of block size %zu", | |
205 | len, ctx->blocksize); | |
206 | return -1; | |
207 | } | |
208 | ||
209 | err = gcry_cipher_encrypt(ctx->handle, | |
62893b67 DB |
210 | out, len, |
211 | in, len); | |
212 | if (err != 0) { | |
213 | error_setg(errp, "Cannot encrypt data: %s", | |
214 | gcry_strerror(err)); | |
215 | return -1; | |
216 | } | |
217 | ||
218 | return 0; | |
219 | } | |
220 | ||
221 | ||
222 | int qcrypto_cipher_decrypt(QCryptoCipher *cipher, | |
223 | const void *in, | |
224 | void *out, | |
225 | size_t len, | |
226 | Error **errp) | |
227 | { | |
3a661f1e | 228 | QCryptoCipherGcrypt *ctx = cipher->opaque; |
62893b67 DB |
229 | gcry_error_t err; |
230 | ||
3a661f1e DB |
231 | if (len % ctx->blocksize) { |
232 | error_setg(errp, "Length %zu must be a multiple of block size %zu", | |
233 | len, ctx->blocksize); | |
234 | return -1; | |
235 | } | |
236 | ||
237 | err = gcry_cipher_decrypt(ctx->handle, | |
62893b67 DB |
238 | out, len, |
239 | in, len); | |
240 | if (err != 0) { | |
241 | error_setg(errp, "Cannot decrypt data: %s", | |
242 | gcry_strerror(err)); | |
243 | return -1; | |
244 | } | |
245 | ||
246 | return 0; | |
247 | } | |
248 | ||
249 | int qcrypto_cipher_setiv(QCryptoCipher *cipher, | |
250 | const uint8_t *iv, size_t niv, | |
251 | Error **errp) | |
252 | { | |
3a661f1e | 253 | QCryptoCipherGcrypt *ctx = cipher->opaque; |
62893b67 DB |
254 | gcry_error_t err; |
255 | ||
3a661f1e DB |
256 | if (niv != ctx->blocksize) { |
257 | error_setg(errp, "Expected IV size %zu not %zu", | |
258 | ctx->blocksize, niv); | |
259 | return -1; | |
260 | } | |
261 | ||
262 | gcry_cipher_reset(ctx->handle); | |
263 | err = gcry_cipher_setiv(ctx->handle, iv, niv); | |
62893b67 DB |
264 | if (err != 0) { |
265 | error_setg(errp, "Cannot set IV: %s", | |
266 | gcry_strerror(err)); | |
267 | return -1; | |
268 | } | |
269 | ||
270 | return 0; | |
271 | } |