forked from I2P_Developers/i2p.i2p
KeyGenerator: Add support for converting
all signing key types from private to public
This commit is contained in:
135
core/java/src/net/i2p/crypto/ECUtil.java
Normal file
135
core/java/src/net/i2p/crypto/ECUtil.java
Normal file
@ -0,0 +1,135 @@
|
||||
package net.i2p.crypto;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.security.spec.ECField;
|
||||
import java.security.spec.ECFieldFp;
|
||||
import java.security.spec.ECPoint;
|
||||
import java.security.spec.EllipticCurve;
|
||||
|
||||
import net.i2p.util.NativeBigInteger;
|
||||
|
||||
/**
|
||||
* Used by KeyGenerator.getSigningPublicKey()
|
||||
*
|
||||
* Modified from
|
||||
* http://stackoverflow.com/questions/15727147/scalar-multiplication-of-point-over-elliptic-curve
|
||||
* Apparently public domain.
|
||||
* Supported P-192 only.
|
||||
* Added curve parameters to support all curves.
|
||||
*
|
||||
* @since 0.9.16
|
||||
*/
|
||||
class ECUtil {
|
||||
|
||||
private static final BigInteger TWO = new BigInteger("2");
|
||||
private static final BigInteger THREE = new BigInteger("3");
|
||||
|
||||
public static ECPoint scalarMult(ECPoint p, BigInteger kin, EllipticCurve curve) {
|
||||
ECPoint r = ECPoint.POINT_INFINITY;
|
||||
BigInteger prime = ((ECFieldFp) curve.getField()).getP();
|
||||
BigInteger k = kin.mod(prime);
|
||||
int length = k.bitLength();
|
||||
byte[] binarray = new byte[length];
|
||||
for (int i = 0; i <= length-1; i++) {
|
||||
binarray[i] = k.mod(TWO).byteValue();
|
||||
k = k.divide(TWO);
|
||||
}
|
||||
|
||||
for (int i = length-1; i >= 0; i--) {
|
||||
// i should start at length-1 not -2 because the MSB of binarry may not be 1
|
||||
r = doublePoint(r, curve);
|
||||
if (binarray[i] == 1)
|
||||
r = addPoint(r, p, curve);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
private static ECPoint addPoint(ECPoint r, ECPoint s, EllipticCurve curve) {
|
||||
if (r.equals(s))
|
||||
return doublePoint(r, curve);
|
||||
else if (r.equals(ECPoint.POINT_INFINITY))
|
||||
return s;
|
||||
else if (s.equals(ECPoint.POINT_INFINITY))
|
||||
return r;
|
||||
BigInteger prime = ((ECFieldFp) curve.getField()).getP();
|
||||
BigInteger slope = (r.getAffineY().subtract(s.getAffineY())).multiply(r.getAffineX().subtract(s.getAffineX()).modInverse(prime)).mod(prime);
|
||||
slope = new NativeBigInteger(slope);
|
||||
BigInteger xOut = (slope.modPow(TWO, prime).subtract(r.getAffineX())).subtract(s.getAffineX()).mod(prime);
|
||||
BigInteger yOut = s.getAffineY().negate().mod(prime);
|
||||
yOut = yOut.add(slope.multiply(s.getAffineX().subtract(xOut))).mod(prime);
|
||||
ECPoint out = new ECPoint(xOut, yOut);
|
||||
return out;
|
||||
}
|
||||
|
||||
private static ECPoint doublePoint(ECPoint r, EllipticCurve curve) {
|
||||
if (r.equals(ECPoint.POINT_INFINITY))
|
||||
return r;
|
||||
BigInteger slope = (r.getAffineX().pow(2)).multiply(THREE);
|
||||
slope = slope.add(curve.getA());
|
||||
BigInteger prime = ((ECFieldFp) curve.getField()).getP();
|
||||
slope = slope.multiply((r.getAffineY().multiply(TWO)).modInverse(prime));
|
||||
BigInteger xOut = slope.pow(2).subtract(r.getAffineX().multiply(TWO)).mod(prime);
|
||||
BigInteger yOut = (r.getAffineY().negate()).add(slope.multiply(r.getAffineX().subtract(xOut))).mod(prime);
|
||||
ECPoint out = new ECPoint(xOut, yOut);
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* P-192 test only.
|
||||
* See KeyGenerator.main() for a test of all supported curves.
|
||||
*/
|
||||
/****
|
||||
public static void main(String[] args) {
|
||||
EllipticCurve P192 = ECConstants.P192_SPEC.getCurve();
|
||||
BigInteger xs = new BigInteger("d458e7d127ae671b0c330266d246769353a012073e97acf8", 16);
|
||||
BigInteger ys = new BigInteger("325930500d851f336bddc050cf7fb11b5673a1645086df3b", 16);
|
||||
BigInteger xt = new BigInteger("f22c4395213e9ebe67ddecdd87fdbd01be16fb059b9753a4", 16);
|
||||
BigInteger yt = new BigInteger("264424096af2b3597796db48f8dfb41fa9cecc97691a9c79", 16);
|
||||
ECPoint S = new ECPoint(xs,ys);
|
||||
ECPoint T = new ECPoint(xt,yt);
|
||||
|
||||
// Verifying addition
|
||||
ECPoint Rst = addPoint(S, T, P192);
|
||||
BigInteger xst = new BigInteger("48e1e4096b9b8e5ca9d0f1f077b8abf58e843894de4d0290", 16); // Specified value of x of point R for addition in NIST Routine example
|
||||
System.out.println("x-coordinate of point Rst is : " + Rst.getAffineX());
|
||||
System.out.println("y-coordinate of point Rst is : " + Rst.getAffineY());
|
||||
if (Rst.getAffineX().equals(xst))
|
||||
System.out.println("Adding is correct");
|
||||
else
|
||||
System.out.println("Adding FAIL");
|
||||
|
||||
//Verifying Doubling
|
||||
BigInteger xr = new BigInteger("30c5bc6b8c7da25354b373dc14dd8a0eba42d25a3f6e6962", 16); // Specified value of x of point R for doubling in NIST Routine example
|
||||
BigInteger yr = new BigInteger("0dde14bc4249a721c407aedbf011e2ddbbcb2968c9d889cf", 16);
|
||||
ECPoint R2s = new ECPoint(xr, yr); // Specified value of y of point R for doubling in NIST Routine example
|
||||
System.out.println("x-coordinate of point R2s is : " + R2s.getAffineX());
|
||||
System.out.println("y-coordinate of point R2s is : " + R2s.getAffineY());
|
||||
System.out.println("x-coordinate of calculated point is : " + doublePoint(S, P192).getAffineX());
|
||||
System.out.println("y-coordinate of calculated point is : " + doublePoint(S, P192).getAffineY());
|
||||
if (R2s.getAffineX().equals(doublePoint(S, P192).getAffineX()) &&
|
||||
R2s.getAffineY().equals(doublePoint(S, P192).getAffineY()))
|
||||
System.out.println("Doubling is correct");
|
||||
else
|
||||
System.out.println("Doubling FAIL");
|
||||
|
||||
xr = new BigInteger("1faee4205a4f669d2d0a8f25e3bcec9a62a6952965bf6d31", 16); // Specified value of x of point R for scalar Multiplication in NIST Routine example
|
||||
yr = new BigInteger("5ff2cdfa508a2581892367087c696f179e7a4d7e8260fb06", 16); // Specified value of y of point R for scalar Multiplication in NIST Routine example
|
||||
ECPoint Rds = new ECPoint(xr, yr);
|
||||
BigInteger d = new BigInteger("a78a236d60baec0c5dd41b33a542463a8255391af64c74ee", 16);
|
||||
|
||||
ECPoint Rs = scalarMult(S, d, P192);
|
||||
|
||||
System.out.println("x-coordinate of point Rds is : " + Rds.getAffineX());
|
||||
System.out.println("y-coordinate of point Rds is : " + Rds.getAffineY());
|
||||
System.out.println("x-coordinate of calculated point is : " + Rs.getAffineX());
|
||||
System.out.println("y-coordinate of calculated point is : " + Rs.getAffineY());
|
||||
|
||||
|
||||
if (Rds.getAffineX().equals(Rs.getAffineX()) &&
|
||||
Rds.getAffineY().equals(Rs.getAffineY()))
|
||||
System.out.println("Scalar Multiplication is correct");
|
||||
else
|
||||
System.out.println("Scalar Multiplication FAIL");
|
||||
}
|
||||
****/
|
||||
}
|
@ -12,11 +12,25 @@ package net.i2p.crypto;
|
||||
import java.math.BigInteger;
|
||||
import java.security.GeneralSecurityException;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.KeyFactory;
|
||||
import java.security.KeyPair;
|
||||
import java.security.KeyPairGenerator;
|
||||
import java.security.ProviderException;
|
||||
import java.security.interfaces.ECPrivateKey;
|
||||
import java.security.interfaces.ECPublicKey;
|
||||
import java.security.interfaces.RSAPrivateKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.security.spec.ECParameterSpec;
|
||||
import java.security.spec.ECPoint;
|
||||
import java.security.spec.ECPublicKeySpec;
|
||||
import java.security.spec.EllipticCurve;
|
||||
import java.security.spec.RSAKeyGenParameterSpec;
|
||||
import java.security.spec.RSAPublicKeySpec;
|
||||
|
||||
import net.i2p.I2PAppContext;
|
||||
import net.i2p.crypto.eddsa.EdDSAPrivateKey;
|
||||
import net.i2p.crypto.eddsa.EdDSAPublicKey;
|
||||
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
|
||||
import net.i2p.data.Hash;
|
||||
import net.i2p.data.PrivateKey;
|
||||
import net.i2p.data.PublicKey;
|
||||
@ -268,24 +282,56 @@ public class KeyGenerator {
|
||||
}
|
||||
|
||||
/** Convert a SigningPrivateKey to a SigningPublicKey.
|
||||
* DSA-SHA1 only.
|
||||
* As of 0.9.16, supports all key types.
|
||||
*
|
||||
* @param priv a SigningPrivateKey object
|
||||
* @return a SigningPublicKey object
|
||||
* @throws IllegalArgumentException on bad key
|
||||
* @throws IllegalArgumentException on bad key or unknown type
|
||||
*/
|
||||
public static SigningPublicKey getSigningPublicKey(SigningPrivateKey priv) {
|
||||
if (priv.getType() != SigType.DSA_SHA1)
|
||||
throw new IllegalArgumentException();
|
||||
BigInteger x = new NativeBigInteger(1, priv.toByteArray());
|
||||
BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
|
||||
SigningPublicKey pub = new SigningPublicKey();
|
||||
SigType type = priv.getType();
|
||||
if (type == null)
|
||||
throw new IllegalArgumentException("Unknown type");
|
||||
try {
|
||||
pub.setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
|
||||
} catch (InvalidKeyException ike) {
|
||||
throw new IllegalArgumentException(ike);
|
||||
switch (type.getBaseAlgorithm()) {
|
||||
case DSA:
|
||||
BigInteger x = new NativeBigInteger(1, priv.toByteArray());
|
||||
BigInteger y = CryptoConstants.dsag.modPow(x, CryptoConstants.dsap);
|
||||
SigningPublicKey pub = new SigningPublicKey();
|
||||
pub.setData(SigUtil.rectify(y, SigningPublicKey.KEYSIZE_BYTES));
|
||||
return pub;
|
||||
|
||||
case EC:
|
||||
ECPrivateKey ecpriv = SigUtil.toJavaECKey(priv);
|
||||
BigInteger s = ecpriv.getS();
|
||||
ECParameterSpec spec = (ECParameterSpec) type.getParams();
|
||||
EllipticCurve curve = spec.getCurve();
|
||||
ECPoint g = spec.getGenerator();
|
||||
ECPoint w = ECUtil.scalarMult(g, s, curve);
|
||||
ECPublicKeySpec ecks = new ECPublicKeySpec(w, ecpriv.getParams());
|
||||
KeyFactory eckf = KeyFactory.getInstance("EC");
|
||||
ECPublicKey ecpub = (ECPublicKey) eckf.generatePublic(ecks);
|
||||
return SigUtil.fromJavaKey(ecpub, type);
|
||||
|
||||
case RSA:
|
||||
RSAPrivateKey rsapriv = SigUtil.toJavaRSAKey(priv);
|
||||
BigInteger exp = ((RSAKeyGenParameterSpec)type.getParams()).getPublicExponent();
|
||||
RSAPublicKeySpec rsaks = new RSAPublicKeySpec(rsapriv.getModulus(), exp);
|
||||
KeyFactory rsakf = KeyFactory.getInstance("RSA");
|
||||
RSAPublicKey rsapub = (RSAPublicKey) rsakf.generatePublic(rsaks);
|
||||
return SigUtil.fromJavaKey(rsapub, type);
|
||||
|
||||
case EdDSA:
|
||||
EdDSAPrivateKey epriv = SigUtil.toJavaEdDSAKey(priv);
|
||||
EdDSAPublicKey epub = new EdDSAPublicKey(new EdDSAPublicKeySpec(epriv.getA(), epriv.getParams()));
|
||||
return SigUtil.fromJavaKey(epub, type);
|
||||
|
||||
default:
|
||||
throw new IllegalArgumentException("Unsupported algorithm");
|
||||
}
|
||||
} catch (GeneralSecurityException gse) {
|
||||
throw new IllegalArgumentException("Conversion failed", gse);
|
||||
}
|
||||
return pub;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
@ -322,14 +368,20 @@ public class KeyGenerator {
|
||||
long stime = 0;
|
||||
long vtime = 0;
|
||||
SimpleDataStructure keys[] = KeyGenerator.getInstance().generateSigningKeys(type);
|
||||
//System.out.println("pubkey " + keys[0]);
|
||||
SigningPublicKey pubkey = (SigningPublicKey) keys[0];
|
||||
SigningPrivateKey privkey = (SigningPrivateKey) keys[1];
|
||||
SigningPublicKey pubkey2 = getSigningPublicKey(privkey);
|
||||
if (pubkey.equals(pubkey2))
|
||||
System.out.println(type + " private-to-public test PASSED");
|
||||
else
|
||||
System.out.println(type + " private-to-public test FAILED");
|
||||
//System.out.println("privkey " + keys[1]);
|
||||
for (int i = 0; i < runs; i++) {
|
||||
RandomSource.getInstance().nextBytes(src);
|
||||
long start = System.nanoTime();
|
||||
Signature sig = DSAEngine.getInstance().sign(src, (SigningPrivateKey) keys[1]);
|
||||
Signature sig = DSAEngine.getInstance().sign(src, privkey);
|
||||
long mid = System.nanoTime();
|
||||
boolean ok = DSAEngine.getInstance().verifySignature(sig, src, (SigningPublicKey) keys[0]);
|
||||
boolean ok = DSAEngine.getInstance().verifySignature(sig, src, pubkey);
|
||||
long end = System.nanoTime();
|
||||
stime += mid - start;
|
||||
vtime += end - mid;
|
||||
|
@ -331,7 +331,7 @@ public class SigUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated unused
|
||||
*
|
||||
*/
|
||||
public static RSAPrivateKey toJavaRSAKey(SigningPrivateKey pk)
|
||||
throws GeneralSecurityException {
|
||||
@ -344,7 +344,7 @@ public class SigUtil {
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated unused
|
||||
*
|
||||
*/
|
||||
public static SigningPublicKey fromJavaKey(RSAPublicKey pk, SigType type)
|
||||
throws GeneralSecurityException {
|
||||
|
@ -75,8 +75,12 @@ public class SigningPrivateKey extends SimpleDataStructure {
|
||||
return _type;
|
||||
}
|
||||
|
||||
/** converts this signing private key to its public equivalent
|
||||
* @return a SigningPublicKey object derived from this private key
|
||||
/**
|
||||
* Converts this signing private key to its public equivalent.
|
||||
* As of 0.9.16, supports all key types.
|
||||
*
|
||||
* @return a SigningPublicKey object derived from this private key
|
||||
* @throws IllegalArgumentException on bad key or unknown or unsupported type
|
||||
*/
|
||||
public SigningPublicKey toPublic() {
|
||||
return KeyGenerator.getSigningPublicKey(this);
|
||||
|
Reference in New Issue
Block a user