Skip to content

Commit e6e1b65

Browse files
committed
EdDSA improvements
- better guards on context values - add verify method to public keys
1 parent dfa28d3 commit e6e1b65

File tree

13 files changed

+196
-20
lines changed

13 files changed

+196
-20
lines changed

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,11 +102,28 @@ public void sign(int algorithm, byte[] ctx, byte[] msg, int msgOff, int msgLen,
102102
}
103103
case Ed25519.Algorithm.Ed25519ctx:
104104
{
105+
if (null == ctx)
106+
{
107+
throw new NullPointerException("'ctx' cannot be null");
108+
}
109+
if (ctx.length > 255)
110+
{
111+
throw new IllegalArgumentException("ctx");
112+
}
113+
105114
Ed25519.sign(data, 0, pk, 0, ctx, msg, msgOff, msgLen, sig, sigOff);
106115
break;
107116
}
108117
case Ed25519.Algorithm.Ed25519ph:
109118
{
119+
if (null == ctx)
120+
{
121+
throw new NullPointerException("'ctx' cannot be null");
122+
}
123+
if (ctx.length > 255)
124+
{
125+
throw new IllegalArgumentException("ctx");
126+
}
110127
if (Ed25519.PREHASH_SIZE != msgLen)
111128
{
112129
throw new IllegalArgumentException("msgLen");

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

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,56 @@ public byte[] getEncoded()
4747
return Arrays.clone(data);
4848
}
4949

50+
public boolean verify(int algorithm, byte[] ctx, byte[] msg, int msgOff, int msgLen, byte[] sig, int sigOff)
51+
{
52+
switch (algorithm)
53+
{
54+
case Ed25519.Algorithm.Ed25519:
55+
{
56+
if (null != ctx)
57+
{
58+
throw new IllegalArgumentException("ctx");
59+
}
60+
61+
return Ed25519.verify(sig, sigOff, data, 0, msg, msgOff, msgLen);
62+
}
63+
case Ed25519.Algorithm.Ed25519ctx:
64+
{
65+
if (null == ctx)
66+
{
67+
throw new NullPointerException("'ctx' cannot be null");
68+
}
69+
if (ctx.length > 255)
70+
{
71+
throw new IllegalArgumentException("ctx");
72+
}
73+
74+
return Ed25519.verify(sig, sigOff, data, 0, ctx, msg, msgOff, msgLen);
75+
}
76+
case Ed25519.Algorithm.Ed25519ph:
77+
{
78+
if (null == ctx)
79+
{
80+
throw new NullPointerException("'ctx' cannot be null");
81+
}
82+
if (ctx.length > 255)
83+
{
84+
throw new IllegalArgumentException("ctx");
85+
}
86+
if (Ed25519.PREHASH_SIZE != msgLen)
87+
{
88+
throw new IllegalArgumentException("msgLen");
89+
}
90+
91+
return Ed25519.verifyPrehash(sig, sigOff, data, 0, ctx, msg, msgOff);
92+
}
93+
default:
94+
{
95+
throw new IllegalArgumentException("algorithm");
96+
}
97+
}
98+
}
99+
50100
private static byte[] validate(byte[] buf)
51101
{
52102
if (buf.length != KEY_SIZE)

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

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,11 +92,28 @@ public void sign(int algorithm, byte[] ctx, byte[] msg, int msgOff, int msgLen,
9292
{
9393
case Ed448.Algorithm.Ed448:
9494
{
95+
if (null == ctx)
96+
{
97+
throw new NullPointerException("'ctx' cannot be null");
98+
}
99+
if (ctx.length > 255)
100+
{
101+
throw new IllegalArgumentException("ctx");
102+
}
103+
95104
Ed448.sign(data, 0, pk, 0, ctx, msg, msgOff, msgLen, sig, sigOff);
96105
break;
97106
}
98107
case Ed448.Algorithm.Ed448ph:
99108
{
109+
if (null == ctx)
110+
{
111+
throw new NullPointerException("'ctx' cannot be null");
112+
}
113+
if (ctx.length > 255)
114+
{
115+
throw new IllegalArgumentException("ctx");
116+
}
100117
if (Ed448.PREHASH_SIZE != msgLen)
101118
{
102119
throw new IllegalArgumentException("msgLen");

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,47 @@ public byte[] getEncoded()
4747
return Arrays.clone(data);
4848
}
4949

50+
public boolean verify(int algorithm, byte[] ctx, byte[] msg, int msgOff, int msgLen, byte[] sig, int sigOff)
51+
{
52+
switch (algorithm)
53+
{
54+
case Ed448.Algorithm.Ed448:
55+
{
56+
if (null == ctx)
57+
{
58+
throw new NullPointerException("'ctx' cannot be null");
59+
}
60+
if (ctx.length > 255)
61+
{
62+
throw new IllegalArgumentException("ctx");
63+
}
64+
65+
return Ed448.verify(sig, sigOff, data, 0, ctx, msg, msgOff, msgLen);
66+
}
67+
case Ed448.Algorithm.Ed448ph:
68+
{
69+
if (null == ctx)
70+
{
71+
throw new NullPointerException("'ctx' cannot be null");
72+
}
73+
if (ctx.length > 255)
74+
{
75+
throw new IllegalArgumentException("ctx");
76+
}
77+
if (Ed448.PREHASH_SIZE != msgLen)
78+
{
79+
throw new IllegalArgumentException("msgLen");
80+
}
81+
82+
return Ed448.verifyPrehash(sig, sigOff, data, 0, ctx, msg, msgOff);
83+
}
84+
default:
85+
{
86+
throw new IllegalArgumentException("algorithm");
87+
}
88+
}
89+
}
90+
5091
private static byte[] validate(byte[] buf)
5192
{
5293
if (buf.length != KEY_SIZE)

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ public void reset()
7878
buffer.reset();
7979
}
8080

81-
private static class Buffer extends ByteArrayOutputStream
81+
private static final class Buffer extends ByteArrayOutputStream
8282
{
8383
synchronized byte[] generateSignature(Ed25519PrivateKeyParameters privateKey)
8484
{
@@ -96,8 +96,7 @@ synchronized boolean verifySignature(Ed25519PublicKeyParameters publicKey, byte[
9696
return false;
9797
}
9898

99-
byte[] pk = publicKey.getEncoded();
100-
boolean result = Ed25519.verify(signature, 0, pk, 0, buf, 0, count);
99+
boolean result = publicKey.verify(Ed25519.Algorithm.Ed25519, null, buf, 0, count, signature, 0);
101100
reset();
102101
return result;
103102
}

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

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,11 @@ public class Ed25519ctxSigner
2222

2323
public Ed25519ctxSigner(byte[] context)
2424
{
25+
if (null == context)
26+
{
27+
throw new NullPointerException("'context' cannot be null");
28+
}
29+
2530
this.context = Arrays.clone(context);
2631
}
2732

@@ -80,7 +85,7 @@ public void reset()
8085
buffer.reset();
8186
}
8287

83-
private static class Buffer extends ByteArrayOutputStream
88+
private static final class Buffer extends ByteArrayOutputStream
8489
{
8590
synchronized byte[] generateSignature(Ed25519PrivateKeyParameters privateKey, byte[] ctx)
8691
{
@@ -98,8 +103,7 @@ synchronized boolean verifySignature(Ed25519PublicKeyParameters publicKey, byte[
98103
return false;
99104
}
100105

101-
byte[] pk = publicKey.getEncoded();
102-
boolean result = Ed25519.verify(signature, 0, pk, 0, ctx, buf, 0, count);
106+
boolean result = publicKey.verify(Ed25519.Algorithm.Ed25519ctx, ctx, buf, 0, count, signature, 0);
103107
reset();
104108
return result;
105109
}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ public class Ed25519phSigner
2121

2222
public Ed25519phSigner(byte[] context)
2323
{
24+
if (null == context)
25+
{
26+
throw new NullPointerException("'context' cannot be null");
27+
}
28+
2429
this.context = Arrays.clone(context);
2530
}
2631

@@ -84,8 +89,13 @@ public boolean verifySignature(byte[] signature)
8489
return false;
8590
}
8691

87-
byte[] pk = publicKey.getEncoded();
88-
return Ed25519.verifyPrehash(signature, 0, pk, 0, context, prehash);
92+
byte[] msg = new byte[Ed25519.PREHASH_SIZE];
93+
if (Ed25519.PREHASH_SIZE != prehash.doFinal(msg, 0))
94+
{
95+
throw new IllegalStateException("Prehash digest failed");
96+
}
97+
98+
return publicKey.verify(Ed25519.Algorithm.Ed25519ph, context, msg, 0, Ed25519.PREHASH_SIZE, signature, 0);
8999
}
90100

91101
public void reset()

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

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import org.bouncycastle.math.ec.rfc8032.Ed448;
1111
import org.bouncycastle.util.Arrays;
1212

13-
1413
public class Ed448Signer
1514
implements Signer
1615
{
@@ -23,6 +22,11 @@ public class Ed448Signer
2322

2423
public Ed448Signer(byte[] context)
2524
{
25+
if (null == context)
26+
{
27+
throw new NullPointerException("'context' cannot be null");
28+
}
29+
2630
this.context = Arrays.clone(context);
2731
}
2832

@@ -81,7 +85,7 @@ public void reset()
8185
buffer.reset();
8286
}
8387

84-
private static class Buffer extends ByteArrayOutputStream
88+
private static final class Buffer extends ByteArrayOutputStream
8589
{
8690
synchronized byte[] generateSignature(Ed448PrivateKeyParameters privateKey, byte[] ctx)
8791
{
@@ -99,8 +103,7 @@ synchronized boolean verifySignature(Ed448PublicKeyParameters publicKey, byte[]
99103
return false;
100104
}
101105

102-
byte[] pk = publicKey.getEncoded();
103-
boolean result = Ed448.verify(signature, 0, pk, 0, ctx, buf, 0, count);
106+
boolean result = publicKey.verify(Ed448.Algorithm.Ed448, ctx, buf, 0, count, signature, 0);
104107
reset();
105108
return result;
106109
}

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

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ public class Ed448phSigner
2121

2222
public Ed448phSigner(byte[] context)
2323
{
24+
if (null == context)
25+
{
26+
throw new NullPointerException("'context' cannot be null");
27+
}
28+
2429
this.context = Arrays.clone(context);
2530
}
2631

@@ -84,8 +89,13 @@ public boolean verifySignature(byte[] signature)
8489
return false;
8590
}
8691

87-
byte[] pk = publicKey.getEncoded();
88-
return Ed448.verifyPrehash(signature, 0, pk, 0, context, prehash);
92+
byte[] msg = new byte[Ed448.PREHASH_SIZE];
93+
if (Ed448.PREHASH_SIZE != prehash. doFinal(msg, 0, Ed448.PREHASH_SIZE))
94+
{
95+
throw new IllegalStateException("Prehash digest failed");
96+
}
97+
98+
return publicKey.verify(Ed448.Algorithm.Ed448ph, context, msg, 0, Ed448.PREHASH_SIZE, signature, 0);
8999
}
90100

91101
public void reset()

core/src/main/java/org/bouncycastle/math/ec/rfc8032/Ed25519.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,11 @@ private static int checkPoint(int[] x, int[] y, int[] z)
202202

203203
private static boolean checkPointVar(byte[] p)
204204
{
205+
if ((decode32(p, 28) & 0x7FFFFFFF) < P[7])
206+
{
207+
return true;
208+
}
209+
205210
int[] t = new int[COORD_INTS];
206211
decode32(p, 0, t, 0, COORD_INTS);
207212
t[COORD_INTS - 1] &= 0x7FFFFFFF;
@@ -223,7 +228,12 @@ private static byte[] copy(byte[] buf, int off, int len)
223228

224229
private static Digest createDigest()
225230
{
226-
return new SHA512Digest();
231+
Digest d = new SHA512Digest();
232+
if (d.getDigestSize() != 64)
233+
{
234+
throw new IllegalStateException();
235+
}
236+
return d;
227237
}
228238

229239
public static Digest createPrehash()
@@ -369,7 +379,7 @@ public static void generatePrivateKey(SecureRandom random, byte[] k)
369379
public static void generatePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff)
370380
{
371381
Digest d = createDigest();
372-
byte[] h = new byte[d.getDigestSize()];
382+
byte[] h = new byte[64];
373383

374384
d.update(sk, skOff, SECRET_KEY_SIZE);
375385
d.doFinal(h, 0);
@@ -470,7 +480,7 @@ private static void implSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte
470480
}
471481

472482
Digest d = createDigest();
473-
byte[] h = new byte[d.getDigestSize()];
483+
byte[] h = new byte[64];
474484

475485
d.update(sk, skOff, SECRET_KEY_SIZE);
476486
d.doFinal(h, 0);
@@ -493,7 +503,7 @@ private static void implSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[]
493503
}
494504

495505
Digest d = createDigest();
496-
byte[] h = new byte[d.getDigestSize()];
506+
byte[] h = new byte[64];
497507

498508
d.update(sk, skOff, SECRET_KEY_SIZE);
499509
d.doFinal(h, 0);
@@ -533,7 +543,7 @@ private static boolean implVerify(byte[] sig, int sigOff, byte[] pk, int pkOff,
533543
}
534544

535545
Digest d = createDigest();
536-
byte[] h = new byte[d.getDigestSize()];
546+
byte[] h = new byte[64];
537547

538548
dom2(d, phflag, ctx);
539549
d.update(R, 0, POINT_BYTES);

0 commit comments

Comments
 (0)