[PATCH 3/3] Add a simple PKCS#1 padding mode
Dmitry Eremin-Solenikov
dbaryshkov at gmail.com
Sat Jul 13 16:50:07 CEST 2013
* cipher/pubkey.c (sexp_data_to_mpi, pkcs1_encode_for_signature_simple):
handle s-exp like (data (flags pkcs1) (value xxxxx))
Allow user to specify (flags pkcs1) to enable pkcs1 padding of raw value
(no hash algorithm is specified). It is up to the user to verify that
passed value is properly formatted and includes DER-encoded ASN OID of
the hash function.
Signed-off-by: Dmitry Eremin-Solenikov <dbaryshkov at gmail.com>
---
cipher/pubkey.c | 81 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
tests/basic.c | 2 +-
2 files changed, 82 insertions(+), 1 deletion(-)
diff --git a/cipher/pubkey.c b/cipher/pubkey.c
index 378e072..028cbb4 100644
--- a/cipher/pubkey.c
+++ b/cipher/pubkey.c
@@ -1126,6 +1126,73 @@ pkcs1_encode_for_signature (gcry_mpi_t *r_result, unsigned int nbits,
}
+/* Encode {VALUE,VALUELEN} for an NBITS keys and hash algorith ALGO
+ 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.)
+*/
+static gcry_err_code_t
+pkcs1_encode_for_signature_simple (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 = gcry_malloc (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);
+ gcry_free (frame);
+
+ return rc;
+}
+
+
/* Mask generation function for OAEP. See RFC-3447 B.2.1. */
static gcry_err_code_t
mgf1 (unsigned char *output, size_t outlen, unsigned char *seed, size_t seedlen,
@@ -2602,6 +2669,20 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi,
gcry_free (random_override);
}
}
+ else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lvalue
+ && (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
+ {
+ const void * value;
+ size_t valuelen;
+
+ if ( !(value=gcry_sexp_nth_data (lvalue, 1, &valuelen)) || !valuelen )
+ rc = GPG_ERR_INV_OBJ;
+ else
+ {
+ rc = pkcs1_encode_for_signature_simple (ret_mpi, ctx->nbits,
+ value, valuelen);
+ }
+ }
else if (ctx->encoding == PUBKEY_ENC_PKCS1 && lhash
&& (ctx->op == PUBKEY_OP_SIGN || ctx->op == PUBKEY_OP_VERIFY))
{
diff --git a/tests/basic.c b/tests/basic.c
index 01bdd46..a9cdbe6 100644
--- a/tests/basic.c
+++ b/tests/basic.c
@@ -2456,7 +2456,7 @@ check_pubkey_sign (int n, gcry_sexp_t skey, gcry_sexp_t pkey, int algo)
{ "(data\n (flags pkcs1)\n"
" (value #11223344556677889900AA#))\n",
GCRY_PK_RSA,
- GPG_ERR_CONFLICT },
+ 0 },
{ "(data\n (flags raw foo)\n"
" (value #11223344556677889900AA#))\n",
0,
--
1.7.10.4
More information about the Gcrypt-devel
mailing list