[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