Skip to content

Commit c0c7066

Browse files
authored
fix: PasetoPublicTest fails when running (say 1000) times with - The … (#96)
The ASN split can also be less than 48, so we need to add padding in front of it. Instead of writing code to change a BigInteger to a byte array we now use the BC utility method. Closes gh-95
1 parent b35f2d9 commit c0c7066

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

version3/src/main/java/org/paseto4j/version3/CryptoFunctions.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
import java.security.PublicKey;
3535
import java.security.SecureRandom;
3636
import java.security.Signature;
37-
import java.util.Arrays;
3837
import javax.crypto.Cipher;
3938
import javax.crypto.Mac;
4039
import javax.crypto.SecretKey;
@@ -48,6 +47,7 @@
4847
import org.bouncycastle.crypto.generators.HKDFBytesGenerator;
4948
import org.bouncycastle.crypto.params.HKDFParameters;
5049
import org.bouncycastle.jce.provider.BouncyCastleProvider;
50+
import org.bouncycastle.util.BigIntegers;
5151
import org.paseto4j.commons.ByteUtils;
5252
import org.paseto4j.commons.Pair;
5353

@@ -141,12 +141,14 @@ public static byte[] hkdfSha384(byte[] key, byte[] info) {
141141
return out;
142142
}
143143

144-
public static byte[] toUnsignedByteArray(BigInteger value) {
145-
byte[] signedValue = value.toByteArray();
146-
if (signedValue[0] != 0x00) {
147-
return signedValue;
144+
private static byte[] toUnsignedByteArray(BigInteger n, int length) {
145+
byte[] bs = BigIntegers.asUnsignedByteArray(n);
146+
if (bs.length < length) {
147+
byte[] tmp = new byte[length];
148+
System.arraycopy(bs, 0, tmp, length - bs.length, bs.length);
149+
bs = tmp;
148150
}
149-
return Arrays.copyOfRange(signedValue, 1, signedValue.length);
151+
return bs;
150152
}
151153

152154
public static byte[] sign(PrivateKey privateKey, byte[] msg) {
@@ -162,7 +164,8 @@ public static byte[] sign(PrivateKey privateKey, byte[] msg) {
162164
ASN1Integer r = (ASN1Integer) seq.getObjectAt(0);
163165
ASN1Integer s = (ASN1Integer) seq.getObjectAt(1);
164166

165-
return ByteUtils.concat(toUnsignedByteArray(r.getValue()), toUnsignedByteArray(s.getValue()));
167+
return ByteUtils.concat(
168+
toUnsignedByteArray(r.getValue(), 48), toUnsignedByteArray(s.getValue(), 48));
166169

167170
} catch (GeneralSecurityException e) {
168171
throw new IllegalStateException(e);

version3/src/test/java/org/paseto4j/version3/PasetoPublicTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import java.io.IOException;
3232
import java.io.Reader;
3333
import java.io.StringReader;
34+
import java.io.StringWriter;
3435
import java.security.InvalidAlgorithmParameterException;
3536
import java.security.KeyPair;
3637
import java.security.KeyPairGenerator;
@@ -40,9 +41,14 @@
4041
import java.security.SignatureException;
4142
import java.security.spec.ECGenParameterSpec;
4243
import java.util.stream.Stream;
44+
import org.bouncycastle.asn1.ASN1Object;
45+
import org.bouncycastle.asn1.ASN1Sequence;
46+
import org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
4347
import org.bouncycastle.jce.provider.BouncyCastleProvider;
4448
import org.bouncycastle.openssl.PEMParser;
4549
import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter;
50+
import org.bouncycastle.util.io.pem.PemObject;
51+
import org.bouncycastle.util.io.pem.PemWriter;
4652
import org.junit.jupiter.api.Assertions;
4753
import org.junit.jupiter.api.Test;
4854
import org.junit.jupiter.params.ParameterizedTest;
@@ -65,6 +71,17 @@ public static KeyPair readEC(String pem) throws IOException {
6571
return new JcaPEMKeyConverter().getKeyPair((org.bouncycastle.openssl.PEMKeyPair) parsed);
6672
}
6773

74+
public static String writeToPEM(java.security.PrivateKey privateKey) throws IOException {
75+
var writer = new StringWriter();
76+
try (var pemWriter = new PemWriter(writer)) {
77+
var pki = PrivateKeyInfo.getInstance(ASN1Sequence.getInstance(privateKey.getEncoded()));
78+
ASN1Object asn = (ASN1Object) pki.parsePrivateKey();
79+
pemWriter.writeObject(new PemObject("EC PRIVATE KEY", asn.getEncoded("DER")));
80+
pemWriter.flush();
81+
return writer.toString();
82+
}
83+
}
84+
6885
@ParameterizedTest
6986
@MethodSource("testVectors")
7087
void signTestVectors(
@@ -111,8 +128,22 @@ void normalUsage()
111128
generator.initialize(spec);
112129
var expectedPayload = "test message";
113130
var keyPair = generator.generateKeyPair();
131+
114132
var signedMessage = Paseto.sign(new PrivateKey(keyPair.getPrivate(), V3), expectedPayload);
133+
var payload =
134+
Paseto.parse(new org.paseto4j.commons.PublicKey(keyPair.getPublic(), V3), signedMessage);
115135

136+
Assertions.assertEquals(expectedPayload, payload);
137+
}
138+
139+
@Test
140+
void signingWhereASNPartsShouldBePadded() throws IOException, SignatureException {
141+
var pem =
142+
"-----BEGIN EC PRIVATE KEY-----\nMIGkAgEBBDBKvAg41dsJ64e+CY5Ona1PdhkHtDXZawacdj4fcUQVqR2hy19NML7S\nWpHchEsBzCegBwYFK4EEACKhZANiAARnuVQrWJkAJ7tBA9HkSvgpyn6haQQHZ4a2\nKqJwZ6LwVujOpP4gOPaIrL0fGDR2zQSZMaggHfYemqordD9nq9oPzBwVI+KZ8Rnq\nl35zsijbS3D6g5tN1cfcxtmB9c/2KVs=\n-----END EC PRIVATE KEY-----";
143+
var keyPair = readEC(pem);
144+
var expectedPayload = "test message";
145+
146+
var signedMessage = Paseto.sign(new PrivateKey(keyPair.getPrivate(), V3), expectedPayload);
116147
var payload =
117148
Paseto.parse(new org.paseto4j.commons.PublicKey(keyPair.getPublic(), V3), signedMessage);
118149

0 commit comments

Comments
 (0)