-
Notifications
You must be signed in to change notification settings - Fork 21
/
ecdsa_p256_sha256_java.java
130 lines (107 loc) · 4.85 KB
/
ecdsa_p256_sha256_java.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Please, note that you will need to add a folder called libs here and put
// the bouncycastle file bcprov-jdk15on-155.jar in it.
// Otherwise the wrapper and the makefile won't work.
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.KeyFactory;
import java.security.SecureRandom;
import java.security.Security;
import java.math.BigInteger;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import java.security.MessageDigest;
import java.security.Signature;
import java.security.SignatureException;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.ECGenParameterSpec;
import java.security.spec.ECParameterSpec;
import java.security.spec.ECPoint;
import java.security.spec.ECPublicKeySpec;
import java.security.spec.ECPrivateKeySpec;
import org.bouncycastle.jce.ECNamedCurveTable;
import java.util.Arrays;
import javax.xml.bind.DatatypeConverter;
import org.bouncycastle.jce.spec.ECNamedCurveParameterSpec;
import org.bouncycastle.jce.spec.ECNamedCurveSpec;
public class ecdsa_p256_sha256_java {
public static byte[] toByteArray(String s) {
return DatatypeConverter.parseHexBinary(s);
}
// using Wycheproof code, since if it exists, don't reinvent it.
public static BigInteger extractR(byte[] signature) throws Exception {
int startR = (signature[1] & 0x80) != 0 ? 3 : 2;
int lengthR = signature[startR + 1];
return new BigInteger(Arrays.copyOfRange(signature, startR + 2, startR + 2 + lengthR));
}
// using Wycheproof code, since if it exists, don't reinvent it.
public static BigInteger extractS(byte[] signature) throws Exception {
int startR = (signature[1] & 0x80) != 0 ? 3 : 2;
int lengthR = signature[startR + 1];
int startS = startR + 2 + lengthR;
int lengthS = signature[startS + 1];
return new BigInteger(Arrays.copyOfRange(signature, startS + 2, startS + 2 + lengthS));
}
public static void main(String[] args) throws Exception {
Security.addProvider(new BouncyCastleProvider());
SecureRandom random = new SecureRandom();
if (args.length != 5 && args.length != 4) {
System.out.println(args.length);
throw new Exception("Wrong args length");
}
byte[] input = toByteArray(args[args.length-1]);
KeyFactory kf = KeyFactory.getInstance("ECDSA","BC");
Signature signer = Signature.getInstance("SHA256withECDSA","BC");
String name = "secp256r1";
// inspired from https://stackoverflow.com/questions/33218674/how-to-make-a-bouncy-castle-ecpublickey
ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(name);
ECParameterSpec params = new ECNamedCurveSpec(name, parameterSpec.getCurve(),parameterSpec.getG(), parameterSpec.getN(), parameterSpec.getH(), parameterSpec.getSeed());
if (args.length == 4) {
ECPrivateKey priKey = (ECPrivateKey) kf.generatePrivate(
new ECPrivateKeySpec(
new BigInteger(args[2],16),
params)
);
signer.initSign(priKey);
// generate a signature
signer.update(input);
byte[] signature = signer.sign();
String r = String.format("%064x", (extractR(signature)));
String s = String.format("%064x", (extractS(signature)));
System.out.println(r);
System.out.println(s);
} else {
BigInteger r = new BigInteger(args[2], 16);
BigInteger s = new BigInteger(args[3], 16);
ECPoint point = new ECPoint(
new BigInteger(args[0], 16),
new BigInteger(args[1], 16)
);
ECPublicKey pubKey = (ECPublicKey) kf.generatePublic(new ECPublicKeySpec(point, params));
// verify a signature
signer.initVerify(pubKey);
signer.update(input);
// using Wycheproof code, since if it exists, don't reinvent it.
byte[] rb = r.toByteArray();
byte[] sb = s.toByteArray();
int off = (2 + 2) + rb.length;
int tot = off + (2 - 2) + sb.length;
byte[] der = new byte[tot + 2];
der[0] = 0x30;
der[1] = (byte) (tot & 0xff);
der[2 + 0] = 0x02;
der[2 + 1] = (byte) (rb.length & 0xff);
System.arraycopy(rb, 0, der, 2 + 2, rb.length);
der[off + 0] = 0x02;
der[off + 1] = (byte) (sb.length & 0xff);
System.arraycopy(sb, 0, der, off + 2, sb.length);
if (signer.verify(der))
{
System.out.println("true");
}
else
{
System.out.println("false");
}
}
}
}