diff --git a/pom.xml b/pom.xml
index de8c9deb..4e242e1f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -35,13 +35,13 @@
0.10.3
1.6
2.8.9
- 1.79
+ 1.80
5.8.2
2.30.2
- 1.20.4
- 1.20.4
+ 1.20.6
+ 1.20.6
@@ -221,7 +221,7 @@
maven-failsafe-plugin
2.22.2
-
+
maven-surefire-plugin
3.2.5
@@ -237,7 +237,7 @@
true
+ implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
true
true
true
@@ -281,11 +281,6 @@
protobuf-java
${protobuf.version}
-
- net.i2p.crypto
- eddsa
- ${net.i2p.crypto.eddsa.version}
-
io.vavr
vavr
diff --git a/src/main/java/org/biscuitsec/biscuit/crypto/Ed25519KeyPair.java b/src/main/java/org/biscuitsec/biscuit/crypto/Ed25519KeyPair.java
index 7b7815d0..d57fcdf8 100644
--- a/src/main/java/org/biscuitsec/biscuit/crypto/Ed25519KeyPair.java
+++ b/src/main/java/org/biscuitsec/biscuit/crypto/Ed25519KeyPair.java
@@ -1,81 +1,52 @@
package org.biscuitsec.biscuit.crypto;
-import biscuit.format.schema.Schema;
-import java.security.InvalidKeyException;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
-import java.security.Signature;
-import java.security.SignatureException;
-import net.i2p.crypto.eddsa.EdDSAEngine;
-import net.i2p.crypto.eddsa.EdDSAPrivateKey;
-import net.i2p.crypto.eddsa.EdDSAPublicKey;
-import net.i2p.crypto.eddsa.spec.EdDSANamedCurveSpec;
-import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable;
-import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec;
-import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
import org.biscuitsec.biscuit.token.builder.Utils;
+import org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator;
+import org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters;
+import org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters;
+import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
+import org.bouncycastle.crypto.signers.Ed25519Signer;
final class Ed25519KeyPair extends KeyPair {
- private static final int BUFFER_SIZE = 32;
-
public static final int SIGNATURE_LENGTH = 64;
- private final EdDSAPrivateKey privateKey;
- private final EdDSAPublicKey publicKey;
-
- private static final EdDSANamedCurveSpec ED_25519 =
- EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519);
+ private final Ed25519PrivateKeyParameters privateKey;
+ private final Ed25519PublicKeyParameters publicKey;
Ed25519KeyPair(byte[] bytes) {
- EdDSAPrivateKeySpec privKeySpec = new EdDSAPrivateKeySpec(bytes, ED_25519);
- EdDSAPrivateKey privKey = new EdDSAPrivateKey(privKeySpec);
-
- EdDSAPublicKeySpec pubKeySpec = new EdDSAPublicKeySpec(privKey.getA(), ED_25519);
- EdDSAPublicKey pubKey = new EdDSAPublicKey(pubKeySpec);
+ Ed25519PrivateKeyParameters privateKey = new Ed25519PrivateKeyParameters(bytes);
+ Ed25519PublicKeyParameters publicKey = privateKey.generatePublicKey();
- this.privateKey = privKey;
- this.publicKey = pubKey;
+ this.privateKey = privateKey;
+ this.publicKey = publicKey;
}
Ed25519KeyPair(SecureRandom rng) {
- byte[] b = new byte[BUFFER_SIZE];
- rng.nextBytes(b);
- EdDSAPrivateKeySpec privKeySpec = new EdDSAPrivateKeySpec(b, ED_25519);
- EdDSAPrivateKey privKey = new EdDSAPrivateKey(privKeySpec);
+ Ed25519KeyPairGenerator kpg = new Ed25519KeyPairGenerator();
+ kpg.init(new Ed25519KeyGenerationParameters(rng));
- EdDSAPublicKeySpec pubKeySpec = new EdDSAPublicKeySpec(privKey.getA(), ED_25519);
- EdDSAPublicKey pubKey = new EdDSAPublicKey(pubKeySpec);
-
- this.privateKey = privKey;
- this.publicKey = pubKey;
- }
-
- Ed25519KeyPair(String hex) {
- this(Utils.hexStringToByteArray(hex));
- }
-
- public static java.security.PublicKey decode(byte[] data) {
- return new EdDSAPublicKey(new EdDSAPublicKeySpec(data, ED_25519));
- }
+ AsymmetricCipherKeyPair kp = kpg.generateKeyPair();
+ Ed25519PrivateKeyParameters privateKey = (Ed25519PrivateKeyParameters) kp.getPrivate();
+ Ed25519PublicKeyParameters publicKey = (Ed25519PublicKeyParameters) kp.getPublic();
- public static Signature getSignature() throws NoSuchAlgorithmException {
- return new EdDSAEngine(MessageDigest.getInstance(ED_25519.getHashAlgorithm()));
+ this.privateKey = privateKey;
+ this.publicKey = publicKey;
}
@Override
- public byte[] sign(byte[] data)
- throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
- Signature sgr = KeyPair.generateSignature(Schema.PublicKey.Algorithm.Ed25519);
- sgr.initSign(privateKey);
- sgr.update(data);
- return sgr.sign();
+ public byte[] sign(byte[] data) {
+ var sgr = new Ed25519Signer();
+ sgr.init(true, this.privateKey);
+ sgr.update(data, 0, data.length);
+ return sgr.generateSignature();
}
@Override
public byte[] toBytes() {
- return privateKey.getSeed();
+ return privateKey.getEncoded();
}
@Override
@@ -85,6 +56,6 @@ public String toHex() {
@Override
public PublicKey getPublicKey() {
- return new PublicKey(Schema.PublicKey.Algorithm.Ed25519, this.publicKey);
+ return new Ed25519PublicKey(this.publicKey);
}
}
diff --git a/src/main/java/org/biscuitsec/biscuit/crypto/Ed25519PublicKey.java b/src/main/java/org/biscuitsec/biscuit/crypto/Ed25519PublicKey.java
new file mode 100644
index 00000000..652fb643
--- /dev/null
+++ b/src/main/java/org/biscuitsec/biscuit/crypto/Ed25519PublicKey.java
@@ -0,0 +1,60 @@
+package org.biscuitsec.biscuit.crypto;
+
+import biscuit.format.schema.Schema.PublicKey.Algorithm;
+import java.util.Arrays;
+import org.bouncycastle.crypto.params.Ed25519PublicKeyParameters;
+import org.bouncycastle.crypto.signers.Ed25519Signer;
+
+class Ed25519PublicKey extends PublicKey {
+ private final Ed25519PublicKeyParameters publicKey;
+
+ Ed25519PublicKey(final Ed25519PublicKeyParameters publicKey) {
+ super();
+ this.publicKey = publicKey;
+ }
+
+ static Ed25519PublicKey loadEd25519(byte[] data) {
+ return new Ed25519PublicKey(new Ed25519PublicKeyParameters(data));
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return this.publicKey.getEncoded();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ Ed25519PublicKey publicKey = (Ed25519PublicKey) o;
+
+ return Arrays.equals(this.toBytes(), publicKey.toBytes());
+ }
+
+ @Override
+ public int hashCode() {
+ return this.publicKey.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "ed25519/" + toHex().toLowerCase();
+ }
+
+ public Algorithm getAlgorithm() {
+ return Algorithm.Ed25519;
+ }
+
+ @Override
+ public boolean verify(byte[] data, byte[] signature) {
+ var sgr = new Ed25519Signer();
+ sgr.init(false, this.publicKey);
+ sgr.update(data, 0, data.length);
+ return sgr.verifySignature(signature);
+ }
+}
diff --git a/src/main/java/org/biscuitsec/biscuit/crypto/KeyPair.java b/src/main/java/org/biscuitsec/biscuit/crypto/KeyPair.java
index 62498eb5..eba27a3b 100644
--- a/src/main/java/org/biscuitsec/biscuit/crypto/KeyPair.java
+++ b/src/main/java/org/biscuitsec/biscuit/crypto/KeyPair.java
@@ -1,12 +1,8 @@
package org.biscuitsec.biscuit.crypto;
import biscuit.format.schema.Schema.PublicKey.Algorithm;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
-import java.security.Signature;
-import java.security.SignatureException;
-import net.i2p.crypto.eddsa.Utils;
+import org.biscuitsec.biscuit.token.builder.Utils;
/** Private and public key. */
public abstract class KeyPair implements Signer {
@@ -16,7 +12,7 @@ public static KeyPair generate(Algorithm algorithm) {
}
public static KeyPair generate(Algorithm algorithm, String hex) {
- return generate(algorithm, Utils.hexToBytes(hex));
+ return generate(algorithm, Utils.hexStringToByteArray(hex));
}
public static KeyPair generate(Algorithm algorithm, byte[] bytes) {
@@ -39,24 +35,6 @@ public static KeyPair generate(Algorithm algorithm, SecureRandom rng) {
}
}
- public static Signature generateSignature(Algorithm algorithm) throws NoSuchAlgorithmException {
- if (algorithm == Algorithm.Ed25519) {
- return Ed25519KeyPair.getSignature();
- } else if (algorithm == Algorithm.SECP256R1) {
- return SECP256R1KeyPair.getSignature();
- } else {
- throw new NoSuchAlgorithmException("Unsupported algorithm");
- }
- }
-
- public static boolean verify(PublicKey publicKey, byte[] data, byte[] signature)
- throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
- Signature sgr = KeyPair.generateSignature(publicKey.getAlgorithm());
- sgr.initVerify(publicKey.getKey());
- sgr.update(data);
- return sgr.verify(signature);
- }
-
public abstract byte[] toBytes();
public abstract String toHex();
diff --git a/src/main/java/org/biscuitsec/biscuit/crypto/PublicKey.java b/src/main/java/org/biscuitsec/biscuit/crypto/PublicKey.java
index aced9765..30c0eaab 100644
--- a/src/main/java/org/biscuitsec/biscuit/crypto/PublicKey.java
+++ b/src/main/java/org/biscuitsec/biscuit/crypto/PublicKey.java
@@ -3,58 +3,34 @@
import biscuit.format.schema.Schema;
import biscuit.format.schema.Schema.PublicKey.Algorithm;
import com.google.protobuf.ByteString;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
import java.util.Optional;
import java.util.Set;
-import net.i2p.crypto.eddsa.EdDSAPublicKey;
import org.biscuitsec.biscuit.error.Error;
import org.biscuitsec.biscuit.token.builder.Utils;
-import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
-public final class PublicKey {
-
- private final java.security.PublicKey key;
- private final Algorithm algorithm;
+public abstract class PublicKey {
private static final Set SUPPORTED_ALGORITHMS =
Set.of(Algorithm.Ed25519, Algorithm.SECP256R1);
- public PublicKey(Algorithm algorithm, java.security.PublicKey publicKey) {
- this.key = publicKey;
- this.algorithm = algorithm;
- }
-
- public PublicKey(Algorithm algorithm, byte[] data) {
+ public static PublicKey load(Algorithm algorithm, byte[] data) {
if (algorithm == Algorithm.Ed25519) {
- this.key = Ed25519KeyPair.decode(data);
+ return Ed25519PublicKey.loadEd25519(data);
} else if (algorithm == Algorithm.SECP256R1) {
- this.key = SECP256R1KeyPair.decode(data);
+ return SECP256R1PublicKey.loadSECP256R1(data);
} else {
- throw new IllegalArgumentException("Invalid algorithm");
+ throw new IllegalArgumentException("Unsupported algorithm");
}
- this.algorithm = algorithm;
}
- public PublicKey(Algorithm algorithm, String hex) {
- byte[] data = Utils.hexStringToByteArray(hex);
- if (algorithm == Algorithm.Ed25519) {
- this.key = Ed25519KeyPair.decode(data);
- } else if (algorithm == Algorithm.SECP256R1) {
- this.key = SECP256R1KeyPair.decode(data);
- } else {
- throw new IllegalArgumentException("Invalid algorithm");
- }
- this.algorithm = algorithm;
+ public static PublicKey load(Algorithm algorithm, String hex) {
+ return load(algorithm, Utils.hexStringToByteArray(hex));
}
- public byte[] toBytes() {
- if (this.algorithm == Algorithm.Ed25519) {
- return ((EdDSAPublicKey) getKey()).getAbyte();
- } else if (this.algorithm == Algorithm.SECP256R1) {
- return ((BCECPublicKey) getKey()).getQ().getEncoded(true); // true = compressed
- } else {
- throw new IllegalArgumentException("Invalid algorithm");
- }
- }
+ public abstract byte[] toBytes();
public String toHex() {
return Utils.byteArrayToHexString(this.toBytes());
@@ -63,7 +39,7 @@ public String toHex() {
public Schema.PublicKey serialize() {
Schema.PublicKey.Builder publicKey = Schema.PublicKey.newBuilder();
publicKey.setKey(ByteString.copyFrom(this.toBytes()));
- publicKey.setAlgorithm(this.algorithm);
+ publicKey.setAlgorithm(this.getAlgorithm());
return publicKey.build();
}
@@ -72,7 +48,7 @@ public static PublicKey deserialize(Schema.PublicKey pk)
if (!pk.hasAlgorithm() || !pk.hasKey() || !SUPPORTED_ALGORITHMS.contains(pk.getAlgorithm())) {
throw new Error.FormatError.DeserializationError("Invalid public key");
}
- return new PublicKey(pk.getAlgorithm(), pk.getKey().toByteArray());
+ return PublicKey.load(pk.getAlgorithm(), pk.getKey().toByteArray());
}
public static Optional validateSignatureLength(Algorithm algorithm, int length) {
@@ -93,41 +69,8 @@ public static Optional validateSignatureLength(Algorithm algorithm, int l
return error;
}
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- PublicKey publicKey = (PublicKey) o;
-
- return this.key.equals(publicKey.getKey());
- }
-
- @Override
- public int hashCode() {
- return getKey().hashCode();
- }
-
- @Override
- public String toString() {
- if (this.algorithm == Algorithm.Ed25519) {
- return "ed25519/" + toHex().toLowerCase();
- } else if (this.algorithm == Algorithm.SECP256R1) {
- return "secp256r1/" + toHex().toLowerCase();
- } else {
- return null;
- }
- }
+ public abstract Algorithm getAlgorithm();
- public java.security.PublicKey getKey() {
- return this.key;
- }
-
- public Algorithm getAlgorithm() {
- return this.algorithm;
- }
+ public abstract boolean verify(byte[] data, byte[] signature)
+ throws InvalidKeyException, SignatureException, NoSuchAlgorithmException;
}
diff --git a/src/main/java/org/biscuitsec/biscuit/crypto/SECP256R1KeyPair.java b/src/main/java/org/biscuitsec/biscuit/crypto/SECP256R1KeyPair.java
index c7d4aa5f..c1373067 100644
--- a/src/main/java/org/biscuitsec/biscuit/crypto/SECP256R1KeyPair.java
+++ b/src/main/java/org/biscuitsec/biscuit/crypto/SECP256R1KeyPair.java
@@ -1,6 +1,5 @@
package org.biscuitsec.biscuit.crypto;
-import biscuit.format.schema.Schema;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
@@ -27,15 +26,14 @@ final class SECP256R1KeyPair extends KeyPair {
private final BCECPrivateKey privateKey;
private final BCECPublicKey publicKey;
- private static final String ALGORITHM = "ECDSA";
- private static final String CURVE = "secp256r1";
- private static final ECNamedCurveParameterSpec SECP256R1 =
- ECNamedCurveTable.getParameterSpec(CURVE);
-
static {
Security.addProvider(new BouncyCastleProvider());
}
+ static final String ALGORITHM = "ECDSA";
+ static final String CURVE = "secp256r1";
+ static final ECNamedCurveParameterSpec SECP256R1 = ECNamedCurveTable.getParameterSpec(CURVE);
+
SECP256R1KeyPair(byte[] bytes) {
var privateKeySpec = new ECPrivateKeySpec(BigIntegers.fromUnsignedByteArray(bytes), SECP256R1);
var privateKey =
@@ -65,24 +63,14 @@ final class SECP256R1KeyPair extends KeyPair {
this.publicKey = publicKey;
}
- SECP256R1KeyPair(String hex) {
- this(Utils.hexStringToByteArray(hex));
- }
-
- public static java.security.PublicKey decode(byte[] data) {
- var params = ECNamedCurveTable.getParameterSpec(CURVE);
- var spec = new ECPublicKeySpec(params.getCurve().decodePoint(data), params);
- return new BCECPublicKey(ALGORITHM, spec, BouncyCastleProvider.CONFIGURATION);
- }
-
- public static Signature getSignature() throws NoSuchAlgorithmException {
+ static Signature getSignature() throws NoSuchAlgorithmException {
return Signature.getInstance("SHA256withECDSA", new BouncyCastleProvider());
}
@Override
public byte[] sign(byte[] data)
throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
- Signature sgr = KeyPair.generateSignature(Schema.PublicKey.Algorithm.SECP256R1);
+ Signature sgr = getSignature();
sgr.initSign(privateKey);
sgr.update(data);
return sgr.sign();
@@ -100,6 +88,6 @@ public String toHex() {
@Override
public PublicKey getPublicKey() {
- return new PublicKey(Schema.PublicKey.Algorithm.SECP256R1, publicKey);
+ return new SECP256R1PublicKey(this.publicKey);
}
}
diff --git a/src/main/java/org/biscuitsec/biscuit/crypto/SECP256R1PublicKey.java b/src/main/java/org/biscuitsec/biscuit/crypto/SECP256R1PublicKey.java
new file mode 100644
index 00000000..4e7d46be
--- /dev/null
+++ b/src/main/java/org/biscuitsec/biscuit/crypto/SECP256R1PublicKey.java
@@ -0,0 +1,74 @@
+package org.biscuitsec.biscuit.crypto;
+
+import static org.biscuitsec.biscuit.crypto.SECP256R1KeyPair.CURVE;
+import static org.biscuitsec.biscuit.crypto.SECP256R1KeyPair.getSignature;
+
+import biscuit.format.schema.Schema.PublicKey.Algorithm;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.SignatureException;
+import java.util.Arrays;
+import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
+import org.bouncycastle.jce.ECNamedCurveTable;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.bouncycastle.jce.spec.ECPublicKeySpec;
+
+@SuppressWarnings("checkstyle:AbbreviationAsWordInName")
+class SECP256R1PublicKey extends PublicKey {
+
+ private final BCECPublicKey publicKey;
+
+ SECP256R1PublicKey(BCECPublicKey publicKey) {
+ super();
+ this.publicKey = publicKey;
+ }
+
+ static SECP256R1PublicKey loadSECP256R1(byte[] data) {
+ var params = ECNamedCurveTable.getParameterSpec(CURVE);
+ var spec = new ECPublicKeySpec(params.getCurve().decodePoint(data), params);
+ return new SECP256R1PublicKey(
+ new BCECPublicKey(SECP256R1KeyPair.ALGORITHM, spec, BouncyCastleProvider.CONFIGURATION));
+ }
+
+ @Override
+ public byte[] toBytes() {
+ return this.publicKey.getQ().getEncoded(true);
+ } // true : compressed
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ SECP256R1PublicKey publicKey = (SECP256R1PublicKey) o;
+
+ return Arrays.equals(this.toBytes(), publicKey.toBytes());
+ }
+
+ @Override
+ public int hashCode() {
+ return this.publicKey.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "secp256r1/" + toHex().toLowerCase();
+ }
+
+ public Algorithm getAlgorithm() {
+ return Algorithm.SECP256R1;
+ }
+
+ @Override
+ public boolean verify(byte[] data, byte[] signature)
+ throws InvalidKeyException, SignatureException, NoSuchAlgorithmException {
+ var sgr = getSignature();
+ sgr.initVerify(this.publicKey);
+ sgr.update(data);
+ return sgr.verify(signature);
+ }
+}
diff --git a/src/main/java/org/biscuitsec/biscuit/crypto/Token.java b/src/main/java/org/biscuitsec/biscuit/crypto/Token.java
index 63a2eb0b..093b2ef4 100644
--- a/src/main/java/org/biscuitsec/biscuit/crypto/Token.java
+++ b/src/main/java/org/biscuitsec/biscuit/crypto/Token.java
@@ -64,7 +64,7 @@ public Either verify(PublicKey root)
byte[] signature = this.signatures.get(i);
byte[] payload = BlockSignatureBuffer.getBufferSignature(nextKey, block);
- if (KeyPair.verify(currentKey, payload, signature)) {
+ if (currentKey.verify(payload, signature)) {
currentKey = nextKey;
} else {
return Left(
diff --git a/src/main/java/org/biscuitsec/biscuit/datalog/Combinator.java b/src/main/java/org/biscuitsec/biscuit/datalog/Combinator.java
index 7dc8f8e4..3fd25191 100644
--- a/src/main/java/org/biscuitsec/biscuit/datalog/Combinator.java
+++ b/src/main/java/org/biscuitsec/biscuit/datalog/Combinator.java
@@ -119,7 +119,10 @@ public Option>> getNext() {
// no need to copy all the expressions at all levels
this.currentIt =
new Combinator(
- vars, predicates.subList(1, predicates.size()), this.allFacts, this.symbolTable);
+ vars,
+ predicates.subList(1, predicates.size()),
+ this.allFacts,
+ this.symbolTable);
}
break;
diff --git a/src/main/java/org/biscuitsec/biscuit/datalog/MatchedVariables.java b/src/main/java/org/biscuitsec/biscuit/datalog/MatchedVariables.java
index 6f55d192..770cb952 100644
--- a/src/main/java/org/biscuitsec/biscuit/datalog/MatchedVariables.java
+++ b/src/main/java/org/biscuitsec/biscuit/datalog/MatchedVariables.java
@@ -64,8 +64,8 @@ public MatchedVariables(final Set ids) {
}
}
- public Option