Skip to content

Remove ed-25519-java move to Bouncy Castle #118

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 5 additions & 10 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@
<vavr.version>0.10.3</vavr.version>
<re2j.version>1.6</re2j.version>
<gson.version>2.8.9</gson.version>
<bcprov.version>1.79</bcprov.version>
<bcprov.version>1.80</bcprov.version>

<!-- test dependencies -->
<junit.version>5.8.2</junit.version>
<awssdk-kms.version>2.30.2</awssdk-kms.version>
<testcontainers-junit-jupiter.version>1.20.4</testcontainers-junit-jupiter.version>
<testcontainers-localstack.version>1.20.4</testcontainers-localstack.version>
<testcontainers-junit-jupiter.version>1.20.6</testcontainers-junit-jupiter.version>
<testcontainers-localstack.version>1.20.6</testcontainers-localstack.version>
</properties>

<licenses>
Expand Down Expand Up @@ -221,7 +221,7 @@
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.2</version>
</plugin>
<plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<dependencies>
Expand All @@ -237,7 +237,7 @@
<disable>true</disable>
</consoleOutputReporter>
<statelessTestsetInfoReporter
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
implementation="org.apache.maven.plugin.surefire.extensions.junit5.JUnit5StatelessTestsetInfoTreeReporter">
<printStacktraceOnError>true</printStacktraceOnError>
<printStacktraceOnFailure>true</printStacktraceOnFailure>
<printStdoutOnError>true</printStdoutOnError>
Expand Down Expand Up @@ -281,11 +281,6 @@
<artifactId>protobuf-java</artifactId>
<version>${protobuf.version}</version>
</dependency>
<dependency>
<groupId>net.i2p.crypto</groupId>
<artifactId>eddsa</artifactId>
<version>${net.i2p.crypto.eddsa.version}</version>
</dependency>
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
Expand Down
81 changes: 26 additions & 55 deletions src/main/java/org/biscuitsec/biscuit/crypto/Ed25519KeyPair.java
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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);
}
}
60 changes: 60 additions & 0 deletions src/main/java/org/biscuitsec/biscuit/crypto/Ed25519PublicKey.java
Original file line number Diff line number Diff line change
@@ -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);
}
}
26 changes: 2 additions & 24 deletions src/main/java/org/biscuitsec/biscuit/crypto/KeyPair.java
Original file line number Diff line number Diff line change
@@ -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 {
Expand All @@ -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) {
Expand All @@ -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();
Expand Down
Loading