Skip to content

Commit 3d3ca2d

Browse files
gefeilidghgit
authored andcommitted
Add support for different curves
1 parent 9cb941f commit 3d3ca2d

File tree

4 files changed

+223
-105
lines changed

4 files changed

+223
-105
lines changed

core/src/main/java/org/bouncycastle/crypto/generators/ECCSIKeyPairGenerator.java

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,13 @@
33
import java.math.BigInteger;
44
import java.security.SecureRandom;
55

6-
import org.bouncycastle.asn1.x9.X9ECParameters;
76
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
87
import org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
98
import org.bouncycastle.crypto.CryptoServicePurpose;
109
import org.bouncycastle.crypto.CryptoServicesRegistrar;
1110
import org.bouncycastle.crypto.Digest;
1211
import org.bouncycastle.crypto.KeyGenerationParameters;
1312
import org.bouncycastle.crypto.constraints.DefaultServiceProperties;
14-
import org.bouncycastle.crypto.digests.SHA256Digest;
15-
import org.bouncycastle.crypto.ec.CustomNamedCurves;
1613
import org.bouncycastle.crypto.params.ECCSIKeyGenerationParameters;
1714
import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
1815
import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
@@ -21,28 +18,27 @@
2118
public class ECCSIKeyPairGenerator
2219
implements AsymmetricCipherKeyPairGenerator
2320
{
24-
// Initialize NIST P-256 curve
25-
private static final X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
26-
private static final BigInteger q = params.getCurve().getOrder();
27-
28-
// And the base point (generator) is:
29-
private static final ECPoint G = params.getG();
30-
//int N = 32; // 256 bits
31-
21+
private BigInteger q;
22+
private ECPoint G;
23+
private Digest digest;
3224
private ECCSIKeyGenerationParameters parameters;
3325

3426
@Override
3527
public void init(KeyGenerationParameters parameters)
3628
{
3729
this.parameters = (ECCSIKeyGenerationParameters)parameters;
30+
this.q = this.parameters.getQ();
31+
this.G = this.parameters.getG();
32+
this.digest = this.parameters.getDigest();
3833

39-
CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties("ECCSI", 256, null, CryptoServicePurpose.KEYGEN));
34+
CryptoServicesRegistrar.checkConstraints(new DefaultServiceProperties("ECCSI", this.parameters.getN(), null, CryptoServicePurpose.KEYGEN));
4035
}
4136

4237
@Override
4338
public AsymmetricCipherKeyPair generateKeyPair()
4439
{
4540
SecureRandom random = parameters.getRandom();
41+
this.digest.reset();
4642
byte[] id = parameters.getId();
4743
ECPoint kpak = parameters.getKPAK();
4844
// 1) Choose v, a random (ephemeral) non-zero element of F_q;
@@ -51,7 +47,6 @@ public AsymmetricCipherKeyPair generateKeyPair()
5147
ECPoint pvt = G.multiply(v).normalize();
5248

5349
// 3) Compute a hash value HS = hash( G || KPAK || ID || PVT ), an N-octet integer;
54-
Digest digest = new SHA256Digest();
5550
byte[] tmp = G.getEncoded(false);
5651
digest.update(tmp, 0, tmp.length);
5752
tmp = kpak.getEncoded(false);

core/src/main/java/org/bouncycastle/crypto/params/ECCSIKeyGenerationParameters.java

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,39 +4,37 @@
44
import java.security.SecureRandom;
55

66
import org.bouncycastle.asn1.x9.X9ECParameters;
7+
import org.bouncycastle.crypto.Digest;
78
import org.bouncycastle.crypto.KeyGenerationParameters;
8-
import org.bouncycastle.crypto.ec.CustomNamedCurves;
99
import org.bouncycastle.math.ec.ECPoint;
1010
import org.bouncycastle.util.Arrays;
1111

1212
public class ECCSIKeyGenerationParameters
1313
extends KeyGenerationParameters
1414
{
15-
private static final BigInteger q;
16-
private static final ECPoint G;
17-
18-
static
19-
{
20-
X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
21-
q = params.getCurve().getOrder();
22-
G = params.getG();
23-
}
24-
15+
private final BigInteger q;
16+
private final ECPoint G;
17+
private final Digest digest;
2518
private final byte[] id;
2619
private final BigInteger ksak;
2720
private final ECPoint kpak;
21+
private final int n;
2822

2923
/**
3024
* initialise the generator with a source of randomness
3125
* and a strength (in bits).
3226
*
3327
* @param random the random byte source.
3428
*/
35-
public ECCSIKeyGenerationParameters(SecureRandom random, byte[] id)
29+
public ECCSIKeyGenerationParameters(SecureRandom random, X9ECParameters params, Digest digest, byte[] id)
3630
{
37-
super(random, 256);
31+
super(random, params.getCurve().getA().bitLength());
32+
this.q = params.getCurve().getOrder();
33+
this.G = params.getG();
34+
this.digest = digest;
3835
this.id = Arrays.clone(id);
39-
this.ksak = new BigInteger(256, random).mod(q);
36+
this.n = params.getCurve().getA().bitLength();
37+
this.ksak = new BigInteger(n, random).mod(q);
4038
this.kpak = G.multiply(ksak).normalize();
4139
}
4240

@@ -54,4 +52,24 @@ public BigInteger computeSSK(BigInteger hs_v)
5452
{
5553
return ksak.add(hs_v).mod(q);
5654
}
55+
56+
public BigInteger getQ()
57+
{
58+
return q;
59+
}
60+
61+
public ECPoint getG()
62+
{
63+
return G;
64+
}
65+
66+
public Digest getDigest()
67+
{
68+
return digest;
69+
}
70+
71+
public int getN()
72+
{
73+
return n;
74+
}
5775
}

core/src/main/java/org/bouncycastle/crypto/signers/ECCSISigner.java

Lines changed: 86 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -10,29 +10,34 @@
1010
import org.bouncycastle.crypto.DataLengthException;
1111
import org.bouncycastle.crypto.Digest;
1212
import org.bouncycastle.crypto.Signer;
13-
import org.bouncycastle.crypto.digests.SHA256Digest;
14-
import org.bouncycastle.crypto.ec.CustomNamedCurves;
1513
import org.bouncycastle.crypto.params.ECCSIPrivateKeyParameters;
1614
import org.bouncycastle.crypto.params.ECCSIPublicKeyParameters;
1715
import org.bouncycastle.crypto.params.ParametersWithRandom;
1816
import org.bouncycastle.math.ec.ECPoint;
1917
import org.bouncycastle.util.Arrays;
2018
import org.bouncycastle.util.BigIntegers;
2119

20+
/**
21+
* Implementation of Elliptic Curve-based Certificateless Signatures for Identity-Based Encryption (ECCSI)
22+
* as defined in RFC 6507.
23+
* <p>
24+
* This class handles both signature generation and verification using the ECCSI scheme. It supports:
25+
* <ul>
26+
* <li>NIST P-256 (secp256r1) elliptic curve parameters</li>
27+
* <li>SHA-256 hash function</li>
28+
* <li>Certificateless signatures using KMS Public Authentication Key (KPAK)</li>
29+
* <li>Identity-based signatures with Secret Signing Key (SSK)</li>
30+
* </ul>
31+
*
32+
* @see <a href="https://datatracker.ietf.org/doc/html/rfc6507">RFC 6507: Elliptic Curve-Based Certificateless
33+
* Signatures for Identity-Based Encryption (ECCSI)</a>
34+
*/
2235
public class ECCSISigner
2336
implements Signer
2437
{
25-
private static final BigInteger q;
26-
private static final ECPoint G;
27-
28-
static
29-
{
30-
X9ECParameters params = CustomNamedCurves.getByName("secP256r1");
31-
q = params.getCurve().getOrder();
32-
G = params.getG();
33-
}
34-
35-
private final Digest digest = new SHA256Digest();
38+
private final BigInteger q;
39+
private final ECPoint G;
40+
private final Digest digest;
3641
private BigInteger j;
3742
private BigInteger r;
3843
private ECPoint Y;
@@ -41,72 +46,26 @@ public class ECCSISigner
4146
private CipherParameters param;
4247
private ByteArrayOutputStream stream;
4348
private boolean forSigning;
49+
private final int N;
4450

45-
public ECCSISigner(ECPoint kpak, byte[] id)
51+
52+
public ECCSISigner(ECPoint kpak, X9ECParameters params, Digest digest, byte[] id)
4653
{
4754
this.kpak = kpak;
4855
this.id = id;
56+
this.q = params.getCurve().getOrder();
57+
this.G = params.getG();
58+
this.digest = digest;
59+
this.digest.reset();
60+
this.N = (params.getCurve().getOrder().bitLength() + 7) >> 3;
4961
}
5062

5163
@Override
5264
public void init(boolean forSigning, CipherParameters param)
5365
{
5466
this.forSigning = forSigning;
5567
this.param = param;
56-
SecureRandom random = null;
57-
if (param instanceof ParametersWithRandom)
58-
{
59-
random = ((ParametersWithRandom)param).getRandom();
60-
param = ((ParametersWithRandom)param).getParameters();
61-
}
62-
ECPoint kpak_computed = null;
63-
ECPoint pvt;
64-
if (forSigning)
65-
{
66-
ECCSIPrivateKeyParameters parameters = (ECCSIPrivateKeyParameters)param;
67-
68-
j = new BigInteger(256, random).mod(q);
69-
ECPoint J = G.multiply(j).normalize();
70-
r = J.getAffineXCoord().toBigInteger();
71-
pvt = parameters.getPublicKeyParameters().getPVT();
72-
kpak_computed = G.multiply(parameters.getSSK());
73-
}
74-
else
75-
{
76-
ECCSIPublicKeyParameters parameters = (ECCSIPublicKeyParameters)param;
77-
pvt = parameters.getPVT();
78-
stream = new ByteArrayOutputStream();
79-
}
80-
81-
// compute HS
82-
byte[] tmp = G.getEncoded(false);
83-
digest.update(tmp, 0, tmp.length);
84-
tmp = kpak.getEncoded(false);
85-
digest.update(tmp, 0, tmp.length);
86-
digest.update(id, 0, id.length);
87-
tmp = pvt.getEncoded(false);
88-
digest.update(tmp, 0, tmp.length);
89-
tmp = new byte[digest.getDigestSize()];
90-
digest.doFinal(tmp, 0);
91-
BigInteger HS = new BigInteger(1, tmp).mod(q);
92-
93-
//HE = hash( HS || r || M );
94-
digest.update(tmp, 0, tmp.length);
95-
if (forSigning)
96-
{
97-
kpak_computed = kpak_computed.subtract(pvt.multiply(HS)).normalize();
98-
if (!kpak_computed.equals(kpak))
99-
{
100-
throw new IllegalArgumentException("Invalid KPAK");
101-
}
102-
byte[] rBytes = BigIntegers.asUnsignedByteArray(32, r);
103-
digest.update(rBytes, 0, rBytes.length);
104-
}
105-
else
106-
{
107-
// Compute Y = HS*PVT + KPAK
108-
Y = pvt.multiply(HS).add(kpak).normalize();
109-
}
68+
reset();
11069
}
11170

11271
@Override
@@ -153,17 +112,17 @@ public byte[] generateSignature()
153112

154113
BigInteger sPrime = denominator.modInverse(q).multiply(j).mod(q);
155114

156-
return Arrays.concatenate(BigIntegers.asUnsignedByteArray(32, r), BigIntegers.asUnsignedByteArray(32, sPrime),
115+
return Arrays.concatenate(BigIntegers.asUnsignedByteArray(this.N, r), BigIntegers.asUnsignedByteArray(this.N, sPrime),
157116
params.getPublicKeyParameters().getPVT().getEncoded(false));
158117
}
159118

160119
@Override
161120
public boolean verifySignature(byte[] signature)
162121
{
163-
byte[] bytes = Arrays.copyOf(signature, 32);
164-
BigInteger s = new BigInteger(1, Arrays.copyOfRange(signature, 32, 64));
122+
byte[] bytes = Arrays.copyOf(signature, this.N);
123+
BigInteger s = new BigInteger(1, Arrays.copyOfRange(signature, this.N, this.N << 1));
165124
r = new BigInteger(1, bytes).mod(q);
166-
digest.update(bytes, 0, 32);
125+
digest.update(bytes, 0, this.N);
167126
bytes = stream.toByteArray();
168127
digest.update(bytes, 0, bytes.length);
169128
bytes = new byte[digest.getDigestSize()];
@@ -185,6 +144,61 @@ public boolean verifySignature(byte[] signature)
185144
@Override
186145
public void reset()
187146
{
147+
digest.reset();
148+
CipherParameters param = this.param;
149+
SecureRandom random = null;
150+
if (param instanceof ParametersWithRandom)
151+
{
152+
random = ((ParametersWithRandom)param).getRandom();
153+
param = ((ParametersWithRandom)param).getParameters();
154+
}
155+
ECPoint kpak_computed = null;
156+
ECPoint pvt;
157+
if (forSigning)
158+
{
159+
ECCSIPrivateKeyParameters parameters = (ECCSIPrivateKeyParameters)param;
160+
pvt = parameters.getPublicKeyParameters().getPVT();
161+
j = new BigInteger(q.bitLength(), random);
162+
ECPoint J = G.multiply(j).normalize();
163+
r = J.getAffineXCoord().toBigInteger().mod(q);
188164

165+
kpak_computed = G.multiply(parameters.getSSK());
166+
}
167+
else
168+
{
169+
ECCSIPublicKeyParameters parameters = (ECCSIPublicKeyParameters)param;
170+
pvt = parameters.getPVT();
171+
stream = new ByteArrayOutputStream();
172+
}
173+
174+
// compute HS
175+
byte[] tmp = G.getEncoded(false);
176+
digest.update(tmp, 0, tmp.length);
177+
tmp = kpak.getEncoded(false);
178+
digest.update(tmp, 0, tmp.length);
179+
digest.update(id, 0, id.length);
180+
tmp = pvt.getEncoded(false);
181+
digest.update(tmp, 0, tmp.length);
182+
tmp = new byte[digest.getDigestSize()];
183+
digest.doFinal(tmp, 0);
184+
BigInteger HS = new BigInteger(1, tmp).mod(q);
185+
186+
//HE = hash( HS || r || M );
187+
digest.update(tmp, 0, tmp.length);
188+
if (forSigning)
189+
{
190+
kpak_computed = kpak_computed.subtract(pvt.multiply(HS)).normalize();
191+
if (!kpak_computed.equals(kpak))
192+
{
193+
throw new IllegalArgumentException("Invalid KPAK");
194+
}
195+
byte[] rBytes = BigIntegers.asUnsignedByteArray(this.N, r);
196+
digest.update(rBytes, 0, rBytes.length);
197+
}
198+
else
199+
{
200+
// Compute Y = HS*PVT + KPAK
201+
Y = pvt.multiply(HS).add(kpak).normalize();
202+
}
189203
}
190204
}

0 commit comments

Comments
 (0)