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