123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- /* rsa.c
- *
- * Copyright (C) 2006-2014 wolfSSL Inc.
- *
- * This file is part of CyaSSL.
- *
- * CyaSSL 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.
- *
- * CyaSSL 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-1301, USA
- */
- #include "rsa.h"
- #include "error-crypt.h"
- #include "api.h"
- #ifdef IN_PAL
- int _DkRandomBitsRead (void *buffer, int size);
- #define DkRandomBitsRead _DkRandomBitsRead
- #else
- int DkRandomBitsRead (void *buffer, int size);
- #endif
- void * malloc (int size);
- void free (void * mem);
- #define XMALLOC malloc
- #define XFREE free
- #define XMEMCPY memcpy
- #define XMEMSET memset
- 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,
- RSA_MIN_PAD_SZ = 11 /* seperator + 0 + pad value + 8 pads */
- };
- int InitRSAKey(RSAKey *key)
- {
- key->type = -1; /* haven't decided yet */
- key->n.dp = key->e.dp = 0; /* public alloc parts */
- key->d.dp = key->p.dp = 0; /* private alloc parts */
- key->q.dp = key->dP.dp = 0;
- key->u.dp = key->dQ.dp = 0;
- return 0;
- }
- int FreeRSAKey(RSAKey *key)
- {
- (void)key;
- if (key->type == RSA_PRIVATE) {
- mp_clear(&key->u);
- mp_clear(&key->dQ);
- mp_clear(&key->dP);
- mp_clear(&key->q);
- mp_clear(&key->p);
- mp_clear(&key->d);
- }
- mp_clear(&key->e);
- mp_clear(&key->n);
- return 0;
- }
- static int RSAPad(const byte *input, word32 inputLen, byte *pkcsBlock,
- word32 pkcsBlockLen, byte padValue)
- {
- if (inputLen == 0)
- return 0;
- pkcsBlock[0] = 0x0; /* set first byte to zero and advance */
- pkcsBlock++; pkcsBlockLen--;
- pkcsBlock[0] = padValue; /* insert padValue */
- if (padValue == RSA_BLOCK_TYPE_1)
- /* pad with 0xff bytes */
- XMEMSET(&pkcsBlock[1], 0xFF, pkcsBlockLen - inputLen - 2);
- else {
- /* pad with non-zero random bytes */
- word32 padLen = pkcsBlockLen - inputLen - 1, i;
- int ret = DkRandomBitsRead(&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 (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))
- return RSA_PAD_E;
- outputLen = pkcsBlockLen - i;
- invalid = (outputLen > maxOutputLen) || invalid;
- if (invalid)
- return RSA_PAD_E;
- *output = (byte *)(pkcsBlock + i);
- return outputLen;
- }
- static int RSAFunction(const byte *in, word32 inLen, byte *out, word32 *outLen,
- int type, RSAKey *key)
- {
- #define ERROR_OUT(x) { ret = (x); goto done;}
- mp_int tmp;
- int ret = 0;
- word32 keyLen, len;
- if (mp_init(&tmp) != MP_OKAY)
- return MP_INIT_E;
- if (mp_read_unsigned_bin(&tmp, (byte*)in, inLen) != MP_OKAY)
- ERROR_OUT(MP_READ_E);
- if (type == RSA_PRIVATE_DECRYPT || type == RSA_PRIVATE_ENCRYPT) {
- #define INNER_ERROR_OUT(x) { ret = (x); goto inner_done; }
- mp_int tmpa, tmpb;
- if (mp_init(&tmpa) != MP_OKAY)
- ERROR_OUT(MP_INIT_E);
- if (mp_init(&tmpb) != MP_OKAY) {
- mp_clear(&tmpa);
- ERROR_OUT(MP_INIT_E);
- }
- /* tmpa = tmp^dP mod p */
- if (mp_exptmod(&tmp, &key->dP, &key->p, &tmpa) != MP_OKAY)
- INNER_ERROR_OUT(MP_EXPTMOD_E);
- /* tmpb = tmp^dQ mod q */
- if (mp_exptmod(&tmp, &key->dQ, &key->q, &tmpb) != MP_OKAY)
- INNER_ERROR_OUT(MP_EXPTMOD_E);
- /* tmp = (tmpa - tmpb) *qInv (mod p) */
- if (mp_sub(&tmpa, &tmpb, &tmp) != MP_OKAY)
- INNER_ERROR_OUT(MP_SUB_E);
- if (mp_mulmod(&tmp, &key->u, &key->p, &tmp) != MP_OKAY)
- INNER_ERROR_OUT(MP_MULMOD_E);
- /* tmp = tmpb + q *tmp */
- if (mp_mul(&tmp, &key->q, &tmp) != MP_OKAY)
- INNER_ERROR_OUT(MP_MUL_E);
- if (mp_add(&tmp, &tmpb, &tmp) != MP_OKAY)
- INNER_ERROR_OUT(MP_ADD_E);
- inner_done:
- mp_clear(&tmpa);
- mp_clear(&tmpb);
- if (ret != 0) return ret;
- }
- else if (type == RSA_PUBLIC_ENCRYPT || type == RSA_PUBLIC_DECRYPT) {
- if (mp_exptmod(&tmp, &key->e, &key->n, &tmp) != MP_OKAY)
- ERROR_OUT(MP_EXPTMOD_E);
- }
- else
- ERROR_OUT(RSA_WRONG_TYPE_E);
- keyLen = mp_unsigned_bin_size(&key->n);
- if (keyLen > *outLen)
- ERROR_OUT(RSA_BUFFER_E);
- len = mp_unsigned_bin_size(&tmp);
- /* pad front w/ zeros to match key length */
- while (len < keyLen) {
- *out++ = 0x00;
- len++;
- }
- *outLen = keyLen;
- /* convert */
- if (mp_to_unsigned_bin(&tmp, out) != MP_OKAY)
- ERROR_OUT(MP_TO_E);
- done:
- mp_clear(&tmp);
- return ret;
- }
- int RSAPublicEncrypt(const byte *in, word32 inLen, byte *out, word32 outLen,
- RSAKey *key)
- {
- int sz, ret;
- sz = mp_unsigned_bin_size(&key->n);
- if (sz > (int)outLen)
- return RSA_BUFFER_E;
- if (inLen > (word32)(sz - RSA_MIN_PAD_SZ))
- return RSA_BUFFER_E;
- ret = RSAPad(in, inLen, out, sz, RSA_BLOCK_TYPE_2);
- if (ret != 0)
- return ret;
- if ((ret = RSAFunction(out, sz, out, &outLen, RSA_PUBLIC_ENCRYPT, key)) < 0)
- sz = ret;
- return sz;
- }
- int RSAPrivateDecryptInline(byte *in, word32 inLen, byte* *out, RSAKey *key)
- {
- int ret;
- if ((ret = RSAFunction(in, inLen, in, &inLen, RSA_PRIVATE_DECRYPT, key))
- < 0) {
- return ret;
- }
- return RSAUnPad(in, inLen, out, RSA_BLOCK_TYPE_2);
- }
- int RSAPrivateDecrypt(const byte *in, word32 inLen, byte *out, word32 outLen,
- RSAKey *key)
- {
- int plainLen;
- byte *tmp;
- byte *pad = 0;
- tmp = (byte *)XMALLOC(inLen);
- if (tmp == NULL) {
- return MEMORY_E;
- }
- XMEMCPY(tmp, in, inLen);
- if ( (plainLen = RSAPrivateDecryptInline(tmp, inLen, &pad, key) ) < 0) {
- XFREE(tmp);
- return plainLen;
- }
- if (plainLen > (int)outLen)
- plainLen = BAD_FUNC_ARG;
- else
- XMEMCPY(out, pad, plainLen);
- XMEMSET(tmp, 0x00, inLen);
- XFREE(tmp);
- return plainLen;
- }
- /* for RSA Verify */
- int RSASSL_VerifyInline(byte *in, word32 inLen, byte* *out, RSAKey *key)
- {
- int ret;
- if ((ret = RSAFunction(in, inLen, in, &inLen, RSA_PUBLIC_DECRYPT, key))
- < 0) {
- return ret;
- }
- return RSAUnPad(in, inLen, out, RSA_BLOCK_TYPE_1);
- }
- int RSASSL_Verify(const byte *in, word32 inLen, byte *out, word32 outLen,
- RSAKey *key)
- {
- int plainLen;
- byte *tmp;
- byte *pad = 0;
- tmp = (byte *)XMALLOC(inLen);
- if (tmp == NULL) {
- return MEMORY_E;
- }
- XMEMCPY(tmp, in, inLen);
- if ( (plainLen = RSASSL_VerifyInline(tmp, inLen, &pad, key) ) < 0) {
- XFREE(tmp);
- return plainLen;
- }
- if (plainLen > (int)outLen)
- plainLen = BAD_FUNC_ARG;
- else
- XMEMCPY(out, pad, plainLen);
- XMEMSET(tmp, 0x00, inLen);
- XFREE(tmp);
- return plainLen;
- }
- /* for RSA Sign */
- int RSASSL_Sign(const byte *in, word32 inLen, byte *out, word32 outLen,
- RSAKey *key)
- {
- int sz, ret;
- sz = mp_unsigned_bin_size(&key->n);
- if (sz > (int)outLen)
- return RSA_BUFFER_E;
- if (inLen > (word32)(sz - RSA_MIN_PAD_SZ))
- return RSA_BUFFER_E;
- ret = RSAPad(in, inLen, out, sz, RSA_BLOCK_TYPE_1);
- if (ret != 0)
- return ret;
- if ((ret = RSAFunction(out, sz, out, &outLen, RSA_PRIVATE_ENCRYPT,key)) < 0)
- sz = ret;
- return sz;
- }
- int RSAEncryptSize(RSAKey *key)
- {
- return mp_unsigned_bin_size(&key->n);
- }
- int RSAPublicKeyDecodeRaw(const byte* n, word32 nSz, const byte* e, word32 eSz,
- RSAKey* key)
- {
- if (n == NULL || e == NULL || key == NULL)
- return BAD_FUNC_ARG;
- key->type = RSA_PUBLIC;
- if (mp_init(&key->n) != MP_OKAY)
- return MP_INIT_E;
- if (mp_read_unsigned_bin(&key->n, n, nSz) != 0) {
- mp_clear(&key->n);
- return ASN_GETINT_E;
- }
- if (mp_init(&key->e) != MP_OKAY) {
- mp_clear(&key->n);
- return MP_INIT_E;
- }
- if (mp_read_unsigned_bin(&key->e, e, eSz) != 0) {
- mp_clear(&key->n);
- mp_clear(&key->e);
- return ASN_GETINT_E;
- }
- return 0;
- }
- int RSAFlattenPublicKey(RSAKey *key, byte *e, word32 *eSz, byte *n, word32 *nSz)
- {
- int sz, ret;
- if (key == NULL || e == NULL || eSz == NULL || n == NULL || nSz == NULL)
- return BAD_FUNC_ARG;
- sz = mp_unsigned_bin_size(&key->e);
- if ((word32)sz > *nSz)
- return RSA_BUFFER_E;
- ret = mp_to_unsigned_bin(&key->e, e);
- if (ret != MP_OKAY)
- return ret;
- *eSz = (word32)sz;
- sz = mp_unsigned_bin_size(&key->n);
- if ((word32)sz > *nSz)
- return RSA_BUFFER_E;
- ret = mp_to_unsigned_bin(&key->n, n);
- if (ret != MP_OKAY)
- return ret;
- *nSz = (word32)sz;
- return 0;
- }
- static int rand_prime(mp_int *N, int len)
- {
- int err, res;
- byte *buf;
- if (N == NULL)
- return BAD_FUNC_ARG;
- /* allow sizes between 2 and 512 bytes for a prime size */
- if (len < 2 || len > 512) {
- return BAD_FUNC_ARG;
- }
- /* allocate buffer to work with */
- buf = (byte*)XMALLOC(len);
- if (buf == NULL) {
- return MEMORY_E;
- }
- XMEMSET(buf, 0, len);
- do {
- /* generate value */
- err = DkRandomBitsRead(buf, len);
- if (err < 0) {
- XFREE(buf);
- return err;
- }
- /* munge bits */
- buf[0] |= 0x80 | 0x40;
- buf[len-1] |= 0x01;
- /* load value */
- if ((err = mp_read_unsigned_bin(N, buf, len)) != MP_OKAY) {
- XFREE(buf);
- return err;
- }
- /* test */
- if ((err = mp_prime_is_prime(N, 8, &res)) != MP_OKAY) {
- XFREE(buf);
- return err;
- }
- } while (res == MP_NO);
- XMEMSET(buf, 0, len);
- XFREE(buf);
- return 0;
- }
- /* Make an RSA key for size bits, with e specified, 65537 is a good e */
- int MakeRSAKey(RSAKey *key, int size, long e)
- {
- mp_int p, q, tmp1, tmp2, tmp3;
- int err;
- if (key == NULL)
- return BAD_FUNC_ARG;
- if (size < RSA_MIN_SIZE || size > RSA_MAX_SIZE)
- return BAD_FUNC_ARG;
- if (e < 3 || (e & 1) == 0)
- return BAD_FUNC_ARG;
- if ((err = mp_init_multi(&p, &q, &tmp1, &tmp2, &tmp3, NULL)) != MP_OKAY)
- return err;
- err = mp_set_int(&tmp3, e);
- /* make p */
- if (err == MP_OKAY) {
- do {
- err = rand_prime(&p, size/16); /* size in bytes/2 */
- if (err == MP_OKAY)
- err = mp_sub_d(&p, 1, &tmp1); /* tmp1 = p-1 */
- if (err == MP_OKAY)
- err = mp_gcd(&tmp1, &tmp3, &tmp2); /* tmp2 = gcd(p-1, e) */
- } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0); /* e divdes p-1 */
- }
- /* make q */
- if (err == MP_OKAY) {
- do {
- err = rand_prime(&q, size/16); /* size in bytes/2 */
- if (err == MP_OKAY)
- err = mp_sub_d(&q, 1, &tmp1); /* tmp1 = q-1 */
- if (err == MP_OKAY)
- err = mp_gcd(&tmp1, &tmp3, &tmp2); /* tmp2 = gcd(q-1, e) */
- } while (err == MP_OKAY && mp_cmp_d(&tmp2, 1) != 0); /* e divdes q-1 */
- }
- if (err == MP_OKAY)
- err = mp_init_multi(&key->n, &key->e, &key->d, &key->p, &key->q, NULL);
- if (err == MP_OKAY)
- err = mp_init_multi(&key->dP, &key->dQ, &key->u, NULL, NULL, NULL);
- if (err == MP_OKAY)
- err = mp_sub_d(&p, 1, &tmp2); /* tmp2 = p-1 */
- if (err == MP_OKAY)
- err = mp_lcm(&tmp1, &tmp2, &tmp1); /* tmp1 = lcm(p-1, q-1),last loop */
- /* make key */
- if (err == MP_OKAY)
- err = mp_set_int(&key->e, e); /* key->e = e */
- if (err == MP_OKAY) /* key->d = 1/e mod lcm(p-1, q-1) */
- err = mp_invmod(&key->e, &tmp1, &key->d);
- if (err == MP_OKAY)
- err = mp_mul(&p, &q, &key->n); /* key->n = pq */
- if (err == MP_OKAY)
- err = mp_sub_d(&p, 1, &tmp1);
- if (err == MP_OKAY)
- err = mp_sub_d(&q, 1, &tmp2);
- if (err == MP_OKAY)
- err = mp_mod(&key->d, &tmp1, &key->dP);
- if (err == MP_OKAY)
- err = mp_mod(&key->d, &tmp2, &key->dQ);
- if (err == MP_OKAY)
- err = mp_invmod(&q, &p, &key->u);
- if (err == MP_OKAY)
- err = mp_copy(&p, &key->p);
- if (err == MP_OKAY)
- err = mp_copy(&q, &key->q);
- if (err == MP_OKAY)
- key->type = RSA_PRIVATE;
- mp_clear(&tmp3);
- mp_clear(&tmp2);
- mp_clear(&tmp1);
- mp_clear(&q);
- mp_clear(&p);
- if (err != MP_OKAY) {
- FreeRSAKey(key);
- return err;
- }
- return 0;
- }
|