gcrypt: Remove open-coded OAEP padding.
[paraslash.git] / gcrypt.c
1 /*
2  * Copyright (C) 2011 Andre Noll <maan@tuebingen.mpg.de>
3  *
4  * Licensed under the GPL v2. For licencing details see COPYING.
5  */
6
7 /** \file gcrypt.c Libgrcypt-based encryption/decryption routines. */
8
9 #include <regex.h>
10 #include <gcrypt.h>
11
12 #include "para.h"
13 #include "error.h"
14 #include "string.h"
15 #include "crypt.h"
16 #include "crypt_backend.h"
17 #include "fd.h"
18 #include "base64.h"
19
20 //#define GCRYPT_DEBUG 1
21
22 #ifdef GCRYPT_DEBUG
23 static void dump_buffer(const char *msg, unsigned char *buf, int len)
24 {
25         int i;
26
27         fprintf(stderr, "%s (%d bytes): ", msg, len);
28         for (i = 0; i < len; i++)
29                 fprintf(stderr, "%02x ", buf[i]);
30         fprintf(stderr, "\n");
31 }
32 #else
33 /** Empty. Define GCRYPT_DEBUG to dump buffers. */
34 #define dump_buffer(a, b, c)
35 #endif
36
37 void hash_function(const char *data, unsigned long len, unsigned char *hash)
38 {
39         gcry_error_t gret;
40         gcry_md_hd_t handle;
41         unsigned char *md;
42
43         gret = gcry_md_open(&handle, GCRY_MD_SHA1, 0);
44         assert(gret == 0);
45         gcry_md_write(handle, data, (size_t)len);
46         gcry_md_final(handle);
47         md = gcry_md_read(handle, GCRY_MD_SHA1);
48         assert(md);
49         memcpy(hash, md, HASH_SIZE);
50         gcry_md_close(handle);
51 }
52
53 void get_random_bytes_or_die(unsigned char *buf, int num)
54 {
55         gcry_randomize(buf, (size_t)num, GCRY_STRONG_RANDOM);
56 }
57
58 /*
59  * This is called at the beginning of every program that uses libgcrypt. We
60  * don't have to initialize any random seed here, but we must initialize the
61  * gcrypt library. This task is performed by gcry_check_version() which can
62  * also check that the gcrypt library version is at least the minimal required
63  * version.
64  */
65 void init_random_seed_or_die(void)
66 {
67         const char *ver, *req_ver;
68
69         ver = gcry_check_version(NULL);
70         req_ver = "1.5.0";
71         if (!gcry_check_version(req_ver)) {
72                 PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n",
73                         req_ver, ver);
74                 exit(EXIT_FAILURE);
75         }
76 }
77
78 /** S-expression for the public part of an RSA key. */
79 #define RSA_PUBKEY_SEXP "(public-key (rsa (n %m) (e %m)))"
80 /** S-expression for a private RSA key. */
81 #define RSA_PRIVKEY_SEXP "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))"
82 /** S-expression for decryption. */
83 #define RSA_DECRYPT_SEXP "(enc-val(flags oaep)(rsa(a %m)))"
84
85 struct asymmetric_key {
86         gcry_sexp_t sexp;
87         int num_bytes;
88 };
89
90 static const char *gcrypt_strerror(gcry_error_t gret)
91 {
92         return gcry_strerror(gcry_err_code(gret));
93 }
94
95 static int decode_key(const char *key_file, const char *header_str,
96                 const char *footer_str, unsigned char **result)
97 {
98         int ret, ret2, i, j;
99         void *map;
100         size_t map_size, key_size, blob_size;
101         unsigned char *blob = NULL;
102         char *begin, *footer, *key;
103
104         ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL);
105         if (ret < 0)
106                 goto out;
107         ret = -E_KEY_MARKER;
108         if (strncmp(map, header_str, strlen(header_str)))
109                 goto unmap;
110         footer = strstr(map, footer_str);
111         ret = -E_KEY_MARKER;
112         if (!footer)
113                 goto unmap;
114         begin = map + strlen(header_str);
115         /* skip whitespace at the beginning */
116         for (; begin < footer; begin++) {
117                 if (para_isspace(*begin))
118                         continue;
119                 break;
120         }
121         ret = -E_KEY_MARKER;
122         if (begin >= footer)
123                 goto unmap;
124
125         key_size = footer - begin;
126         key = para_malloc(key_size + 1);
127         for (i = 0, j = 0; begin + i < footer; i++) {
128                 if (para_isspace(begin[i]))
129                         continue;
130                 key[j++] = begin[i];
131         }
132         key[j] = '\0';
133         ret = base64_decode(key, j, (char **)&blob, &blob_size);
134         free(key);
135         if (ret < 0)
136                 goto free_unmap;
137         ret = blob_size;
138         goto unmap;
139 free_unmap:
140         free(blob);
141         blob = NULL;
142 unmap:
143         ret2 = para_munmap(map, map_size);
144         if (ret >= 0 && ret2 < 0)
145                 ret = ret2;
146         if (ret < 0) {
147                 free(blob);
148                 blob = NULL;
149         }
150 out:
151         *result = blob;
152         return ret;
153 }
154
155 /** ASN Types and their code. */
156 enum asn1_types {
157         /** The next object is an integer. */
158         ASN1_TYPE_INTEGER = 0x2,
159         /** Bit string object. */
160         ASN1_TYPE_BIT_STRING = 0x03,
161         /** Keys start with one big type sequence. */
162         ASN1_TYPE_SEQUENCE = 0x30,
163 };
164
165 /* bit 6 has value 0 */
166 static inline bool is_primitive(unsigned char c)
167 {
168         return (c & (1<<6)) == 0;
169 }
170
171 static inline bool is_primitive_integer(unsigned char c)
172 {
173         if (!is_primitive(c))
174                 return false;
175         return (c & 0x1f) == ASN1_TYPE_INTEGER;
176 }
177
178 /* Bit 8 is zero (and bits 7-1 give the length) */
179 static inline bool is_short_form(unsigned char c)
180 {
181         return (c & 0x80) == 0;
182 }
183
184 static inline int get_short_form_length(unsigned char c)
185 {
186         return c & 0x7f;
187 }
188
189 static inline int get_long_form_num_length_bytes(unsigned char c)
190 {
191         return c & 0x7f;
192 }
193
194 static int find_pubkey_bignum_offset(const unsigned char *data, int len)
195 {
196         const unsigned char *p = data, *end = data + len;
197
198         /* the whole thing starts with one sequence */
199         if (*p != ASN1_TYPE_SEQUENCE)
200                 return -E_ASN1_PARSE;
201         p++;
202         if (p >= end)
203                 return -E_ASN1_PARSE;
204         if (is_short_form(*p))
205                 p++;
206         else
207                 p += 1 + get_long_form_num_length_bytes(*p);
208         if (p >= end)
209                 return -E_ASN1_PARSE;
210         /* another sequence containing the object id, skip it */
211         if (*p != ASN1_TYPE_SEQUENCE)
212                 return -E_ASN1_PARSE;
213         p++;
214         if (p >= end)
215                 return -E_ASN1_PARSE;
216         if (!is_short_form(*p))
217                 return -E_ASN1_PARSE;
218         p += 1 + get_short_form_length(*p);
219         if (p >= end)
220                 return -E_ASN1_PARSE;
221         /* all numbers are wrapped in a bit string object that follows */
222         if (*p != ASN1_TYPE_BIT_STRING)
223                 return -E_ASN1_PARSE;
224         p++;
225         if (p >= end)
226                 return -E_ASN1_PARSE;
227         if (is_short_form(*p))
228                 p++;
229         else
230                 p += 1 + get_long_form_num_length_bytes(*p);
231         p++; /* skip number of unused bits in the bit string */
232         if (p >= end)
233                 return -E_ASN1_PARSE;
234
235         /* next, we have a sequence of two integers (n and e) */
236         if (*p != ASN1_TYPE_SEQUENCE)
237                 return -E_ASN1_PARSE;
238         p++;
239         if (p >= end)
240                 return -E_ASN1_PARSE;
241         if (is_short_form(*p))
242                 p++;
243         else
244                 p += 1 + get_long_form_num_length_bytes(*p);
245         if (p >= end)
246                 return -E_ASN1_PARSE;
247         if (*p != ASN1_TYPE_INTEGER)
248                 return -E_ASN1_PARSE;
249         return p - data;
250 }
251
252 /*
253  * Returns: Number of bytes scanned. This may differ from the value returned via
254  * bn_bytes because the latter does not include the ASN.1 prefix and a leading
255  * zero is not considered as an additional byte for bn_bytes.
256  */
257 static int read_bignum(unsigned char *start, unsigned char *end, gcry_mpi_t *bn,
258                 int *bn_bytes)
259 {
260         int i, bn_size;
261         gcry_error_t gret;
262         unsigned char *cp = start;
263
264         if (!is_primitive_integer(*cp))
265                 return -E_BAD_PRIVATE_KEY;
266         cp++;
267         if (is_short_form(*cp)) {
268                 bn_size = get_short_form_length(*cp);
269                 cp++;
270         } else {
271                 int num_bytes = get_long_form_num_length_bytes(*cp);
272                 if (cp + num_bytes > end)
273                         return -E_BAD_PRIVATE_KEY;
274                 if (num_bytes > 4) /* nobody has such a large modulus */
275                         return -E_BAD_PRIVATE_KEY;
276                 cp++;
277                 bn_size = 0;
278                 for (i = 0; i < num_bytes; i++, cp++)
279                         bn_size = (bn_size << 8) + *cp;
280         }
281         PARA_DEBUG_LOG("bn_size %d (0x%x)\n", bn_size, (unsigned)bn_size);
282         gret = gcry_mpi_scan(bn, GCRYMPI_FMT_STD, cp, bn_size, NULL);
283         if (gret) {
284                 PARA_ERROR_LOG("%s while scanning n\n",
285                         gcry_strerror(gcry_err_code(gret)));
286                 return-E_MPI_SCAN;
287         }
288         /*
289          * Don't take the first leading zero into account for the size of the
290          * bignum.
291          */
292         if (*cp == '\0') {
293                 cp++;
294                 bn_size--;
295         }
296         if (bn_bytes)
297                 *bn_bytes = bn_size;
298         cp += bn_size;
299 //      unsigned char *buf;
300 //      gcry_mpi_aprint(GCRYMPI_FMT_HEX, &buf, NULL, *bn);
301 //      PARA_CRIT_LOG("bn: %s\n", buf);
302         return cp - start;
303 }
304
305 static int find_privkey_bignum_offset(const unsigned char *data, int len)
306 {
307         const unsigned char *p = data, *end = data + len;
308
309         /* like the public key, the whole thing is contained in a sequence */
310         if (*p != ASN1_TYPE_SEQUENCE)
311                 return -E_ASN1_PARSE;
312         p++;
313         if (p >= end)
314                 return -E_ASN1_PARSE;
315         if (is_short_form(*p))
316                 p++;
317         else
318                 p += 1 + get_long_form_num_length_bytes(*p);
319         if (p >= end)
320                 return -E_ASN1_PARSE;
321
322         /* skip next integer */
323         if (*p != ASN1_TYPE_INTEGER)
324                 return -E_ASN1_PARSE;
325         p++;
326         if (p >= end)
327                 return -E_ASN1_PARSE;
328         if (is_short_form(*p))
329                 p += 1 + get_short_form_length(*p);
330         else
331                 p += 1 + get_long_form_num_length_bytes(*p);
332         if (p >= end)
333                 return -E_ASN1_PARSE;
334         return p - data;
335 }
336
337 /** Private keys start with this header. */
338 #define PRIVATE_KEY_HEADER "-----BEGIN RSA PRIVATE KEY-----"
339 /** Private keys end with this footer. */
340 #define PRIVATE_KEY_FOOTER "-----END RSA PRIVATE KEY-----"
341
342 static int get_private_key(const char *key_file, struct asymmetric_key **result)
343 {
344         gcry_mpi_t n = NULL, e = NULL, d = NULL, p = NULL, q = NULL,
345                 u = NULL;
346         unsigned char *blob, *cp, *end;
347         int blob_size, ret, n_size;
348         gcry_error_t gret;
349         size_t erroff;
350         gcry_sexp_t sexp;
351         struct asymmetric_key *key;
352
353         ret = decode_key(key_file, PRIVATE_KEY_HEADER, PRIVATE_KEY_FOOTER,
354                 &blob);
355         if (ret < 0)
356                 return ret;
357         blob_size = ret;
358         end = blob + blob_size;
359         ret = find_privkey_bignum_offset(blob, blob_size);
360         if (ret < 0)
361                 goto free_blob;
362         PARA_INFO_LOG("reading RSA params at offset %d\n", ret);
363         cp = blob + ret;
364
365         ret = read_bignum(cp, end, &n, &n_size);
366         if (ret < 0)
367                 goto free_blob;
368         cp += ret;
369
370         ret = read_bignum(cp, end, &e, NULL);
371         if (ret < 0)
372                 goto release_n;
373         cp += ret;
374
375         ret = read_bignum(cp, end, &d, NULL);
376         if (ret < 0)
377                 goto release_e;
378         cp += ret;
379
380         ret = read_bignum(cp, end, &p, NULL);
381         if (ret < 0)
382                 goto release_d;
383         cp += ret;
384
385         ret = read_bignum(cp, end, &q, NULL);
386         if (ret < 0)
387                 goto release_p;
388         cp += ret;
389         ret = read_bignum(cp, end, &u, NULL);
390         if (ret < 0)
391                 goto release_q;
392         /*
393          * OpenSSL uses slightly different parameters than gcrypt. To use these
394          * parameters we need to swap the values of p and q and recompute u.
395          */
396         if (gcry_mpi_cmp(p, q) > 0) {
397                 gcry_mpi_swap(p, q);
398                 gcry_mpi_invm(u, p, q);
399         }
400         gret = gcry_sexp_build(&sexp, &erroff, RSA_PRIVKEY_SEXP,
401                 n, e, d, p, q, u);
402
403         if (gret) {
404                 PARA_ERROR_LOG("offset %zu: %s\n", erroff,
405                         gcry_strerror(gcry_err_code(gret)));
406                 ret = -E_SEXP_BUILD;
407                 goto release_u;
408         }
409         key = para_malloc(sizeof(*key));
410         key->sexp = sexp;
411         *result = key;
412         ret = n_size * 8;
413         PARA_INFO_LOG("succesfully read %d bit private key\n", ret);
414 release_u:
415         gcry_mpi_release(u);
416 release_q:
417         gcry_mpi_release(q);
418 release_p:
419         gcry_mpi_release(p);
420 release_d:
421         gcry_mpi_release(d);
422 release_e:
423         gcry_mpi_release(e);
424 release_n:
425         gcry_mpi_release(n);
426 free_blob:
427         free(blob);
428         return ret;
429 }
430
431 /** Public keys start with this header. */
432 #define PUBLIC_KEY_HEADER "-----BEGIN PUBLIC KEY-----"
433 /** Public keys end with this footer. */
434 #define PUBLIC_KEY_FOOTER "-----END PUBLIC KEY-----"
435
436 static int get_asn_public_key(const char *key_file, struct asymmetric_key **result)
437 {
438         gcry_mpi_t n = NULL, e = NULL;
439         unsigned char *blob, *cp, *end;
440         int blob_size, ret, n_size;
441         gcry_error_t gret;
442         size_t erroff;
443         gcry_sexp_t sexp;
444         struct asymmetric_key *key;
445
446         ret = decode_key(key_file, PUBLIC_KEY_HEADER, PUBLIC_KEY_FOOTER,
447                 &blob);
448         if (ret < 0)
449                 return ret;
450         blob_size = ret;
451         end = blob + blob_size;
452         ret = find_pubkey_bignum_offset(blob, blob_size);
453         if (ret < 0)
454                 goto free_blob;
455         PARA_DEBUG_LOG("decoding public RSA params at offset %d\n", ret);
456         cp = blob + ret;
457
458         ret = read_bignum(cp, end, &n, &n_size);
459         if (ret < 0)
460                 goto free_blob;
461         cp += ret;
462
463         ret = read_bignum(cp, end, &e, NULL);
464         if (ret < 0)
465                 goto release_n;
466
467         gret = gcry_sexp_build(&sexp, &erroff, RSA_PUBKEY_SEXP, n, e);
468         if (gret) {
469                 PARA_ERROR_LOG("offset %zu: %s\n", erroff,
470                         gcry_strerror(gcry_err_code(gret)));
471                 ret = -E_SEXP_BUILD;
472                 goto release_e;
473         }
474         key = para_malloc(sizeof(*key));
475         key->sexp = sexp;
476         key->num_bytes = n_size;
477         *result = key;
478         ret = n_size;
479         PARA_INFO_LOG("successfully read %d bit asn public key\n", n_size * 8);
480
481 release_e:
482         gcry_mpi_release(e);
483 release_n:
484         gcry_mpi_release(n);
485 free_blob:
486         free(blob);
487         return ret;
488 }
489
490 static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result)
491 {
492         int ret;
493         gcry_error_t gret;
494         unsigned char *blob = NULL, *p, *end;
495         size_t nr_scanned, erroff, decoded_size;
496         gcry_mpi_t e = NULL, n = NULL;
497
498         PARA_DEBUG_LOG("decoding %d byte public rsa-ssh key\n", size);
499         ret = uudecode((char *)data, size, (char **)&blob, &decoded_size);
500         if (ret < 0)
501                 goto free_blob;
502         end = blob + decoded_size;
503         dump_buffer("decoded key", blob, decoded_size);
504         ret = check_ssh_key_header(blob, decoded_size);
505         if (ret < 0)
506                 goto free_blob;
507         p = blob + ret;
508         ret = -E_SSH_PARSE;
509         if (p >= end)
510                 goto free_blob;
511         PARA_DEBUG_LOG("scanning modulus and public exponent\n");
512         gret = gcry_mpi_scan(&e, GCRYMPI_FMT_SSH, p, end - p, &nr_scanned);
513         if (gret) {
514                 ret = -E_MPI_SCAN;
515                 PARA_CRIT_LOG("%s\n", gcry_strerror(gcry_err_code(gret)));
516                 goto free_blob;
517         }
518         PARA_DEBUG_LOG("scanned e (%zu bytes)\n", nr_scanned);
519 //      gcry_mpi_aprint(GCRYMPI_FMT_HEX, &buf, NULL, rsa_e);
520 //      PARA_CRIT_LOG("e: %s\n", buf);
521         p += nr_scanned;
522         if (p >= end)
523                 goto release_e;
524         gret = gcry_mpi_scan(&n, GCRYMPI_FMT_SSH, p, end - p, &nr_scanned);
525         if (gret) {
526                 ret = -E_MPI_SCAN;
527                 PARA_ERROR_LOG("%s\n", gcry_strerror(gcry_err_code(gret)));
528                 goto release_e;
529         }
530         PARA_DEBUG_LOG("scanned n (%zu bytes)\n", nr_scanned);
531 //      gcry_mpi_aprint(GCRYMPI_FMT_HEX, &buf, NULL, rsa_n);
532 //      PARA_CRIT_LOG("n: %s\n", buf);
533         gret = gcry_sexp_build(result, &erroff, RSA_PUBKEY_SEXP, n, e);
534         if (gret) {
535                 PARA_ERROR_LOG("offset %zu: %s\n", erroff,
536                         gcry_strerror(gcry_err_code(gret)));
537                 ret = -E_SEXP_BUILD;
538                 goto release_n;
539         }
540         ret = nr_scanned / 32 * 32;
541         PARA_INFO_LOG("successfully read %d bit ssh public key\n", ret * 8);
542 release_n:
543         gcry_mpi_release(n);
544 release_e:
545         gcry_mpi_release(e);
546 free_blob:
547         free(blob);
548         return ret;
549 }
550
551 int get_asymmetric_key(const char *key_file, int private,
552                 struct asymmetric_key **result)
553 {
554         int ret, ret2;
555         void *map;
556         size_t map_size;
557         unsigned char *start, *end;
558         gcry_sexp_t sexp;
559         struct asymmetric_key *key;
560
561         if (private)
562                 return get_private_key(key_file, result);
563         ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL);
564         if (ret < 0)
565                 return ret;
566         ret = is_ssh_rsa_key(map, map_size);
567         if (!ret) {
568                 ret = para_munmap(map, map_size);
569                 if (ret < 0)
570                         return ret;
571                 return get_asn_public_key(key_file, result);
572         }
573         start = map + ret;
574         end = map + map_size;
575         ret = -E_SSH_PARSE;
576         if (start >= end)
577                 goto unmap;
578         ret = get_ssh_public_key(start, end - start, &sexp);
579         if (ret < 0)
580                 goto unmap;
581         key = para_malloc(sizeof(*key));
582         key->num_bytes = ret;
583         key->sexp = sexp;
584         *result = key;
585 unmap:
586         ret2 = para_munmap(map, map_size);
587         if (ret >= 0 && ret2 < 0)
588                 ret = ret2;
589         return ret;
590 }
591
592 void free_asymmetric_key(struct asymmetric_key *key)
593 {
594         if (!key)
595                 return;
596         gcry_sexp_release(key->sexp);
597         free(key);
598 }
599
600 static int decode_rsa(gcry_sexp_t sexp, unsigned char *outbuf, size_t *nbytes)
601 {
602         const char *p = gcry_sexp_nth_data(sexp, 1, nbytes);
603
604         if (!p) {
605                 PARA_ERROR_LOG("could not get data from list\n");
606                 return -E_OEAP;
607         }
608         memcpy(outbuf, p, *nbytes);
609         return 1;
610 }
611
612 int priv_decrypt(const char *key_file, unsigned char *outbuf,
613                 unsigned char *inbuf, int inlen)
614 {
615         gcry_error_t gret;
616         int ret;
617         struct asymmetric_key *priv;
618         gcry_mpi_t in_mpi = NULL;
619         gcry_sexp_t in, out, priv_key;
620         size_t nbytes;
621
622         ret = check_key_file(key_file, true);
623         if (ret < 0)
624                 return ret;
625         PARA_INFO_LOG("decrypting %d byte input\n", inlen);
626         /* key_file -> asymmetric key priv */
627         ret = get_private_key(key_file, &priv);
628         if (ret < 0)
629                 return ret;
630
631         /* asymmetric key priv -> sexp priv_key */
632         ret = -E_SEXP_FIND;
633         priv_key = gcry_sexp_find_token(priv->sexp, "private-key", 0);
634         if (!priv_key)
635                 goto free_key;
636
637         /* inbuf -> in_mpi */
638         gret = gcry_mpi_scan(&in_mpi, GCRYMPI_FMT_USG, inbuf,
639                 inlen, NULL);
640         if (gret) {
641                 PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
642                 ret = -E_MPI_SCAN;
643                 goto key_release;
644         }
645         /* in_mpi -> in sexp */
646         gret = gcry_sexp_build(&in, NULL, RSA_DECRYPT_SEXP, in_mpi);
647         if (gret) {
648                 PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
649                 ret = -E_SEXP_BUILD;
650                 goto in_mpi_release;
651         }
652
653         /* rsa decryption: in sexp -> out sexp */
654         gret = gcry_pk_decrypt(&out, in, priv_key);
655         if (gret) {
656                 PARA_ERROR_LOG("decrypt: %s\n", gcrypt_strerror(gret));
657                 ret = -E_SEXP_DECRYPT;
658                 goto in_release;
659         }
660         ret = decode_rsa(out, outbuf, &nbytes);
661         if (ret < 0)
662                 goto out_release;
663         PARA_INFO_LOG("successfully decrypted %zu byte message\n", nbytes);
664         ret = nbytes;
665 out_release:
666         gcry_sexp_release(out);
667 in_release:
668         gcry_sexp_release(in);
669 in_mpi_release:
670         gcry_mpi_release(in_mpi);
671 key_release:
672         gcry_sexp_release(priv_key);
673 free_key:
674         free_asymmetric_key(priv);
675         return ret;
676 }
677
678 int pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
679                 unsigned len, unsigned char *outbuf)
680 {
681         gcry_error_t gret;
682         gcry_sexp_t pub_key, in, out, out_a;
683         gcry_mpi_t out_mpi = NULL;
684         size_t nbytes;
685         int ret;
686
687         PARA_INFO_LOG("encrypting %u byte input with %d-byte key\n", len, pub->num_bytes);
688
689         /* get pub key */
690         pub_key = gcry_sexp_find_token(pub->sexp, "public-key", 0);
691         if (!pub_key)
692                 return -E_SEXP_FIND;
693         gret = gcry_sexp_build(&in, NULL, "(data(flags oaep)(value %b))", len, inbuf);
694         if (gret) {
695                 PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
696                 ret = -E_SEXP_BUILD;
697                 goto key_release;
698         }
699         /* rsa sexp encryption: in -> out */
700         gret = gcry_pk_encrypt(&out, in, pub_key);
701         if (gret) {
702                 PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
703                 ret = -E_SEXP_ENCRYPT;
704                 goto in_release;
705         }
706         /* extract a, an MPI with the result of the RSA operation */
707         ret = -E_SEXP_FIND;
708         out_a = gcry_sexp_find_token(out, "a", 0);
709         if (!out_a)
710                 goto out_release;
711         /* convert sexp out_a -> out_mpi */
712         out_mpi = gcry_sexp_nth_mpi(out_a, 1, GCRYMPI_FMT_USG);
713         if (!out_mpi) {
714                 ret = -E_SEXP_FIND;
715                 goto out_a_release;
716         }
717         gret = gcry_mpi_print(GCRYMPI_FMT_USG, outbuf, 512 /* FIXME */, &nbytes, out_mpi);
718         if (gret) {
719                 PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
720                 ret = -E_SEXP_ENCRYPT;
721                 goto out_mpi_release;
722         }
723         PARA_INFO_LOG("encrypted buffer is %zu bytes\n", nbytes);
724         dump_buffer("enc buf", outbuf, nbytes);
725         ret = nbytes;
726
727 out_mpi_release:
728         gcry_mpi_release(out_mpi);
729 out_a_release:
730         gcry_sexp_release(out_a);
731 out_release:
732         gcry_sexp_release(out);
733 in_release:
734         gcry_sexp_release(in);
735 key_release:
736         gcry_sexp_release(pub_key);
737         return ret;
738 }
739
740 struct stream_cipher {
741         gcry_cipher_hd_t handle;
742 };
743
744 struct stream_cipher *sc_new(const unsigned char *data, int len,
745                 bool use_aes)
746 {
747         gcry_error_t gret;
748         struct stream_cipher *sc = para_malloc(sizeof(*sc));
749
750         if (use_aes) {
751                 assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
752                 gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_AES128,
753                         GCRY_CIPHER_MODE_CTR, 0);
754                 assert(gret == 0);
755                 gret = gcry_cipher_setkey(sc->handle, data,
756                         AES_CRT128_BLOCK_SIZE);
757                 assert(gret == 0);
758                 gret = gcry_cipher_setctr(sc->handle,
759                         data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE);
760                 assert(gret == 0);
761                 return sc;
762         }
763         gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_ARCFOUR,
764                 GCRY_CIPHER_MODE_STREAM, 0);
765         if (gret) {
766                 PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
767                 free(sc);
768                 return NULL;
769         }
770         gret = gcry_cipher_setkey(sc->handle, data, (size_t)len);
771         assert(gret == 0);
772         return sc;
773 }
774
775 void sc_free(struct stream_cipher *sc)
776 {
777         if (!sc)
778                 return;
779         gcry_cipher_close(sc->handle);
780         free(sc);
781 }
782
783 void sc_crypt(struct stream_cipher *sc, struct iovec *src, struct iovec *dst)
784 {
785         gcry_cipher_hd_t handle = sc->handle;
786         gcry_error_t gret;
787
788         /* perform in-place encryption */
789         *dst = *src;
790         gret = gcry_cipher_encrypt(handle, src->iov_base, src->iov_len,
791                 NULL, 0);
792         assert(gret == 0);
793 }