+int apc_pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
+ unsigned len, unsigned char *outbuf)
+{
+ gcry_error_t gret;
+ gcry_sexp_t pub_key, in, out, out_a;
+ gcry_mpi_t out_mpi = NULL;
+ size_t nbytes;
+ int ret;
+
+ PARA_INFO_LOG("encrypting %u byte input with %d-byte key\n", len, pub->num_bytes);
+
+ /* get pub key */
+ pub_key = gcry_sexp_find_token(pub->sexp, "public-key", 0);
+ if (!pub_key)
+ return -E_SEXP_FIND;
+ gret = gcry_sexp_build(&in, NULL, "(data(flags oaep)(value %b))", len, inbuf);
+ if (gret) {
+ PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
+ ret = -E_SEXP_BUILD;
+ goto key_release;
+ }
+ /* rsa sexp encryption: in -> out */
+ gret = gcry_pk_encrypt(&out, in, pub_key);
+ if (gret) {
+ PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
+ ret = -E_SEXP_ENCRYPT;
+ goto in_release;
+ }
+ /* extract a, an MPI with the result of the RSA operation */
+ ret = -E_SEXP_FIND;
+ out_a = gcry_sexp_find_token(out, "a", 0);
+ if (!out_a)
+ goto out_release;
+ /* convert sexp out_a -> out_mpi */
+ out_mpi = gcry_sexp_nth_mpi(out_a, 1, GCRYMPI_FMT_USG);
+ if (!out_mpi) {
+ ret = -E_SEXP_FIND;
+ goto out_a_release;
+ }
+ gret = gcry_mpi_print(GCRYMPI_FMT_USG, outbuf, 512 /* FIXME */, &nbytes, out_mpi);
+ if (gret) {
+ PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
+ ret = -E_SEXP_ENCRYPT;
+ goto out_mpi_release;
+ }
+ PARA_INFO_LOG("encrypted buffer is %zu bytes\n", nbytes);
+ dump_buffer("enc buf", outbuf, nbytes);
+ ret = nbytes;
+
+out_mpi_release:
+ gcry_mpi_release(out_mpi);
+out_a_release:
+ gcry_sexp_release(out_a);
+out_release:
+ gcry_sexp_release(out);
+in_release:
+ gcry_sexp_release(in);
+key_release:
+ gcry_sexp_release(pub_key);
+ return ret;
+}
+
+struct stream_cipher {
+ gcry_cipher_hd_t handle;
+};
+
+struct stream_cipher *sc_new(const unsigned char *data, int len)
+{
+ gcry_error_t gret;
+ struct stream_cipher *sc = para_malloc(sizeof(*sc));
+
+ assert(len >= 2 * AES_CRT128_BLOCK_SIZE);
+ gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_AES128,
+ GCRY_CIPHER_MODE_CTR, 0);
+ assert(gret == 0);
+ gret = gcry_cipher_setkey(sc->handle, data,
+ AES_CRT128_BLOCK_SIZE);
+ assert(gret == 0);
+ gret = gcry_cipher_setctr(sc->handle,
+ data + AES_CRT128_BLOCK_SIZE, AES_CRT128_BLOCK_SIZE);
+ assert(gret == 0);
+ return sc;
+}
+
+void sc_free(struct stream_cipher *sc)