tomcrypt/src/pk/rsa/rsa_exptmod.c

182 lines
5.6 KiB
C
Raw Normal View History

2004-05-12 20:42:16 +00:00
/* LibTomCrypt, modular cryptographic library -- Tom St Denis
*
* LibTomCrypt is a library that provides various cryptographic
* algorithms in a highly modular and flexible manner.
*
* The library is free for all purposes without any express
* guarantee it works.
*
2007-07-20 17:48:02 +00:00
* Tom St Denis, tomstdenis@gmail.com, http://libtom.org
*
* Added RSA blinding --nmav
2004-05-12 20:42:16 +00:00
*/
2004-12-30 23:55:53 +00:00
#include "tomcrypt.h"
2004-05-12 20:42:16 +00:00
2004-12-30 23:55:53 +00:00
/**
@file rsa_exptmod.c
2014-01-03 15:16:59 +01:00
RSA PKCS exptmod, Tom St Denis
*/
2004-05-12 20:42:16 +00:00
2007-07-20 17:48:02 +00:00
#ifdef LTC_MRSA
2004-05-12 20:42:16 +00:00
/**
Compute an RSA modular exponentiation
2004-12-30 23:55:53 +00:00
@param in The input data to send into RSA
@param inlen The length of the input (octets)
@param out [out] The destination
2004-12-30 23:55:53 +00:00
@param outlen [in/out] The max size and resulting size of the output
@param which Which exponent to use, e.g. PK_PRIVATE or PK_PUBLIC
@param key The RSA key to use
2004-12-30 23:55:53 +00:00
@return CRYPT_OK if successful
*/
2004-05-31 02:36:47 +00:00
int rsa_exptmod(const unsigned char *in, unsigned long inlen,
unsigned char *out, unsigned long *outlen, int which,
2004-05-12 20:42:16 +00:00
rsa_key *key)
{
void *tmp, *tmpa, *tmpb;
#ifdef LTC_RSA_BLINDING
void *rnd, *rndi /* inverse of rnd */;
#endif
2004-05-12 20:42:16 +00:00
unsigned long x;
int err, no_crt;
2004-05-12 20:42:16 +00:00
2004-12-30 23:55:53 +00:00
LTC_ARGCHK(in != NULL);
LTC_ARGCHK(out != NULL);
LTC_ARGCHK(outlen != NULL);
LTC_ARGCHK(key != NULL);
2004-06-20 02:41:49 +00:00
/* is the key of the right type for the operation? */
2004-10-30 03:00:26 +00:00
if (which == PK_PRIVATE && (key->type != PK_PRIVATE)) {
2004-05-12 20:42:16 +00:00
return CRYPT_PK_NOT_PRIVATE;
}
/* must be a private or public operation */
if (which != PK_PRIVATE && which != PK_PUBLIC) {
return CRYPT_PK_INVALID_TYPE;
}
/* init and copy into tmp */
if ((err = mp_init_multi(&tmp, &tmpa, &tmpb,
#ifdef LTC_RSA_BLINDING
&rnd, &rndi,
#endif /* LTC_RSA_BLINDING */
NULL)) != CRYPT_OK)
{ return err; }
2011-03-21 21:17:59 +01:00
if ((err = mp_read_unsigned_bin(tmp, (unsigned char *)in, (int)inlen)) != CRYPT_OK)
{ goto error; }
2004-05-12 20:42:16 +00:00
/* sanity check on the input */
2005-08-01 16:36:47 +00:00
if (mp_cmp(key->N, tmp) == LTC_MP_LT) {
2004-05-12 20:42:16 +00:00
err = CRYPT_PK_INVALID_SIZE;
2006-12-16 18:10:04 +00:00
goto error;
2004-05-12 20:42:16 +00:00
}
/* are we using the private exponent and is the key optimized? */
2004-10-30 03:00:26 +00:00
if (which == PK_PRIVATE) {
#ifdef LTC_RSA_BLINDING
/* do blinding */
err = mp_rand(rnd, mp_get_digit_count(key->N));
if (err != CRYPT_OK) {
goto error;
}
/* rndi = 1/rnd mod N */
err = mp_invmod(rnd, key->N, rndi);
if (err != CRYPT_OK) {
goto error;
}
/* rnd = rnd^e */
err = mp_exptmod( rnd, key->e, key->N, rnd);
if (err != CRYPT_OK) {
goto error;
}
/* tmp = tmp*rnd mod N */
err = mp_mulmod( tmp, rnd, key->N, tmp);
if (err != CRYPT_OK) {
goto error;
}
#endif /* LTC_RSA_BLINDING */
no_crt = (key->dP == NULL) || (mp_get_digit_count(key->dP) == 0);
if (no_crt) {
/*
* In case CRT optimization parameters are not provided,
* the private key is directly used to exptmod it
*/
if ((err = mp_exptmod(tmp, key->d, key->N, tmp)) != CRYPT_OK) { goto error; }
} else {
/* tmpa = tmp^dP mod p */
if ((err = mp_exptmod(tmp, key->dP, key->p, tmpa)) != CRYPT_OK) { goto error; }
/* tmpb = tmp^dQ mod q */
if ((err = mp_exptmod(tmp, key->dQ, key->q, tmpb)) != CRYPT_OK) { goto error; }
/* tmp = (tmpa - tmpb) * qInv (mod p) */
if ((err = mp_sub(tmpa, tmpb, tmp)) != CRYPT_OK) { goto error; }
if ((err = mp_mulmod(tmp, key->qP, key->p, tmp)) != CRYPT_OK) { goto error; }
/* tmp = tmpb + q * tmp */
if ((err = mp_mul(tmp, key->q, tmp)) != CRYPT_OK) { goto error; }
if ((err = mp_add(tmp, tmpb, tmp)) != CRYPT_OK) { goto error; }
}
#ifdef LTC_RSA_BLINDING
/* unblind */
err = mp_mulmod( tmp, rndi, key->N, tmp);
if (err != CRYPT_OK) {
goto error;
}
#endif
#ifdef LTC_RSA_CRT_HARDENING
if (!no_crt) {
if ((err = mp_exptmod(tmp, key->e, key->N, tmpa)) != CRYPT_OK) { goto error; }
if ((err = mp_read_unsigned_bin(tmpb, (unsigned char *)in, (int)inlen)) != CRYPT_OK) { goto error; }
if (mp_cmp(tmpa, tmpb) != LTC_MP_EQ) { err = CRYPT_ERROR; goto error; }
}
#endif
2004-05-12 20:42:16 +00:00
} else {
/* exptmod it */
2005-08-01 16:36:47 +00:00
if ((err = mp_exptmod(tmp, key->e, key->N, tmp)) != CRYPT_OK) { goto error; }
2004-05-12 20:42:16 +00:00
}
/* read it back */
2005-08-01 16:36:47 +00:00
x = (unsigned long)mp_unsigned_bin_size(key->N);
2004-05-12 20:42:16 +00:00
if (x > *outlen) {
2006-06-18 01:37:50 +00:00
*outlen = x;
2004-05-12 20:42:16 +00:00
err = CRYPT_BUFFER_OVERFLOW;
2006-12-16 18:10:04 +00:00
goto error;
2004-05-12 20:42:16 +00:00
}
2005-06-27 11:47:35 +00:00
/* this should never happen ... */
2005-08-01 16:36:47 +00:00
if (mp_unsigned_bin_size(tmp) > mp_unsigned_bin_size(key->N)) {
2005-06-27 11:47:35 +00:00
err = CRYPT_ERROR;
2006-12-16 18:10:04 +00:00
goto error;
2005-06-27 11:47:35 +00:00
}
2004-05-12 20:42:16 +00:00
*outlen = x;
/* convert it */
2004-05-31 02:36:47 +00:00
zeromem(out, x);
2005-08-01 16:36:47 +00:00
if ((err = mp_to_unsigned_bin(tmp, out+(x-mp_unsigned_bin_size(tmp)))) != CRYPT_OK) { goto error; }
2004-05-12 20:42:16 +00:00
/* clean up and return */
err = CRYPT_OK;
error:
mp_clear_multi(
#ifdef LTC_RSA_BLINDING
rndi, rnd,
#endif /* LTC_RSA_BLINDING */
tmpb, tmpa, tmp, NULL);
2004-05-12 20:42:16 +00:00
return err;
}
#endif
2005-06-09 00:08:13 +00:00
/* $Source$ */
/* $Revision$ */
/* $Date$ */