Skip to content

Commit 6580b53

Browse files
committed
Split Public Keys
1 parent 7045c99 commit 6580b53

28 files changed

+305
-268
lines changed

Diff for: pom.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@
221221
<artifactId>maven-failsafe-plugin</artifactId>
222222
<version>2.22.2</version>
223223
</plugin>
224-
<plugin>
224+
<plugin>
225225
<artifactId>maven-surefire-plugin</artifactId>
226226
<version>3.2.5</version>
227227
<dependencies>
@@ -237,7 +237,7 @@
237237
<disable>true</disable>
238238
</consoleOutputReporter>
239239
<statelessTestsetInfoReporter
240-
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
240+
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
241241
<printStacktraceOnError>true</printStacktraceOnError>
242242
<printStacktraceOnFailure>true</printStacktraceOnFailure>
243243
<printStdoutOnError>true</printStdoutOnError>
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,16 @@
11
package org.biscuitsec.biscuit.crypto;
22

3-
import biscuit.format.schema.Schema;
4-
5-
import java.io.IOException;
6-
import java.security.*;
7-
import java.security.spec.InvalidKeySpecException;
8-
import java.security.spec.NamedParameterSpec;
9-
import java.security.spec.X509EncodedKeySpec;
10-
3+
import java.security.InvalidKeyException;
4+
import java.security.NoSuchAlgorithmException;
5+
import java.security.SecureRandom;
6+
import java.security.SignatureException;
117
import org.biscuitsec.biscuit.token.builder.Utils;
12-
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
13-
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
8+
import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
9+
import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator;
10+
import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters;
1411
import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
1512
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
1613
import org.bouncycastle.crypto.signers.Ed25519Signer;
17-
import org.bouncycastle.internal.asn1.edec.EdECObjectIdentifiers;
18-
import org.bouncycastle.jcajce.provider.asymmetric.dh.BCDHPublicKey;
19-
import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPublicKey;
20-
import org.bouncycastle.util.encoders.Hex;
2114

2215
final class Ed25519KeyPair extends KeyPair {
2316
private static final int BUFFER_SIZE = 32;
@@ -36,12 +29,13 @@ final class Ed25519KeyPair extends KeyPair {
3629
}
3730

3831
Ed25519KeyPair(SecureRandom rng) {
39-
byte[] b = new byte[BUFFER_SIZE];
40-
rng.nextBytes(b);
4132

42-
Ed25519PrivateKeyParameters privateKey = new Ed25519PrivateKeyParameters(b);
33+
Ed25519KeyPairGenerator kpg = new Ed25519KeyPairGenerator();
34+
kpg.init(new Ed25519KeyGenerationParameters(rng));
4335

44-
Ed25519PublicKeyParameters publicKey = privateKey.generatePublicKey();
36+
AsymmetricCipherKeyPair kp = kpg.generateKeyPair();
37+
Ed25519PrivateKeyParameters privateKey = (Ed25519PrivateKeyParameters) kp.getPrivate();
38+
Ed25519PublicKeyParameters publicKey = (Ed25519PublicKeyParameters) kp.getPublic();
4539

4640
this.privateKey = privateKey;
4741
this.publicKey = publicKey;
@@ -51,22 +45,6 @@ final class Ed25519KeyPair extends KeyPair {
5145
this(Utils.hexStringToByteArray(hex));
5246
}
5347

54-
/*
55-
public static java.security.PublicKey decode(byte[] data) {
56-
var keyFactory = KeyFactory.getInstance("Ed25519");
57-
58-
// Wrap public key in ASN.1 format so we can use X509EncodedKeySpec to read it
59-
var pubKeyInfo = new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), data);
60-
var x509KeySpec = new X509EncodedKeySpec(pubKeyInfo.getEncoded());
61-
62-
return new BCDHPublicKey(x509KeySpec);
63-
}
64-
65-
66-
public static Signature getSignature() throws NoSuchAlgorithmException {
67-
return new EdDSAEngine(MessageDigest.getInstance(ED_25519.getHashAlgorithm()));
68-
}*/
69-
7048
@Override
7149
public byte[] sign(byte[] data)
7250
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
@@ -76,13 +54,6 @@ public byte[] sign(byte[] data)
7654
return sgr.generateSignature();
7755
}
7856

79-
public static boolean verify(PublicKey publicKey, byte[] data, byte[] signature) {
80-
var sgr = new Ed25519Signer();
81-
sgr.init(false, new Ed25519PublicKeyParameters(publicKey.toBytes()));
82-
sgr.update(data, 0, data.length);
83-
return sgr.verifySignature(signature);
84-
}
85-
8657
@Override
8758
public byte[] toBytes() {
8859
return privateKey.getEncoded();
@@ -95,6 +66,6 @@ public String toHex() {
9566

9667
@Override
9768
public PublicKey getPublicKey() {
98-
return new PublicKey(Schema.PublicKey.Algorithm.Ed25519, this.publicKey.getEncoded());
69+
return new Ed25519PublicKey(this.publicKey);
9970
}
10071
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package org.biscuitsec.biscuit.crypto;
2+
3+
import biscuit.format.schema.Schema.PublicKey.Algorithm;
4+
import java.util.Arrays;
5+
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
6+
import org.bouncycastle.crypto.signers.Ed25519Signer;
7+
8+
class Ed25519PublicKey extends PublicKey {
9+
private final Ed25519PublicKeyParameters publicKey;
10+
11+
Ed25519PublicKey(final Ed25519PublicKeyParameters publicKey) {
12+
super();
13+
this.publicKey = publicKey;
14+
}
15+
16+
static Ed25519PublicKey loadEd25519(byte[] data) {
17+
return new Ed25519PublicKey(new Ed25519PublicKeyParameters(data));
18+
}
19+
20+
@Override
21+
public byte[] toBytes() {
22+
return this.publicKey.getEncoded();
23+
}
24+
25+
@Override
26+
public boolean equals(Object o) {
27+
if (this == o) {
28+
return true;
29+
}
30+
if (o == null || getClass() != o.getClass()) {
31+
return false;
32+
}
33+
34+
Ed25519PublicKey publicKey = (Ed25519PublicKey) o;
35+
36+
return Arrays.equals(this.toBytes(), publicKey.toBytes());
37+
}
38+
39+
@Override
40+
public int hashCode() {
41+
return this.publicKey.hashCode();
42+
}
43+
44+
@Override
45+
public String toString() {
46+
return "ed25519/" + toHex().toLowerCase();
47+
}
48+
49+
public Algorithm getAlgorithm() {
50+
return Algorithm.Ed25519;
51+
}
52+
53+
@Override
54+
public boolean verify(byte[] data, byte[] signature) {
55+
var sgr = new Ed25519Signer();
56+
sgr.init(false, this.publicKey);
57+
sgr.update(data, 0, data.length);
58+
return sgr.verifySignature(signature);
59+
}
60+
}

Diff for: src/main/java/org/biscuitsec/biscuit/crypto/KeyPair.java

+2-27
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,8 @@
11
package org.biscuitsec.biscuit.crypto;
22

33
import biscuit.format.schema.Schema.PublicKey.Algorithm;
4-
5-
import java.io.IOException;
6-
import java.security.*;
7-
import java.security.spec.InvalidKeySpecException;
8-
4+
import java.security.SecureRandom;
5+
import java.security.Security;
96
import org.biscuitsec.biscuit.token.builder.Utils;
107
import org.bouncycastle.jce.provider.BouncyCastleProvider;
118

@@ -44,28 +41,6 @@ public static KeyPair generate(Algorithm algorithm, SecureRandom rng) {
4441
}
4542
}
4643

47-
/*
48-
public static Signature generateSignature(Algorithm algorithm) throws NoSuchAlgorithmException {
49-
if (algorithm == Algorithm.Ed25519) {
50-
return Ed25519KeyPair.getSignature();
51-
} else if (algorithm == Algorithm.SECP256R1) {
52-
return SECP256R1KeyPair.getSignature();
53-
} else {
54-
throw new NoSuchAlgorithmException("Unsupported algorithm");
55-
}
56-
}*/
57-
58-
public static boolean verify(PublicKey publicKey, byte[] data, byte[] signature)
59-
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
60-
if (publicKey.getAlgorithm() == Algorithm.Ed25519) {
61-
return Ed25519KeyPair.verify(publicKey,data, signature);
62-
} else if (publicKey.getAlgorithm() == Algorithm.SECP256R1) {
63-
return SECP256R1KeyPair.verify(publicKey, data, signature);
64-
} else {
65-
throw new NoSuchAlgorithmException("Unsupported algorithm");
66-
}
67-
}
68-
6944
public abstract byte[] toBytes();
7045

7146
public abstract String toHex();

Diff for: src/main/java/org/biscuitsec/biscuit/crypto/PublicKey.java

+19-59
Original file line numberDiff line numberDiff line change
@@ -3,45 +3,34 @@
33
import biscuit.format.schema.Schema;
44
import biscuit.format.schema.Schema.PublicKey.Algorithm;
55
import com.google.protobuf.ByteString;
6-
7-
import java.io.IOException;
6+
import java.security.InvalidKeyException;
87
import java.security.NoSuchAlgorithmException;
9-
import java.security.spec.InvalidKeySpecException;
10-
import java.util.Arrays;
8+
import java.security.SignatureException;
119
import java.util.Optional;
1210
import java.util.Set;
1311
import org.biscuitsec.biscuit.error.Error;
1412
import org.biscuitsec.biscuit.token.builder.Utils;
15-
import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
16-
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
17-
import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPublicKey;
18-
19-
public final class PublicKey {
2013

21-
private final byte[] key;
22-
private final Algorithm algorithm;
14+
public abstract class PublicKey {
2315

2416
private static final Set<Algorithm> SUPPORTED_ALGORITHMS =
2517
Set.of(Algorithm.Ed25519, Algorithm.SECP256R1);
2618

27-
public PublicKey(Algorithm algorithm, java.security.PublicKey publicKey) {
28-
this.key = publicKey.getEncoded();
29-
this.algorithm = algorithm;
30-
}
31-
32-
public PublicKey(Algorithm algorithm, byte[] data) {
33-
this.key = data;
34-
this.algorithm = algorithm;
19+
public static PublicKey load(Algorithm algorithm, byte[] data) {
20+
if (algorithm == Algorithm.Ed25519) {
21+
return Ed25519PublicKey.loadEd25519(data);
22+
} else if (algorithm == Algorithm.SECP256R1) {
23+
return Secp256R1PublicKey.loadSecp256r1(data);
24+
} else {
25+
throw new IllegalArgumentException("Unsupported algorithm");
26+
}
3527
}
3628

37-
public PublicKey(Algorithm algorithm, String hex) {
38-
this.key = Utils.hexStringToByteArray(hex);
39-
this.algorithm = algorithm;
29+
public static PublicKey load(Algorithm algorithm, String hex) {
30+
return load(algorithm, Utils.hexStringToByteArray(hex));
4031
}
4132

42-
public byte[] toBytes() {
43-
return this.key;
44-
}
33+
public abstract byte[] toBytes();
4534

4635
public String toHex() {
4736
return Utils.byteArrayToHexString(this.toBytes());
@@ -50,7 +39,7 @@ public String toHex() {
5039
public Schema.PublicKey serialize() {
5140
Schema.PublicKey.Builder publicKey = Schema.PublicKey.newBuilder();
5241
publicKey.setKey(ByteString.copyFrom(this.toBytes()));
53-
publicKey.setAlgorithm(this.algorithm);
42+
publicKey.setAlgorithm(this.getAlgorithm());
5443
return publicKey.build();
5544
}
5645

@@ -59,7 +48,7 @@ public static PublicKey deserialize(Schema.PublicKey pk)
5948
if (!pk.hasAlgorithm() || !pk.hasKey() || !SUPPORTED_ALGORITHMS.contains(pk.getAlgorithm())) {
6049
throw new Error.FormatError.DeserializationError("Invalid public key");
6150
}
62-
return new PublicKey(pk.getAlgorithm(), pk.getKey().toByteArray());
51+
return PublicKey.load(pk.getAlgorithm(), pk.getKey().toByteArray());
6352
}
6453

6554
public static Optional<Error> validateSignatureLength(Algorithm algorithm, int length) {
@@ -80,37 +69,8 @@ public static Optional<Error> validateSignatureLength(Algorithm algorithm, int l
8069
return error;
8170
}
8271

83-
@Override
84-
public boolean equals(Object o) {
85-
if (this == o) {
86-
return true;
87-
}
88-
if (o == null || getClass() != o.getClass()) {
89-
return false;
90-
}
72+
public abstract Algorithm getAlgorithm();
9173

92-
PublicKey publicKey = (PublicKey) o;
93-
94-
return this.algorithm.equals(publicKey.algorithm) && Arrays.equals(this.key, publicKey.toBytes());
95-
}
96-
97-
@Override
98-
public int hashCode() {
99-
return Arrays.hashCode(this.key);
100-
}
101-
102-
@Override
103-
public String toString() {
104-
if (this.algorithm == Algorithm.Ed25519) {
105-
return "ed25519/" + toHex().toLowerCase();
106-
} else if (this.algorithm == Algorithm.SECP256R1) {
107-
return "secp256r1/" + toHex().toLowerCase();
108-
} else {
109-
return null;
110-
}
111-
}
112-
113-
public Algorithm getAlgorithm() {
114-
return this.algorithm;
115-
}
74+
public abstract boolean verify(byte[] data, byte[] signature)
75+
throws InvalidKeyException, SignatureException, NoSuchAlgorithmException;
11676
}

Diff for: src/main/java/org/biscuitsec/biscuit/crypto/SECP256R1KeyPair.java

+6-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
package org.biscuitsec.biscuit.crypto;
22

3-
import biscuit.format.schema.Schema;
43
import java.security.InvalidKeyException;
54
import java.security.NoSuchAlgorithmException;
65
import java.security.SecureRandom;
7-
import java.security.Security;
86
import java.security.Signature;
97
import java.security.SignatureException;
108
import org.biscuitsec.biscuit.token.builder.Utils;
@@ -27,11 +25,9 @@ final class SECP256R1KeyPair extends KeyPair {
2725
private final BCECPrivateKey privateKey;
2826
private final BCECPublicKey publicKey;
2927

30-
private static final String ALGORITHM = "ECDSA";
31-
private static final String CURVE = "secp256r1";
32-
private static final ECNamedCurveParameterSpec SECP256R1 =
33-
ECNamedCurveTable.getParameterSpec(CURVE);
34-
28+
static final String ALGORITHM = "ECDSA";
29+
static final String CURVE = "secp256r1";
30+
static final ECNamedCurveParameterSpec SECP256R1 = ECNamedCurveTable.getParameterSpec(CURVE);
3531

3632
SECP256R1KeyPair(byte[] bytes) {
3733
var privateKeySpec = new ECPrivateKeySpec(BigIntegers.fromUnsignedByteArray(bytes), SECP256R1);
@@ -72,7 +68,7 @@ public static java.security.PublicKey decode(byte[] data) {
7268
return new BCECPublicKey(ALGORITHM, spec, BouncyCastleProvider.CONFIGURATION);
7369
}
7470

75-
private static Signature getSignature() throws NoSuchAlgorithmException {
71+
static Signature getSignature() throws NoSuchAlgorithmException {
7672
return Signature.getInstance("SHA256withECDSA", new BouncyCastleProvider());
7773
}
7874

@@ -86,7 +82,7 @@ public byte[] sign(byte[] data)
8682
}
8783

8884
public static boolean verify(PublicKey publicKey, byte[] data, byte[] signature)
89-
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
85+
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
9086
var sgr = getSignature();
9187
sgr.initVerify(decode(publicKey.toBytes()));
9288
sgr.update(data);
@@ -105,6 +101,6 @@ public String toHex() {
105101

106102
@Override
107103
public PublicKey getPublicKey() {
108-
return new PublicKey(Schema.PublicKey.Algorithm.SECP256R1, publicKey);
104+
return new Secp256R1PublicKey(this.publicKey);
109105
}
110106
}

0 commit comments

Comments
 (0)