mood: Speed up int_sqrt().
[paraslash.git] / gcrypt.c
index 1ae7cfb..1fde479 100644 (file)
--- a/gcrypt.c
+++ b/gcrypt.c
@@ -19,9 +19,6 @@
 
 //#define GCRYPT_DEBUG 1
 
-static bool libgcrypt_has_oaep;
-static const char *rsa_decrypt_sexp;
-
 #ifdef GCRYPT_DEBUG
 static void dump_buffer(const char *msg, unsigned char *buf, int len)
 {
@@ -63,134 +60,25 @@ void get_random_bytes_or_die(unsigned char *buf, int num)
  * don't have to initialize any random seed here, but we must initialize the
  * gcrypt library. This task is performed by gcry_check_version() which can
  * also check that the gcrypt library version is at least the minimal required
- * version. This function also tells us whether we have to use our own OAEP
- * padding code.
+ * version.
  */
 void init_random_seed_or_die(void)
 {
-       const char *ver, *req_ver;
-
-       ver = gcry_check_version(NULL);
-       req_ver = "1.4.0";
-       if (!gcry_check_version(req_ver)) {
-               PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n",
-                       req_ver, ver);
-               exit(EXIT_FAILURE);
-       }
-       req_ver = "1.5.0";
-       if (gcry_check_version(req_ver)) {
-               libgcrypt_has_oaep = true;
-               rsa_decrypt_sexp = "(enc-val(flags oaep)(rsa(a %m)))";
-       } else {
-               libgcrypt_has_oaep = false;
-               rsa_decrypt_sexp = "(enc-val(rsa(a %m)))";
-       }
+       const char *req_ver = "1.5.0";
+
+       if (gcry_check_version(req_ver))
+               return;
+       PARA_EMERG_LOG("fatal: need at least libgcrypt-%s, have: %s\n",
+               req_ver, gcry_check_version(NULL));
+       exit(EXIT_FAILURE);
 }
 
 /** S-expression for the public part of an RSA key. */
 #define RSA_PUBKEY_SEXP "(public-key (rsa (n %m) (e %m)))"
 /** S-expression for a private RSA key. */
 #define RSA_PRIVKEY_SEXP "(private-key (rsa (n %m) (e %m) (d %m) (p %m) (q %m) (u %m)))"
-
-/* rfc 3447, appendix B.2 */
-static void mgf1(unsigned char *seed, size_t seed_len, unsigned result_len,
-               unsigned char *result)
-{
-       gcry_error_t gret;
-       gcry_md_hd_t handle;
-       size_t n;
-       unsigned char *md;
-       unsigned char octet_string[4], *rp = result, *end = rp + result_len;
-
-       assert(result_len / HASH_SIZE < 1ULL << 31);
-       gret = gcry_md_open(&handle, GCRY_MD_SHA1, 0);
-       assert(gret == 0);
-       for (n = 0; rp < end; n++) {
-               gcry_md_write(handle, seed, seed_len);
-               octet_string[0] = (unsigned char)((n >> 24) & 255);
-               octet_string[1] = (unsigned char)((n >> 16) & 255);
-               octet_string[2] = (unsigned char)((n >> 8)) & 255;
-               octet_string[3] = (unsigned char)(n & 255);
-               gcry_md_write(handle, octet_string, 4);
-               gcry_md_final(handle);
-               md = gcry_md_read(handle, GCRY_MD_SHA1);
-               memcpy(rp, md, PARA_MIN(HASH_SIZE, (int)(end - rp)));
-               rp += HASH_SIZE;
-               gcry_md_reset(handle);
-       }
-       gcry_md_close(handle);
-}
-
-/** The sha1 hash of an empty file. */
-static const unsigned char empty_hash[HASH_SIZE] =
-       "\xda" "\x39" "\xa3" "\xee" "\x5e"
-       "\x6b" "\x4b" "\x0d" "\x32" "\x55"
-       "\xbf" "\xef" "\x95" "\x60" "\x18"
-       "\x90" "\xaf" "\xd8" "\x07" "\x09";
-
-/* rfc3447, section 7.1.1 */
-static void pad_oaep(unsigned char *in, size_t in_len, unsigned char *out,
-               size_t out_len)
-{
-       size_t ps_len = out_len - in_len - 2 * HASH_SIZE - 2;
-       size_t n, mask_len = out_len - HASH_SIZE - 1;
-       unsigned char *seed = out + 1, *db = seed + HASH_SIZE,
-               *ps = db + HASH_SIZE, *one = ps + ps_len;
-       unsigned char *db_mask, seed_mask[HASH_SIZE];
-
-       assert(in_len <= out_len - 2 - 2 * HASH_SIZE);
-       assert(out_len > 2 * HASH_SIZE + 2);
-       PARA_DEBUG_LOG("padding %zu byte input -> %zu byte output\n",
-               in_len, out_len);
-       dump_buffer("unpadded buffer", in, in_len);
-
-       out[0] = '\0';
-       get_random_bytes_or_die(seed, HASH_SIZE);
-       memcpy(db, empty_hash, HASH_SIZE);
-       memset(ps, 0, ps_len);
-       *one = 0x01;
-       memcpy(one + 1, in, in_len);
-       db_mask = para_malloc(mask_len);
-       mgf1(seed, HASH_SIZE, mask_len, db_mask);
-       for (n = 0; n < mask_len; n++)
-               db[n] ^= db_mask[n];
-       mgf1(db, mask_len, HASH_SIZE, seed_mask);
-       for (n = 0; n < HASH_SIZE; n++)
-               seed[n] ^= seed_mask[n];
-       free(db_mask);
-       dump_buffer("padded buffer", out, out_len);
-}
-
-/* rfc 3447, section 7.1.2 */
-static int unpad_oaep(unsigned char *in, size_t in_len, unsigned char *out,
-               size_t *out_len)
-{
-       unsigned char *masked_seed = in + 1;
-       unsigned char *db = in + 1 + HASH_SIZE;
-       unsigned char seed[HASH_SIZE], seed_mask[HASH_SIZE];
-       unsigned char *db_mask, *p;
-       size_t n, mask_len = in_len - HASH_SIZE - 1;
-
-       mgf1(db, mask_len, HASH_SIZE, seed_mask);
-       for (n = 0; n < HASH_SIZE; n++)
-               seed[n] = masked_seed[n] ^ seed_mask[n];
-       db_mask = para_malloc(mask_len);
-       mgf1(seed, HASH_SIZE, mask_len, db_mask);
-       for (n = 0; n < mask_len; n++)
-               db[n] ^= db_mask[n];
-       free(db_mask);
-       if (memcmp(db, empty_hash, HASH_SIZE))
-               return -E_OEAP;
-       for (p = db + HASH_SIZE; p < in + in_len - 1; p++)
-               if (*p != '\0')
-                       break;
-       if (p >= in + in_len - 1)
-               return -E_OEAP;
-       p++;
-       *out_len = in + in_len - p;
-       memcpy(out, p, *out_len);
-       return 1;
-}
+/** S-expression for decryption. */
+#define RSA_DECRYPT_SEXP "(enc-val(flags oaep)(rsa(a %m)))"
 
 struct asymmetric_key {
        gcry_sexp_t sexp;
@@ -586,72 +474,21 @@ void free_public_key(struct asymmetric_key *key)
        free(key);
 }
 
-static int decode_rsa(gcry_sexp_t sexp, int key_size, unsigned char *outbuf,
-               size_t *nbytes)
+static int decode_rsa(gcry_sexp_t sexp, unsigned char *outbuf, size_t *nbytes)
 {
-       int ret;
-       gcry_error_t gret;
-       unsigned char oaep_buf[512];
-       gcry_mpi_t out_mpi;
-
-       if (libgcrypt_has_oaep) {
-               const char *p = gcry_sexp_nth_data(sexp, 1, nbytes);
-
-               if (!p) {
-                       PARA_ERROR_LOG("could not get data from list\n");
-                       return -E_OEAP;
-               }
-               memcpy(outbuf, p, *nbytes);
-               return 1;
-       }
-       out_mpi = gcry_sexp_nth_mpi(sexp, 0, GCRYMPI_FMT_USG);
-       if (!out_mpi)
-               return -E_SEXP_FIND;
-       gret = gcry_mpi_print(GCRYMPI_FMT_USG, oaep_buf, sizeof(oaep_buf),
-               nbytes, out_mpi);
-       if (gret) {
-               PARA_ERROR_LOG("mpi_print: %s\n", gcrypt_strerror(gret));
-               ret = -E_MPI_PRINT;
-               goto out_mpi_release;
-       }
-       /*
-        * An oaep-encoded buffer always starts with at least one zero byte.
-        * However, leading zeroes in an mpi are omitted in the output of
-        * gcry_mpi_print() when using the GCRYMPI_FMT_USG format. The
-        * alternative, GCRYMPI_FMT_STD, does not work either because here the
-        * leading zero(es) might also be omitted, depending on the value of
-        * the second byte.
-        *
-        * To circumvent this, we shift the oaep buffer to the right. But first
-        * we check that the buffer actually started with a zero byte, i.e. that
-        * nbytes < key_size. Otherwise a decoding error occurred.
-        */
-       ret = -E_SEXP_DECRYPT;
-       if (*nbytes >= key_size)
-               goto out_mpi_release;
-       memmove(oaep_buf + key_size - *nbytes, oaep_buf, *nbytes);
-       memset(oaep_buf, 0, key_size - *nbytes);
+       const char *p = gcry_sexp_nth_data(sexp, 1, nbytes);
 
-       PARA_DEBUG_LOG("decrypted buffer before unpad (%d bytes):\n",
-               key_size);
-       dump_buffer("non-unpadded decrypted buffer", oaep_buf, key_size);
-       ret = unpad_oaep(oaep_buf, key_size, outbuf, nbytes);
-       if (ret < 0)
-               goto out_mpi_release;
-       PARA_DEBUG_LOG("decrypted buffer after unpad (%zu bytes):\n",
-               *nbytes);
-       dump_buffer("unpadded decrypted buffer", outbuf, *nbytes);
-       ret = 1;
-out_mpi_release:
-       gcry_mpi_release(out_mpi);
-       return ret;
+       if (!p)
+               return -E_RSA_DECODE;
+       memcpy(outbuf, p, *nbytes);
+       return 1;
 }
 
 int priv_decrypt(const char *key_file, unsigned char *outbuf,
                unsigned char *inbuf, int inlen)
 {
        gcry_error_t gret;
-       int ret, key_size;
+       int ret;
        struct asymmetric_key *priv;
        gcry_mpi_t in_mpi = NULL;
        gcry_sexp_t in, out, priv_key;
@@ -665,7 +502,6 @@ int priv_decrypt(const char *key_file, unsigned char *outbuf,
        ret = get_private_key(key_file, &priv);
        if (ret < 0)
                return ret;
-       key_size = ret / 8;
 
        /* asymmetric key priv -> sexp priv_key */
        ret = -E_SEXP_FIND;
@@ -682,7 +518,7 @@ int priv_decrypt(const char *key_file, unsigned char *outbuf,
                goto key_release;
        }
        /* in_mpi -> in sexp */
-       gret = gcry_sexp_build(&in, NULL, rsa_decrypt_sexp, in_mpi);
+       gret = gcry_sexp_build(&in, NULL, RSA_DECRYPT_SEXP, in_mpi);
        if (gret) {
                PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
                ret = -E_SEXP_BUILD;
@@ -696,7 +532,7 @@ int priv_decrypt(const char *key_file, unsigned char *outbuf,
                ret = -E_SEXP_DECRYPT;
                goto in_release;
        }
-       ret = decode_rsa(out, key_size, outbuf, &nbytes);
+       ret = decode_rsa(out, outbuf, &nbytes);
        if (ret < 0)
                goto out_release;
        PARA_INFO_LOG("successfully decrypted %zu byte message\n", nbytes);
@@ -730,18 +566,7 @@ int pub_encrypt(struct asymmetric_key *pub, unsigned char *inbuf,
        pub_key = gcry_sexp_find_token(pub->sexp, "public-key", 0);
        if (!pub_key)
                return -E_SEXP_FIND;
-       if (libgcrypt_has_oaep) {
-               gret = gcry_sexp_build(&in, NULL,
-                       "(data(flags oaep)(value %b))", len, inbuf);
-       } else {
-               unsigned char padded_input[256];
-               const size_t pad_size = 256;
-               /* inbuf -> padded inbuf */
-               pad_oaep(inbuf, len, padded_input, pad_size);
-               /* padded inbuf -> in sexp */
-               gret = gcry_sexp_build(&in, NULL,
-                       "(data(flags raw)(value %b))", pad_size, padded_input);
-       }
+       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;
@@ -792,33 +617,20 @@ struct stream_cipher {
        gcry_cipher_hd_t handle;
 };
 
-struct stream_cipher *sc_new(const unsigned char *data, int len,
-               bool use_aes)
+struct stream_cipher *sc_new(const unsigned char *data, int len)
 {
        gcry_error_t gret;
        struct stream_cipher *sc = para_malloc(sizeof(*sc));
 
-       if (use_aes) {
-               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;
-       }
-       gret = gcry_cipher_open(&sc->handle, GCRY_CIPHER_ARCFOUR,
-               GCRY_CIPHER_MODE_STREAM, 0);
-       if (gret) {
-               PARA_ERROR_LOG("%s\n", gcrypt_strerror(gret));
-               free(sc);
-               return NULL;
-       }
-       gret = gcry_cipher_setkey(sc->handle, data, (size_t)len);
+       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;
 }