[PATCH v2] Add a simple (raw) PKCS#1 padding mode

Dmitry Eremin-Solenikov dbaryshkov at gmail.com
Sun Dec 22 14:12:28 CET 2013


* src/cipher.h (PUBKEY_ENC_PKCS1_RAW): New.
* cipher/pubkey-util.c (_gcry_pk_util_parse_flaglist): Handle pkcs1-raw
  flag.
* cipher/pubkey-util.c (_gcry_pk_util_data_to_mpi):
  Handle s-exp like (data (flags pkcs1-raw) (value xxxxx))
* cipher/rsa-common.c (_gcry_rsa_pkcs1_encode_raw_for_sig):
  PKCS#1-encode data with embedded hash OID for signature verification.
* tests/basic.c (check_pubkey_sign): Add tests for s-exps with pkcs1-raw
  flag.

--
Allow user to specify (flags pkcs1-raw) to enable pkcs1 padding of raw
value (no hash algorithm is specified). It is up to the user to verify
that the passed value is properly formatted and includes DER-encoded
ASN OID of the used hash function.

Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov at gmail.com>
---
 cipher/pubkey-internal.h |  4 +++
 cipher/pubkey-util.c     | 25 +++++++++++++++++++
 cipher/rsa-common.c      | 65 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/cipher.h             |  1 +
 tests/basic.c            |  8 ++++++
 5 files changed, 103 insertions(+)

diff --git a/cipher/pubkey-internal.h b/cipher/pubkey-internal.h
index db1399d..96fe0e4 100644
--- a/cipher/pubkey-internal.h
+++ b/cipher/pubkey-internal.h
@@ -56,6 +56,10 @@ gpg_err_code_t
 _gcry_rsa_pkcs1_decode_for_enc (unsigned char **r_result, size_t *r_resultlen,
                                 unsigned int nbits, gcry_mpi_t value);
 gpg_err_code_t
+_gcry_rsa_pkcs1_encode_raw_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
+                                const unsigned char *value, size_t valuelen);
+
+gpg_err_code_t
 _gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
                                 const unsigned char *value, size_t valuelen,
                                 int algo);
diff --git a/cipher/pubkey-util.c b/cipher/pubkey-util.c
index 616b499..514f1eb 100644
--- a/cipher/pubkey-util.c
+++ b/cipher/pubkey-util.c
@@ -142,6 +142,16 @@ _gcry_pk_util_parse_flaglist (gcry_sexp_t list,
             rc = GPG_ERR_INV_FLAG;
           break;
 
+	case 9:
+          if (!memcmp (s, "pkcs1-raw", 9) && encoding == PUBKEY_ENC_UNKNOWN)
+            {
+              encoding = PUBKEY_ENC_PKCS1_RAW;
+              flags |= PUBKEY_FLAG_FIXEDLEN;
+            }
+          else if (!igninvflag)
+            rc = GPG_ERR_INV_FLAG;
+          break;
+
         case 10:
           if (!memcmp (s, "igninvflag", 10))
             igninvflag = 1;
@@ -850,6 +860,21 @@ _gcry_pk_util_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
                                                  ctx->hash_algo);
         }
     }
+  else if (ctx->encoding == PUBKEY_ENC_PKCS1_RAW && lvalue
+	   && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
+    {
+      const void * value;
+      size_t valuelen;
+
+      if (sexp_length (lvalue) != 2)
+        rc = GPG_ERR_INV_OBJ;
+      else if ( !(value=sexp_nth_data (lvalue, 1, &valuelen))
+                || !valuelen )
+        rc = GPG_ERR_INV_OBJ;
+      else
+        rc = _gcry_rsa_pkcs1_encode_raw_for_sig (ret_mpi, ctx->nbits,
+                                                 value, valuelen);
+    }
   else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue
 	   && ctx->op == PUBKEY_OP_ENCRYPT)
     {
diff --git a/cipher/rsa-common.c b/cipher/rsa-common.c
index 4f5a659..f56e989 100644
--- a/cipher/rsa-common.c
+++ b/cipher/rsa-common.c
@@ -319,6 +319,71 @@ _gcry_rsa_pkcs1_encode_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
   return rc;
 }
 
+/* Encode {VALUE,VALUELEN} for an NBITS keys using the pkcs#1 block
+   type 1 padding.  On success the result is stored as a new MPI at
+   R_RESULT.  On error the value at R_RESULT is undefined.
+
+   We encode the value in this way:
+
+     0  1  PAD(n bytes)  0  VALUE(valuelen bytes)
+
+   0   is a marker we unfortunately can't encode because we return an
+       MPI which strips all leading zeroes.
+   1   is the block type.
+   PAD consists of 0xff bytes.
+   0   marks the end of the padding.
+
+   (Note that PGP prior to version 2.3 encoded the message digest as:
+      0   1   MD(16 bytes)   0   PAD(n bytes)   1
+    The MD is always 16 bytes here because it's always MD5.  GnuPG
+    does not not support pre-v2.3 signatures, but I'm including this
+    comment so the information is easily found if needed.)
+*/
+gpg_err_code_t
+_gcry_rsa_pkcs1_encode_raw_for_sig (gcry_mpi_t *r_result, unsigned int nbits,
+                                const unsigned char *value, size_t valuelen)
+{
+  gcry_err_code_t rc = 0;
+  gcry_error_t err;
+  byte *frame = NULL;
+  size_t nframe = (nbits+7) / 8;
+  int i;
+  size_t n;
+
+  if ( !valuelen || valuelen + 4 > nframe)
+    {
+      /* Can't encode an DLEN byte digest MD into an NFRAME byte
+         frame.  */
+      return GPG_ERR_TOO_SHORT;
+    }
+
+  if ( !(frame = xtrymalloc (nframe)) )
+    return gpg_err_code_from_syserror ();
+
+  /* Assemble the pkcs#1 block type 1. */
+  n = 0;
+  frame[n++] = 0;
+  frame[n++] = 1; /* block type */
+  i = nframe - valuelen - 3 ;
+  gcry_assert (i > 1);
+  memset (frame+n, 0xff, i );
+  n += i;
+  frame[n++] = 0;
+  memcpy (frame+n, value, valuelen );
+  n += valuelen;
+  gcry_assert (n == nframe);
+
+  /* Convert it into an MPI. */
+  err = _gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, n, &nframe);
+  if (err)
+    rc = gcry_err_code (err);
+  else if (DBG_CIPHER)
+    log_mpidump ("PKCS#1 block type 1 encoded data", *r_result);
+  xfree (frame);
+
+  return rc;
+}
+
 
 /* Mask generation function for OAEP.  See RFC-3447 B.2.1.  */
 static gcry_err_code_t
diff --git a/src/cipher.h b/src/cipher.h
index 10bfe0c..26ffddc 100644
--- a/src/cipher.h
+++ b/src/cipher.h
@@ -54,6 +54,7 @@ enum pk_encoding
   {
     PUBKEY_ENC_RAW,
     PUBKEY_ENC_PKCS1,
+    PUBKEY_ENC_PKCS1_RAW,
     PUBKEY_ENC_OAEP,
     PUBKEY_ENC_PSS,
     PUBKEY_ENC_UNKNOWN
diff --git a/tests/basic.c b/tests/basic.c
index 0eb8215..055b7b6 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -5092,6 +5092,10 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
 	" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
 	GCRY_PK_RSA,
 	0 },
+      { "(data\n (flags pkcs1-raw)\n"
+	" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
+	GCRY_PK_RSA,
+	GPG_ERR_CONFLICT },
       { "(data\n (flags oaep)\n"
 	" (hash sha1 #11223344556677889900AABBCCDDEEFF10203040#))\n",
 	0,
@@ -5124,6 +5128,10 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
 	" (value #11223344556677889900AA#))\n",
 	GCRY_PK_RSA,
 	GPG_ERR_CONFLICT },
+      { "(data\n (flags pkcs1-raw)\n"
+	" (value #11223344556677889900AA#))\n",
+	GCRY_PK_RSA,
+	0 },
       { "(data\n (flags raw foo)\n"
 	" (value #11223344556677889900AA#))\n",
 	0,
-- 
1.8.5.1




More information about the Gcrypt-devel mailing list