2d86ea2a1d
SVN-Revision: 13738
1081 lines
24 KiB
C
1081 lines
24 KiB
C
/*
|
|
* Copyright (c) 1997-1999 The Stanford SRP Authentication Project
|
|
* All Rights Reserved.
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining
|
|
* a copy of this software and associated documentation files (the
|
|
* "Software"), to deal in the Software without restriction, including
|
|
* without limitation the rights to use, copy, modify, merge, publish,
|
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
|
* permit persons to whom the Software is furnished to do so, subject to
|
|
* the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be
|
|
* included in all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
|
|
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
|
|
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
|
|
*
|
|
* IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
|
|
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
|
|
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF
|
|
* THE POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT
|
|
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*
|
|
* In addition, the following conditions apply:
|
|
*
|
|
* 1. Any software that incorporates the SRP authentication technology
|
|
* must display the following acknowlegment:
|
|
* "This product uses the 'Secure Remote Password' cryptographic
|
|
* authentication system developed by Tom Wu (tjw@CS.Stanford.EDU)."
|
|
*
|
|
* 2. Any software that incorporates all or part of the SRP distribution
|
|
* itself must also display the following acknowledgment:
|
|
* "This product includes software developed by Tom Wu and Eugene
|
|
* Jhong for the SRP Distribution (http://srp.stanford.edu/srp/)."
|
|
*
|
|
* 3. Redistributions in source or binary form must retain an intact copy
|
|
* of this copyright notice and list of conditions.
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "t_defines.h"
|
|
#include "t_pwd.h"
|
|
#include "t_read.h"
|
|
#include "bn.h"
|
|
#include "bn_lcl.h"
|
|
#include "bn_prime.h"
|
|
|
|
#define TABLE_SIZE 32
|
|
|
|
static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1,
|
|
const BIGNUM *a1_odd, int k, BN_CTX *ctx, BN_MONT_CTX *mont);
|
|
|
|
/*
|
|
* This is the safe prime generation logic.
|
|
* To generate a safe prime p (where p = 2q+1 and q is prime), we start
|
|
* with a random odd q that is one bit shorter than the desired length
|
|
* of p. We use a simple 30-element sieve to filter the values of q
|
|
* and consider only those that are 11, 23, or 29 (mod 30). (If q were
|
|
* anything else, either q or p would be divisible by 2, 3, or 5).
|
|
* For the values of q that are left, we apply the following tests in
|
|
* this order:
|
|
*
|
|
* trial divide q
|
|
* let p = 2q + 1
|
|
* trial divide p
|
|
* apply Fermat test to q (2^q == 2 (mod q))
|
|
* apply Fermat test to p (2^p == 2 (mod p))
|
|
* apply real probablistic primality test to q
|
|
* apply real probablistic primality test to p
|
|
*
|
|
* A number that passes all these tests is considered a safe prime for
|
|
* our purposes. The tests are ordered this way for efficiency; the
|
|
* slower tests are run rarely if ever at all.
|
|
*/
|
|
|
|
static int
|
|
trialdiv(x)
|
|
const BigInteger x;
|
|
{
|
|
static int primes[] = { /* All odd primes < 256 */
|
|
3, 5, 7, 11, 13, 17, 19, 23, 29,
|
|
31, 37, 41, 43, 47, 53, 59, 61, 67,
|
|
71, 73, 79, 83, 89, 97, 101, 103,
|
|
107, 109, 113, 127, 131, 137, 139, 149, 151,
|
|
157, 163, 167, 173, 179, 181, 191, 193, 197,
|
|
199, 211, 223, 227, 229, 233, 239, 241, 251
|
|
};
|
|
static int nprimes = sizeof(primes) / sizeof(int);
|
|
int i;
|
|
|
|
for(i = 0; i < nprimes; ++i) {
|
|
if(BigIntegerModInt(x, primes[i]) == 0)
|
|
return primes[i];
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/* x + sieve30[x%30] == 11, 23, or 29 (mod 30) */
|
|
|
|
static int sieve30[] =
|
|
{ 11, 10, 9, 8, 7, 6, 5, 4, 3, 2,
|
|
1, 12, 11, 10, 9, 8, 7, 6, 5, 4,
|
|
3, 2, 1, 6, 5, 4, 3, 2, 1, 12
|
|
};
|
|
|
|
/* Find a Sophie-Germain prime between "lo" and "hi". NOTE: this is not
|
|
a "safe prime", but the smaller prime. Take 2q+1 to get the safe prime. */
|
|
|
|
static void
|
|
sophie_germain(q, lo, hi)
|
|
BigInteger q; /* assumed initialized */
|
|
const BigInteger lo;
|
|
const BigInteger hi;
|
|
{
|
|
BigInteger m, p, r;
|
|
char parambuf[MAXPARAMLEN];
|
|
int foundprime = 0;
|
|
int i, mod30;
|
|
|
|
m = BigIntegerFromInt(0);
|
|
BigIntegerSub(m, hi, lo);
|
|
i = (BigIntegerBitLen(m) + 7) / 8;
|
|
t_random(parambuf, i);
|
|
r = BigIntegerFromBytes(parambuf, i);
|
|
BigIntegerMod(r, r, m);
|
|
|
|
BigIntegerAdd(q, r, lo);
|
|
if(BigIntegerModInt(q, 2) == 0)
|
|
BigIntegerAddInt(q, q, 1); /* make q odd */
|
|
|
|
mod30 = BigIntegerModInt(q, 30); /* mod30 = q % 30 */
|
|
|
|
BigIntegerFree(m);
|
|
m = BigIntegerFromInt(2); /* m = 2 */
|
|
p = BigIntegerFromInt(0);
|
|
|
|
while(BigIntegerCmp(q, hi) < 0) {
|
|
if(trialdiv(q) < 2) {
|
|
BigIntegerMulInt(p, q, 2); /* p = 2 * q */
|
|
BigIntegerAddInt(p, p, 1); /* p += 1 */
|
|
if(trialdiv(p) < 2) {
|
|
BigIntegerModExp(r, m, q, q); /* r = 2^q % q */
|
|
if(BigIntegerCmpInt(r, 2) == 0) { /* if(r == 2) */
|
|
BigIntegerModExp(r, m, p, p); /* r = 2^p % p */
|
|
if(BigIntegerCmpInt(r, 2) == 0) { /* if(r == 2) */
|
|
if(BigIntegerCheckPrime(q) && BigIntegerCheckPrime(p)) {
|
|
++foundprime;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
i = sieve30[mod30];
|
|
BigIntegerAddInt(q, q, i); /* q += i */
|
|
mod30 = (mod30 + i) % 30;
|
|
}
|
|
|
|
/* should wrap around on failure */
|
|
if(!foundprime) {
|
|
fprintf(stderr, "Prime generation failed!\n");
|
|
exit(1);
|
|
}
|
|
|
|
BigIntegerFree(r);
|
|
BigIntegerFree(m);
|
|
BigIntegerFree(p);
|
|
}
|
|
|
|
_TYPE( struct t_confent * )
|
|
t_makeconfent(tc, nsize)
|
|
struct t_conf * tc;
|
|
int nsize;
|
|
{
|
|
BigInteger n, g, q, t, u;
|
|
|
|
t = BigIntegerFromInt(0);
|
|
u = BigIntegerFromInt(1); /* u = 1 */
|
|
BigIntegerLShift(t, u, nsize - 2); /* t = 2^(nsize-2) */
|
|
BigIntegerMulInt(u, t, 2); /* u = 2^(nsize-1) */
|
|
|
|
q = BigIntegerFromInt(0);
|
|
sophie_germain(q, t, u);
|
|
|
|
n = BigIntegerFromInt(0);
|
|
BigIntegerMulInt(n, q, 2);
|
|
BigIntegerAddInt(n, n, 1);
|
|
|
|
/* Look for a generator mod n */
|
|
g = BigIntegerFromInt(2);
|
|
while(1) {
|
|
BigIntegerModExp(t, g, q, n); /* t = g^q % n */
|
|
if(BigIntegerCmpInt(t, 1) == 0) /* if(t == 1) */
|
|
BigIntegerAddInt(g, g, 1); /* ++g */
|
|
else
|
|
break;
|
|
}
|
|
BigIntegerFree(t);
|
|
BigIntegerFree(u);
|
|
BigIntegerFree(q);
|
|
|
|
tc->tcbuf.modulus.data = tc->modbuf;
|
|
tc->tcbuf.modulus.len = BigIntegerToBytes(n, tc->tcbuf.modulus.data);
|
|
BigIntegerFree(n);
|
|
|
|
tc->tcbuf.generator.data = tc->genbuf;
|
|
tc->tcbuf.generator.len = BigIntegerToBytes(g, tc->tcbuf.generator.data);
|
|
BigIntegerFree(g);
|
|
|
|
tc->tcbuf.index = 1;
|
|
return &tc->tcbuf;
|
|
}
|
|
|
|
_TYPE( struct t_confent * )
|
|
t_makeconfent_c(tc, nsize)
|
|
struct t_conf * tc;
|
|
int nsize;
|
|
{
|
|
BigInteger g, n, p, q, j, k, t, u;
|
|
int psize, qsize;
|
|
|
|
psize = nsize / 2;
|
|
qsize = nsize - psize;
|
|
|
|
t = BigIntegerFromInt(1); /* t = 1 */
|
|
u = BigIntegerFromInt(0);
|
|
BigIntegerLShift(u, t, psize - 3); /* u = t*2^(psize-3) = 2^(psize-3) */
|
|
BigIntegerMulInt(t, u, 3); /* t = 3*u = 1.5*2^(psize-2) */
|
|
BigIntegerAdd(u, u, t); /* u += t [u = 2^(psize-1)] */
|
|
j = BigIntegerFromInt(0);
|
|
sophie_germain(j, t, u);
|
|
|
|
k = BigIntegerFromInt(0);
|
|
if(qsize != psize) {
|
|
BigIntegerFree(t);
|
|
t = BigIntegerFromInt(1); /* t = 1 */
|
|
BigIntegerLShift(u, t, qsize - 3); /* u = t*2^(qsize-3) = 2^(qsize-3) */
|
|
BigIntegerMulInt(t, u, 3); /* t = 3*u = 1.5*2^(qsize-2) */
|
|
BigIntegerAdd(u, u, t); /* u += t [u = 2^(qsize-1)] */
|
|
}
|
|
sophie_germain(k, t, u);
|
|
|
|
p = BigIntegerFromInt(0);
|
|
BigIntegerMulInt(p, j, 2); /* p = 2 * j */
|
|
BigIntegerAddInt(p, p, 1); /* p += 1 */
|
|
|
|
q = BigIntegerFromInt(0);
|
|
BigIntegerMulInt(q, k, 2); /* q = 2 * k */
|
|
BigIntegerAddInt(q, q, 1); /* q += 1 */
|
|
|
|
n = BigIntegerFromInt(0);
|
|
BigIntegerMul(n, p, q); /* n = p * q */
|
|
BigIntegerMul(u, j, k); /* u = j * k */
|
|
|
|
BigIntegerFree(p);
|
|
BigIntegerFree(q);
|
|
BigIntegerFree(j);
|
|
BigIntegerFree(k);
|
|
|
|
g = BigIntegerFromInt(2); /* g = 2 */
|
|
|
|
/* Look for a generator mod n */
|
|
while(1) {
|
|
BigIntegerModExp(t, g, u, n); /* t = g^u % n */
|
|
if(BigIntegerCmpInt(t, 1) == 0)
|
|
BigIntegerAddInt(g, g, 1); /* ++g */
|
|
else
|
|
break;
|
|
}
|
|
|
|
BigIntegerFree(u);
|
|
BigIntegerFree(t);
|
|
|
|
tc->tcbuf.modulus.data = tc->modbuf;
|
|
tc->tcbuf.modulus.len = BigIntegerToBytes(n, tc->tcbuf.modulus.data);
|
|
BigIntegerFree(n);
|
|
|
|
tc->tcbuf.generator.data = tc->genbuf;
|
|
tc->tcbuf.generator.len = BigIntegerToBytes(g, tc->tcbuf.generator.data);
|
|
BigIntegerFree(g);
|
|
|
|
tc->tcbuf.index = 1;
|
|
return &tc->tcbuf;
|
|
}
|
|
|
|
_TYPE( struct t_confent * )
|
|
t_newconfent(tc)
|
|
struct t_conf * tc;
|
|
{
|
|
tc->tcbuf.index = 0;
|
|
tc->tcbuf.modulus.data = tc->modbuf;
|
|
tc->tcbuf.modulus.len = 0;
|
|
tc->tcbuf.generator.data = tc->genbuf;
|
|
tc->tcbuf.generator.len = 0;
|
|
return &tc->tcbuf;
|
|
}
|
|
|
|
_TYPE( void )
|
|
t_putconfent(ent, fp)
|
|
const struct t_confent * ent;
|
|
FILE * fp;
|
|
{
|
|
char strbuf[MAXB64PARAMLEN];
|
|
|
|
fprintf(fp, "%d:%s:", ent->index,
|
|
t_tob64(strbuf, ent->modulus.data, ent->modulus.len));
|
|
fprintf(fp, "%s\n",
|
|
t_tob64(strbuf, ent->generator.data, ent->generator.len));
|
|
}
|
|
|
|
int
|
|
BigIntegerBitLen(b)
|
|
BigInteger b;
|
|
{
|
|
return BN_num_bits(b);
|
|
}
|
|
|
|
int
|
|
BigIntegerCheckPrime(n)
|
|
BigInteger n;
|
|
{
|
|
BN_CTX * ctx = BN_CTX_new();
|
|
int rv = BN_is_prime(n, 25, NULL, ctx, NULL);
|
|
BN_CTX_free(ctx);
|
|
return rv;
|
|
}
|
|
|
|
unsigned int
|
|
BigIntegerModInt(d, m)
|
|
BigInteger d;
|
|
unsigned int m;
|
|
{
|
|
return BN_mod_word(d, m);
|
|
}
|
|
|
|
void
|
|
BigIntegerMod(result, d, m)
|
|
BigInteger result, d, m;
|
|
{
|
|
BN_CTX * ctx = BN_CTX_new();
|
|
BN_mod(result, d, m, ctx);
|
|
BN_CTX_free(ctx);
|
|
}
|
|
|
|
void
|
|
BigIntegerMul(result, m1, m2)
|
|
BigInteger result, m1, m2;
|
|
{
|
|
BN_CTX * ctx = BN_CTX_new();
|
|
BN_mul(result, m1, m2, ctx);
|
|
BN_CTX_free(ctx);
|
|
}
|
|
|
|
void
|
|
BigIntegerLShift(result, x, bits)
|
|
BigInteger result, x;
|
|
unsigned int bits;
|
|
{
|
|
BN_lshift(result, x, bits);
|
|
}
|
|
|
|
int BN_is_prime(const BIGNUM *a, int checks, void (*callback)(int,int,void *),
|
|
BN_CTX *ctx_passed, void *cb_arg)
|
|
{
|
|
return BN_is_prime_fasttest(a, checks, callback, ctx_passed, cb_arg, 0);
|
|
}
|
|
|
|
int BN_is_prime_fasttest(const BIGNUM *a, int checks,
|
|
void (*callback)(int,int,void *),
|
|
BN_CTX *ctx_passed, void *cb_arg,
|
|
int do_trial_division)
|
|
{
|
|
int i, j, ret = -1;
|
|
int k;
|
|
BN_CTX *ctx = NULL;
|
|
BIGNUM *A1, *A1_odd, *check; /* taken from ctx */
|
|
BN_MONT_CTX *mont = NULL;
|
|
const BIGNUM *A = NULL;
|
|
|
|
if (checks == BN_prime_checks)
|
|
checks = BN_prime_checks_for_size(BN_num_bits(a));
|
|
|
|
/* first look for small factors */
|
|
if (!BN_is_odd(a))
|
|
return(0);
|
|
if (do_trial_division)
|
|
{
|
|
for (i = 1; i < NUMPRIMES; i++)
|
|
if (BN_mod_word(a, primes[i]) == 0)
|
|
return 0;
|
|
if (callback != NULL) callback(1, -1, cb_arg);
|
|
}
|
|
|
|
if (ctx_passed != NULL)
|
|
ctx = ctx_passed;
|
|
else
|
|
if ((ctx=BN_CTX_new()) == NULL)
|
|
goto err;
|
|
BN_CTX_start(ctx);
|
|
|
|
/* A := abs(a) */
|
|
if (a->neg)
|
|
{
|
|
BIGNUM *t;
|
|
if ((t = BN_CTX_get(ctx)) == NULL) goto err;
|
|
BN_copy(t, a);
|
|
t->neg = 0;
|
|
A = t;
|
|
}
|
|
else
|
|
A = a;
|
|
A1 = BN_CTX_get(ctx);
|
|
A1_odd = BN_CTX_get(ctx);
|
|
check = BN_CTX_get(ctx);
|
|
if (check == NULL) goto err;
|
|
|
|
/* compute A1 := A - 1 */
|
|
if (!BN_copy(A1, A))
|
|
goto err;
|
|
if (!BN_sub_word(A1, 1))
|
|
goto err;
|
|
if (BN_is_zero(A1))
|
|
{
|
|
ret = 0;
|
|
goto err;
|
|
}
|
|
|
|
/* write A1 as A1_odd * 2^k */
|
|
k = 1;
|
|
while (!BN_is_bit_set(A1, k))
|
|
k++;
|
|
if (!BN_rshift(A1_odd, A1, k))
|
|
goto err;
|
|
|
|
/* Montgomery setup for computations mod A */
|
|
mont = BN_MONT_CTX_new();
|
|
if (mont == NULL)
|
|
goto err;
|
|
if (!BN_MONT_CTX_set(mont, A, ctx))
|
|
goto err;
|
|
|
|
for (i = 0; i < checks; i++)
|
|
{
|
|
if (!BN_pseudo_rand(check, BN_num_bits(A1), 0, 0))
|
|
goto err;
|
|
if (BN_cmp(check, A1) >= 0)
|
|
if (!BN_sub(check, check, A1))
|
|
goto err;
|
|
if (!BN_add_word(check, 1))
|
|
goto err;
|
|
/* now 1 <= check < A */
|
|
|
|
j = witness(check, A, A1, A1_odd, k, ctx, mont);
|
|
if (j == -1) goto err;
|
|
if (j)
|
|
{
|
|
ret=0;
|
|
goto err;
|
|
}
|
|
if (callback != NULL) callback(1,i,cb_arg);
|
|
}
|
|
ret=1;
|
|
err:
|
|
if (ctx != NULL)
|
|
{
|
|
BN_CTX_end(ctx);
|
|
if (ctx_passed == NULL)
|
|
BN_CTX_free(ctx);
|
|
}
|
|
if (mont != NULL)
|
|
BN_MONT_CTX_free(mont);
|
|
|
|
return(ret);
|
|
}
|
|
|
|
static int witness(BIGNUM *w, const BIGNUM *a, const BIGNUM *a1,
|
|
const BIGNUM *a1_odd, int k, BN_CTX *ctx, BN_MONT_CTX *mont)
|
|
{
|
|
if (!BN_mod_exp_mont(w, w, a1_odd, a, ctx, mont)) /* w := w^a1_odd mod a */
|
|
return -1;
|
|
if (BN_is_one(w))
|
|
return 0; /* probably prime */
|
|
if (BN_cmp(w, a1) == 0)
|
|
return 0; /* w == -1 (mod a), 'a' is probably prime */
|
|
while (--k)
|
|
{
|
|
if (!BN_mod_mul(w, w, w, a, ctx)) /* w := w^2 mod a */
|
|
return -1;
|
|
if (BN_is_one(w))
|
|
return 1; /* 'a' is composite, otherwise a previous 'w' would
|
|
* have been == -1 (mod 'a') */
|
|
if (BN_cmp(w, a1) == 0)
|
|
return 0; /* w == -1 (mod a), 'a' is probably prime */
|
|
}
|
|
/* If we get here, 'w' is the (a-1)/2-th power of the original 'w',
|
|
* and it is neither -1 nor +1 -- so 'a' cannot be prime */
|
|
return 1;
|
|
}
|
|
|
|
int BN_mod_exp_mont(BIGNUM *rr, BIGNUM *a, const BIGNUM *p,
|
|
const BIGNUM *m, BN_CTX *ctx, BN_MONT_CTX *in_mont)
|
|
{
|
|
int i,j,bits,ret=0,wstart,wend,window,wvalue;
|
|
int start=1,ts=0;
|
|
BIGNUM *d,*r;
|
|
BIGNUM *aa;
|
|
BIGNUM val[TABLE_SIZE];
|
|
BN_MONT_CTX *mont=NULL;
|
|
|
|
bn_check_top(a);
|
|
bn_check_top(p);
|
|
bn_check_top(m);
|
|
|
|
if (!(m->d[0] & 1))
|
|
{
|
|
return(0);
|
|
}
|
|
bits=BN_num_bits(p);
|
|
if (bits == 0)
|
|
{
|
|
BN_one(rr);
|
|
return(1);
|
|
}
|
|
BN_CTX_start(ctx);
|
|
d = BN_CTX_get(ctx);
|
|
r = BN_CTX_get(ctx);
|
|
if (d == NULL || r == NULL) goto err;
|
|
|
|
/* If this is not done, things will break in the montgomery
|
|
* part */
|
|
|
|
if (in_mont != NULL)
|
|
mont=in_mont;
|
|
else
|
|
{
|
|
if ((mont=BN_MONT_CTX_new()) == NULL) goto err;
|
|
if (!BN_MONT_CTX_set(mont,m,ctx)) goto err;
|
|
}
|
|
|
|
BN_init(&val[0]);
|
|
ts=1;
|
|
if (BN_ucmp(a,m) >= 0)
|
|
{
|
|
if (!BN_mod(&(val[0]),a,m,ctx))
|
|
goto err;
|
|
aa= &(val[0]);
|
|
}
|
|
else
|
|
aa=a;
|
|
if (!BN_to_montgomery(&(val[0]),aa,mont,ctx)) goto err; /* 1 */
|
|
|
|
window = BN_window_bits_for_exponent_size(bits);
|
|
if (window > 1)
|
|
{
|
|
if (!BN_mod_mul_montgomery(d,&(val[0]),&(val[0]),mont,ctx)) goto err; /* 2 */
|
|
j=1<<(window-1);
|
|
for (i=1; i<j; i++)
|
|
{
|
|
BN_init(&(val[i]));
|
|
if (!BN_mod_mul_montgomery(&(val[i]),&(val[i-1]),d,mont,ctx))
|
|
goto err;
|
|
}
|
|
ts=i;
|
|
}
|
|
|
|
start=1; /* This is used to avoid multiplication etc
|
|
* when there is only the value '1' in the
|
|
* buffer. */
|
|
wvalue=0; /* The 'value' of the window */
|
|
wstart=bits-1; /* The top bit of the window */
|
|
wend=0; /* The bottom bit of the window */
|
|
|
|
if (!BN_to_montgomery(r,BN_value_one(),mont,ctx)) goto err;
|
|
for (;;)
|
|
{
|
|
if (BN_is_bit_set(p,wstart) == 0)
|
|
{
|
|
if (!start)
|
|
{
|
|
if (!BN_mod_mul_montgomery(r,r,r,mont,ctx))
|
|
goto err;
|
|
}
|
|
if (wstart == 0) break;
|
|
wstart--;
|
|
continue;
|
|
}
|
|
/* We now have wstart on a 'set' bit, we now need to work out
|
|
* how bit a window to do. To do this we need to scan
|
|
* forward until the last set bit before the end of the
|
|
* window */
|
|
j=wstart;
|
|
wvalue=1;
|
|
wend=0;
|
|
for (i=1; i<window; i++)
|
|
{
|
|
if (wstart-i < 0) break;
|
|
if (BN_is_bit_set(p,wstart-i))
|
|
{
|
|
wvalue<<=(i-wend);
|
|
wvalue|=1;
|
|
wend=i;
|
|
}
|
|
}
|
|
|
|
/* wend is the size of the current window */
|
|
j=wend+1;
|
|
/* add the 'bytes above' */
|
|
if (!start)
|
|
for (i=0; i<j; i++)
|
|
{
|
|
if (!BN_mod_mul_montgomery(r,r,r,mont,ctx))
|
|
goto err;
|
|
}
|
|
|
|
/* wvalue will be an odd number < 2^window */
|
|
if (!BN_mod_mul_montgomery(r,r,&(val[wvalue>>1]),mont,ctx))
|
|
goto err;
|
|
|
|
/* move the 'window' down further */
|
|
wstart-=wend+1;
|
|
wvalue=0;
|
|
start=0;
|
|
if (wstart < 0) break;
|
|
}
|
|
if (!BN_from_montgomery(rr,r,mont,ctx)) goto err;
|
|
ret=1;
|
|
err:
|
|
if ((in_mont == NULL) && (mont != NULL)) BN_MONT_CTX_free(mont);
|
|
BN_CTX_end(ctx);
|
|
for (i=0; i<ts; i++)
|
|
BN_clear_free(&(val[i]));
|
|
return(ret);
|
|
}
|
|
|
|
BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w)
|
|
{
|
|
#ifndef BN_LLONG
|
|
BN_ULONG ret=0;
|
|
#else
|
|
BN_ULLONG ret=0;
|
|
#endif
|
|
int i;
|
|
|
|
w&=BN_MASK2;
|
|
for (i=a->top-1; i>=0; i--)
|
|
{
|
|
#ifndef BN_LLONG
|
|
ret=((ret<<BN_BITS4)|((a->d[i]>>BN_BITS4)&BN_MASK2l))%w;
|
|
ret=((ret<<BN_BITS4)|(a->d[i]&BN_MASK2l))%w;
|
|
#else
|
|
ret=(BN_ULLONG)(((ret<<(BN_ULLONG)BN_BITS2)|a->d[i])%
|
|
(BN_ULLONG)w);
|
|
#endif
|
|
}
|
|
return((BN_ULONG)ret);
|
|
}
|
|
|
|
static int bnrand(int pseudorand, BIGNUM *rnd, int bits, int top, int bottom)
|
|
{
|
|
unsigned char *buf=NULL;
|
|
int ret=0,bit,bytes,mask;
|
|
|
|
if (bits == 0)
|
|
{
|
|
BN_zero(rnd);
|
|
return 1;
|
|
}
|
|
|
|
bytes=(bits+7)/8;
|
|
bit=(bits-1)%8;
|
|
mask=0xff<<bit;
|
|
|
|
buf=(unsigned char *)malloc(bytes);
|
|
if (buf == NULL)
|
|
{
|
|
goto err;
|
|
}
|
|
|
|
/* make a random number and set the top and bottom bits */
|
|
/* this ignores the pseudorand flag */
|
|
|
|
t_random(buf, bytes);
|
|
|
|
if (top)
|
|
{
|
|
if (bit == 0)
|
|
{
|
|
buf[0]=1;
|
|
buf[1]|=0x80;
|
|
}
|
|
else
|
|
{
|
|
buf[0]|=(3<<(bit-1));
|
|
buf[0]&= ~(mask<<1);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
buf[0]|=(1<<bit);
|
|
buf[0]&= ~(mask<<1);
|
|
}
|
|
if (bottom) /* set bottom bits to whatever odd is */
|
|
buf[bytes-1]|=1;
|
|
if (!BN_bin2bn(buf,bytes,rnd)) goto err;
|
|
ret=1;
|
|
err:
|
|
if (buf != NULL)
|
|
{
|
|
memset(buf,0,bytes);
|
|
free(buf);
|
|
}
|
|
return(ret);
|
|
}
|
|
|
|
/* BN_pseudo_rand is the same as BN_rand, now. */
|
|
|
|
int BN_pseudo_rand(BIGNUM *rnd, int bits, int top, int bottom)
|
|
{
|
|
return bnrand(1, rnd, bits, top, bottom);
|
|
}
|
|
|
|
#define MONT_WORD /* use the faster word-based algorithm */
|
|
|
|
int BN_mod_mul_montgomery(BIGNUM *r, BIGNUM *a, BIGNUM *b,
|
|
BN_MONT_CTX *mont, BN_CTX *ctx)
|
|
{
|
|
BIGNUM *tmp,*tmp2;
|
|
int ret=0;
|
|
|
|
BN_CTX_start(ctx);
|
|
tmp = BN_CTX_get(ctx);
|
|
tmp2 = BN_CTX_get(ctx);
|
|
if (tmp == NULL || tmp2 == NULL) goto err;
|
|
|
|
bn_check_top(tmp);
|
|
bn_check_top(tmp2);
|
|
|
|
if (a == b)
|
|
{
|
|
if (!BN_sqr(tmp,a,ctx)) goto err;
|
|
}
|
|
else
|
|
{
|
|
if (!BN_mul(tmp,a,b,ctx)) goto err;
|
|
}
|
|
/* reduce from aRR to aR */
|
|
if (!BN_from_montgomery(r,tmp,mont,ctx)) goto err;
|
|
ret=1;
|
|
err:
|
|
BN_CTX_end(ctx);
|
|
return(ret);
|
|
}
|
|
|
|
int BN_from_montgomery(BIGNUM *ret, BIGNUM *a, BN_MONT_CTX *mont,
|
|
BN_CTX *ctx)
|
|
{
|
|
int retn=0;
|
|
|
|
#ifdef MONT_WORD
|
|
BIGNUM *n,*r;
|
|
BN_ULONG *ap,*np,*rp,n0,v,*nrp;
|
|
int al,nl,max,i,x,ri;
|
|
|
|
BN_CTX_start(ctx);
|
|
if ((r = BN_CTX_get(ctx)) == NULL) goto err;
|
|
|
|
if (!BN_copy(r,a)) goto err;
|
|
n= &(mont->N);
|
|
|
|
ap=a->d;
|
|
/* mont->ri is the size of mont->N in bits (rounded up
|
|
to the word size) */
|
|
al=ri=mont->ri/BN_BITS2;
|
|
|
|
nl=n->top;
|
|
if ((al == 0) || (nl == 0)) { r->top=0; return(1); }
|
|
|
|
max=(nl+al+1); /* allow for overflow (no?) XXX */
|
|
if (bn_wexpand(r,max) == NULL) goto err;
|
|
if (bn_wexpand(ret,max) == NULL) goto err;
|
|
|
|
r->neg=a->neg^n->neg;
|
|
np=n->d;
|
|
rp=r->d;
|
|
nrp= &(r->d[nl]);
|
|
|
|
/* clear the top words of T */
|
|
#if 1
|
|
for (i=r->top; i<max; i++) /* memset? XXX */
|
|
r->d[i]=0;
|
|
#else
|
|
memset(&(r->d[r->top]),0,(max-r->top)*sizeof(BN_ULONG));
|
|
#endif
|
|
|
|
r->top=max;
|
|
n0=mont->n0;
|
|
|
|
#ifdef BN_COUNT
|
|
printf("word BN_from_montgomery %d * %d\n",nl,nl);
|
|
#endif
|
|
for (i=0; i<nl; i++)
|
|
{
|
|
#ifdef __TANDEM
|
|
{
|
|
long long t1;
|
|
long long t2;
|
|
long long t3;
|
|
t1 = rp[0] * (n0 & 0177777);
|
|
t2 = 037777600000l;
|
|
t2 = n0 & t2;
|
|
t3 = rp[0] & 0177777;
|
|
t2 = (t3 * t2) & BN_MASK2;
|
|
t1 = t1 + t2;
|
|
v=bn_mul_add_words(rp,np,nl,(BN_ULONG) t1);
|
|
}
|
|
#else
|
|
v=bn_mul_add_words(rp,np,nl,(rp[0]*n0)&BN_MASK2);
|
|
#endif
|
|
nrp++;
|
|
rp++;
|
|
if (((nrp[-1]+=v)&BN_MASK2) >= v)
|
|
continue;
|
|
else
|
|
{
|
|
if (((++nrp[0])&BN_MASK2) != 0) continue;
|
|
if (((++nrp[1])&BN_MASK2) != 0) continue;
|
|
for (x=2; (((++nrp[x])&BN_MASK2) == 0); x++) ;
|
|
}
|
|
}
|
|
bn_fix_top(r);
|
|
|
|
/* mont->ri will be a multiple of the word size */
|
|
#if 0
|
|
BN_rshift(ret,r,mont->ri);
|
|
#else
|
|
ret->neg = r->neg;
|
|
x=ri;
|
|
rp=ret->d;
|
|
ap= &(r->d[x]);
|
|
if (r->top < x)
|
|
al=0;
|
|
else
|
|
al=r->top-x;
|
|
ret->top=al;
|
|
al-=4;
|
|
for (i=0; i<al; i+=4)
|
|
{
|
|
BN_ULONG t1,t2,t3,t4;
|
|
|
|
t1=ap[i+0];
|
|
t2=ap[i+1];
|
|
t3=ap[i+2];
|
|
t4=ap[i+3];
|
|
rp[i+0]=t1;
|
|
rp[i+1]=t2;
|
|
rp[i+2]=t3;
|
|
rp[i+3]=t4;
|
|
}
|
|
al+=4;
|
|
for (; i<al; i++)
|
|
rp[i]=ap[i];
|
|
#endif
|
|
#else /* !MONT_WORD */
|
|
BIGNUM *t1,*t2;
|
|
|
|
BN_CTX_start(ctx);
|
|
t1 = BN_CTX_get(ctx);
|
|
t2 = BN_CTX_get(ctx);
|
|
if (t1 == NULL || t2 == NULL) goto err;
|
|
|
|
if (!BN_copy(t1,a)) goto err;
|
|
BN_mask_bits(t1,mont->ri);
|
|
|
|
if (!BN_mul(t2,t1,&mont->Ni,ctx)) goto err;
|
|
BN_mask_bits(t2,mont->ri);
|
|
|
|
if (!BN_mul(t1,t2,&mont->N,ctx)) goto err;
|
|
if (!BN_add(t2,a,t1)) goto err;
|
|
BN_rshift(ret,t2,mont->ri);
|
|
#endif /* MONT_WORD */
|
|
|
|
if (BN_ucmp(ret, &(mont->N)) >= 0)
|
|
{
|
|
BN_usub(ret,ret,&(mont->N));
|
|
}
|
|
retn=1;
|
|
err:
|
|
BN_CTX_end(ctx);
|
|
return(retn);
|
|
}
|
|
|
|
void BN_MONT_CTX_init(BN_MONT_CTX *ctx)
|
|
{
|
|
ctx->ri=0;
|
|
BN_init(&(ctx->RR));
|
|
BN_init(&(ctx->N));
|
|
BN_init(&(ctx->Ni));
|
|
ctx->flags=0;
|
|
}
|
|
|
|
BN_MONT_CTX *BN_MONT_CTX_new(void)
|
|
{
|
|
BN_MONT_CTX *ret;
|
|
|
|
if ((ret=(BN_MONT_CTX *)malloc(sizeof(BN_MONT_CTX))) == NULL)
|
|
return(NULL);
|
|
|
|
BN_MONT_CTX_init(ret);
|
|
ret->flags=BN_FLG_MALLOCED;
|
|
return(ret);
|
|
}
|
|
|
|
void BN_MONT_CTX_free(BN_MONT_CTX *mont)
|
|
{
|
|
if(mont == NULL)
|
|
return;
|
|
|
|
BN_free(&(mont->RR));
|
|
BN_free(&(mont->N));
|
|
BN_free(&(mont->Ni));
|
|
if (mont->flags & BN_FLG_MALLOCED)
|
|
free(mont);
|
|
}
|
|
|
|
int BN_MONT_CTX_set(BN_MONT_CTX *mont, const BIGNUM *mod, BN_CTX *ctx)
|
|
{
|
|
BIGNUM Ri,*R;
|
|
|
|
BN_init(&Ri);
|
|
R= &(mont->RR); /* grab RR as a temp */
|
|
BN_copy(&(mont->N),mod); /* Set N */
|
|
|
|
#ifdef MONT_WORD
|
|
{
|
|
BIGNUM tmod;
|
|
BN_ULONG buf[2];
|
|
|
|
mont->ri=(BN_num_bits(mod)+(BN_BITS2-1))/BN_BITS2*BN_BITS2;
|
|
BN_zero(R);
|
|
BN_set_bit(R,BN_BITS2); /* R */
|
|
|
|
buf[0]=mod->d[0]; /* tmod = N mod word size */
|
|
buf[1]=0;
|
|
tmod.d=buf;
|
|
tmod.top=1;
|
|
tmod.dmax=2;
|
|
tmod.neg=mod->neg;
|
|
/* Ri = R^-1 mod N*/
|
|
if ((BN_mod_inverse(&Ri,R,&tmod,ctx)) == NULL)
|
|
goto err;
|
|
BN_lshift(&Ri,&Ri,BN_BITS2); /* R*Ri */
|
|
if (!BN_is_zero(&Ri))
|
|
BN_sub_word(&Ri,1);
|
|
else /* if N mod word size == 1 */
|
|
BN_set_word(&Ri,BN_MASK2); /* Ri-- (mod word size) */
|
|
BN_div(&Ri,NULL,&Ri,&tmod,ctx); /* Ni = (R*Ri-1)/N,
|
|
* keep only least significant word: */
|
|
mont->n0=Ri.d[0];
|
|
BN_free(&Ri);
|
|
}
|
|
#else /* !MONT_WORD */
|
|
{ /* bignum version */
|
|
mont->ri=BN_num_bits(mod);
|
|
BN_zero(R);
|
|
BN_set_bit(R,mont->ri); /* R = 2^ri */
|
|
/* Ri = R^-1 mod N*/
|
|
if ((BN_mod_inverse(&Ri,R,mod,ctx)) == NULL)
|
|
goto err;
|
|
BN_lshift(&Ri,&Ri,mont->ri); /* R*Ri */
|
|
BN_sub_word(&Ri,1);
|
|
/* Ni = (R*Ri-1) / N */
|
|
BN_div(&(mont->Ni),NULL,&Ri,mod,ctx);
|
|
BN_free(&Ri);
|
|
}
|
|
#endif
|
|
|
|
/* setup RR for conversions */
|
|
BN_zero(&(mont->RR));
|
|
BN_set_bit(&(mont->RR),mont->ri*2);
|
|
BN_mod(&(mont->RR),&(mont->RR),&(mont->N),ctx);
|
|
|
|
return(1);
|
|
err:
|
|
return(0);
|
|
}
|
|
|
|
BIGNUM *BN_value_one(void)
|
|
{
|
|
static BN_ULONG data_one=1L;
|
|
static BIGNUM const_one={&data_one,1,1,0};
|
|
|
|
return(&const_one);
|
|
}
|
|
|
|
/* solves ax == 1 (mod n) */
|
|
BIGNUM *BN_mod_inverse(BIGNUM *in, BIGNUM *a, const BIGNUM *n, BN_CTX *ctx)
|
|
{
|
|
BIGNUM *A,*B,*X,*Y,*M,*D,*R=NULL;
|
|
BIGNUM *T,*ret=NULL;
|
|
int sign;
|
|
|
|
bn_check_top(a);
|
|
bn_check_top(n);
|
|
|
|
BN_CTX_start(ctx);
|
|
A = BN_CTX_get(ctx);
|
|
B = BN_CTX_get(ctx);
|
|
X = BN_CTX_get(ctx);
|
|
D = BN_CTX_get(ctx);
|
|
M = BN_CTX_get(ctx);
|
|
Y = BN_CTX_get(ctx);
|
|
if (Y == NULL) goto err;
|
|
|
|
if (in == NULL)
|
|
R=BN_new();
|
|
else
|
|
R=in;
|
|
if (R == NULL) goto err;
|
|
|
|
BN_zero(X);
|
|
BN_one(Y);
|
|
if (BN_copy(A,a) == NULL) goto err;
|
|
if (BN_copy(B,n) == NULL) goto err;
|
|
sign=1;
|
|
|
|
while (!BN_is_zero(B))
|
|
{
|
|
if (!BN_div(D,M,A,B,ctx)) goto err;
|
|
T=A;
|
|
A=B;
|
|
B=M;
|
|
/* T has a struct, M does not */
|
|
|
|
if (!BN_mul(T,D,X,ctx)) goto err;
|
|
if (!BN_add(T,T,Y)) goto err;
|
|
M=Y;
|
|
Y=X;
|
|
X=T;
|
|
sign= -sign;
|
|
}
|
|
if (sign < 0)
|
|
{
|
|
if (!BN_sub(Y,n,Y)) goto err;
|
|
}
|
|
|
|
if (BN_is_one(A))
|
|
{ if (!BN_mod(R,Y,n,ctx)) goto err; }
|
|
else
|
|
{
|
|
goto err;
|
|
}
|
|
ret=R;
|
|
err:
|
|
if ((ret == NULL) && (in == NULL)) BN_free(R);
|
|
BN_CTX_end(ctx);
|
|
return(ret);
|
|
}
|
|
|
|
int BN_set_bit(BIGNUM *a, int n)
|
|
{
|
|
int i,j,k;
|
|
|
|
i=n/BN_BITS2;
|
|
j=n%BN_BITS2;
|
|
if (a->top <= i)
|
|
{
|
|
if (bn_wexpand(a,i+1) == NULL) return(0);
|
|
for(k=a->top; k<i+1; k++)
|
|
a->d[k]=0;
|
|
a->top=i+1;
|
|
}
|
|
|
|
a->d[i]|=(((BN_ULONG)1)<<j);
|
|
return(1);
|
|
}
|
|
|