diff options
author | Werner Koch <wk@gnupg.org> | 2013-09-07 10:06:46 +0200 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2013-09-19 16:43:33 +0200 |
commit | 071f70b9a766187fc70f6abc6a69d50752449285 (patch) | |
tree | 52508dcffe687cfa1385f010077d7ffb87c2fe20 /cipher/pubkey.c | |
parent | eca9e2e50ddd4c9020fe1d4a9a3c77d20ebb90f6 (diff) | |
download | libgcrypt-071f70b9a766187fc70f6abc6a69d50752449285.tar.gz |
pk: Move RSA encoding functions to a new file.
* cipher/rsa-common: New.
* cipher/pubkey.c (pkcs1_encode_for_encryption): Move to rsa-common.c
and rename to _gcry_rsa_pkcs1_encode_for_enc.
(pkcs1_decode_for_encryption): Move to rsa-common.c and rename to
_gcry_rsa_pkcs1_decode_for_enc.
(pkcs1_encode_for_signature): Move to rsa-common.c and rename to
_gcry_rsa_pkcs1_encode_for_sig.
(oaep_encode): Move to rsa-common.c and rename to
_gcry_rsa_oaep_encode.
(oaep_decode): Move to rsa-common.c and rename to
_gcry_rsa_oaep_decode.
(pss_encode): Move to rsa-common.c and rename to _gcry_rsa_pss_encode.
(pss_verify): Move to rsa-common.c and rename to _gcry_rsa_pss_decode.
(octet_string_from_mpi, mgf1): Move to rsa-common.c.
Signed-off-by: Werner Koch <wk@gnupg.org>
Diffstat (limited to 'cipher/pubkey.c')
-rw-r--r-- | cipher/pubkey.c | 1026 |
1 files changed, 38 insertions, 988 deletions
diff --git a/cipher/pubkey.c b/cipher/pubkey.c index dc56cc31..25859817 100644 --- a/cipher/pubkey.c +++ b/cipher/pubkey.c @@ -297,975 +297,6 @@ pubkey_check_secret_key (int algo, gcry_mpi_t *skey) } -/* Turn VALUE into an octet string and store it in an allocated buffer - at R_FRAME or - if R_RAME is NULL - copy it into the caller - provided buffer SPACE; either SPACE or R_FRAME may be used. If - SPACE if not NULL, the caller must provide a buffer of at least - NBYTES. If the resulting octet string is shorter than NBYTES pad - it to the left with zeroes. If VALUE does not fit into NBYTES - return an error code. */ -static gpg_err_code_t -octet_string_from_mpi (unsigned char **r_frame, void *space, - gcry_mpi_t value, size_t nbytes) -{ - return _gcry_mpi_to_octet_string (r_frame, space, value, nbytes); -} - - -/* Encode {VALUE,VALUELEN} for an NBITS keys using the pkcs#1 block - type 2 padding. On sucess the result is stored as a new MPI at - R_RESULT. On error the value at R_RESULT is undefined. - - If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as - the seed instead of using a random string for it. This feature is - only useful for regression tests. Note that this value may not - contain zero bytes. - - We encode the value in this way: - - 0 2 RND(n bytes) 0 VALUE - - 0 is a marker we unfortunately can't encode because we return an - MPI which strips all leading zeroes. - 2 is the block type. - RND are non-zero random bytes. - - (Note that OpenPGP includes the cipher algorithm and a checksum in - VALUE; the caller needs to prepare the value accordingly.) - */ -static gcry_err_code_t -pkcs1_encode_for_encryption (gcry_mpi_t *r_result, unsigned int nbits, - const unsigned char *value, size_t valuelen, - const unsigned char *random_override, - size_t random_override_len) -{ - gcry_err_code_t rc = 0; - gcry_error_t err; - unsigned char *frame = NULL; - size_t nframe = (nbits+7) / 8; - int i; - size_t n; - unsigned char *p; - - if (valuelen + 7 > nframe || !nframe) - { - /* Can't encode a VALUELEN value in a NFRAME bytes frame. */ - return GPG_ERR_TOO_SHORT; /* The key is too short. */ - } - - if ( !(frame = gcry_malloc_secure (nframe))) - return gpg_err_code_from_syserror (); - - n = 0; - frame[n++] = 0; - frame[n++] = 2; /* block type */ - i = nframe - 3 - valuelen; - gcry_assert (i > 0); - - if (random_override) - { - int j; - - if (random_override_len != i) - { - gcry_free (frame); - return GPG_ERR_INV_ARG; - } - /* Check that random does not include a zero byte. */ - for (j=0; j < random_override_len; j++) - if (!random_override[j]) - { - gcry_free (frame); - return GPG_ERR_INV_ARG; - } - memcpy (frame + n, random_override, random_override_len); - n += random_override_len; - } - else - { - p = gcry_random_bytes_secure (i, GCRY_STRONG_RANDOM); - /* Replace zero bytes by new values. */ - for (;;) - { - int j, k; - unsigned char *pp; - - /* Count the zero bytes. */ - for (j=k=0; j < i; j++) - { - if (!p[j]) - k++; - } - if (!k) - break; /* Okay: no (more) zero bytes. */ - - k += k/128 + 3; /* Better get some more. */ - pp = gcry_random_bytes_secure (k, GCRY_STRONG_RANDOM); - for (j=0; j < i && k; ) - { - if (!p[j]) - p[j] = pp[--k]; - if (p[j]) - j++; - } - gcry_free (pp); - } - memcpy (frame+n, p, i); - n += i; - gcry_free (p); - } - - frame[n++] = 0; - memcpy (frame+n, value, valuelen); - n += valuelen; - gcry_assert (n == nframe); - - 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 2 encoded data", *r_result); - gcry_free (frame); - - return rc; -} - - -/* Decode a plaintext in VALUE assuming pkcs#1 block type 2 padding. - NBITS is the size of the secret key. On success the result is - stored as a newly allocated buffer at R_RESULT and its valid length at - R_RESULTLEN. On error NULL is stored at R_RESULT. */ -static gcry_err_code_t -pkcs1_decode_for_encryption (unsigned char **r_result, size_t *r_resultlen, - unsigned int nbits, gcry_mpi_t value) -{ - gcry_error_t err; - unsigned char *frame = NULL; - size_t nframe = (nbits+7) / 8; - size_t n; - - *r_result = NULL; - - if ( !(frame = gcry_malloc_secure (nframe))) - return gpg_err_code_from_syserror (); - - err = gcry_mpi_print (GCRYMPI_FMT_USG, frame, nframe, &n, value); - if (err) - { - gcry_free (frame); - return gcry_err_code (err); - } - - nframe = n; /* Set NFRAME to the actual length. */ - - /* FRAME = 0x00 || 0x02 || PS || 0x00 || M - - pkcs#1 requires that the first byte is zero. Our MPIs usually - strip leading zero bytes; thus we are not able to detect them. - However due to the way gcry_mpi_print is implemented we may see - leading zero bytes nevertheless. We handle this by making the - first zero byte optional. */ - if (nframe < 4) - { - gcry_free (frame); - return GPG_ERR_ENCODING_PROBLEM; /* Too short. */ - } - n = 0; - if (!frame[0]) - n++; - if (frame[n++] != 0x02) - { - gcry_free (frame); - return GPG_ERR_ENCODING_PROBLEM; /* Wrong block type. */ - } - - /* Skip the non-zero random bytes and the terminating zero byte. */ - for (; n < nframe && frame[n] != 0x00; n++) - ; - if (n+1 >= nframe) - { - gcry_free (frame); - return GPG_ERR_ENCODING_PROBLEM; /* No zero byte. */ - } - n++; /* Skip the zero byte. */ - - /* To avoid an extra allocation we reuse the frame buffer. The only - caller of this function will anyway free the result soon. */ - memmove (frame, frame + n, nframe - n); - *r_result = frame; - *r_resultlen = nframe - n; - - if (DBG_CIPHER) - log_printhex ("value extracted from PKCS#1 block type 2 encoded data", - *r_result, *r_resultlen); - - return 0; -} - - -/* 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 ASN(asnlen bytes) 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. - ASN is the DER encoding of the hash algorithm; along with the VALUE - it yields a valid DER encoding. - - (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 (gcry_mpi_t *r_result, unsigned int nbits, - const unsigned char *value, size_t valuelen, - int algo) -{ - gcry_err_code_t rc = 0; - gcry_error_t err; - byte asn[100]; - byte *frame = NULL; - size_t nframe = (nbits+7) / 8; - int i; - size_t n; - size_t asnlen, dlen; - - asnlen = DIM(asn); - dlen = gcry_md_get_algo_dlen (algo); - - if (gcry_md_algo_info (algo, GCRYCTL_GET_ASNOID, asn, &asnlen)) - { - /* We don't have yet all of the above algorithms. */ - return GPG_ERR_NOT_IMPLEMENTED; - } - - if ( valuelen != dlen ) - { - /* Hash value does not match the length of digest for - the given algorithm. */ - return GPG_ERR_CONFLICT; - } - - if ( !dlen || dlen + asnlen + 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 - asnlen - 3 ; - gcry_assert (i > 1); - memset (frame+n, 0xff, i ); - n += i; - frame[n++] = 0; - memcpy (frame+n, asn, asnlen); - n += asnlen; - 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, - int algo) -{ - size_t dlen, nbytes, n; - int idx; - gcry_md_hd_t hd; - gcry_error_t err; - - err = gcry_md_open (&hd, algo, 0); - if (err) - return gpg_err_code (err); - - dlen = gcry_md_get_algo_dlen (algo); - - /* We skip step 1 which would be assert(OUTLEN <= 2^32). The loop - in step 3 is merged with step 4 by concatenating no more octets - than what would fit into OUTPUT. The ceiling for the counter IDX - is implemented indirectly. */ - nbytes = 0; /* Step 2. */ - idx = 0; - while ( nbytes < outlen ) - { - unsigned char c[4], *digest; - - if (idx) - gcry_md_reset (hd); - - c[0] = (idx >> 24) & 0xFF; - c[1] = (idx >> 16) & 0xFF; - c[2] = (idx >> 8) & 0xFF; - c[3] = idx & 0xFF; - idx++; - - gcry_md_write (hd, seed, seedlen); - gcry_md_write (hd, c, 4); - digest = gcry_md_read (hd, 0); - - n = (outlen - nbytes < dlen)? (outlen - nbytes) : dlen; - memcpy (output+nbytes, digest, n); - nbytes += n; - } - - gcry_md_close (hd); - return GPG_ERR_NO_ERROR; -} - - -/* RFC-3447 (pkcs#1 v2.1) OAEP encoding. NBITS is the length of the - key measured in bits. ALGO is the hash function; it must be a - valid and usable algorithm. {VALUE,VALUELEN} is the message to - encrypt. {LABEL,LABELLEN} is the optional label to be associated - with the message, if LABEL is NULL the default is to use the empty - string as label. On success the encoded ciphertext is returned at - R_RESULT. - - If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as - the seed instead of using a random string for it. This feature is - only useful for regression tests. - - Here is figure 1 from the RFC depicting the process: - - +----------+---------+-------+ - DB = | lHash | PS | M | - +----------+---------+-------+ - | - +----------+ V - | seed |--> MGF ---> xor - +----------+ | - | | - +--+ V | - |00| xor <----- MGF <-----| - +--+ | | - | | | - V V V - +--+----------+----------------------------+ - EM = |00|maskedSeed| maskedDB | - +--+----------+----------------------------+ - */ -static gcry_err_code_t -oaep_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo, - const unsigned char *value, size_t valuelen, - const unsigned char *label, size_t labellen, - const void *random_override, size_t random_override_len) -{ - gcry_err_code_t rc = 0; - gcry_error_t err; - unsigned char *frame = NULL; - size_t nframe = (nbits+7) / 8; - unsigned char *p; - size_t hlen; - size_t n; - - *r_result = NULL; - - /* Set defaults for LABEL. */ - if (!label || !labellen) - { - label = (const unsigned char*)""; - labellen = 0; - } - - hlen = gcry_md_get_algo_dlen (algo); - - /* We skip step 1a which would be to check that LABELLEN is not - greater than 2^61-1. See rfc-3447 7.1.1. */ - - /* Step 1b. Note that the obsolete rfc-2437 uses the check: - valuelen > nframe - 2 * hlen - 1 . */ - if (valuelen > nframe - 2 * hlen - 2 || !nframe) - { - /* Can't encode a VALUELEN value in a NFRAME bytes frame. */ - return GPG_ERR_TOO_SHORT; /* The key is too short. */ - } - - /* Allocate the frame. */ - frame = gcry_calloc_secure (1, nframe); - if (!frame) - return gpg_err_code_from_syserror (); - - /* Step 2a: Compute the hash of the label. We store it in the frame - where later the maskedDB will commence. */ - gcry_md_hash_buffer (algo, frame + 1 + hlen, label, labellen); - - /* Step 2b: Set octet string to zero. */ - /* This has already been done while allocating FRAME. */ - - /* Step 2c: Create DB by concatenating lHash, PS, 0x01 and M. */ - n = nframe - valuelen - 1; - frame[n] = 0x01; - memcpy (frame + n + 1, value, valuelen); - - /* Step 3d: Generate seed. We store it where the maskedSeed will go - later. */ - if (random_override) - { - if (random_override_len != hlen) - { - gcry_free (frame); - return GPG_ERR_INV_ARG; - } - memcpy (frame + 1, random_override, hlen); - } - else - gcry_randomize (frame + 1, hlen, GCRY_STRONG_RANDOM); - - /* Step 2e and 2f: Create maskedDB. */ - { - unsigned char *dmask; - - dmask = gcry_malloc_secure (nframe - hlen - 1); - if (!dmask) - { - rc = gpg_err_code_from_syserror (); - gcry_free (frame); - return rc; - } - rc = mgf1 (dmask, nframe - hlen - 1, frame+1, hlen, algo); - if (rc) - { - gcry_free (dmask); - gcry_free (frame); - return rc; - } - for (n = 1 + hlen, p = dmask; n < nframe; n++) - frame[n] ^= *p++; - gcry_free (dmask); - } - - /* Step 2g and 2h: Create maskedSeed. */ - { - unsigned char *smask; - - smask = gcry_malloc_secure (hlen); - if (!smask) - { - rc = gpg_err_code_from_syserror (); - gcry_free (frame); - return rc; - } - rc = mgf1 (smask, hlen, frame + 1 + hlen, nframe - hlen - 1, algo); - if (rc) - { - gcry_free (smask); - gcry_free (frame); - return rc; - } - for (n = 1, p = smask; n < 1 + hlen; n++) - frame[n] ^= *p++; - gcry_free (smask); - } - - /* Step 2i: Concatenate 0x00, maskedSeed and maskedDB. */ - /* This has already been done by using in-place operations. */ - - /* Convert the stuff into an MPI as expected by the caller. */ - err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, frame, nframe, NULL); - if (err) - rc = gcry_err_code (err); - else if (DBG_CIPHER) - log_mpidump ("OAEP encoded data", *r_result); - gcry_free (frame); - - return rc; -} - - -/* RFC-3447 (pkcs#1 v2.1) OAEP decoding. NBITS is the length of the - key measured in bits. ALGO is the hash function; it must be a - valid and usable algorithm. VALUE is the raw decrypted message - {LABEL,LABELLEN} is the optional label to be associated with the - message, if LABEL is NULL the default is to use the empty string as - label. On success the plaintext is returned as a newly allocated - buffer at R_RESULT; its valid length is stored at R_RESULTLEN. On - error NULL is stored at R_RESULT. */ -static gcry_err_code_t -oaep_decode (unsigned char **r_result, size_t *r_resultlen, - unsigned int nbits, int algo, - gcry_mpi_t value, const unsigned char *label, size_t labellen) -{ - gcry_err_code_t rc; - unsigned char *frame = NULL; /* Encoded messages (EM). */ - unsigned char *masked_seed; /* Points into FRAME. */ - unsigned char *masked_db; /* Points into FRAME. */ - unsigned char *seed = NULL; /* Allocated space for the seed and DB. */ - unsigned char *db; /* Points into SEED. */ - unsigned char *lhash = NULL; /* Hash of the label. */ - size_t nframe; /* Length of the ciphertext (EM). */ - size_t hlen; /* Length of the hash digest. */ - size_t db_len; /* Length of DB and masked_db. */ - size_t nkey = (nbits+7)/8; /* Length of the key in bytes. */ - int failed = 0; /* Error indicator. */ - size_t n; - - *r_result = NULL; - - /* This code is implemented as described by rfc-3447 7.1.2. */ - - /* Set defaults for LABEL. */ - if (!label || !labellen) - { - label = (const unsigned char*)""; - labellen = 0; - } - - /* Get the length of the digest. */ - hlen = gcry_md_get_algo_dlen (algo); - - /* Hash the label right away. */ - lhash = gcry_malloc (hlen); - if (!lhash) - return gpg_err_code_from_syserror (); - gcry_md_hash_buffer (algo, lhash, label, labellen); - - /* Turn the MPI into an octet string. If the octet string is - shorter than the key we pad it to the left with zeroes. This may - happen due to the leading zero in OAEP frames and due to the - following random octets (seed^mask) which may have leading zero - bytes. This all is needed to cope with our leading zeroes - suppressing MPI implementation. The code implictly implements - Step 1b (bail out if NFRAME != N). */ - rc = octet_string_from_mpi (&frame, NULL, value, nkey); - if (rc) - { - gcry_free (lhash); - return GPG_ERR_ENCODING_PROBLEM; - } - nframe = nkey; - - /* Step 1c: Check that the key is long enough. */ - if ( nframe < 2 * hlen + 2 ) - { - gcry_free (frame); - gcry_free (lhash); - return GPG_ERR_ENCODING_PROBLEM; - } - - /* Step 2 has already been done by the caller and the - gcry_mpi_aprint above. */ - - /* Allocate space for SEED and DB. */ - seed = gcry_malloc_secure (nframe - 1); - if (!seed) - { - rc = gpg_err_code_from_syserror (); - gcry_free (frame); - gcry_free (lhash); - return rc; - } - db = seed + hlen; - - /* To avoid choosen ciphertext attacks from now on we make sure to - run all code even in the error case; this avoids possible timing - attacks as described by Manger. */ - - /* Step 3a: Hash the label. */ - /* This has already been done. */ - - /* Step 3b: Separate the encoded message. */ - masked_seed = frame + 1; - masked_db = frame + 1 + hlen; - db_len = nframe - 1 - hlen; - - /* Step 3c and 3d: seed = maskedSeed ^ mgf(maskedDB, hlen). */ - if (mgf1 (seed, hlen, masked_db, db_len, algo)) - failed = 1; - for (n = 0; n < hlen; n++) - seed[n] ^= masked_seed[n]; - - /* Step 3e and 3f: db = maskedDB ^ mgf(seed, db_len). */ - if (mgf1 (db, db_len, seed, hlen, algo)) - failed = 1; - for (n = 0; n < db_len; n++) - db[n] ^= masked_db[n]; - - /* Step 3g: Check lhash, an possible empty padding string terminated - by 0x01 and the first byte of EM being 0. */ - if (memcmp (lhash, db, hlen)) - failed = 1; - for (n = hlen; n < db_len; n++) - if (db[n] == 0x01) - break; - if (n == db_len) - failed = 1; - if (frame[0]) - failed = 1; - - gcry_free (lhash); - gcry_free (frame); - if (failed) - { - gcry_free (seed); - return GPG_ERR_ENCODING_PROBLEM; - } - - /* Step 4: Output M. */ - /* To avoid an extra allocation we reuse the seed buffer. The only - caller of this function will anyway free the result soon. */ - n++; - memmove (seed, db + n, db_len - n); - *r_result = seed; - *r_resultlen = db_len - n; - seed = NULL; - - if (DBG_CIPHER) - log_printhex ("value extracted from OAEP encoded data", - *r_result, *r_resultlen); - - return 0; -} - - -/* RFC-3447 (pkcs#1 v2.1) PSS encoding. Encode {VALUE,VALUELEN} for - an NBITS key. Note that VALUE is already the mHash from the - picture below. ALGO is a valid hash algorithm and SALTLEN is the - length of salt to be used. On success the result is stored as a - new MPI at R_RESULT. On error the value at R_RESULT is undefined. - - If {RANDOM_OVERRIDE, RANDOM_OVERRIDE_LEN} is given it is used as - the salt instead of using a random string for the salt. This - feature is only useful for regression tests. - - Here is figure 2 from the RFC (errata 595 applied) depicting the - process: - - +-----------+ - | M | - +-----------+ - | - V - Hash - | - V - +--------+----------+----------+ - M' = |Padding1| mHash | salt | - +--------+----------+----------+ - | - +--------+----------+ V - DB = |Padding2| salt | Hash - +--------+----------+ | - | | - V | +----+ - xor <--- MGF <---| |0xbc| - | | +----+ - | | | - V V V - +-------------------+----------+----+ - EM = | maskedDB | H |0xbc| - +-------------------+----------+----+ - - */ -static gcry_err_code_t -pss_encode (gcry_mpi_t *r_result, unsigned int nbits, int algo, - const unsigned char *value, size_t valuelen, int saltlen, - const void *random_override, size_t random_override_len) -{ - gcry_err_code_t rc = 0; - gcry_error_t err; - size_t hlen; /* Length of the hash digest. */ - unsigned char *em = NULL; /* Encoded message. */ - size_t emlen = (nbits+7)/8; /* Length in bytes of EM. */ - unsigned char *h; /* Points into EM. */ - unsigned char *buf = NULL; /* Help buffer. */ - size_t buflen; /* Length of BUF. */ - unsigned char *mhash; /* Points into BUF. */ - unsigned char *salt; /* Points into BUF. */ - unsigned char *dbmask; /* Points into BUF. */ - unsigned char *p; - size_t n; - - /* This code is implemented as described by rfc-3447 9.1.1. */ - - /* Get the length of the digest. */ - hlen = gcry_md_get_algo_dlen (algo); - gcry_assert (hlen); /* We expect a valid ALGO here. */ - - /* Allocate a help buffer and setup some pointers. */ - buflen = 8 + hlen + saltlen + (emlen - hlen - 1); - buf = gcry_malloc (buflen); - if (!buf) - { - rc = gpg_err_code_from_syserror (); - goto leave; - } - mhash = buf + 8; - salt = mhash + hlen; - dbmask= salt + saltlen; - - /* Step 2: That would be: mHash = Hash(M) but our input is already - mHash thus we do only a consistency check and copy to MHASH. */ - if (valuelen != hlen) - { - rc = GPG_ERR_INV_LENGTH; - goto leave; - } - memcpy (mhash, value, hlen); - - /* Step 3: Check length constraints. */ - if (emlen < hlen + saltlen + 2) - { - rc = GPG_ERR_TOO_SHORT; - goto leave; - } - - /* Allocate space for EM. */ - em = gcry_malloc (emlen); - if (!em) - { - rc = gpg_err_code_from_syserror (); - goto leave; - } - h = em + emlen - 1 - hlen; - - /* Step 4: Create a salt. */ - if (saltlen) - { - if (random_override) - { - if (random_override_len != saltlen) - { - rc = GPG_ERR_INV_ARG; - goto leave; - } - memcpy (salt, random_override, saltlen); - } - else - gcry_randomize (salt, saltlen, GCRY_STRONG_RANDOM); - } - - /* Step 5 and 6: M' = Hash(Padding1 || mHash || salt). */ - memset (buf, 0, 8); /* Padding. */ - gcry_md_hash_buffer (algo, h, buf, 8 + hlen + saltlen); - - /* Step 7 and 8: DB = PS || 0x01 || salt. */ - /* Note that we use EM to store DB and later Xor in-place. */ - p = em + emlen - 1 - hlen - saltlen - 1; - memset (em, 0, p - em); - *p++ = 0x01; - memcpy (p, salt, saltlen); - - /* Step 9: dbmask = MGF(H, emlen - hlen - 1). */ - mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo); - - /* Step 10: maskedDB = DB ^ dbMask */ - for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++) - em[n] ^= *p; - - /* Step 11: Set the leftmost bits to zero. */ - em[0] &= 0xFF >> (8 * emlen - nbits); - - /* Step 12: EM = maskedDB || H || 0xbc. */ - em[emlen-1] = 0xbc; - - /* Convert EM into an MPI. */ - err = gcry_mpi_scan (r_result, GCRYMPI_FMT_USG, em, emlen, NULL); - if (err) - rc = gcry_err_code (err); - else if (DBG_CIPHER) - log_mpidump ("PSS encoded data", *r_result); - - leave: - if (em) - { - wipememory (em, emlen); - gcry_free (em); - } - if (buf) - { - wipememory (buf, buflen); - gcry_free (buf); - } - return rc; -} - - -/* Verify a signature assuming PSS padding. VALUE is the hash of the - message (mHash) encoded as an MPI; its length must match the digest - length of ALGO. ENCODED is the output of the RSA public key - function (EM). NBITS is the size of the public key. ALGO is the - hash algorithm and SALTLEN is the length of the used salt. The - function returns 0 on success or on error code. */ -static gcry_err_code_t -pss_verify (gcry_mpi_t value, gcry_mpi_t encoded, unsigned int nbits, int algo, - size_t saltlen) -{ - gcry_err_code_t rc = 0; - size_t hlen; /* Length of the hash digest. */ - unsigned char *em = NULL; /* Encoded message. */ - size_t emlen = (nbits+7)/8; /* Length in bytes of EM. */ - unsigned char *salt; /* Points into EM. */ - unsigned char *h; /* Points into EM. */ - unsigned char *buf = NULL; /* Help buffer. */ - size_t buflen; /* Length of BUF. */ - unsigned char *dbmask; /* Points into BUF. */ - unsigned char *mhash; /* Points into BUF. */ - unsigned char *p; - size_t n; - - /* This code is implemented as described by rfc-3447 9.1.2. */ - - /* Get the length of the digest. */ - hlen = gcry_md_get_algo_dlen (algo); - gcry_assert (hlen); /* We expect a valid ALGO here. */ - - /* Allocate a help buffer and setup some pointers. - This buffer is used for two purposes: - +------------------------------+-------+ - 1. | dbmask | mHash | - +------------------------------+-------+ - emlen - hlen - 1 hlen - - +----------+-------+---------+-+-------+ - 2. | padding1 | mHash | salt | | mHash | - +----------+-------+---------+-+-------+ - 8 hlen saltlen hlen - */ - buflen = 8 + hlen + saltlen; - if (buflen < emlen - hlen - 1) - buflen = emlen - hlen - 1; - buflen += hlen; - buf = gcry_malloc (buflen); - if (!buf) - { - rc = gpg_err_code_from_syserror (); - goto leave; - } - dbmask = buf; - mhash = buf + buflen - hlen; - - /* Step 2: That would be: mHash = Hash(M) but our input is already - mHash thus we only need to convert VALUE into MHASH. */ - rc = octet_string_from_mpi (NULL, mhash, value, hlen); - if (rc) - goto leave; - - /* Convert the signature into an octet string. */ - rc = octet_string_from_mpi (&em, NULL, encoded, emlen); - if (rc) - goto leave; - - /* Step 3: Check length of EM. Because we internally use MPI - functions we can't do this properly; EMLEN is always the length - of the key because octet_string_from_mpi needs to left pad the - result with zero to cope with the fact that our MPIs suppress all - leading zeroes. Thus what we test here are merely the digest and - salt lengths to the key. */ - if (emlen < hlen + saltlen + 2) - { - rc = GPG_ERR_TOO_SHORT; /* For the hash and saltlen. */ - goto leave; - } - - /* Step 4: Check last octet. */ - if (em[emlen - 1] != 0xbc) - { - rc = GPG_ERR_BAD_SIGNATURE; - goto leave; - } - - /* Step 5: Split EM. */ - h = em + emlen - 1 - hlen; - - /* Step 6: Check the leftmost bits. */ - if ((em[0] & ~(0xFF >> (8 * emlen - nbits)))) - { - rc = GPG_ERR_BAD_SIGNATURE; - goto leave; - } - - /* Step 7: dbmask = MGF(H, emlen - hlen - 1). */ - mgf1 (dbmask, emlen - hlen - 1, h, hlen, algo); - - /* Step 8: maskedDB = DB ^ dbMask. */ - for (n = 0, p = dbmask; n < emlen - hlen - 1; n++, p++) - em[n] ^= *p; - - /* Step 9: Set leftmost bits in DB to zero. */ - em[0] &= 0xFF >> (8 * emlen - nbits); - - /* Step 10: Check the padding of DB. */ - for (n = 0; n < emlen - hlen - saltlen - 2 && !em[n]; n++) - ; - if (n != emlen - hlen - saltlen - 2 || em[n++] != 1) - { - rc = GPG_ERR_BAD_SIGNATURE; - goto leave; - } - - /* Step 11: Extract salt from DB. */ - salt = em + n; - - /* Step 12: M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt */ - memset (buf, 0, 8); - memcpy (buf+8, mhash, hlen); - memcpy (buf+8+hlen, salt, saltlen); - - /* Step 13: H' = Hash(M'). */ - gcry_md_hash_buffer (algo, buf, buf, 8 + hlen + saltlen); - - /* Step 14: Check H == H'. */ - rc = memcmp (h, buf, hlen) ? GPG_ERR_BAD_SIGNATURE : GPG_ERR_NO_ERROR; - - leave: - if (em) - { - wipememory (em, emlen); - gcry_free (em); - } - if (buf) - { - wipememory (buf, buflen); - gcry_free (buf); - } - return rc; -} - - -/* Callback for the pubkey algorithm code to verify PSS signatures. - OPAQUE is the data provided by the actual caller. The meaning of - TMP depends on the actual algorithm (but there is only RSA); now - for RSA it is the output of running the public key function on the - input. */ -static int -pss_verify_cmp (void *opaque, gcry_mpi_t tmp) -{ - struct pk_encoding_ctx *ctx = opaque; - gcry_mpi_t hash = ctx->verify_arg; - - return pss_verify (hash, tmp, ctx->nbits - 1, ctx->hash_algo, ctx->saltlen); -} - - /* Internal function. */ static gcry_err_code_t sexp_elements_extract (gcry_sexp_t key_sexp, const char *element_names, @@ -1926,6 +957,23 @@ sexp_to_enc (gcry_sexp_t sexp, gcry_mpi_t **retarray, gcry_pk_spec_t **r_spec, return err; } + +/* Callback for the pubkey algorithm code to verify PSS signatures. + OPAQUE is the data provided by the actual caller. The meaning of + TMP depends on the actual algorithm (but there is only RSA); now + for RSA it is the output of running the public key function on the + input. */ +static int +pss_verify_cmp (void *opaque, gcry_mpi_t tmp) +{ + struct pk_encoding_ctx *ctx = opaque; + gcry_mpi_t hash = ctx->verify_arg; + + return _gcry_rsa_pss_verify (hash, tmp, ctx->nbits - 1, + ctx->hash_algo, ctx->saltlen); +} + + /* Take the hash value and convert into an MPI, suitable for passing to the low level functions. We currently support the old style way of passing just a MPI and the modern interface which @@ -2174,10 +1222,10 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, goto leave; } - rc = pkcs1_encode_for_encryption (ret_mpi, ctx->nbits, - value, valuelen, - random_override, - random_override_len); + rc = _gcry_rsa_pkcs1_encode_for_enc (ret_mpi, ctx->nbits, + value, valuelen, + random_override, + random_override_len); gcry_free (random_override); } } @@ -2201,9 +1249,9 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, || !valuelen ) rc = GPG_ERR_INV_OBJ; else - rc = pkcs1_encode_for_signature (ret_mpi, ctx->nbits, - value, valuelen, - ctx->hash_algo); + rc = _gcry_rsa_pkcs1_encode_for_sig (ret_mpi, ctx->nbits, + value, valuelen, + ctx->hash_algo); } } else if (ctx->encoding == PUBKEY_ENC_OAEP && lvalue @@ -2283,10 +1331,10 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, goto leave; } - rc = oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo, - value, valuelen, - ctx->label, ctx->labellen, - random_override, random_override_len); + rc = _gcry_rsa_oaep_encode (ret_mpi, ctx->nbits, ctx->hash_algo, + value, valuelen, + ctx->label, ctx->labellen, + random_override, random_override_len); gcry_free (random_override); } @@ -2354,9 +1402,10 @@ sexp_data_to_mpi (gcry_sexp_t input, gcry_mpi_t *ret_mpi, } /* Encode the data. (NBITS-1 is due to 8.1.1, step 1.) */ - rc = pss_encode (ret_mpi, ctx->nbits - 1, ctx->hash_algo, - value, valuelen, ctx->saltlen, - random_override, random_override_len); + rc = _gcry_rsa_pss_encode (ret_mpi, ctx->nbits - 1, + ctx->hash_algo, + value, valuelen, ctx->saltlen, + random_override, random_override_len); gcry_free (random_override); } @@ -2590,8 +1639,9 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) switch (ctx.encoding) { case PUBKEY_ENC_PKCS1: - rc = pkcs1_decode_for_encryption (&unpad, &unpadlen, - gcry_pk_get_nbits (s_skey), plain); + rc = _gcry_rsa_pkcs1_decode_for_enc (&unpad, &unpadlen, + gcry_pk_get_nbits (s_skey), + plain); mpi_free (plain); plain = NULL; if (!rc) @@ -2600,9 +1650,9 @@ gcry_pk_decrypt (gcry_sexp_t *r_plain, gcry_sexp_t s_data, gcry_sexp_t s_skey) break; case PUBKEY_ENC_OAEP: - rc = oaep_decode (&unpad, &unpadlen, - gcry_pk_get_nbits (s_skey), ctx.hash_algo, - plain, ctx.label, ctx.labellen); + rc = _gcry_rsa_oaep_decode (&unpad, &unpadlen, + gcry_pk_get_nbits (s_skey), ctx.hash_algo, + plain, ctx.label, ctx.labellen); mpi_free (plain); plain = NULL; if (!rc) |