gcrypt: Remove open-coded OAEP padding.
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 10 Jul 2016 14:15:37 +0000 (16:15 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Sat, 7 Jan 2017 19:21:18 +0000 (20:21 +0100)
The open-coded OAEP padding implementaton of gcrypt.c was necessary to
support old libgcrypt versions which do not have the oaep flag. These
days, everybody ought to have moved on to 1.5.0 (released 2011)
or later, so lets require this version from now on.

decode_rsa() used its key_size parameter only for old gcrypt versions,
so the parameter can be removed. Also, the E_MPI_PRINT error code
has become unused and can be removed from error.h.

Since rsa_decrypt_sexp is now constant, there is no need to have a
variable for this, so we can make it a preprocessor definition instead.

error.h
gcrypt.c

diff --git a/error.h b/error.h
index 899c574..dbd97ae 100644 (file)
--- a/error.h
+++ b/error.h
        PARA_ERROR(MP3_INFO, "could not read mp3 info"), \
        PARA_ERROR(MP4ASC, "audio spec config error"), \
        PARA_ERROR(MP4V2, "mp4v2 library error"), \
-       PARA_ERROR(MPI_PRINT, "could not convert multi-precision integer"), \
        PARA_ERROR(MPI_SCAN, "could not scan multi-precision integer"), \
        PARA_ERROR(NAME_TOO_LONG, "name too long for struct sockaddr_un"), \
        PARA_ERROR(NO_AFHI, "audio format handler info required"), \
index 7c19aeb..f4dbeb8 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,27 @@ 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";
+       req_ver = "1.5.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)))";
-       }
 }
 
 /** 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;
@@ -707,72 +597,23 @@ void free_asymmetric_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) {
+               PARA_ERROR_LOG("could not get data from list\n");
+               return -E_OEAP;
+       }
+       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;
@@ -786,7 +627,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;
@@ -803,7 +643,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;
@@ -817,7 +657,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);
@@ -850,18 +690,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;