Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
24 changes: 23 additions & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,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>

<!-- 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>
</properties>

<licenses>
Expand Down Expand Up @@ -259,13 +263,31 @@
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk18on</artifactId>
<version>1.79</version>
<version>${bcprov.version}</version>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>kms</artifactId>
<version>${awssdk-kms.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<version>${testcontainers-junit-jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>localstack</artifactId>
<version>${testcontainers-localstack.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package org.biscuitsec.biscuit.crypto;

import org.biscuitsec.biscuit.token.format.ExternalSignature;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Optional;

public class BlockSignatureBuffer {
public static byte[] getBufferSignature(PublicKey nextPubKey, byte[] data) {
return getBufferSignature(nextPubKey, data, Optional.empty());
}

public static byte[] getBufferSignature(PublicKey nextPubKey, byte[] data, Optional<ExternalSignature> externalSignature) {
var buffer = ByteBuffer.allocate(4 + data.length + nextPubKey.toBytes().length + externalSignature.map((a) -> a.signature.length).orElse(0)).order(ByteOrder.LITTLE_ENDIAN);
buffer.put(data);
externalSignature.ifPresent(signature -> buffer.put(signature.signature));
buffer.putInt(nextPubKey.algorithm.getNumber());
buffer.put(nextPubKey.toBytes());
buffer.flip();
return buffer.array();
}

public static byte[] getBufferSealedSignature(PublicKey nextPubKey, byte[] data, byte[] blockSignature) {
var buffer = ByteBuffer.allocate(4 + data.length + nextPubKey.toBytes().length + blockSignature.length).order(ByteOrder.LITTLE_ENDIAN);
buffer.put(data);
buffer.putInt(nextPubKey.algorithm.getNumber());
buffer.put(nextPubKey.toBytes());
buffer.put(blockSignature);
buffer.flip();
return buffer.array();
}
}
22 changes: 11 additions & 11 deletions src/main/java/org/biscuitsec/biscuit/crypto/Ed25519KeyPair.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,12 @@
import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec;
import org.biscuitsec.biscuit.token.builder.Utils;

import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;

final class Ed25519KeyPair extends KeyPair {

Expand Down Expand Up @@ -62,6 +63,14 @@ public static Signature getSignature() throws NoSuchAlgorithmException {
return new EdDSAEngine(MessageDigest.getInstance(ed25519.getHashAlgorithm()));
}

@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();
}

@Override
public byte[] toBytes() {
return privateKey.getSeed();
Expand All @@ -72,18 +81,9 @@ public String toHex() {
return Utils.byteArrayToHexString(toBytes());
}

@Override
public java.security.PublicKey publicKey() {
return publicKey;
}

@Override
public PrivateKey private_key() {
return privateKey;
}

@Override
public PublicKey public_key() {
return new PublicKey(Schema.PublicKey.Algorithm.Ed25519, this.publicKey);
}

}
16 changes: 11 additions & 5 deletions src/main/java/org/biscuitsec/biscuit/crypto/KeyPair.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
import biscuit.format.schema.Schema.PublicKey.Algorithm;
import net.i2p.crypto.eddsa.Utils;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Signature;
import java.security.SignatureException;

/**
* Private and public key.
*/
public abstract class KeyPair {
public abstract class KeyPair implements Signer {

public static KeyPair generate(Algorithm algorithm) {
return generate(algorithm, new SecureRandom());
Expand Down Expand Up @@ -51,13 +53,17 @@ public static Signature generateSignature(Algorithm algorithm) throws NoSuchAlgo
}
}

public static boolean verify(PublicKey publicKey, byte[] data, byte[] signature) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sgr = KeyPair.generateSignature(publicKey.algorithm);
sgr.initVerify(publicKey.key);
sgr.update(data);
return sgr.verify(signature);
}

public abstract byte[] toBytes();

public abstract String toHex();

public abstract java.security.PublicKey publicKey();

public abstract java.security.PrivateKey private_key();

@Override
public abstract PublicKey public_key();
}
22 changes: 11 additions & 11 deletions src/main/java/org/biscuitsec/biscuit/crypto/SECP256R1KeyPair.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.util.BigIntegers;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;

final class SECP256R1KeyPair extends KeyPair {

Expand Down Expand Up @@ -72,6 +73,14 @@ public 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);
sgr.initSign(privateKey);
sgr.update(data);
return sgr.sign();
}

@Override
public byte[] toBytes() {
return BigIntegers.asUnsignedByteArray(privateKey.getD());
Expand All @@ -82,18 +91,9 @@ public String toHex() {
return Utils.byteArrayToHexString(toBytes());
}

@Override
public java.security.PublicKey publicKey() {
return publicKey;
}

@Override
public PrivateKey private_key() {
return privateKey;
}

@Override
public PublicKey public_key() {
return new PublicKey(Schema.PublicKey.Algorithm.SECP256R1, publicKey);
}

}
29 changes: 29 additions & 0 deletions src/main/java/org/biscuitsec/biscuit/crypto/Signer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.biscuitsec.biscuit.crypto;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;

/**
* Interface to enable the cryptographic signature of payload.
* It can be adapted depending of the needs
*/
public interface Signer {
/**
* Sign the payload with the signer key
*
* @param payload
* @return the signature of payload by
* @throws NoSuchAlgorithmException
* @throws InvalidKeyException
* @throws SignatureException
*/
public byte[] sign(byte[] payload) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException;

/**
* Return the public key of the signer and the associated algorithm
*
* @return
*/
public PublicKey public_key();
}
46 changes: 12 additions & 34 deletions src/main/java/org/biscuitsec/biscuit/crypto/Token.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
import org.biscuitsec.biscuit.error.Error;
import io.vavr.control.Either;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.security.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.ArrayList;

import static io.vavr.API.Left;
Expand All @@ -17,17 +17,11 @@ class Token {
public final ArrayList<byte[]> signatures;
public final KeyPair next;

public Token(KeyPair rootKeyPair, byte[] message, KeyPair next) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
Signature sgr = KeyPair.generateSignature(next.public_key().algorithm);
ByteBuffer algo_buf = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
algo_buf.putInt(Integer.valueOf(next.public_key().algorithm.getNumber()));
algo_buf.flip();
sgr.initSign(rootKeyPair.private_key());
sgr.update(message);
sgr.update(algo_buf);
sgr.update(next.public_key().toBytes());
public Token(final Signer rootSigner, byte[] message, KeyPair next) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {

byte[] signature = sgr.sign();
byte[] payload = BlockSignatureBuffer.getBufferSignature(next.public_key(), message);

byte[] signature = rootSigner.sign(payload);

this.blocks = new ArrayList<>();
this.blocks.add(message);
Expand All @@ -47,16 +41,8 @@ public Token(final ArrayList<byte[]> blocks, final ArrayList<PublicKey> keys, fi
}

public Token append(KeyPair keyPair, byte[] message) throws NoSuchAlgorithmException, SignatureException, InvalidKeyException {
Signature sgr = KeyPair.generateSignature(next.public_key().algorithm);
sgr.initSign(this.next.private_key());
ByteBuffer algo_buf = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
algo_buf.putInt(Integer.valueOf(next.public_key().algorithm.getNumber()));
algo_buf.flip();
sgr.update(message);
sgr.update(algo_buf);
sgr.update(keyPair.public_key().toBytes());

byte[] signature = sgr.sign();
byte[] payload = BlockSignatureBuffer.getBufferSignature(keyPair.public_key(), message);
byte[] signature = this.next.sign(payload);

Token token = new Token(this.blocks, this.keys, this.signatures, keyPair);
token.blocks.add(message);
Expand All @@ -74,23 +60,15 @@ public Either<Error, Void> verify(PublicKey root) throws NoSuchAlgorithmExceptio
PublicKey next_key = this.keys.get(i);
byte[] signature = this.signatures.get(i);

ByteBuffer algo_buf = ByteBuffer.allocate(4).order(ByteOrder.LITTLE_ENDIAN);
algo_buf.putInt(Integer.valueOf(next.public_key().algorithm.getNumber()));
algo_buf.flip();
Signature sgr = KeyPair.generateSignature(next.public_key().algorithm);
sgr.initVerify(current_key.key);
sgr.update(block);
sgr.update(algo_buf);
sgr.update(next_key.toBytes());

if (sgr.verify(signature)) {
byte[] payload = BlockSignatureBuffer.getBufferSignature(next_key, block);
if (KeyPair.verify(current_key, payload, signature)) {
current_key = next_key;
} else {
return Left(new Error.FormatError.Signature.InvalidSignature("signature error: Verification equation was not satisfied"));
}
}

if(this.next.publicKey() == current_key.key) {
if (this.next.public_key().equals(current_key)) {
return Right(null);
} else {
return Left(new Error.FormatError.Signature.InvalidSignature("signature error: Verification equation was not satisfied"));
Expand Down
15 changes: 7 additions & 8 deletions src/main/java/org/biscuitsec/biscuit/token/Biscuit.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.biscuitsec.biscuit.token;

import biscuit.format.schema.Schema;
import biscuit.format.schema.Schema.PublicKey.Algorithm;
import org.biscuitsec.biscuit.crypto.KeyDelegate;
import org.biscuitsec.biscuit.crypto.KeyPair;
Expand All @@ -27,7 +26,7 @@ public class Biscuit extends UnverifiedBiscuit {
* @param root root private key
* @return
*/
public static org.biscuitsec.biscuit.token.builder.Biscuit builder(final KeyPair root) {
public static org.biscuitsec.biscuit.token.builder.Biscuit builder(final org.biscuitsec.biscuit.crypto.Signer root) {
return new org.biscuitsec.biscuit.token.builder.Biscuit(new SecureRandom(), root);
}

Expand All @@ -47,11 +46,11 @@ public static org.biscuitsec.biscuit.token.builder.Biscuit builder(final SecureR
/**
* Creates a token builder
*
* @param rng random number generator
* @param root root private key
* @param rng random number generator
* @param root root private key
* @return
*/
public static org.biscuitsec.biscuit.token.builder.Biscuit builder(final SecureRandom rng, final KeyPair root, final Option<Integer> root_key_id) {
public static org.biscuitsec.biscuit.token.builder.Biscuit builder(final SecureRandom rng, final org.biscuitsec.biscuit.crypto.Signer root, final Option<Integer> root_key_id) {
return new org.biscuitsec.biscuit.token.builder.Biscuit(rng, root, root_key_id);
}

Expand All @@ -63,7 +62,7 @@ public static org.biscuitsec.biscuit.token.builder.Biscuit builder(final SecureR
* @param authority authority block
* @return Biscuit
*/
public static Biscuit make(final SecureRandom rng, final KeyPair root, final Block authority) throws Error.FormatError {
public static Biscuit make(final SecureRandom rng, final org.biscuitsec.biscuit.crypto.Signer root, final Block authority) throws Error.FormatError {
return Biscuit.make(rng, root, Option.none(), authority);
}

Expand All @@ -75,7 +74,7 @@ public static Biscuit make(final SecureRandom rng, final KeyPair root, final Blo
* @param authority authority block
* @return Biscuit
*/
public static Biscuit make(final SecureRandom rng, final KeyPair root, final Integer root_key_id, final Block authority) throws Error.FormatError {
public static Biscuit make(final SecureRandom rng, final org.biscuitsec.biscuit.crypto.Signer root, final Integer root_key_id, final Block authority) throws Error.FormatError {
return Biscuit.make(rng, root, Option.of(root_key_id), authority);
}

Expand All @@ -87,7 +86,7 @@ public static Biscuit make(final SecureRandom rng, final KeyPair root, final Int
* @param authority authority block
* @return Biscuit
*/
static private Biscuit make(final SecureRandom rng, final KeyPair root, final Option<Integer> root_key_id, final Block authority) throws Error.FormatError {
static private Biscuit make(final SecureRandom rng, final org.biscuitsec.biscuit.crypto.Signer root, final Option<Integer> root_key_id, final Block authority) throws Error.FormatError {
ArrayList<Block> blocks = new ArrayList<>();

KeyPair next = KeyPair.generate(root.public_key().algorithm, rng);
Expand Down
Loading