Skip to content

Commit

Permalink
Merge pull request #93 from /issues/91
Browse files Browse the repository at this point in the history
Issues/91
  • Loading branch information
cnorburn authored Feb 4, 2022
2 parents 32a15a1 + 8e5b414 commit 85f4a43
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,26 @@ KeyPair generateKeyPair(final String algorithm, final String curve) {
public byte[] getPublicKeyRawBytes(final PublicKey publicKey) {
return TYPES_FACTORY.getInstance(CLType.PUBLIC_KEY).serialize(publicKey);
}

/**
* To be overridden by signatures that do not want DER ASN1 signatures.
*
* @param signed the signature bytes to convert
* @return the converted bytes
*/
@Override
public byte[] convertFromDER(final byte[] signed) {
return signed;
}

/**
* To be overridden by signatures that do not want DER ASN1 signatures.
*
* @param signed the signature bytes to convert
* @return the converted bytes
*/
@Override
public byte[] convertToDER(final byte[] signed) {
return signed;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,8 @@ public interface KeyPairBuilder {
* @return a new PublicKet created from the provided bytes
*/
PublicKey createPublicKey(final byte[] publicKey);

byte [] convertFromDER(final byte[] signed);

byte [] convertToDER(final byte[] signed);
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,8 @@ public KeyPairBuilder getKeyPairBuilderForPublicKey(final PublicKey publicKey) {

throw new SignatureException("Unsupported PublicKey " + publicKey);
}

public KeyPairBuilder getKeyPairBuilder(final String algorithm) {
return getKeyPairBuilder(Algorithm.fromString(algorithm));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@

import com.casper.sdk.exceptions.SignatureException;
import com.casper.sdk.types.Algorithm;
import org.bouncycastle.asn1.ASN1EncodableVector;
import org.bouncycastle.asn1.ASN1Integer;
import org.bouncycastle.asn1.ASN1Sequence;
import org.bouncycastle.asn1.DERSequence;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECParameterSpec;
import org.bouncycastle.jce.spec.ECPublicKeySpec;
import org.bouncycastle.math.ec.ECPoint;

import java.io.IOException;
import java.math.BigInteger;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.PublicKey;
import java.util.Arrays;

import static com.casper.sdk.service.signing.SigningService.PROVIDER;

Expand Down Expand Up @@ -48,4 +55,53 @@ public PublicKey createPublicKey(final byte[] publicKey) {
throw new SignatureException(e);
}
}

/**
* Converts an DER ASN.1 signature to a P1363 Signature
*
* @param asn1EncodedSignature the DER signature bytes
* @return the P1363 signature
*/
@Override
public byte[] convertFromDER(byte[] asn1EncodedSignature) {
final ASN1Sequence seq = ASN1Sequence.getInstance(asn1EncodedSignature);
final BigInteger r = ((ASN1Integer) seq.getObjectAt(0)).getValue();
final BigInteger s = ((ASN1Integer) seq.getObjectAt(1)).getValue();
int n = (r.bitLength() + 7) / 8;
// round up to the nearest even integer
//noinspection IntegerDivisionInFloatingPointContext
n = Math.round((n + 1) / 2) * 2;
final byte[] out = new byte[2 * n];
toFixed(r, out, 0, n);
toFixed(s, out, n, n);
return out;
}

/**
* Converts a P1363 encoded signature to a DER ASN1 signature
*
* @param p1363EncodedSignature the signature the convert
* @return a DER ASN.1 signature
*/
@Override
public byte[] convertToDER(byte[] p1363EncodedSignature) {
final int n = p1363EncodedSignature.length / 2;
final BigInteger r = new BigInteger(+1, Arrays.copyOfRange(p1363EncodedSignature, 0, n));
final BigInteger s = new BigInteger(+1, Arrays.copyOfRange(p1363EncodedSignature, n, n * 2));
final ASN1EncodableVector v = new ASN1EncodableVector();
v.add(new ASN1Integer(r));
v.add(new ASN1Integer(s));
try {
return new DERSequence(v).getEncoded();
} catch (IOException e) {
throw new SignatureException(e);
}
}

private void toFixed(BigInteger x, byte[] a, int off, int len) {
final byte[] t = x.toByteArray();
if (t.length == len + 1 && t[0] == 0) System.arraycopy(t, 1, a, off, len);
else if (t.length <= len) System.arraycopy(t, 0, a, off + len - t.length, t.length);
else throw new SignatureException("Invalid length");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ public byte[] signWithPrivateKey(final PrivateKey privateKey, final byte[] toSig
final Signature sig = Signature.getInstance(privateKey.getAlgorithm(), PROVIDER);
sig.initSign(privateKey);
sig.update(toSign);
return sig.sign();
return getKeyPairBuilder(privateKey.getAlgorithm()).convertFromDER(sig.sign());

} catch (Exception e) {
throw new SignatureException(e);
}
Expand Down Expand Up @@ -119,7 +120,7 @@ public boolean verifySignature(final PublicKey publicKey, final byte[] toSign, f
final Signature sig = Signature.getInstance(publicKey.getAlgorithm(), PROVIDER);
sig.initVerify(publicKey);
sig.update(toSign);
return sig.verify(signature);
return sig.verify(this.getKeyPairBuilder(publicKey.getAlgorithm()).convertToDER(signature));
} catch (Exception e) {
return false;
}
Expand Down Expand Up @@ -156,6 +157,10 @@ private KeyPairBuilder getKeyPairBuilder(final Algorithm algorithm) {
return keyPairFactory.getKeyPairBuilder(algorithm);
}

private KeyPairBuilder getKeyPairBuilder(final String algorithm) {
return keyPairFactory.getKeyPairBuilder(algorithm);
}

private KeyPairBuilder getKeyPairBuilderForPublicKey(final PublicKey publicKey) {
return keyPairFactory.getKeyPairBuilderForPublicKey(publicKey);
}
Expand Down
16 changes: 11 additions & 5 deletions src/main/java/com/casper/sdk/types/Algorithm.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import java.util.Map;

/**
* The emum of supported signature algorithms
* The enum of supported signature algorithms
*/
public enum Algorithm {

Expand All @@ -25,10 +25,6 @@ public enum Algorithm {
this.value = value;
}

public static Algorithm valueOf(int pageType) {
return map.get(pageType);
}

public static Algorithm fromId(char id) {
if (id == 1 || id == '1') {
return ED25519;
Expand All @@ -38,6 +34,16 @@ public static Algorithm fromId(char id) {
throw new IllegalArgumentException("Unknown algorithm ID " + id);
}

public static Algorithm fromString(final String algorithm) {
switch (algorithm) {
case "ECDSA":
return SECP256K1;
case "Ed25519":
return ED25519;
}
throw new IllegalArgumentException("Unknown algorithm " + algorithm);
}

public int getValue() {
return value;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.casper.sdk.service.signing;

import com.casper.sdk.service.serialization.util.ByteUtils;
import com.casper.sdk.types.CLPublicKey;
import com.casper.sdk.types.Algorithm;
import com.casper.sdk.types.CLPublicKey;
import org.apache.commons.io.IOUtils;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import org.bouncycastle.jcajce.provider.asymmetric.edec.BCEdDSAPublicKey;
Expand Down Expand Up @@ -57,6 +57,14 @@ void loadEd25519KeyPair() {
// Assert the message was signed
assertThat(signedBytes.length, is(64));

// Expect the same bytes for all incarnations
final byte[] deterministic = new byte[]{
40, 26, 91, -28, -20, 113, -70, -17, 105, -30, 12, 76, 39, -64, 75, 95, -21, -124, -61, -50, 74, -78,
100, -77, 90, -67, -55, 37, 10, 25, 119, -49, -54, -82, 59, 99, -33, -95, 75, 82, -4, -39, -31, 9, -34,
69, 18, -54, -36, -9, -53, -69, 54, 14, 117, -43, 35, -97, -101, 105, 100, 125, -10, 5
};
assertThat(signedBytes, is(deterministic));

// Verify the signature
assertThat(signingService.verifySignature(keyPair.getPublic(), message, signedBytes), is(true));

Expand Down Expand Up @@ -197,7 +205,7 @@ void saveED25519PublicPem() throws IOException {
@Test
void eD25519k1FromClPublicKey() {

final byte [] rawBytes = ByteUtils.decodeHex("01d30f6a241199e68217cb05abcefc7c8267c5226b8e644f1f8d0a79b87ed04f07");
final byte[] rawBytes = ByteUtils.decodeHex("01d30f6a241199e68217cb05abcefc7c8267c5226b8e644f1f8d0a79b87ed04f07");
final CLPublicKey clPublicKey = new CLPublicKey(rawBytes);
final java.security.PublicKey publicKey = signingService.fromClPublicKey(clPublicKey);

Expand All @@ -208,7 +216,7 @@ void eD25519k1FromClPublicKey() {
@Test
void secp256k1FromClPublicKey() {

final byte [] rawBytes = ByteUtils.decodeHex("02035793d9a677ec9cf0d3d2a7a61fb98c173c04b63925cfe387203b19d312fa37b0");
final byte[] rawBytes = ByteUtils.decodeHex("02035793d9a677ec9cf0d3d2a7a61fb98c173c04b63925cfe387203b19d312fa37b0");
final CLPublicKey clPublicKey = new CLPublicKey(rawBytes);
final java.security.PublicKey publicKey = signingService.fromClPublicKey(clPublicKey);

Expand Down

0 comments on commit 85f4a43

Please sign in to comment.