java-ec.com.unbound.common.crypto.ec.SunEC Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of unbound-java-provider Show documentation
Show all versions of unbound-java-provider Show documentation
This is a collection of JAVA libraries that implement Unbound cryptographic classes for JAVA provider, PKCS11 wrapper, cryptoki, and advapi
package com.unbound.common.crypto.ec;
import javax.crypto.KeyAgreement;
import java.math.BigInteger;
import java.security.AlgorithmParameters;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.*;
import java.time.Clock;
public final class SunEC
{
public static final class Curve
{
private ECGenParameterSpec genSpec;
private AlgorithmParameters algParam;
private ECParameterSpec spec;
private EllipticCurve ec;
private ECFieldFp field;
public ECPoint G;
public BigInteger q;
public BigInteger p;
public BigInteger a;
public BigInteger b;
public int bits;
public int size;
private Curve(String name)
{
genSpec = new ECGenParameterSpec(name);
try
{
algParam = AlgorithmParameters.getInstance("EC");
algParam.init(genSpec);
spec = algParam.getParameterSpec(ECParameterSpec.class);
q = spec.getOrder();
G = spec.getGenerator();
bits = q.bitLength();
size = (bits + 7) / 8;
ec = spec.getCurve();
a = ec.getA();
b = ec.getB();
field = (ECFieldFp) ec.getField();
p = field.getP();
}
catch (NoSuchAlgorithmException | InvalidParameterSpecException e)
{
throw new RuntimeException(e);
}
}
private static class Arithmetic
{
public static final BigInteger ZERO = BigInteger.valueOf(0);
public static final BigInteger ONE = BigInteger.valueOf(1);
public static final BigInteger TWO = BigInteger.valueOf(2);
public static final BigInteger FOUR = BigInteger.valueOf(4);
private static final int[] jacobiTable = {0, 1, 0, -1, 0, -1, 0, 1};
public static int jacobi(BigInteger A, BigInteger B)
{
BigInteger a, b, v;
long k = 1;
k = 1;
// test trivial cases
if (B.equals(ZERO))
{
a = A.abs();
return a.equals(ONE) ? 1 : 0;
}
if (!A.testBit(0) && !B.testBit(0))
{
return 0;
}
a = A;
b = B;
if (b.signum() == -1)
{ // b < 0
b = b.negate(); // b = -b
if (a.signum() == -1)
{
k = -1;
}
}
v = ZERO;
while (!b.testBit(0))
{
v = v.add(ONE); // v = v + 1
b = b.divide(TWO); // b = b/2
}
if (v.testBit(0))
{
k = k * jacobiTable[a.intValue() & 7];
}
if (a.signum() < 0)
{ // a < 0
if (b.testBit(1))
{
k = -k; // k = -k
}
a = a.negate(); // a = -a
}
// main loop
while (a.signum() != 0)
{
v = ZERO;
while (!a.testBit(0))
{ // a is even
v = v.add(ONE);
a = a.divide(TWO);
}
if (v.testBit(0))
{
k = k * jacobiTable[b.intValue() & 7];
}
if (a.compareTo(b) < 0)
{ // a < b
// swap and correct intermediate result
BigInteger x = a;
a = b;
b = x;
if (a.testBit(1) && b.testBit(1))
{
k = -k;
}
}
a = a.subtract(b);
}
return b.equals(ONE) ? (int) k : 0;
}
public static BigInteger sqrtP(BigInteger a, BigInteger p)
throws IllegalArgumentException
{
BigInteger v = null;
if (a.compareTo(ZERO) < 0)
{
a = a.add(p);
}
if (a.equals(ZERO))
{
return ZERO;
}
if (p.equals(TWO))
{
return a;
}
// p = 3 mod 4
if (p.testBit(0) && p.testBit(1))
{
if (jacobi(a, p) == 1)
{ // a quadr. residue mod p
v = p.add(ONE); // v = p+1
v = v.shiftRight(2); // v = v/4
return a.modPow(v, p); // return a^v mod p
// return --> a^((p+1)/4) mod p
}
throw new IllegalArgumentException("No quadratic residue: " + a + ", " + p);
}
long t = 0;
// initialization
// compute k and s, where p = 2^s (2k+1) +1
BigInteger k = p.subtract(ONE); // k = p-1
long s = 0;
while (!k.testBit(0))
{ // while k is even
s++; // s = s+1
k = k.shiftRight(1); // k = k/2
}
k = k.subtract(ONE); // k = k - 1
k = k.shiftRight(1); // k = k/2
// initial values
BigInteger r = a.modPow(k, p); // r = a^k mod p
BigInteger n = r.multiply(r).remainder(p); // n = r^2 % p
n = n.multiply(a).remainder(p); // n = n * a % p
r = r.multiply(a).remainder(p); // r = r * a %p
if (n.equals(ONE))
{
return r;
}
// non-quadratic residue
BigInteger z = TWO; // z = 2
while (jacobi(z, p) == 1)
{
// while z quadratic residue
z = z.add(ONE); // z = z + 1
}
v = k;
v = v.multiply(TWO); // v = 2k
v = v.add(ONE); // v = 2k + 1
BigInteger c = z.modPow(v, p); // c = z^v mod p
// iteration
while (n.compareTo(ONE) == 1)
{ // n > 1
k = n; // k = n
t = s; // t = s
s = 0;
while (!k.equals(ONE))
{ // k != 1
k = k.multiply(k).mod(p); // k = k^2 % p
s++; // s = s + 1
}
t -= s; // t = t - s
if (t == 0)
{
throw new IllegalArgumentException("No quadratic residue: " + a + ", " + p);
}
v = ONE;
for (long i = 0; i < t - 1; i++)
{
v = v.shiftLeft(1); // v = 1 * 2^(t - 1)
}
c = c.modPow(v, p); // c = c^v mod p
r = r.multiply(c).remainder(p); // r = r * c % p
c = c.multiply(c).remainder(p); // c = c^2 % p
n = n.multiply(c).mod(p); // n = n * c % p
}
return r;
}
public static BigInteger subP(BigInteger a, BigInteger b, BigInteger p)
{
if (a.compareTo(b) >= 0) return a.subtract(b);
return a.add(p).subtract(b);
}
public static BigInteger divP(BigInteger a, BigInteger b, BigInteger p)
{
BigInteger inv = b.modInverse(p);
return a.multiply(inv).mod(p);
}
}
private BigInteger subP(BigInteger x, BigInteger y)
{
return Arithmetic.subP(x, y, p);
}
private BigInteger divP(BigInteger x, BigInteger y)
{
return Arithmetic.divP(x, y, p);
}
public ECPoint add(ECPoint a, ECPoint b)
{
BigInteger x2, y2;
BigInteger x0 = a.getAffineX();
BigInteger y0 = a.getAffineY();
BigInteger x1 = b.getAffineX();
BigInteger y1 = b.getAffineY();
BigInteger s;
if (a.equals(b))
{
BigInteger TWO = BigInteger.valueOf(2);
BigInteger THREE = BigInteger.valueOf(3);
s = divP(x0.multiply(x0).multiply(THREE).add(this.a).mod(p), y0.multiply(TWO.mod(p)));
}
else
{
s = divP(subP(y0, y1), subP(x0, x1));
}
x2 = subP(subP(s.multiply(s).mod(p), x0), x1);
y2 = subP(subP(x0, x2).multiply(s).mod(p), y0);
return new ECPoint(x2, y2);
}
public ECPrivateKey getPrivateKey(BigInteger d)
{
try
{
return (ECPrivateKey) KeyFactory.getInstance("EC").generatePrivate(new ECPrivateKeySpec(d, spec));
}
catch (Exception e)
{
throw new IllegalArgumentException(e);
}
}
public ECPublicKey getPublicKey(ECPoint point)
{
try
{
return (ECPublicKey) KeyFactory.getInstance("EC").generatePublic(new ECPublicKeySpec(point, spec));
}
catch (Exception e)
{
throw new IllegalArgumentException(e);
}
}
public static byte[] ecdh(KeyAgreement ka, ECPrivateKey prv, ECPublicKey pub)
{
try
{
if (ka==null) ka = KeyAgreement.getInstance("ECDH");
ka.init(prv);
ka.doPhase(pub, true);
return ka.generateSecret();
}
catch (Exception e)
{
throw new IllegalArgumentException(e);
}
}
public static byte[] ecdh(ECPrivateKey prv, ECPublicKey pub)
{
return ecdh(null, prv, pub);
}
public ECPoint mul(ECPrivateKey prvKey, BigInteger d, ECPublicKey pubKey, ECPoint p)
{
return mul(null, prvKey, d, pubKey, p);
}
public ECPoint mul(KeyAgreement ka, ECPrivateKey prvKey, BigInteger d, ECPublicKey pubKey, ECPoint p)
{
if (prvKey == null) prvKey = getPrivateKey(d);
if (pubKey == null) pubKey = getPublicKey(p);
if (p == null) p = pubKey.getW();
BigInteger x = new BigInteger(1, ecdh(ka, prvKey, pubKey));
BigInteger d1 = prvKey.getS().add(BigInteger.ONE);
ECPrivateKey next = getPrivateKey(d1);
BigInteger xNext = new BigInteger(1, ecdh(next, pubKey));
BigInteger y0 = recoverY(x, false);
ECPoint point = new ECPoint(x, y0);
BigInteger xTest = add(point, p).getAffineX();
if (xTest.equals(xNext)) return point;
BigInteger y1 = field.getP().subtract(y0);
return new ECPoint(x, y1);
}
public ECPoint mul(BigInteger d, ECPoint p)
{
return mul(null, d, null, p);
}
private BigInteger recoverY(BigInteger x, boolean bit0)
{
BigInteger a = ec.getA();
BigInteger b = ec.getB();
BigInteger p = field.getP();
BigInteger y2 = x.multiply(x).add(a).multiply(x).add(b).mod(p);
BigInteger y = Arithmetic.sqrtP(y2, p);
if (bit0 != y.testBit(0))
{
y = p.subtract(y).mod(p);
}
return y;
}
}
static public Curve getSecP256R1()
{
return new Curve("secp256r1");
}
static public Curve getSecP256K1() { return new Curve("secp256k1"); }
static public Curve getSecP384R1() { return new Curve("secp384r1"); }
static public Curve getSecP521R1() { return new Curve("secp521r1"); }
static void test(SunEC.Curve cc, com.unbound.common.crypto.ec.Curve curve) throws Exception
{
assert(cc.p.equals(curve.getP()));
assert(cc.b.equals(curve.getB()));
assert(cc.q.equals(curve.getQ()));
assert(cc.a.equals(curve.getA()));
ECPoint GG = cc.G;
Point G = curve.G;
assert(!G.isInfinity());
assert(G.equals(GG));
assert(G.getX().equals(GG.getAffineX()));
assert(G.getY().equals(GG.getAffineY()));
assert(G.isOnCurve());
ECPoint GG2 = cc.add(GG, GG);
Point G2 = G.dbl();
assert(G2.equals(GG2));
ECPoint GG3 = cc.add(GG2, GG); GG3 = cc.add(GG3, GG3); GG3 = cc.add(GG3, GG);
Point G3 = G.add(G2);
G3 = G3.dbl();
G3 = G3.add(G);
assert(G3.equals(GG3));
assert(G3.getX().equals(GG3.getAffineX()));
assert(G3.getY().equals(GG3.getAffineY()));
assert(G3.isOnCurve());
BigInteger dd = new BigInteger(254, new SecureRandom());
int n = 10000;
/*
ECPoint GG4 = null;
ECPrivateKey prvKey = cc.getPrivateKey(dd);
ECPublicKey pubKey = cc.getPublicKey(GG);
KeyAgreement ka;
try { ka = KeyAgreement.getInstance("ECDH"); }
catch (NoSuchAlgorithmException e) { throw new RuntimeException(e); }
long t1 = Clock.systemUTC().millis();
for (int i=0; i