DSApriv* dsagen(DSApub *opub) { DSApub *pub; DSApriv *priv; mpint *exp; mpint *g; mpint *r; int bits; priv = dsaprivalloc(); pub = &priv->pub; if(opub != nil){ pub->p = mpcopy(opub->p); pub->q = mpcopy(opub->q); } else { pub->p = mpnew(0); pub->q = mpnew(0); DSAprimes(pub->q, pub->p, nil); } bits = Dbits*pub->p->top; pub->alpha = mpnew(0); pub->key = mpnew(0); priv->secret = mpnew(0); // find a generator alpha of the multiplicative // group Z*p, i.e., of order n = p-1. We use the // fact that q divides p-1 to reduce the exponent. exp = mpnew(0); g = mpnew(0); r = mpnew(0); mpsub(pub->p, mpone, exp); mpdiv(exp, pub->q, exp, r); if(mpcmp(r, mpzero) != 0) sysfatal("dsagen foul up"); while(1){ mprand(bits, genrandom, g); mpmod(g, pub->p, g); mpexp(g, exp, pub->p, pub->alpha); if(mpcmp(pub->alpha, mpone) != 0) break; } mpfree(g); mpfree(exp); // create the secret key mprand(bits, genrandom, priv->secret); mpmod(priv->secret, pub->p, priv->secret); mpexp(pub->alpha, priv->secret, pub->p, pub->key); return priv; }
// find a prime p of length n and a generator alpha of Z^*_p // Alg 4.86 Menezes et al () Handbook, p.164 void gensafeprime(mpint *p, mpint *alpha, int n, int accuracy) { mpint *q, *b; q = mpnew(n-1); while(1){ genprime(q, n-1, accuracy); mpleft(q, 1, p); mpadd(p, mpone, p); // p = 2*q+1 if(probably_prime(p, accuracy)) break; } // now find a generator alpha of the multiplicative // group Z*_p of order p-1=2q b = mpnew(0); while(1){ mprand(n, genrandom, alpha); mpmod(alpha, p, alpha); mpmul(alpha, alpha, b); mpmod(b, p, b); if(mpcmp(b, mpone) == 0) continue; mpexp(alpha, q, p, b); if(mpcmp(b, mpone) != 0) break; } mpfree(b); mpfree(q); }
DSAsig* dsasign(DSApriv *priv, mpint *m) { DSApub *pub = &priv->pub; DSAsig *sig; mpint *qm1, *k, *kinv, *r, *s; mpint *q = pub->q, *p = pub->p, *alpha = pub->alpha; int qlen = mpsignif(q); qm1 = mpnew(0); kinv = mpnew(0); r = mpnew(0); s = mpnew(0); k = mpnew(0); mpsub(pub->q, mpone, qm1); // find a k that has an inverse mod q while(1){ mprand(qlen, genrandom, k); if((mpcmp(mpone, k) > 0) || (mpcmp(k, qm1) >= 0)) continue; mpextendedgcd(k, q, r, kinv, s); if(mpcmp(r, mpone) != 0) continue; break; } // make kinv positive mpmod(kinv, qm1, kinv); // r = ((alpha**k) mod p) mod q mpexp(alpha, k, p, r); mpmod(r, q, r); // s = (kinv*(m + ar)) mod q mpmul(r, priv->secret, s); mpadd(s, m, s); mpmul(s, kinv, s); mpmod(s, q, s); sig = dsasigalloc(); sig->r = r; sig->s = s; mpfree(qm1); mpfree(k); mpfree(kinv); return sig; }
EGpriv* eggen(int nlen, int rounds) { EGpub *pub; EGpriv *priv; priv = egprivalloc(); pub = &priv->pub; pub->p = mpnew(0); pub->alpha = mpnew(0); pub->key = mpnew(0); priv->secret = mpnew(0); gensafeprime(pub->p, pub->alpha, nlen, rounds); mprand(nlen-1, genrandom, priv->secret); mpexp(pub->alpha, priv->secret, pub->p, pub->key); return priv; }
ECpriv* ecgen(ECdomain *dom, ECpriv *p) { if(p == nil){ p = mallocz(sizeof(*p), 1); if(p == nil) return nil; p->x = mpnew(0); p->y = mpnew(0); p->d = mpnew(0); } for(;;){ mprand(mpsignif(dom->n), genrandom, p->d); if(mpcmp(p->d, mpzero) > 0 && mpcmp(p->d, dom->n) < 0) break; } ecmul(dom, dom->G, p->d, p); return p; }
static int mpsqrt(mpint *n, mpint *p, mpint *r) { mpint *a, *t, *s, *xp, *xq, *yp, *yq, *zp, *zq, *N; if(mpleg(n, p) == -1) return 0; a = mpnew(0); t = mpnew(0); s = mpnew(0); N = mpnew(0); xp = mpnew(0); xq = mpnew(0); yp = mpnew(0); yq = mpnew(0); zp = mpnew(0); zq = mpnew(0); for(;;){ for(;;){ mprand(mpsignif(p), genrandom, a); if(mpcmp(a, mpzero) > 0 && mpcmp(a, p) < 0) break; } mpmul(a, a, t); mpsub(t, n, t); mpmod(t, p, t); if(mpleg(t, p) == -1) break; } mpadd(p, mpone, N); mpright(N, 1, N); mpmul(a, a, t); mpsub(t, n, t); mpassign(a, xp); uitomp(1, xq); uitomp(1, yp); uitomp(0, yq); while(mpcmp(N, mpzero) != 0){ if(N->p[0] & 1){ mpmul(xp, yp, zp); mpmul(xq, yq, zq); mpmul(zq, t, zq); mpadd(zp, zq, zp); mpmod(zp, p, zp); mpmul(xp, yq, zq); mpmul(xq, yp, s); mpadd(zq, s, zq); mpmod(zq, p, yq); mpassign(zp, yp); } mpmul(xp, xp, zp); mpmul(xq, xq, zq); mpmul(zq, t, zq); mpadd(zp, zq, zp); mpmod(zp, p, zp); mpmul(xp, xq, zq); mpadd(zq, zq, zq); mpmod(zq, p, xq); mpassign(zp, xp); mpright(N, 1, N); } if(mpcmp(yq, mpzero) != 0) abort(); mpassign(yp, r); mpfree(a); mpfree(t); mpfree(s); mpfree(N); mpfree(xp); mpfree(xq); mpfree(yp); mpfree(yq); mpfree(zp); mpfree(zq); return 1; }
RSApriv* rsagen(int nlen, int elen, int rounds) { mpint *p, *q, *e, *d, *phi, *n, *t1, *t2, *kp, *kq, *c2; RSApriv *rsa; p = mpnew(nlen/2); q = mpnew(nlen/2); n = mpnew(nlen); e = mpnew(elen); d = mpnew(0); phi = mpnew(nlen); // create the prime factors and euclid's function genprime(p, nlen/2, rounds); genprime(q, nlen - mpsignif(p) + 1, rounds); mpmul(p, q, n); mpsub(p, mpone, e); mpsub(q, mpone, d); mpmul(e, d, phi); // find an e relatively prime to phi t1 = mpnew(0); t2 = mpnew(0); mprand(elen, genrandom, e); if(mpcmp(e,mptwo) <= 0) itomp(3, e); // See Menezes et al. p.291 "8.8 Note (selecting primes)" for discussion // of the merits of various choices of primes and exponents. e=3 is a // common and recommended exponent, but doesn't necessarily work here // because we chose strong rather than safe primes. for(;;){ mpextendedgcd(e, phi, t1, d, t2); if(mpcmp(t1, mpone) == 0) break; mpadd(mpone, e, e); } mpfree(t1); mpfree(t2); // compute chinese remainder coefficient c2 = mpnew(0); mpinvert(p, q, c2); // for crt a**k mod p == (a**(k mod p-1)) mod p kq = mpnew(0); kp = mpnew(0); mpsub(p, mpone, phi); mpmod(d, phi, kp); mpsub(q, mpone, phi); mpmod(d, phi, kq); rsa = rsaprivalloc(); rsa->pub.ek = e; rsa->pub.n = n; rsa->dk = d; rsa->kp = kp; rsa->kq = kq; rsa->p = p; rsa->q = q; rsa->c2 = c2; mpfree(phi); return rsa; }
/* * Miller-Rabin probabilistic primality testing * Knuth (1981) Seminumerical Algorithms, p.379 * Menezes et al () Handbook, p.39 * 0 if composite; 1 if almost surely prime, Pr(err)<1/4**nrep */ int probably_prime(mpint *n, int nrep) { int j, k, rep, nbits, isprime; mpint *nm1, *q, *x, *y, *r; if(n->sign < 0) sysfatal("negative prime candidate"); if(nrep <= 0) nrep = 18; k = mptoi(n); if(k == 2) /* 2 is prime */ return 1; if(k < 2) /* 1 is not prime */ return 0; if((n->p[0] & 1) == 0) /* even is not prime */ return 0; /* test against small prime numbers */ if(smallprimetest(n) < 0) return 0; /* fermat test, 2^n mod n == 2 if p is prime */ x = uitomp(2, nil); y = mpnew(0); mpexp(x, n, n, y); k = mptoi(y); if(k != 2){ mpfree(x); mpfree(y); return 0; } nbits = mpsignif(n); nm1 = mpnew(nbits); mpsub(n, mpone, nm1); /* nm1 = n - 1 */ k = mplowbits0(nm1); q = mpnew(0); mpright(nm1, k, q); /* q = (n-1)/2**k */ for(rep = 0; rep < nrep; rep++){ for(;;){ /* find x = random in [2, n-2] */ r = mprand(nbits, prng, nil); mpmod(r, nm1, x); mpfree(r); if(mpcmp(x, mpone) > 0) break; } /* y = x**q mod n */ mpexp(x, q, n, y); if(mpcmp(y, mpone) == 0 || mpcmp(y, nm1) == 0) continue; for(j = 1;; j++){ if(j >= k) { isprime = 0; goto done; } mpmul(y, y, x); mpmod(x, n, y); /* y = y*y mod n */ if(mpcmp(y, nm1) == 0) break; if(mpcmp(y, mpone) == 0){ isprime = 0; goto done; } } } isprime = 1; done: mpfree(y); mpfree(x); mpfree(q); mpfree(nm1); return isprime; }
// Miller-Rabin probabilistic primality testing // Knuth (1981) Seminumerical Algorithms, p.379 // Menezes et al () Handbook, p.39 // 0 if composite; 1 if almost surely prime, Pr(err)<1/4**nrep int probably_prime(mpint *n, int nrep) { int j, k, rep, nbits, isprime = 1; mpint *nm1, *q, *x, *y, *r; if(n->sign < 0) sysfatal("negative prime candidate"); if(nrep <= 0) nrep = 18; k = mptoi(n); if(k == 2) // 2 is prime return 1; if(k < 2) // 1 is not prime return 0; if((n->p[0] & 1) == 0) // even is not prime return 0; // test against small prime numbers if(smallprimetest(n) < 0) return 0; // fermat test, 2^n mod n == 2 if p is prime x = uitomp(2, nil); y = mpnew(0); mpexp(x, n, n, y); k = mptoi(y); if(k != 2){ mpfree(x); mpfree(y); return 0; } nbits = mpsignif(n); nm1 = mpnew(nbits); mpsub(n, mpone, nm1); // nm1 = n - 1 */ k = mplowbits0(nm1); q = mpnew(0); mpright(nm1, k, q); // q = (n-1)/2**k for(rep = 0; rep < nrep; rep++){ // x = random in [2, n-2] r = mprand(nbits, prng, nil); mpmod(r, nm1, x); mpfree(r); if(mpcmp(x, mpone) <= 0) continue; // y = x**q mod n mpexp(x, q, n, y); if(mpcmp(y, mpone) == 0 || mpcmp(y, nm1) == 0) goto done; for(j = 1; j < k; j++){ mpmul(y, y, x); mpmod(x, n, y); // y = y*y mod n if(mpcmp(y, nm1) == 0) goto done; if(mpcmp(y, mpone) == 0){ isprime = 0; goto done; } } isprime = 0; } done: mpfree(y); mpfree(x); mpfree(q); mpfree(nm1); return isprime; }