Browse Source

Introduce new RSA API.

This also:
a) deprecates the old RSA and PKCS#1 API.
b) reverts the changes done to them in order to make the now deprecated API
   compatible again with the last release.

The fixes commit mentioned below is the testcase for the Bleichenbacher
attack, which works now again as expected.

Fixes: 9d03c38e ("add flags to `der_decode_sequence()`")
Signed-off-by: Steffen Jaeckel <[email protected]>
Steffen Jaeckel 1 month ago
parent
commit
9e47b3aa74

+ 15 - 8
demos/timing.c

@@ -702,11 +702,21 @@ static void time_rsa(void)
    unsigned char buf[2][2048] = { 0 };
    unsigned long x, y, z, zzz;
    int           err, zz, stat;
+   ltc_rsa_op_parameters rsa_params = {
+      .u.crypt.lparam = (const unsigned char *)"testprog",
+      .u.crypt.lparamlen = 8,
+      .prng = &yarrow_prng,
+      .wprng = find_prng("yarrow"),
+      .params.hash_alg = "sha1",
+      .params.mgf1_hash_alg = "sha1",
+      .params.saltlen = 8,
+   };
 
    if (ltc_mp.name == NULL) return;
 
    for (x = 2048; x <= 8192; x <<= 1) {
        t2 = 0;
+       rsa_params.padding = LTC_PKCS_1_OAEP;
        for (y = 0; y < 4; y++) {
            t_start();
            t1 = t_read();
@@ -734,9 +744,7 @@ static void time_rsa(void)
            t_start();
            t1 = t_read();
            z = sizeof(buf[1]);
-           if ((err = rsa_encrypt_key(buf[0], 32, buf[1], &z, (const unsigned char *)"testprog", 8, &yarrow_prng,
-                                      find_prng("yarrow"), find_hash("sha1"),
-                                      &key)) != CRYPT_OK) {
+           if ((err = rsa_encrypt_key_v2(buf[0], 32, buf[1], &z, &rsa_params, &key)) != CRYPT_OK) {
               fprintf(stderr, "\n\nrsa_encrypt_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
               exit(EXIT_FAILURE);
            }
@@ -755,8 +763,7 @@ static void time_rsa(void)
            t_start();
            t1 = t_read();
            zzz = sizeof(buf[0]);
-           if ((err = rsa_decrypt_key(buf[1], z, buf[0], &zzz, (const unsigned char *)"testprog", 8,  find_hash("sha1"),
-                                      &zz, &key)) != CRYPT_OK) {
+           if ((err = rsa_decrypt_key_v2(buf[1], z, buf[0], &zzz, &rsa_params, &zz, &key)) != CRYPT_OK) {
               fprintf(stderr, "\n\nrsa_decrypt_key says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
               exit(EXIT_FAILURE);
            }
@@ -771,12 +778,12 @@ static void time_rsa(void)
        fprintf(stderr, "RSA-%lu decrypt_key took %15"PRI64"u cycles\n", x, t2);
 
        t2 = 0;
+       rsa_params.padding = LTC_PKCS_1_PSS;
        for (y = 0; y < 256; y++) {
           t_start();
           t1 = t_read();
           z = sizeof(buf[1]);
-          if ((err = rsa_sign_hash(buf[0], 20, buf[1], &z, &yarrow_prng,
-                                   find_prng("yarrow"), find_hash("sha1"), 8, &key)) != CRYPT_OK) {
+          if ((err = rsa_sign_hash_v2(buf[0], 20, buf[1], &z, &rsa_params, &key)) != CRYPT_OK) {
               fprintf(stderr, "\n\nrsa_sign_hash says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
               exit(EXIT_FAILURE);
            }
@@ -794,7 +801,7 @@ static void time_rsa(void)
        for (y = 0; y < 2048; y++) {
           t_start();
           t1 = t_read();
-          if ((err = rsa_verify_hash(buf[1], z, buf[0], 20, find_hash("sha1"), 8, &stat, &key)) != CRYPT_OK) {
+          if ((err = rsa_verify_hash_v2(buf[1], z, buf[0], 20, &rsa_params, &stat, &key)) != CRYPT_OK) {
               fprintf(stderr, "\n\nrsa_verify_hash says %s, wait...no it should say %s...damn you!\n", error_to_string(err), error_to_string(CRYPT_OK));
               exit(EXIT_FAILURE);
           }

+ 461 - 231
doc/crypt.tex

@@ -4430,171 +4430,6 @@ RSA wrote the PKCS \#1 specifications which detail RSA Public Key Cryptography.
 padding algorithms for encryption and signatures.  The standard includes the \textit{v1.5} and \textit{v2.1} algorithms.
 To simplify matters a little the v2.1 encryption and signature padding algorithms are called OAEP and PSS respectively.
 
-\mysection{PKCS \#1 Padding}
-PKCS \#1 v1.5 padding is so simple that both signature and encryption padding are performed by the same function.  Note: the
-signature padding does \textbf{not} include the ASN.1 padding required.  That is performed by the rsa\_sign\_hash\_ex() function
-documented later on in this chapter.
-
-\subsection{PKCS \#1 v1.5 Encoding}
-The following function performs PKCS \#1 v1.5 padding:
-\index{pkcs\_1\_v1\_5\_encode()}
-\begin{verbatim}
-int pkcs_1_v1_5_encode(
-    const unsigned char *msg,
-          unsigned long  msglen,
-                    int  block_type,
-          unsigned long  modulus_bitlen,
-             prng_state *prng,
-                    int  prng_idx,
-          unsigned char *out,
-          unsigned long *outlen);
-\end{verbatim}
-
-This will encode the message pointed to by \textit{msg} of length \textit{msglen} octets.  The \textit{block\_type} parameter must be set to
-\textbf{LTC\_PKCS\_1\_EME} to perform encryption padding.  It must be set to \textbf{LTC\_PKCS\_1\_EMSA} to perform signature padding.  The \textit{modulus\_bitlen}
-parameter indicates the length of the modulus in bits.  The padded data is stored in \textit{out} with a length of \textit{outlen} octets.  The output will not be
-longer than the modulus which helps allocate the correct output buffer size.
-
-Only encryption padding requires a PRNG.  When performing signature padding the \textit{prng\_idx} parameter may be left to zero as it is not checked for validity.
-
-\subsection{PKCS \#1 v1.5 Decoding}
-The following function performs PKCS \#1 v1.5 de--padding:
-\index{pkcs\_1\_v1\_5\_decode()}
-\begin{verbatim}
-int pkcs_1_v1_5_decode(
-    const unsigned char *msg,
-          unsigned long  msglen,
-                    int  block_type,
-          unsigned long  modulus_bitlen,
-          unsigned char *out,
-          unsigned long *outlen,
-                    int *is_valid);
-\end{verbatim}
-\index{LTC\_PKCS\_1\_EME} \index{LTC\_PKCS\_1\_EMSA}
-This will remove the PKCS padding data pointed to by \textit{msg} of length \textit{msglen}.  The decoded data is stored in \textit{out} of length
-\textit{outlen}.  If the padding is valid, a 1 is stored in \textit{is\_valid}, otherwise, a 0 is stored.  The \textit{block\_type} parameter must be set to either
-\textbf{LTC\_PKCS\_1\_EME} or \textbf{LTC\_PKCS\_1\_EMSA} depending on whether encryption or signature padding is being removed.
-
-\mysection{PKCS \#1 v2.1 Encryption}
-PKCS \#1 RSA Encryption amounts to OAEP padding of the input message followed by the modular exponentiation.  As far as this portion of
-the library is concerned we are only dealing with th OAEP padding of the message.
-
-\subsection{OAEP Encoding}
-
-The following function performs PKCS \#1 v2.1 encryption padding:
-
-\index{pkcs\_1\_oaep\_encode()}
-\begin{alltt}
-int pkcs_1_oaep_encode(
-    const unsigned char *msg,
-          unsigned long  msglen,
-    const unsigned char *lparam,
-          unsigned long  lparamlen,
-          unsigned long  modulus_bitlen,
-             prng_state *prng,
-                    int  prng_idx,
-                    int  mgf_hash,
-                    int  lparam_hash,
-          unsigned char *out,
-          unsigned long *outlen);
-\end{alltt}
-
-This accepts \textit{msg} as input of length \textit{msglen} which will be OAEP padded.  The \textit{lparam} variable is an additional system specific
-tag that can be applied to the encoding.  This is useful to identify which system encoded the message.  If no variance is desired then
-\textit{lparam} can be set to \textbf{NULL}.
-
-OAEP encoding requires the length of the modulus in bits in order to calculate the size of the output.  This is passed as the parameter
-\textit{modulus\_bitlen}.  \textit{mgf\_hash} is the index into the hash descriptor table of the hash desired for the mask generation function (MGF).
-\textit{lparam\_hash} is the index into the hash descriptor table of the hash desired for the \textit{lparam}.  This value can also be set to $-1$
-to indicate usage of the same algorithm than for the MGF.  PKCS \#1 allows any hash to be
-used but both the encoder and decoder must use the same hash in order for this to succeed.  The size of hash output affects the maximum
- sized input message.  \textit{prng\_idx} and \textit{prng} are the random number generator arguments required to randomize the padding process.
-The padded message is stored in \textit{out} along with the length in \textit{outlen}.
-
-If $h$ is the length of the hash and $m$ the length of the modulus (both in octets) then the maximum payload for \textit{msg} is
-$m - 2h - 2$.  For example, with a $1024$--bit RSA key and SHA--1 as the hash the maximum payload is $86$ bytes.
-
-Note that when the message is padded it still has not been RSA encrypted.  You must pass the output of this function to
-rsa\_exptmod() to encrypt it.
-
-\subsection{OAEP Decoding}
-
-\index{pkcs\_1\_oaep\_decode()}
-\begin{alltt}
-int pkcs_1_oaep_decode(
-    const unsigned char *msg,
-          unsigned long  msglen,
-    const unsigned char *lparam,
-          unsigned long  lparamlen,
-          unsigned long  modulus_bitlen,
-                    int  mgf_hash,
-                    int  lparam_hash,
-          unsigned char *out,
-          unsigned long *outlen,
-                    int *res);
-\end{alltt}
-
-This function decodes an OAEP encoded message and outputs the original message that was passed to the OAEP encoder.  \textit{msg} is the
-output of pkcs\_1\_oaep\_encode() of length \textit{msglen}.  \textit{lparam} is the same system variable passed to the OAEP encoder.  If it does not
-match what was used during encoding this function will not decode the packet.  \textit{modulus\_bitlen} is the size of the RSA modulus in bits
-and must match what was used during encoding.  Similarly the \textit{mgf\_hash} and \textit{lparam\_hash} indexes into the hash descriptor table must
-match what was used during encoding.
-
-If the function succeeds it decodes the OAEP encoded message into \textit{out} of length \textit{outlen} and stores a
-$1$ in \textit{res}.  If the packet is invalid it stores $0$ in \textit{res} and if the function fails for another reason
-it returns an error code.
-
-\mysection{PKCS \#1 Digital Signatures}
-
-\subsection{PSS Encoding}
-PSS encoding is the second half of the PKCS \#1 standard which is padding to be applied to messages that are signed.
-
-\index{pkcs\_1\_pss\_encode()}
-\begin{alltt}
-int pkcs_1_pss_encode(
-    const unsigned char *msghash,
-          unsigned long  msghashlen,
-          unsigned long  saltlen,
-             prng_state *prng,
-                    int  prng_idx,
-                    int  hash_idx,
-          unsigned long  modulus_bitlen,
-          unsigned char *out,
-          unsigned long *outlen);
-\end{alltt}
-
-This function assumes the message to be PSS encoded has previously been hashed.  The input hash \textit{msghash} is of length
-\textit{msghashlen}.  PSS allows a variable length random salt (it can be zero length) to be introduced in the signature process.
-\textit{hash\_idx} is the index into the hash descriptor table of the hash to use.  \textit{prng\_idx} and \textit{prng} are the random
-number generator information required for the salt.
-
-Similar to OAEP encoding \textit{modulus\_bitlen} is the size of the RSA modulus (in bits).  It limits the size of the salt.  If $m$ is the length
-of the modulus $h$ the length of the hash output (in octets) then there can be $m - h - 2$ bytes of salt.
-
-This function does not actually sign the data it merely pads the hash of a message so that it can be processed by rsa\_exptmod().
-
-\subsection{PSS Decoding}
-
-To decode a PSS encoded signature block you have to use the following.
-
-\index{pkcs\_1\_pss\_decode()}
-\begin{alltt}
-int pkcs_1_pss_decode(
-    const unsigned char *msghash,
-          unsigned long  msghashlen,
-    const unsigned char *sig,
-          unsigned long  siglen,
-          unsigned long  saltlen,
-                    int  hash_idx,
-          unsigned long  modulus_bitlen,
-                    int *res);
-\end{alltt}
-This will decode the PSS encoded message in \textit{sig} of length \textit{siglen} and compare it to values in \textit{msghash} of length
-\textit{msghashlen}.  If the block is a valid PSS block and the decoded hash equals the hash supplied \textit{res} is set to non--zero.  Otherwise,
-it is set to zero.  The rest of the parameters are as in the PSS encode call.
-
-It's important to use the same \textit{saltlen} and hash for both encoding and decoding as otherwise the procedure will not work.
-
 \mysection{RSA Key Operations}
 \subsection{Background}
 
@@ -4696,6 +4531,73 @@ int rsa_get_size(rsa_key *key);
 \end{verbatim}
 This can be used to determine the modulus size of an RSA key.
 
+\mysection{RSA Key Operation Parameters}
+
+The following RSA Key Operations share \code{struct}s which hold the parameters used in the operations.
+
+\index{RSASSA-PSS-params}
+\begin{small}
+\begin{verbatim}
+   RSASSA-PSS-params ::= SEQUENCE {
+       hashAlgorithm      [0] HashAlgorithm      DEFAULT sha1,
+       maskGenAlgorithm   [1] MaskGenAlgorithm   DEFAULT mgf1SHA1,
+       saltLength         [2] INTEGER            DEFAULT 20,
+       trailerField       [3] TrailerField       DEFAULT trailerFieldBC
+   }
+\end{verbatim}
+\end{small}
+
+\href{https://datatracker.ietf.org/doc/html/rfc8017}{\textit{RFC 8017}} defines the ASN.1 module for \code{RSASSA-PSS-params} as shown above.
+
+\index{ltc\_rsa\_parameters}
+\begin{small}
+\begin{verbatim}
+typedef struct ltc_rsa_parameters {
+   /** PSS/OAEP or PKCS #1 v1.5 style
+    *  0 -> PKCS #1 v1.5, 1 -> PSS/OAEP */
+   int pss_oaep;
+   /** saltLength is only defined for PSS
+    * If saltLength == 0 -> OAEP, else -> PSS */
+   unsigned long saltlen;
+   /** lparam hash for OAEP
+    *     resp.
+    *  signature hash for PSS
+    * and MGF hash algorithms */
+   const char *hash_alg, *mgf1_hash_alg;
+} ltc_rsa_parameters;
+\end{verbatim}
+\end{small}
+
+The \code{struct ltc\_rsa\_parameters} represents the RSA parameters as defined in \code{RSASSA-PSS-params}.
+This \code{struct} is used in two points, first when parsing an RSA key which contains those parameters in order to restrict the usage of the RSA key
+to the given set of parameters, c.f. TBD. Its second use is explained below and defines the parameters used for an RSA operation.
+
+\index{ltc\_rsa\_op\_parameters}
+\begin{small}
+\begin{verbatim}
+typedef struct ltc_rsa_op_parameters {
+   /* pss_oaep flag is unused */
+   ltc_rsa_parameters params;
+   /* The padding type */
+   int padding;
+   /* The PRNG to use.
+    * Only required for signing and encryption. */
+   int wprng;
+   prng_state *prng;
+   /* Operation-specific parameters */
+   union {
+      struct {
+         const unsigned char *lparam;
+               unsigned long  lparamlen;
+      } crypt;
+   } u;
+} ltc_rsa_op_parameters;
+\end{verbatim}
+\end{small}
+
+The \code{struct ltc\_rsa\_op\_parameters} holds all the potential arguments required for one of the four possible RSA operations.
+
+
 \mysection{RSA Key Encryption}
 Normally RSA is used to encrypt short symmetric keys which are then used in block ciphers to encrypt a message.
 To facilitate encrypting short keys the following functions have been provided.
@@ -4718,30 +4620,24 @@ This function will OAEP pad \textit{in} of length \textit{inlen} bytes, RSA encr
 in \textit{out} of length \textit{outlen} octets.  The \textit{lparam} and \textit{lparamlen} are the same parameters you would pass
 to \index{pkcs\_1\_oaep\_encode()} pkcs\_1\_oaep\_encode().
 
-\subsection{Extended Encryption}
+This API function is implemented as a macro and under the hood uses the API as described in Chapter \ref{rsa-encrypt-v2}.
+
+\subsection{Extended Encryption v2}
+\label{rsa-encrypt-v2}
 As of v1.15, the library supports both v1.5 and v2.1 PKCS \#1 style paddings in these higher level functions.  The following is the extended
 encryption function:
 
-\index{rsa\_encrypt\_key\_ex()}
+\index{rsa\_encrypt\_key\_v2()}
 \begin{verbatim}
-int rsa_encrypt_key_ex(
-    const unsigned char *in,
-          unsigned long  inlen,
-          unsigned char *out,
-          unsigned long *outlen,
-    const unsigned char *lparam,
-          unsigned long  lparamlen,
-             prng_state *prng,
-                    int  prng_idx,
-                    int  mgf_hash,
-                    int  lparam_hash,
-                    int  padding,
-                rsa_key *key);
+int rsa_encrypt_key_v2(const unsigned char   *in,     unsigned long  inlen,
+                             unsigned char   *out,    unsigned long *outlen,
+                       ltc_rsa_op_parameters *opts,
+                       const rsa_key         *key);
 \end{verbatim}
 
 \index{LTC\_PKCS\_1\_OAEP} \index{LTC\_PKCS\_1\_V1\_5}
-The parameters are all the same as for rsa\_encrypt\_key() except for the addition of the \textit{padding} parameter.  It must be set to
-\textbf{LTC\_PKCS\_1\_V1\_5} to perform v1.5 encryption, or set to \textbf{LTC\_PKCS\_1\_OAEP} to perform v2.1 encryption.
+The parameters are all the same as for \code{rsa\_encrypt\_key()} except for the addition of the \textit{padding} parameter.  It must be set to
+\code{LTC\_PKCS\_1\_V1\_5} to perform v1.5 encryption, or set to \code{LTC\_PKCS\_1\_OAEP} to perform v2.1 encryption.
 
 When performing v1.5 encryption, the hash and lparam parameters are totally ignored and can be set to \textbf{NULL} or zero (respectively).
 
@@ -4766,29 +4662,26 @@ to pkcs\_1\_oaep\_decode().
 
 If the RSA decrypted data is not a valid OAEP packet then \textit{stat} is set to $0$.  Otherwise, it is set to $1$.
 
-\subsection{Extended Decryption}
+This API function is implemented as a macro and under the hood uses the API as described in Chapter \ref{rsa-decrypt-v2}.
+
+\subsection{Extended Decryption v2}
+\label{rsa-decrypt-v2}
 As of v1.15, the library supports both v1.5 and v2.1 PKCS \#1 style paddings in these higher level functions.  The following is the extended
 decryption function:
 
-\index{rsa\_decrypt\_key\_ex()}
+\index{rsa\_decrypt\_key\_v2()}
 \begin{verbatim}
-int rsa_decrypt_key_ex(
-    const unsigned char *in,
-          unsigned long  inlen,
-          unsigned char *out,
-          unsigned long *outlen,
-    const unsigned char *lparam,
-          unsigned long  lparamlen,
-                    int  hash_idx,
-                    int  padding,
-                    int *stat,
-                rsa_key *key);
+int rsa_decrypt_key_v2(const unsigned char   *in,     unsigned long  inlen,
+                             unsigned char   *out,    unsigned long *outlen,
+                       ltc_rsa_op_parameters *opts,
+                             int             *stat,
+                       const rsa_key         *key);
 \end{verbatim}
 
-Similar to the extended encryption, the new parameter \textit{padding} indicates which version of the PKCS \#1 standard to use.
-It must be set to \textbf{LTC\_PKCS\_1\_V1\_5} to perform v1.5 decryption, or set to \textbf{LTC\_PKCS\_1\_OAEP} to perform v2.1 decryption.
+Similar to the extended encryption, the parameter \textit{opts.padding} indicates which version of the PKCS \#1 standard to use.
+It must be set to \code{LTC\_PKCS\_1\_V1\_5} to perform v1.5 decryption, or set to \code{LTC\_PKCS\_1\_OAEP} to perform v2.1 decryption.
 
-When performing v1.5 decryption, the hash and lparam parameters are totally ignored and can be set to \textbf{NULL} or zero (respectively).
+When performing v1.5 decryption, the \textit{opts.params.hash\_alg} and \textit{opts.u.crypt.lparam} parameters are totally ignored and can be set to \code{NULL} or zero (respectively).
 
 
 \mysection{RSA Signature Generation}
@@ -4816,37 +4709,33 @@ hash the message being signed.  The \textit{saltlen} parameter indicates the len
 default value is between 8 and 16 octets.  Strictly, it must be small than $modulus\_len - hLen - 2$ where \textit{modulus\_len} is the size of
 the RSA modulus (in octets), and \textit{hLen} is the length of the message digest produced by the chosen hash.
 
-\subsection{Extended Signatures}
+This API function is implemented as a macro and under the hood uses the API as described in Chapter \ref{rsa-sign-v2}.
+
+\subsection{Extended Signatures v2}
+\label{rsa-sign-v2}
 
 As of v1.15, the library supports both v1.5 and v2.1 signatures.  The extended signature generation function has the following prototype:
 
-\index{rsa\_sign\_hash\_ex()}
+\index{rsa\_sign\_hash\_v2()}
 \begin{verbatim}
-int rsa_sign_hash_ex(
-    const unsigned char *in,
-          unsigned long  inlen,
-          unsigned char *out,
-          unsigned long *outlen,
-                    int  padding,
-          prng_state    *prng,
-                    int  prng_idx,
-                    int  hash_idx,
-          unsigned long  saltlen,
-                rsa_key *key);
+int rsa_sign_hash_v2(const unsigned char   *hash,   unsigned long  hashlen,
+                           unsigned char   *sig,    unsigned long *siglen,
+                     ltc_rsa_op_parameters *opts,
+                     const rsa_key         *key);
 \end{verbatim}
 
 This will PKCS encode the message digest pointed to by \textit{in} of length \textit{inlen} octets.  Next, the PKCS encoded hash will be RSA
-\textit{signed} and the output stored in the buffer pointed to by \textit{out} of length \textit{outlen} octets.  The \textit{padding} parameter
-must be set to \textbf{LTC\_PKCS\_1\_V1\_5} to produce a v1.5 signature, otherwise, it must be set to \textbf{LTC\_PKCS\_1\_PSS} to produce a
+\textit{signed} and the output stored in the buffer pointed to by \textit{out} of length \textit{outlen} octets.  The \textit{opts.padding} parameter
+must be set to \code{LTC\_PKCS\_1\_V1\_5} to produce a v1.5 signature, otherwise, it must be set to \code{LTC\_PKCS\_1\_PSS} to produce a
 v2.1 signature.
 
 \index{LTC\_PKCS\_1\_V1\_5\_NA1}
 As of v1.18.0, the library also supports v1.5 signature generation without ASN.1 encoding the signature which can be indicated by passing
-\textbf{LTC\_PKCS\_1\_V1\_5\_NA1} as \textit{padding} parameter. This option has been introduced to provide compatibilty to SSL3.0 implementations
+\code{LTC\_PKCS\_1\_V1\_5\_NA1} as \textit{opts.padding} parameter. This option has been introduced to provide compatibilty to SSL3.0 implementations
 which implemented this.
 
-When generating a standard v1.5 signature the \textit{prng}, and \textit{prng\_idx} parameters are ignored.
-When generating a v1.5 signature without ASN.1 decoding additionally the textit{hash\_idx} parameter is ignored.
+When generating a standard v1.5 signature the \textit{opts.prng}, and \textit{opts.wprng} parameters are ignored.
+When generating a v1.5 signature without ASN.1 decoding additionally the \textit{opts.params.hash\_alg} parameter is ignored.
 
 \mysection{RSA Signature Verification}
 \index{rsa\_verify\_hash()}
@@ -4867,6 +4756,8 @@ and the extracted hash is compared against the message digest pointed to by \tex
 If the RSA decoded data is not a valid PSS message, or if the PSS decoded hash does not match the \textit{msghash}
 value, \textit{res} is set to $0$.  Otherwise, if the function succeeds, and signature is valid \textit{res} is set to $1$.
 
+This API function is implemented as a macro and under the hood uses the API as described in Chapter \ref{rsa-verify-v2}.
+
 \subsection{RSA Signature Salt Length}
 
 The v2.1 signature algorithm requires a salt length to be able to properly
@@ -4883,22 +4774,18 @@ As stated in the PKCS\#1 RFC3447 "Typical salt lengths in octets are hLen
 This function is provided to be able to use other lengths as well and to make
 sure at runtime that the RSA key can handle the desired salt length.
 
-\subsection{Extended Verification}
+\subsection{Extended Verification v2}
+\label{rsa-verify-v2}
 
 As of v1.15, the library supports both v1.5 and v2.1 signature verification.  The extended signature verification function has the following prototype:
 
-\index{rsa\_verify\_hash\_ex()}
+\index{rsa\_verify\_hash\_v2()}
 \begin{verbatim}
-int rsa_verify_hash_ex(
-    const unsigned char *sig,
-          unsigned long  siglen,
-    const unsigned char *hash,
-          unsigned long  hashlen,
-                    int  padding,
-                    int  hash_idx,
-          unsigned long  saltlen,
-                    int *stat,
-                rsa_key *key);
+int rsa_verify_hash_v2(const unsigned char   *sig,    unsigned long  siglen,
+                       const unsigned char   *hash,   unsigned long  hashlen,
+                       ltc_rsa_op_parameters *opts,
+                             int             *stat,
+                       const rsa_key         *key);
 \end{verbatim}
 
 This will RSA \textit{verify} the signature pointed to by \textit{sig} of length \textit{siglen} octets.  Next, the RSA decoded data is PKCS decoded
@@ -8973,7 +8860,7 @@ This will build the library and link against LibTomMath (which must be installed
 The file \textit{tomcrypt\_cfg.h} is what lets you control various high level macros which control the behaviour of the library.  Build options are also
 stored in \textit{tomcrypt\_custom.h} which allow the enabling and disabling of various algorithms.
 
-\subsubsection{ARGTYPE}
+\subsection{ARGTYPE}
 This lets you control how the LTC\_ARGCHK macro will behave.  The macro is used to check pointers inside the functions against
 NULL.  There are four settings for ARGTYPE.  When set to 0, it will have the default behaviour of printing a message to
 stderr and raising a SIGABRT signal.  This is provided so all platforms that use LibTomCrypt can have an error that functions
@@ -8982,7 +8869,7 @@ stderr then return execution to the caller.  This could lead to a segmentation f
 if you handle signals on your own.  When set to 3, it will resolve to a empty macro and no error checking will be performed.  Finally, when set
 to 4, it will return CRYPT\_INVALID\_ARG to the caller.
 
-\subsubsection{Endianness}
+\subsection{Endianness}
 There are five macros related to endianness issues.  For little endian platforms define, \textbf{ENDIAN\_LITTLE}.  For big endian
 platforms define \textbf{ENDIAN\_BIG}.  Similarly when the default word size of an \textit{unsigned long} is 32-bits define \textbf{ENDIAN\_32BITWORD}
 or define \textbf{ENDIAN\_64BITWORD} when its 64-bits.  If you do not define any of them the library will automatically use \textbf{ENDIAN\_NEUTRAL}
@@ -10356,7 +10243,9 @@ for RSA--1024 the output is always 128 bytes regardless of how small the numeric
 Since the function is given the entire RSA key (for private keys only) CRT is possible as prescribed in the PKCS \#1 v2.1 specification.
 
 
-\mysection{Deprecated API functions}
+\chapter{Deprecated API functions}
+
+\mysection{After v1.18.2}
 
 \subsection{Elliptic Curve Cryptography - $GF(p)$}
 
@@ -10408,6 +10297,347 @@ int ecc_verify_hash_rfc7518(const unsigned char *sig,
 These two ECC verify functions have been deprecated in favor of \code{ecc\_verify\_hash\_v2()}.
 Please check Chapter \ref{ecc-verify} for details.
 
+\subsection{PKCS \#1 Padding}
+PKCS \#1 v1.5 padding is so simple that both signature and encryption padding are performed by the same function.  Note: the
+signature padding does \textbf{not} include the ASN.1 padding required.  That is performed by the rsa\_sign\_hash\_ex() function
+documented later on in this chapter.
+
+\subsection{PKCS \#1 v1.5 Encoding}
+The following function performs PKCS \#1 v1.5 padding:
+\index{pkcs\_1\_v1\_5\_encode()}
+\begin{verbatim}
+int pkcs_1_v1_5_encode(
+    const unsigned char *msg,
+          unsigned long  msglen,
+                    int  block_type,
+          unsigned long  modulus_bitlen,
+             prng_state *prng,
+                    int  prng_idx,
+          unsigned char *out,
+          unsigned long *outlen);
+\end{verbatim}
+
+This will encode the message pointed to by \textit{msg} of length \textit{msglen} octets.  The \textit{block\_type} parameter must be set to
+\textbf{LTC\_PKCS\_1\_EME} to perform encryption padding.  It must be set to \textbf{LTC\_PKCS\_1\_EMSA} to perform signature padding.  The \textit{modulus\_bitlen}
+parameter indicates the length of the modulus in bits.  The padded data is stored in \textit{out} with a length of \textit{outlen} octets.  The output will not be
+longer than the modulus which helps allocate the correct output buffer size.
+
+Only encryption padding requires a PRNG.  When performing signature padding the \textit{prng\_idx} parameter may be left to zero as it is not checked for validity.
+
+\subsection{PKCS \#1 v1.5 Decoding}
+The following function performs PKCS \#1 v1.5 de--padding:
+\index{pkcs\_1\_v1\_5\_decode()}
+\begin{verbatim}
+int pkcs_1_v1_5_decode(
+    const unsigned char *msg,
+          unsigned long  msglen,
+                    int  block_type,
+          unsigned long  modulus_bitlen,
+          unsigned char *out,
+          unsigned long *outlen,
+                    int *is_valid);
+\end{verbatim}
+\index{LTC\_PKCS\_1\_EME} \index{LTC\_PKCS\_1\_EMSA}
+This will remove the PKCS padding data pointed to by \textit{msg} of length \textit{msglen}.  The decoded data is stored in \textit{out} of length
+\textit{outlen}.  If the padding is valid, a 1 is stored in \textit{is\_valid}, otherwise, a 0 is stored.  The \textit{block\_type} parameter must be set to either
+\textbf{LTC\_PKCS\_1\_EME} or \textbf{LTC\_PKCS\_1\_EMSA} depending on whether encryption or signature padding is being removed.
+
+\mysection{PKCS \#1 v2.1 Encryption}
+PKCS \#1 RSA Encryption amounts to OAEP padding of the input message followed by the modular exponentiation.  As far as this portion of
+the library is concerned we are only dealing with the OAEP padding of the message.
+
+\subsection{OAEP Encoding}
+
+The following function performs PKCS \#1 v2.1 encryption padding:
+
+\index{pkcs\_1\_oaep\_encode()}
+\begin{alltt}
+int pkcs_1_oaep_encode(
+    const unsigned char *msg,
+          unsigned long  msglen,
+    const unsigned char *lparam,
+          unsigned long  lparamlen,
+          unsigned long  modulus_bitlen,
+             prng_state *prng,
+                    int  prng_idx,
+                    int  mgf_hash,
+                    int  lparam_hash,
+          unsigned char *out,
+          unsigned long *outlen);
+\end{alltt}
+
+This accepts \textit{msg} as input of length \textit{msglen} which will be OAEP padded.  The \textit{lparam} variable is an additional system specific
+tag that can be applied to the encoding.  This is useful to identify which system encoded the message.  If no variance is desired then
+\textit{lparam} can be set to \textbf{NULL}.
+
+OAEP encoding requires the length of the modulus in bits in order to calculate the size of the output.  This is passed as the parameter
+\textit{modulus\_bitlen}.  \textit{mgf\_hash} is the index into the hash descriptor table of the hash desired for the mask generation function (MGF).
+\textit{lparam\_hash} is the index into the hash descriptor table of the hash desired for the \textit{lparam}.  This value can also be set to $-1$
+to indicate usage of the same algorithm than for the MGF.  PKCS \#1 allows any hash to be
+used but both the encoder and decoder must use the same hash in order for this to succeed.  The size of hash output affects the maximum
+ sized input message.  \textit{prng\_idx} and \textit{prng} are the random number generator arguments required to randomize the padding process.
+The padded message is stored in \textit{out} along with the length in \textit{outlen}.
+
+If $h$ is the length of the hash and $m$ the length of the modulus (both in octets) then the maximum payload for \textit{msg} is
+$m - 2h - 2$.  For example, with a $1024$--bit RSA key and SHA--1 as the hash the maximum payload is $86$ bytes.
+
+Note that when the message is padded it still has not been RSA encrypted.  You must pass the output of this function to
+rsa\_exptmod() to encrypt it.
+
+\subsection{OAEP Decoding}
+
+\index{pkcs\_1\_oaep\_decode()}
+\begin{alltt}
+int pkcs_1_oaep_decode(
+    const unsigned char *msg,
+          unsigned long  msglen,
+    const unsigned char *lparam,
+          unsigned long  lparamlen,
+          unsigned long  modulus_bitlen,
+                    int  mgf_hash,
+                    int  lparam_hash,
+          unsigned char *out,
+          unsigned long *outlen,
+                    int *res);
+\end{alltt}
+
+This function decodes an OAEP encoded message and outputs the original message that was passed to the OAEP encoder.  \textit{msg} is the
+output of pkcs\_1\_oaep\_encode() of length \textit{msglen}.  \textit{lparam} is the same system variable passed to the OAEP encoder.  If it does not
+match what was used during encoding this function will not decode the packet.  \textit{modulus\_bitlen} is the size of the RSA modulus in bits
+and must match what was used during encoding.  Similarly the \textit{mgf\_hash} and \textit{lparam\_hash} indexes into the hash descriptor table must
+match what was used during encoding.
+
+If the function succeeds it decodes the OAEP encoded message into \textit{out} of length \textit{outlen} and stores a
+$1$ in \textit{res}.  If the packet is invalid it stores $0$ in \textit{res} and if the function fails for another reason
+it returns an error code.
+
+\mysection{PKCS \#1 Digital Signatures}
+
+\subsection{PSS Encoding}
+PSS encoding is the second half of the PKCS \#1 standard which is padding to be applied to messages that are signed.
+
+\index{pkcs\_1\_pss\_encode()}
+\begin{alltt}
+int pkcs_1_pss_encode(
+    const unsigned char *msghash,
+          unsigned long  msghashlen,
+          unsigned long  saltlen,
+             prng_state *prng,
+                    int  prng_idx,
+                    int  hash_idx,
+          unsigned long  modulus_bitlen,
+          unsigned char *out,
+          unsigned long *outlen);
+\end{alltt}
+
+This function assumes the message to be PSS encoded has previously been hashed.  The input hash \textit{msghash} is of length
+\textit{msghashlen}.  PSS allows a variable length random salt (it can be zero length) to be introduced in the signature process.
+\textit{hash\_idx} is the index into the hash descriptor table of the hash to use.  \textit{prng\_idx} and \textit{prng} are the random
+number generator information required for the salt.
+
+Similar to OAEP encoding \textit{modulus\_bitlen} is the size of the RSA modulus (in bits).  It limits the size of the salt.  If $m$ is the length
+of the modulus $h$ the length of the hash output (in octets) then there can be $m - h - 2$ bytes of salt.
+
+This function does not actually sign the data it merely pads the hash of a message so that it can be processed by rsa\_exptmod().
+
+\subsection{PSS Decoding}
+
+To decode a PSS encoded signature block you have to use the following.
+
+\index{pkcs\_1\_pss\_decode()}
+\begin{alltt}
+int pkcs_1_pss_decode(
+    const unsigned char *msghash,
+          unsigned long  msghashlen,
+    const unsigned char *sig,
+          unsigned long  siglen,
+          unsigned long  saltlen,
+                    int  hash_idx,
+          unsigned long  modulus_bitlen,
+                    int *res);
+\end{alltt}
+This will decode the PSS encoded message in \textit{sig} of length \textit{siglen} and compare it to values in \textit{msghash} of length
+\textit{msghashlen}.  If the block is a valid PSS block and the decoded hash equals the hash supplied \textit{res} is set to non--zero.  Otherwise,
+it is set to zero.  The rest of the parameters are as in the PSS encode call.
+
+It's important to use the same \textit{saltlen} and hash for both encoding and decoding as otherwise the procedure will not work.
+
+\mysection{RSA Key Encryption}
+
+\index{rsa\_encrypt\_key()}
+\begin{verbatim}
+int rsa_encrypt_key(
+    const unsigned char *in,
+          unsigned long  inlen,
+          unsigned char *out,
+          unsigned long *outlen,
+    const unsigned char *lparam,
+          unsigned long  lparamlen,
+             prng_state *prng,
+                    int  prng_idx,
+                    int  hash_idx,
+                rsa_key *key);
+\end{verbatim}
+This function will OAEP pad \textit{in} of length \textit{inlen} bytes, RSA encrypt it, and store the ciphertext
+in \textit{out} of length \textit{outlen} octets.  The \textit{lparam} and \textit{lparamlen} are the same parameters you would pass
+to \index{pkcs\_1\_oaep\_encode()} pkcs\_1\_oaep\_encode().
+
+\subsection{Extended Encryption}
+As of v1.15, the library supports both v1.5 and v2.1 PKCS \#1 style paddings in these higher level functions.  The following is the extended
+encryption function:
+
+\index{rsa\_encrypt\_key\_ex()}
+\begin{verbatim}
+int rsa_encrypt_key_ex(
+    const unsigned char *in,
+          unsigned long  inlen,
+          unsigned char *out,
+          unsigned long *outlen,
+    const unsigned char *lparam,
+          unsigned long  lparamlen,
+             prng_state *prng,
+                    int  prng_idx,
+                    int  mgf_hash,
+                    int  lparam_hash,
+                    int  padding,
+                rsa_key *key);
+\end{verbatim}
+
+\mysection{RSA Key Decryption}
+\index{rsa\_decrypt\_key()}
+\begin{verbatim}
+int rsa_decrypt_key(
+    const unsigned char *in,
+          unsigned long  inlen,
+          unsigned char *out,
+          unsigned long *outlen,
+    const unsigned char *lparam,
+          unsigned long  lparamlen,
+                    int  mgf_hash,
+                    int  lparam_hash,
+                    int *stat,
+                rsa_key *key);
+\end{verbatim}
+This function will RSA decrypt \textit{in} of length \textit{inlen} then OAEP de-pad the resulting data and store it in
+\textit{out} of length \textit{outlen}.  The \textit{lparam} and \textit{lparamlen} are the same parameters you would pass
+to pkcs\_1\_oaep\_decode().
+
+If the RSA decrypted data is not a valid OAEP packet then \textit{stat} is set to $0$.  Otherwise, it is set to $1$.
+
+\subsection{Extended Decryption}
+As of v1.15, the library supports both v1.5 and v2.1 PKCS \#1 style paddings in these higher level functions.  The following is the extended
+decryption function:
+
+\index{rsa\_decrypt\_key\_ex()}
+\begin{verbatim}
+int rsa_decrypt_key_ex(
+    const unsigned char *in,
+          unsigned long  inlen,
+          unsigned char *out,
+          unsigned long *outlen,
+    const unsigned char *lparam,
+          unsigned long  lparamlen,
+                    int  hash_idx,
+                    int  padding,
+                    int *stat,
+                rsa_key *key);
+\end{verbatim}
+
+\mysection{RSA Signature Generation}
+Similar to RSA key encryption RSA is also used to \textit{digitally sign} message digests (hashes).  To facilitate this
+process the following functions have been provided.
+
+\index{rsa\_sign\_hash()}
+\begin{verbatim}
+int rsa_sign_hash(const unsigned char *in,
+                        unsigned long  inlen,
+                        unsigned char *out,
+                        unsigned long *outlen,
+                           prng_state *prng,
+                                  int  prng_idx,
+                                  int  hash_idx,
+                        unsigned long  saltlen,
+                              rsa_key *key);
+\end{verbatim}
+
+This will PSS encode the message digest pointed to by \textit{in} of length \textit{inlen} octets.  Next, the PSS encoded hash will be RSA
+\textit{signed} and the output stored in the buffer pointed to by \textit{out} of length \textit{outlen} octets.
+
+The \textit{hash\_idx} parameter indicates which hash will be used to create the PSS encoding.  It should be the same as the hash used to
+hash the message being signed.  The \textit{saltlen} parameter indicates the length of the desired salt, and should typically be small.  A good
+default value is between 8 and 16 octets.  Strictly, it must be small than $modulus\_len - hLen - 2$ where \textit{modulus\_len} is the size of
+the RSA modulus (in octets), and \textit{hLen} is the length of the message digest produced by the chosen hash.
+
+\subsection{Extended Signatures}
+
+As of v1.15, the library supports both v1.5 and v2.1 signatures.  The extended signature generation function has the following prototype:
+
+\index{rsa\_sign\_hash\_ex()}
+\begin{verbatim}
+int rsa_sign_hash_ex(
+    const unsigned char *in,
+          unsigned long  inlen,
+          unsigned char *out,
+          unsigned long *outlen,
+                    int  padding,
+          prng_state    *prng,
+                    int  prng_idx,
+                    int  hash_idx,
+          unsigned long  saltlen,
+                rsa_key *key);
+\end{verbatim}
+
+This will PKCS encode the message digest pointed to by \textit{in} of length \textit{inlen} octets.  Next, the PKCS encoded hash will be RSA
+\textit{signed} and the output stored in the buffer pointed to by \textit{out} of length \textit{outlen} octets.  The \textit{padding} parameter
+must be set to \textbf{LTC\_PKCS\_1\_V1\_5} to produce a v1.5 signature, otherwise, it must be set to \textbf{LTC\_PKCS\_1\_PSS} to produce a
+v2.1 signature.
+
+\index{LTC\_PKCS\_1\_V1\_5\_NA1}
+As of v1.18.0, the library also supports v1.5 signature generation without ASN.1 encoding the signature which can be indicated by passing
+\textbf{LTC\_PKCS\_1\_V1\_5\_NA1} as \textit{padding} parameter. This option has been introduced to provide compatibilty to SSL3.0 implementations
+which implemented this.
+
+When generating a standard v1.5 signature the \textit{prng}, and \textit{prng\_idx} parameters are ignored.
+When generating a v1.5 signature without ASN.1 decoding additionally the textit{hash\_idx} parameter is ignored.
+
+\mysection{RSA Signature Verification}
+\index{rsa\_verify\_hash()}
+\begin{verbatim}
+int rsa_verify_hash(const unsigned char *sig,
+                          unsigned long  siglen,
+                    const unsigned char *msghash,
+                          unsigned long  msghashlen,
+                                    int  hash_idx,
+                          unsigned long  saltlen,
+                                    int *stat,
+                                rsa_key *key);
+\end{verbatim}
+
+This will RSA \textit{verify} the signature pointed to by \textit{sig} of length \textit{siglen} octets.  Next, the RSA decoded data is PSS decoded
+and the extracted hash is compared against the message digest pointed to by \textit{msghash} of length \textit{msghashlen} octets.
+
+If the RSA decoded data is not a valid PSS message, or if the PSS decoded hash does not match the \textit{msghash}
+value, \textit{res} is set to $0$.  Otherwise, if the function succeeds, and signature is valid \textit{res} is set to $1$.
+
+\subsection{Extended Verification}
+
+As of v1.15, the library supports both v1.5 and v2.1 signature verification.  The extended signature verification function has the following prototype:
+
+\index{rsa\_verify\_hash\_ex()}
+\begin{verbatim}
+int rsa_verify_hash_ex(
+    const unsigned char *sig,
+          unsigned long  siglen,
+    const unsigned char *hash,
+          unsigned long  hashlen,
+                    int  padding,
+                    int  hash_idx,
+          unsigned long  saltlen,
+                    int *stat,
+                rsa_key *key);
+\end{verbatim}
+
+
 \clearpage
 \addcontentsline{toc}{chapter}{Index}
 \printindex

+ 108 - 24
src/headers/tomcrypt_pk.h

@@ -70,7 +70,10 @@ typedef struct ltc_rsa_parameters {
    /** saltLength is only defined for PSS
     * If saltLength == 0 -> OAEP, else -> PSS */
    unsigned long saltlen;
-   /** hash and MGF hash algorithms */
+   /** lparam hash for OAEP
+    *     resp.
+    *  signature hash for PSS
+    * and MGF hash algorithms */
    const char *hash_alg, *mgf1_hash_alg;
 } ltc_rsa_parameters;
 
@@ -109,52 +112,133 @@ int rsa_exptmod(const unsigned char *in,   unsigned long inlen,
 
 void rsa_free(rsa_key *key);
 
-/* These use PKCS #1 v2.0 padding */
-#define rsa_encrypt_key(in, inlen, out, outlen, lparam, lparamlen, prng, prng_idx, hash_idx, key) \
-  rsa_encrypt_key_ex(in, inlen, out, outlen, lparam, lparamlen, prng, prng_idx, hash_idx, -1, LTC_PKCS_1_OAEP, key)
-
-#define rsa_decrypt_key(in, inlen, out, outlen, lparam, lparamlen, hash_idx, stat, key) \
-  rsa_decrypt_key_ex(in, inlen, out, outlen, lparam, lparamlen, hash_idx, -1, LTC_PKCS_1_OAEP, stat, key)
-
-#define rsa_sign_hash(in, inlen, out, outlen, prng, prng_idx, hash_idx, saltlen, key) \
-  rsa_sign_hash_ex(in, inlen, out, outlen, LTC_PKCS_1_PSS, prng, prng_idx, hash_idx, hash_idx, saltlen, key)
-
-#define rsa_verify_hash(sig, siglen, hash, hashlen, hash_idx, saltlen, stat, key) \
-  rsa_verify_hash_ex(sig, siglen, hash, hashlen, LTC_PKCS_1_PSS, hash_idx, hash_idx, saltlen, stat, key)
-
-#define rsa_sign_saltlen_get_max(hash_idx, key) \
-  rsa_sign_saltlen_get_max_ex(LTC_PKCS_1_PSS, hash_idx, key)
+typedef struct ltc_rsa_op_parameters {
+   /* The RSA API will set the `pss_oaep` field for you,
+    * depending on the value of `padding`. */
+   ltc_rsa_parameters params;
+   /* The padding type */
+   int padding;
+   /* The PRNG to use.
+    * Only required for signing and encryption. */
+   int wprng;
+   prng_state *prng;
+   /* Operation-specific parameters */
+   union {
+      struct {
+         const unsigned char *lparam;
+               unsigned long  lparamlen;
+      } crypt;
+      /* let's make space for potential future extensions */
+      ulong64 dummy[8];
+   } u;
+} ltc_rsa_op_parameters;
+
+int rsa_encrypt_key_v2(const unsigned char   *in,     unsigned long  inlen,
+                             unsigned char   *out,    unsigned long *outlen,
+                       ltc_rsa_op_parameters *opts,
+                       const rsa_key         *key);
+
+int rsa_decrypt_key_v2(const unsigned char   *in,     unsigned long  inlen,
+                             unsigned char   *out,    unsigned long *outlen,
+                       ltc_rsa_op_parameters *opts,
+                             int             *stat,
+                       const rsa_key         *key);
+
+int rsa_sign_hash_v2(const unsigned char   *hash,   unsigned long  hashlen,
+                           unsigned char   *sig,    unsigned long *siglen,
+                     ltc_rsa_op_parameters *opts,
+                     const rsa_key         *key);
+
+int rsa_verify_hash_v2(const unsigned char   *sig,    unsigned long  siglen,
+                       const unsigned char   *hash,   unsigned long  hashlen,
+                       ltc_rsa_op_parameters *opts,
+                             int             *stat,
+                       const rsa_key         *key);
 
+/* These use PKCS #1 v2.0 padding */
+#define ltc_rsa_encrypt_key(in, inlen, out, outlen, lp, lplen, prng_, prng_idx, hash_idx, key) \
+      rsa_encrypt_key_v2(in, inlen, out, outlen, \
+                         &(ltc_rsa_op_parameters){ \
+                           .u.crypt.lparam = lp, \
+                           .u.crypt.lparamlen = lplen,\
+                           .prng = prng_, \
+                           .wprng = prng_idx, \
+                           .params.mgf1_hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \
+                           .params.hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \
+                           .padding = LTC_PKCS_1_OAEP, \
+                         }, key)
+
+#define ltc_rsa_decrypt_key(in, inlen, out, outlen, lp, lplen, hash_idx, stat, key) \
+      rsa_decrypt_key_v2(in, inlen, out, outlen, \
+                         &(ltc_rsa_op_parameters){ \
+                           .u.crypt.lparam = lp, \
+                           .u.crypt.lparamlen = lplen,\
+                           .params.mgf1_hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \
+                           .params.hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \
+                           .padding = LTC_PKCS_1_OAEP, \
+                         }, stat, key)
+
+#define ltc_rsa_sign_hash(hash, hashlen, sig, siglen, prng_, prng_idx, hash_idx, saltlen_, key) \
+      rsa_sign_hash_v2(hash, hashlen, sig, siglen, \
+                         &(ltc_rsa_op_parameters){ \
+                           .prng = prng_, \
+                           .wprng = prng_idx, \
+                           .params.mgf1_hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \
+                           .params.hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \
+                           .params.saltlen = saltlen_, \
+                           .padding = LTC_PKCS_1_PSS, \
+                         }, key)
+
+#define ltc_rsa_verify_hash(sig, siglen, hash, hashlen, hash_idx, saltlen_, stat, key) \
+      rsa_verify_hash_v2(sig, siglen, hash, hashlen, \
+                         &(ltc_rsa_op_parameters){ \
+                           .params.mgf1_hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \
+                           .params.hash_alg = hash_is_valid(hash_idx) == CRYPT_OK ? hash_descriptor[hash_idx].name : NULL, \
+                           .params.saltlen = saltlen_, \
+                           .padding = LTC_PKCS_1_PSS, \
+                         }, stat, key)
+
+/* If you used those in v1, they're still working */
+#define rsa_encrypt_key ltc_rsa_encrypt_key
+#define rsa_decrypt_key ltc_rsa_decrypt_key
+#define rsa_sign_hash   ltc_rsa_sign_hash
+#define rsa_verify_hash ltc_rsa_verify_hash
+
+#ifndef LTC_NO_DEPRECATED_APIS
 /* These can be switched between PKCS #1 v2.x and PKCS #1 v1.5 paddings */
+LTC_DEPRECATED(rsa_encrypt_key_v2)
 int rsa_encrypt_key_ex(const unsigned char *in,       unsigned long  inlen,
                              unsigned char *out,      unsigned long *outlen,
                        const unsigned char *lparam,   unsigned long  lparamlen,
                              prng_state    *prng,     int            prng_idx,
-                             int            mgf_hash, int            lparam_hash,
-                             int            padding,
+                             int            hash_idx, int            padding,
                        const rsa_key       *key);
 
+LTC_DEPRECATED(rsa_decrypt_key_v2)
 int rsa_decrypt_key_ex(const unsigned char *in,             unsigned long  inlen,
                              unsigned char *out,            unsigned long *outlen,
                        const unsigned char *lparam,         unsigned long  lparamlen,
-                             int            mgf_hash,       int            lparam_hash,
-                             int            padding,
+                             int            hash_idx,       int            padding,
                              int           *stat,     const rsa_key       *key);
 
+LTC_DEPRECATED(rsa_sign_hash_v2)
 int rsa_sign_hash_ex(const unsigned char *in,       unsigned long  inlen,
                            unsigned char *out,      unsigned long *outlen,
                            int            padding,
                            prng_state    *prng,               int  prng_idx,
-                           int            hash_idx,           int  mgf_hash_idx,
-                           unsigned long  saltlen,
+                           int            hash_idx, unsigned long  saltlen,
                      const rsa_key       *key);
 
+LTC_DEPRECATED(rsa_verify_hash_v2)
 int rsa_verify_hash_ex(const unsigned char *sig,            unsigned long  siglen,
                        const unsigned char *hash,           unsigned long  hashlen,
                              int            padding,
-                             int            hash_idx,                 int  mgf_hash_idx,
-                             unsigned long  saltlen,
+                             int            hash_idx,       unsigned long  saltlen,
                              int           *stat,     const rsa_key       *key);
+#endif /* LTC_NO_DEPRECATED_APIS */
+
+#define rsa_sign_saltlen_get_max(hash_idx, key) \
+  rsa_sign_saltlen_get_max_ex(LTC_PKCS_1_PSS, hash_idx, key)
 
 int rsa_sign_saltlen_get_max_ex(int padding, int hash_idx, const rsa_key *key);
 

+ 13 - 4
src/headers/tomcrypt_pkcs.h

@@ -20,14 +20,19 @@ enum ltc_pkcs_1_paddings
   LTC_PKCS_1_V1_5_NA1 = 4         /* PKCS #1 v1.5 padding - No ASN.1 (\sa ltc_pkcs_1_v1_5_blocks) */
 };
 
+#ifndef LTC_NO_DEPRECATED_APIS
+LTC_DEPRECATED(nothing. API will be internal)
 int pkcs_1_mgf1(      int            hash_idx,
                 const unsigned char *seed, unsigned long seedlen,
                       unsigned char *mask, unsigned long masklen);
 
+LTC_DEPRECATED(nothing. API will be removed)
 int pkcs_1_i2osp(void *n, unsigned long modulus_len, unsigned char *out);
+LTC_DEPRECATED(nothing. API will be removed)
 int pkcs_1_os2ip(void *n, unsigned char *in, unsigned long inlen);
 
 /* *** v1.5 padding */
+LTC_DEPRECATED(nothing. API will be internal)
 int pkcs_1_v1_5_encode(const unsigned char *msg,
                              unsigned long  msglen,
                              int            block_type,
@@ -37,6 +42,7 @@ int pkcs_1_v1_5_encode(const unsigned char *msg,
                              unsigned char *out,
                              unsigned long *outlen);
 
+LTC_DEPRECATED(nothing. API will be internal)
 int pkcs_1_v1_5_decode(const unsigned char *msg,
                              unsigned long  msglen,
                                        int  block_type,
@@ -46,30 +52,33 @@ int pkcs_1_v1_5_decode(const unsigned char *msg,
                                        int *is_valid);
 
 /* *** v2.1 padding */
+LTC_DEPRECATED(nothing. API will be internal)
 int pkcs_1_oaep_encode(const unsigned char *msg,    unsigned long msglen,
                        const unsigned char *lparam, unsigned long lparamlen,
                              unsigned long modulus_bitlen, prng_state *prng,
-                             int           prng_idx,
-                             int           mgf_hash, int lparam_hash,
+                             int           prng_idx, int          hash_idx,
                              unsigned char *out,    unsigned long *outlen);
 
+LTC_DEPRECATED(nothing. API will be internal)
 int pkcs_1_oaep_decode(const unsigned char *msg,    unsigned long msglen,
                        const unsigned char *lparam, unsigned long lparamlen,
-                             unsigned long modulus_bitlen,
-                             int           mgf_hash, int          lparam_hash,
+                             unsigned long modulus_bitlen, int hash_idx,
                              unsigned char *out,    unsigned long *outlen,
                              int           *res);
 
+LTC_DEPRECATED(nothing. API will be internal)
 int pkcs_1_pss_encode(const unsigned char *msghash, unsigned long msghashlen,
                             unsigned long saltlen,  prng_state   *prng,
                             int           prng_idx, int           hash_idx,
                             unsigned long modulus_bitlen,
                             unsigned char *out,     unsigned long *outlen);
 
+LTC_DEPRECATED(nothing. API will be internal)
 int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
                       const unsigned char *sig,     unsigned long siglen,
                             unsigned long saltlen,  int           hash_idx,
                             unsigned long modulus_bitlen, int    *res);
+#endif /* LTC_NO_DEPRECATED_APIS */
 
 #endif /* LTC_PKCS_1 */
 

+ 78 - 16
src/headers/tomcrypt_private.h

@@ -446,13 +446,51 @@ int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long
 
 /* ---- DH Routines ---- */
 #ifdef LTC_MRSA
+/* Receiving side, i.e. Decrypt or Verify */
+#define LTC_RSA_OP_RECV  0x00u
+/* Sending side, i.e. Encrypt or Sign */
+#define LTC_RSA_OP_SEND  0x01u
+/* En- or Decrypt */
+#define LTC_RSA_OP_CRYPT 0x00u
+/* Sign or Verify */
+#define LTC_RSA_OP_SIGN  0x02u
+/* All combinations of the above
+ * but only the PKCS#1 de-/encoding part */
+#define LTC_RSA_OP_PKCS1 0x04u
+
 typedef enum ltc_rsa_op {
-   LTC_RSA_CRYPT,
-   LTC_RSA_SIGN
+   LTC_RSA_DECRYPT = LTC_RSA_OP_CRYPT | LTC_RSA_OP_RECV,
+   LTC_RSA_ENCRYPT = LTC_RSA_OP_CRYPT | LTC_RSA_OP_SEND,
+   LTC_RSA_VERIFY  = LTC_RSA_OP_SIGN | LTC_RSA_OP_RECV,
+   LTC_RSA_SIGN    = LTC_RSA_OP_SIGN | LTC_RSA_OP_SEND,
+   LTC_PKCS1_ENCRYPT = LTC_RSA_OP_PKCS1 | LTC_RSA_ENCRYPT,
+   LTC_PKCS1_DECRYPT = LTC_RSA_OP_PKCS1 | LTC_RSA_DECRYPT,
+   LTC_PKCS1_SIGN    = LTC_RSA_OP_PKCS1 | LTC_RSA_SIGN,
+   LTC_PKCS1_VERIFY  = LTC_RSA_OP_PKCS1 | LTC_RSA_VERIFY,
 } ltc_rsa_op;
+
+typedef struct ltc_rsa_op_check {
+   const rsa_key *key;
+   ltc_rsa_op_parameters *params;
+   int hash_alg, mgf1_hash_alg;
+} ltc_rsa_op_checked;
+
+#define ltc_rsa_op_checked_init(k, p) {  \
+   .key = k,                           \
+   .params = p,                        \
+   .hash_alg = -1,                     \
+   .mgf1_hash_alg = -1,                \
+}
+
+#define ltc_pkcs1_op_checked_init(p) ltc_rsa_op_checked_init(NULL, p)
+
 int rsa_init(rsa_key *key);
 void rsa_shrink_key(rsa_key *key);
-int rsa_key_valid_op(const rsa_key *key, ltc_rsa_op op, int padding, int hash_idx);
+int rsa_args_to_op_params(const unsigned char *lparam, unsigned long lparamlen,
+                          prng_state *prng, int prng_idx, int hash_idx,
+                          int padding, unsigned long saltlen,
+                          ltc_rsa_op_parameters *params);
+int rsa_key_valid_op(ltc_rsa_op op, ltc_rsa_op_checked *params);
 int rsa_params_equal(const ltc_rsa_parameters *a, const ltc_rsa_parameters *b);
 int rsa_make_key_bn_e(prng_state *prng, int wprng, int size, void *e,
                       rsa_key *key); /* used by op-tee */
@@ -766,19 +804,43 @@ int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2);
 /* tomcrypt_pkcs.h */
 
 #ifdef LTC_PKCS_1
-
-int pkcs_1_pss_encode_mgf1(const unsigned char *msghash,       unsigned long  msghashlen,
-                                 unsigned long saltlen,
-                                 prng_state    *prng,                    int  prng_idx,
-                                 int           hash_idx,                 int  mgf_hash_idx,
-                                 unsigned long modulus_bitlen,
-                                 unsigned char *out,           unsigned long *outlen);
-int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen,
-                           const unsigned char *sig,     unsigned long siglen,
-                                 unsigned long saltlen,
-                                          int  hash_idx,           int mgf_hash_idx,
-                                 unsigned long modulus_bitlen,     int *res);
-
+int ltc_pkcs_1_mgf1(int                  hash_idx,
+                    const unsigned char *seed, unsigned long seedlen,
+                          unsigned char *mask, unsigned long masklen);
+
+int ltc_pkcs_1_pss_encode_mgf1(const unsigned char *msghash,       unsigned long  msghashlen,
+                             ltc_rsa_op_parameters *params,
+                                     unsigned long  modulus_bitlen,
+                                     unsigned char *out,           unsigned long *outlen);
+int ltc_pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long  msghashlen,
+                               const unsigned char *sig,     unsigned long  siglen,
+                               ltc_rsa_op_parameters *params,
+                                     unsigned long  modulus_bitlen,    int *res);
+int ltc_pkcs_1_oaep_encode(const unsigned char   *msg,    unsigned long msglen,
+                          ltc_rsa_op_parameters *params,
+                                unsigned long    modulus_bitlen,
+                                unsigned char   *out,    unsigned long *outlen);
+int ltc_pkcs_1_oaep_decode(const unsigned char *msg,    unsigned long msglen,
+                         ltc_rsa_op_parameters *params,
+                                 unsigned long  modulus_bitlen,
+                                 unsigned char *out,    unsigned long *outlen,
+                                 int           *res);
+
+int ltc_pkcs_1_v1_5_encode(const unsigned char *msg,
+                                 unsigned long  msglen,
+                                           int  block_type,
+                                 unsigned long  modulus_bitlen,
+                                    prng_state *prng,
+                                           int  prng_idx,
+                                 unsigned char *out,
+                                 unsigned long *outlen);
+int ltc_pkcs_1_v1_5_decode(const unsigned char *msg,
+                                 unsigned long  msglen,
+                                           int  block_type,
+                                 unsigned long  modulus_bitlen,
+                                 unsigned char *out,
+                                 unsigned long *outlen,
+                                           int *is_valid);
 #endif /* LTC_PKCS_1 */
 
 #ifdef LTC_PKCS_8

+ 358 - 1
src/misc/deprecated.c

@@ -79,10 +79,367 @@ int ecc_verify_hash_rfc7518(const unsigned char *sig,  unsigned long siglen,
 }
 #endif /* LTC_MECC */
 
+#ifdef LTC_MRSA
+/**
+    (PKCS #1 v2.0) OAEP pad then encrypt
+    @param in          The plaintext
+    @param inlen       The length of the plaintext (octets)
+    @param out         [out] The ciphertext
+    @param outlen      [in/out] The max size and resulting size of the ciphertext
+    @param lparam      The system "lparam" for the encryption
+    @param lparamlen   The length of lparam (octets)
+    @param prng        An active PRNG
+    @param prng_idx    The index of the desired prng
+    @param hash_idx    The index of the desired hash
+    @param padding     Type of padding (LTC_PKCS_1_OAEP or LTC_PKCS_1_V1_5)
+    @param key         The RSA key to encrypt to
+    @return CRYPT_OK if successful
+*/
+int rsa_encrypt_key_ex(const unsigned char *in,       unsigned long  inlen,
+                             unsigned char *out,      unsigned long *outlen,
+                       const unsigned char *lparam,   unsigned long  lparamlen,
+                             prng_state    *prng,     int            prng_idx,
+                             int            hash_idx, int            padding,
+                       const rsa_key       *key)
+{
+   int err;
+   ltc_rsa_op_parameters params;
+   if ((err = rsa_args_to_op_params(lparam, lparamlen,
+                                    prng, prng_idx,
+                                    hash_idx,
+                                    padding, 0,
+                                    &params)) != CRYPT_OK) {
+      return err;
+   }
+   return rsa_encrypt_key_v2(in, inlen, out, outlen, &params, key);
+}
+
+/**
+   PKCS #1 decrypt then v1.5 or OAEP depad
+   @param in          The ciphertext
+   @param inlen       The length of the ciphertext (octets)
+   @param out         [out] The plaintext
+   @param outlen      [in/out] The max size and resulting size of the plaintext (octets)
+   @param lparam      The system "lparam" value
+   @param lparamlen   The length of the lparam value (octets)
+   @param hash_idx    The hash algorithm used
+   @param padding     Type of padding (LTC_PKCS_1_OAEP or LTC_PKCS_1_V1_5)
+   @param stat        [out] Result of the decryption, 1==valid, 0==invalid
+   @param key         The corresponding private RSA key
+   @return CRYPT_OK if succcessul (even if invalid)
+*/
+int rsa_decrypt_key_ex(const unsigned char *in,             unsigned long  inlen,
+                             unsigned char *out,            unsigned long *outlen,
+                       const unsigned char *lparam,         unsigned long  lparamlen,
+                             int            hash_idx,       int            padding,
+                             int           *stat,     const rsa_key       *key)
+{
+   int err;
+   ltc_rsa_op_parameters params;
+   if ((err = rsa_args_to_op_params(lparam, lparamlen,
+                                    NULL, -1,
+                                    hash_idx,
+                                    padding, 0,
+                                    &params)) != CRYPT_OK) {
+      return err;
+   }
+   return rsa_decrypt_key_v2(in, inlen, out, outlen, &params, stat, key);
+}
+
+/**
+  PKCS #1 pad then sign
+  @param in        The hash to sign
+  @param inlen     The length of the hash to sign (octets)
+  @param out       [out] The signature
+  @param outlen    [in/out] The max size and resulting size of the signature
+  @param padding   Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1)
+  @param prng      An active PRNG state
+  @param prng_idx  The index of the PRNG desired
+  @param hash_idx  The index of the hash desired
+  @param saltlen   The length of the salt desired (octets)
+  @param key       The private RSA key to use
+  @return CRYPT_OK if successful
+*/
+int rsa_sign_hash_ex(const unsigned char *in,       unsigned long  inlen,
+                           unsigned char *out,      unsigned long *outlen,
+                           int            padding,
+                           prng_state    *prng,               int  prng_idx,
+                           int            hash_idx, unsigned long  saltlen,
+                     const rsa_key       *key)
+{
+   int err;
+   ltc_rsa_op_parameters params;
+   if ((err = rsa_args_to_op_params(NULL, 0,
+                                    prng, prng_idx,
+                                    hash_idx,
+                                    padding, saltlen,
+                                    &params)) != CRYPT_OK) {
+      return err;
+   }
+   return rsa_sign_hash_v2(in, inlen, out, outlen, &params, key);
+}
+
+/**
+  PKCS #1 de-sign then v1.5 or PSS depad
+  @param sig              The signature data
+  @param siglen           The length of the signature data (octets)
+  @param hash             The hash of the message that was signed
+  @param hashlen          The length of the hash of the message that was signed (octets)
+  @param padding          Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1)
+  @param hash_idx         The index of the desired hash
+  @param saltlen          The length of the salt used during signature
+  @param stat             [out] The result of the signature comparison, 1==valid, 0==invalid
+  @param key              The public RSA key corresponding to the key that performed the signature
+  @return CRYPT_OK on success (even if the signature is invalid)
+*/
+int rsa_verify_hash_ex(const unsigned char *sig,            unsigned long  siglen,
+                       const unsigned char *hash,           unsigned long  hashlen,
+                             int            padding,
+                             int            hash_idx,       unsigned long  saltlen,
+                             int           *stat,     const rsa_key       *key)
+{
+   int err;
+   ltc_rsa_op_parameters params;
+   if ((err = rsa_args_to_op_params(NULL, 0,
+                                    NULL, -1,
+                                    hash_idx,
+                                    padding, saltlen,
+                                    &params)) != CRYPT_OK) {
+      return err;
+   }
+   return rsa_verify_hash_v2(sig, siglen, hash, hashlen, &params, stat, key);
+}
+
+int rsa_args_to_op_params(const unsigned char *lparam, unsigned long lparamlen,
+                          prng_state *prng, int prng_idx, int hash_idx,
+                          int padding, unsigned long saltlen,
+                          ltc_rsa_op_parameters *params)
+{
+   int err;
+   ltc_rsa_op_parameters p = {
+                               .u.crypt.lparam = lparam,
+                               .u.crypt.lparamlen = lparamlen,
+                               .prng = prng,
+                               .wprng = prng_idx,
+                               .padding = padding,
+                               .params.saltlen = saltlen,
+   };
+   if ((err = hash_is_valid(hash_idx)) == CRYPT_OK) {
+      if (hash_descriptor[hash_idx].name == NULL) {
+         return CRYPT_INVALID_HASH;
+      }
+      p.params.hash_alg = hash_descriptor[hash_idx].name;
+      p.params.mgf1_hash_alg = p.params.hash_alg;
+      *params = p;
+   } else if (padding == LTC_PKCS_1_V1_5 || padding == LTC_PKCS_1_V1_5_NA1) {
+      /* PKCS#1 1.5 does not necessarily require a hash */
+      err = CRYPT_OK;
+      *params = p;
+   }
+   return err;
+}
+#endif /* LTC_MRSA */
+
+
+#ifdef LTC_PKCS_1
+/**
+   Perform PKCS #1 MGF1 (internal)
+   @param hash_idx    The index of the hash desired
+   @param seed        The seed for MGF1
+   @param seedlen     The length of the seed
+   @param mask        [out] The destination
+   @param masklen     The length of the mask desired
+   @return CRYPT_OK if successful
+*/
+int pkcs_1_mgf1(int                  hash_idx,
+                const unsigned char *seed, unsigned long seedlen,
+                      unsigned char *mask, unsigned long masklen)
+{
+   return ltc_pkcs_1_mgf1(hash_idx, seed, seedlen, mask, masklen);
+}
+/**
+  PKCS #1 v2.00 OAEP encode
+  @param msg             The data to encode
+  @param msglen          The length of the data to encode (octets)
+  @param lparam          A session or system parameter (can be NULL)
+  @param lparamlen       The length of the lparam data
+  @param modulus_bitlen  The bit length of the RSA modulus
+  @param prng            An active PRNG state
+  @param prng_idx        The index of the PRNG desired
+  @param hash_idx        The index of the hash desired
+  @param out             [out] The destination for the encoded data
+  @param outlen          [in/out] The max size and resulting size of the encoded data
+  @return CRYPT_OK if successful
+*/
+int pkcs_1_oaep_encode(const unsigned char *msg,    unsigned long msglen,
+                       const unsigned char *lparam, unsigned long lparamlen,
+                             unsigned long modulus_bitlen, prng_state *prng,
+                             int           prng_idx, int          hash_idx,
+                             unsigned char *out,    unsigned long *outlen)
+{
+   int err;
+   ltc_rsa_op_parameters params;
+   if ((err = rsa_args_to_op_params(lparam, lparamlen,
+                                    prng, prng_idx,
+                                    hash_idx,
+                                    LTC_PKCS_1_OAEP, 0,
+                                    &params)) != CRYPT_OK) {
+      return err;
+   }
+   return ltc_pkcs_1_oaep_encode(msg, msglen, &params, modulus_bitlen, out, outlen);
+}
+
+/**
+   PKCS #1 v2.00 OAEP decode
+   @param msg              The encoded data to decode
+   @param msglen           The length of the encoded data (octets)
+   @param lparam           The session or system data (can be NULL)
+   @param lparamlen        The length of the lparam
+   @param modulus_bitlen   The bit length of the RSA modulus
+   @param mgf_hash         The hash algorithm used for the MGF
+   @param lparam_hash      The hash algorithm used when hashing the lparam (can be -1)
+   @param out              [out] Destination of decoding
+   @param outlen           [in/out] The max size and resulting size of the decoding
+   @param res              [out] Result of decoding, 1==valid, 0==invalid
+   @return CRYPT_OK if successful
+*/
+int pkcs_1_oaep_decode(const unsigned char *msg,    unsigned long msglen,
+                       const unsigned char *lparam, unsigned long lparamlen,
+                             unsigned long modulus_bitlen, int hash_idx,
+                             unsigned char *out,    unsigned long *outlen,
+                             int           *res)
+{
+   int err;
+   ltc_rsa_op_parameters params;
+   if ((err = rsa_args_to_op_params(lparam, lparamlen,
+                                    NULL, -1,
+                                    hash_idx,
+                                    LTC_PKCS_1_OAEP, 0,
+                                    &params)) != CRYPT_OK) {
+      return err;
+   }
+   return ltc_pkcs_1_oaep_decode(msg, msglen, &params, modulus_bitlen, out, outlen, res);
+}
+
+/**
+   PKCS #1 v2.00 Signature Encoding using MGF1 and both hashes are the same
+   @param msghash          The hash to encode
+   @param msghashlen       The length of the hash (octets)
+   @param saltlen          The length of the salt desired (octets)
+   @param prng             An active PRNG context
+   @param prng_idx         The index of the PRNG desired
+   @param hash_idx         The index of the hash desired
+   @param modulus_bitlen   The bit length of the RSA modulus
+   @param out              [out] The destination of the encoding
+   @param outlen           [in/out] The max size and resulting size of the encoded data
+   @return CRYPT_OK if successful
+*/
+int pkcs_1_pss_encode(const unsigned char *msghash,  unsigned long msghashlen,
+                            unsigned long saltlen,   prng_state   *prng,
+                            int           prng_idx,  int           hash_idx,
+                            unsigned long modulus_bitlen,
+                            unsigned char *out,      unsigned long *outlen)
+{
+   int err;
+   ltc_rsa_op_parameters params;
+   if ((err = rsa_args_to_op_params(NULL, 0,
+                                    prng, prng_idx,
+                                    hash_idx,
+                                    LTC_PKCS_1_PSS, saltlen,
+                                    &params)) != CRYPT_OK) {
+      return err;
+   }
+   return ltc_pkcs_1_pss_encode_mgf1(msghash, msghashlen, &params, modulus_bitlen, out, outlen);
+}
+
+/**
+   PKCS #1 v2.00 PSS decode
+   @param  msghash         The hash to verify
+   @param  msghashlen      The length of the hash (octets)
+   @param  sig             The signature data (encoded data)
+   @param  siglen          The length of the signature data (octets)
+   @param  saltlen         The length of the salt used (octets)
+   @param  hash_idx        The index of the hash desired
+   @param  modulus_bitlen  The bit length of the RSA modulus
+   @param  res             [out] The result of the comparison, 1==valid, 0==invalid
+   @return CRYPT_OK if successful (even if the comparison failed)
+*/
+int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
+                      const unsigned char *sig,     unsigned long siglen,
+                            unsigned long saltlen,  int           hash_idx,
+                            unsigned long modulus_bitlen, int    *res)
+{
+   int err;
+   ltc_rsa_op_parameters params;
+   if ((err = rsa_args_to_op_params(NULL, 0,
+                                    NULL, -1,
+                                    hash_idx,
+                                    LTC_PKCS_1_PSS, saltlen,
+                                    &params)) != CRYPT_OK) {
+      return err;
+   }
+   return ltc_pkcs_1_pss_decode_mgf1(msghash, msghashlen, sig, siglen, &params, modulus_bitlen, res);
+}
+
+
+/*! \brief PKCS #1 v1.5 encode.
+ *
+ *  \param msg              The data to encode
+ *  \param msglen           The length of the data to encode (octets)
+ *  \param block_type       Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks)
+ *  \param modulus_bitlen   The bit length of the RSA modulus
+ *  \param prng             An active PRNG state (only for LTC_PKCS_1_EME)
+ *  \param prng_idx         The index of the PRNG desired (only for LTC_PKCS_1_EME)
+ *  \param out              [out] The destination for the encoded data
+ *  \param outlen           [in/out] The max size and resulting size of the encoded data
+ *
+ *  \return CRYPT_OK if successful
+ */
+int pkcs_1_v1_5_encode(const unsigned char *msg,
+                             unsigned long  msglen,
+                                       int  block_type,
+                             unsigned long  modulus_bitlen,
+                                prng_state *prng,
+                                       int  prng_idx,
+                             unsigned char *out,
+                             unsigned long *outlen)
+{
+   return ltc_pkcs_1_v1_5_encode(msg, msglen,
+                                 block_type, modulus_bitlen,
+                                 prng, prng_idx,
+                                 out, outlen);
+}
+
+/** @brief PKCS #1 v1.5 decode.
+ *
+ *  @param msg              The encoded data to decode
+ *  @param msglen           The length of the encoded data (octets)
+ *  @param block_type       Block type to use in padding (\sa ltc_pkcs_1_v1_5_blocks)
+ *  @param modulus_bitlen   The bit length of the RSA modulus
+ *  @param out              [out] Destination of decoding
+ *  @param outlen           [in/out] The max size and resulting size of the decoding
+ *  @param is_valid         [out] Boolean whether the padding was valid
+ *
+ *  @return CRYPT_OK if successful
+ */
+int pkcs_1_v1_5_decode(const unsigned char *msg,
+                             unsigned long  msglen,
+                                       int  block_type,
+                             unsigned long  modulus_bitlen,
+                             unsigned char *out,
+                             unsigned long *outlen,
+                                       int *is_valid)
+{
+   return ltc_pkcs_1_v1_5_decode(msg, msglen,
+                                 block_type, modulus_bitlen,
+                                 out, outlen,
+                                 is_valid);
+}
+#endif /* LTC_PKCS_1 */
+
 int compare_testvector(const void* is, const unsigned long is_len, const void* should, const unsigned long should_len, const char* what, int which)
 {
    return ltc_compare_testvector(is, is_len, should, should_len, what, which);
 }
 
-
 #endif /* LTC_NO_DEPRECATED_APIS */

+ 3 - 3
src/pk/pkcs1/pkcs_1_mgf1.c

@@ -18,9 +18,9 @@
    @param masklen     The length of the mask desired
    @return CRYPT_OK if successful
 */
-int pkcs_1_mgf1(int                  hash_idx,
-                const unsigned char *seed, unsigned long seedlen,
-                      unsigned char *mask, unsigned long masklen)
+int ltc_pkcs_1_mgf1(int                  hash_idx,
+                    const unsigned char *seed, unsigned long seedlen,
+                          unsigned char *mask, unsigned long masklen)
 {
    unsigned long hLen, x;
    ulong32       counter;

+ 18 - 30
src/pk/pkcs1/pkcs_1_oaep_decode.c

@@ -8,53 +8,41 @@
 */
 
 #ifdef LTC_PKCS_1
-
 /**
    PKCS #1 v2.00 OAEP decode
    @param msg              The encoded data to decode
    @param msglen           The length of the encoded data (octets)
-   @param lparam           The session or system data (can be NULL)
-   @param lparamlen        The length of the lparam
+   @param params           The PKCS#1 operation's parameters
    @param modulus_bitlen   The bit length of the RSA modulus
-   @param mgf_hash         The hash algorithm used for the MGF
-   @param lparam_hash      The hash algorithm used when hashing the lparam (can be -1)
    @param out              [out] Destination of decoding
    @param outlen           [in/out] The max size and resulting size of the decoding
    @param res              [out] Result of decoding, 1==valid, 0==invalid
    @return CRYPT_OK if successful
 */
-int pkcs_1_oaep_decode(const unsigned char *msg,    unsigned long msglen,
-                       const unsigned char *lparam, unsigned long lparamlen,
-                             unsigned long modulus_bitlen,
-                             int mgf_hash, int lparam_hash,
-                             unsigned char *out,    unsigned long *outlen,
-                             int           *res)
+int ltc_pkcs_1_oaep_decode(const unsigned char *msg,    unsigned long msglen,
+                         ltc_rsa_op_parameters *params,
+                                 unsigned long  modulus_bitlen,
+                                 unsigned char *out,    unsigned long *outlen,
+                                 int           *res)
 {
    unsigned char *DB, *seed, *mask;
    unsigned long hLen, x, y, modulus_len;
-   int           err, ret, lparam_hash_used;
+   int           err, ret;
+   ltc_rsa_op_checked op_checked = ltc_pkcs1_op_checked_init(params);
 
    LTC_ARGCHK(msg    != NULL);
    LTC_ARGCHK(out    != NULL);
    LTC_ARGCHK(outlen != NULL);
    LTC_ARGCHK(res    != NULL);
 
+   if ((err = rsa_key_valid_op(LTC_PKCS1_DECRYPT, &op_checked)) != CRYPT_OK) {
+      return err;
+   }
+
    /* default to invalid packet */
    *res = 0;
 
-   /* test valid hash */
-   if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) {
-      return err;
-   }
-   if (lparam_hash != -1) {
-      if ((err = hash_is_valid(lparam_hash)) != CRYPT_OK) {
-         return err;
-      }
-      lparam_hash_used = lparam_hash;
-   } else {
-      lparam_hash_used = mgf_hash;
-   }
-   hLen        = hash_descriptor[lparam_hash_used].hashsize;
+   hLen        = hash_descriptor[op_checked.hash_alg].hashsize;
    modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
 
    /* test hash/message size */
@@ -104,7 +92,7 @@ int pkcs_1_oaep_decode(const unsigned char *msg,    unsigned long msglen,
    x += modulus_len - hLen - 1;
 
    /* compute MGF1 of maskedDB (hLen) */
-   if ((err = pkcs_1_mgf1(mgf_hash, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
+   if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
       goto LBL_ERR;
    }
 
@@ -114,7 +102,7 @@ int pkcs_1_oaep_decode(const unsigned char *msg,    unsigned long msglen,
    }
 
    /* compute MGF1 of seed (k - hlen - 1) */
-   if ((err = pkcs_1_mgf1(mgf_hash, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+   if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
       goto LBL_ERR;
    }
 
@@ -127,13 +115,13 @@ int pkcs_1_oaep_decode(const unsigned char *msg,    unsigned long msglen,
 
    /* compute lhash and store it in seed [reuse temps!] */
    x = modulus_len;
-   if (lparam != NULL) {
-      if ((err = hash_memory(lparam_hash_used, lparam, lparamlen, seed, &x)) != CRYPT_OK) {
+   if (op_checked.params->u.crypt.lparam != NULL) {
+      if ((err = hash_memory(op_checked.hash_alg, op_checked.params->u.crypt.lparam, op_checked.params->u.crypt.lparamlen, seed, &x)) != CRYPT_OK) {
          goto LBL_ERR;
       }
    } else {
       /* can't pass hash_memory a NULL so use DB with zero length */
-      if ((err = hash_memory(lparam_hash_used, DB, 0, seed, &x)) != CRYPT_OK) {
+      if ((err = hash_memory(op_checked.hash_alg, DB, 0, seed, &x)) != CRYPT_OK) {
          goto LBL_ERR;
       }
    }

+ 15 - 35
src/pk/pkcs1/pkcs_1_oaep_encode.c

@@ -8,55 +8,35 @@
 */
 
 #ifdef LTC_PKCS_1
-
 /**
   PKCS #1 v2.00 OAEP encode
   @param msg             The data to encode
   @param msglen          The length of the data to encode (octets)
-  @param lparam          A session or system parameter (can be NULL)
-  @param lparamlen       The length of the lparam data
+  @param params          The PKCS#1 operation's parameters
   @param modulus_bitlen  The bit length of the RSA modulus
-  @param prng            An active PRNG state
-  @param prng_idx        The index of the PRNG desired
-  @param hash_idx        The index of the hash desired
   @param out             [out] The destination for the encoded data
   @param outlen          [in/out] The max size and resulting size of the encoded data
   @return CRYPT_OK if successful
 */
-int pkcs_1_oaep_encode(const unsigned char *msg,    unsigned long msglen,
-                       const unsigned char *lparam, unsigned long lparamlen,
-                             unsigned long modulus_bitlen, prng_state *prng,
-                             int           prng_idx,
-                             int           mgf_hash, int lparam_hash,
-                             unsigned char *out,    unsigned long *outlen)
+int ltc_pkcs_1_oaep_encode(const unsigned char   *msg,    unsigned long msglen,
+                          ltc_rsa_op_parameters *params,
+                                unsigned long    modulus_bitlen,
+                                unsigned char   *out,    unsigned long *outlen)
 {
    unsigned char *DB, *seed, *mask;
    unsigned long hLen, x, y, modulus_len;
-   int           err, lparam_hash_used;
+   int           err;
+   ltc_rsa_op_checked op_checked = ltc_pkcs1_op_checked_init(params);
 
    LTC_ARGCHK((msglen == 0) || (msg != NULL));
    LTC_ARGCHK(out    != NULL);
    LTC_ARGCHK(outlen != NULL);
 
-   /* test valid hash */
-   if ((err = hash_is_valid(mgf_hash)) != CRYPT_OK) {
-      return err;
-   }
-   if (lparam_hash != -1) {
-      if ((err = hash_is_valid(lparam_hash)) != CRYPT_OK) {
-         return err;
-      }
-      lparam_hash_used = lparam_hash;
-   } else {
-      lparam_hash_used = mgf_hash;
-   }
-
-   /* valid prng */
-   if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
+   if ((err = rsa_key_valid_op(LTC_PKCS1_ENCRYPT, &op_checked)) != CRYPT_OK) {
       return err;
    }
 
-   hLen        = hash_descriptor[lparam_hash_used].hashsize;
+   hLen        = hash_descriptor[op_checked.hash_alg].hashsize;
    modulus_len = (modulus_bitlen >> 3) + (modulus_bitlen & 7 ? 1 : 0);
 
    /* test message size */
@@ -84,13 +64,13 @@ int pkcs_1_oaep_encode(const unsigned char *msg,    unsigned long msglen,
    /* get lhash */
    /* DB == lhash || PS || 0x01 || M, PS == k - mlen - 2hlen - 2 zeroes */
    x = modulus_len;
-   if (lparam != NULL) {
-      if ((err = hash_memory(lparam_hash_used, lparam, lparamlen, DB, &x)) != CRYPT_OK) {
+   if (op_checked.params->u.crypt.lparam != NULL) {
+      if ((err = hash_memory(op_checked.hash_alg, op_checked.params->u.crypt.lparam, op_checked.params->u.crypt.lparamlen, DB, &x)) != CRYPT_OK) {
          goto LBL_ERR;
       }
    } else {
       /* can't pass hash_memory a NULL so use `out` with zero length */
-      if ((err = hash_memory(lparam_hash_used, out, 0, DB, &x)) != CRYPT_OK) {
+      if ((err = hash_memory(op_checked.hash_alg, out, 0, DB, &x)) != CRYPT_OK) {
          goto LBL_ERR;
       }
    }
@@ -111,13 +91,13 @@ int pkcs_1_oaep_encode(const unsigned char *msg,    unsigned long msglen,
    }
 
    /* now choose a random seed */
-   if (prng_descriptor[prng_idx].read(seed, hLen, prng) != hLen) {
+   if (prng_descriptor[op_checked.params->wprng].read(seed, hLen, op_checked.params->prng) != hLen) {
       err = CRYPT_ERROR_READPRNG;
       goto LBL_ERR;
    }
 
    /* compute MGF1 of seed (k - hlen - 1) */
-   if ((err = pkcs_1_mgf1(mgf_hash, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+   if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, seed, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
       goto LBL_ERR;
    }
 
@@ -127,7 +107,7 @@ int pkcs_1_oaep_encode(const unsigned char *msg,    unsigned long msglen,
    }
 
    /* compute MGF1 of maskedDB (hLen) */
-   if ((err = pkcs_1_mgf1(mgf_hash, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
+   if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, DB, modulus_len - hLen - 1, mask, hLen)) != CRYPT_OK) {
       goto LBL_ERR;
    }
 

+ 19 - 45
src/pk/pkcs1/pkcs_1_pss_decode.c

@@ -10,46 +10,41 @@
 #ifdef LTC_PKCS_1
 
 /**
-   PKCS #1 v2.00 PSS decode
+   PKCS #1 v2.00 Signature Verification
    @param  msghash         The hash to verify
    @param  msghashlen      The length of the hash (octets)
    @param  sig             The signature data (encoded data)
    @param  siglen          The length of the signature data (octets)
-   @param  saltlen         The length of the salt used (octets)
-   @param  hash_idx        The index of the hash desired
-   @param  mgf_hash_idx    The index of the hash desired for MGF1
+   @param  params          The PKCS#1 operation's parameters
    @param  modulus_bitlen  The bit length of the RSA modulus
    @param  res             [out] The result of the comparison, 1==valid, 0==invalid
    @return CRYPT_OK if successful (even if the comparison failed)
 */
-int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashlen,
-                           const unsigned char *sig,     unsigned long siglen,
-                                 unsigned long saltlen,
-                                          int  hash_idx,           int mgf_hash_idx,
-                                 unsigned long modulus_bitlen,     int *res)
+int ltc_pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long  msghashlen,
+                               const unsigned char *sig,     unsigned long  siglen,
+                               ltc_rsa_op_parameters *params,
+                                     unsigned long  modulus_bitlen,    int *res)
 {
    unsigned char *DB, *mask, *salt, *hash;
-   unsigned long x, y, hLen, modulus_len;
+   unsigned long x, y, hLen, modulus_len, saltlen;
    int           err;
    hash_state    md;
+   ltc_rsa_op_checked op_checked = ltc_pkcs1_op_checked_init(params);
 
    LTC_ARGCHK(msghash != NULL);
+   LTC_ARGCHK(sig     != NULL);
+   LTC_ARGCHK(params  != NULL);
    LTC_ARGCHK(res     != NULL);
 
    /* default to invalid */
    *res = 0;
 
-   /* ensure hash is valid */
-   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
+   if ((err = rsa_key_valid_op(LTC_PKCS1_VERIFY, &op_checked)) != CRYPT_OK) {
       return err;
    }
-   if (hash_idx != mgf_hash_idx) {
-      if ((err = hash_is_valid(mgf_hash_idx)) != CRYPT_OK) {
-         return err;
-      }
-   }
 
-   hLen        = hash_descriptor[hash_idx].hashsize;
+   hLen        = hash_descriptor[op_checked.hash_alg].hashsize;
+   saltlen     = params->params.saltlen;
    modulus_bitlen--;
    modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0);
 
@@ -102,7 +97,7 @@ int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashle
    }
 
    /* generate mask of length modulus_len - hLen - 1 from hash */
-   if ((err = pkcs_1_mgf1(mgf_hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+   if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
       goto LBL_ERR;
    }
 
@@ -131,20 +126,20 @@ int pkcs_1_pss_decode_mgf1(const unsigned char *msghash, unsigned long msghashle
    }
 
    /* M = (eight) 0x00 || msghash || salt, mask = H(M) */
-   if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) {
+   if ((err = hash_descriptor[op_checked.hash_alg].init(&md)) != CRYPT_OK) {
       goto LBL_ERR;
    }
    zeromem(mask, 8);
-   if ((err = hash_descriptor[hash_idx].process(&md, mask, 8)) != CRYPT_OK) {
+   if ((err = hash_descriptor[op_checked.hash_alg].process(&md, mask, 8)) != CRYPT_OK) {
       goto LBL_ERR;
    }
-   if ((err = hash_descriptor[hash_idx].process(&md, msghash, msghashlen)) != CRYPT_OK) {
+   if ((err = hash_descriptor[op_checked.hash_alg].process(&md, msghash, msghashlen)) != CRYPT_OK) {
       goto LBL_ERR;
    }
-   if ((err = hash_descriptor[hash_idx].process(&md, DB+x, saltlen)) != CRYPT_OK) {
+   if ((err = hash_descriptor[op_checked.hash_alg].process(&md, DB+x, saltlen)) != CRYPT_OK) {
       goto LBL_ERR;
    }
-   if ((err = hash_descriptor[hash_idx].done(&md, mask)) != CRYPT_OK) {
+   if ((err = hash_descriptor[op_checked.hash_alg].done(&md, mask)) != CRYPT_OK) {
       goto LBL_ERR;
    }
 
@@ -170,25 +165,4 @@ LBL_ERR:
    return err;
 }
 
-
-/**
-   PKCS #1 v2.00 PSS decode
-   @param  msghash         The hash to verify
-   @param  msghashlen      The length of the hash (octets)
-   @param  sig             The signature data (encoded data)
-   @param  siglen          The length of the signature data (octets)
-   @param  saltlen         The length of the salt used (octets)
-   @param  hash_idx        The index of the hash desired
-   @param  modulus_bitlen  The bit length of the RSA modulus
-   @param  res             [out] The result of the comparison, 1==valid, 0==invalid
-   @return CRYPT_OK if successful (even if the comparison failed)
-*/
-int pkcs_1_pss_decode(const unsigned char *msghash, unsigned long msghashlen,
-                      const unsigned char *sig,     unsigned long siglen,
-                            unsigned long saltlen,  int           hash_idx,
-                            unsigned long modulus_bitlen, int    *res)
-{
-   return pkcs_1_pss_decode_mgf1(msghash, msghashlen, sig, siglen, saltlen, hash_idx, hash_idx, modulus_bitlen, res);
-}
-
 #endif /* LTC_PKCS_1 */

+ 18 - 53
src/pk/pkcs1/pkcs_1_pss_encode.c

@@ -13,46 +13,34 @@
    PKCS #1 v2.00 Signature Encoding
    @param msghash          The hash to encode
    @param msghashlen       The length of the hash (octets)
-   @param saltlen          The length of the salt desired (octets)
-   @param prng             An active PRNG context
-   @param prng_idx         The index of the PRNG desired
-   @param hash_idx         The index of the hash desired
-   @param mgf_hash_idx     The index of the hash desired for MGF1
+   @param params           The PKCS#1 operation's parameters
    @param modulus_bitlen   The bit length of the RSA modulus
    @param out              [out] The destination of the encoding
    @param outlen           [in/out] The max size and resulting size of the encoded data
    @return CRYPT_OK if successful
 */
-int pkcs_1_pss_encode_mgf1(const unsigned char *msghash,       unsigned long  msghashlen,
-                                 unsigned long saltlen,
-                                 prng_state    *prng,                    int  prng_idx,
-                                 int           hash_idx,                 int  mgf_hash_idx,
-                                 unsigned long modulus_bitlen,
-                                 unsigned char *out,           unsigned long *outlen)
+int ltc_pkcs_1_pss_encode_mgf1(const unsigned char *msghash,       unsigned long  msghashlen,
+                             ltc_rsa_op_parameters *params,
+                                     unsigned long  modulus_bitlen,
+                                     unsigned char *out,           unsigned long *outlen)
 {
    unsigned char *DB, *mask, *salt, *hash;
-   unsigned long x, y, hLen, modulus_len;
+   unsigned long x, y, hLen, modulus_len, saltlen;
    int           err;
    hash_state    md;
+   ltc_rsa_op_checked op_checked = ltc_pkcs1_op_checked_init(params);
 
    LTC_ARGCHK(msghash != NULL);
+   LTC_ARGCHK(params  != NULL);
    LTC_ARGCHK(out     != NULL);
    LTC_ARGCHK(outlen  != NULL);
 
-   /* ensure hashes and PRNG are valid */
-   if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
-      return err;
-   }
-   if (hash_idx != mgf_hash_idx) {
-      if ((err = hash_is_valid(mgf_hash_idx)) != CRYPT_OK) {
-         return err;
-      }
-   }
-   if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
+   if ((err = rsa_key_valid_op(LTC_PKCS1_SIGN, &op_checked)) != CRYPT_OK) {
       return err;
    }
 
-   hLen        = hash_descriptor[hash_idx].hashsize;
+   hLen        = hash_descriptor[op_checked.hash_alg].hashsize;
+   saltlen     = params->params.saltlen;
    modulus_bitlen--;
    modulus_len = (modulus_bitlen>>3) + (modulus_bitlen & 7 ? 1 : 0);
 
@@ -85,27 +73,27 @@ int pkcs_1_pss_encode_mgf1(const unsigned char *msghash,       unsigned long  ms
 
    /* generate random salt */
    if (saltlen > 0) {
-      if (prng_descriptor[prng_idx].read(salt, saltlen, prng) != saltlen) {
+      if (prng_descriptor[params->wprng].read(salt, saltlen, params->prng) != saltlen) {
          err = CRYPT_ERROR_READPRNG;
          goto LBL_ERR;
       }
    }
 
    /* M = (eight) 0x00 || msghash || salt, hash = H(M) */
-   if ((err = hash_descriptor[hash_idx].init(&md)) != CRYPT_OK) {
+   if ((err = hash_descriptor[op_checked.hash_alg].init(&md)) != CRYPT_OK) {
       goto LBL_ERR;
    }
    zeromem(DB, 8);
-   if ((err = hash_descriptor[hash_idx].process(&md, DB, 8)) != CRYPT_OK) {
+   if ((err = hash_descriptor[op_checked.hash_alg].process(&md, DB, 8)) != CRYPT_OK) {
       goto LBL_ERR;
    }
-   if ((err = hash_descriptor[hash_idx].process(&md, msghash, msghashlen)) != CRYPT_OK) {
+   if ((err = hash_descriptor[op_checked.hash_alg].process(&md, msghash, msghashlen)) != CRYPT_OK) {
       goto LBL_ERR;
    }
-   if ((err = hash_descriptor[hash_idx].process(&md, salt, saltlen)) != CRYPT_OK) {
+   if ((err = hash_descriptor[op_checked.hash_alg].process(&md, salt, saltlen)) != CRYPT_OK) {
       goto LBL_ERR;
    }
-   if ((err = hash_descriptor[hash_idx].done(&md, hash)) != CRYPT_OK) {
+   if ((err = hash_descriptor[op_checked.hash_alg].done(&md, hash)) != CRYPT_OK) {
       goto LBL_ERR;
    }
 
@@ -118,7 +106,7 @@ int pkcs_1_pss_encode_mgf1(const unsigned char *msghash,       unsigned long  ms
    /* x += saltlen; */
 
    /* generate mask of length modulus_len - hLen - 1 from hash */
-   if ((err = pkcs_1_mgf1(mgf_hash_idx, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
+   if ((err = ltc_pkcs_1_mgf1(op_checked.mgf1_hash_alg, hash, hLen, mask, modulus_len - hLen - 1)) != CRYPT_OK) {
       goto LBL_ERR;
    }
 
@@ -168,27 +156,4 @@ LBL_ERR:
    return err;
 }
 
-
-/**
-   PKCS #1 v2.00 Signature Encoding using MGF1 and both hashes are the same
-   @param msghash          The hash to encode
-   @param msghashlen       The length of the hash (octets)
-   @param saltlen          The length of the salt desired (octets)
-   @param prng             An active PRNG context
-   @param prng_idx         The index of the PRNG desired
-   @param hash_idx         The index of the hash desired
-   @param modulus_bitlen   The bit length of the RSA modulus
-   @param out              [out] The destination of the encoding
-   @param outlen           [in/out] The max size and resulting size of the encoded data
-   @return CRYPT_OK if successful
-*/
-int pkcs_1_pss_encode(const unsigned char *msghash,  unsigned long msghashlen,
-                            unsigned long saltlen,   prng_state   *prng,
-                            int           prng_idx,  int           hash_idx,
-                            unsigned long modulus_bitlen,
-                            unsigned char *out,      unsigned long *outlen)
-{
-   return pkcs_1_pss_encode_mgf1(msghash, msghashlen, saltlen, prng, prng_idx, hash_idx, hash_idx, modulus_bitlen, out, outlen);
-}
-
 #endif /* LTC_PKCS_1 */

+ 7 - 7
src/pk/pkcs1/pkcs_1_v1_5_decode.c

@@ -21,13 +21,13 @@
  *
  *  @return CRYPT_OK if successful
  */
-int pkcs_1_v1_5_decode(const unsigned char *msg,
-                             unsigned long  msglen,
-                                       int  block_type,
-                             unsigned long  modulus_bitlen,
-                             unsigned char *out,
-                             unsigned long *outlen,
-                                       int *is_valid)
+int ltc_pkcs_1_v1_5_decode(const unsigned char *msg,
+                                 unsigned long  msglen,
+                                           int  block_type,
+                                 unsigned long  modulus_bitlen,
+                                 unsigned char *out,
+                                 unsigned long *outlen,
+                                           int *is_valid)
 {
   unsigned long modulus_len, ps_len, i;
   int result;

+ 8 - 8
src/pk/pkcs1/pkcs_1_v1_5_encode.c

@@ -22,14 +22,14 @@
  *
  *  \return CRYPT_OK if successful
  */
-int pkcs_1_v1_5_encode(const unsigned char *msg,
-                             unsigned long  msglen,
-                                       int  block_type,
-                             unsigned long  modulus_bitlen,
-                                prng_state *prng,
-                                       int  prng_idx,
-                             unsigned char *out,
-                             unsigned long *outlen)
+int ltc_pkcs_1_v1_5_encode(const unsigned char *msg,
+                                 unsigned long  msglen,
+                                           int  block_type,
+                                 unsigned long  modulus_bitlen,
+                                    prng_state *prng,
+                                           int  prng_idx,
+                                 unsigned char *out,
+                                 unsigned long *outlen)
 {
   unsigned long modulus_len, ps_len, i;
   unsigned char *ps;

+ 12 - 20
src/pk/rsa/rsa_decrypt_key.c

@@ -8,44 +8,37 @@
 */
 
 #ifdef LTC_MRSA
-
 /**
-   PKCS #1 decrypt then v1.5 or OAEP depad
+   Decrypt then (PKCS #1 v2.0) OAEP or (PKCS #1 v1.5) EME depad
    @param in          The ciphertext
    @param inlen       The length of the ciphertext (octets)
    @param out         [out] The plaintext
    @param outlen      [in/out] The max size and resulting size of the plaintext (octets)
-   @param lparam      The system "lparam" value
-   @param lparamlen   The length of the lparam value (octets)
-   @param mgf_hash    The hash algorithm used for the MGF
-   @param lparam_hash The hash algorithm used when hashing the lparam (can be -1)
-   @param padding     Type of padding (LTC_PKCS_1_OAEP or LTC_PKCS_1_V1_5)
+   @param params      The RSA operation's parameters
    @param stat        [out] Result of the decryption, 1==valid, 0==invalid
    @param key         The corresponding private RSA key
    @return CRYPT_OK if succcessul (even if invalid)
 */
-int rsa_decrypt_key_ex(const unsigned char *in,             unsigned long  inlen,
+int rsa_decrypt_key_v2(const unsigned char *in,             unsigned long  inlen,
                              unsigned char *out,            unsigned long *outlen,
-                       const unsigned char *lparam,         unsigned long  lparamlen,
-                             int            mgf_hash,       int            lparam_hash,
-                             int            padding,
+                     ltc_rsa_op_parameters *params,
                              int           *stat,     const rsa_key       *key)
 {
-  unsigned long modulus_bitlen, modulus_bytelen, x;
   int           err;
   unsigned char *tmp;
+  unsigned long modulus_bitlen, modulus_bytelen, x;
+  ltc_rsa_op_checked op_checked = ltc_rsa_op_checked_init(key, params);
 
   LTC_ARGCHK(in     != NULL);
   LTC_ARGCHK(out    != NULL);
   LTC_ARGCHK(outlen != NULL);
-  LTC_ARGCHK(key    != NULL);
   LTC_ARGCHK(stat   != NULL);
 
   /* default to invalid */
   *stat = 0;
 
   /* valid padding? */
-  if ((err = rsa_key_valid_op(key, LTC_RSA_CRYPT, padding, mgf_hash)) != CRYPT_OK) {
+  if ((err = rsa_key_valid_op(LTC_RSA_DECRYPT, &op_checked)) != CRYPT_OK) {
     return err;
   }
 
@@ -64,20 +57,19 @@ int rsa_decrypt_key_ex(const unsigned char *in,             unsigned long  inlen
      return CRYPT_MEM;
   }
 
-  /* rsa decode the packet */
+  /* rsa exptmod the packet */
   x = inlen;
   if ((err = ltc_mp.rsa_me(in, inlen, tmp, &x, PK_PRIVATE, key)) != CRYPT_OK) {
      XFREE(tmp);
      return err;
   }
 
-  if (padding == LTC_PKCS_1_OAEP) {
-    /* now OAEP decode the packet */
-    err = pkcs_1_oaep_decode(tmp, x, lparam, lparamlen, modulus_bitlen, mgf_hash,
-                             lparam_hash, out, outlen, stat);
+  if (params->padding == LTC_PKCS_1_OAEP) {
+    /* now OAEP depad the packet */
+    err = ltc_pkcs_1_oaep_decode(tmp, x, params, modulus_bitlen, out, outlen, stat);
   } else {
     /* now PKCS #1 v1.5 depad the packet */
-    err = pkcs_1_v1_5_decode(tmp, x, LTC_PKCS_1_EME, modulus_bitlen, out, outlen, stat);
+    err = ltc_pkcs_1_v1_5_decode(tmp, x, LTC_PKCS_1_EME, modulus_bitlen, out, outlen, stat);
   }
 
   XFREE(tmp);

+ 20 - 37
src/pk/rsa/rsa_encrypt_key.c

@@ -8,48 +8,33 @@
 */
 
 #ifdef LTC_MRSA
-
 /**
-    (PKCS #1 v2.0) OAEP pad then encrypt
-    @param in          The plaintext
-    @param inlen       The length of the plaintext (octets)
-    @param out         [out] The ciphertext
-    @param outlen      [in/out] The max size and resulting size of the ciphertext
-    @param lparam      The system "lparam" for the encryption
-    @param lparamlen   The length of lparam (octets)
-    @param prng        An active PRNG
-    @param prng_idx    The index of the desired prng
-    @param hash_idx    The index of the desired hash
-    @param padding     Type of padding (LTC_PKCS_1_OAEP or LTC_PKCS_1_V1_5)
-    @param key         The RSA key to encrypt to
-    @return CRYPT_OK if successful
+   (PKCS #1 v2.0) OAEP or (PKCS #1 v1.5) EME pad then encrypt
+   @param in          The plaintext
+   @param inlen       The length of the plaintext (octets)
+   @param out         [out] The ciphertext
+   @param outlen      [in/out] The max size and resulting size of the ciphertext
+   @param params      The RSA operation's parameters
+   @param key         The RSA key to encrypt to
+   @return CRYPT_OK if successful
 */
-int rsa_encrypt_key_ex(const unsigned char *in,       unsigned long  inlen,
-                             unsigned char *out,      unsigned long *outlen,
-                       const unsigned char *lparam,   unsigned long  lparamlen,
-                             prng_state    *prng,     int            prng_idx,
-                             int            mgf_hash, int            lparam_hash,
-                             int            padding,
-                       const rsa_key       *key)
+int rsa_encrypt_key_v2(const unsigned char   *in,     unsigned long  inlen,
+                             unsigned char   *out,    unsigned long *outlen,
+                       ltc_rsa_op_parameters *params,
+                       const rsa_key         *key)
 {
-  unsigned long modulus_bitlen, modulus_bytelen, x;
   int           err;
+  unsigned long modulus_bitlen, modulus_bytelen, x;
+  ltc_rsa_op_checked op_checked = ltc_rsa_op_checked_init(key, params);
 
   LTC_ARGCHK((inlen == 0) || (in != NULL));
   LTC_ARGCHK(out    != NULL);
   LTC_ARGCHK(outlen != NULL);
-  LTC_ARGCHK(key    != NULL);
 
-  /* valid padding? */
-  if ((err = rsa_key_valid_op(key, LTC_RSA_CRYPT, padding, mgf_hash)) != CRYPT_OK) {
+  if ((err = rsa_key_valid_op(LTC_RSA_ENCRYPT, &op_checked)) != CRYPT_OK) {
     return err;
   }
 
-  /* valid prng? */
-  if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
-     return err;
-  }
-
   /* get modulus len in bits */
   modulus_bitlen = ltc_mp_count_bits( (key->N));
 
@@ -60,20 +45,18 @@ int rsa_encrypt_key_ex(const unsigned char *in,       unsigned long  inlen,
      return CRYPT_BUFFER_OVERFLOW;
   }
 
-  if (padding == LTC_PKCS_1_OAEP) {
+  if (params->padding == LTC_PKCS_1_OAEP) {
     /* OAEP pad the key */
     x = *outlen;
-    if ((err = pkcs_1_oaep_encode(in, inlen, lparam,
-                                  lparamlen, modulus_bitlen, prng, prng_idx, mgf_hash,
-                                  lparam_hash, out, &x)) != CRYPT_OK) {
+    if ((err = ltc_pkcs_1_oaep_encode(in, inlen, params, modulus_bitlen, out, &x)) != CRYPT_OK) {
        return err;
     }
   } else {
     /* PKCS #1 v1.5 pad the key */
     x = *outlen;
-    if ((err = pkcs_1_v1_5_encode(in, inlen, LTC_PKCS_1_EME,
-                                  modulus_bitlen, prng, prng_idx,
-                                  out, &x)) != CRYPT_OK) {
+    if ((err = ltc_pkcs_1_v1_5_encode(in, inlen, LTC_PKCS_1_EME,
+                                      modulus_bitlen, params->prng, params->wprng,
+                                      out, &x)) != CRYPT_OK) {
       return err;
     }
   }

+ 98 - 32
src/pk/rsa/rsa_key.c

@@ -100,68 +100,134 @@ void rsa_free(rsa_key *key)
    XMEMSET(&key->params, 0, sizeof(key->params));
 }
 
-static LTC_INLINE int s_rsa_key_valid_pss_algs(const rsa_key *key, int padding, int hash_idx)
+static LTC_INLINE int s_rsa_key_valid_rsa_params(ltc_rsa_op_checked *check)
 {
-   if (!key->params.pss_oaep) {
+   const ltc_rsa_parameters *key_params, *op_params;
+   /* This is called from PKCS#1 de-/encoder code, so we can't check the key */
+   if (check->key == NULL) {
       return CRYPT_OK;
    }
-   if (padding != LTC_PKCS_1_PSS) {
+   key_params = &check->key->params;
+   op_params = &check->params->params;
+   /* The key is restricted to PSS, so check the op's params */
+   if (key_params->pss_oaep
+         && !rsa_params_equal(key_params, op_params)) {
       return CRYPT_PK_TYPE_MISMATCH;
    }
-   if (key->params.hash_alg == NULL || find_hash(key->params.hash_alg) != hash_idx) {
+   /* No PSS or OAEP, so we're fine. */
+   if (!key_params->pss_oaep
+         || !op_params->pss_oaep) {
+      return CRYPT_OK;
+   }
+   /* Verify hash algs */
+   if (key_params->hash_alg == NULL
+         || find_hash(key_params->hash_alg) != check->hash_alg) {
       return CRYPT_INVALID_HASH;
    }
-   if (key->params.mgf1_hash_alg == NULL) {
+   if (key_params->mgf1_hash_alg == NULL
+         || find_hash(key_params->mgf1_hash_alg) != check->mgf1_hash_alg) {
       return CRYPT_INVALID_HASH;
    }
-   return hash_is_valid(find_hash(key->params.mgf1_hash_alg));
+   return CRYPT_OK;
 }
 
-static LTC_INLINE int s_rsa_key_valid_sign(const rsa_key *key, int padding, int hash_idx)
+static LTC_INLINE int s_rsa_key_set_hash_algs(ltc_rsa_op_checked *check)
 {
-   if ((padding != LTC_PKCS_1_V1_5) &&
-       (padding != LTC_PKCS_1_PSS) &&
-       (padding != LTC_PKCS_1_V1_5_NA1)) {
-     return CRYPT_PK_INVALID_PADDING;
+   ltc_rsa_op_parameters *params = check->params;
+   if (params->params.hash_alg == NULL
+         || (check->hash_alg = find_hash(params->params.hash_alg)) == -1) {
+      return CRYPT_INVALID_HASH;
+   }
+   if (params->params.mgf1_hash_alg == NULL) {
+      if (!params->params.pss_oaep)
+         return CRYPT_OK;
+   } else if ((check->mgf1_hash_alg = find_hash(params->params.mgf1_hash_alg)) != -1) {
+      return CRYPT_OK;
+   }
+   return CRYPT_INVALID_HASH;
+}
+
+static LTC_INLINE int s_rsa_key_valid_sign(ltc_rsa_op_checked *check)
+{
+   ltc_rsa_op_parameters *params = check->params;
+   if ((params->padding != LTC_PKCS_1_V1_5)
+         && (params->padding != LTC_PKCS_1_PSS)
+         && (params->padding != LTC_PKCS_1_V1_5_NA1)) {
+      return CRYPT_PK_INVALID_PADDING;
    }
 
-   if (padding != LTC_PKCS_1_V1_5_NA1) {
-      int err;
-      /* valid hash ? */
-      if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
-        return err;
+   if (params->padding != LTC_PKCS_1_V1_5_NA1) {
+      int err = s_rsa_key_set_hash_algs(check);
+      if (err != CRYPT_OK) {
+         return err;
       }
    }
-   return s_rsa_key_valid_pss_algs(key, padding, hash_idx);
+   if (params->padding == LTC_PKCS_1_V1_5) {
+      /* not all hashes have OIDs... so sad */
+      if (check->hash_alg == -1
+            || hash_descriptor[check->hash_alg].OIDlen == 0) {
+         return CRYPT_INVALID_ARG;
+      }
+   }
+   return s_rsa_key_valid_rsa_params(check);
 }
 
-static LTC_INLINE int s_rsa_key_valid_crypt(const rsa_key *key, int padding, int hash_idx)
+static LTC_INLINE int s_rsa_key_valid_crypt(ltc_rsa_op_checked *check)
 {
-   if ((padding != LTC_PKCS_1_V1_5) &&
-       (padding != LTC_PKCS_1_OAEP)) {
+   ltc_rsa_op_parameters *params = check->params;
+   if ((params->padding != LTC_PKCS_1_V1_5) &&
+       (params->padding != LTC_PKCS_1_OAEP)) {
      return CRYPT_PK_INVALID_PADDING;
    }
 
-   if (padding == LTC_PKCS_1_OAEP) {
-      int err;
-      /* valid hash? */
-      if ((err = hash_is_valid(hash_idx)) != CRYPT_OK) {
-        return err;
+   if (params->padding == LTC_PKCS_1_OAEP) {
+      int err = s_rsa_key_set_hash_algs(check);
+      if (err != CRYPT_OK) {
+         return err;
       }
    }
-   return s_rsa_key_valid_pss_algs(key, padding, hash_idx);
+   return s_rsa_key_valid_rsa_params(check);
+}
+
+static LTC_INLINE int s_rsa_check_prng(ltc_rsa_op_parameters *params)
+{
+   if (params->padding != LTC_PKCS_1_PSS)
+      return CRYPT_OK;
+   if (params->prng == NULL)
+      return CRYPT_INVALID_PRNG;
+   /* valid prng ? */
+   return prng_is_valid(params->wprng);
 }
 
-int rsa_key_valid_op(const rsa_key *key, ltc_rsa_op op, int padding, int hash_idx)
+int rsa_key_valid_op(ltc_rsa_op op, ltc_rsa_op_checked *check)
 {
+   int err;
+   check->hash_alg = check->mgf1_hash_alg = -1;
+   LTC_ARGCHK(check->params != NULL);
+   if ((op & LTC_RSA_OP_PKCS1) != LTC_RSA_OP_PKCS1) {
+      /* PKCS#1 ops don't need an RSA key */
+      LTC_ARGCHK(check->key    != NULL);
+   }
+   check->params->params.pss_oaep = check->params->padding == LTC_PKCS_1_OAEP
+         || check->params->padding == LTC_PKCS_1_PSS;
+   if ((op & LTC_RSA_OP_SEND) == LTC_RSA_OP_SEND) {
+      if ((err = s_rsa_check_prng(check->params)) != CRYPT_OK) {
+         return err;
+      }
+   }
    switch (op) {
+      case LTC_RSA_ENCRYPT:
+      case LTC_RSA_DECRYPT:
+      case LTC_PKCS1_ENCRYPT:
+      case LTC_PKCS1_DECRYPT:
+         return s_rsa_key_valid_crypt(check);
       case LTC_RSA_SIGN:
-         return s_rsa_key_valid_sign(key, padding, hash_idx);
-      case LTC_RSA_CRYPT:
-         return s_rsa_key_valid_crypt(key, padding, hash_idx);
-      default:
-         return CRYPT_ERROR;
+      case LTC_RSA_VERIFY:
+      case LTC_PKCS1_SIGN:
+      case LTC_PKCS1_VERIFY:
+         return s_rsa_key_valid_sign(check);
    }
+   return CRYPT_ERROR;
 }
 
 int rsa_params_equal(const ltc_rsa_parameters *a, const ltc_rsa_parameters *b)

+ 29 - 49
src/pk/rsa/rsa_sign_hash.c

@@ -8,64 +8,48 @@
 */
 
 #ifdef LTC_MRSA
-
 /**
   PKCS #1 pad then sign
-  @param in        The hash to sign
-  @param inlen     The length of the hash to sign (octets)
-  @param out       [out] The signature
-  @param outlen    [in/out] The max size and resulting size of the signature
-  @param padding   Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1)
-  @param prng      An active PRNG state
-  @param prng_idx  The index of the PRNG desired
-  @param hash_idx  The index of the hash desired
-  @param saltlen   The length of the salt desired (octets)
+  @param hash      The hash to sign
+  @param hashlen   The length of the hash to sign (octets)
+  @param sig       [out] The signature
+  @param siglen    [in/out] The max size and resulting size of the signature
+  @param params    The RSA operation parameters
   @param key       The private RSA key to use
   @return CRYPT_OK if successful
 */
-int rsa_sign_hash_ex(const unsigned char *in,       unsigned long  inlen,
-                           unsigned char *out,      unsigned long *outlen,
-                           int            padding,
-                           prng_state    *prng,               int  prng_idx,
-                           int            hash_idx,           int  mgf_hash_idx,
-                           unsigned long  saltlen,
-                     const rsa_key       *key)
+int rsa_sign_hash_v2(const unsigned char   *hash,   unsigned long  hashlen,
+                           unsigned char   *sig,    unsigned long *siglen,
+                     ltc_rsa_op_parameters *params,
+                     const rsa_key         *key)
 {
    unsigned long modulus_bitlen, modulus_bytelen, x, y;
    int           err;
+   ltc_rsa_op_checked op_check = ltc_rsa_op_checked_init(key, params);
 
-   LTC_ARGCHK(in       != NULL);
-   LTC_ARGCHK(out      != NULL);
-   LTC_ARGCHK(outlen   != NULL);
+   LTC_ARGCHK(hash     != NULL);
+   LTC_ARGCHK(sig      != NULL);
+   LTC_ARGCHK(siglen   != NULL);
    LTC_ARGCHK(key      != NULL);
 
-   /* valid padding? */
-   if ((err = rsa_key_valid_op(key, LTC_RSA_SIGN, padding, hash_idx)) != CRYPT_OK) {
+   if ((err = rsa_key_valid_op(LTC_RSA_SIGN, &op_check)) != CRYPT_OK) {
      return err;
    }
 
-   if (padding == LTC_PKCS_1_PSS) {
-     /* valid prng ? */
-     if ((err = prng_is_valid(prng_idx)) != CRYPT_OK) {
-        return err;
-     }
-   }
-
    /* get modulus len in bits */
    modulus_bitlen = ltc_mp_count_bits((key->N));
 
-  /* outlen must be at least the size of the modulus */
+  /* siglen must be at least the size of the modulus */
   modulus_bytelen = ltc_mp_unsigned_bin_size((key->N));
-  if (modulus_bytelen > *outlen) {
-     *outlen = modulus_bytelen;
+  if (modulus_bytelen > *siglen) {
+     *siglen = modulus_bytelen;
      return CRYPT_BUFFER_OVERFLOW;
   }
 
-  if (padding == LTC_PKCS_1_PSS) {
+  if (params->padding == LTC_PKCS_1_PSS) {
     /* PSS pad the key */
-    x = *outlen;
-    if ((err = pkcs_1_pss_encode_mgf1(in, inlen, saltlen, prng, prng_idx,
-                                      hash_idx, mgf_hash_idx, modulus_bitlen, out, &x)) != CRYPT_OK) {
+    x = *siglen;
+    if ((err = ltc_pkcs_1_pss_encode_mgf1(hash, hashlen, params, modulus_bitlen, sig, &x)) != CRYPT_OK) {
        return err;
     }
   } else {
@@ -73,12 +57,8 @@ int rsa_sign_hash_ex(const unsigned char *in,       unsigned long  inlen,
     unsigned char *tmpin = NULL;
     const unsigned char *tmpin_ro;
 
-    if (padding == LTC_PKCS_1_V1_5) {
+    if (params->padding == LTC_PKCS_1_V1_5) {
       ltc_asn1_list digestinfo[2], siginfo[2];
-      /* not all hashes have OIDs... so sad */
-      if (hash_descriptor[hash_idx].OIDlen == 0) {
-         return CRYPT_INVALID_ARG;
-      }
 
     /* construct the SEQUENCE
         SEQUENCE {
@@ -88,10 +68,10 @@ int rsa_sign_hash_ex(const unsigned char *in,       unsigned long  inlen,
          hash    OCTET STRING
         }
      */
-      LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, hash_descriptor[hash_idx].OID, hash_descriptor[hash_idx].OIDlen);
+      LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, hash_descriptor[op_check.hash_alg].OID, hash_descriptor[op_check.hash_alg].OIDlen);
       LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL,              NULL,                          0);
       LTC_SET_ASN1(siginfo,    0, LTC_ASN1_SEQUENCE,          digestinfo,                    2);
-      LTC_SET_ASN1(siginfo,    1, LTC_ASN1_OCTET_STRING,      in,                            inlen);
+      LTC_SET_ASN1(siginfo,    1, LTC_ASN1_OCTET_STRING,      hash,                            hashlen);
 
       /* allocate memory for the encoding */
       y = ltc_mp_unsigned_bin_size(key->N);
@@ -107,14 +87,14 @@ int rsa_sign_hash_ex(const unsigned char *in,       unsigned long  inlen,
       tmpin_ro = tmpin;
     } else {
       /* set the pointer and data-length to the input values */
-      tmpin_ro = in;
-      y = inlen;
+      tmpin_ro = hash;
+      y = hashlen;
     }
 
-    x = *outlen;
-    err = pkcs_1_v1_5_encode(tmpin_ro, y, LTC_PKCS_1_EMSA, modulus_bitlen, NULL, 0, out, &x);
+    x = *siglen;
+    err = ltc_pkcs_1_v1_5_encode(tmpin_ro, y, LTC_PKCS_1_EMSA, modulus_bitlen, NULL, 0, sig, &x);
 
-    if (padding == LTC_PKCS_1_V1_5) {
+    if (params->padding == LTC_PKCS_1_V1_5) {
       XFREE(tmpin);
     }
 
@@ -124,7 +104,7 @@ int rsa_sign_hash_ex(const unsigned char *in,       unsigned long  inlen,
   }
 
   /* RSA encode it */
-  return ltc_mp.rsa_me(out, x, out, outlen, PK_PRIVATE, key);
+  return ltc_mp.rsa_me(sig, x, sig, siglen, PK_PRIVATE, key);
 }
 
 #endif /* LTC_MRSA */

+ 19 - 31
src/pk/rsa/rsa_verify_hash.c

@@ -1,5 +1,6 @@
 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
 /* SPDX-License-Identifier: Unlicense */
+#define LTC_DEPRECATED(x)
 #include "tomcrypt_private.h"
 
 /**
@@ -8,30 +9,27 @@
 */
 
 #ifdef LTC_MRSA
-
 /**
   PKCS #1 de-sign then v1.5 or PSS depad
   @param sig              The signature data
   @param siglen           The length of the signature data (octets)
   @param hash             The hash of the message that was signed
   @param hashlen          The length of the hash of the message that was signed (octets)
-  @param padding          Type of padding (LTC_PKCS_1_PSS, LTC_PKCS_1_V1_5 or LTC_PKCS_1_V1_5_NA1)
-  @param hash_idx         The index of the desired hash
-  @param saltlen          The length of the salt used during signature
+  @param params    The RSA operation parameters
   @param stat             [out] The result of the signature comparison, 1==valid, 0==invalid
   @param key              The public RSA key corresponding to the key that performed the signature
   @return CRYPT_OK on success (even if the signature is invalid)
 */
-int rsa_verify_hash_ex(const unsigned char *sig,            unsigned long  siglen,
-                       const unsigned char *hash,           unsigned long  hashlen,
-                             int            padding,
-                             int            hash_idx,                 int  mgf_hash_idx,
-                             unsigned long  saltlen,
-                             int           *stat,     const rsa_key       *key)
+int rsa_verify_hash_v2(const unsigned char   *sig,    unsigned long  siglen,
+                       const unsigned char   *hash,   unsigned long  hashlen,
+                       ltc_rsa_op_parameters *params,
+                             int             *stat,
+                       const rsa_key         *key)
 {
   unsigned long modulus_bitlen, modulus_bytelen, x;
   int           err;
   unsigned char *tmpbuf;
+  ltc_rsa_op_checked op_check = ltc_rsa_op_checked_init(key, params);
 
   LTC_ARGCHK(hash  != NULL);
   LTC_ARGCHK(sig   != NULL);
@@ -41,8 +39,7 @@ int rsa_verify_hash_ex(const unsigned char *sig,            unsigned long  sigle
   /* default to invalid */
   *stat = 0;
 
-  /* valid padding? */
-  if ((err = rsa_key_valid_op(key, LTC_RSA_SIGN, padding, hash_idx)) != CRYPT_OK) {
+  if ((err = rsa_key_valid_op(LTC_RSA_VERIFY, &op_check)) != CRYPT_OK) {
     return err;
   }
 
@@ -74,14 +71,14 @@ int rsa_verify_hash_ex(const unsigned char *sig,            unsigned long  sigle
      return CRYPT_INVALID_PACKET;
   }
 
-  if (padding == LTC_PKCS_1_PSS) {
+  if (params->padding == LTC_PKCS_1_PSS) {
     /* PSS decode and verify it */
 
     if(modulus_bitlen%8 == 1){
-      err = pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf+1, x-1, saltlen, hash_idx, mgf_hash_idx, modulus_bitlen, stat);
+      err = ltc_pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf+1, x-1, params, modulus_bitlen, stat);
     }
     else{
-      err = pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf, x, saltlen, hash_idx, mgf_hash_idx, modulus_bitlen, stat);
+      err = ltc_pkcs_1_pss_decode_mgf1(hash, hashlen, tmpbuf, x, params, modulus_bitlen, stat);
     }
 
   } else {
@@ -98,21 +95,15 @@ int rsa_verify_hash_ex(const unsigned char *sig,            unsigned long  sigle
       goto bail_2;
     }
 
-    if ((err = pkcs_1_v1_5_decode(tmpbuf, x, LTC_PKCS_1_EMSA, modulus_bitlen, out, &outlen, &decoded)) != CRYPT_OK) {
+    if ((err = ltc_pkcs_1_v1_5_decode(tmpbuf, x, LTC_PKCS_1_EMSA, modulus_bitlen, out, &outlen, &decoded)) != CRYPT_OK) {
       XFREE(out);
       goto bail_2;
     }
 
-    if (padding == LTC_PKCS_1_V1_5) {
+    if (params->padding == LTC_PKCS_1_V1_5) {
       unsigned long loid[16], reallen;
       ltc_asn1_list digestinfo[2], siginfo[2];
 
-      /* not all hashes have OIDs... so sad */
-      if (hash_descriptor[hash_idx].OIDlen == 0) {
-         err = CRYPT_INVALID_ARG;
-         goto bail_2;
-      }
-
       /* now we must decode out[0...outlen-1] using ASN.1, test the OID and then test the hash */
       /* construct the SEQUENCE
         SEQUENCE {
@@ -124,16 +115,13 @@ int rsa_verify_hash_ex(const unsigned char *sig,            unsigned long  sigle
      */
       LTC_SET_ASN1(digestinfo, 0, LTC_ASN1_OBJECT_IDENTIFIER, loid, LTC_ARRAY_SIZE(loid));
       LTC_SET_ASN1(digestinfo, 1, LTC_ASN1_NULL,              NULL,                          0);
+      digestinfo[1].optional = 1;
       LTC_SET_ASN1(siginfo,    0, LTC_ASN1_SEQUENCE,          digestinfo,                    2);
       LTC_SET_ASN1(siginfo,    1, LTC_ASN1_OCTET_STRING,      tmpbuf,                        siglen);
 
       if (der_decode_sequence_strict(out, outlen, siginfo, 2) != CRYPT_OK) {
-         /* fallback to Legacy:missing NULL */
-         LTC_SET_ASN1(siginfo, 0, LTC_ASN1_SEQUENCE,          digestinfo,                    1);
-         if ((err = der_decode_sequence_strict(out, outlen, siginfo, 2)) != CRYPT_OK) {
-           XFREE(out);
-           goto bail_2;
-         }
+         XFREE(out);
+         goto bail_2;
       }
 
       if ((err = der_length_sequence(siginfo, 2, &reallen)) != CRYPT_OK) {
@@ -143,8 +131,8 @@ int rsa_verify_hash_ex(const unsigned char *sig,            unsigned long  sigle
 
       /* test OID */
       if ((reallen == outlen) &&
-          (digestinfo[0].size == hash_descriptor[hash_idx].OIDlen) &&
-        (XMEMCMP(digestinfo[0].data, hash_descriptor[hash_idx].OID, sizeof(unsigned long) * hash_descriptor[hash_idx].OIDlen) == 0) &&
+          (digestinfo[0].size == hash_descriptor[op_check.hash_alg].OIDlen) &&
+        (XMEMCMP(digestinfo[0].data, hash_descriptor[op_check.hash_alg].OID, sizeof(unsigned long) * hash_descriptor[op_check.hash_alg].OIDlen) == 0) &&
           (siginfo[1].size == hashlen) &&
         (XMEMCMP(siginfo[1].data, hash, hashlen) == 0)) {
          *stat = 1;

+ 44 - 0
tests/deprecated_test.c

@@ -1,5 +1,6 @@
 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
 /* SPDX-License-Identifier: Unlicense */
+#ifndef LTC_NO_DEPRECATED_APIS
 #define LTC_DEPRECATED(x)
 #include  <tomcrypt_test.h>
 
@@ -39,10 +40,53 @@ static void s_ecc_test(void)
 }
 #endif
 
+#ifdef LTC_MRSA
+extern const unsigned char ltc_rsa_private_test_key[];
+extern const unsigned long ltc_rsa_private_test_key_sz;
+extern const unsigned char ltc_openssl_public_rsa[];
+extern const unsigned long ltc_openssl_public_rsa_sz;
+static void s_rsa_test(void)
+{
+   rsa_key key, pubkey;
+   int stat;
+   const unsigned char tv[] = "test";
+   unsigned char buf0[1024], buf1[1024];
+   unsigned long buf0len, buf1len;
+
+   /* We need an MPI provider for RSA */
+   if (ltc_mp.name == NULL) return;
+
+   DO(rsa_import(ltc_rsa_private_test_key, ltc_rsa_private_test_key_sz, &key));
+   DO(rsa_import(ltc_openssl_public_rsa, ltc_openssl_public_rsa_sz, &pubkey));
+
+   buf0len = sizeof(buf0);
+   DO(rsa_sign_hash_ex(tv, 4, buf0, &buf0len, LTC_PKCS_1_PSS, &yarrow_prng, find_prng("yarrow"), find_hash("sha1"), 8, &key));
+   buf1len = sizeof(buf1);
+   DO(rsa_verify_hash_ex(buf0, buf0len, tv, 4, LTC_PKCS_1_PSS, find_hash("sha1"), 8, &stat, &pubkey));
+   ENSURE(stat == 1);
+
+   buf0len = sizeof(buf0);
+   DO(rsa_encrypt_key_ex(tv, 4, buf0, &buf0len, NULL, 0, &yarrow_prng, find_prng("yarrow"), find_hash("sha1"), LTC_PKCS_1_OAEP, &pubkey));
+   buf1len = sizeof(buf1);
+   DO(rsa_decrypt_key_ex(buf0, buf0len, buf1, &buf1len, NULL, 0, find_hash("sha1"), LTC_PKCS_1_OAEP, &stat, &key));
+   ENSURE(stat == 1);
+   COMPARE_TESTVECTOR(buf1, buf1len, tv, 4, "s_rsa_test", 0);
+
+   rsa_free(&pubkey);
+   rsa_free(&key);
+}
+#endif
+#endif /* LTC_NO_DEPRECATED_APIS */
+
 int deprecated_test(void)
 {
+#ifndef LTC_NO_DEPRECATED_APIS
 #ifdef LTC_MECC
    s_ecc_test();
 #endif
+#ifdef LTC_MRSA
+   s_rsa_test();
+#endif
+#endif /* LTC_NO_DEPRECATED_APIS */
    return 0;
 }

+ 11 - 11
tests/pkcs_1_eme_test.c

@@ -11,16 +11,16 @@
 int pkcs_1_eme_test(void)
 {
   struct ltc_prng_descriptor* no_prng_desc = no_prng_desc_get();
-  int prng_idx = register_prng(no_prng_desc);
-  int hash_idx = find_hash("sha1");
-  unsigned int i;
-  unsigned int j;
+  ltc_rsa_op_parameters rsa_params = {
+                                      .wprng = register_prng(no_prng_desc),
+                                      .prng = (void*)no_prng_desc,
+                                      .params.hash_alg = "sha1",
+                                      .padding = LTC_PKCS_1_V1_5
+  };
+  unsigned int i, j;
 
   if (ltc_mp.name == NULL) return CRYPT_NOP;
 
-  DO(prng_is_valid(prng_idx));
-  DO(hash_is_valid(hash_idx));
-
   for (i = 0; i < LTC_ARRAY_SIZE(testcases_eme); ++i) {
     testcase_t* t = &testcases_eme[i];
     rsa_key k, *key = &k;
@@ -41,11 +41,11 @@ int pkcs_1_eme_test(void)
         unsigned char buf[256], obuf[256];
         unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf);
         int stat;
-        prng_descriptor[prng_idx].add_entropy(s->o2, s->o2_l, (void*)no_prng_desc);
-        DOX(rsa_encrypt_key_ex(s->o1, s->o1_l, obuf, &obuflen, NULL, 0, (void*)no_prng_desc, prng_idx, -1, -1, LTC_PKCS_1_V1_5, key), s->name);
+        prng_descriptor[rsa_params.wprng].add_entropy(s->o2, s->o2_l, (void*)rsa_params.prng);
+        DOX(rsa_encrypt_key_v2(s->o1, s->o1_l, obuf, &obuflen, &rsa_params, key), s->name);
         COMPARE_TESTVECTOR(obuf, obuflen, s->o3, s->o3_l,s->name, j);
-        DOX(rsa_decrypt_key_ex(obuf, obuflen, buf, &buflen, NULL, 0, -1, -1, LTC_PKCS_1_V1_5, &stat, key), s->name);
-        DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name);
+        DOX(rsa_decrypt_key_v2(obuf, obuflen, buf, &buflen, &rsa_params, &stat, key), s->name);
+        ENSUREX(stat == 1, s->name);
     } /* for */
 
     ltc_mp_deinit_multi(key->d,  key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, LTC_NULL);

+ 8 - 5
tests/pkcs_1_emsa_test.c

@@ -10,9 +10,12 @@
 
 int pkcs_1_emsa_test(void)
 {
+  ltc_rsa_op_parameters rsa_params = {
+                                      .params.hash_alg = "sha1",
+                                      .padding = LTC_PKCS_1_V1_5
+  };
   int hash_idx = find_hash("sha1");
-  unsigned int i;
-  unsigned int j;
+  unsigned int i, j;
 
   if (ltc_mp.name == NULL) return CRYPT_NOP;
 
@@ -39,10 +42,10 @@ int pkcs_1_emsa_test(void)
         unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf);
         int stat;
         DOX(hash_memory(hash_idx, s->o1, s->o1_l, buf, &buflen), s->name);
-        DOX(rsa_sign_hash_ex(buf, buflen, obuf, &obuflen, LTC_PKCS_1_V1_5, NULL, -1, hash_idx, -1, 0, key), s->name);
+        DOX(rsa_sign_hash_v2(buf, buflen, obuf, &obuflen, &rsa_params, key), s->name);
         COMPARE_TESTVECTOR(obuf, obuflen, s->o2, s->o2_l,s->name, j);
-        DOX(rsa_verify_hash_ex(obuf, obuflen, buf, buflen, LTC_PKCS_1_V1_5, hash_idx, -1, 0, &stat, key), s->name);
-        DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name);
+        DOX(rsa_verify_hash_v2(obuf, obuflen, buf, buflen, &rsa_params, &stat, key), s->name);
+        ENSUREX(stat == 1, s->name);
     } /* for */
 
     ltc_mp_deinit_multi(key->d,  key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, LTC_NULL);

+ 12 - 10
tests/pkcs_1_oaep_test.c

@@ -11,15 +11,17 @@
 int pkcs_1_oaep_test(void)
 {
   struct ltc_prng_descriptor* no_prng_desc = no_prng_desc_get();
-  int prng_idx = register_prng(no_prng_desc);
-  int hash_idx = find_hash("sha1");
-  unsigned int i;
-  unsigned int j;
+  ltc_rsa_op_parameters rsa_params = {
+                                      .wprng = register_prng(no_prng_desc),
+                                      .prng = (void*)no_prng_desc,
+                                      .params.hash_alg = "sha1",
+                                      .params.mgf1_hash_alg = "sha1",
+                                      .padding = LTC_PKCS_1_OAEP
+  };
+  unsigned int i, j;
 
   if (ltc_mp.name == NULL) return CRYPT_NOP;
 
-  DO(prng_is_valid(prng_idx));
-  DO(hash_is_valid(hash_idx));
 
   for (i = 0; i < LTC_ARRAY_SIZE(testcases_oaep); ++i) {
     testcase_t* t = &testcases_oaep[i];
@@ -41,11 +43,11 @@ int pkcs_1_oaep_test(void)
         unsigned char buf[256], obuf[256];
         unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf);
         int stat;
-        prng_descriptor[prng_idx].add_entropy(s->o2, s->o2_l, (void*)no_prng_desc);
-        DOX(rsa_encrypt_key(s->o1, s->o1_l, obuf, &obuflen, NULL, 0, (void*)no_prng_desc, prng_idx, hash_idx, key), s->name);
+        prng_descriptor[rsa_params.wprng].add_entropy(s->o2, s->o2_l, rsa_params.prng);
+        DOX(rsa_encrypt_key_v2(s->o1, s->o1_l, obuf, &obuflen, &rsa_params, key), s->name);
         COMPARE_TESTVECTOR(obuf, obuflen, s->o3, s->o3_l,s->name, j);
-        DOX(rsa_decrypt_key(obuf, obuflen, buf, &buflen, NULL, 0, hash_idx, &stat, key), s->name);
-        DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name);
+        DOX(rsa_decrypt_key_v2(obuf, obuflen, buf, &buflen, &rsa_params, &stat, key), s->name);
+        ENSUREX(stat == 1, s->name);
     } /* for */
 
     ltc_mp_deinit_multi(key->d,  key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, LTC_NULL);

+ 13 - 8
tests/pkcs_1_pss_test.c

@@ -11,14 +11,18 @@
 int pkcs_1_pss_test(void)
 {
   struct ltc_prng_descriptor* no_prng_desc = no_prng_desc_get();
-  int prng_idx = register_prng(no_prng_desc);
+  ltc_rsa_op_parameters rsa_params = {
+                                      .wprng = register_prng(no_prng_desc),
+                                      .prng = (void*)no_prng_desc,
+                                      .params.hash_alg = "sha1",
+                                      .params.mgf1_hash_alg = "sha1",
+                                      .padding = LTC_PKCS_1_PSS
+  };
   int hash_idx = find_hash("sha1");
-  unsigned int i;
-  unsigned int j;
+  unsigned int i, j;
 
   if (ltc_mp.name == NULL) return CRYPT_NOP;
 
-  DO(prng_is_valid(prng_idx));
   DO(hash_is_valid(hash_idx));
 
   for (i = 0; i < LTC_ARRAY_SIZE(testcases_pss); ++i) {
@@ -41,12 +45,13 @@ int pkcs_1_pss_test(void)
         unsigned char buf[20], obuf[256];
         unsigned long buflen = sizeof(buf), obuflen = sizeof(obuf);
         int stat;
-        prng_descriptor[prng_idx].add_entropy(s->o2, s->o2_l, (void*)no_prng_desc);
+        prng_descriptor[rsa_params.wprng].add_entropy(s->o2, s->o2_l, rsa_params.prng);
         DOX(hash_memory(hash_idx, s->o1, s->o1_l, buf, &buflen), s->name);
-        DOX(rsa_sign_hash(buf, buflen, obuf, &obuflen, (void*)no_prng_desc, prng_idx, hash_idx, s->o2_l, key), s->name);
+        rsa_params.params.saltlen = s->o2_l;
+        DOX(rsa_sign_hash_v2(buf, buflen, obuf, &obuflen, &rsa_params, key), s->name);
         COMPARE_TESTVECTOR(obuf, obuflen, s->o3, s->o3_l,s->name, j);
-        DOX(rsa_verify_hash(obuf, obuflen, buf, buflen, hash_idx, s->o2_l, &stat, key), s->name);
-        DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, s->name);
+        DOX(rsa_verify_hash_v2(obuf, obuflen, buf, buflen, &rsa_params, &stat, key), s->name);
+        ENSUREX(stat == 1, s->name);
     } /* for */
 
     ltc_mp_deinit_multi(key->d,  key->e, key->N, key->dQ, key->dP, key->qP, key->p, key->q, LTC_NULL);

+ 25 - 34
tests/pkcs_1_test.c

@@ -13,18 +13,15 @@
 int pkcs_1_test(void)
 {
    unsigned char buf[3][128];
-   int res1, res2, res3, prng_idx, hash_idx;
-   unsigned long x, y, l1, l2, l3, i1, lparamlen, saltlen, modlen;
+   int res1, res2, res3;
+   unsigned long x, y, l1, l2, l3, i1, modlen;
    static const unsigned char lparam[] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
-
-   /* get hash/prng  */
-   hash_idx = find_hash("sha1");
-   prng_idx = find_prng("yarrow");
-
-   if (hash_idx == -1 || prng_idx == -1) {
-      fprintf(stderr, "pkcs_1 tests require sha1/yarrow");
-      return 1;
-   }
+   ltc_rsa_op_parameters rsa_params = {
+                                       .wprng = find_prng("yarrow"),
+                                       .prng = &yarrow_prng,
+                                       .params.hash_alg = "sha1",
+                                       .params.mgf1_hash_alg = "sha1",
+   };
 
    srand(LTC_TEST_RAND_SEED);
    /* do many tests */
@@ -36,49 +33,43 @@ int pkcs_1_test(void)
       for (y = 0; y < l3; y++) buf[0][y] = rand() & 255;
 
       /* pick a random lparam len [0..16] */
-      lparamlen = abs(rand()) % 17;
+      rsa_params.u.crypt.lparamlen = abs(rand()) % 17;
 
       /* pick a random saltlen 0..16 */
-      saltlen   = abs(rand()) % 17;
+      rsa_params.params.saltlen = abs(rand()) % 17;
 
       /* PKCS #1 v2.0 supports modlens not multiple of 8 */
       modlen = 800 + (abs(rand()) % 224);
 
       /* encode it */
       l1 = sizeof(buf[1]);
-      DO(pkcs_1_oaep_encode(buf[0], l3, lparam, lparamlen, modlen, &yarrow_prng, prng_idx, hash_idx, -1, buf[1], &l1));
+      rsa_params.padding = LTC_PKCS_1_OAEP;
+      rsa_params.u.crypt.lparam = lparam;
+      DO(ltc_pkcs_1_oaep_encode(buf[0], l3, &rsa_params, modlen, buf[1], &l1));
 
       /* decode it */
       l2 = sizeof(buf[2]);
-      DO(pkcs_1_oaep_decode(buf[1], l1, lparam, lparamlen, modlen, hash_idx, -1, buf[2], &l2, &res1));
-
-      if (res1 != 1 || l2 != l3 || memcmp(buf[2], buf[0], l3) != 0) {
-         fprintf(stderr, "Outsize == %lu, should have been %lu, res1 = %d, lparamlen = %lu, msg contents follow.\n", l2, l3, res1, lparamlen);
-         fprintf(stderr, "ORIGINAL:\n");
-         for (x = 0; x < l3; x++) {
-             fprintf(stderr, "%02x ", buf[0][x]);
-         }
-         fprintf(stderr, "\nRESULT:\n");
-         for (x = 0; x < l2; x++) {
-             fprintf(stderr, "%02x ", buf[2][x]);
-         }
-         fprintf(stderr, "\n\n");
-         return 1;
-      }
+      DO(ltc_pkcs_1_oaep_decode(buf[1], l1, &rsa_params, modlen, buf[2], &l2, &res1));
+
+      ENSURE(res1 == 1);
+      COMPARE_TESTVECTOR(buf[0], l3, buf[2], l2, "PKCS#1 OAEP", x);
 
       /* test PSS */
       l1 = sizeof(buf[1]);
-      DO(pkcs_1_pss_encode(buf[0], l3, saltlen, &yarrow_prng, prng_idx, hash_idx, modlen, buf[1], &l1));
-      DO(pkcs_1_pss_decode(buf[0], l3, buf[1], l1, saltlen, hash_idx, modlen, &res1));
+      rsa_params.padding = LTC_PKCS_1_PSS;
+      rsa_params.u.crypt.lparam = NULL;
+      rsa_params.u.crypt.lparamlen = 0;
+      DO(ltc_pkcs_1_pss_encode_mgf1(buf[0], l3, &rsa_params, modlen, buf[1], &l1));
+      DO(ltc_pkcs_1_pss_decode_mgf1(buf[0], l3, buf[1], l1, &rsa_params, modlen, &res1));
 
       buf[0][i1 = abs(rand()) % l3] ^= 1;
-      DO(pkcs_1_pss_decode(buf[0], l3, buf[1], l1, saltlen, hash_idx, modlen, &res2));
+      DO(ltc_pkcs_1_pss_decode_mgf1(buf[0], l3, buf[1], l1, &rsa_params, modlen, &res2));
 
       buf[0][i1] ^= 1;
       buf[1][abs(rand()) % (l1 - 1)] ^= 1;
-      pkcs_1_pss_decode(buf[0], l3, buf[1], l1, saltlen, hash_idx, modlen, &res3);
+      ltc_pkcs_1_pss_decode_mgf1(buf[0], l3, buf[1], l1, &rsa_params, modlen, &res3);
       if (!(res1 == 1 && res2 == 0 && res3 == 0)) {
-         fprintf(stderr, "PSS failed: %d, %d, %d, %lu, %lu\n", res1, res2, res3, l3, saltlen);
+         fprintf(stderr, "PSS failed: %d, %d, %d, %lu, %lu\n", res1, res2, res3, l3, rsa_params.params.saltlen);
          return 1;
       }
    }

+ 137 - 48
tests/rsa_test.c

@@ -134,7 +134,7 @@ static const char *hex_key[] = {
      "DCCC27C8E4DC6248D59BAFF5AB60F621FD53E2B75D09C91AA104A9FC612C5D04583A5A39F14A215667FDCC20A38F78185A793D2E8E7E860AE6A833C104174A9F" };
 
 /*** openssl public RSA key in DER format */
-static const unsigned char openssl_public_rsa[] = {
+const unsigned char ltc_openssl_public_rsa[] = {
    0x30, 0x81, 0x9f, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
    0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81, 0x00, 0xcf, 0x9a, 0xde,
    0x64, 0x8a, 0xda, 0xc8, 0x33, 0x20, 0xa9, 0xd7, 0x83, 0x31, 0x19, 0x54, 0xb2, 0x9a, 0x85, 0xa7,
@@ -146,6 +146,7 @@ static const unsigned char openssl_public_rsa[] = {
    0xe2, 0x76, 0x0c, 0xc9, 0x63, 0x6c, 0x49, 0x58, 0x93, 0xed, 0xcc, 0xaa, 0xdc, 0x25, 0x3b, 0x0a,
    0x60, 0x3f, 0x8b, 0x54, 0x3a, 0xc3, 0x4d, 0x31, 0xe7, 0x94, 0xa4, 0x44, 0xfd, 0x02, 0x03, 0x01,
    0x00, 0x01,  };
+const unsigned long ltc_openssl_public_rsa_sz = sizeof(ltc_openssl_public_rsa);
 
 /* same key but with extra headers stripped */
 static const unsigned char openssl_public_rsa_stripped[] = {
@@ -184,22 +185,24 @@ static int rsa_compat_test(void)
    int stat, i;
    unsigned char buf[1024], key_parts[8][128];
    unsigned long len, key_lens[8];
+   ltc_rsa_op_parameters rsa_params = {0};
 
    /* try reading the key */
    DO(rsa_import(ltc_rsa_private_test_key, sizeof(ltc_rsa_private_test_key), &key));
-   DO(rsa_import(openssl_public_rsa, sizeof(openssl_public_rsa), &pubkey));
+   DO(rsa_import(ltc_openssl_public_rsa, sizeof(ltc_openssl_public_rsa), &pubkey));
 
    /* sign-verify a message with PKCS #1 v1.5 no ASN.1 */
    len = sizeof(buf);
-   DO(rsa_sign_hash_ex((unsigned char*)"test", 4, buf, &len, LTC_PKCS_1_V1_5_NA1, NULL, 0, 0, 0, 0, &key));
+   rsa_params.padding = LTC_PKCS_1_V1_5_NA1;
+   DO(rsa_sign_hash_v2((unsigned char*)"test", 4, buf, &len, &rsa_params, &key));
    if (len != sizeof(openssl_rsautl_pkcs) || memcmp(buf, openssl_rsautl_pkcs, len)) {
-      fprintf(stderr, "RSA rsa_sign_hash_ex + LTC_PKCS_1_V1_5_NA1 failed\n");
+      fprintf(stderr, "RSA rsa_sign_hash_v2 + LTC_PKCS_1_V1_5_NA1 failed\n");
       return 1;
    }
    stat = 0;
-   DO(rsa_verify_hash_ex(openssl_rsautl_pkcs, sizeof(openssl_rsautl_pkcs), (unsigned char*)"test", 4, LTC_PKCS_1_V1_5_NA1, 0, 0, 0, &stat, &pubkey));
+   DO(rsa_verify_hash_v2(openssl_rsautl_pkcs, sizeof(openssl_rsautl_pkcs), (unsigned char*)"test", 4, &rsa_params, &stat, &pubkey));
    if (stat != 1) {
-      fprintf(stderr, "RSA rsa_verify_hash_ex + LTC_PKCS_1_V1_5_NA1 failed\n");
+      fprintf(stderr, "RSA rsa_verify_hash_v2 + LTC_PKCS_1_V1_5_NA1 failed\n");
       return 1;
    }
    rsa_free(&pubkey);
@@ -222,7 +225,7 @@ static int rsa_compat_test(void)
    rsa_free(&key);
 
    /* try reading the public key */
-   DO(rsa_import(openssl_public_rsa, sizeof(openssl_public_rsa), &key));
+   DO(rsa_import(ltc_openssl_public_rsa, sizeof(ltc_openssl_public_rsa), &key));
    len = sizeof(buf);
    DO(rsa_export(buf, &len, PK_PUBLIC, &key));
    COMPARE_TESTVECTOR(buf, len, openssl_public_rsa_stripped, sizeof(openssl_public_rsa_stripped), "RSA public export (from OpenSSL)", 0);
@@ -257,10 +260,10 @@ static int rsa_compat_test(void)
    rsa_free(&key);
 
    /* try export in SubjectPublicKeyInfo format of the public key */
-   DO(rsa_import(openssl_public_rsa, sizeof(openssl_public_rsa), &key));
+   DO(rsa_import(ltc_openssl_public_rsa, sizeof(ltc_openssl_public_rsa), &key));
    len = sizeof(buf);
    DO(rsa_export(buf, &len, PK_PUBLIC | PK_STD, &key));
-   COMPARE_TESTVECTOR(buf, len, openssl_public_rsa, sizeof(openssl_public_rsa),  "RSA public export (X.509)", 0);
+   COMPARE_TESTVECTOR(buf, len, ltc_openssl_public_rsa, sizeof(ltc_openssl_public_rsa),  "RSA public export (X.509)", 0);
    rsa_free(&key);
 
    return 0;
@@ -319,6 +322,7 @@ static int s_rsa_cryptx_issue_69(void)
    unsigned char buf0[512], buf1[512];
    unsigned long l0, l1;
    int stat;
+   ltc_rsa_op_parameters rsa_params = {0};
 
    l0 = sizeof(buf0);
    l1 = sizeof(buf1);
@@ -331,9 +335,10 @@ static int s_rsa_cryptx_issue_69(void)
    l1 = sizeof(buf1);
    DO(radix_to_bin(sig1, 16, buf0, &l0));
    DO(radix_to_bin(hash, 16, buf1, &l1));
-   SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, 0, &stat, &key));
+   rsa_params.padding = LTC_PKCS_1_V1_5;
+   SHOULD_FAIL(rsa_verify_hash_v2(buf0, l0, buf1, l1, &rsa_params, &stat, &key));
    DO(radix_to_bin(sig2, 16, buf0, &l0));
-   SHOULD_FAIL(rsa_verify_hash_ex(buf0, l0, buf1, l1, LTC_PKCS_1_V1_5, 0, 0, 0, &stat, &key));
+   SHOULD_FAIL(rsa_verify_hash_v2(buf0, l0, buf1, l1, &rsa_params, &stat, &key));
    rsa_free(&key);
    return CRYPT_OK;
 }
@@ -448,17 +453,81 @@ static int s_rsa_import_pkcs8(const void *in, unsigned long inlen, void *key)
 #endif
 #endif
 
+static int s_rsa_macros_test(void)
+{
+   rsa_key key, pubkey;
+   int stat;
+   const unsigned char tv[] = "test";
+   unsigned char buf0[1024], buf1[1024];
+   unsigned long buf0len, buf1len;
+
+   DO(rsa_import(ltc_rsa_private_test_key, sizeof(ltc_rsa_private_test_key), &key));
+   DO(rsa_import(ltc_openssl_public_rsa, sizeof(ltc_openssl_public_rsa), &pubkey));
+
+   buf0len = sizeof(buf0);
+   DO(ltc_rsa_sign_hash(tv, 4, buf0, &buf0len, &yarrow_prng, find_prng("yarrow"), find_hash("sha1"), 8, &key));
+   buf1len = sizeof(buf1);
+   DO(ltc_rsa_verify_hash(buf0, buf0len, tv, 4, find_hash("sha1"), 8, &stat, &key));
+   ENSURE(stat == 1);
+
+   buf0len = sizeof(buf0);
+   DO(ltc_rsa_encrypt_key(tv, 4, buf0, &buf0len, NULL, 0, &yarrow_prng, find_prng("yarrow"), find_hash("sha1"), &pubkey));
+   buf1len = sizeof(buf1);
+   DO(ltc_rsa_decrypt_key(buf0, buf0len, buf1, &buf1len, NULL, 0, find_hash("sha1"), &stat, &key));
+   ENSURE(stat == 1);
+   COMPARE_TESTVECTOR(buf1, buf1len, tv, 4, "s_rsa_macros_test", 0);
+
+   rsa_free(&pubkey);
+   rsa_free(&key);
+
+   return CRYPT_OK;
+}
+
+static int s_rsa_pss_test(void)
+{
+   rsa_key key;
+   const unsigned char tv[] = "test";
+   unsigned char buf0[1024];
+   unsigned long buf0len;
+   ltc_rsa_op_parameters rsa_oparams = {
+     .prng = &yarrow_prng,
+     .wprng = find_prng("yarrow"),
+     .padding = LTC_PKCS_1_OAEP,
+     .u.crypt.lparam = tv,
+     .u.crypt.lparamlen = (unsigned long)4,
+     .params.hash_alg = "sha1",
+     .params.mgf1_hash_alg = "sha256",
+     .params.saltlen = 7,
+   };
+
+   DO(rsa_import(ltc_rsa_private_test_key, sizeof(ltc_rsa_private_test_key), &key));
+
+   buf0len = sizeof(buf0);
+   DO(rsa_encrypt_key_v2(tv, 4, buf0, &buf0len, &rsa_oparams, &key));
+   DO(rsa_encrypt_key_v2(tv, 4, buf0, &buf0len, &rsa_oparams, &key));
+   key.params = rsa_oparams.params;
+   DO(rsa_encrypt_key_v2(tv, 4, buf0, &buf0len, &rsa_oparams, &key));
+   /* If the key is a PSS key, we must do a PSS operation */
+   rsa_oparams.padding = LTC_PKCS_1_V1_5;
+   SHOULD_FAIL(rsa_encrypt_key_v2(tv, 4, buf0, &buf0len, &rsa_oparams, &key));
+
+   rsa_free(&key);
+
+   return CRYPT_OK;
+}
+
 int rsa_test(void)
 {
    unsigned char in[1024], out[1024], tmp[3072];
    rsa_key       key, privKey, pubKey;
-   int           hash_idx, prng_idx, stat, stat2, i, mgf_hash, label_hash;
-   unsigned long rsa_msgsize, len, len2, len3, cnt, cnt2, max_msgsize;
+   int           prng_idx, stat, stat2, i, mgf_hash;
+   unsigned long rsa_msgsize, len, len2, len3, cnt, cnt2, max_msgsize, label_hash;
    static unsigned char lparam[] = { 0x01, 0x02, 0x03, 0x04 };
    void* dP;
    unsigned char* p;
    unsigned char* p2;
    unsigned char* p3;
+   ltc_rsa_op_parameters rsa_params = {0};
 
    if (ltc_mp.name == NULL) return CRYPT_NOP;
 
@@ -466,12 +535,15 @@ int rsa_test(void)
       return 1;
    }
 
-   hash_idx = find_hash("sha1");
-   prng_idx = find_prng("yarrow");
-   if (hash_idx == -1 || prng_idx == -1) {
+   rsa_params.params.hash_alg = "sha1";
+   rsa_params.wprng = find_prng("yarrow");
+   mgf_hash = find_hash(rsa_params.params.hash_alg);
+   if (mgf_hash == -1 || rsa_params.wprng == -1) {
       fprintf(stderr, "rsa_test requires LTC_SHA1 and yarrow");
       return 1;
    }
+   rsa_params.prng = &yarrow_prng;
+   prng_idx = rsa_params.wprng;
 
 #ifdef LTC_TEST_READDIR
    DO(test_process_dir("tests/rsa", &key, s_rsa_import_x509, NULL, (dir_cleanup_cb)rsa_free, "rsa_test"));
@@ -481,6 +553,8 @@ int rsa_test(void)
    DO(test_process_dir("tests/rsa-pkcs8", &key, s_rsa_import_pkcs8, NULL, (dir_cleanup_cb)rsa_free, "rsa_pkcs8_test"));
 #endif
 
+   DO(s_rsa_pss_test());
+   DO(s_rsa_macros_test());
    DO(s_rsa_cryptx_issue_69());
    DO(s_rsa_issue_301(prng_idx));
    DO(s_rsa_public_ubin_e(prng_idx));
@@ -512,13 +586,13 @@ print_hex("q", tmp, len);
    /* make a random key/msg */
    ENSURE(yarrow_read(in, 117, &yarrow_prng) == 117);
 
+   rsa_params.padding = LTC_PKCS_1_OAEP;
 #ifdef LTC_TEST_EXT
    for (mgf_hash = 0; mgf_hash < TAB_SIZE; ++mgf_hash) {
       if (hash_is_valid(mgf_hash) != CRYPT_OK)
          continue;
 #else
    {
-      mgf_hash = hash_idx;
 #endif
       for (label_hash = 0; label_hash < TAB_SIZE; ++label_hash) {
          if (hash_is_valid(label_hash) != CRYPT_OK)
@@ -526,6 +600,8 @@ print_hex("q", tmp, len);
          if (2 * hash_descriptor[label_hash].hashsize > 126)
             continue;
          max_msgsize = 128 - (2 * hash_descriptor[label_hash].hashsize) - 2;
+         rsa_params.params.hash_alg = hash_descriptor[label_hash].name;
+         rsa_params.params.mgf1_hash_alg = hash_descriptor[mgf_hash].name;
 
 #if defined(LTC_TEST_DBG) && LTC_TEST_DBG > 1
          fprintf(stderr, "Test MGF(%s), Labelhash(%s) with max_msgsize %lu\n", hash_descriptor[mgf_hash].name, hash_descriptor[label_hash].name, max_msgsize);
@@ -536,59 +612,66 @@ print_hex("q", tmp, len);
             len  = sizeof(out);
             len2 = rsa_msgsize;
 
-            DO(rsa_encrypt_key_ex(in, rsa_msgsize, out, &len, NULL, 0, &yarrow_prng, prng_idx, mgf_hash, label_hash, LTC_PKCS_1_OAEP, &key));
+            DO(rsa_encrypt_key_v2(in, rsa_msgsize, out, &len, &rsa_params, &key));
             /* change a byte */
             out[8] ^= 1;
-            SHOULD_FAIL(rsa_decrypt_key_ex(out, len, tmp, &len2, NULL, 0, mgf_hash, label_hash, LTC_PKCS_1_OAEP, &stat2, &key));
+            SHOULD_FAIL(rsa_decrypt_key_v2(out, len, tmp, &len2, &rsa_params, &stat2, &key));
             /* change a byte back */
             out[8] ^= 1;
             ENSURE(len2 == rsa_msgsize);
 
             len2 = rsa_msgsize;
-            DO(rsa_decrypt_key_ex(out, len, tmp, &len2, NULL, 0, mgf_hash, label_hash, LTC_PKCS_1_OAEP, &stat, &key));
+            DO(rsa_decrypt_key_v2(out, len, tmp, &len2, &rsa_params, &stat, &key));
             ENSUREX(stat == 1 && stat2 == 0, "rsa_decrypt_key (without lparam)");
             COMPARE_TESTVECTOR(tmp, len2, in, rsa_msgsize,  "rsa_decrypt_key (without lparam)", cnt << 8 | rsa_msgsize);
          }
 
          /* encrypt the key (with lparam) */
+         rsa_params.u.crypt.lparam = lparam;
+         rsa_params.u.crypt.lparamlen = sizeof(lparam);
          for (rsa_msgsize = 0; rsa_msgsize <= max_msgsize; rsa_msgsize++) {
             len  = sizeof(out);
             len2 = rsa_msgsize;
-            DO(rsa_encrypt_key_ex(rsa_msgsize ? in : NULL, rsa_msgsize, out, &len, lparam, sizeof(lparam), &yarrow_prng, prng_idx, mgf_hash, label_hash, LTC_PKCS_1_OAEP, &key));
+            DO(rsa_encrypt_key_v2(rsa_msgsize ? in : NULL, rsa_msgsize, out, &len, &rsa_params, &key));
             /* change a byte */
             out[8] ^= 1;
-            SHOULD_FAIL(rsa_decrypt_key_ex(out, len, tmp, &len2, lparam, sizeof(lparam), mgf_hash, label_hash, LTC_PKCS_1_OAEP, &stat2, &key));
+            SHOULD_FAIL(rsa_decrypt_key_v2(out, len, tmp, &len2, &rsa_params, &stat2, &key));
             ENSURE(len2 == rsa_msgsize);
 
             /* change a byte back */
             out[8] ^= 1;
 
             len2 = rsa_msgsize;
-            DO(rsa_decrypt_key_ex(out, len, tmp, &len2, lparam, sizeof(lparam), mgf_hash, label_hash, LTC_PKCS_1_OAEP, &stat, &key));
+            DO(rsa_decrypt_key_v2(out, len, tmp, &len2, &rsa_params, &stat, &key));
             ENSURE(stat == 1 && stat2 == 0);
             COMPARE_TESTVECTOR(tmp, len2, in, rsa_msgsize,  "rsa_decrypt_key (with lparam)", rsa_msgsize);
          }
+         rsa_params.u.crypt.lparam = NULL;
+         rsa_params.u.crypt.lparamlen = 0;
 
       }
    }
-
+   rsa_params.params.hash_alg = "sha1";
+   rsa_params.params.mgf1_hash_alg = "sha1";
 
 
    /* encrypt the key PKCS #1 v1.5 (payload from 1 to 117 bytes) */
+   rsa_params.padding = LTC_PKCS_1_V1_5;
    for (rsa_msgsize = 0; rsa_msgsize <= 117; rsa_msgsize++) {
       len  = sizeof(out);
       len2 = rsa_msgsize;
-      DO(rsa_encrypt_key_ex(in, rsa_msgsize, out, &len, NULL, 0, &yarrow_prng, prng_idx, 0, -1, LTC_PKCS_1_V1_5, &key));
+      DO(rsa_encrypt_key_v2(in, rsa_msgsize, out, &len, &rsa_params, &key));
 
       len2 = rsa_msgsize;
-      DO(rsa_decrypt_key_ex(out, len, tmp, &len2, NULL, 0, 0, -1, LTC_PKCS_1_V1_5, &stat, &key));
+      DO(rsa_decrypt_key_v2(out, len, tmp, &len2, &rsa_params, &stat, &key));
       ENSURE(stat == 1);
       COMPARE_TESTVECTOR(tmp, len2, in, rsa_msgsize,  "rsa_decrypt_key_ex", rsa_msgsize);
    }
 
    /* sign a message (unsalted, lower cholestorol and Atkins approved) now */
    len = sizeof(out);
-   DO(rsa_sign_hash(in, 20, out, &len, &yarrow_prng, prng_idx, hash_idx, 0, &key));
+   rsa_params.padding = LTC_PKCS_1_PSS;
+   DO(rsa_sign_hash_v2(in, 20, out, &len, &rsa_params, &key));
 
 /* export key and import as both private and public */
    len2 = sizeof(tmp);
@@ -607,20 +690,20 @@ print_hex("q", tmp, len);
    dbg_malloc_stats();
 
    /* verify with original */
-   DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat, &key));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &key));
    /* change a byte */
    in[0] ^= 1;
-   DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat2, &key));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &key));
 
    ENSUREX(stat == 1 && stat2 == 0, "rsa_verify_hash (unsalted, origKey) failed");
 
    /* verify with privKey */
    /* change byte back to original */
    in[0] ^= 1;
-   DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat, &privKey));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &privKey));
    /* change a byte */
    in[0] ^= 1;
-   DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat2, &privKey));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &privKey));
 
    if (!(stat == 1 && stat2 == 0)) {
       fprintf(stderr, "rsa_verify_hash (unsalted, privKey) failed, %d, %d", stat, stat2);
@@ -636,10 +719,10 @@ print_hex("q", tmp, len);
    privKey.dP = NULL;
    /* change byte back to original */
    in[0] ^= 1;
-   DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat, &privKey));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &privKey));
    /* change a byte */
    in[0] ^= 1;
-   DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat2, &privKey));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &privKey));
 
    if (!(stat == 1 && stat2 == 0)) {
       fprintf(stderr, "rsa_verify_hash (unsalted, privKey) failed, %d, %d", stat, stat2);
@@ -653,10 +736,10 @@ print_hex("q", tmp, len);
    /* verify with pubKey */
    /* change byte back to original */
    in[0] ^= 1;
-   DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat, &pubKey));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &pubKey));
    /* change a byte */
    in[0] ^= 1;
-   DO(rsa_verify_hash(out, len, in, 20, hash_idx, 0, &stat2, &pubKey));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &pubKey));
 
    if (!(stat == 1 && stat2 == 0)) {
       fprintf(stderr, "rsa_verify_hash (unsalted, pubkey) failed, %d, %d", stat, stat2);
@@ -668,11 +751,12 @@ print_hex("q", tmp, len);
 
    /* sign a message (salted) now (use privKey to make, pubKey to verify) */
    len = sizeof(out);
-   DO(rsa_sign_hash(in, 20, out, &len, &yarrow_prng, prng_idx, hash_idx, 8, &privKey));
-   DO(rsa_verify_hash(out, len, in, 20, hash_idx, 8, &stat, &pubKey));
+   rsa_params.params.saltlen = 8;
+   DO(rsa_sign_hash_v2(in, 20, out, &len, &rsa_params, &privKey));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &pubKey));
    /* change a byte */
    in[0] ^= 1;
-   DO(rsa_verify_hash(out, len, in, 20, hash_idx, 8, &stat2, &pubKey));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &pubKey));
 
    if (!(stat == 1 && stat2 == 0)) {
       fprintf(stderr, "rsa_verify_hash (salted) failed, %d, %d", stat, stat2);
@@ -681,17 +765,19 @@ print_hex("q", tmp, len);
       rsa_free(&privKey);
       return 1;
    }
+   rsa_params.params.saltlen = 0;
 
    /* sign a message with PKCS #1 v1.5 */
    len = sizeof(out);
-   DO(rsa_sign_hash_ex(in, 20, out, &len, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 0, 8, &privKey));
-   DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 0, 8, &stat, &pubKey));
+   rsa_params.padding = LTC_PKCS_1_V1_5;
+   DO(rsa_sign_hash_v2(in, 20, out, &len, &rsa_params, &privKey));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat, &pubKey));
    /* change a byte */
    in[0] ^= 1;
-   DO(rsa_verify_hash_ex(out, len, in, 20, LTC_PKCS_1_V1_5, hash_idx, 0, 8, &stat2, &pubKey));
+   DO(rsa_verify_hash_v2(out, len, in, 20, &rsa_params, &stat2, &pubKey));
 
    if (!(stat == 1 && stat2 == 0)) {
-      fprintf(stderr, "rsa_verify_hash_ex failed, %d, %d", stat, stat2);
+      fprintf(stderr, "rsa_verify_hash_v2 failed, %d, %d", stat, stat2);
       rsa_free(&key);
       rsa_free(&pubKey);
       rsa_free(&privKey);
@@ -717,14 +803,14 @@ print_hex("q", tmp, len);
    p = in;
    p2 = out;
    p3 = tmp;
-   for (i = 0; i < 9; ++i) {
+   for (i = 0; i < 10; ++i) {
      len = sizeof(in);
      len2 = sizeof(out);
      /* (1) */
-     DO(rsa_sign_hash_ex(p, 20, p2, &len2, LTC_PKCS_1_V1_5, &yarrow_prng, prng_idx, hash_idx, 0, 8, &privKey));
+     DO(rsa_sign_hash_v2(p, 20, p2, &len2, &rsa_params, &privKey));
      /* (2) */
-     DOX(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, 0, -1, &stat, &pubKey), "should succeed");
-     DOX(stat == 1?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should succeed");
+     DOX(rsa_verify_hash_v2(p2, len2, p, 20, &rsa_params, &stat, &pubKey), "should succeed");
+     ENSURE(stat == 1);
      len3 = sizeof(tmp);
      /* (3) */
      DO(ltc_mp.rsa_me(p2, len2, p3, &len3, PK_PUBLIC, &key));
@@ -757,8 +843,11 @@ print_hex("q", tmp, len);
 
      len3 = sizeof(tmp);
      /* (6) */
-     SHOULD_FAIL(rsa_verify_hash_ex(p2, len2, p, 20, LTC_PKCS_1_V1_5, hash_idx, -1, -1, &stat, &pubKey));
-     DOX(stat == 0?CRYPT_OK:CRYPT_FAIL_TESTVECTOR, "should fail");
+     if (i < 8)
+        SHOULD_FAIL(rsa_verify_hash_v2(p2, len2, p, 20, &rsa_params, &stat, &pubKey));
+     else
+        DO(rsa_verify_hash_v2(p2, len2, p, 20, &rsa_params, &stat, &pubKey));
+     ENSURE(stat == 0);
    }
    rsa_free(&key);