diff --git a/checkstyle.xml b/checkstyle.xml new file mode 100644 index 0000000..8d66889 --- /dev/null +++ b/checkstyle.xml @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/pom.xml b/pom.xml index 689648c..1c4df94 100644 --- a/pom.xml +++ b/pom.xml @@ -54,6 +54,27 @@ 1.8 + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.0.0 + + + validate + validate + + checkstyle.xml + UTF-8 + true + true + false + + + check + + + + diff --git a/wse-common/pom.xml b/wse-common/pom.xml index d379164..47d68f3 100644 --- a/wse-common/pom.xml +++ b/wse-common/pom.xml @@ -11,4 +11,22 @@ wse-common WSE common utilities + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.20.1 + + + + integration-test + verify + + + + + + diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltPubEphVal.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltPubEphVal.java new file mode 100644 index 0000000..2907702 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltPubEphVal.java @@ -0,0 +1,52 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.math.BigInteger; + +import com.github.glusk2.wse.common.util.Mapping; + +public final class SRP6CltPubEphVal implements SRP6Integer { + + private final SRP6Integer srp6_N; + private final SRP6Integer srp6_g; + private final SRP6Integer srp6_a; + private final Mapping rule; + + private SRP6Integer A; + + public SRP6CltPubEphVal( + SRP6Integer N, + SRP6Integer g, + SRP6Integer a, + Mapping rule + ) { + this.srp6_N = N; + this.srp6_g = g; + this.srp6_a = a; + this.rule = rule; + } + + private SRP6Integer compute_A() { + BigInteger N = srp6_N.bigInteger(); + BigInteger g = srp6_g.bigInteger(); + BigInteger a = srp6_a.bigInteger(); + + //A = g^a + return rule.map(g.modPow(a, N)); + } + + @Override + public byte[] bytes() { + if (A == null) { + A = compute_A(); + } + return A.bytes(); + } + + @Override + public BigInteger bigInteger() { + if (A == null) { + A = compute_A(); + } + return A.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltSesKey.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltSesKey.java new file mode 100644 index 0000000..abdb137 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltSesKey.java @@ -0,0 +1,91 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.math.BigInteger; + +import com.github.glusk2.wse.common.util.Mapping; + +public final class SRP6CltSesKey implements SRP6Integer { + + private final SRP6Integer srp6_N; + private final SRP6Integer srp6_g; + private final SRP6Integer srp6_k; + private final SRP6Integer srp6_x; + private final SRP6Integer srp6_u; + private final SRP6Integer srp6_a; + private final SRP6Integer srp6_B; + private final Mapping rule; + + private SRP6Integer S; + + public SRP6CltSesKey( + SRP6Integer N, + SRP6Integer g, + SRP6Integer x, + SRP6Integer u, + SRP6Integer a, + SRP6Integer B, + Mapping rule + ) { + this( + N, + g, + new SRP6PrecomputedValue(new BigInteger("3")), + x, + u, + a, + B, + rule + ); + } + + public SRP6CltSesKey( + SRP6Integer N, + SRP6Integer g, + SRP6Integer k, + SRP6Integer x, + SRP6Integer u, + SRP6Integer a, + SRP6Integer B, + Mapping rule + ) { + this.srp6_N = N; + this.srp6_g = g; + this.srp6_k = k; + this.srp6_x = x; + this.srp6_u = u; + this.srp6_a = a; + this.srp6_B = B; + this.rule = rule; + } + + private SRP6Integer compute_S() { + BigInteger N = srp6_N.bigInteger(); + BigInteger g = srp6_g.bigInteger(); + BigInteger k = srp6_k.bigInteger(); + BigInteger x = srp6_x.bigInteger(); + BigInteger u = srp6_u.bigInteger(); + BigInteger a = srp6_a.bigInteger(); + BigInteger B = srp6_B.bigInteger(); + + //S = (B - kg^x) ^ (a + ux) + return rule.map( + B.subtract(k.multiply(g.modPow(x, N))) + .modPow(a.add(u.multiply(x)), N)); + } + + @Override + public byte[] bytes() { + if (S == null) { + S = compute_S(); + } + return S.bytes(); + } + + @Override + public BigInteger bigInteger() { + if (S == null) { + S = compute_S(); + } + return S.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltSesProof.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltSesProof.java new file mode 100644 index 0000000..1e0aaed --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltSesProof.java @@ -0,0 +1,75 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import com.github.glusk2.wse.common.crypto.util.hashing.DigestArgument; +import com.github.glusk2.wse.common.crypto.util.hashing.ImmutableMessageDigest; +import com.github.glusk2.wse.common.crypto.util.hashing.IntermediateDigest; +import com.github.glusk2.wse.common.crypto.util.hashing.StringArgument; +import com.github.glusk2.wse.common.crypto.util.hashing.XoredArgumentPair; + +public final class SRP6CltSesProof implements DigestArgument { + + private final IntermediateDigest proof; + + private byte[] M1; + + public SRP6CltSesProof( + ImmutableMessageDigest imd, + SRP6Integer N, + SRP6Integer g, + String I, + SRP6Integer s, + SRP6Integer A, + SRP6Integer B, + DigestArgument K + ) { + this(imd, N, g, I, StandardCharsets.UTF_8, s, A, B, K); + } + + public SRP6CltSesProof( + ImmutableMessageDigest imd, + SRP6Integer N, + SRP6Integer g, + String I, + Charset charset, + SRP6Integer s, + SRP6Integer A, + SRP6Integer B, + DigestArgument K + ) { + this( + new IntermediateDigest( + imd, + new XoredArgumentPair( + new IntermediateDigest(imd, N), + new IntermediateDigest(imd, g) + ), + new IntermediateDigest( + imd, + new StringArgument( + I, + charset + ) + ), + s, + A, + B, + K + ) + ); + } + + public SRP6CltSesProof(IntermediateDigest proof) { + this.proof = proof; + } + + @Override + public byte[] bytes() { + if (M1 == null) { + M1 = proof.bytes(); + } + return M1; + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6FromBigIntRule.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6FromBigIntRule.java new file mode 100644 index 0000000..82a59ff --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6FromBigIntRule.java @@ -0,0 +1,24 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.util.Mapping; + +public final class SRP6FromBigIntRule + implements Mapping { + + private final int size; + private final ByteOrder order; + + public SRP6FromBigIntRule(int size, ByteOrder order) { + this.size = size; + this.order = order; + } + + @Override + public SRP6Integer map(final BigInteger key) { + return new SRP6PrecomputedValue(key, size, order); + } + +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6FromRawRule.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6FromRawRule.java new file mode 100644 index 0000000..86dce73 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6FromRawRule.java @@ -0,0 +1,21 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.util.Mapping; + +public final class SRP6FromRawRule implements Mapping { + + private final int size; + private final ByteOrder order; + + public SRP6FromRawRule(int size, ByteOrder order) { + this.size = size; + this.order = order; + } + + @Override + public SRP6Integer map(final byte[] key) { + return new SRP6PrecomputedValue(key, size, order); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6HashedSesKey.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6HashedSesKey.java new file mode 100644 index 0000000..a9c9912 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6HashedSesKey.java @@ -0,0 +1,55 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import com.github.glusk2.wse.common.crypto.util.hashing.DigestArgument; +import com.github.glusk2.wse.common.crypto.util.hashing.ImmutableMessageDigest; + +public final class SRP6HashedSesKey implements DigestArgument { + + private final ImmutableMessageDigest imd; + private final SRP6Integer S; + + private DigestArgument K; + + public SRP6HashedSesKey( + ImmutableMessageDigest imd, + SRP6Integer S + ) { + this.imd = imd; + this.S = S; + } + + /** + * This method implements the SHA_Interleave hash function as described in + * RFC2945 + * (section 3.1. Interleaved SHA). + */ + private DigestArgument compute_K() { + byte[] t = S.bytes(); + int off = t.length % 2; + int halfSize = (t.length - off) / 2; + + byte[] e = new byte[halfSize]; + byte[] o = new byte[halfSize]; + for (int i = off; i < halfSize; i++) { + e[i - off] = t[2 * i - off]; + o[i - off] = t[2 * i + 1 - off]; + } + e = imd.update(e).digest(); + o = imd.update(o).digest(); + + byte[] res = new byte[e.length + o.length]; + for (int i = 0; i < res.length / 2; i++) { + res[2 * i ] = e[i]; + res[2 * i + 1] = o[i]; + } + return new DigestArgument.RAW_BYTES(res); + } + + @Override + public byte[] bytes() { + if (K == null) { + K = compute_K(); + } + return K.bytes(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6Integer.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6Integer.java new file mode 100644 index 0000000..814aec2 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6Integer.java @@ -0,0 +1,14 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.math.BigInteger; + +import javax.xml.bind.DatatypeConverter; + +import com.github.glusk2.wse.common.crypto.util.hashing.DigestArgument; + +public interface SRP6Integer extends DigestArgument { + default String string() { + return DatatypeConverter.printHexBinary(bytes()); + } + BigInteger bigInteger(); +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6PrecomputedValue.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6PrecomputedValue.java new file mode 100644 index 0000000..c4dc897 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6PrecomputedValue.java @@ -0,0 +1,108 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import javax.xml.bind.DatatypeConverter; + +import com.github.glusk2.wse.common.crypto.util.bytearrays.Bba; +import com.github.glusk2.wse.common.crypto.util.bytearrays.ByteArray; +import com.github.glusk2.wse.common.crypto.util.bytearrays.Lba; +import com.github.glusk2.wse.common.crypto.util.bytearrays.Reversed; +import com.github.glusk2.wse.common.crypto.util.bytearrays.ZeroPadded; + +/** + * An SRP6 precomputed integer value. + *

+ * This class accepts either a byte array or a {@link BigInteger} + * representation of a SRP6 variable. It configures the representation + * via the constructors. + */ +public final class SRP6PrecomputedValue implements SRP6Integer { + + private final BigInteger bi; + private final ByteArray ba; + + /** + * A BigInteger extension that allows specific instantiation options. + * For example, using this class u can instantiate a BigInteger object, + * by providing little endian byte array representation. + */ + private static final class BigIntExt extends BigInteger { + private static final long serialVersionUID = 1L; + + BigIntExt(ByteArray ba, ByteOrder bo) { + this(bo == ByteOrder.LITTLE_ENDIAN ? new Reversed(ba) : ba); + } + + BigIntExt(ByteArray ba) { + super(1, ba.array()); + } + } + + public SRP6PrecomputedValue(BigInteger bi) { + this(bi, ByteOrder.LITTLE_ENDIAN); + } + + public SRP6PrecomputedValue(BigInteger bi, ByteOrder bo) { + this(bi, bo == ByteOrder.LITTLE_ENDIAN ? new Lba(bi) : new Bba(bi)); + } + + public SRP6PrecomputedValue(BigInteger bi, int size) { + this(bi, size, ByteOrder.LITTLE_ENDIAN); + } + + public SRP6PrecomputedValue(BigInteger bi, int size, ByteOrder bo) { + this( + bi, + bo == ByteOrder.LITTLE_ENDIAN ? + new Lba(bi, size) : new Bba(bi, size) + ); + } + + + public SRP6PrecomputedValue(String hex, ByteOrder order) { + this(DatatypeConverter.parseHexBinary(hex), order); + } + + public SRP6PrecomputedValue(byte[] arr, ByteOrder order) { + this(arr, arr.length, order); + } + + public SRP6PrecomputedValue(byte[] arr, int size, ByteOrder bo) { + this(new ByteArray.WRAPPER(arr), size, bo); + } + + public SRP6PrecomputedValue(ByteArray arr, int size, ByteOrder bo) { + this( + new BigIntExt(arr, bo), + bo == ByteOrder.LITTLE_ENDIAN ? + new ZeroPadded( + arr, + size + ) : + new Reversed( + new ZeroPadded( + new Reversed(arr), + size + ) + ) + ); + } + + + private SRP6PrecomputedValue(BigInteger bi, ByteArray ba) { + this.bi = bi; + this.ba = ba; + } + + @Override + public byte[] bytes() { + return ba.array(); + } + + @Override + public BigInteger bigInteger() { + return bi; + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6PrivateKey.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6PrivateKey.java new file mode 100644 index 0000000..a75ab0c --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6PrivateKey.java @@ -0,0 +1,83 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.math.BigInteger; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +import com.github.glusk2.wse.common.crypto.util.hashing.DigestArgument; +import com.github.glusk2.wse.common.crypto.util.hashing.ImmutableMessageDigest; +import com.github.glusk2.wse.common.crypto.util.hashing.IntermediateDigest; +import com.github.glusk2.wse.common.crypto.util.hashing.StringArgument; +import com.github.glusk2.wse.common.util.Mapping; + +public final class SRP6PrivateKey implements SRP6Integer { + + private final ImmutableMessageDigest imd; + private final SRP6Integer s; + private final DigestArgument p; + private final Mapping rule; + + private SRP6Integer x; + + public SRP6PrivateKey( + ImmutableMessageDigest imd, + SRP6Integer s, + String I, + String P, + Mapping rule + ) { + this(imd, s, I, P, StandardCharsets.UTF_8, rule); + } + + public SRP6PrivateKey( + ImmutableMessageDigest imd, + SRP6Integer s, + String I, + String P, + Charset charset, + Mapping rule + ) { + this( + imd, + s, + new IntermediateDigest( + imd, + new StringArgument(I + ":" + P, charset) + ), + rule + ); + } + + public SRP6PrivateKey( + ImmutableMessageDigest imd, + SRP6Integer s, + DigestArgument p, + Mapping rule + ) { + this.imd = imd; + this.rule = rule; + this.p = p; + this.s = s; + } + + private SRP6Integer compute_x() { + // H(salt | H(username | ":" | password)) = H(salt | p) + return rule.map(imd.update(s, p).digest()); + } + + @Override + public byte[] bytes() { + if (x == null) { + x = compute_x(); + } + return x.bytes(); + } + + @Override + public BigInteger bigInteger() { + if (x == null) { + x = compute_x(); + } + return x.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6Record.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6Record.java new file mode 100644 index 0000000..a04d146 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6Record.java @@ -0,0 +1,10 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.sql.SQLException; + +public interface SRP6Record { + SRP6Integer verifier() throws SQLException; + SRP6Integer salt() throws SQLException; + SRP6Integer modulus() throws SQLException; + SRP6Integer generator() throws SQLException; +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6ScrPar.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6ScrPar.java new file mode 100644 index 0000000..b690fad --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6ScrPar.java @@ -0,0 +1,49 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.math.BigInteger; + +import com.github.glusk2.wse.common.crypto.util.hashing.ImmutableMessageDigest; +import com.github.glusk2.wse.common.util.Mapping; + +public final class SRP6ScrPar implements SRP6Integer { + + private final ImmutableMessageDigest imd; + private final Mapping rule; + private final SRP6Integer A; + private final SRP6Integer B; + + private SRP6Integer u; + + public SRP6ScrPar( + ImmutableMessageDigest imd, + SRP6Integer A, + SRP6Integer B, + Mapping rule + ) { + this.imd = imd; + this.A = A; + this.B = B; + this.rule = rule; + } + + private SRP6Integer compute_u() { + // u = H(A, B) + return rule.map(imd.update(A, B).digest()); + } + + @Override + public byte[] bytes() { + if (u == null) { + u = compute_u(); + } + return u.bytes(); + } + + @Override + public BigInteger bigInteger() { + if (u == null) { + u = compute_u(); + } + return u.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvPubEphVal.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvPubEphVal.java new file mode 100644 index 0000000..4e22edc --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvPubEphVal.java @@ -0,0 +1,81 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.math.BigInteger; + +import com.github.glusk2.wse.common.util.Mapping; + +/** + * An SRP6 Server Public Ephemeral value - B. + */ +public final class SRP6SrvPubEphVal implements SRP6Integer { + private final SRP6Integer srp6_k; + private final SRP6Integer srp6_b; + private final SRP6Integer srp6_v; + private final SRP6Integer srp6_g; + private final SRP6Integer srp6_N; + private final Mapping rule; + + private SRP6Integer B; + + public SRP6SrvPubEphVal( + SRP6Integer N, + SRP6Integer g, + SRP6Integer v, + SRP6Integer b, + Mapping rule + ) { + this( + N, + g, + new SRP6PrecomputedValue( + new BigInteger("3") + ), + v, + b, + rule + ); + } + + public SRP6SrvPubEphVal( + SRP6Integer N, + SRP6Integer g, + SRP6Integer k, + SRP6Integer v, + SRP6Integer b, + Mapping rule + ) { + this.srp6_N = N; + this.srp6_g = g; + this.srp6_k = k; + this.srp6_v = v; + this.srp6_b = b; + this.rule = rule; + } + + private SRP6Integer computeB() { + BigInteger k = srp6_k.bigInteger(); + BigInteger b = srp6_b.bigInteger(); + BigInteger v = srp6_v.bigInteger(); + BigInteger g = srp6_g.bigInteger(); + BigInteger N = srp6_N.bigInteger(); + + // B = kv + g^b + return rule.map(k.multiply(v).add(g.modPow(b, N)).mod(N)); + } + + @Override + public byte[] bytes() { + if (B == null) { + B = computeB(); + } + return B.bytes(); + } + + @Override + public BigInteger bigInteger() { + if (B == null) { + B = computeB(); + } + return B.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvSesKey.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvSesKey.java new file mode 100644 index 0000000..49ed195 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvSesKey.java @@ -0,0 +1,59 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.math.BigInteger; + +import com.github.glusk2.wse.common.util.Mapping; + +public final class SRP6SrvSesKey implements SRP6Integer { + private final SRP6Integer srp6_N; + private final SRP6Integer srp6_A; + private final SRP6Integer srp6_v; + private final SRP6Integer srp6_b; + private final SRP6Integer srp6_u; + private final Mapping rule; + + private SRP6Integer S; + + public SRP6SrvSesKey( + SRP6Integer N, + SRP6Integer A, + SRP6Integer v, + SRP6Integer u, + SRP6Integer b, + Mapping rule + ) { + this.srp6_N = N; + this.srp6_A = A; + this.srp6_v = v; + this.srp6_u = u; + this.srp6_b = b; + this.rule = rule; + } + + private SRP6Integer compute_S() { + BigInteger N = srp6_N.bigInteger(); + BigInteger A = srp6_A.bigInteger(); + BigInteger v = srp6_v.bigInteger(); + BigInteger b = srp6_b.bigInteger(); + BigInteger u = srp6_u.bigInteger(); + + // S = (A*v^u)^b + return rule.map(A.multiply(v.modPow(u, N)).modPow(b, N)); + } + + @Override + public byte[] bytes() { + if (S == null) { + S = compute_S(); + } + return S.bytes(); + } + + @Override + public BigInteger bigInteger() { + if (S == null) { + S = compute_S(); + } + return S.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvSesProof.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvSesProof.java new file mode 100644 index 0000000..7e370ab --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvSesProof.java @@ -0,0 +1,33 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import com.github.glusk2.wse.common.crypto.util.hashing.DigestArgument; +import com.github.glusk2.wse.common.crypto.util.hashing.ImmutableMessageDigest; +import com.github.glusk2.wse.common.crypto.util.hashing.IntermediateDigest; + +public final class SRP6SrvSesProof implements DigestArgument { + + private final IntermediateDigest proof; + + private byte[] M2; + + public SRP6SrvSesProof( + ImmutableMessageDigest imd, + SRP6Integer A, + DigestArgument M, + DigestArgument K + ) { + this(new IntermediateDigest(imd, A, M, K)); + } + + public SRP6SrvSesProof(IntermediateDigest proof) { + this.proof = proof; + } + + @Override + public byte[] bytes() { + if (M2 == null) { + M2 = proof.bytes(); + } + return M2; + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6Verifier.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6Verifier.java new file mode 100644 index 0000000..7cea5cf --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/SRP6Verifier.java @@ -0,0 +1,52 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import java.math.BigInteger; + +import com.github.glusk2.wse.common.util.Mapping; + +public final class SRP6Verifier implements SRP6Integer { + + private final SRP6Integer srp6_N; + private final SRP6Integer srp6_g; + private final SRP6Integer srp6_x; + private final Mapping rule; + + private SRP6Integer v; + + public SRP6Verifier( + SRP6Integer N, + SRP6Integer g, + SRP6Integer x, + Mapping rule + ) { + this.srp6_N = N; + this.srp6_g = g; + this.srp6_x = x; + this.rule = rule; + } + + private SRP6Integer compute_v() { + BigInteger N = srp6_N.bigInteger(); + BigInteger g = srp6_g.bigInteger(); + BigInteger x = srp6_x.bigInteger(); + + // v = g^x + return rule.map(g.modPow(x, N)); + } + + @Override + public byte[] bytes() { + if (v == null) { + v = compute_v(); + } + return v.bytes(); + } + + @Override + public BigInteger bigInteger() { + if (v == null) { + v = compute_v(); + } + return v.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_A.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_A.java new file mode 100644 index 0000000..3e8e480 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_A.java @@ -0,0 +1,34 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_A implements SRP6Integer { + + private static final SRP6Integer A = + new SRP6PrecomputedValue( + new BigInteger( + ("61D5E490 F6F1B795 47B0704C 436F523D D0E560F0 C64115BB" + + "72557EC4 4352E890 3211C046 92272D8B 2D1A5358 A2CF1B6E" + + "0BFCF99F 921530EC 8E393561 79EAE45E 42BA92AE ACED8251" + + "71E1E8B9 AF6D9C03 E1327F44 BE087EF0 6530E69F 66615261" + + "EEF54073 CA11CF58 58F0EDFD FE15EFEA B349EF5D 76988A36" + + "72FAC47B 0769447B").replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return A.bytes(); + } + + @Override + public BigInteger bigInteger() { + return A.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_B.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_B.java new file mode 100644 index 0000000..a5a7671 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_B.java @@ -0,0 +1,34 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_B implements SRP6Integer { + + private static final SRP6Integer B = + new SRP6PrecomputedValue( + new BigInteger( + ("BD0C6151 2C692C0C B6D041FA 01BB152D 4916A1E7 7AF46AE1" + + "05393011 BAF38964 DC46A067 0DD125B9 5A981652 236F99D9" + + "B681CBF8 7837EC99 6C6DA044 53728610 D0C6DDB5 8B318885" + + "D7D82C7F 8DEB75CE 7BD4FBAA 37089E6F 9C6059F3 88838E7A" + + "00030B33 1EB76840 910440B1 B27AAEAE EB4012B7 D7665238" + + "A8E3FB00 4B117B58").replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return B.bytes(); + } + + @Override + public BigInteger bigInteger() { + return B.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_N.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_N.java new file mode 100644 index 0000000..9357349 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_N.java @@ -0,0 +1,34 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_N implements SRP6Integer { + + private static final SRP6Integer N = + new SRP6PrecomputedValue( + new BigInteger( + ("EEAF0AB9 ADB38DD6 9C33F80A FA8FC5E8 60726187 75FF3C0B" + + "9EA2314C 9C256576 D674DF74 96EA81D3 383B4813 D692C6E0" + + "E0D5D8E2 50B98BE4 8E495C1D 6089DAD1 5DC7D7B4 6154D6B6" + + "CE8EF4AD 69B15D49 82559B29 7BCF1885 C529F566 660E57EC" + + "68EDBC3C 05726CC0 2FD4CBF4 976EAA9A FD5138FE 8376435B" + + "9FC61D2F C0EB06E3").replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return N.bytes(); + } + + @Override + public BigInteger bigInteger() { + return N.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_S.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_S.java new file mode 100644 index 0000000..3fcf26d --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_S.java @@ -0,0 +1,34 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_S implements SRP6Integer { + + private static final SRP6Integer S = + new SRP6PrecomputedValue( + new BigInteger( + ("B0DC82BA BCF30674 AE450C02 87745E79 90A3381F 63B387AA" + + "F271A10D 233861E3 59B48220 F7C4693C 9AE12B0A 6F67809F" + + "0876E2D0 13800D6C 41BB59B6 D5979B5C 00A172B4 A2A5903A" + + "0BDCAF8A 709585EB 2AFAFA8F 3499B200 210DCC1F 10EB3394" + + "3CD67FC8 8A2F39A4 BE5BEC4E C0A3212D C346D7E4 74B29EDE" + + "8A469FFE CA686E5A").replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return S.bytes(); + } + + @Override + public BigInteger bigInteger() { + return S.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_a.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_a.java new file mode 100644 index 0000000..4eab446 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_a.java @@ -0,0 +1,30 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_a implements SRP6Integer { + + private static final SRP6Integer a = + new SRP6PrecomputedValue( + new BigInteger( + ("60975527 035CF2AD 1989806F 0407210B C81EDC04 E2762A56" + + "AFD529DD DA2D4393").replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return a.bytes(); + } + + @Override + public BigInteger bigInteger() { + return a.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_b.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_b.java new file mode 100644 index 0000000..c3a688a --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_b.java @@ -0,0 +1,30 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_b implements SRP6Integer { + + private static final SRP6Integer b = + new SRP6PrecomputedValue( + new BigInteger( + ("E487CB59 D31AC550 471E81F0 0F6928E0 1DDA08E9 74A004F4" + + "9E61F5D1 05284D20").replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return b.bytes(); + } + + @Override + public BigInteger bigInteger() { + return b.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_g.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_g.java new file mode 100644 index 0000000..874c10d --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_g.java @@ -0,0 +1,23 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_g implements SRP6Integer { + + private static final SRP6Integer g = + new SRP6PrecomputedValue(new BigInteger("2"), ByteOrder.BIG_ENDIAN); + + @Override + public byte[] bytes() { + return g.bytes(); + } + + @Override + public BigInteger bigInteger() { + return g.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_k.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_k.java new file mode 100644 index 0000000..097be3a --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_k.java @@ -0,0 +1,30 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_k implements SRP6Integer { + + private static final SRP6Integer k = + new SRP6PrecomputedValue( + new BigInteger( + "7556AA04 5AEF2CDD 07ABAF0F 665C3E81 8913186F" + .replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return k.bytes(); + } + + @Override + public BigInteger bigInteger() { + return k.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_s.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_s.java new file mode 100644 index 0000000..15bc77f --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_s.java @@ -0,0 +1,30 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_s implements SRP6Integer { + + private static final SRP6Integer s = + new SRP6PrecomputedValue( + new BigInteger( + "BEB25379 D1A8581E B5A72767 3A2441EE" + .replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return s.bytes(); + } + + @Override + public BigInteger bigInteger() { + return s.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_u.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_u.java new file mode 100644 index 0000000..42812ab --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_u.java @@ -0,0 +1,30 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_u implements SRP6Integer { + + private static final SRP6Integer u = + new SRP6PrecomputedValue( + new BigInteger( + "CE38B959 3487DA98 554ED47D 70A7AE5F 462EF019" + .replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return u.bytes(); + } + + @Override + public BigInteger bigInteger() { + return u.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_v.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_v.java new file mode 100644 index 0000000..b242ae1 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_v.java @@ -0,0 +1,34 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_v implements SRP6Integer { + + private static final SRP6Integer v = + new SRP6PrecomputedValue( + new BigInteger( + ("7E273DE8 696FFC4F 4E337D05 B4B375BE B0DDE156 9E8FA00A" + + "9886D812 9BADA1F1 822223CA 1A605B53 0E379BA4 729FDC59" + + "F105B478 7E5186F5 C671085A 1447B52A 48CF1970 B4FB6F84" + + "00BBF4CE BFBB1681 52E08AB5 EA53D15C 1AFF87B2 B9DA6E04" + + "E058AD51 CC72BFC9 033B564E 26480D78 E955A5E2 9E7AB245" + + "DB2BE315 E2099AFB").replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return v.bytes(); + } + + @Override + public BigInteger bigInteger() { + return v.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_x.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_x.java new file mode 100644 index 0000000..98a59fd --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/srp6/rfc5054/RFC5054TestVector_x.java @@ -0,0 +1,30 @@ +package com.github.glusk2.wse.common.crypto.srp6.rfc5054; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import com.github.glusk2.wse.common.crypto.srp6.SRP6PrecomputedValue; +import com.github.glusk2.wse.common.crypto.srp6.SRP6Integer; + +public final class RFC5054TestVector_x implements SRP6Integer { + + private static final SRP6Integer x = + new SRP6PrecomputedValue( + new BigInteger( + "94B7555A ABE9127C C58CCF49 93DB6CF8 4D16C124" + .replace(" ", ""), + 16 + ), + ByteOrder.BIG_ENDIAN + ); + + @Override + public byte[] bytes() { + return x.bytes(); + } + + @Override + public BigInteger bigInteger() { + return x.bigInteger(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/Bba.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/Bba.java new file mode 100644 index 0000000..ab0f2fa --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/Bba.java @@ -0,0 +1,39 @@ +package com.github.glusk2.wse.common.crypto.util.bytearrays; + +import java.math.BigInteger; + +public final class Bba implements ByteArray { + private final ByteArray ba; + + public Bba(BigInteger bi, int size) { + this( + new Reversed( + new ZeroPadded( + new Reversed( + new NoLeadingZeroes( + new ByteArray.WRAPPER(bi.toByteArray()) + ) + ), + size + ) + ) + ); + } + + public Bba(BigInteger bi) { + this( + new NoLeadingZeroes( + new ByteArray.WRAPPER(bi.toByteArray()) + ) + ); + } + + private Bba(ByteArray ba) { + this.ba = ba; + } + + @Override + public byte[] array() { + return ba.array(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/ByteArray.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/ByteArray.java new file mode 100644 index 0000000..bf3b8b7 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/ByteArray.java @@ -0,0 +1,20 @@ +package com.github.glusk2.wse.common.crypto.util.bytearrays; + +public interface ByteArray { + + byte[] array(); + + final class WRAPPER implements ByteArray { + + private final byte[] arr; + + public WRAPPER(byte[] arr) { + this.arr = arr; + } + + @Override + public byte[] array() { + return arr; + } + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/Lba.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/Lba.java new file mode 100644 index 0000000..56b9255 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/Lba.java @@ -0,0 +1,63 @@ +package com.github.glusk2.wse.common.crypto.util.bytearrays; + +import java.math.BigInteger; + +/** + * Little-Endian {@link ByteArray} representation of a {@link BigInteger} + * object. + */ +public final class Lba implements ByteArray { + + private final ByteArray ba; + + /** + * @param bi + * {@link BigInteger} object from which {@code this} little-endian + * byte array is to be constructed. + * @param size + * Required {@link #array()} length. {@link #array()} is padded + * with {@code size - (bi.toByteArray().length - #leading_zeroes)} + * 0 bytes. {@code #leading_zeroes} is the number of leading zeroes + * in {@code bi.toByteArray()}. + */ + public Lba(BigInteger bi, int size) { + this( + new ZeroPadded( + new Reversed( + new NoLeadingZeroes( + new ByteArray.WRAPPER(bi.toByteArray()) + ) + ), + size + ) + ); + } + + /** + * @param bi + * {@link BigInteger} object from which {@code this} little-endian + * byte array is to be constructed. + */ + public Lba(BigInteger bi) { + this( + new Reversed( + new NoLeadingZeroes( + new ByteArray.WRAPPER(bi.toByteArray()) + ) + ) + ); + } + + private Lba(ByteArray ba) { + this.ba = ba; + } + + /** + * Little-endian byte array representation of the {@link BigInteger} object + * passed through the constructor. + */ + @Override + public byte[] array() { + return ba.array(); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/NoLeadingZeroes.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/NoLeadingZeroes.java new file mode 100644 index 0000000..de0cc1c --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/NoLeadingZeroes.java @@ -0,0 +1,26 @@ +package com.github.glusk2.wse.common.crypto.util.bytearrays; + +import java.util.Arrays; + +public final class NoLeadingZeroes implements ByteArray { + private final ByteArray ba; + + public NoLeadingZeroes(ByteArray ba) { + this.ba = ba; + } + + @Override + public byte[] array() { + byte[] original = this.ba.array(); + + int i = 0; + while (i < original.length && original[i] == 0) { + i++; + } + + if (i == 0) { + return original; + } + return Arrays.copyOfRange(original, i, original.length); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/Reversed.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/Reversed.java new file mode 100644 index 0000000..9536c3d --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/Reversed.java @@ -0,0 +1,22 @@ +package com.github.glusk2.wse.common.crypto.util.bytearrays; + +public final class Reversed implements ByteArray { + private final ByteArray ba; + + public Reversed(ByteArray ba) { + this.ba = ba; + } + + @Override + public byte[] array() { + byte[] reversed = this.ba.array().clone(); + + for (int i = 0; i < reversed.length / 2; i++) { + byte tmp = reversed[i]; + reversed[i] = reversed[reversed.length - 1 - i]; + reversed[reversed.length - 1 - i] = tmp; + } + + return reversed; + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/ZeroPadded.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/ZeroPadded.java new file mode 100644 index 0000000..fb5328b --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/bytearrays/ZeroPadded.java @@ -0,0 +1,31 @@ +package com.github.glusk2.wse.common.crypto.util.bytearrays; + +import java.util.Arrays; + +public final class ZeroPadded implements ByteArray { + private final ByteArray bat; + private final int newSize; + + public ZeroPadded(ByteArray bat, int newSize) { + this.bat = bat; + this.newSize = newSize; + } + + @Override + public byte[] array() { + byte[] original = this.bat.array(); + if (this.newSize < original.length) { + throw new RuntimeException( + String.format( + "New size is smaller than original array length. " + + "Original size: %d, new size: %d. Possible loss of data!", + original.length, this.newSize) + ); + } + + if (this.newSize == original.length) { + return original; + } + return Arrays.copyOfRange(original, 0, this.newSize); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/DigestArgument.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/DigestArgument.java new file mode 100644 index 0000000..a98e96e --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/DigestArgument.java @@ -0,0 +1,20 @@ +package com.github.glusk2.wse.common.crypto.util.hashing; + +public interface DigestArgument { + + byte[] bytes(); + + final class RAW_BYTES implements DigestArgument { + + private final byte[] bArr; + + public RAW_BYTES(byte[] bArr) { + this.bArr = bArr; + } + + @Override + public byte[] bytes() { + return bArr; + } + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/ImdSimpleCopy.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/ImdSimpleCopy.java new file mode 100644 index 0000000..75df259 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/ImdSimpleCopy.java @@ -0,0 +1,47 @@ +package com.github.glusk2.wse.common.crypto.util.hashing; + +import java.security.MessageDigest; + +/** + * A simple "copy-before-action" {@code ImmutableMessageDigest} object. + */ +public final class ImdSimpleCopy implements ImmutableMessageDigest { + private final MessageDigest md; + + public ImdSimpleCopy(MessageDigest md) { + this.md = md; + } + + private static MessageDigest clone(final MessageDigest md) { + try { + return (MessageDigest) md.clone(); + } catch (CloneNotSupportedException cnse) { + throw + new RuntimeException( + String.format( + "Couldn't make digest of partial content - the " + + "underlying MessageDigest object: %s is not " + + "cloneable.", + md + ), + cnse + ); + } + } + + @Override + public byte[] digest() { + return clone(this.md).digest(); + } + + @Override + public ImmutableMessageDigest update( + final byte[] arr, + final int offset, + final int len + ) { + MessageDigest clone = clone(this.md); + clone.update(arr, offset, len); + return new ImdSimpleCopy(clone); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/ImmutableMessageDigest.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/ImmutableMessageDigest.java new file mode 100644 index 0000000..a254717 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/ImmutableMessageDigest.java @@ -0,0 +1,23 @@ +package com.github.glusk2.wse.common.crypto.util.hashing; + +/** + * Extension of {@code MessageDigest} functionality that allows method chaining + * and is immutable. + */ +public interface ImmutableMessageDigest { + byte[] digest(); + + ImmutableMessageDigest update(byte[] arr, int offset, int len); + + default ImmutableMessageDigest update(byte[] arr) { + return update(arr, 0, arr.length); + } + + default ImmutableMessageDigest update(DigestArgument... args) { + ImmutableMessageDigest imd = this; + for (DigestArgument arg : args) { + imd = imd.update(arg.bytes()); + } + return imd; + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/IntermediateDigest.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/IntermediateDigest.java new file mode 100644 index 0000000..9fda949 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/IntermediateDigest.java @@ -0,0 +1,21 @@ +package com.github.glusk2.wse.common.crypto.util.hashing; + +public final class IntermediateDigest implements DigestArgument { + + private final ImmutableMessageDigest imd; + private final DigestArgument[] args; + + public IntermediateDigest( + ImmutableMessageDigest imd, + DigestArgument... args + ) { + this.imd = imd; + this.args = args; + } + + @Override + public byte[] bytes() { + return imd.update(args).digest(); + } + +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/StringArgument.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/StringArgument.java new file mode 100644 index 0000000..ae9b359 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/StringArgument.java @@ -0,0 +1,24 @@ +package com.github.glusk2.wse.common.crypto.util.hashing; + +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; + +public final class StringArgument implements DigestArgument { + + private final String string; + private final Charset charset; + + public StringArgument(String string) { + this(string, StandardCharsets.UTF_8); + } + + public StringArgument(String string, Charset charset) { + this.string = string; + this.charset = charset; + } + + @Override + public byte[] bytes() { + return string.getBytes(charset); + } +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/XoredArgumentPair.java b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/XoredArgumentPair.java new file mode 100644 index 0000000..dc8d2e0 --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/crypto/util/hashing/XoredArgumentPair.java @@ -0,0 +1,27 @@ +package com.github.glusk2.wse.common.crypto.util.hashing; + +import java.math.BigInteger; + +public final class XoredArgumentPair implements DigestArgument { + + private final DigestArgument arg1; + private final DigestArgument arg2; + + public XoredArgumentPair(DigestArgument arg1, DigestArgument arg2) { + this.arg1 = arg1; + this.arg2 = arg2; + } + + @Override + public byte[] bytes() { + return + new BigInteger( + arg1.bytes() + ).xor( + new BigInteger( + arg2.bytes() + ) + ).toByteArray(); + } + +} diff --git a/wse-common/src/main/java/com/github/glusk2/wse/common/util/Mapping.java b/wse-common/src/main/java/com/github/glusk2/wse/common/util/Mapping.java new file mode 100644 index 0000000..0c1cb6c --- /dev/null +++ b/wse-common/src/main/java/com/github/glusk2/wse/common/util/Mapping.java @@ -0,0 +1,5 @@ +package com.github.glusk2.wse.common.util; + +public interface Mapping { + V map(K key); +} diff --git a/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltPubEphlValTest.java b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltPubEphlValTest.java new file mode 100644 index 0000000..6921b4c --- /dev/null +++ b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltPubEphlValTest.java @@ -0,0 +1,37 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import org.junit.Test; + +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_A; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_N; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_a; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_g; +import com.github.glusk2.wse.common.util.Mapping; + +public class SRP6CltPubEphlValTest { + @Test + public void testRFC5054() { + final Mapping rule = + new SRP6FromBigIntRule( + new RFC5054TestVector_N().bytes().length, + ByteOrder.BIG_ENDIAN + ); + + assertTrue( + "Computed value doesn't match the test vector.", + new RFC5054TestVector_A().string().equals( + new SRP6CltPubEphVal( + new RFC5054TestVector_N(), + new RFC5054TestVector_g(), + new RFC5054TestVector_a(), + rule + ).string() + ) + ); + } +} diff --git a/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltSesKeyTest.java b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltSesKeyTest.java new file mode 100644 index 0000000..6558e59 --- /dev/null +++ b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6CltSesKeyTest.java @@ -0,0 +1,45 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import org.junit.Test; + +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_B; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_N; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_S; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_a; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_g; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_k; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_u; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_x; +import com.github.glusk2.wse.common.util.Mapping; + +public class SRP6CltSesKeyTest { + @Test + public void testRFC5054() { + final Mapping rule = + new SRP6FromBigIntRule( + new RFC5054TestVector_N().bytes().length, + ByteOrder.BIG_ENDIAN + ); + + assertTrue( + "Computed value doesn't match the test vector.", + new RFC5054TestVector_S().string().equals( + new SRP6CltSesKey( + new RFC5054TestVector_N(), + new RFC5054TestVector_g(), + new RFC5054TestVector_k(), + new RFC5054TestVector_x(), + new RFC5054TestVector_u(), + new RFC5054TestVector_a(), + new RFC5054TestVector_B(), + rule + ).string() + ) + ); + } +} diff --git a/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6IT.java b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6IT.java new file mode 100644 index 0000000..0d463a8 --- /dev/null +++ b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6IT.java @@ -0,0 +1,90 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import static org.junit.Assert.fail; + +import java.math.BigInteger; +import java.nio.ByteOrder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; + +import org.junit.Assert; +import org.junit.Test; + +import com.github.glusk2.wse.common.crypto.util.hashing.DigestArgument; +import com.github.glusk2.wse.common.crypto.util.hashing.ImdSimpleCopy; +import com.github.glusk2.wse.common.crypto.util.hashing.ImmutableMessageDigest; +import com.github.glusk2.wse.common.util.Mapping; + +public class SRP6IT { + ByteOrder order = ByteOrder.LITTLE_ENDIAN; + + SRP6Integer N = + new SRP6PrecomputedValue( + new BigInteger( + ("AC903A4E 02EEA129 AF182912 72F6AF74" + + "6852AB3F 0107FD6A A6A6EB9B CFBBF1E4 7B").replaceAll(" ", ""), + 16 + ), + order + ); + + SRP6Integer g = new SRP6PrecomputedValue(new BigInteger("2"), order); + + int pad = N.bytes().length; + + @Test + public void testSRP6Protocol() { + ImmutableMessageDigest imd = null; + try { + imd = new ImdSimpleCopy(MessageDigest.getInstance("SHA-1")); + } catch (NoSuchAlgorithmException e) { + fail(e.getMessage()); + } + SecureRandom rng = new SecureRandom(); + + Mapping intPadRule = + new SRP6FromBigIntRule(pad, order); + Mapping shaPadRule = + new SRP6FromRawRule(20, order); + + // Alice registers with Bob - creates a record of the form + // -------------------------------------------------------------------- + String I = "Alice"; + String P = "lkji2"; + SRP6Integer s = new SRP6PrecomputedValue(rng.generateSeed(pad), order); + SRP6Integer x = new SRP6PrivateKey(imd, s, I, P, shaPadRule); + SRP6Integer v = new SRP6Verifier(N, g, x, intPadRule); + // -------------------------------------------------------------------- + + // Alice sends her username to Bob on login and he looks up her record. + // He replies with B: + SRP6Integer b = new SRP6PrecomputedValue(rng.generateSeed(pad), order); + SRP6Integer B = new SRP6SrvPubEphVal(N, g, v, b, intPadRule); + // -------------------------------------------------------------------- + + // Alice can now compute the session key: + SRP6Integer a = new SRP6PrecomputedValue(rng.generateSeed(pad), order); + SRP6Integer A = new SRP6CltPubEphVal(N, g, a, intPadRule); + SRP6Integer u = new SRP6ScrPar(imd, A, B, shaPadRule); + DigestArgument client_K = + new SRP6HashedSesKey( + imd, + new SRP6CltSesKey(N, g, x, u, a, B, intPadRule) + ); + //--------------------------------------------------------------------- + + // Now Bob computes the session key: + DigestArgument server_K = + new SRP6HashedSesKey( + imd, + new SRP6SrvSesKey(N, A, v, u, b, intPadRule) + ); + + Assert.assertArrayEquals( + "Keys don't match!", + client_K.bytes(), + server_K.bytes() + ); + } +} diff --git a/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6PrivateKeyTest.java b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6PrivateKeyTest.java new file mode 100644 index 0000000..935273c --- /dev/null +++ b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6PrivateKeyTest.java @@ -0,0 +1,82 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.nio.ByteOrder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.junit.Test; + +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_s; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_x; +import com.github.glusk2.wse.common.crypto.util.hashing.ImdSimpleCopy; +import com.github.glusk2.wse.common.crypto.util.hashing.ImmutableMessageDigest; +import com.github.glusk2.wse.common.util.Mapping; + +public class SRP6PrivateKeyTest { + @Test + public void testRFC5054() { + ImmutableMessageDigest imd = null; + try { + imd = new ImdSimpleCopy(MessageDigest.getInstance("SHA-1")); + } catch (NoSuchAlgorithmException nsae) { + fail(nsae.getMessage()); + } + final Mapping rule = + new SRP6FromRawRule(20, ByteOrder.BIG_ENDIAN); + + assertTrue( + "Computed value doesn't match the test vector.", + new RFC5054TestVector_x().string().equals( + new SRP6PrivateKey( + imd, + new RFC5054TestVector_s(), + "alice", + "password123", + rule + ).string() + ) + ); + } + + @Test + public void test2() { + ImmutableMessageDigest imd = null; + try { + imd = new ImdSimpleCopy(MessageDigest.getInstance("SHA-1")); + } catch (NoSuchAlgorithmException nsae) { + fail(nsae.getMessage()); + } + final Mapping rule = + new SRP6FromRawRule(20, ByteOrder.LITTLE_ENDIAN); + // SHA-1("USER:USER") + final SRP6Integer p = + new SRP6PrecomputedValue( + "EB5D7590 55285597 CA115295 1A585A47 5E1CB1BD" + .replaceAll(" ", ""), + ByteOrder.LITTLE_ENDIAN + ); + final SRP6Integer s = + new SRP6PrecomputedValue( + ("0D4894AB B6F8C86B 33FC586D 161B16C9" + + "AE2588A3 378395B6 E2CBE36E 76B60F6A" + ).replaceAll(" ", ""), + ByteOrder.LITTLE_ENDIAN + ); + final SRP6Integer x = + new SRP6PrecomputedValue( + "611C7539 A20DC594 FBCC45A6 BDDABF4D 67645F52" + .replaceAll(" ", ""), + ByteOrder.LITTLE_ENDIAN + ); + + assertTrue( + "Computed value doesn't match the test vector.", + x.string().equals( + new SRP6PrivateKey(imd, s, p, rule).string() + ) + ); + } +} diff --git a/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6ScrParTest.java b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6ScrParTest.java new file mode 100644 index 0000000..e375a12 --- /dev/null +++ b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6ScrParTest.java @@ -0,0 +1,43 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.nio.ByteOrder; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +import org.junit.Test; + +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_A; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_B; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_u; +import com.github.glusk2.wse.common.crypto.util.hashing.ImdSimpleCopy; +import com.github.glusk2.wse.common.crypto.util.hashing.ImmutableMessageDigest; +import com.github.glusk2.wse.common.util.Mapping; + +public class SRP6ScrParTest { + @Test + public void testRFC5054() { + ImmutableMessageDigest imd = null; + try { + imd = new ImdSimpleCopy(MessageDigest.getInstance("SHA-1")); + } catch (NoSuchAlgorithmException nsae) { + fail(nsae.getMessage()); + } + final Mapping rule = + new SRP6FromRawRule(20, ByteOrder.BIG_ENDIAN); + + assertTrue( + "Computed value doesn't match the test vector.", + new RFC5054TestVector_u().string().equals( + new SRP6ScrPar( + imd, + new RFC5054TestVector_A(), + new RFC5054TestVector_B(), + rule + ).string() + ) + ); + } +} diff --git a/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvPubEphVaLTest.java b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvPubEphVaLTest.java new file mode 100644 index 0000000..4c04ca0 --- /dev/null +++ b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvPubEphVaLTest.java @@ -0,0 +1,41 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import org.junit.Test; + +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_B; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_N; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_b; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_g; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_k; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_v; +import com.github.glusk2.wse.common.util.Mapping; + +public class SRP6SrvPubEphVaLTest { + @Test + public void testRFC5054() { + final Mapping rule = + new SRP6FromBigIntRule( + new RFC5054TestVector_N().bytes().length, + ByteOrder.BIG_ENDIAN + ); + + assertTrue( + "Computed value doesn't match the test vector.", + new RFC5054TestVector_B().string().equals( + new SRP6SrvPubEphVal( + new RFC5054TestVector_N(), + new RFC5054TestVector_g(), + new RFC5054TestVector_k(), + new RFC5054TestVector_v(), + new RFC5054TestVector_b(), + rule + ).string() + ) + ); + } +} diff --git a/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvSesKeyTest.java b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvSesKeyTest.java new file mode 100644 index 0000000..c0f1457 --- /dev/null +++ b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6SrvSesKeyTest.java @@ -0,0 +1,41 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import org.junit.Test; + +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_A; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_N; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_S; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_b; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_u; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_v; +import com.github.glusk2.wse.common.util.Mapping; + +public class SRP6SrvSesKeyTest { + @Test + public void testRFC5054() { + final Mapping rule = + new SRP6FromBigIntRule( + new RFC5054TestVector_N().bytes().length, + ByteOrder.BIG_ENDIAN + ); + + assertTrue( + "Computed value doesn't match the test vector.", + new RFC5054TestVector_S().string().equals( + new SRP6SrvSesKey( + new RFC5054TestVector_N(), + new RFC5054TestVector_A(), + new RFC5054TestVector_v(), + new RFC5054TestVector_u(), + new RFC5054TestVector_b(), + rule + ).string() + ) + ); + } +} diff --git a/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6VerifierTest.java b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6VerifierTest.java new file mode 100644 index 0000000..7eb9f99 --- /dev/null +++ b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/srp6/SRP6VerifierTest.java @@ -0,0 +1,36 @@ +package com.github.glusk2.wse.common.crypto.srp6; + +import static org.junit.Assert.assertTrue; + +import java.math.BigInteger; +import java.nio.ByteOrder; + +import org.junit.Test; + +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_N; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_g; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_v; +import com.github.glusk2.wse.common.crypto.srp6.rfc5054.RFC5054TestVector_x; +import com.github.glusk2.wse.common.util.Mapping; + +public class SRP6VerifierTest { + @Test + public void testRFC5054() { + final Mapping rule = + new SRP6FromBigIntRule( + new RFC5054TestVector_N().bytes().length, + ByteOrder.BIG_ENDIAN + ); + + assertTrue( + new RFC5054TestVector_v().string().equals( + new SRP6Verifier( + new RFC5054TestVector_N(), + new RFC5054TestVector_g(), + new RFC5054TestVector_x(), + rule + ).string() + ) + ); + } +} diff --git a/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/util/md/ImdSimpleCopyTest.java b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/util/md/ImdSimpleCopyTest.java new file mode 100644 index 0000000..8bea3fb --- /dev/null +++ b/wse-common/src/test/java/com/github/glusk2/wse/common/crypto/util/md/ImdSimpleCopyTest.java @@ -0,0 +1,67 @@ +package com.github.glusk2.wse.common.crypto.util.md; + +import static org.junit.Assert.*; + +import java.security.MessageDigest; + +import org.junit.Test; + +import com.github.glusk2.wse.common.crypto.util.hashing.ImdSimpleCopy; +import com.github.glusk2.wse.common.crypto.util.hashing.ImmutableMessageDigest; + +public class ImdSimpleCopyTest { + + @Test + public void testImdSimpleCopy() { + try { + new ImdSimpleCopy(MessageDigest.getInstance("SHA-1")); + } catch (Exception e) { + fail("Test failed" + e.getMessage()); + } + } + + @Test + public void testDigest() { + try { + byte[] input = { 1, 2, 3, 4 }; + + MessageDigest md = MessageDigest.getInstance("SHA-1"); + ImmutableMessageDigest imd = + new ImdSimpleCopy( + MessageDigest.getInstance("SHA-1") + ); + + md.update(input, 0, input.length); + imd = imd.update(input, 0, input.length); + + + assertArrayEquals(md.digest(), imd.digest()); + } catch (Exception e) { + fail("Test failed" + e.getMessage()); + } + } + + @Test + public void testUpdate() { + try { + byte[] input = { 1, 2, 3, 4 }; + + MessageDigest md = MessageDigest.getInstance("SHA-1"); + ImmutableMessageDigest imd = + new ImdSimpleCopy( + MessageDigest.getInstance("SHA-1") + ); + + md.update(input, 0, input.length); + md.update(input, 0, input.length); + + imd = imd.update(input, 0, input.length) + .update(input, 0, input.length); + + assertArrayEquals(md.digest(), imd.digest()); + } catch (Exception e) { + fail("Test failed" + e.getMessage()); + } + } + +}