2766 lines
76 KiB
C
2766 lines
76 KiB
C
/* rsa.c
|
|
*
|
|
* Copyright (C) 2006-2017 wolfSSL Inc.
|
|
*
|
|
* This file is part of wolfSSL.
|
|
*
|
|
* wolfSSL is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* wolfSSL is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
|
|
*/
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H /* configure options when using autoconf */
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <wolfssl/options.h>
|
|
#include <wolfssl/wolfcrypt/settings.h>
|
|
|
|
#ifndef NO_RSA
|
|
|
|
#define USER_CRYPTO_ERROR -101
|
|
|
|
#ifdef OPENSSL_EXTRA
|
|
#include <wolfssl/openssl/rsa.h> /* include for openssl compatibility */
|
|
#include <wolfssl/openssl/bn.h>
|
|
#endif
|
|
#include "user_rsa.h"
|
|
|
|
#ifdef DEBUG_WOLFSSL /* debug done without variadric to allow older compilers */
|
|
#include <stdio.h>
|
|
#define USER_DEBUG(x) printf x
|
|
#else
|
|
#define USER_DEBUG(x)
|
|
#endif
|
|
|
|
#define ASN_INTEGER 0x02
|
|
#define ASN_BIT_STRING 0x03
|
|
#define ASN_TAG_NULL 0x05
|
|
#define ASN_OBJECT_ID 0x06
|
|
|
|
|
|
/* Make sure compiler doesn't skip -- used from wolfSSL */
|
|
static inline void ForceZero(const void* mem, word32 len)
|
|
{
|
|
volatile byte* z = (volatile byte*)mem;
|
|
|
|
while (len--) *z++ = 0;
|
|
}
|
|
|
|
enum {
|
|
RSA_PUBLIC_ENCRYPT = 0,
|
|
RSA_PUBLIC_DECRYPT = 1,
|
|
RSA_PRIVATE_ENCRYPT = 2,
|
|
RSA_PRIVATE_DECRYPT = 3,
|
|
|
|
RSA_BLOCK_TYPE_1 = 1,
|
|
RSA_BLOCK_TYPE_2 = 2,
|
|
|
|
RSA_MIN_SIZE = 512,
|
|
RSA_MAX_SIZE = 4096, /* max allowed in IPP library */
|
|
|
|
RSA_MIN_PAD_SZ = 11 /* seperator + 0 + pad value + 8 pads */
|
|
};
|
|
|
|
|
|
int wc_InitRsaKey_ex(RsaKey* key, void* heap, int devId)
|
|
{
|
|
|
|
USER_DEBUG(("Entering wc_InitRsaKey\n"));
|
|
|
|
if (key == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* set full struct as 0 */
|
|
ForceZero(key, sizeof(RsaKey));
|
|
|
|
USER_DEBUG(("\tExit wc_InitRsaKey\n"));
|
|
|
|
(void)devId;
|
|
(void)heap;
|
|
return 0;
|
|
}
|
|
|
|
int wc_InitRsaKey(RsaKey* key, void* heap)
|
|
{
|
|
return wc_InitRsaKey_ex(key, heap, INVALID_DEVID);
|
|
}
|
|
|
|
|
|
/* three functions needed for cert and key gen */
|
|
#if defined(WOLFSSL_CERT_GEN) || defined(WOLFSSL_KEY_GEN)
|
|
/* return 1 if there is a leading bit*/
|
|
int wc_Rsa_leading_bit(void* bn)
|
|
{
|
|
int ret = 0;
|
|
int dataSz;
|
|
Ipp32u* data;
|
|
Ipp32u q;
|
|
int qSz = sizeof(Ipp32u);
|
|
|
|
if (ippsExtGet_BN(NULL, &dataSz, NULL, bn) != ippStsNoErr) {
|
|
USER_DEBUG(("ippsExtGet_BN Rsa leading bit error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* convert from size in binary to Ipp32u */
|
|
dataSz = dataSz / 32 + ((dataSz % 32)? 1 : 0);
|
|
data = (Ipp32u*)XMALLOC(dataSz * sizeof(Ipp32u), NULL,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (data == NULL) {
|
|
USER_DEBUG(("Rsa leading bit memory error\n"));
|
|
return 0;
|
|
}
|
|
|
|
/* extract value from BN */
|
|
if (ippsExtGet_BN(NULL, NULL, data, bn) != ippStsNoErr) {
|
|
USER_DEBUG(("Rsa leading bit error\n"));
|
|
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return 0;
|
|
}
|
|
|
|
/* use method like what's used in wolfssl tfm.c */
|
|
q = data[dataSz - 1];
|
|
|
|
ret = 0;
|
|
while (qSz > 0) {
|
|
if (q != 0)
|
|
ret = (q & 0x80) != 0;
|
|
q >>= 8;
|
|
qSz--;
|
|
}
|
|
|
|
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
|
|
return ret;
|
|
}
|
|
|
|
|
|
/* get the size in bytes of BN */
|
|
int wc_Rsa_unsigned_bin_size(void* bn)
|
|
{
|
|
int ret = 0;
|
|
if (ippsExtGet_BN(NULL, &ret, NULL, bn) != ippStsNoErr) {
|
|
USER_DEBUG(("Rsa unsigned bin size error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
return (ret / 8) + ((ret % 8)? 1: 0); /* size in bytes */
|
|
}
|
|
|
|
#ifndef MP_OKAY
|
|
#define MP_OKAY 0
|
|
#endif
|
|
|
|
/* extract the bn value to a unsigned byte array and return MP_OKAY on succes */
|
|
int wc_Rsa_to_unsigned_bin(void* bn, byte* in, int inLen)
|
|
{
|
|
if (ippsGetOctString_BN((Ipp8u*)in, inLen, bn) != ippStsNoErr) {
|
|
USER_DEBUG(("Rsa to unsigned bin error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
return MP_OKAY;
|
|
}
|
|
#endif /* WOLFSSL_CERT_GEN or WOLFSSL_KEY_GEN */
|
|
|
|
|
|
#ifdef OPENSSL_EXTRA /* functions needed for openssl compatibility layer */
|
|
static int SetIndividualExternal(WOLFSSL_BIGNUM** bn, IppsBigNumState* in)
|
|
{
|
|
IppStatus ret;
|
|
byte* data;
|
|
int sz;
|
|
|
|
USER_DEBUG(("Entering SetIndividualExternal\n"));
|
|
|
|
if (bn == NULL || in == NULL) {
|
|
USER_DEBUG(("inputs NULL error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (*bn == NULL) {
|
|
*bn = wolfSSL_BN_new();
|
|
if (*bn == NULL) {
|
|
USER_DEBUG(("SetIndividualExternal alloc failed\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
}
|
|
|
|
/* get size of array needed and extract oct array of data */
|
|
ret = ippsGetSize_BN(in, &sz);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
data = (byte*)XMALLOC(sz, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (data == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsGetOctString_BN(data, sz, in);
|
|
if (ret != ippStsNoErr) {
|
|
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* store the data into a wolfSSL Big Number */
|
|
*bn = wolfSSL_BN_bin2bn(data, sz, *bn);
|
|
|
|
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int SetIndividualInternal(WOLFSSL_BIGNUM* bn, IppsBigNumState** mpi)
|
|
{
|
|
int length, ctxSz, sz;
|
|
IppStatus ret;
|
|
Ipp8u* data;
|
|
|
|
USER_DEBUG(("Entering SetIndividualInternal\n"));
|
|
|
|
if (bn == NULL || bn->internal == NULL) {
|
|
USER_DEBUG(("bn NULL error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
length = wolfSSL_BN_num_bytes(bn);
|
|
|
|
/* if not IPP BN then create one */
|
|
if (*mpi == NULL) {
|
|
ret = ippsBigNumGetSize(length, &ctxSz);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
*mpi = (IppsBigNumState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (*mpi == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsBigNumInit(length, *mpi);
|
|
if (ret != ippStsNoErr) {
|
|
XFREE(*mpi, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
}
|
|
|
|
/* get the size of array needed and check IPP BigNum */
|
|
if (ippsGetSize_BN(*mpi, &sz) != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (sz < length) {
|
|
USER_DEBUG(("big num size is too small\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
data = (Ipp8u*)XMALLOC(length, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (data == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* extract the wolfSSL BigNum and store it into IPP BigNum */
|
|
if (wolfSSL_BN_bn2bin(bn, data) < 0) {
|
|
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
USER_DEBUG(("error in getting bin from wolfssl bn\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsSetOctString_BN(data, length, *mpi);
|
|
if (ret != ippStsNoErr) {
|
|
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
XFREE(data, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* WolfSSL -> OpenSSL */
|
|
int SetRsaExternal(WOLFSSL_RSA* rsa)
|
|
{
|
|
RsaKey* key;
|
|
USER_DEBUG(("Entering SetRsaExternal\n"));
|
|
|
|
if (rsa == NULL || rsa->internal == NULL) {
|
|
USER_DEBUG(("rsa key NULL error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key = (RsaKey*)rsa->internal;
|
|
|
|
if (SetIndividualExternal(&rsa->n, key->n) != 0) {
|
|
USER_DEBUG(("rsa n key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (SetIndividualExternal(&rsa->e, key->e) != 0) {
|
|
USER_DEBUG(("rsa e key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (SetIndividualExternal(&rsa->d, key->dipp) != 0) {
|
|
USER_DEBUG(("rsa d key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (SetIndividualExternal(&rsa->p, key->pipp) != 0) {
|
|
USER_DEBUG(("rsa p key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (SetIndividualExternal(&rsa->q, key->qipp) != 0) {
|
|
USER_DEBUG(("rsa q key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (SetIndividualExternal(&rsa->dmp1, key->dPipp) != 0) {
|
|
USER_DEBUG(("rsa dP key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (SetIndividualExternal(&rsa->dmq1, key->dQipp) != 0) {
|
|
USER_DEBUG(("rsa dQ key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (SetIndividualExternal(&rsa->iqmp, key->uipp) != 0) {
|
|
USER_DEBUG(("rsa u key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
rsa->exSet = 1;
|
|
|
|
/* SSL_SUCCESS */
|
|
return 1;
|
|
}
|
|
|
|
|
|
/* Openssl -> WolfSSL */
|
|
int SetRsaInternal(WOLFSSL_RSA* rsa)
|
|
{
|
|
int ctxSz, pSz, qSz;
|
|
IppStatus ret;
|
|
RsaKey* key;
|
|
USER_DEBUG(("Entering SetRsaInternal\n"));
|
|
|
|
if (rsa == NULL || rsa->internal == NULL) {
|
|
USER_DEBUG(("rsa key NULL error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key = (RsaKey*)rsa->internal;
|
|
|
|
if (SetIndividualInternal(rsa->n, &key->n) != 0) {
|
|
USER_DEBUG(("rsa n key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (SetIndividualInternal(rsa->e, &key->e) != 0) {
|
|
USER_DEBUG(("rsa e key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* public key */
|
|
key->type = RSA_PUBLIC;
|
|
|
|
if (rsa->d != NULL) {
|
|
if (SetIndividualInternal(rsa->d, &key->dipp) != 0) {
|
|
USER_DEBUG(("rsa d key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* private key */
|
|
key->type = RSA_PRIVATE;
|
|
}
|
|
|
|
if (rsa->p != NULL &&
|
|
SetIndividualInternal(rsa->p, &key->pipp) != 0) {
|
|
USER_DEBUG(("rsa p key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (rsa->q != NULL &&
|
|
SetIndividualInternal(rsa->q, &key->qipp) != 0) {
|
|
USER_DEBUG(("rsa q key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (rsa->dmp1 != NULL &&
|
|
SetIndividualInternal(rsa->dmp1, &key->dPipp) != 0) {
|
|
USER_DEBUG(("rsa dP key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (rsa->dmq1 != NULL &&
|
|
SetIndividualInternal(rsa->dmq1, &key->dQipp) != 0) {
|
|
USER_DEBUG(("rsa dQ key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (rsa->iqmp != NULL &&
|
|
SetIndividualInternal(rsa->iqmp, &key->uipp) != 0) {
|
|
USER_DEBUG(("rsa u key error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
rsa->inSet = 1;
|
|
|
|
/* get sizes of IPP BN key states created from input */
|
|
ret = ippsGetSize_BN(key->n, &key->nSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsGetSize_BN(key->e, &key->eSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key->sz = key->nSz; /* set modulus size */
|
|
|
|
/* convert to size in bits */
|
|
key->nSz = key->nSz * 8;
|
|
key->eSz = key->eSz * 8;
|
|
|
|
/* set up public key state */
|
|
ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (key->pPub == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_SetPublicKey error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (key->pipp != NULL && key->qipp != NULL && key->dipp != NULL &&
|
|
key->dPipp != NULL && key->dQipp != NULL && key->uipp != NULL) {
|
|
/* get bn sizes needed for private key set up */
|
|
ret = ippsGetSize_BN(key->pipp, &pSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsGetSize_BN(key->qipp, &qSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* store sizes needed for creating tmp private keys */
|
|
ret = ippsGetSize_BN(key->dipp, &key->dSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* convert to size in bits */
|
|
key->dSz = key->dSz * 8;
|
|
pSz = pSz * 8;
|
|
qSz = qSz * 8;
|
|
|
|
/* set up private key state */
|
|
ret = ippsRSA_GetSizePrivateKeyType2(pSz, qSz, &ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetSizePrivateKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key->prvSz = ctxSz;
|
|
key->pPrv = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, 0,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (key->pPrv == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsRSA_InitPrivateKeyType2(pSz, qSz, key->pPrv, ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_InitPrivateKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsRSA_SetPrivateKeyType2(key->pipp, key->qipp, key->dPipp,
|
|
key->dQipp, key->uipp, key->pPrv);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_SetPrivateKey error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
}
|
|
|
|
/* SSL_SUCCESS */
|
|
return 1;
|
|
}
|
|
#endif /* OPENSSLEXTRA */
|
|
|
|
|
|
/* Padding scheme function used in wolfSSL for signing needed for matching
|
|
existing API signing scheme
|
|
input : the msg to be signed
|
|
inputLen : length of input msg
|
|
pkcsBlock : the outputed padded msg
|
|
pkcsBlockLen : length of outptued padded msg buffer
|
|
padValue : the padded value after first 00 , is either 01 or 02
|
|
rng : random number generator structure
|
|
*/
|
|
static int wc_RsaPad(const byte* input, word32 inputLen, byte* pkcsBlock,
|
|
word32 pkcsBlockLen, byte padValue, WC_RNG* rng)
|
|
{
|
|
if (inputLen == 0 || pkcsBlockLen == 0) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
pkcsBlock[0] = 0x0; /* set first byte to zero and advance */
|
|
pkcsBlock++; pkcsBlockLen--;
|
|
pkcsBlock[0] = padValue; /* insert padValue */
|
|
|
|
if (padValue == RSA_BLOCK_TYPE_1) {
|
|
if (pkcsBlockLen < inputLen + 2) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* pad with 0xff bytes */
|
|
XMEMSET(&pkcsBlock[1], 0xFF, pkcsBlockLen - inputLen - 2);
|
|
}
|
|
else {
|
|
/* pad with non-zero random bytes */
|
|
word32 padLen, i;
|
|
int ret;
|
|
|
|
if (pkcsBlockLen < inputLen + 1) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
padLen = pkcsBlockLen - inputLen - 1;
|
|
ret = wc_RNG_GenerateBlock(rng, &pkcsBlock[1], padLen);
|
|
|
|
if (ret != 0)
|
|
return ret;
|
|
|
|
/* remove zeros */
|
|
for (i = 1; i < padLen; i++)
|
|
if (pkcsBlock[i] == 0) pkcsBlock[i] = 0x01;
|
|
}
|
|
|
|
pkcsBlock[pkcsBlockLen-inputLen-1] = 0; /* separator */
|
|
XMEMCPY(pkcsBlock+pkcsBlockLen-inputLen, input, inputLen);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* UnPad plaintext, set start to *output, return length of plaintext,
|
|
* < 0 on error */
|
|
static int RsaUnPad(const byte *pkcsBlock, unsigned int pkcsBlockLen,
|
|
byte **output, byte padValue)
|
|
{
|
|
word32 maxOutputLen = (pkcsBlockLen > 10) ? (pkcsBlockLen - 10) : 0,
|
|
invalid = 0,
|
|
i = 1,
|
|
outputLen;
|
|
|
|
if (pkcsBlockLen == 0) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (pkcsBlock[0] != 0x0) /* skip past zero */
|
|
invalid = 1;
|
|
pkcsBlock++; pkcsBlockLen--;
|
|
|
|
/* Require block type padValue */
|
|
invalid = (pkcsBlock[0] != padValue) || invalid;
|
|
|
|
/* verify the padding until we find the separator */
|
|
if (padValue == RSA_BLOCK_TYPE_1) {
|
|
while (i<pkcsBlockLen && pkcsBlock[i++] == 0xFF) {/* Null body */}
|
|
}
|
|
else {
|
|
while (i<pkcsBlockLen && pkcsBlock[i++]) {/* Null body */}
|
|
}
|
|
|
|
if(!(i==pkcsBlockLen || pkcsBlock[i-1]==0)) {
|
|
USER_DEBUG(("RsaUnPad error, bad formatting\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
outputLen = pkcsBlockLen - i;
|
|
invalid = (outputLen > maxOutputLen) || invalid;
|
|
|
|
if (invalid) {
|
|
USER_DEBUG(("RsaUnPad error, bad formatting\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
*output = (byte *)(pkcsBlock + i);
|
|
return outputLen;
|
|
}
|
|
|
|
|
|
/* Set up memory and structure for a Big Number
|
|
* returns ippStsNoErr on success
|
|
*/
|
|
static IppStatus init_bn(IppsBigNumState** in, int sz)
|
|
{
|
|
int ctxSz;
|
|
IppStatus ret;
|
|
|
|
ret = ippsBigNumGetSize(sz, &ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
return ret;
|
|
}
|
|
|
|
*in = (IppsBigNumState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (*in == NULL) {
|
|
return ippStsNoMemErr;
|
|
}
|
|
|
|
ret = ippsBigNumInit(sz, *in);
|
|
if (ret != ippStsNoErr) {
|
|
XFREE(*in, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
*in = NULL;
|
|
return ret;
|
|
}
|
|
|
|
return ippStsNoErr;
|
|
}
|
|
|
|
|
|
/* Set up memory and structure for a Montgomery struct
|
|
* returns ippStsNoErr on success
|
|
*/
|
|
static IppStatus init_mont(IppsMontState** mont, int* ctxSz,
|
|
IppsBigNumState* modul)
|
|
{
|
|
int mSz;
|
|
Ipp32u* m;
|
|
IppStatus ret;
|
|
|
|
ret = ippsExtGet_BN(NULL, ctxSz, NULL, modul);
|
|
if (ret != ippStsNoErr) {
|
|
return ret;
|
|
}
|
|
|
|
/* convert bits to Ipp32u array size and round up
|
|
32 is number of bits in type */
|
|
mSz = (*ctxSz/32)+((*ctxSz % 32)? 1: 0);
|
|
m = (Ipp32u*)XMALLOC(mSz * sizeof(Ipp32u), 0, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (m == NULL) {
|
|
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return ippStsNoMemErr;
|
|
}
|
|
|
|
ret = ippsExtGet_BN(NULL, NULL, m, modul);
|
|
if (ret != ippStsNoErr) {
|
|
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return ret;
|
|
}
|
|
|
|
ret = ippsMontGetSize(IppsSlidingWindows, mSz, ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return ret;
|
|
}
|
|
|
|
/* 2. Allocate working buffer using malloc */
|
|
*mont = (IppsMontState*)XMALLOC(*ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (mont == NULL) {
|
|
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return ippStsNoMemErr;
|
|
}
|
|
ret = ippsMontInit(IppsSlidingWindows, mSz, *mont);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsMontInit error of %s\n", ippGetStatusString(ret)));
|
|
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(*mont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
*mont = NULL;
|
|
return ret;
|
|
}
|
|
|
|
/* 3. Call the function MontSet to set big number module */
|
|
ret = ippsMontSet(m, mSz, *mont);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsMontSet error of %s\n", ippGetStatusString(ret)));
|
|
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(*mont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
*mont = NULL;
|
|
return ret;
|
|
}
|
|
|
|
XFREE(m, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
|
|
return ippStsNoErr;
|
|
}
|
|
|
|
|
|
|
|
int wc_FreeRsaKey(RsaKey* key)
|
|
{
|
|
if (key == NULL)
|
|
return 0;
|
|
|
|
USER_DEBUG(("Entering wc_FreeRsaKey\n"));
|
|
|
|
if (key->pPub != NULL) {
|
|
XFREE(key->pPub, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
key->pPub = NULL;
|
|
}
|
|
|
|
if (key->pPrv != NULL) {
|
|
/* write over senstive information */
|
|
ForceZero(key->pPrv, key->prvSz);
|
|
XFREE(key->pPrv, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
key->pPrv = NULL;
|
|
}
|
|
|
|
if (key->n != NULL) {
|
|
XFREE(key->n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
key->n = NULL;
|
|
}
|
|
|
|
if (key->e != NULL) {
|
|
XFREE(key->e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
key->e = NULL;
|
|
}
|
|
|
|
if (key->dipp != NULL) {
|
|
XFREE(key->dipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
key->dipp = NULL;
|
|
}
|
|
|
|
if (key->pipp != NULL) {
|
|
XFREE(key->pipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
key->pipp = NULL;
|
|
}
|
|
|
|
if (key->qipp != NULL) {
|
|
XFREE(key->qipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
key->qipp = NULL;
|
|
}
|
|
|
|
if (key->dPipp != NULL) {
|
|
XFREE(key->dPipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
key->dPipp = NULL;
|
|
}
|
|
|
|
if (key->dQipp != NULL) {
|
|
XFREE(key->dQipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
key->dQipp = NULL;
|
|
}
|
|
|
|
if (key->uipp != NULL) {
|
|
XFREE(key->uipp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
key->uipp = NULL;
|
|
}
|
|
|
|
USER_DEBUG(("\tExit wc_FreeRsaKey\n"));
|
|
(void)key;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* Some parsing functions from wolfSSL code needed to match wolfSSL API used */
|
|
static int GetLength(const byte* input, word32* inOutIdx, int* len,
|
|
word32 maxIdx)
|
|
{
|
|
int length = 0;
|
|
word32 idx = *inOutIdx;
|
|
byte b;
|
|
|
|
*len = 0; /* default length */
|
|
|
|
if ((idx + 1) > maxIdx) { /* for first read */
|
|
USER_DEBUG(("GetLength bad index on input\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
b = input[idx++];
|
|
if (b >= 0x80) {
|
|
word32 bytes = b & 0x7F;
|
|
|
|
if ((idx + bytes) > maxIdx) { /* for reading bytes */
|
|
USER_DEBUG(("GetLength bad long length\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
while (bytes--) {
|
|
b = input[idx++];
|
|
length = (length << 8) | b;
|
|
}
|
|
}
|
|
else
|
|
length = b;
|
|
|
|
if ((idx + length) > maxIdx) { /* for user of length */
|
|
USER_DEBUG(("GetLength value exceeds buffer length\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
*inOutIdx = idx;
|
|
if (length > 0)
|
|
*len = length;
|
|
|
|
return length;
|
|
}
|
|
|
|
|
|
static int GetInt(IppsBigNumState** mpi, const byte* input, word32* inOutIdx,
|
|
word32 maxIdx)
|
|
{
|
|
IppStatus ret;
|
|
word32 idx = *inOutIdx;
|
|
byte b;
|
|
int length;
|
|
int ctxSz;
|
|
|
|
if ((idx + 1) > maxIdx)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
b = input[idx++];
|
|
if (b != 0x02)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (GetLength(input, &idx, &length, maxIdx) < 0)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (length > 0) {
|
|
/* remove leading zero */
|
|
if ( (b = input[idx++]) == 0x00)
|
|
length--;
|
|
else
|
|
idx--;
|
|
}
|
|
|
|
ret = ippsBigNumGetSize(length, &ctxSz);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
*mpi = (IppsBigNumState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (*mpi == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsBigNumInit(length, *mpi);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsSetOctString_BN((Ipp8u*)input + idx, length, *mpi);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
*inOutIdx = idx + length;
|
|
return 0;
|
|
}
|
|
|
|
|
|
static int GetSequence(const byte* input, word32* inOutIdx, int* len,
|
|
word32 maxIdx)
|
|
{
|
|
int length = -1;
|
|
word32 idx = *inOutIdx;
|
|
|
|
if ((idx + 1) > maxIdx)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (input[idx++] != (0x10 | 0x20) ||
|
|
GetLength(input, &idx, &length, maxIdx) < 0)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
*len = length;
|
|
*inOutIdx = idx;
|
|
|
|
return length;
|
|
}
|
|
|
|
|
|
static int GetMyVersion(const byte* input, word32* inOutIdx,
|
|
int* version, word32 maxIdx)
|
|
{
|
|
word32 idx = *inOutIdx;
|
|
|
|
if ((idx + 3) > maxIdx)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (input[idx++] != 0x02)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (input[idx++] != 0x01)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
*version = input[idx++];
|
|
*inOutIdx = idx;
|
|
|
|
return *version;
|
|
}
|
|
|
|
|
|
int wc_RsaPrivateKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
|
|
word32 inSz)
|
|
{
|
|
int version, length;
|
|
int ctxSz, pSz, qSz;
|
|
IppStatus ret;
|
|
|
|
if (input == NULL || inOutIdx == NULL || key == NULL) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
USER_DEBUG(("Entering wc_RsaPrivateKeyDecode\n"));
|
|
|
|
/* read in key information */
|
|
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (GetMyVersion(input, inOutIdx, &version, inSz) < 0)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
key->type = RSA_PRIVATE;
|
|
|
|
if (GetInt(&key->n, input, inOutIdx, inSz) < 0 ||
|
|
GetInt(&key->e, input, inOutIdx, inSz) < 0 ||
|
|
GetInt(&key->dipp, input, inOutIdx, inSz) < 0 ||
|
|
GetInt(&key->pipp, input, inOutIdx, inSz) < 0 ||
|
|
GetInt(&key->qipp, input, inOutIdx, inSz) < 0 ||
|
|
GetInt(&key->dPipp, input, inOutIdx, inSz) < 0 ||
|
|
GetInt(&key->dQipp, input, inOutIdx, inSz) < 0 ||
|
|
GetInt(&key->uipp, input, inOutIdx, inSz) < 0 )
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* get sizes of IPP BN key states created from input */
|
|
ret = ippsGetSize_BN(key->n, &key->nSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsGetSize_BN(key->e, &key->eSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key->sz = key->nSz; /* set modulus size */
|
|
|
|
/* convert to size in bits */
|
|
key->nSz = key->nSz * 8;
|
|
key->eSz = key->eSz * 8;
|
|
|
|
/* set up public key state */
|
|
ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (key->pPub == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* get bn sizes needed for private key set up */
|
|
ret = ippsGetSize_BN(key->pipp, &pSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsGetSize_BN(key->qipp, &qSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* store sizes needed for creating tmp private keys */
|
|
ret = ippsGetSize_BN(key->dipp, &key->dSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* convert to size in bits */
|
|
key->dSz = key->dSz * 8;
|
|
pSz = pSz * 8;
|
|
qSz = qSz * 8;
|
|
|
|
/* set up private key state */
|
|
ret = ippsRSA_GetSizePrivateKeyType2(pSz, qSz, &ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetSizePrivateKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key->prvSz = ctxSz;
|
|
key->pPrv = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, 0,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (key->pPrv == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsRSA_InitPrivateKeyType2(pSz, qSz, key->pPrv, ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_InitPrivateKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsRSA_SetPrivateKeyType2(key->pipp, key->qipp, key->dPipp,
|
|
key->dQipp, key->uipp, key->pPrv);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_SetPrivateKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
USER_DEBUG(("\tExit wc_RsaPrivateKeyDecode\n"));
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* read in a public RSA key */
|
|
int wc_RsaPublicKeyDecode(const byte* input, word32* inOutIdx, RsaKey* key,
|
|
word32 inSz)
|
|
{
|
|
int length;
|
|
int ctxSz;
|
|
IppStatus ret;
|
|
#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
|
|
byte b;
|
|
#endif
|
|
|
|
if (input == NULL || inOutIdx == NULL || key == NULL) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
USER_DEBUG(("Entering wc_RsaPublicKeyDecode\n"));
|
|
|
|
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
key->type = RSA_PUBLIC;
|
|
|
|
#if defined(OPENSSL_EXTRA) || defined(RSA_DECODE_EXTRA)
|
|
if ((*inOutIdx + 1) > inSz)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
b = input[*inOutIdx];
|
|
if (b != ASN_INTEGER) {
|
|
/* not from decoded cert, will have algo id, skip past */
|
|
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
b = input[(*inOutIdx)++];
|
|
if (b != ASN_OBJECT_ID)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (GetLength(input, inOutIdx, &length, inSz) < 0)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
*inOutIdx += length; /* skip past */
|
|
|
|
/* could have NULL tag and 0 terminator, but may not */
|
|
b = input[(*inOutIdx)++];
|
|
|
|
if (b == ASN_TAG_NULL) {
|
|
b = input[(*inOutIdx)++];
|
|
if (b != 0)
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
else {
|
|
/* go back, didn't have it */
|
|
(*inOutIdx)--;
|
|
}
|
|
|
|
/* should have bit tag length and seq next */
|
|
b = input[(*inOutIdx)++];
|
|
if (b != ASN_BIT_STRING)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (GetLength(input, inOutIdx, &length, inSz) <= 0)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* could have 0 */
|
|
b = input[(*inOutIdx)++];
|
|
if (b != 0)
|
|
(*inOutIdx)--;
|
|
|
|
if (GetSequence(input, inOutIdx, &length, inSz) < 0)
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
#endif /* OPENSSL_EXTRA || RSA_DECODE_EXTRA */
|
|
|
|
if (GetInt(&key->n, input, inOutIdx, inSz) < 0 ||
|
|
GetInt(&key->e, input, inOutIdx, inSz) < 0) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* get sizes set for IPP BN states */
|
|
ret = ippsGetSize_BN(key->n, &key->nSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsGetSize_BN(key->e, &key->eSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key->sz = key->nSz; /* set modulus size */
|
|
|
|
/* convert to size in bits */
|
|
key->nSz = key->nSz * 8;
|
|
key->eSz = key->eSz * 8;
|
|
|
|
/* set up public key state */
|
|
ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (key->pPub == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
USER_DEBUG(("\tExit RsaPublicKeyDecode\n"));
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* import RSA public key elements (n, e) into RsaKey structure (key) */
|
|
int wc_RsaPublicKeyDecodeRaw(const byte* n, word32 nSz, const byte* e,
|
|
word32 eSz, RsaKey* key)
|
|
{
|
|
IppStatus ret;
|
|
int ctxSz;
|
|
|
|
USER_DEBUG(("Entering wc_RsaPublicKeyDecodeRaw\n"));
|
|
|
|
if (n == NULL || e == NULL || key == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* set up IPP key states -- read in n */
|
|
ret = init_bn(&key->n, nSz);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsSetOctString_BN((Ipp8u*)n, nSz, key->n);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* read in e */
|
|
ret = init_bn(&key->e, eSz);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsSetOctString_BN((Ipp8u*)e, eSz, key->e);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* store size and convert to binary */
|
|
key->sz = nSz;
|
|
nSz = nSz * 8;
|
|
eSz = eSz * 8;
|
|
|
|
/* set up public key state */
|
|
ret = ippsRSA_GetSizePublicKey(nSz, eSz, &ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetSizePublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (key->pPub == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsRSA_InitPublicKey(nSz, eSz, key->pPub, ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsRSA_SetPublicKey(key->n,key->e, key->pPub);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
key->nSz = nSz;
|
|
key->eSz = eSz;
|
|
key->type = RSA_PUBLIC;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* encrypt using PKCS v15 */
|
|
int wc_RsaPublicEncrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
|
|
RsaKey* key, WC_RNG* rng)
|
|
{
|
|
IppStatus ret;
|
|
Ipp8u* scratchBuffer;
|
|
int scratchSz;
|
|
|
|
if (key == NULL || in == NULL || out == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (key->pPub == NULL || outLen < key->sz)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* set size of scratch buffer */
|
|
ret = ippsRSA_GetBufferSizePublicKey(&scratchSz, key->pPub);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
scratchBuffer = (Ipp8u*)XMALLOC(scratchSz*(sizeof(Ipp8u)), 0,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (scratchBuffer == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsRSAEncrypt_PKCSv15((Ipp8u*)in, inLen, NULL, (Ipp8u*)out,
|
|
key->pPub, scratchBuffer);
|
|
if (ret != ippStsNoErr) {
|
|
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
USER_DEBUG(("encrypt error of %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
|
|
(void)rng;
|
|
return key->sz;
|
|
}
|
|
|
|
|
|
/* decrypt using PLCS v15 */
|
|
int wc_RsaPrivateDecrypt(const byte* in, word32 inLen, byte* out, word32 outLen,
|
|
RsaKey* key)
|
|
{
|
|
IppStatus ret;
|
|
Ipp8u* scratchBuffer;
|
|
int scratchSz;
|
|
int outSz;
|
|
|
|
if (in == NULL || out == NULL || key == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (key->pPrv == NULL || inLen != key->sz)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
outSz = outLen;
|
|
|
|
/* set size of scratch buffer */
|
|
ret = ippsRSA_GetBufferSizePrivateKey(&scratchSz, key->pPrv);
|
|
if (ret != ippStsNoErr) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
scratchBuffer = (Ipp8u*)XMALLOC(scratchSz*(sizeof(Ipp8u)), 0,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (scratchBuffer == NULL) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* perform decryption using IPP */
|
|
ret = ippsRSADecrypt_PKCSv15((Ipp8u*)in, (Ipp8u*)out, &outSz, key->pPrv,
|
|
scratchBuffer);
|
|
if (ret != ippStsNoErr) {
|
|
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
USER_DEBUG(("decrypt error of %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
|
|
return outSz;
|
|
}
|
|
|
|
|
|
/* out is a pointer that is set to the location in byte array "in" where input
|
|
data has been decrypted */
|
|
int wc_RsaPrivateDecryptInline(byte* in, word32 inLen, byte** out, RsaKey* key)
|
|
{
|
|
int outSz;
|
|
byte* tmp;
|
|
|
|
USER_DEBUG(("Entering wc_RsaPrivateDecryptInline\n"));
|
|
|
|
/* allocate a buffer for max decrypted text */
|
|
tmp = (byte*)XMALLOC(key->sz, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (tmp == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
outSz = wc_RsaPrivateDecrypt(in, inLen, tmp, key->sz, key);
|
|
if (outSz >= 0) {
|
|
XMEMCPY(in, tmp, outSz);
|
|
*out = in;
|
|
}
|
|
else {
|
|
XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
USER_DEBUG(("\tExit wc_RsaPrivateDecryptInline\n"));
|
|
|
|
return outSz;
|
|
}
|
|
|
|
|
|
/* Used to clean up memory when exiting, clean up memory used */
|
|
static int FreeHelper(IppsBigNumState* pTxt, IppsBigNumState* cTxt,
|
|
Ipp8u* scratchBuffer, void* pPub)
|
|
{
|
|
if (pTxt != NULL)
|
|
XFREE(pTxt, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (cTxt != NULL)
|
|
XFREE(cTxt, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (scratchBuffer != NULL)
|
|
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (pPub != NULL)
|
|
XFREE(pPub, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* for Rsa Verify
|
|
in : byte array to be verified
|
|
inLen : length of input array
|
|
out : pointer to location of in byte array that has been verified
|
|
*/
|
|
int wc_RsaSSL_VerifyInline(byte* in, word32 inLen, byte** out, RsaKey* key)
|
|
{
|
|
|
|
int ctxSz;
|
|
int scratchSz;
|
|
Ipp8u* scratchBuffer = NULL;
|
|
IppStatus ret;
|
|
IppsRSAPrivateKeyState* pPub = NULL;
|
|
IppsBigNumState* pTxt = NULL;
|
|
IppsBigNumState* cTxt = NULL;
|
|
|
|
USER_DEBUG(("Entering wc_RsaSSL_VerifyInline\n"));
|
|
|
|
if (key == NULL || key->n == NULL || key->e == NULL) {
|
|
USER_DEBUG(("n or e element was null\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (in == NULL || inLen == 0 || out == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* set up a private key state using public key values */
|
|
ret = ippsRSA_GetSizePrivateKeyType1(key->nSz, key->eSz, &ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetSizePrivateKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
pPub = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (pPub == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsRSA_InitPrivateKeyType1(key->nSz, key->eSz, pPub, ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
USER_DEBUG(("ippsRSA_InitPrivateKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsRSA_SetPrivateKeyType1(key->n, key->e, pPub);
|
|
if (ret != ippStsNoErr) {
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
USER_DEBUG(("ippsRSA_SetPrivateKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* set size of scratch buffer */
|
|
ret = ippsRSA_GetBufferSizePrivateKey(&scratchSz, pPub);
|
|
if (ret != ippStsNoErr) {
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
scratchBuffer = (Ipp8u*)XMALLOC(scratchSz*(sizeof(Ipp8u)), 0,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (scratchBuffer == NULL) {
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* load plain and cipher into big num states */
|
|
ret = init_bn(&pTxt, key->sz);
|
|
if (ret != ippStsNoErr) {
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
ret = ippsSetOctString_BN((Ipp8u*)in, key->sz, pTxt);
|
|
if (ret != ippStsNoErr) {
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* set up cipher to hold signature */
|
|
ret = init_bn(&cTxt, key->sz);
|
|
if (ret != ippStsNoErr) {
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
ret = ippsSetOctString_BN((Ipp8u*)in, key->sz, cTxt);
|
|
if (ret != ippStsNoErr) {
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* decrypt using public key information */
|
|
ret = ippsRSA_Decrypt(cTxt, pTxt, pPub, scratchBuffer);
|
|
if (ret != ippStsNoErr) {
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
USER_DEBUG(("decrypt error of %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* extract big num struct to octect string */
|
|
ret = ippsGetOctString_BN((Ipp8u*)in, key->sz, pTxt);
|
|
if (ret != ippStsNoErr) {
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
USER_DEBUG(("BN get string error of %s\n", ippGetStatusString(ret)));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
FreeHelper(pTxt, cTxt, scratchBuffer, pPub);
|
|
|
|
/* unpad the decrypted information and return size of array */
|
|
return RsaUnPad(in, inLen, out, RSA_BLOCK_TYPE_1);
|
|
}
|
|
|
|
|
|
/* sets up and call VerifyInline to verify a signature */
|
|
int wc_RsaSSL_Verify(const byte* in, word32 inLen, byte* out, word32 outLen,
|
|
RsaKey* key)
|
|
{
|
|
int plainLen;
|
|
byte* tmp;
|
|
byte* pad = 0;
|
|
|
|
if (out == NULL || in == NULL || key == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
tmp = (byte*)XMALLOC(inLen, key->heap, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (tmp == NULL) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
XMEMCPY(tmp, in, inLen);
|
|
|
|
/* verify signature and test if output buffer is large enough */
|
|
plainLen = wc_RsaSSL_VerifyInline(tmp, inLen, &pad, key);
|
|
if (plainLen < 0) {
|
|
XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return plainLen;
|
|
}
|
|
|
|
if (plainLen > (int)outLen)
|
|
plainLen = USER_CRYPTO_ERROR;
|
|
else
|
|
XMEMCPY(out, pad, plainLen);
|
|
|
|
ForceZero(tmp, inLen);
|
|
XFREE(tmp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
|
|
return plainLen;
|
|
}
|
|
|
|
|
|
/* Check if a > b , if so c = a mod b
|
|
return ippStsNoErr on success */
|
|
static IppStatus reduce(IppsBigNumState* a, IppsBigNumState* b,
|
|
IppsBigNumState* c)
|
|
{
|
|
IppStatus ret;
|
|
|
|
if ((ret = ippsMod_BN(a, b, c)) != ippStsNoErr)
|
|
return ret;
|
|
|
|
return ippStsNoErr;
|
|
}
|
|
|
|
|
|
static IppStatus exptmod(IppsBigNumState* a, IppsBigNumState* b,
|
|
IppsMontState* mont, IppsBigNumState* out, IppsBigNumState* one)
|
|
{
|
|
IppStatus ret;
|
|
|
|
ret = ippsMontForm(a, mont, a);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsMontForm error of %s\n", ippGetStatusString(ret)));
|
|
return ret;
|
|
}
|
|
|
|
/* a = a^b mod mont */
|
|
ret = ippsMontExp(a, b, mont, out);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsMontExp error of %s\n", ippGetStatusString(ret)));
|
|
return ret;
|
|
}
|
|
|
|
/* convert back from montgomery */
|
|
ret = ippsMontMul(out, one, mont, out);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsMontMul error of %s\n", ippGetStatusString(ret)));
|
|
return ret;
|
|
}
|
|
|
|
return ippStsNoErr;
|
|
}
|
|
|
|
|
|
static void Free_BN(IppsBigNumState* bn)
|
|
{
|
|
int sz, ctxSz;
|
|
IppStatus ret;
|
|
|
|
if (bn != NULL) {
|
|
ret = ippStsNoErr;
|
|
ret |= ippsGetSize_BN(bn, &sz);
|
|
ret |= ippsBigNumGetSize(sz, &ctxSz);
|
|
if (ret == ippStsNoErr) {
|
|
ForceZero(bn, ctxSz);
|
|
}
|
|
else {
|
|
USER_DEBUG(("Issue with clearing a struct in RsaSSL_Sign free\n"));
|
|
}
|
|
XFREE(bn, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
bn = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
/* free up memory used during CRT sign operation */
|
|
static void FreeSignHelper(IppsBigNumState* one, IppsBigNumState* tmp,
|
|
IppsBigNumState* tmpP, IppsBigNumState* tmpQ, IppsBigNumState* tmpa,
|
|
IppsBigNumState* tmpb)
|
|
{
|
|
Free_BN(one);
|
|
Free_BN(tmp);
|
|
Free_BN(tmpP);
|
|
Free_BN(tmpQ);
|
|
Free_BN(tmpa);
|
|
Free_BN(tmpb);
|
|
}
|
|
|
|
|
|
/* for Rsa Sign */
|
|
int wc_RsaSSL_Sign(const byte* in, word32 inLen, byte* out, word32 outLen,
|
|
RsaKey* key, WC_RNG* rng)
|
|
{
|
|
int sz, pSz, qSz;
|
|
IppStatus ret;
|
|
word32 outSz = outLen;
|
|
|
|
IppsMontState* pMont = NULL;
|
|
IppsMontState* qMont = NULL;
|
|
|
|
IppsBigNumState* one = NULL;
|
|
IppsBigNumState* tmp = NULL;
|
|
IppsBigNumState* tmpP = NULL;
|
|
IppsBigNumState* tmpQ = NULL;
|
|
IppsBigNumState* tmpa = NULL;
|
|
IppsBigNumState* tmpb = NULL;
|
|
|
|
IppsBigNumSGN sa, sb;
|
|
|
|
Ipp8u o[1];
|
|
o[0] = 1;
|
|
|
|
USER_DEBUG(("Entering wc_RsaSSL_Sign\n"));
|
|
|
|
if (in == NULL || out == NULL || key == NULL || rng == NULL) {
|
|
USER_DEBUG(("Bad argument to wc_RsaSSL_Sign\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
sz = key->sz;
|
|
|
|
|
|
/* sanity check on key being used */
|
|
if (key->pipp == NULL || key->qipp == NULL || key->uipp == NULL ||
|
|
key->dPipp == NULL || key->dQipp == NULL) {
|
|
USER_DEBUG(("Bad key argument to wc_RsaSSL_Sign\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (sz > (int)outLen) {
|
|
USER_DEBUG(("Bad argument outLen to wc_RsaSSL_Sign\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (sz < RSA_MIN_PAD_SZ) {
|
|
USER_DEBUG(("Key size is too small\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (inLen > (word32)(sz - RSA_MIN_PAD_SZ)) {
|
|
USER_DEBUG(("Bad argument inLen to wc_RsaSSL_Sign\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* Set up needed pkcs v15 padding */
|
|
if (wc_RsaPad(in, inLen, out, sz, RSA_BLOCK_TYPE_1, rng) != 0) {
|
|
USER_DEBUG(("RSA Padding error\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* tmp = intput to sign */
|
|
ret = init_bn(&tmp, sz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
ret = ippsSetOctString_BN(out, sz, tmp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsSetOctString_BN error of %s\n",
|
|
ippGetStatusString(ret)));
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* tmpP = tmp mod p */
|
|
ret = init_bn(&tmpP, sz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* tmpQ = tmp mod q */
|
|
ret = init_bn(&tmpQ, sz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* tmpa */
|
|
ret = init_bn(&tmpa, sz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* tmpb */
|
|
ret = init_bn(&tmpb, sz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* one : used for conversion from Montgomery to classical */
|
|
ret = init_bn(&one, sz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("init_BN error of %s\n", ippGetStatusString(ret)));
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
ret = ippsSetOctString_BN(o, 1, one);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsSetOctString_BN error of %s\n",
|
|
ippGetStatusString(ret)));
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/**
|
|
Set up Montgomery state
|
|
*/
|
|
ret = init_mont(&pMont, &pSz, key->pipp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("init_mont error of %s\n", ippGetStatusString(ret)));
|
|
if (pMont != NULL) {
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
}
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = init_mont(&qMont, &qSz, key->qipp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("init_mont error of %s\n", ippGetStatusString(ret)));
|
|
if (qMont != NULL) {
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
}
|
|
ForceZero(pMont, pSz);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/**
|
|
Check and reduce input
|
|
This is needed for calls to MontExp since required value of a < modulus
|
|
*/
|
|
ret = reduce(tmp, key->pipp, tmpP);
|
|
if (ret != ippStsNoErr)
|
|
{
|
|
USER_DEBUG(("reduce error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = reduce(tmp, key->qipp, tmpQ);
|
|
if (ret != ippStsNoErr)
|
|
{
|
|
USER_DEBUG(("reduce error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* tmpa = (tmp mod p)^dP mod p */
|
|
ret = exptmod(tmpP, key->dPipp, pMont, tmpa, one);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("exptmod error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* tmpb = (tmp mod q)^dQ mod q */
|
|
ret = exptmod(tmpQ, key->dQipp, qMont, tmpb, one);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("exptmod error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* tmp = (tmpa - tmpb) * qInv (mod p) */
|
|
ret = ippsSub_BN(tmpa, tmpb, tmp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsSub_BN error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
ret = ippsMul_BN(tmp, key->uipp, tmp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsMul_BN error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* mod performed the same was as wolfSSL fp_mod -- tmpa is just scratch */
|
|
ret = ippsDiv_BN(tmp, key->pipp, tmpa, tmp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsDiv_BN error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* Check sign of values and perform conditional add */
|
|
ret = ippsExtGet_BN(&sa, NULL, NULL, tmp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsExtGet_BN error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
ret = ippsExtGet_BN(&sb, NULL, NULL, key->pipp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsExtGet_BN error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
if (sa != sb) {
|
|
ret = ippsAdd_BN(tmp, key->pipp, tmp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsAdd_BN error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
}
|
|
|
|
/* tmp = tmpb + q * tmp */
|
|
ret = ippsMul_BN(tmp, key->qipp, tmp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsSub_BN error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
|
|
ret = ippsAdd_BN(tmp, tmpb, tmp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsSub_BN error of %s\n", ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* Extract the output */
|
|
ret = ippsGetOctString_BN(out, sz, tmp);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetOctString_BN error of %s\n",
|
|
ippGetStatusString(ret)));
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
outSz = sz;
|
|
|
|
/* clear memory and free */
|
|
ForceZero(pMont, pSz);
|
|
ForceZero(qMont, qSz);
|
|
XFREE(qMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pMont, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
FreeSignHelper(one, tmp, tmpP, tmpQ, tmpa, tmpb);
|
|
|
|
return outSz;
|
|
}
|
|
|
|
|
|
int wc_RsaEncryptSize(RsaKey* key)
|
|
{
|
|
if (key == NULL)
|
|
return 0;
|
|
|
|
return key->sz;
|
|
}
|
|
|
|
|
|
/* flatten RsaKey structure into individual elements (e, n) */
|
|
int wc_RsaFlattenPublicKey(RsaKey* key, byte* e, word32* eSz, byte* n,
|
|
word32* nSz)
|
|
{
|
|
int sz, bytSz;
|
|
IppStatus ret;
|
|
|
|
USER_DEBUG(("Entering wc_RsaFlattenPublicKey\n"));
|
|
|
|
if (key == NULL || e == NULL || eSz == NULL || n == NULL || nSz == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
bytSz = sizeof(byte) * 8;
|
|
ret = ippsExtGet_BN(NULL, &sz, NULL, key->e);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* sz is in bits change to bytes */
|
|
sz = (sz / bytSz) + ((sz % bytSz)? 1 : 0);
|
|
|
|
if (*eSz < (word32)sz)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsGetOctString_BN(e, sz, key->e);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
*eSz = (word32)sz;
|
|
|
|
/* flatten n */
|
|
ret = ippsExtGet_BN(NULL, &sz, NULL, key->n);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* sz is in bits change to bytes */
|
|
sz = (sz / bytSz) + ((sz % bytSz)? 1: 0);
|
|
|
|
if (*nSz < (word32)sz)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
ret = ippsGetOctString_BN(n, sz, key->n);
|
|
if (ret != ippStsNoErr)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
*nSz = (word32)sz;
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
IppStatus wolfSSL_rng(Ipp32u* pData, int nBits, void* pEbsParams);
|
|
IppStatus wolfSSL_rng(Ipp32u* pData, int nBits, void* pEbsParams)
|
|
{
|
|
int nBytes;
|
|
|
|
if (pData == NULL) {
|
|
USER_DEBUG(("error with wolfSSL_rng argument\n"));
|
|
return ippStsErr;
|
|
}
|
|
|
|
nBytes = (nBits/8) + ((nBits % 8)? 1: 0);
|
|
if (wc_RNG_GenerateBlock((WC_RNG*)pEbsParams, (byte*)pData, nBytes) != 0) {
|
|
USER_DEBUG(("error in generating random wolfSSL block\n"));
|
|
return ippStsErr;
|
|
}
|
|
|
|
return ippStsNoErr;
|
|
}
|
|
|
|
|
|
#ifdef WOLFSSL_KEY_GEN
|
|
/* Make an RSA key for size bits, with e specified, 65537 is a good e */
|
|
int wc_MakeRsaKey(RsaKey* key, int size, long e, WC_RNG* rng)
|
|
{
|
|
IppStatus ret;
|
|
int scratchSz;
|
|
int i; /* for trys on calling make key */
|
|
int ctxSz;
|
|
|
|
IppsBigNumState* pSrcPublicExp = NULL;
|
|
Ipp8u* scratchBuffer = NULL;
|
|
Ipp8u eAry[8];
|
|
int trys = 8; /* Miller-Rabin test parameter */
|
|
IppsPrimeState* pPrime = NULL;
|
|
|
|
int qBitSz; /* size of q factor */
|
|
int bytSz; /* size of key in bytes */
|
|
int leng;
|
|
|
|
USER_DEBUG(("Entering wc_MakeRsaKey\n"));
|
|
|
|
/* get byte size and individual private key size -- round up */
|
|
qBitSz = (size / 2) + ((size % 2)? 1: 0);
|
|
bytSz = (size / 8) + ((size % 8)? 1: 0);
|
|
|
|
if (key == NULL || rng == NULL) {
|
|
USER_DEBUG(("Error, NULL argument passed in\n"));
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
if (e < 3 || (e&1) == 0)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (size > RSA_MAX_SIZE || size < RSA_MIN_SIZE)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
key->type = RSA_PRIVATE;
|
|
key->sz = bytSz;
|
|
|
|
/* initialize prime number */
|
|
ret = ippsPrimeGetSize(size, &ctxSz); /* size in bits */
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsPrimeGetSize error of %s\n", ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
pPrime = (IppsPrimeState*)XMALLOC(ctxSz, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (pPrime == NULL) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
ret = ippsPrimeInit(size, pPrime);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsPrimeInit error of %s\n", ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* define RSA privete key type 2 */
|
|
/* length in bits of p and q factors */
|
|
ret = ippsRSA_GetSizePrivateKeyType2(qBitSz, qBitSz, &ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetSizePrivateKeyType2 error of %s\n",
|
|
ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
key->prvSz = ctxSz; /* used when freeing private key */
|
|
key->pPrv = (IppsRSAPrivateKeyState*)XMALLOC(ctxSz, NULL,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (key->pPrv == NULL) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* length in bits of p and q factors */
|
|
ret = ippsRSA_InitPrivateKeyType2(qBitSz, qBitSz, key->pPrv, ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_InitPrivateKeyType2 error of %s\n",
|
|
ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* allocate scratch buffer */
|
|
ret = ippsRSA_GetBufferSizePrivateKey(&scratchSz, key->pPrv);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetBufferSizePrivateKey error of %s\n",
|
|
ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
scratchBuffer = (Ipp8u*)XMALLOC(scratchSz, 0, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (scratchBuffer == NULL) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* set up initial value of pScrPublicExp */
|
|
leng = (int)sizeof(long); /* # of Ipp32u in long */
|
|
|
|
/* place the value of e into the array eAry then load into BN */
|
|
for (i = 0; i < leng; i++) {
|
|
eAry[i] = (e >> (8 * (leng - 1 - i))) & 0XFF;
|
|
}
|
|
ret = init_bn(&pSrcPublicExp, leng);
|
|
if (ret != ippStsNoErr) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
ret = ippsSetOctString_BN(eAry, leng, pSrcPublicExp);
|
|
if (ret != ippStsNoErr) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* initializing key->n */
|
|
ret = init_bn(&key->n, bytSz);
|
|
if (ret != ippStsNoErr) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* initializing public exponent key->e */
|
|
ret = init_bn(&key->e, leng);
|
|
if (ret != ippStsNoErr) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* private exponent key->dipp */
|
|
ret = init_bn(&key->dipp, bytSz);
|
|
if (ret != ippStsNoErr) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* call IPP to generate keys, if inseficent entropy error call again */
|
|
ret = ippStsInsufficientEntropy;
|
|
while (ret == ippStsInsufficientEntropy) {
|
|
ret = ippsRSA_GenerateKeys(pSrcPublicExp, key->n, key->e,
|
|
key->dipp, key->pPrv, scratchBuffer, trys, pPrime,
|
|
wolfSSL_rng, rng);
|
|
if (ret == ippStsNoErr) {
|
|
break;
|
|
}
|
|
|
|
/* catch all errors other than entropy error */
|
|
if (ret != ippStsInsufficientEntropy) {
|
|
USER_DEBUG(("ippsRSA_GeneratKeys error of %s\n",
|
|
ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
}
|
|
|
|
/* get bn sizes needed for private key set up */
|
|
ret = ippsExtGet_BN(NULL, &key->eSz, NULL, key->e);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
ret = ippsExtGet_BN(NULL, &key->nSz, NULL, key->n);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsGetSize_BN error %s\n", ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* set up public key state */
|
|
ret = ippsRSA_GetSizePublicKey(key->nSz, key->eSz, &ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetSizePublicKey error %s nSz = %d eSz = %d\n",
|
|
ippGetStatusString(ret), key->nSz, key->eSz));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
key->pPub = (IppsRSAPublicKeyState*)XMALLOC(ctxSz, NULL,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (key->pPub == NULL) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
ret = ippsRSA_InitPublicKey(key->nSz, key->eSz, key->pPub, ctxSz);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_InitPublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
ret = ippsRSA_SetPublicKey(key->n, key->e, key->pPub);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_SetPublicKey error %s\n",
|
|
ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* get private key information for key struct */
|
|
leng = size/16; /* size of q, p, u, dP, dQ */
|
|
ret = init_bn(&key->pipp, leng);
|
|
if (ret != ippStsNoErr) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* set up q BN for key */
|
|
ret = init_bn(&key->qipp, leng);
|
|
if (ret != ippStsNoErr) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* set up dP BN for key */
|
|
ret = init_bn(&key->dPipp, leng);
|
|
if (ret != ippStsNoErr) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* set up dQ BN for key */
|
|
ret = init_bn(&key->dQipp, leng);
|
|
if (ret != ippStsNoErr) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* set up u BN for key */
|
|
ret = init_bn(&key->uipp, leng);
|
|
if (ret != ippStsNoErr) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
|
|
/* get values from created key */
|
|
ret = ippsRSA_GetPrivateKeyType2(key->pipp, key->qipp, key->dPipp,
|
|
key->dQipp, key->uipp, key->pPrv);
|
|
if (ret != ippStsNoErr) {
|
|
USER_DEBUG(("ippsRSA_GetPrivateKeyType2 error %s\n",
|
|
ippGetStatusString(ret)));
|
|
ret = USER_CRYPTO_ERROR;
|
|
goto makeKeyEnd;
|
|
}
|
|
ret = 0; /* success case */
|
|
|
|
makeKeyEnd:
|
|
/* clean up memory used */
|
|
XFREE(pSrcPublicExp, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(scratchBuffer, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(pPrime, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
|
|
if (ret != 0) { /* with fail case free RSA components created */
|
|
wc_FreeRsaKey(key);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
/********** duplicate code needed -- future refactor */
|
|
#define MAX_VERSION_SZ 5
|
|
#define MAX_SEQ_SZ 5
|
|
#define ASN_CONTEXT_SPECIFIC 0x80
|
|
#define ASN_CONSTRUCTED 0x20
|
|
#define ASN_LONG_LENGTH 0x80
|
|
#define ASN_SEQUENCE 0x10
|
|
#define RSA_INTS 8
|
|
#define FALSE 0
|
|
#define TRUE 1
|
|
|
|
#define MAX_LENGTH_SZ 4
|
|
#define RSAk 645
|
|
#define keyType 2
|
|
#define MAX_RSA_INT_SZ 517
|
|
#define MAX_RSA_E_SZ 16
|
|
#define MAX_ALGO_SZ 20
|
|
|
|
static word32 BytePrecision(word32 value)
|
|
{
|
|
word32 i;
|
|
for (i = sizeof(value); i; --i)
|
|
if (value >> ((i - 1) * WOLFSSL_BIT_SIZE))
|
|
break;
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
static int SetMyVersion(word32 version, byte* output, int header)
|
|
{
|
|
int i = 0;
|
|
|
|
if (output == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (header) {
|
|
output[i++] = ASN_CONTEXT_SPECIFIC | ASN_CONSTRUCTED;
|
|
output[i++] = ASN_BIT_STRING;
|
|
}
|
|
output[i++] = ASN_INTEGER;
|
|
output[i++] = 0x01;
|
|
output[i++] = (byte)version;
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
static word32 SetLength(word32 length, byte* output)
|
|
{
|
|
word32 i = 0, j;
|
|
|
|
if (length < 0x80)
|
|
output[i++] = (byte)length;
|
|
else {
|
|
output[i++] = (byte)(BytePrecision(length) | ASN_LONG_LENGTH);
|
|
|
|
for (j = BytePrecision(length); j; --j) {
|
|
output[i] = (byte)(length >> ((j - 1) * WOLFSSL_BIT_SIZE));
|
|
i++;
|
|
}
|
|
}
|
|
|
|
return i;
|
|
}
|
|
|
|
|
|
static word32 SetSequence(word32 len, byte* output)
|
|
{
|
|
output[0] = ASN_SEQUENCE | ASN_CONSTRUCTED;
|
|
return SetLength(len, output + 1) + 1;
|
|
}
|
|
|
|
|
|
static word32 SetAlgoID(int algoOID, byte* output, int type, int curveSz)
|
|
{
|
|
/* adding TAG_NULL and 0 to end */
|
|
|
|
/* RSA keyType */
|
|
#ifndef NO_RSA
|
|
static const byte RSA_AlgoID[] = { 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
|
|
0x01, 0x01, 0x01, 0x05, 0x00};
|
|
#endif /* NO_RSA */
|
|
|
|
int algoSz = 0;
|
|
int tagSz = 2; /* tag null and terminator */
|
|
word32 idSz, seqSz;
|
|
const byte* algoName = 0;
|
|
byte ID_Length[MAX_LENGTH_SZ];
|
|
byte seqArray[MAX_SEQ_SZ + 1]; /* add object_id to end */
|
|
|
|
if (type == keyType) { /* keyType */
|
|
switch (algoOID) {
|
|
#ifndef NO_RSA
|
|
case RSAk:
|
|
algoSz = sizeof(RSA_AlgoID);
|
|
algoName = RSA_AlgoID;
|
|
break;
|
|
#endif /* NO_RSA */
|
|
default:
|
|
/* unknown key algo */
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
/* unknown algo type */
|
|
return 0;
|
|
}
|
|
|
|
idSz = SetLength(algoSz - tagSz, ID_Length); /* don't include tags */
|
|
seqSz = SetSequence(idSz + algoSz + 1 + curveSz, seqArray);
|
|
/* +1 for object id, curveID of curveSz follows for ecc */
|
|
seqArray[seqSz++] = ASN_OBJECT_ID;
|
|
|
|
XMEMCPY(output, seqArray, seqSz);
|
|
XMEMCPY(output + seqSz, ID_Length, idSz);
|
|
XMEMCPY(output + seqSz + idSz, algoName, algoSz);
|
|
|
|
return seqSz + idSz + algoSz;
|
|
|
|
}
|
|
|
|
|
|
/* Write a public RSA key to output */
|
|
static int SetRsaPublicKey(byte* output, RsaKey* key,
|
|
int outLen, int with_header)
|
|
{
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* n = NULL;
|
|
byte* e = NULL;
|
|
#else
|
|
byte n[MAX_RSA_INT_SZ];
|
|
byte e[MAX_RSA_E_SZ];
|
|
#endif
|
|
byte seq[MAX_SEQ_SZ];
|
|
byte len[MAX_LENGTH_SZ + 1]; /* trailing 0 */
|
|
int nSz;
|
|
int eSz;
|
|
int seqSz;
|
|
int lenSz;
|
|
int idx;
|
|
int rawLen;
|
|
int leadingBit;
|
|
int err;
|
|
|
|
if (output == NULL || key == NULL || outLen < MAX_SEQ_SZ)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
/* n */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
n = (byte*)XMALLOC(MAX_RSA_INT_SZ, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (n == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
#endif
|
|
|
|
leadingBit = wc_Rsa_leading_bit(key->n);
|
|
rawLen = wc_Rsa_unsigned_bin_size(key->n);
|
|
if ((int)rawLen < 0) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
rawLen = rawLen + leadingBit;
|
|
n[0] = ASN_INTEGER;
|
|
nSz = SetLength(rawLen, n + 1) + 1; /* int tag */
|
|
|
|
if ( (nSz + rawLen) < MAX_RSA_INT_SZ) {
|
|
if (leadingBit)
|
|
n[nSz] = 0;
|
|
err = ippsGetOctString_BN((Ipp8u*)n + nSz, rawLen - leadingBit, key->n);
|
|
if (err == ippStsNoErr)
|
|
nSz += rawLen;
|
|
else {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
#endif
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
}
|
|
else {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
#endif
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* e */
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
e = (byte*)XMALLOC(MAX_RSA_E_SZ, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (e == NULL) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
#endif
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
#endif
|
|
|
|
leadingBit = wc_Rsa_leading_bit(key->e);
|
|
rawLen = wc_Rsa_unsigned_bin_size(key->e);
|
|
if ((int)rawLen < 0) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
rawLen = rawLen + leadingBit;
|
|
e[0] = ASN_INTEGER;
|
|
eSz = SetLength(rawLen, e + 1) + 1; /* int tag */
|
|
|
|
if ( (eSz + rawLen) < MAX_RSA_E_SZ) {
|
|
if (leadingBit)
|
|
e[eSz] = 0;
|
|
err = ippsGetOctString_BN((Ipp8u*)e + eSz, rawLen - leadingBit, key->e);
|
|
if (err == ippStsNoErr)
|
|
eSz += rawLen;
|
|
else {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
#endif
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
}
|
|
else {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
#endif
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
seqSz = SetSequence(nSz + eSz, seq);
|
|
|
|
/* check output size */
|
|
if ( (seqSz + nSz + eSz) > outLen) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
#endif
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* headers */
|
|
if (with_header) {
|
|
int algoSz;
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
byte* algo = NULL;
|
|
|
|
algo = (byte*)XMALLOC(MAX_ALGO_SZ, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (algo == NULL) {
|
|
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
#else
|
|
byte algo[MAX_ALGO_SZ];
|
|
#endif
|
|
algoSz = SetAlgoID(RSAk, algo, keyType, 0);
|
|
lenSz = SetLength(seqSz + nSz + eSz + 1, len);
|
|
len[lenSz++] = 0; /* trailing 0 */
|
|
|
|
/* write, 1 is for ASN_BIT_STRING */
|
|
idx = SetSequence(nSz + eSz + seqSz + lenSz + 1 + algoSz, output);
|
|
|
|
/* check output size */
|
|
if ( (idx + algoSz + 1 + lenSz + seqSz + nSz + eSz) > outLen) {
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(algo, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
#endif
|
|
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* algo */
|
|
XMEMCPY(output + idx, algo, algoSz);
|
|
idx += algoSz;
|
|
/* bit string */
|
|
output[idx++] = ASN_BIT_STRING;
|
|
/* length */
|
|
XMEMCPY(output + idx, len, lenSz);
|
|
idx += lenSz;
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(algo, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
#endif
|
|
}
|
|
else
|
|
idx = 0;
|
|
|
|
/* seq */
|
|
XMEMCPY(output + idx, seq, seqSz);
|
|
idx += seqSz;
|
|
/* n */
|
|
XMEMCPY(output + idx, n, nSz);
|
|
idx += nSz;
|
|
/* e */
|
|
XMEMCPY(output + idx, e, eSz);
|
|
idx += eSz;
|
|
|
|
#ifdef WOLFSSL_SMALL_STACK
|
|
XFREE(n, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
XFREE(e, NULL, DYNAMIC_TYPE_USER_CRYPTO);
|
|
#endif
|
|
|
|
return idx;
|
|
}
|
|
|
|
|
|
static IppsBigNumState* GetRsaInt(RsaKey* key, int idx)
|
|
{
|
|
if (idx == 0)
|
|
return key->n;
|
|
if (idx == 1)
|
|
return key->e;
|
|
if (idx == 2)
|
|
return key->dipp;
|
|
if (idx == 3)
|
|
return key->pipp;
|
|
if (idx == 4)
|
|
return key->qipp;
|
|
if (idx == 5)
|
|
return key->dPipp;
|
|
if (idx == 6)
|
|
return key->dQipp;
|
|
if (idx == 7)
|
|
return key->uipp;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/* Release Tmp RSA resources */
|
|
static INLINE void FreeTmpRsas(byte** tmps, void* heap)
|
|
{
|
|
int i;
|
|
|
|
(void)heap;
|
|
|
|
for (i = 0; i < RSA_INTS; i++)
|
|
XFREE(tmps[i], heap, DYNAMIC_TYPE_USER_CRYPTO);
|
|
}
|
|
|
|
|
|
/* Convert RsaKey key to DER format, write to output (inLen), return bytes
|
|
written */
|
|
int wc_RsaKeyToDer(RsaKey* key, byte* output, word32 inLen)
|
|
{
|
|
word32 seqSz, verSz, rawLen, intTotalLen = 0;
|
|
word32 sizes[RSA_INTS];
|
|
int i, j, outLen, ret = 0, lbit;
|
|
|
|
byte seq[MAX_SEQ_SZ];
|
|
byte ver[MAX_VERSION_SZ];
|
|
byte* tmps[RSA_INTS];
|
|
|
|
USER_DEBUG(("Entering RsaKeyToDer\n"));
|
|
|
|
if (!key || !output)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
if (key->type != RSA_PRIVATE)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
for (i = 0; i < RSA_INTS; i++)
|
|
tmps[i] = NULL;
|
|
|
|
/* write all big ints from key to DER tmps */
|
|
for (i = 0; i < RSA_INTS; i++) {
|
|
Ipp32u isZero;
|
|
IppsBigNumState* keyInt = GetRsaInt(key, i);
|
|
|
|
ippsCmpZero_BN(keyInt, &isZero); /* makes isZero 0 if true */
|
|
rawLen = wc_Rsa_unsigned_bin_size(keyInt);
|
|
if ((int)rawLen < 0) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* leading zero */
|
|
if (!isZero || wc_Rsa_leading_bit(keyInt))
|
|
lbit = 1;
|
|
else
|
|
lbit = 0;
|
|
|
|
rawLen += lbit;
|
|
|
|
tmps[i] = (byte*)XMALLOC(rawLen + MAX_SEQ_SZ, key->heap,
|
|
DYNAMIC_TYPE_USER_CRYPTO);
|
|
if (tmps[i] == NULL) {
|
|
ret = USER_CRYPTO_ERROR;
|
|
break;
|
|
}
|
|
|
|
tmps[i][0] = ASN_INTEGER;
|
|
sizes[i] = SetLength(rawLen, tmps[i] + 1) + 1 + lbit; /* tag & lbit */
|
|
|
|
if (sizes[i] <= MAX_SEQ_SZ) {
|
|
int err;
|
|
|
|
/* leading zero */
|
|
if (lbit)
|
|
tmps[i][sizes[i]-1] = 0x00;
|
|
|
|
/* extract data*/
|
|
err = ippsGetOctString_BN((Ipp8u*)(tmps[i] + sizes[i]),
|
|
rawLen - lbit, keyInt);
|
|
if (err == ippStsOk) {
|
|
sizes[i] += (rawLen-lbit); /* lbit included in rawLen */
|
|
intTotalLen += sizes[i];
|
|
ret = 0;
|
|
}
|
|
else {
|
|
ret = USER_CRYPTO_ERROR;
|
|
USER_DEBUG(("ippsGetOctString_BN error %s\n",
|
|
ippGetStatusString(err)));
|
|
break;
|
|
}
|
|
}
|
|
else {
|
|
ret = USER_CRYPTO_ERROR;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ret != 0) {
|
|
FreeTmpRsas(tmps, key->heap);
|
|
return ret;
|
|
}
|
|
|
|
/* make headers */
|
|
verSz = SetMyVersion(0, ver, FALSE);
|
|
seqSz = SetSequence(verSz + intTotalLen, seq);
|
|
|
|
outLen = seqSz + verSz + intTotalLen;
|
|
if (outLen > (int)inLen) {
|
|
return USER_CRYPTO_ERROR;
|
|
}
|
|
|
|
/* write to output */
|
|
XMEMCPY(output, seq, seqSz);
|
|
j = seqSz;
|
|
XMEMCPY(output + j, ver, verSz);
|
|
j += verSz;
|
|
|
|
for (i = 0; i < RSA_INTS; i++) {
|
|
XMEMCPY(output + j, tmps[i], sizes[i]);
|
|
j += sizes[i];
|
|
}
|
|
FreeTmpRsas(tmps, key->heap);
|
|
|
|
return outLen;
|
|
}
|
|
|
|
|
|
/* Convert Rsa Public key to DER format, write to output (inLen), return bytes
|
|
written
|
|
*/
|
|
int wc_RsaKeyToPublicDer(RsaKey* key, byte* output, word32 inLen)
|
|
{
|
|
return SetRsaPublicKey(output, key, inLen, 1);
|
|
}
|
|
|
|
|
|
#endif /* WOLFSSL_KEY_GEN */
|
|
|
|
#ifdef WC_RSA_BLINDING
|
|
|
|
int wc_RsaSetRNG(RsaKey* key, WC_RNG* rng)
|
|
{
|
|
if (key == NULL)
|
|
return USER_CRYPTO_ERROR;
|
|
|
|
(void)rng;
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif /* WC_RSA_BLINDING */
|
|
|
|
#endif /* NO_RSA */
|
|
|