aboutsummaryrefslogtreecommitdiff
path: root/src/cz/crcs/ectester/common/util/ECUtil.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/cz/crcs/ectester/common/util/ECUtil.java')
-rw-r--r--src/cz/crcs/ectester/common/util/ECUtil.java187
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;
+ }
+
+
}