diff options
Diffstat (limited to 'src/cz/crcs/ectester/common/util/ECUtil.java')
| -rw-r--r-- | src/cz/crcs/ectester/common/util/ECUtil.java | 187 |
1 files changed, 179 insertions, 8 deletions
diff --git a/src/cz/crcs/ectester/common/util/ECUtil.java b/src/cz/crcs/ectester/common/util/ECUtil.java index 511f93f..d5e8006 100644 --- a/src/cz/crcs/ectester/common/util/ECUtil.java +++ b/src/cz/crcs/ectester/common/util/ECUtil.java @@ -9,20 +9,26 @@ import org.bouncycastle.asn1.DERSequence; import org.bouncycastle.asn1.DERSequenceParser; import org.bouncycastle.crypto.digests.SHA1Digest; +import java.io.FileInputStream; import java.io.IOException; import java.math.BigInteger; import java.nio.charset.StandardCharsets; import java.security.KeyPair; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.security.interfaces.ECKey; import java.security.interfaces.ECPrivateKey; import java.security.interfaces.ECPublicKey; import java.security.spec.*; +import java.util.LinkedList; +import java.util.List; +import java.util.Random; /** * @author Jan Jancar johny@neuromancer.sk */ public class ECUtil { + private static Random rand = new Random(); public static byte[] toByteArray(BigInteger what, int bits) { byte[] raw = what.toByteArray(); @@ -95,7 +101,7 @@ public class ECUtil { private static boolean isResidue(BigInteger a, BigInteger p) { BigInteger exponent = p.subtract(BigInteger.ONE).divide(BigInteger.valueOf(2)); BigInteger result = a.modPow(exponent, p); - return result.intValueExact() == 1; + return result.equals(BigInteger.ONE); } private static BigInteger modSqrt(BigInteger a, BigInteger p) { @@ -192,7 +198,7 @@ public class ECUtil { } } - public static byte[] semiRandomKey(EC_Curve curve) { + private static byte[] hashCurve(EC_Curve curve) { int bytes = (curve.getBits() + 7) / 8; byte[] result = new byte[bytes]; SHA1Digest digest = new SHA1Digest(); @@ -207,19 +213,102 @@ public class ECUtil { written += toWrite; digest.update(dig, 0, dig.length); } + return result; + } + + public static EC_Params fullRandomKey(EC_Curve curve) { + int bytes = (curve.getBits() + 7) / 8; + byte[] result = new byte[bytes]; + rand.nextBytes(result); BigInteger priv = new BigInteger(1, result); BigInteger order = new BigInteger(1, curve.getParam(EC_Consts.PARAMETER_R)[0]); priv = priv.mod(order); - return toByteArray(priv, curve.getBits()); + return new EC_Params(EC_Consts.PARAMETER_S, new byte[][]{toByteArray(priv, curve.getBits())}); + } + + public static EC_Params fixedRandomKey(EC_Curve curve) { + byte[] hash = hashCurve(curve); + BigInteger priv = new BigInteger(1, hash); + BigInteger order = new BigInteger(1, curve.getParam(EC_Consts.PARAMETER_R)[0]); + priv = priv.mod(order); + return new EC_Params(EC_Consts.PARAMETER_S, new byte[][]{toByteArray(priv, curve.getBits())}); + } + + private static BigInteger computeRHS(BigInteger x, BigInteger a, BigInteger b, BigInteger p) { + BigInteger rhs = x.modPow(BigInteger.valueOf(3), p); + rhs = rhs.add(a.multiply(x)).mod(p); + rhs = rhs.add(b).mod(p); + return rhs; + } + + public static EC_Params fullRandomPoint(EC_Curve curve) { + EllipticCurve ecCurve = curve.toCurve(); + + BigInteger p; + if (ecCurve.getField() instanceof ECFieldFp) { + ECFieldFp fp = (ECFieldFp) ecCurve.getField(); + p = fp.getP(); + if (!p.isProbablePrime(20)) { + return null; + } + } else { + //TODO + return null; + } + BigInteger x; + BigInteger rhs; + do { + x = new BigInteger(ecCurve.getField().getFieldSize(), rand).mod(p); + rhs = computeRHS(x, ecCurve.getA(), ecCurve.getB(), p); + } while (!isResidue(rhs, p)); + BigInteger y = modSqrt(rhs, p); + if (rand.nextBoolean()) { + y = p.subtract(y); + } + + byte[] xArr = toByteArray(x, ecCurve.getField().getFieldSize()); + byte[] yArr = toByteArray(y, ecCurve.getField().getFieldSize()); + return new EC_Params(EC_Consts.PARAMETER_W, new byte[][]{xArr, yArr}); + } + + public static EC_Params fixedRandomPoint(EC_Curve curve) { + EllipticCurve ecCurve = curve.toCurve(); + + BigInteger p; + if (ecCurve.getField() instanceof ECFieldFp) { + ECFieldFp fp = (ECFieldFp) ecCurve.getField(); + p = fp.getP(); + if (!p.isProbablePrime(20)) { + return null; + } + } else { + //TODO + return null; + } + + BigInteger x = new BigInteger(1, hashCurve(curve)).mod(p); + BigInteger rhs = computeRHS(x, ecCurve.getA(), ecCurve.getB(), p); + while (!isResidue(rhs, p)) { + x = x.add(BigInteger.ONE).mod(p); + rhs = computeRHS(x, ecCurve.getA(), ecCurve.getB(), p); + } + BigInteger y = modSqrt(rhs, p); + if (y.bitCount() % 2 == 0) { + y = p.subtract(y); + } + + byte[] xArr = toByteArray(x, ecCurve.getField().getFieldSize()); + byte[] yArr = toByteArray(y, ecCurve.getField().getFieldSize()); + return new EC_Params(EC_Consts.PARAMETER_W, new byte[][]{xArr, yArr}); } - private static ECPoint toPoint(EC_Params params) { + public static ECPoint toPoint(EC_Params params) { return new ECPoint( new BigInteger(1, params.getParam(EC_Consts.PARAMETER_W)[0]), new BigInteger(1, params.getParam(EC_Consts.PARAMETER_W)[1])); } - private static BigInteger toScalar(EC_Params params) { + public static BigInteger toScalar(EC_Params params) { return new BigInteger(1, params.getParam(EC_Consts.PARAMETER_S)[0]); } @@ -273,11 +362,22 @@ public class ECUtil { public static BigInteger recoverSignatureNonce(byte[] signature, byte[] data, BigInteger privkey, ECParameterSpec params, String hashType) { try { int bitSize = params.getOrder().bitLength(); - MessageDigest md = MessageDigest.getInstance(hashType); - byte[] hash = md.digest(data); + // Hash the data. + byte[] hash; + if (hashType.equals("NONE")) { + hash = data; + } else { + MessageDigest md = MessageDigest.getInstance(hashType); + hash = md.digest(data); + } + // Trim bitSize of rightmost bits. BigInteger hashInt = new BigInteger(1, hash); - hashInt = hashInt.and(BigInteger.ONE.shiftLeft(bitSize + 1).subtract(BigInteger.ONE)); + int hashBits = hashInt.bitLength(); + if (hashBits > bitSize) { + hashInt = hashInt.shiftRight(hashBits - bitSize); + } + // Parse DERSignature BigInteger[] sigPair = fromDERSignature(signature); BigInteger r = sigPair[0]; BigInteger s = sigPair[1]; @@ -290,4 +390,75 @@ public class ECUtil { return null; } } + + public static EC_Params joinParams(EC_Params... params) { + List<EC_Params> paramList = new LinkedList<>(); + short paramMask = 0; + int len = 0; + for (EC_Params param : params) { + if (param == null) { + continue; + } + int i = 0; + for (; i + 1 < paramList.size(); ++i) { + if (paramList.get(i + 1).getParams() == param.getParams()) { + throw new IllegalArgumentException(); + } + if (paramList.get(i + 1).getParams() < param.getParams()) { + break; + } + } + paramList.add(i, param); + paramMask |= param.getParams(); + len += param.numParams(); + } + + byte[][] res = new byte[len][]; + int i = 0; + for (EC_Params param : params) { + for (byte[] data : param.getData()) { + res[i++] = data.clone(); + } + } + return new EC_Params(paramMask, res); + } + + public static EC_Params loadParams(short params, String named, String file) throws IOException { + EC_Params result = null; + if (file != null) { + result = new EC_Params(params); + + FileInputStream in = new FileInputStream(file); + result.readCSV(in); + in.close(); + } else if (named != null) { + if (params == EC_Consts.PARAMETER_W) { + result = EC_Store.getInstance().getObject(EC_Key.Public.class, named); + } else if (params == EC_Consts.PARAMETER_S) { + result = EC_Store.getInstance().getObject(EC_Key.Private.class, named); + } + + if (result == null) { + result = EC_Store.getInstance().getObject(EC_Keypair.class, named); + } + } + return result; + } + + public static ECKey loadKey(short params, String named, String file, ECParameterSpec spec) throws IOException { + if (params == EC_Consts.PARAMETERS_KEYPAIR) { + throw new IllegalArgumentException(); + } + EC_Params param = loadParams(params, named, file); + if (param != null) { + if (params == EC_Consts.PARAMETER_W) { + return new RawECPublicKey(toPoint(param), spec); + } else if (params == EC_Consts.PARAMETER_S) { + return new RawECPrivateKey(toScalar(param), spec); + } + } + return null; + } + + } |
