Merge tag 'v9.0.0-rc3'
[qemu/ar7.git] / crypto / akcipher-gcrypt.c.inc
blobabb1fb272e459a3679711fcd6b8d8b017116ceb3
1 /*
2  * QEMU Crypto akcipher algorithms
3  *
4  * Copyright (c) 2022 Bytedance
5  * Author: lei he <helei.sig11@bytedance.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19  *
20  */
22 #include <gcrypt.h>
24 #include "qemu/osdep.h"
25 #include "qemu/host-utils.h"
26 #include "crypto/akcipher.h"
27 #include "crypto/random.h"
28 #include "qapi/error.h"
29 #include "sysemu/cryptodev.h"
30 #include "rsakey.h"
32 typedef struct QCryptoGcryptRSA {
33     QCryptoAkCipher akcipher;
34     gcry_sexp_t key;
35     QCryptoRSAPaddingAlgorithm padding_alg;
36     QCryptoHashAlgorithm hash_alg;
37 } QCryptoGcryptRSA;
39 static void qcrypto_gcrypt_rsa_free(QCryptoAkCipher *akcipher)
41     QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher;
42     if (!rsa) {
43         return;
44     }
46     gcry_sexp_release(rsa->key);
47     g_free(rsa);
50 static QCryptoGcryptRSA *qcrypto_gcrypt_rsa_new(
51     const QCryptoAkCipherOptionsRSA *opt,
52     QCryptoAkCipherKeyType type,
53     const uint8_t *key,  size_t keylen,
54     Error **errp);
56 QCryptoAkCipher *qcrypto_akcipher_new(const QCryptoAkCipherOptions *opts,
57                                       QCryptoAkCipherKeyType type,
58                                       const uint8_t *key, size_t keylen,
59                                       Error **errp)
61     switch (opts->alg) {
62     case QCRYPTO_AKCIPHER_ALG_RSA:
63         return (QCryptoAkCipher *)qcrypto_gcrypt_rsa_new(
64             &opts->u.rsa, type, key, keylen, errp);
66     default:
67         error_setg(errp, "Unsupported algorithm: %u", opts->alg);
68         return NULL;
69     }
71     return NULL;
74 static void qcrypto_gcrypt_set_rsa_size(QCryptoAkCipher *akcipher, gcry_mpi_t n)
76     size_t key_size = (gcry_mpi_get_nbits(n) + 7) / 8;
77     akcipher->max_plaintext_len = key_size;
78     akcipher->max_ciphertext_len = key_size;
79     akcipher->max_dgst_len = key_size;
80     akcipher->max_signature_len = key_size;
83 static int qcrypto_gcrypt_parse_rsa_private_key(
84     QCryptoGcryptRSA *rsa,
85     const uint8_t *key, size_t keylen, Error **errp)
87     g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse(
88         QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE, key, keylen, errp);
89     gcry_mpi_t n = NULL, e = NULL, d = NULL, p = NULL, q = NULL, u = NULL;
90     bool compute_mul_inv = false;
91     int ret = -1;
92     gcry_error_t err;
94     if (!rsa_key) {
95         return ret;
96     }
98     err = gcry_mpi_scan(&n, GCRYMPI_FMT_STD,
99                         rsa_key->n.data, rsa_key->n.len, NULL);
100     if (gcry_err_code(err) != 0) {
101         error_setg(errp, "Failed to parse RSA parameter n: %s/%s",
102                    gcry_strsource(err), gcry_strerror(err));
103         goto cleanup;
104     }
106     err = gcry_mpi_scan(&e, GCRYMPI_FMT_STD,
107                         rsa_key->e.data, rsa_key->e.len, NULL);
108     if (gcry_err_code(err) != 0) {
109         error_setg(errp, "Failed to parse RSA parameter e: %s/%s",
110                    gcry_strsource(err), gcry_strerror(err));
111         goto cleanup;
112     }
114     err = gcry_mpi_scan(&d, GCRYMPI_FMT_STD,
115                         rsa_key->d.data, rsa_key->d.len, NULL);
116     if (gcry_err_code(err) != 0) {
117         error_setg(errp, "Failed to parse RSA parameter d: %s/%s",
118                    gcry_strsource(err), gcry_strerror(err));
119         goto cleanup;
120     }
122     err = gcry_mpi_scan(&p, GCRYMPI_FMT_STD,
123                         rsa_key->p.data, rsa_key->p.len, NULL);
124     if (gcry_err_code(err) != 0) {
125         error_setg(errp, "Failed to parse RSA parameter p: %s/%s",
126                    gcry_strsource(err), gcry_strerror(err));
127         goto cleanup;
128     }
130     err = gcry_mpi_scan(&q, GCRYMPI_FMT_STD,
131                         rsa_key->q.data, rsa_key->q.len, NULL);
132     if (gcry_err_code(err) != 0) {
133         error_setg(errp, "Failed to parse RSA parameter q: %s/%s",
134                    gcry_strsource(err), gcry_strerror(err));
135         goto cleanup;
136     }
138     if (gcry_mpi_cmp_ui(p, 0) > 0 && gcry_mpi_cmp_ui(q, 0) > 0) {
139         compute_mul_inv = true;
141         u = gcry_mpi_new(0);
142         if (gcry_mpi_cmp(p, q) > 0) {
143             gcry_mpi_swap(p, q);
144         }
145         gcry_mpi_invm(u, p, q);
146     }
148     if (compute_mul_inv) {
149         err = gcry_sexp_build(&rsa->key, NULL,
150             "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))",
151             n, e, d, p, q, u);
152     } else {
153         err = gcry_sexp_build(&rsa->key, NULL,
154             "(private-key (rsa (n %m) (e %m) (d %m)))", n, e, d);
155     }
156     if (gcry_err_code(err) != 0) {
157         error_setg(errp, "Failed to build RSA private key: %s/%s",
158                    gcry_strsource(err), gcry_strerror(err));
159         goto cleanup;
160     }
161     qcrypto_gcrypt_set_rsa_size((QCryptoAkCipher *)rsa,  n);
162     ret = 0;
164 cleanup:
165     gcry_mpi_release(n);
166     gcry_mpi_release(e);
167     gcry_mpi_release(d);
168     gcry_mpi_release(p);
169     gcry_mpi_release(q);
170     gcry_mpi_release(u);
171     return ret;
174 static int qcrypto_gcrypt_parse_rsa_public_key(QCryptoGcryptRSA *rsa,
175                                                const uint8_t *key,
176                                                size_t keylen,
177                                                Error **errp)
180     g_autoptr(QCryptoAkCipherRSAKey) rsa_key = qcrypto_akcipher_rsakey_parse(
181         QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC, key, keylen, errp);
182     gcry_mpi_t n = NULL, e = NULL;
183     int ret = -1;
184     gcry_error_t err;
186     if (!rsa_key) {
187         return ret;
188     }
190     err = gcry_mpi_scan(&n, GCRYMPI_FMT_STD,
191                         rsa_key->n.data, rsa_key->n.len, NULL);
192     if (gcry_err_code(err) != 0) {
193         error_setg(errp, "Failed to parse RSA parameter n: %s/%s",
194                    gcry_strsource(err), gcry_strerror(err));
195         goto cleanup;
196     }
198     err = gcry_mpi_scan(&e, GCRYMPI_FMT_STD,
199                         rsa_key->e.data, rsa_key->e.len, NULL);
200     if (gcry_err_code(err) != 0) {
201         error_setg(errp, "Failed to parse RSA parameter e: %s/%s",
202                    gcry_strsource(err), gcry_strerror(err));
203         goto cleanup;
204     }
206     err = gcry_sexp_build(&rsa->key, NULL,
207                           "(public-key (rsa (n %m) (e %m)))", n, e);
208     if (gcry_err_code(err) != 0) {
209         error_setg(errp, "Failed to build RSA public key: %s/%s",
210                    gcry_strsource(err), gcry_strerror(err));
211         goto cleanup;
212     }
213     qcrypto_gcrypt_set_rsa_size((QCryptoAkCipher *)rsa, n);
214     ret = 0;
216 cleanup:
217     gcry_mpi_release(n);
218     gcry_mpi_release(e);
219     return ret;
222 static int qcrypto_gcrypt_rsa_encrypt(QCryptoAkCipher *akcipher,
223                                       const void *in, size_t in_len,
224                                       void *out, size_t out_len,
225                                       Error **errp)
227     QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher;
228     int ret = -1;
229     gcry_sexp_t data_sexp = NULL, cipher_sexp = NULL;
230     gcry_sexp_t cipher_sexp_item = NULL;
231     gcry_mpi_t cipher_mpi = NULL;
232     const char *result;
233     gcry_error_t err;
234     size_t actual_len;
236     if (in_len > akcipher->max_plaintext_len) {
237         error_setg(errp, "Plaintext length is greater than key size: %d",
238                    akcipher->max_plaintext_len);
239         return ret;
240     }
242     err = gcry_sexp_build(&data_sexp, NULL,
243                           "(data (flags %s) (value %b))",
244                           QCryptoRSAPaddingAlgorithm_str(rsa->padding_alg),
245                           in_len, in);
246     if (gcry_err_code(err) != 0) {
247         error_setg(errp, "Failed to build plaintext: %s/%s",
248                    gcry_strsource(err), gcry_strerror(err));
249         goto cleanup;
250     }
252     err = gcry_pk_encrypt(&cipher_sexp, data_sexp, rsa->key);
253     if (gcry_err_code(err) != 0) {
254         error_setg(errp, "Failed to encrypt: %s/%s",
255                    gcry_strsource(err), gcry_strerror(err));
256         goto cleanup;
257     }
259     /* S-expression of cipher: (enc-val (rsa (a a-mpi))) */
260     cipher_sexp_item = gcry_sexp_find_token(cipher_sexp, "a", 0);
261     if (!cipher_sexp_item || gcry_sexp_length(cipher_sexp_item) != 2) {
262         error_setg(errp, "Invalid ciphertext result");
263         goto cleanup;
264     }
266     if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) {
267         cipher_mpi = gcry_sexp_nth_mpi(cipher_sexp_item, 1, GCRYMPI_FMT_USG);
268         if (!cipher_mpi) {
269             error_setg(errp, "Invalid ciphertext result");
270             goto cleanup;
271         }
272         err = gcry_mpi_print(GCRYMPI_FMT_USG, out, out_len,
273                              &actual_len, cipher_mpi);
274         if (gcry_err_code(err) != 0) {
275             error_setg(errp, "Failed to print MPI: %s/%s",
276                        gcry_strsource(err), gcry_strerror(err));
277             goto cleanup;
278         }
280         if (actual_len > out_len) {
281             error_setg(errp, "Ciphertext buffer length is too small");
282             goto cleanup;
283         }
285         /* We always padding leading-zeros for RSA-RAW */
286         if (actual_len < out_len) {
287             memmove((uint8_t *)out + (out_len - actual_len), out, actual_len);
288             memset(out, 0, out_len - actual_len);
289         }
290         ret = out_len;
292     } else {
293         result = gcry_sexp_nth_data(cipher_sexp_item, 1, &actual_len);
294         if (!result) {
295             error_setg(errp, "Invalid ciphertext result");
296             goto cleanup;
297         }
298         if (actual_len > out_len) {
299             error_setg(errp, "Ciphertext buffer length is too small");
300             goto cleanup;
301         }
302         memcpy(out, result, actual_len);
303         ret = actual_len;
304     }
306 cleanup:
307     gcry_sexp_release(data_sexp);
308     gcry_sexp_release(cipher_sexp);
309     gcry_sexp_release(cipher_sexp_item);
310     gcry_mpi_release(cipher_mpi);
311     return ret;
314 static int qcrypto_gcrypt_rsa_decrypt(QCryptoAkCipher *akcipher,
315                                       const void *in, size_t in_len,
316                                       void *out, size_t out_len,
317                                       Error **errp)
319     QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher;
320     int ret = -1;
321     gcry_sexp_t data_sexp = NULL, cipher_sexp = NULL;
322     gcry_mpi_t data_mpi = NULL;
323     gcry_error_t err;
324     size_t actual_len;
325     const char *result;
327     if (in_len > akcipher->max_ciphertext_len) {
328         error_setg(errp, "Ciphertext length is greater than key size: %d",
329                    akcipher->max_ciphertext_len);
330         return ret;
331     }
333     err = gcry_sexp_build(&cipher_sexp, NULL,
334                           "(enc-val (flags %s) (rsa (a %b) ))",
335                           QCryptoRSAPaddingAlgorithm_str(rsa->padding_alg),
336                           in_len, in);
337     if (gcry_err_code(err) != 0) {
338         error_setg(errp, "Failed to build ciphertext: %s/%s",
339                    gcry_strsource(err), gcry_strerror(err));
340         goto cleanup;
341     }
343     err = gcry_pk_decrypt(&data_sexp, cipher_sexp, rsa->key);
344     if (gcry_err_code(err) != 0) {
345         error_setg(errp, "Failed to decrypt: %s/%s",
346                    gcry_strsource(err), gcry_strerror(err));
347         goto cleanup;
348     }
350     /* S-expression of plaintext: (value plaintext) */
351     if (rsa->padding_alg == QCRYPTO_RSA_PADDING_ALG_RAW) {
352         data_mpi = gcry_sexp_nth_mpi(data_sexp, 1, GCRYMPI_FMT_USG);
353         if (!data_mpi) {
354             error_setg(errp, "Invalid plaintext result");
355             goto cleanup;
356         }
357         err = gcry_mpi_print(GCRYMPI_FMT_USG, out, out_len,
358                              &actual_len, data_mpi);
359         if (gcry_err_code(err) != 0) {
360             error_setg(errp, "Failed to print MPI: %s/%s",
361                        gcry_strsource(err), gcry_strerror(err));
362             goto cleanup;
363         }
364         if (actual_len > out_len) {
365             error_setg(errp, "Plaintext buffer length is too small");
366             goto cleanup;
367         }
368         /* We always padding leading-zeros for RSA-RAW */
369         if (actual_len < out_len) {
370             memmove((uint8_t *)out + (out_len - actual_len), out, actual_len);
371             memset(out, 0, out_len - actual_len);
372         }
373         ret = out_len;
374     } else {
375         result = gcry_sexp_nth_data(data_sexp, 1, &actual_len);
376         if (!result) {
377             error_setg(errp, "Invalid plaintext result");
378             goto cleanup;
379         }
380         if (actual_len > out_len) {
381             error_setg(errp, "Plaintext buffer length is too small");
382             goto cleanup;
383         }
384         memcpy(out, result, actual_len);
385         ret = actual_len;
386     }
388 cleanup:
389     gcry_sexp_release(cipher_sexp);
390     gcry_sexp_release(data_sexp);
391     gcry_mpi_release(data_mpi);
392     return ret;
395 static int qcrypto_gcrypt_rsa_sign(QCryptoAkCipher *akcipher,
396                                    const void *in, size_t in_len,
397                                    void *out, size_t out_len, Error **errp)
399     QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher;
400     int ret = -1;
401     gcry_sexp_t dgst_sexp = NULL, sig_sexp = NULL;
402     gcry_sexp_t sig_sexp_item = NULL;
403     const char *result;
404     gcry_error_t err;
405     size_t actual_len;
407     if (in_len > akcipher->max_dgst_len) {
408         error_setg(errp, "Data length is greater than key size: %d",
409                    akcipher->max_dgst_len);
410         return ret;
411     }
413     if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALG_PKCS1) {
414         error_setg(errp, "Invalid padding %u", rsa->padding_alg);
415         return ret;
416     }
418     err = gcry_sexp_build(&dgst_sexp, NULL,
419                           "(data (flags pkcs1) (hash %s %b))",
420                           QCryptoHashAlgorithm_str(rsa->hash_alg),
421                           in_len, in);
422     if (gcry_err_code(err) != 0) {
423         error_setg(errp, "Failed to build dgst: %s/%s",
424                    gcry_strsource(err), gcry_strerror(err));
425         goto cleanup;
426     }
428     err = gcry_pk_sign(&sig_sexp, dgst_sexp, rsa->key);
429     if (gcry_err_code(err) != 0) {
430         error_setg(errp, "Failed to make signature: %s/%s",
431                    gcry_strsource(err), gcry_strerror(err));
432         goto cleanup;
433     }
435     /* S-expression of signature: (sig-val (rsa (s s-mpi))) */
436     sig_sexp_item = gcry_sexp_find_token(sig_sexp, "s", 0);
437     if (!sig_sexp_item || gcry_sexp_length(sig_sexp_item) != 2) {
438         error_setg(errp, "Invalid signature result");
439         goto cleanup;
440     }
442     result = gcry_sexp_nth_data(sig_sexp_item, 1, &actual_len);
443     if (!result) {
444         error_setg(errp, "Invalid signature result");
445         goto cleanup;
446     }
448     if (actual_len > out_len) {
449         error_setg(errp, "Signature buffer length is too small");
450         goto cleanup;
451     }
452     memcpy(out, result, actual_len);
453     ret = actual_len;
455 cleanup:
456     gcry_sexp_release(dgst_sexp);
457     gcry_sexp_release(sig_sexp);
458     gcry_sexp_release(sig_sexp_item);
460     return ret;
463 static int qcrypto_gcrypt_rsa_verify(QCryptoAkCipher *akcipher,
464                                      const void *in, size_t in_len,
465                                      const void *in2, size_t in2_len,
466                                      Error **errp)
468     QCryptoGcryptRSA *rsa = (QCryptoGcryptRSA *)akcipher;
469     int ret = -1;
470     gcry_sexp_t sig_sexp = NULL, dgst_sexp = NULL;
471     gcry_error_t err;
473     if (in_len > akcipher->max_signature_len) {
474         error_setg(errp, "Signature length is greater than key size: %d",
475                    akcipher->max_signature_len);
476         return ret;
477     }
479     if (in2_len > akcipher->max_dgst_len) {
480         error_setg(errp, "Data length is greater than key size: %d",
481                    akcipher->max_dgst_len);
482         return ret;
483     }
485     if (rsa->padding_alg != QCRYPTO_RSA_PADDING_ALG_PKCS1) {
486         error_setg(errp, "Invalid padding %u", rsa->padding_alg);
487         return ret;
488     }
490     err = gcry_sexp_build(&sig_sexp, NULL,
491                           "(sig-val (rsa (s %b)))", in_len, in);
492     if (gcry_err_code(err) != 0) {
493         error_setg(errp, "Failed to build signature: %s/%s",
494                    gcry_strsource(err), gcry_strerror(err));
495         goto cleanup;
496     }
498     err = gcry_sexp_build(&dgst_sexp, NULL,
499                           "(data (flags pkcs1) (hash %s %b))",
500                           QCryptoHashAlgorithm_str(rsa->hash_alg),
501                           in2_len, in2);
502     if (gcry_err_code(err) != 0) {
503         error_setg(errp, "Failed to build dgst: %s/%s",
504                    gcry_strsource(err), gcry_strerror(err));
505         goto cleanup;
506     }
508     err = gcry_pk_verify(sig_sexp, dgst_sexp, rsa->key);
509     if (gcry_err_code(err) != 0) {
510         error_setg(errp, "Failed to verify signature: %s/%s",
511                    gcry_strsource(err), gcry_strerror(err));
512         goto cleanup;
513     }
514     ret = 0;
516 cleanup:
517     gcry_sexp_release(dgst_sexp);
518     gcry_sexp_release(sig_sexp);
520     return ret;
523 QCryptoAkCipherDriver gcrypt_rsa = {
524     .encrypt = qcrypto_gcrypt_rsa_encrypt,
525     .decrypt = qcrypto_gcrypt_rsa_decrypt,
526     .sign = qcrypto_gcrypt_rsa_sign,
527     .verify = qcrypto_gcrypt_rsa_verify,
528     .free = qcrypto_gcrypt_rsa_free,
531 static QCryptoGcryptRSA *qcrypto_gcrypt_rsa_new(
532     const QCryptoAkCipherOptionsRSA *opt,
533     QCryptoAkCipherKeyType type,
534     const uint8_t *key, size_t keylen,
535     Error **errp)
537     QCryptoGcryptRSA *rsa = g_new0(QCryptoGcryptRSA, 1);
538     rsa->padding_alg = opt->padding_alg;
539     rsa->hash_alg = opt->hash_alg;
540     rsa->akcipher.driver = &gcrypt_rsa;
542     switch (type) {
543     case QCRYPTO_AKCIPHER_KEY_TYPE_PRIVATE:
544         if (qcrypto_gcrypt_parse_rsa_private_key(rsa, key, keylen, errp) != 0) {
545             goto error;
546         }
547         break;
549     case QCRYPTO_AKCIPHER_KEY_TYPE_PUBLIC:
550         if (qcrypto_gcrypt_parse_rsa_public_key(rsa, key, keylen, errp) != 0) {
551             goto error;
552         }
553         break;
555     default:
556         error_setg(errp, "Unknown akcipher key type %d", type);
557         goto error;
558     }
560     return rsa;
562 error:
563     qcrypto_gcrypt_rsa_free((QCryptoAkCipher *)rsa);
564     return NULL;
568 bool qcrypto_akcipher_supports(QCryptoAkCipherOptions *opts)
570     switch (opts->alg) {
571     case QCRYPTO_AKCIPHER_ALG_RSA:
572         switch (opts->u.rsa.padding_alg) {
573         case QCRYPTO_RSA_PADDING_ALG_RAW:
574             return true;
576         case QCRYPTO_RSA_PADDING_ALG_PKCS1:
577             switch (opts->u.rsa.hash_alg) {
578             case QCRYPTO_HASH_ALG_MD5:
579             case QCRYPTO_HASH_ALG_SHA1:
580             case QCRYPTO_HASH_ALG_SHA256:
581             case QCRYPTO_HASH_ALG_SHA512:
582                 return true;
584             default:
585                 return false;
586             }
588         default:
589             return false;
590         }
592     default:
593         return true;
594     }