Skip to content

Commit 003adcd

Browse files
committed
Add new Tests and Test Vectors
* Fixes test vectors to accomadate (rfcs/crypto-conditions#4) * Adds improved test coverage for RFC test vectors.
1 parent c07ba6d commit 003adcd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1914
-285
lines changed

build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
group = 'org.interledger'
22
description = 'Java implementation of the Crypto-Conditions RFC found at https://datatracker.ietf.org/doc/draft-thomas-crypto-conditions/.'
3-
version = '0.2.1-SNAPSHOT'
3+
version = '0.3.0-SNAPSHOT'
44

55
apply plugin: 'java'
66
apply plugin: 'eclipse'
@@ -56,7 +56,7 @@ dependencies {
5656
testCompile 'com.fasterxml.jackson.core:jackson-databind:2.7.0'
5757
testCompile 'org.mockito:mockito-core:2.7.22'
5858
testCompile 'org.hamcrest:hamcrest-all:1.3'
59-
testCompile 'com.google.guava:guava:21.0'
59+
compile 'com.google.guava:guava:21.0'
6060
}
6161

6262
if (project.hasProperty('sign')) {

pom.xml

+6-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<modelVersion>4.0.0</modelVersion>
55
<groupId>org.interledger</groupId>
66
<artifactId>java-crypto-conditions</artifactId>
7-
<version>0.2.1-SNAPSHOT</version>
7+
<version>0.3.0-SNAPSHOT</version>
88
<name>Crypto Conditions (Java)</name>
99
<description>Java implementation of the Crypto-Conditions RFC.</description>
1010
<url>http://github.com/interledger/java-crypto-conditions</url>
@@ -89,6 +89,11 @@
8989
<version>21.0</version>
9090
<scope>test</scope>
9191
</dependency>
92+
<dependency>
93+
<groupId>com.google.guava</groupId>
94+
<artifactId>guava</artifactId>
95+
<version>21.0</version>
96+
</dependency>
9297
</dependencies>
9398
<reporting>
9499
<plugins>

src/main/java/org/interledger/cryptoconditions/Sha256Condition.java

+7
Original file line numberDiff line numberDiff line change
@@ -66,4 +66,11 @@ private byte[] getDigest(byte[] input) {
6666
return messageDigest.digest(input);
6767
}
6868

69+
@Override
70+
public String toString() {
71+
final StringBuilder sb = new StringBuilder("Sha256Condition{");
72+
sb.append("uri=").append(getUri());
73+
sb.append('}');
74+
return sb.toString();
75+
}
6976
}

src/main/java/org/interledger/cryptoconditions/der/CryptoConditionReader.java

+16-13
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class CryptoConditionReader {
4343

4444
/**
4545
* Reads a DER encoded condition from the buffer.
46-
*
46+
*
4747
* @param buffer contains the raw DER encoded condition.
4848
* @return The condition read from the buffer.
4949
*/
@@ -53,7 +53,7 @@ public static Condition readCondition(byte[] buffer) throws DerEncodingException
5353

5454
/**
5555
* Reads a DER encoded condition from the buffer.
56-
*
56+
*
5757
* @param buffer contains the raw DER encoded condition.
5858
* @param offset the position within the buffer to begin reading the condition.
5959
* @param length the number of bytes to read.
@@ -80,7 +80,7 @@ public static Condition readCondition(byte[] buffer, int offset, int length)
8080

8181
/**
8282
* Reads a DER encoded condition from the input stream.
83-
*
83+
*
8484
* @param in The input stream containing the DER encoded condition.
8585
* @return The condition read from the stream.
8686
*/
@@ -108,7 +108,7 @@ public static Condition readCondition(DerInputStream in, AtomicInteger bytesRead
108108
in.readTaggedObject(0, length - innerBytesRead.get(), innerBytesRead).getValue();
109109
long cost = new BigInteger(
110110
in.readTaggedObject(1, length - innerBytesRead.get(), innerBytesRead).getValue())
111-
.longValue();
111+
.longValue();
112112
EnumSet<ConditionType> subtypes = null;
113113
if (type == ConditionType.PREFIX_SHA256 || type == ConditionType.THRESHOLD_SHA256) {
114114
subtypes = ConditionType.getEnumOfTypesFromBitString(
@@ -268,27 +268,30 @@ public static Fulfillment readFulfillment(DerInputStream in, AtomicInteger bytes
268268

269269
case RSA_SHA256:
270270

271-
BigInteger modulus = UnsignedBigInteger.fromUnsignedByteArray(
272-
in.readTaggedObject(0, length - innerBytesRead.get(), innerBytesRead).getValue());
273-
byte[] rsaSignature =
274-
in.readTaggedObject(1, length - innerBytesRead.get(), innerBytesRead).getValue();
271+
final BigInteger modulus = UnsignedBigInteger.fromUnsignedByteArray(
272+
in.readTaggedObject(0, length - innerBytesRead.get(), innerBytesRead).getValue()
273+
);
274+
275+
final byte[] rsaSignature = in.readTaggedObject(
276+
1, length - innerBytesRead.get(), innerBytesRead
277+
).getValue();
275278

276279
bytesRead.addAndGet(innerBytesRead.get());
277280

278-
RSAPublicKeySpec rsaSpec =
279-
new RSAPublicKeySpec(modulus, RsaSha256Fulfillment.PUBLIC_EXPONENT);
281+
final RSAPublicKeySpec rsaSpec = new RSAPublicKeySpec(
282+
modulus, RsaSha256Fulfillment.PUBLIC_EXPONENT
283+
);
280284

281285
try {
282-
KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA");
283-
PublicKey publicKey = rsaKeyFactory.generatePublic(rsaSpec);
286+
final KeyFactory rsaKeyFactory = KeyFactory.getInstance("RSA");
287+
final PublicKey publicKey = rsaKeyFactory.generatePublic(rsaSpec);
284288

285289
return new RsaSha256Fulfillment((RSAPublicKey) publicKey, rsaSignature);
286290

287291
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
288292
throw new RuntimeException("Error creating RSA key.", e);
289293
}
290294

291-
292295
case ED25519_SHA256:
293296
byte[] ed25519key =
294297
in.readTaggedObject(0, length - innerBytesRead.get(), innerBytesRead).getValue();

src/main/java/org/interledger/cryptoconditions/types/Ed25519Sha256Fulfillment.java

+57-11
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,5 @@
11
package org.interledger.cryptoconditions.types;
22

3-
import net.i2p.crypto.eddsa.EdDSAEngine;
4-
import net.i2p.crypto.eddsa.EdDSAPublicKey;
5-
6-
import org.interledger.cryptoconditions.Condition;
7-
import org.interledger.cryptoconditions.ConditionType;
8-
import org.interledger.cryptoconditions.Fulfillment;
9-
import org.interledger.cryptoconditions.der.DerOutputStream;
10-
113
import java.io.ByteArrayOutputStream;
124
import java.io.IOException;
135
import java.io.UncheckedIOException;
@@ -16,6 +8,13 @@
168
import java.security.NoSuchAlgorithmException;
179
import java.security.Signature;
1810
import java.security.SignatureException;
11+
import java.util.Arrays;
12+
import net.i2p.crypto.eddsa.EdDSAEngine;
13+
import net.i2p.crypto.eddsa.EdDSAPublicKey;
14+
import org.interledger.cryptoconditions.Condition;
15+
import org.interledger.cryptoconditions.ConditionType;
16+
import org.interledger.cryptoconditions.Fulfillment;
17+
import org.interledger.cryptoconditions.der.DerOutputStream;
1918

2019

2120
/**
@@ -29,9 +28,9 @@ public class Ed25519Sha256Fulfillment implements Fulfillment {
2928

3029
/**
3130
* Constructs an instance of the fulfillment.
32-
*
33-
* @param publicKey The public key associated with the condition and fulfillment.
34-
* @param signature The signature associated with the fulfillment.
31+
*
32+
* @param publicKey The public key associated with the condition and fulfillment.
33+
* @param signature The signature associated with the fulfillment.
3534
*/
3635
public Ed25519Sha256Fulfillment(EdDSAPublicKey publicKey, byte[] signature) {
3736
this.signature = new byte[signature.length];
@@ -138,4 +137,51 @@ private static MessageDigest getSha512Digest() {
138137

139138
return _DIGEST;
140139
}
140+
141+
/**
142+
* The {@link #condition} field in this class is not part of this equals method because it is a
143+
* value derived from this fulfillment, and is lazily initialized (so it's occasionally null until
144+
* {@link #getCondition()} is called.
145+
*/
146+
@Override
147+
public boolean equals(Object o) {
148+
if (this == o) {
149+
return true;
150+
}
151+
if (o == null || getClass() != o.getClass()) {
152+
return false;
153+
}
154+
155+
Ed25519Sha256Fulfillment that = (Ed25519Sha256Fulfillment) o;
156+
157+
if (!publicKey.equals(that.publicKey)) {
158+
return false;
159+
}
160+
return Arrays.equals(signature, that.signature);
161+
}
162+
163+
@Override
164+
public int hashCode() {
165+
int result = publicKey.hashCode();
166+
result = 31 * result + Arrays.hashCode(signature);
167+
return result;
168+
}
169+
170+
// @Override
171+
// public String toString() {
172+
// final StringBuilder sb = new StringBuilder("Ed25519Sha256Fulfillment{");
173+
// sb.append("type=").append(getType());
174+
// sb.append('}');
175+
// return sb.toString();
176+
// }
177+
178+
@Override
179+
public String toString() {
180+
final StringBuilder sb = new StringBuilder("Ed25519Sha256Fulfillment{");
181+
sb.append("publicKey=").append(publicKey);
182+
sb.append(", signature=").append(Arrays.toString(signature));
183+
sb.append(", type=").append(getType());
184+
sb.append('}');
185+
return sb.toString();
186+
}
141187
}

src/main/java/org/interledger/cryptoconditions/types/PrefixSha256Fulfillment.java

+57-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
package org.interledger.cryptoconditions.types;
22

3-
import org.interledger.cryptoconditions.Condition;
4-
import org.interledger.cryptoconditions.ConditionType;
5-
import org.interledger.cryptoconditions.Fulfillment;
6-
import org.interledger.cryptoconditions.der.DerOutputStream;
7-
83
import java.io.ByteArrayOutputStream;
94
import java.io.IOException;
105
import java.io.UncheckedIOException;
116
import java.math.BigInteger;
127
import java.util.Arrays;
8+
import java.util.Objects;
9+
import org.interledger.cryptoconditions.Condition;
10+
import org.interledger.cryptoconditions.ConditionType;
11+
import org.interledger.cryptoconditions.Fulfillment;
12+
import org.interledger.cryptoconditions.der.DerOutputStream;
1313

1414
/**
1515
* Implementation of a fulfillment based on a prefix, a sub fulfillment, and the SHA-256 function.
@@ -24,10 +24,10 @@ public class PrefixSha256Fulfillment implements Fulfillment {
2424

2525
/**
2626
* Constructs an instance of the fulfillment.
27-
*
28-
* @param prefix The prefix associated with the condition and fulfillment
27+
*
28+
* @param prefix The prefix associated with the condition and fulfillment
2929
* @param maxMessageLength The maximum length of a message.
30-
* @param subfulfillment The sub fulfillments that this fulfillment depends on.
30+
* @param subfulfillment The sub fulfillments that this fulfillment depends on.
3131
*/
3232
public PrefixSha256Fulfillment(byte[] prefix, long maxMessageLength, Fulfillment subfulfillment) {
3333
this.prefix = new byte[prefix.length];
@@ -102,12 +102,9 @@ public PrefixSha256Condition getCondition() {
102102
}
103103

104104
@Override
105-
public boolean verify(Condition condition, byte[] message) {
106-
107-
if (condition == null) {
108-
throw new IllegalArgumentException(
109-
"Can't verify a PrefixSha256Fulfillment against an null condition.");
110-
}
105+
public boolean verify(final Condition condition, final byte[] message) {
106+
Objects.requireNonNull(condition,
107+
"Can't verify a PrefixSha256Fulfillment against a null condition!");
111108

112109
if (!(condition instanceof PrefixSha256Condition)) {
113110
throw new IllegalArgumentException(
@@ -116,7 +113,9 @@ public boolean verify(Condition condition, byte[] message) {
116113

117114
if (message.length > maxMessageLength) {
118115
throw new IllegalArgumentException(
119-
"Message length exceeds maximum message length of " + maxMessageLength + ".");
116+
String
117+
.format("Message length (%s) exceeds maximum message length of (%s).", message.length,
118+
maxMessageLength));
120119
}
121120

122121
if (!getCondition().equals(condition)) {
@@ -130,4 +129,47 @@ public boolean verify(Condition condition, byte[] message) {
130129
return subfulfillment.verify(subcondition, prefixedMessage);
131130
}
132131

132+
/**
133+
* The {@link #condition} field in this class is not part of this equals method because it is a
134+
* value derived from this fulfillment, and is lazily initialized (so it's occasionally null until
135+
* {@link #getCondition()} is called.
136+
*/
137+
@Override
138+
public boolean equals(Object o) {
139+
if (this == o) {
140+
return true;
141+
}
142+
if (o == null || getClass() != o.getClass()) {
143+
return false;
144+
}
145+
146+
PrefixSha256Fulfillment that = (PrefixSha256Fulfillment) o;
147+
148+
if (maxMessageLength != that.maxMessageLength) {
149+
return false;
150+
}
151+
if (subfulfillment != null ? !subfulfillment.equals(that.subfulfillment)
152+
: that.subfulfillment != null) {
153+
return false;
154+
}
155+
return Arrays.equals(prefix, that.prefix);
156+
}
157+
158+
@Override
159+
public int hashCode() {
160+
int result = subfulfillment != null ? subfulfillment.hashCode() : 0;
161+
result = 31 * result + (int) (maxMessageLength ^ (maxMessageLength >>> 32));
162+
result = 31 * result + Arrays.hashCode(prefix);
163+
return result;
164+
}
165+
166+
@Override
167+
public String toString() {
168+
final StringBuilder sb = new StringBuilder("PrefixSha256Fulfillment{");
169+
sb.append("maxMessageLength=").append(maxMessageLength);
170+
sb.append(", prefix=").append(Arrays.toString(prefix));
171+
sb.append(", type=").append(getType());
172+
sb.append('}');
173+
return sb.toString();
174+
}
133175
}

src/main/java/org/interledger/cryptoconditions/types/PreimageSha256Fulfillment.java

+36-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.interledger.cryptoconditions.types;
22

3+
import java.util.Arrays;
34
import org.interledger.cryptoconditions.Condition;
45
import org.interledger.cryptoconditions.ConditionType;
56
import org.interledger.cryptoconditions.Fulfillment;
@@ -23,8 +24,10 @@ public class PreimageSha256Fulfillment implements Fulfillment {
2324
* @param preimage The preimage associated with the fulfillment.
2425
*/
2526
public PreimageSha256Fulfillment(byte[] preimage) {
26-
this.preimage = new byte[preimage.length];
27-
System.arraycopy(preimage, 0, this.preimage, 0, preimage.length);
27+
28+
this.preimage = Arrays.copyOf(preimage, preimage.length);
29+
// this.preimage = new byte[preimage.length];
30+
// System.arraycopy(preimage, 0, this.preimage, 0, preimage.length);
2831
}
2932

3033
@Override
@@ -88,4 +91,35 @@ public boolean verify(Condition condition, byte[] message) {
8891
return getCondition().equals(condition);
8992
}
9093

94+
/**
95+
* The {@link #condition} field in this class is not part of this equals method because it is a
96+
* value derived from this fulfillment, and is lazily initialized (so it's occasionally null until
97+
* {@link #getCondition()} is called.
98+
*/
99+
@Override
100+
public boolean equals(Object o) {
101+
if (this == o) {
102+
return true;
103+
}
104+
if (o == null || getClass() != o.getClass()) {
105+
return false;
106+
}
107+
108+
PreimageSha256Fulfillment that = (PreimageSha256Fulfillment) o;
109+
110+
return Arrays.equals(preimage, that.preimage);
111+
}
112+
113+
@Override
114+
public int hashCode() {
115+
return Arrays.hashCode(preimage);
116+
}
117+
118+
@Override
119+
public String toString() {
120+
final StringBuilder sb = new StringBuilder("PreimageSha256Fulfillment{");
121+
sb.append("type=").append(getType());
122+
sb.append('}');
123+
return sb.toString();
124+
}
91125
}

0 commit comments

Comments
 (0)