diff options
Diffstat (limited to 'FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/dsa.c')
-rw-r--r-- | FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/dsa.c | 808 |
1 files changed, 748 insertions, 60 deletions
diff --git a/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/dsa.c b/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/dsa.c index f2124b197..4b83a571d 100644 --- a/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/dsa.c +++ b/FreeRTOS-Plus/Source/WolfSSL/wolfcrypt/src/dsa.c @@ -1,8 +1,8 @@ /* dsa.c * - * Copyright (C) 2006-2015 wolfSSL Inc. + * Copyright (C) 2006-2020 wolfSSL Inc. * - * This file is part of wolfSSL. (formerly known as CyaSSL) + * 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 @@ -16,9 +16,10 @@ * * 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 + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif @@ -27,97 +28,703 @@ #ifndef NO_DSA -#include <wolfssl/wolfcrypt/dsa.h> -#include <wolfssl/wolfcrypt/sha.h> #include <wolfssl/wolfcrypt/random.h> +#include <wolfssl/wolfcrypt/integer.h> #include <wolfssl/wolfcrypt/error-crypt.h> +#include <wolfssl/wolfcrypt/logging.h> +#include <wolfssl/wolfcrypt/sha.h> +#include <wolfssl/wolfcrypt/dsa.h> +#ifdef NO_INLINE + #include <wolfssl/wolfcrypt/misc.h> +#else + #define WOLFSSL_MISC_INCLUDED + #include <wolfcrypt/src/misc.c> +#endif -enum { - DSA_HALF_SIZE = 20, /* r and s size */ - DSA_SIG_SIZE = 40 /* signature size */ -}; - - -#ifndef WOLFSSL_HAVE_MIN -#define WOLFSSL_HAVE_MIN - - static INLINE word32 min(word32 a, word32 b) - { - return a > b ? b : a; - } +int wc_InitDsaKey(DsaKey* key) +{ + if (key == NULL) + return BAD_FUNC_ARG; -#endif /* WOLFSSL_HAVE_MIN */ + key->type = -1; /* haven't decided yet */ + key->heap = NULL; + + return mp_init_multi( + /* public alloc parts */ + &key->p, + &key->q, + &key->g, + &key->y, + + /* private alloc parts */ + &key->x, + NULL + ); +} -void wc_InitDsaKey(DsaKey* key) +int wc_InitDsaKey_h(DsaKey* key, void* h) { - key->type = -1; /* haven't decided yet */ - -/* TomsFastMath doesn't use memory allocation */ -#ifndef USE_FAST_MATH - key->p.dp = 0; /* public alloc parts */ - key->q.dp = 0; - key->g.dp = 0; - key->y.dp = 0; + int ret = wc_InitDsaKey(key); + if (ret == 0) + key->heap = h; - key->x.dp = 0; /* private alloc parts */ -#endif + return ret; } void wc_FreeDsaKey(DsaKey* key) { - (void)key; -/* TomsFastMath doesn't use memory allocation */ -#ifndef USE_FAST_MATH + if (key == NULL) + return; + if (key->type == DSA_PRIVATE) - mp_clear(&key->x); + mp_forcezero(&key->x); + + mp_clear(&key->x); mp_clear(&key->y); mp_clear(&key->g); mp_clear(&key->q); mp_clear(&key->p); -#endif } -int wc_DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng) +/* validate that (L,N) match allowed sizes from FIPS 186-4, Section 4.2. + * modLen - represents L, the size of p (prime modulus) in bits + * divLen - represents N, the size of q (prime divisor) in bits + * return 0 on success, -1 on error */ +static int CheckDsaLN(int modLen, int divLen) +{ + int ret = -1; + + switch (modLen) { + case 1024: + if (divLen == 160) + ret = 0; + break; + case 2048: + if (divLen == 224 || divLen == 256) + ret = 0; + break; + case 3072: + if (divLen == 256) + ret = 0; + break; + default: + break; + } + + return ret; +} + + +#ifdef WOLFSSL_KEY_GEN + +/* Create DSA key pair (&dsa->x, &dsa->y) + * + * Based on NIST FIPS 186-4, + * "B.1.1 Key Pair Generation Using Extra Random Bits" + * + * rng - pointer to initialized WC_RNG structure + * dsa - pointer to initialized DsaKey structure, will hold generated key + * + * return 0 on success, negative on error */ +int wc_MakeDsaKey(WC_RNG *rng, DsaKey *dsa) +{ + byte* cBuf; + int qSz, pSz, cSz, err; + mp_int tmpQ; + + if (rng == NULL || dsa == NULL) + return BAD_FUNC_ARG; + + qSz = mp_unsigned_bin_size(&dsa->q); + pSz = mp_unsigned_bin_size(&dsa->p); + + /* verify (L,N) pair bit lengths */ + if (CheckDsaLN(pSz * WOLFSSL_BIT_SIZE, qSz * WOLFSSL_BIT_SIZE) != 0) + return BAD_FUNC_ARG; + + /* generate extra 64 bits so that bias from mod function is negligible */ + cSz = qSz + (64 / WOLFSSL_BIT_SIZE); + cBuf = (byte*)XMALLOC(cSz, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (cBuf == NULL) { + return MEMORY_E; + } + + if ((err = mp_init_multi(&dsa->x, &dsa->y, &tmpQ, NULL, NULL, NULL)) + != MP_OKAY) { + XFREE(cBuf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + return err; + } + + do { + /* generate N+64 bits (c) from RBG into &dsa->x, making sure positive. + * Hash_DRBG uses SHA-256 which matches maximum + * requested_security_strength of (L,N) */ + err = wc_RNG_GenerateBlock(rng, cBuf, cSz); + if (err != MP_OKAY) { + mp_clear(&dsa->x); + mp_clear(&dsa->y); + mp_clear(&tmpQ); + XFREE(cBuf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + return err; + } + + err = mp_read_unsigned_bin(&dsa->x, cBuf, cSz); + if (err != MP_OKAY) { + mp_clear(&dsa->x); + mp_clear(&dsa->y); + mp_clear(&tmpQ); + XFREE(cBuf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + return err; + } + } while (mp_cmp_d(&dsa->x, 1) != MP_GT); + + XFREE(cBuf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + + /* tmpQ = q - 1 */ + if (err == MP_OKAY) + err = mp_copy(&dsa->q, &tmpQ); + + if (err == MP_OKAY) + err = mp_sub_d(&tmpQ, 1, &tmpQ); + + /* x = c mod (q-1), &dsa->x holds c */ + if (err == MP_OKAY) + err = mp_mod(&dsa->x, &tmpQ, &dsa->x); + + /* x = c mod (q-1) + 1 */ + if (err == MP_OKAY) + err = mp_add_d(&dsa->x, 1, &dsa->x); + + /* public key : y = g^x mod p */ + if (err == MP_OKAY) + err = mp_exptmod_ex(&dsa->g, &dsa->x, dsa->q.used, &dsa->p, &dsa->y); + + if (err == MP_OKAY) + dsa->type = DSA_PRIVATE; + + if (err != MP_OKAY) { + mp_clear(&dsa->x); + mp_clear(&dsa->y); + } + mp_clear(&tmpQ); + + return err; +} + + +/* modulus_size in bits */ +int wc_MakeDsaParameters(WC_RNG *rng, int modulus_size, DsaKey *dsa) +{ + mp_int tmp, tmp2; + int err, msize, qsize, + loop_check_prime = 0, + check_prime = MP_NO; + unsigned char *buf; + + if (rng == NULL || dsa == NULL) + return BAD_FUNC_ARG; + + /* set group size in bytes from modulus size + * FIPS 186-4 defines valid values (1024, 160) (2048, 256) (3072, 256) + */ + switch (modulus_size) { + case 1024: + qsize = 20; + break; + case 2048: + case 3072: + qsize = 32; + break; + default: + return BAD_FUNC_ARG; + } + + /* modulus size in bytes */ + msize = modulus_size / WOLFSSL_BIT_SIZE; + + /* allocate ram */ + buf = (unsigned char *)XMALLOC(msize - qsize, + dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + if (buf == NULL) { + return MEMORY_E; + } + + /* make a random string that will be multiplied against q */ + err = wc_RNG_GenerateBlock(rng, buf, msize - qsize); + if (err != MP_OKAY) { + XFREE(buf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + return err; + } + + /* force magnitude */ + buf[0] |= 0xC0; + + /* force even */ + buf[msize - qsize - 1] &= ~1; + + if (mp_init_multi(&tmp2, &dsa->p, &dsa->q, 0, 0, 0) != MP_OKAY) { + mp_clear(&dsa->q); + XFREE(buf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + return MP_INIT_E; + } + + err = mp_read_unsigned_bin(&tmp2, buf, msize - qsize); + if (err != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp2); + XFREE(buf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + return err; + } + XFREE(buf, dsa->heap, DYNAMIC_TYPE_TMP_BUFFER); + + /* make our prime q */ + err = mp_rand_prime(&dsa->q, qsize, rng, NULL); + if (err != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp2); + return err; + } + + /* p = random * q */ + err = mp_mul(&dsa->q, &tmp2, &dsa->p); + if (err != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp2); + return err; + } + + /* p = random * q + 1, so q is a prime divisor of p-1 */ + err = mp_add_d(&dsa->p, 1, &dsa->p); + if (err != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp2); + return err; + } + + if (mp_init(&tmp) != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp2); + return MP_INIT_E; + } + + /* tmp = 2q */ + err = mp_add(&dsa->q, &dsa->q, &tmp); + if (err != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp); + mp_clear(&tmp2); + return err; + } + + /* loop until p is prime */ + while (check_prime == MP_NO) { + err = mp_prime_is_prime_ex(&dsa->p, 8, &check_prime, rng); + if (err != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp); + mp_clear(&tmp2); + return err; + } + + if (check_prime != MP_YES) { + /* p += 2q */ + err = mp_add(&tmp, &dsa->p, &dsa->p); + if (err != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp); + mp_clear(&tmp2); + return err; + } + + loop_check_prime++; + } + } + + /* tmp2 += (2*loop_check_prime) + * to have p = (q * tmp2) + 1 prime + */ + if (loop_check_prime) { + err = mp_add_d(&tmp2, 2*loop_check_prime, &tmp2); + if (err != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp); + mp_clear(&tmp2); + return err; + } + } + + if (mp_init(&dsa->g) != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp); + mp_clear(&tmp2); + return MP_INIT_E; + } + + /* find a value g for which g^tmp2 != 1 */ + if (mp_set(&dsa->g, 1) != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&tmp); + mp_clear(&tmp2); + return MP_INIT_E; + } + + do { + err = mp_add_d(&dsa->g, 1, &dsa->g); + if (err != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&dsa->g); + mp_clear(&tmp); + mp_clear(&tmp2); + return err; + } + + err = mp_exptmod(&dsa->g, &tmp2, &dsa->p, &tmp); + if (err != MP_OKAY) { + mp_clear(&dsa->q); + mp_clear(&dsa->p); + mp_clear(&dsa->g); + mp_clear(&tmp); + mp_clear(&tmp2); + return err; + } + + } while (mp_cmp_d(&tmp, 1) == MP_EQ); + + /* at this point tmp generates a group of order q mod p */ + mp_exch(&tmp, &dsa->g); + + mp_clear(&tmp); + mp_clear(&tmp2); + + return MP_OKAY; +} +#endif /* WOLFSSL_KEY_GEN */ + + +static int _DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q, + const char* g, int trusted, WC_RNG* rng) +{ + int err; + word32 pSz, qSz; + + if (dsa == NULL || p == NULL || q == NULL || g == NULL) + return BAD_FUNC_ARG; + + /* read p */ + err = mp_read_radix(&dsa->p, p, MP_RADIX_HEX); + if (err == MP_OKAY && !trusted) { + int isPrime = 1; + if (rng == NULL) + err = mp_prime_is_prime(&dsa->p, 8, &isPrime); + else + err = mp_prime_is_prime_ex(&dsa->p, 8, &isPrime, rng); + + if (err == MP_OKAY) { + if (!isPrime) + err = DH_CHECK_PUB_E; + } + } + + /* read q */ + if (err == MP_OKAY) + err = mp_read_radix(&dsa->q, q, MP_RADIX_HEX); + + /* read g */ + if (err == MP_OKAY) + err = mp_read_radix(&dsa->g, g, MP_RADIX_HEX); + + /* verify (L,N) pair bit lengths */ + pSz = mp_unsigned_bin_size(&dsa->p); + qSz = mp_unsigned_bin_size(&dsa->q); + + if (CheckDsaLN(pSz * WOLFSSL_BIT_SIZE, qSz * WOLFSSL_BIT_SIZE) != 0) { + WOLFSSL_MSG("Invalid DSA p or q parameter size"); + err = BAD_FUNC_ARG; + } + + if (err != MP_OKAY) { + mp_clear(&dsa->p); + mp_clear(&dsa->q); + mp_clear(&dsa->g); + } + + return err; +} + + +/* Import raw DSA parameters into DsaKey structure for use with wc_MakeDsaKey(), + * input parameters (p,q,g) should be represented as ASCII hex values. + * + * dsa - pointer to initialized DsaKey structure + * p - DSA (p) parameter, ASCII hex string + * pSz - length of p + * q - DSA (q) parameter, ASCII hex string + * qSz - length of q + * g - DSA (g) parameter, ASCII hex string + * gSz - length of g + * + * returns 0 on success, negative upon failure + */ +int wc_DsaImportParamsRaw(DsaKey* dsa, const char* p, const char* q, + const char* g) +{ + return _DsaImportParamsRaw(dsa, p, q, g, 1, NULL); +} + + +/* Import raw DSA parameters into DsaKey structure for use with wc_MakeDsaKey(), + * input parameters (p,q,g) should be represented as ASCII hex values. Check + * that the p value is probably prime. + * + * dsa - pointer to initialized DsaKey structure + * p - DSA (p) parameter, ASCII hex string + * pSz - length of p + * q - DSA (q) parameter, ASCII hex string + * qSz - length of q + * g - DSA (g) parameter, ASCII hex string + * gSz - length of g + * trusted - trust that p is OK + * rng - random number generator for the prime test + * + * returns 0 on success, negative upon failure + */ +int wc_DsaImportParamsRawCheck(DsaKey* dsa, const char* p, const char* q, + const char* g, int trusted, WC_RNG* rng) +{ + return _DsaImportParamsRaw(dsa, p, q, g, trusted, rng); +} + + +/* Export raw DSA parameters from DsaKey structure + * + * dsa - pointer to initialized DsaKey structure + * p - output location for DSA (p) parameter + * pSz - [IN/OUT] size of output buffer for p, size of p + * q - output location for DSA (q) parameter + * qSz - [IN/OUT] size of output buffer for q, size of q + * g - output location for DSA (g) parameter + * gSz - [IN/OUT] size of output buffer for g, size of g + * + * If p, q, and g pointers are all passed in as NULL, the function + * will set pSz, qSz, and gSz to the required output buffer sizes for p, + * q, and g. In this case, the function will return LENGTH_ONLY_E. + * + * returns 0 on success, negative upon failure + */ +int wc_DsaExportParamsRaw(DsaKey* dsa, byte* p, word32* pSz, + byte* q, word32* qSz, byte* g, word32* gSz) +{ + int err; + word32 pLen, qLen, gLen; + + if (dsa == NULL || pSz == NULL || qSz == NULL || gSz == NULL) + return BAD_FUNC_ARG; + + /* get required output buffer sizes */ + pLen = mp_unsigned_bin_size(&dsa->p); + qLen = mp_unsigned_bin_size(&dsa->q); + gLen = mp_unsigned_bin_size(&dsa->g); + + /* return buffer sizes and LENGTH_ONLY_E if buffers are NULL */ + if (p == NULL && q == NULL && g == NULL) { + *pSz = pLen; + *qSz = qLen; + *gSz = gLen; + return LENGTH_ONLY_E; + } + + if (p == NULL || q == NULL || g == NULL) + return BAD_FUNC_ARG; + + /* export p */ + if (*pSz < pLen) { + WOLFSSL_MSG("Output buffer for DSA p parameter too small, " + "required size placed into pSz"); + *pSz = pLen; + return BUFFER_E; + } + *pSz = pLen; + err = mp_to_unsigned_bin(&dsa->p, p); + + /* export q */ + if (err == MP_OKAY) { + if (*qSz < qLen) { + WOLFSSL_MSG("Output buffer for DSA q parameter too small, " + "required size placed into qSz"); + *qSz = qLen; + return BUFFER_E; + } + *qSz = qLen; + err = mp_to_unsigned_bin(&dsa->q, q); + } + + /* export g */ + if (err == MP_OKAY) { + if (*gSz < gLen) { + WOLFSSL_MSG("Output buffer for DSA g parameter too small, " + "required size placed into gSz"); + *gSz = gLen; + return BUFFER_E; + } + *gSz = gLen; + err = mp_to_unsigned_bin(&dsa->g, g); + } + + return err; +} + + +/* Export raw DSA key (x, y) from DsaKey structure + * + * dsa - pointer to initialized DsaKey structure + * x - output location for private key + * xSz - [IN/OUT] size of output buffer for x, size of x + * y - output location for public key + * ySz - [IN/OUT] size of output buffer for y, size of y + * + * If x and y pointers are all passed in as NULL, the function + * will set xSz and ySz to the required output buffer sizes for x + * and y. In this case, the function will return LENGTH_ONLY_E. + * + * returns 0 on success, negative upon failure + */ +int wc_DsaExportKeyRaw(DsaKey* dsa, byte* x, word32* xSz, byte* y, word32* ySz) +{ + int err; + word32 xLen, yLen; + + if (dsa == NULL || xSz == NULL || ySz == NULL) + return BAD_FUNC_ARG; + + /* get required output buffer sizes */ + xLen = mp_unsigned_bin_size(&dsa->x); + yLen = mp_unsigned_bin_size(&dsa->y); + + /* return buffer sizes and LENGTH_ONLY_E if buffers are NULL */ + if (x == NULL && y == NULL) { + *xSz = xLen; + *ySz = yLen; + return LENGTH_ONLY_E; + } + + if (x == NULL || y == NULL) + return BAD_FUNC_ARG; + + /* export x */ + if (*xSz < xLen) { + WOLFSSL_MSG("Output buffer for DSA private key (x) too small, " + "required size placed into xSz"); + *xSz = xLen; + return BUFFER_E; + } + *xSz = xLen; + err = mp_to_unsigned_bin(&dsa->x, x); + + /* export y */ + if (err == MP_OKAY) { + if (*ySz < yLen) { + WOLFSSL_MSG("Output buffer to DSA public key (y) too small, " + "required size placed into ySz"); + *ySz = yLen; + return BUFFER_E; + } + *ySz = yLen; + err = mp_to_unsigned_bin(&dsa->y, y); + } + + return err; +} + + +int wc_DsaSign(const byte* digest, byte* out, DsaKey* key, WC_RNG* rng) { - mp_int k, kInv, r, s, H; - int ret, sz; - byte buffer[DSA_HALF_SIZE]; + mp_int k, kInv, r, s, H; +#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME + mp_int b; +#endif + mp_int* qMinus1; + int ret = 0, sz; + byte buffer[DSA_HALF_SIZE]; + byte* tmp; /* initial output pointer */ - sz = min(sizeof(buffer), mp_unsigned_bin_size(&key->q)); + if (digest == NULL || out == NULL || key == NULL || rng == NULL) { + return BAD_FUNC_ARG; + } - /* generate k */ - ret = wc_RNG_GenerateBlock(rng, buffer, sz); - if (ret != 0) - return ret; + tmp = out; - buffer[0] |= 0x0C; + sz = min((int)sizeof(buffer), mp_unsigned_bin_size(&key->q)); +#ifdef WOLFSSL_MP_INVMOD_CONSTANT_TIME if (mp_init_multi(&k, &kInv, &r, &s, &H, 0) != MP_OKAY) +#else + if (mp_init_multi(&k, &kInv, &r, &s, &H, &b) != MP_OKAY) +#endif + { return MP_INIT_E; + } + qMinus1 = &kInv; - if (mp_read_unsigned_bin(&k, buffer, sz) != MP_OKAY) - ret = MP_READ_E; + /* NIST FIPS 186-4: B.2.2 + * Per-Message Secret Number Generation by Testing Candidates + * Generate k in range [1, q-1]. + * Check that k is less than q-1: range [0, q-2]. + * Add 1 to k: range [1, q-1]. + */ + if (mp_sub_d(&key->q, 1, qMinus1)) + ret = MP_SUB_E; - if (ret == 0 && mp_cmp_d(&k, 1) != MP_GT) - ret = MP_CMP_E; + if (ret == 0) { + do { + /* Step 4: generate k */ + ret = wc_RNG_GenerateBlock(rng, buffer, sz); + + /* Step 5 */ + if (ret == 0 && mp_read_unsigned_bin(&k, buffer, sz) != MP_OKAY) + ret = MP_READ_E; + + /* k is a random numnber and it should be less than q-1 + * if k greater than repeat + */ + /* Step 6 */ + } while (ret == 0 && mp_cmp(&k, qMinus1) != MP_LT); + } + /* Step 7 */ + if (ret == 0 && mp_add_d(&k, 1, &k) != MP_OKAY) + ret = MP_MOD_E; +#ifdef WOLFSSL_MP_INVMOD_CONSTANT_TIME /* inverse k mod q */ if (ret == 0 && mp_invmod(&k, &key->q, &kInv) != MP_OKAY) ret = MP_INVMOD_E; /* generate r, r = (g exp k mod p) mod q */ - if (ret == 0 && mp_exptmod(&key->g, &k, &key->p, &r) != MP_OKAY) + if (ret == 0 && mp_exptmod_ex(&key->g, &k, key->q.used, &key->p, + &r) != MP_OKAY) { ret = MP_EXPTMOD_E; + } if (ret == 0 && mp_mod(&r, &key->q, &r) != MP_OKAY) ret = MP_MOD_E; /* generate H from sha digest */ - if (ret == 0 && mp_read_unsigned_bin(&H, digest,SHA_DIGEST_SIZE) != MP_OKAY) + if (ret == 0 && mp_read_unsigned_bin(&H, digest,WC_SHA_DIGEST_SIZE) != MP_OKAY) ret = MP_READ_E; /* generate s, s = (kInv * (H + x*r)) % q */ @@ -129,28 +736,105 @@ int wc_DsaSign(const byte* digest, byte* out, DsaKey* key, RNG* rng) if (ret == 0 && mp_mulmod(&s, &kInv, &key->q, &s) != MP_OKAY) ret = MP_MULMOD_E; +#else + /* Blinding value + * Generate b in range [1, q-1]. + */ + if (ret == 0) { + do { + ret = wc_RNG_GenerateBlock(rng, buffer, sz); + if (ret == 0 && mp_read_unsigned_bin(&b, buffer, sz) != MP_OKAY) + ret = MP_READ_E; + } while (ret == 0 && mp_cmp(&b, qMinus1) != MP_LT); + } + if (ret == 0 && mp_add_d(&b, 1, &b) != MP_OKAY) + ret = MP_MOD_E; + + /* set H from sha digest */ + if (ret == 0 && mp_read_unsigned_bin(&H, digest, + WC_SHA_DIGEST_SIZE) != MP_OKAY) { + ret = MP_READ_E; + } + + /* generate r, r = (g exp k mod p) mod q */ + if (ret == 0 && mp_exptmod_ex(&key->g, &k, key->q.used, &key->p, + &r) != MP_OKAY) { + ret = MP_EXPTMOD_E; + } + + /* calculate s = (H + xr)/k + = b.(H/k.b + x.r/k.b) */ + + /* k = k.b */ + if (ret == 0 && mp_mulmod(&k, &b, &key->q, &k) != MP_OKAY) + ret = MP_MULMOD_E; + + /* kInv = 1/k.b mod q */ + if (ret == 0 && mp_invmod(&k, &key->q, &kInv) != MP_OKAY) + ret = MP_INVMOD_E; + + if (ret == 0 && mp_mod(&r, &key->q, &r) != MP_OKAY) + ret = MP_MOD_E; + + /* s = x.r */ + if (ret == 0 && mp_mul(&key->x, &r, &s) != MP_OKAY) + ret = MP_MUL_E; + + /* s = x.r/k.b */ + if (ret == 0 && mp_mulmod(&s, &kInv, &key->q, &s) != MP_OKAY) + ret = MP_MULMOD_E; + + /* H = H/k.b */ + if (ret == 0 && mp_mulmod(&H, &kInv, &key->q, &H) != MP_OKAY) + ret = MP_MULMOD_E; + + /* s = H/k.b + x.r/k.b + = (H + x.r)/k.b */ + if (ret == 0 && mp_add(&s, &H, &s) != MP_OKAY) + ret = MP_ADD_E; + + /* s = b.(e + x.r)/k.b + = (e + x.r)/k */ + if (ret == 0 && mp_mulmod(&s, &b, &key->q, &s) != MP_OKAY) + ret = MP_MULMOD_E; + + /* s = (e + x.r)/k */ + if (ret == 0 && mp_mod(&s, &key->q, &s) != MP_OKAY) + ret = MP_MOD_E; +#endif + + /* detect zero r or s */ + if (ret == 0 && (mp_iszero(&r) == MP_YES || mp_iszero(&s) == MP_YES)) + ret = MP_ZERO_E; /* write out */ if (ret == 0) { int rSz = mp_unsigned_bin_size(&r); int sSz = mp_unsigned_bin_size(&s); - if (rSz == DSA_HALF_SIZE - 1) { - out[0] = 0; - out++; + while (rSz++ < DSA_HALF_SIZE) { + *out++ = 0x00; /* pad front with zeros */ } if (mp_to_unsigned_bin(&r, out) != MP_OKAY) ret = MP_TO_E; else { - if (sSz == DSA_HALF_SIZE - 1) { - out[rSz] = 0; - out++; - } - ret = mp_to_unsigned_bin(&s, out + rSz); + out = tmp + DSA_HALF_SIZE; /* advance to s in output */ + while (sSz++ < DSA_HALF_SIZE) { + *out++ = 0x00; /* pad front with zeros */ + } + ret = mp_to_unsigned_bin(&s, out); } } + ForceZero(buffer, sz); + mp_forcezero(&kInv); + mp_forcezero(&k); +#ifndef WOLFSSL_MP_INVMOD_CONSTANT_TIME + mp_forcezero(&b); + + mp_clear(&b); +#endif mp_clear(&H); mp_clear(&s); mp_clear(&r); @@ -166,6 +850,10 @@ int wc_DsaVerify(const byte* digest, const byte* sig, DsaKey* key, int* answer) mp_int w, u1, u2, v, r, s; int ret = 0; + if (digest == NULL || sig == NULL || key == NULL || answer == NULL) { + return BAD_FUNC_ARG; + } + if (mp_init_multi(&w, &u1, &u2, &v, &r, &s) != MP_OKAY) return MP_INIT_E; @@ -183,7 +871,7 @@ int wc_DsaVerify(const byte* digest, const byte* sig, DsaKey* key, int* answer) } /* put H into u1 from sha digest */ - if (ret == 0 && mp_read_unsigned_bin(&u1,digest,SHA_DIGEST_SIZE) != MP_OKAY) + if (ret == 0 && mp_read_unsigned_bin(&u1,digest,WC_SHA_DIGEST_SIZE) != MP_OKAY) ret = MP_READ_E; /* w = s invmod q */ |