diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/LICENSE.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/LICENSE.java index e51828668..80f1fd5e4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/LICENSE.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/LICENSE.java @@ -5,7 +5,7 @@ import com.fr.third.org.bouncycastle.util.Strings; /** * The Bouncy Castle License * - * Copyright (c) 2000-2017 The Legion Of The Bouncy Castle Inc. (http://www.bouncycastle.org) + * Copyright (c) 2000-2019 The Legion Of The Bouncy Castle Inc. (http://www.bouncycastle.org) *

* Permission is hereby granted, free of charge, to any person obtaining a copy of this software * and associated documentation files (the "Software"), to deal in the Software without restriction, @@ -25,8 +25,8 @@ import com.fr.third.org.bouncycastle.util.Strings; */ public class LICENSE { - public static String licenseText = - "Copyright (c) 2000-2017 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) " + public static final String licenseText = + "Copyright (c) 2000-2019 The Legion of the Bouncy Castle Inc. (http://www.bouncycastle.org) " + Strings.lineSeparator() + Strings.lineSeparator() + "Permission is hereby granted, free of charge, to any person obtaining a copy of this software " diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1ApplicationSpecific.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1ApplicationSpecific.java index 2b33cbeee..1a4131615 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1ApplicationSpecific.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1ApplicationSpecific.java @@ -3,6 +3,7 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; /** * Base class for an ASN.1 ApplicationSpecific object @@ -153,17 +154,17 @@ public abstract class ASN1ApplicationSpecific /* (non-Javadoc) * @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#encode(com.fr.third.org.bouncycastle.asn1.DEROutputStream) */ - void encode(ASN1OutputStream out) throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - int classBits = BERTags.APPLICATION; + int flags = BERTags.APPLICATION; if (isConstructed) { - classBits |= BERTags.CONSTRUCTED; + flags |= BERTags.CONSTRUCTED; } - out.writeEncoded(classBits, tag, octets); + out.writeEncoded(withTag, flags, tag, octets); } - + boolean asn1Equals( ASN1Primitive o) { @@ -194,25 +195,19 @@ public abstract class ASN1ApplicationSpecific // if (tagNo == 0x1f) { - tagNo = 0; - int b = input[index++] & 0xff; // X.690-0207 8.1.2.4.2 // "c) bits 7 to 1 of the first subsequent octet shall not all be zero." if ((b & 0x7f) == 0) // Note: -1 will pass { - throw new ASN1ParsingException("corrupted stream - invalid high tag number found"); + throw new IOException("corrupted stream - invalid high tag number found"); } - while ((b >= 0) && ((b & 0x80) != 0)) + while ((b & 0x80) != 0) { - tagNo |= (b & 0x7f); - tagNo <<= 7; b = input[index++] & 0xff; } - -// tagNo |= (b & 0x7f); } byte[] tmp = new byte[input.length - index + 1]; @@ -223,4 +218,29 @@ public abstract class ASN1ApplicationSpecific return tmp; } + + public String toString() + { + StringBuffer sb = new StringBuffer(); + sb.append("["); + if (isConstructed()) + { + sb.append("CONSTRUCTED "); + } + sb.append("APPLICATION "); + sb.append(Integer.toString(getApplicationTag())); + sb.append("]"); + // @todo content encoding somehow? + if (this.octets != null) + { + sb.append(" #"); + sb.append(Hex.toHexString(this.octets)); + } + else + { + sb.append(" #null"); + } + sb.append(" "); + return sb.toString(); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1BitString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1BitString.java index 6135a4878..bbaface4f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1BitString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1BitString.java @@ -1,6 +1,5 @@ package com.fr.third.org.bouncycastle.asn1; -import java.io.ByteArrayOutputStream; import java.io.EOFException; import java.io.IOException; import java.io.InputStream; @@ -58,6 +57,7 @@ public abstract class ASN1BitString return 0; } + int bits = 1; while (((val <<= 1) & 0xFF) != 0) @@ -99,6 +99,17 @@ public abstract class ASN1BitString return result; } + protected ASN1BitString(byte data, int padBits) + { + if (padBits > 7 || padBits < 0) + { + throw new IllegalArgumentException("pad bits cannot be greater than 7 or less than 0"); + } + + this.data = new byte[]{ data }; + this.padBits = padBits; + } + /** * Base constructor. * @@ -111,7 +122,7 @@ public abstract class ASN1BitString { if (data == null) { - throw new NullPointerException("data cannot be null"); + throw new NullPointerException("'data' cannot be null"); } if (data.length == 0 && padBits != 0) { @@ -133,21 +144,18 @@ public abstract class ASN1BitString */ public String getString() { - StringBuffer buf = new StringBuffer("#"); - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); + StringBuffer buf = new StringBuffer("#"); + byte[] string; try { - aOut.writeObject(this); + string = getEncoded(); } catch (IOException e) { throw new ASN1ParsingException("Internal error encoding BitString: " + e.getMessage(), e); } - byte[] string = bOut.toByteArray(); - for (int i = 0; i != string.length; i++) { buf.append(table[(string[i] >>> 4) & 0xf]); @@ -163,18 +171,16 @@ public abstract class ASN1BitString public int intValue() { int value = 0; - byte[] string = data; - - if (padBits > 0 && data.length <= 4) + int end = Math.min(4, data.length - 1); + for (int i = 0; i < end; ++i) { - string = derForm(data, padBits); + value |= (data[i] & 0xFF) << (8 * i); } - - for (int i = 0; i != string.length && i != 4; i++) + if (0 <= end && end < 4) { - value |= (string[i] & 0xff) << (8 * i); + byte der = (byte)(data[end] & (0xFF << padBits)); + value |= (der & 0xFF) << (8 * end); } - return value; } @@ -212,11 +218,22 @@ public abstract class ASN1BitString public int hashCode() { - return padBits ^ Arrays.hashCode(this.getBytes()); + int end = data.length; + if (--end < 0) + { + return 1; + } + + byte der = (byte)(data[end] & (0xFF << padBits)); + + int hc = Arrays.hashCode(data, 0, end); + hc *= 257; + hc ^= der; + return hc ^ padBits; } - protected boolean asn1Equals( - ASN1Primitive o) + boolean asn1Equals( + ASN1Primitive o) { if (!(o instanceof ASN1BitString)) { @@ -224,20 +241,46 @@ public abstract class ASN1BitString } ASN1BitString other = (ASN1BitString)o; + if (padBits != other.padBits) + { + return false; + } + byte[] a = data, b = other.data; + int end = a.length; + if (end != b.length) + { + return false; + } + if (--end < 0) + { + return true; + } + for (int i = 0; i < end; ++i) + { + if (a[i] != b[i]) + { + return false; + } + } + + byte derA = (byte)(a[end] & (0xFF << padBits)); + byte derB = (byte)(b[end] & (0xFF << padBits)); - return this.padBits == other.padBits - && Arrays.areEqual(this.getBytes(), other.getBytes()); + return derA == derB; } + /** + * @deprecated Will be hidden/removed. + */ protected static byte[] derForm(byte[] data, int padBits) { - byte[] rv = Arrays.clone(data); - // DER requires pad bits be zero - if (padBits > 0) + if (0 == data.length) { - rv[data.length - 1] &= 0xff << padBits; + return data; } - + byte[] rv = Arrays.clone(data); + // DER requires pad bits be zero + rv[data.length - 1] &= (0xFF << padBits); return rv; } @@ -261,7 +304,7 @@ public abstract class ASN1BitString if (padBits > 0 && padBits < 8) { - if (data[data.length - 1] != (byte)(data[data.length - 1] & (0xff << padBits))) + if (data[data.length - 1] != (byte)(data[data.length - 1] & (0xFF << padBits))) { return new DLBitString(data, padBits); } @@ -286,6 +329,5 @@ public abstract class ASN1BitString return new DLBitString(data, padBits); } - abstract void encode(ASN1OutputStream out) - throws IOException; + abstract void encode(ASN1OutputStream out, boolean withTag) throws IOException; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Boolean.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Boolean.java index 8bbb1d183..aaa37ad61 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Boolean.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Boolean.java @@ -2,12 +2,10 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; -import com.fr.third.org.bouncycastle.util.Arrays; - /** * Public facade of ASN.1 Boolean data. *

- * Use following to place a new instance of ASN.1 Boolean in your dataset: + * Use following to place a new instance of ASN.1 Boolean in your data: *

+ *

* * @param o object to be converted. * @return an instance of ASN1Null, or null. @@ -64,8 +73,7 @@ public abstract class ASN1Null return true; } - abstract void encode(ASN1OutputStream out) - throws IOException; + abstract void encode(ASN1OutputStream out, boolean withTag) throws IOException; public String toString() { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Object.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Object.java index fc787c10e..cb01bcb01 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Object.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Object.java @@ -2,6 +2,7 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.OutputStream; import com.fr.third.org.bouncycastle.util.Encodable; @@ -11,20 +12,26 @@ import com.fr.third.org.bouncycastle.util.Encodable; public abstract class ASN1Object implements ASN1Encodable, Encodable { + public void encodeTo(OutputStream output) throws IOException + { + ASN1OutputStream.create(output).writeObject(this); + } + + public void encodeTo(OutputStream output, String encoding) throws IOException + { + ASN1OutputStream.create(output, encoding).writeObject(this); + } + /** * Return the default BER or DER encoding for this object. * * @return BER/DER byte encoded object. * @throws java.io.IOException on encoding error. */ - public byte[] getEncoded() - throws IOException + public byte[] getEncoded() throws IOException { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - - aOut.writeObject(this); - + encodeTo(bOut); return bOut.toByteArray(); } @@ -35,30 +42,11 @@ public abstract class ASN1Object * @return byte encoded object. * @throws IOException on encoding error. */ - public byte[] getEncoded( - String encoding) - throws IOException + public byte[] getEncoded(String encoding) throws IOException { - if (encoding.equals(ASN1Encoding.DER)) - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - DEROutputStream dOut = new DEROutputStream(bOut); - - dOut.writeObject(this); - - return bOut.toByteArray(); - } - else if (encoding.equals(ASN1Encoding.DL)) - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - DLOutputStream dOut = new DLOutputStream(bOut); - - dOut.writeObject(this); - - return bOut.toByteArray(); - } - - return this.getEncoded(); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + encodeTo(bOut, encoding); + return bOut.toByteArray(); } public int hashCode() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1ObjectIdentifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1ObjectIdentifier.java index b71d2c0cc..9835bb31e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1ObjectIdentifier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1ObjectIdentifier.java @@ -33,9 +33,14 @@ public class ASN1ObjectIdentifier return (ASN1ObjectIdentifier)obj; } - if (obj instanceof ASN1Encodable && ((ASN1Encodable)obj).toASN1Primitive() instanceof ASN1ObjectIdentifier) + if (obj instanceof ASN1Encodable) { - return (ASN1ObjectIdentifier)((ASN1Encodable)obj).toASN1Primitive(); + ASN1Primitive primitive = ((ASN1Encodable)obj).toASN1Primitive(); + + if (primitive instanceof ASN1ObjectIdentifier) + { + return (ASN1ObjectIdentifier)primitive; + } } if (obj instanceof byte[]) @@ -169,7 +174,7 @@ public class ASN1ObjectIdentifier { if (identifier == null) { - throw new IllegalArgumentException("'identifier' cannot be null"); + throw new NullPointerException("'identifier' cannot be null"); } if (!isValidIdentifier(identifier)) { @@ -322,15 +327,9 @@ public class ASN1ObjectIdentifier return 1 + StreamUtil.calculateBodyLength(length) + length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - byte[] enc = getBody(); - - out.write(BERTags.OBJECT_IDENTIFIER); - out.writeLength(enc.length); - out.write(enc); + out.writeEncoded(withTag, BERTags.OBJECT_IDENTIFIER, getBody()); } public int hashCode() @@ -362,35 +361,40 @@ public class ASN1ObjectIdentifier private static boolean isValidBranchID( String branchID, int start) { - boolean periodAllowed = false; + int digitCount = 0; int pos = branchID.length(); while (--pos >= start) { char ch = branchID.charAt(pos); - // TODO Leading zeroes? - if ('0' <= ch && ch <= '9') - { - periodAllowed = true; - continue; - } - if (ch == '.') { - if (!periodAllowed) + if (0 == digitCount + || (digitCount > 1 && branchID.charAt(pos + 1) == '0')) { return false; } - periodAllowed = false; - continue; + digitCount = 0; } + else if ('0' <= ch && ch <= '9') + { + ++digitCount; + } + else + { + return false; + } + } + if (0 == digitCount + || (digitCount > 1 && branchID.charAt(pos + 1) == '0')) + { return false; } - return periodAllowed; + return true; } private static boolean isValidIdentifier( diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1OctetString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1OctetString.java index 7a91ca9e8..d74c6c6e0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1OctetString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1OctetString.java @@ -105,28 +105,78 @@ public abstract class ASN1OctetString /** * return an Octet String from a tagged object. * - * @param obj the tagged object holding the object we want. + * @param taggedObject the tagged object holding the object we want. * @param explicit true if the object is meant to be explicitly * tagged false otherwise. * @exception IllegalArgumentException if the tagged object cannot * be converted. */ public static ASN1OctetString getInstance( - ASN1TaggedObject obj, + ASN1TaggedObject taggedObject, boolean explicit) { - ASN1Primitive o = obj.getObject(); + if (explicit) + { + if (!taggedObject.isExplicit()) + { + throw new IllegalArgumentException("object implicit - explicit expected."); + } + + return getInstance(taggedObject.getObject()); + } + + ASN1Primitive o = taggedObject.getObject(); + + /* + * constructed object which appears to be explicitly tagged and it's really implicit means + * we have to add the surrounding octet string. + */ + if (taggedObject.isExplicit()) + { + ASN1OctetString singleSegment = ASN1OctetString.getInstance(o); + + if (taggedObject instanceof BERTaggedObject) + { + return new BEROctetString(new ASN1OctetString[]{ singleSegment }); + } + + // TODO Should really be similar to the BERTaggedObject case above: +// return new DLOctetString(new ASN1OctetString[]{ singleSegment }); + return (ASN1OctetString)new BEROctetString(new ASN1OctetString[]{ singleSegment }).toDLObject(); + } - if (explicit || o instanceof ASN1OctetString) + if (o instanceof ASN1OctetString) { - return getInstance(o); + ASN1OctetString s = (ASN1OctetString)o; + + if (taggedObject instanceof BERTaggedObject) + { + return s; + } + + return (ASN1OctetString)s.toDLObject(); } - else + + /* + * in this case the parser returns a sequence, convert it into an octet string. + */ + if (o instanceof ASN1Sequence) { - return BEROctetString.fromSequence(ASN1Sequence.getInstance(o)); + ASN1Sequence s = (ASN1Sequence)o; + + if (taggedObject instanceof BERTaggedObject) + { + return BEROctetString.fromSequence(s); + } + + // TODO Should really be similar to the BERTaggedObject case above: +// return DLOctetString.fromSequence(s); + return (ASN1OctetString)BEROctetString.fromSequence(s).toDLObject(); } + + throw new IllegalArgumentException("unknown object in getInstance: " + taggedObject.getClass().getName()); } - + /** * return an Octet String from the given object. * @@ -174,7 +224,7 @@ public abstract class ASN1OctetString { if (string == null) { - throw new NullPointerException("string cannot be null"); + throw new NullPointerException("'string' cannot be null"); } this.string = string; } @@ -242,11 +292,10 @@ public abstract class ASN1OctetString return new DEROctetString(string); } - abstract void encode(ASN1OutputStream out) - throws IOException; + abstract void encode(ASN1OutputStream out, boolean withTag) throws IOException; public String toString() { - return "#"+ Strings.fromByteArray(Hex.encode(string)); + return "#" + Strings.fromByteArray(Hex.encode(string)); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1OutputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1OutputStream.java index cc59b5838..c8269ca0f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1OutputStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1OutputStream.java @@ -2,21 +2,45 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; import java.io.OutputStream; +import java.util.Enumeration; /** * Stream that produces output based on the default encoding for the passed in objects. */ public class ASN1OutputStream { + public static ASN1OutputStream create(OutputStream out) + { + return new ASN1OutputStream(out); + } + + public static ASN1OutputStream create(OutputStream out, String encoding) + { + if (encoding.equals(ASN1Encoding.DER)) + { + return new DEROutputStream(out); + } + else if (encoding.equals(ASN1Encoding.DL)) + { + return new DLOutputStream(out); + } + else + { + return new ASN1OutputStream(out); + } + } + private OutputStream os; - public ASN1OutputStream( - OutputStream os) + /** + * @deprecated Use {@link ASN1OutputStream#create(OutputStream)} instead. + */ + public ASN1OutputStream(OutputStream os) { this.os = os; } - void writeLength( + final void writeLength( int length) throws IOException { @@ -43,37 +67,173 @@ public class ASN1OutputStream } } - void write(int b) + final void write(int b) throws IOException { os.write(b); } - void write(byte[] bytes) + final void write(byte[] bytes, int off, int len) throws IOException { - os.write(bytes); + os.write(bytes, off, len); } - void write(byte[] bytes, int off, int len) + final void writeElements(ASN1Encodable[] elements) throws IOException { - os.write(bytes, off, len); + int count = elements.length; + for (int i = 0; i < count; ++i) + { + ASN1Primitive primitive = elements[i].toASN1Primitive(); + + writePrimitive(primitive, true); + } + } + + final void writeElements(Enumeration elements) + throws IOException + { + while (elements.hasMoreElements()) + { + ASN1Primitive primitive = ((ASN1Encodable)elements.nextElement()).toASN1Primitive(); + + writePrimitive(primitive, true); + } } - void writeEncoded( + final void writeEncoded( + boolean withTag, int tag, - byte[] bytes) + byte contents) throws IOException { - write(tag); - writeLength(bytes.length); - write(bytes); + if (withTag) + { + write(tag); + } + writeLength(1); + write(contents); } - void writeTag(int flags, int tagNo) + final void writeEncoded( + boolean withTag, + int tag, + byte[] contents) throws IOException { + if (withTag) + { + write(tag); + } + writeLength(contents.length); + write(contents, 0, contents.length); + } + + final void writeEncoded( + boolean withTag, + int tag, + byte[] contents, + int contentsOff, + int contentsLen) + throws IOException + { + if (withTag) + { + write(tag); + } + writeLength(contentsLen); + write(contents, contentsOff, contentsLen); + } + + final void writeEncoded( + boolean withTag, + int tag, + byte headByte, + byte[] tailBytes) + throws IOException + { + if (withTag) + { + write(tag); + } + writeLength(1 + tailBytes.length); + write(headByte); + write(tailBytes, 0, tailBytes.length); + } + + final void writeEncoded( + boolean withTag, + int tag, + byte headByte, + byte[] body, + int bodyOff, + int bodyLen, + byte tailByte) + throws IOException + { + if (withTag) + { + write(tag); + } + writeLength(2 + bodyLen); + write(headByte); + write(body, bodyOff, bodyLen); + write(tailByte); + } + + final void writeEncoded(boolean withTag, int flags, int tagNo, byte[] contents) + throws IOException + { + writeTag(withTag, flags, tagNo); + writeLength(contents.length); + write(contents, 0, contents.length); + } + + final void writeEncodedIndef(boolean withTag, int flags, int tagNo, byte[] contents) + throws IOException + { + writeTag(withTag, flags, tagNo); + write(0x80); + write(contents, 0, contents.length); + write(0x00); + write(0x00); + } + + final void writeEncodedIndef(boolean withTag, int tag, ASN1Encodable[] elements) + throws IOException + { + if (withTag) + { + write(tag); + } + write(0x80); + writeElements(elements); + write(0x00); + write(0x00); + } + + final void writeEncodedIndef(boolean withTag, int tag, Enumeration elements) + throws IOException + { + if (withTag) + { + write(tag); + } + write(0x80); + writeElements(elements); + write(0x00); + write(0x00); + } + + final void writeTag(boolean withTag, int flags, int tagNo) + throws IOException + { + if (!withTag) + { + return; + } + if (tagNo < 31) { write(flags | tagNo); @@ -104,46 +264,41 @@ public class ASN1OutputStream } } - void writeEncoded(int flags, int tagNo, byte[] bytes) - throws IOException - { - writeTag(flags, tagNo); - writeLength(bytes.length); - write(bytes); - } - + /** + * @deprecated Will be removed. + */ protected void writeNull() throws IOException { - os.write(BERTags.NULL); - os.write(0x00); + write(BERTags.NULL); + write(0x00); } - public void writeObject( - ASN1Encodable obj) - throws IOException + public void writeObject(ASN1Encodable obj) throws IOException { - if (obj != null) - { - obj.toASN1Primitive().encode(this); - } - else + if (null == obj) { throw new IOException("null object detected"); } + + writePrimitive(obj.toASN1Primitive(), true); + flushInternal(); } - void writeImplicitObject(ASN1Primitive obj) - throws IOException + public void writeObject(ASN1Primitive primitive) throws IOException { - if (obj != null) - { - obj.encode(new ImplicitOutputStream(os)); - } - else + if (null == primitive) { throw new IOException("null object detected"); } + + writePrimitive(primitive, true); + flushInternal(); + } + + void writePrimitive(ASN1Primitive primitive, boolean withTag) throws IOException + { + primitive.encode(this, withTag); } public void close() @@ -158,37 +313,19 @@ public class ASN1OutputStream os.flush(); } - ASN1OutputStream getDERSubStream() + void flushInternal() + throws IOException { - return new DEROutputStream(os); + // Placeholder to support future internal buffering } - ASN1OutputStream getDLSubStream() + DEROutputStream getDERSubStream() { - return new DLOutputStream(os); + return new DEROutputStream(os); } - private class ImplicitOutputStream - extends ASN1OutputStream + ASN1OutputStream getDLSubStream() { - private boolean first = true; - - public ImplicitOutputStream(OutputStream os) - { - super(os); - } - - public void write(int b) - throws IOException - { - if (first) - { - first = false; - } - else - { - super.write(b); - } - } + return new DLOutputStream(os); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Primitive.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Primitive.java index 7c9db6b67..e8459859a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Primitive.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Primitive.java @@ -1,6 +1,7 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; +import java.io.OutputStream; /** * Base class for ASN.1 primitive objects. These are the actual objects used to generate byte encodings. @@ -10,7 +11,16 @@ public abstract class ASN1Primitive { ASN1Primitive() { + } + + public void encodeTo(OutputStream output) throws IOException + { + ASN1OutputStream.create(output).writeObject(this); + } + public void encodeTo(OutputStream output, String encoding) throws IOException + { + ASN1OutputStream.create(output, encoding).writeObject(this); } /** @@ -52,7 +62,17 @@ public abstract class ASN1Primitive return (o instanceof ASN1Encodable) && asn1Equals(((ASN1Encodable)o).toASN1Primitive()); } - public ASN1Primitive toASN1Primitive() + public final boolean equals(ASN1Encodable other) + { + return this == other || (null != other && asn1Equals(other.toASN1Primitive())); + } + + public final boolean equals(ASN1Primitive other) + { + return this == other || asn1Equals(other); + } + + public final ASN1Primitive toASN1Primitive() { return this; } @@ -92,7 +112,7 @@ public abstract class ASN1Primitive */ abstract int encodedLength() throws IOException; - abstract void encode(ASN1OutputStream out) throws IOException; + abstract void encode(ASN1OutputStream out, boolean withTag) throws IOException; /** * Equality (similarity) comparison for two ASN1Primitive objects. diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Sequence.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Sequence.java index a3331face..68313a1ae 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Sequence.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Sequence.java @@ -3,7 +3,7 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; import java.util.Enumeration; import java.util.Iterator; -import java.util.Vector; +import java.util.NoSuchElementException; import com.fr.third.org.bouncycastle.util.Arrays; @@ -60,7 +60,8 @@ public abstract class ASN1Sequence extends ASN1Primitive implements com.fr.third.org.bouncycastle.util.Iterable { - protected Vector seq = new Vector(); + // NOTE: Only non-final to support LazyEncodedSequence + ASN1Encodable[] elements; /** * Return an ASN1Sequence from the given object. @@ -114,7 +115,7 @@ public abstract class ASN1Sequence * dealing with implicitly tagged sequences you really should * be using this method. * - * @param obj the tagged object. + * @param taggedObject the tagged object. * @param explicit true if the object is meant to be explicitly tagged, * false otherwise. * @exception IllegalArgumentException if the tagged object cannot @@ -122,48 +123,48 @@ public abstract class ASN1Sequence * @return an ASN1Sequence instance. */ public static ASN1Sequence getInstance( - ASN1TaggedObject obj, + ASN1TaggedObject taggedObject, boolean explicit) { if (explicit) { - if (!obj.isExplicit()) + if (!taggedObject.isExplicit()) { throw new IllegalArgumentException("object implicit - explicit expected."); } - return ASN1Sequence.getInstance(obj.getObject().toASN1Primitive()); + return getInstance(taggedObject.getObject()); } - else + + ASN1Primitive o = taggedObject.getObject(); + + /* + * constructed object which appears to be explicitly tagged when it should be implicit means + * we have to add the surrounding sequence. + */ + if (taggedObject.isExplicit()) { - ASN1Primitive o = obj.getObject(); - - // - // constructed object which appears to be explicitly tagged - // when it should be implicit means we have to add the - // surrounding sequence. - // - if (obj.isExplicit()) + if (taggedObject instanceof BERTaggedObject) { - if (obj instanceof BERTaggedObject) - { - return new BERSequence(o); - } - else - { - return new DLSequence(o); - } + return new BERSequence(o); } - else + + return new DLSequence(o); + } + + if (o instanceof ASN1Sequence) + { + ASN1Sequence s = (ASN1Sequence)o; + + if (taggedObject instanceof BERTaggedObject) { - if (o instanceof ASN1Sequence) - { - return (ASN1Sequence)o; - } + return s; } + + return (ASN1Sequence)s.toDLObject(); } - throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + throw new IllegalArgumentException("unknown object in getInstance: " + taggedObject.getClass().getName()); } /** @@ -171,79 +172,105 @@ public abstract class ASN1Sequence */ protected ASN1Sequence() { + this.elements = ASN1EncodableVector.EMPTY_ELEMENTS; } /** * Create a SEQUENCE containing one object. * @param obj the object to be put in the SEQUENCE. */ - protected ASN1Sequence( - ASN1Encodable obj) + protected ASN1Sequence(ASN1Encodable element) { - seq.addElement(obj); + if (null == element) + { + throw new NullPointerException("'element' cannot be null"); + } + + this.elements = new ASN1Encodable[]{ element }; } /** * Create a SEQUENCE containing a vector of objects. - * @param v the vector of objects to be put in the SEQUENCE. + * @param elementVector the vector of objects to be put in the SEQUENCE. */ - protected ASN1Sequence( - ASN1EncodableVector v) + protected ASN1Sequence(ASN1EncodableVector elementVector) { - for (int i = 0; i != v.size(); i++) + if (null == elementVector) { - seq.addElement(v.get(i)); + throw new NullPointerException("'elementVector' cannot be null"); } + + this.elements = elementVector.takeElements(); } /** * Create a SEQUENCE containing an array of objects. * @param array the array of objects to be put in the SEQUENCE. */ - protected ASN1Sequence( - ASN1Encodable[] array) + protected ASN1Sequence(ASN1Encodable[] elements) { - for (int i = 0; i != array.length; i++) + if (Arrays.isNullOrContainsNull(elements)) { - seq.addElement(array[i]); + throw new NullPointerException("'elements' cannot be null, or contain null"); } + + this.elements = ASN1EncodableVector.cloneElements(elements); } - public ASN1Encodable[] toArray() + ASN1Sequence(ASN1Encodable[] elements, boolean clone) { - ASN1Encodable[] values = new ASN1Encodable[this.size()]; + this.elements = clone ? ASN1EncodableVector.cloneElements(elements) : elements; + } - for (int i = 0; i != this.size(); i++) - { - values[i] = this.getObjectAt(i); - } + public ASN1Encodable[] toArray() + { + return ASN1EncodableVector.cloneElements(elements); + } - return values; + ASN1Encodable[] toArrayInternal() + { + return elements; } public Enumeration getObjects() { - return seq.elements(); + return new Enumeration() + { + private int pos = 0; + + public boolean hasMoreElements() + { + return pos < elements.length; + } + + public Object nextElement() + { + if (pos >= elements.length) + { + throw new NoSuchElementException("ASN1Sequence Enumeration"); + } + return elements[pos++]; + } + }; } public ASN1SequenceParser parser() { - final ASN1Sequence outer = this; + // NOTE: Call size() here to 'force' a LazyEncodedSequence + final int count = size(); return new ASN1SequenceParser() { - private final int max = size(); - - private int index; + private int pos = 0; public ASN1Encodable readObject() throws IOException { - if (index == max) + if (count == pos) { return null; } - - ASN1Encodable obj = getObjectAt(index++); + + ASN1Encodable obj = elements[pos++]; if (obj instanceof ASN1Sequence) { return ((ASN1Sequence)obj).parser(); @@ -258,12 +285,12 @@ public abstract class ASN1Sequence public ASN1Primitive getLoadedObject() { - return outer; + return ASN1Sequence.this; } - + public ASN1Primitive toASN1Primitive() { - return outer; + return ASN1Sequence.this; } }; } @@ -274,10 +301,9 @@ public abstract class ASN1Sequence * @param index the sequence number (starting at zero) of the object * @return the object at the sequence position indicated by index. */ - public ASN1Encodable getObjectAt( - int index) + public ASN1Encodable getObjectAt(int index) { - return (ASN1Encodable)seq.elementAt(index); + return elements[index]; } /** @@ -287,80 +313,60 @@ public abstract class ASN1Sequence */ public int size() { - return seq.size(); + return elements.length; } public int hashCode() { - Enumeration e = this.getObjects(); - int hashCode = size(); +// return Arrays.hashCode(elements); + int i = elements.length; + int hc = i + 1; - while (e.hasMoreElements()) + while (--i >= 0) { - Object o = getNext(e); - hashCode *= 17; - - hashCode ^= o.hashCode(); + hc *= 257; + hc ^= elements[i].toASN1Primitive().hashCode(); } - return hashCode; + return hc; } - boolean asn1Equals( - ASN1Primitive o) + boolean asn1Equals(ASN1Primitive other) { - if (!(o instanceof ASN1Sequence)) + if (!(other instanceof ASN1Sequence)) { return false; } - - ASN1Sequence other = (ASN1Sequence)o; - if (this.size() != other.size()) + ASN1Sequence that = (ASN1Sequence)other; + + int count = this.size(); + if (that.size() != count) { return false; } - Enumeration s1 = this.getObjects(); - Enumeration s2 = other.getObjects(); - - while (s1.hasMoreElements()) + for (int i = 0; i < count; ++i) { - ASN1Encodable obj1 = getNext(s1); - ASN1Encodable obj2 = getNext(s2); - - ASN1Primitive o1 = obj1.toASN1Primitive(); - ASN1Primitive o2 = obj2.toASN1Primitive(); + ASN1Primitive p1 = this.elements[i].toASN1Primitive(); + ASN1Primitive p2 = that.elements[i].toASN1Primitive(); - if (o1 == o2 || o1.equals(o2)) + if (p1 != p2 && !p1.asn1Equals(p2)) { - continue; + return false; } - - return false; } return true; } - private ASN1Encodable getNext(Enumeration e) - { - ASN1Encodable encObj = (ASN1Encodable)e.nextElement(); - - return encObj; - } - /** * Change current SEQUENCE object to be encoded as {@link DERSequence}. * This is part of Distinguished Encoding Rules form serialization. */ ASN1Primitive toDERObject() { - ASN1Sequence derSeq = new DERSequence(); - - derSeq.seq = this.seq; - - return derSeq; + return new DERSequence(elements, false); } /** @@ -369,11 +375,7 @@ public abstract class ASN1Sequence */ ASN1Primitive toDLObject() { - ASN1Sequence dlSeq = new DLSequence(); - - dlSeq.seq = this.seq; - - return dlSeq; + return new DLSequence(elements, false); } boolean isConstructed() @@ -381,16 +383,34 @@ public abstract class ASN1Sequence return true; } - abstract void encode(ASN1OutputStream out) - throws IOException; + abstract void encode(ASN1OutputStream out, boolean withTag) throws IOException; public String toString() { - return seq.toString(); + // NOTE: Call size() here to 'force' a LazyEncodedSequence + int count = size(); + if (0 == count) + { + return "[]"; + } + + StringBuffer sb = new StringBuffer(); + sb.append('['); + for (int i = 0;;) + { + sb.append(elements[i]); + if (++i >= count) + { + break; + } + sb.append(", "); + } + sb.append(']'); + return sb.toString(); } public Iterator iterator() { - return new Arrays.Iterator(toArray()); + return new Arrays.Iterator(elements); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Set.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Set.java index e2fde8bc8..96b96b3c2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Set.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1Set.java @@ -3,7 +3,7 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; import java.util.Enumeration; import java.util.Iterator; -import java.util.Vector; +import java.util.NoSuchElementException; import com.fr.third.org.bouncycastle.util.Arrays; @@ -98,8 +98,8 @@ public abstract class ASN1Set extends ASN1Primitive implements com.fr.third.org.bouncycastle.util.Iterable { - private Vector set = new Vector(); - private boolean isSorted = false; + protected final ASN1Encodable[] elements; + protected final boolean isSorted; /** * return an ASN1Set from the given object. @@ -153,7 +153,7 @@ public abstract class ASN1Set * dealing with implicitly tagged sets you really should * be using this method. * - * @param obj the tagged object. + * @param taggedObject the tagged object. * @param explicit true if the object is meant to be explicitly tagged * false otherwise. * @exception IllegalArgumentException if the tagged object cannot @@ -161,125 +161,164 @@ public abstract class ASN1Set * @return an ASN1Set instance. */ public static ASN1Set getInstance( - ASN1TaggedObject obj, + ASN1TaggedObject taggedObject, boolean explicit) { if (explicit) { - if (!obj.isExplicit()) + if (!taggedObject.isExplicit()) { throw new IllegalArgumentException("object implicit - explicit expected."); } - return (ASN1Set)obj.getObject(); + return getInstance(taggedObject.getObject()); } - else + + ASN1Primitive o = taggedObject.getObject(); + + /* + * constructed object which appears to be explicitly tagged and it's really implicit means + * we have to add the surrounding set. + */ + if (taggedObject.isExplicit()) { - ASN1Primitive o = obj.getObject(); - - // - // constructed object which appears to be explicitly tagged - // and it's really implicit means we have to add the - // surrounding set. - // - if (obj.isExplicit()) + if (taggedObject instanceof BERTaggedObject) { - if (obj instanceof BERTaggedObject) - { - return new BERSet(o); - } - else - { - return new DLSet(o); - } + return new BERSet(o); } - else + + return new DLSet(o); + } + + if (o instanceof ASN1Set) + { + ASN1Set s = (ASN1Set)o; + + if (taggedObject instanceof BERTaggedObject) { - if (o instanceof ASN1Set) - { - return (ASN1Set)o; - } + return s; + } - // - // in this case the parser returns a sequence, convert it - // into a set. - // - if (o instanceof ASN1Sequence) - { - ASN1Sequence s = (ASN1Sequence)o; - - if (obj instanceof BERTaggedObject) - { - return new BERSet(s.toArray()); - } - else - { - return new DLSet(s.toArray()); - } - } + return (ASN1Set)s.toDLObject(); + } + + /* + * in this case the parser returns a sequence, convert it into a set. + */ + if (o instanceof ASN1Sequence) + { + ASN1Sequence s = (ASN1Sequence)o; + + // NOTE: Will force() a LazyEncodedSequence + ASN1Encodable[] elements = s.toArrayInternal(); + + if (taggedObject instanceof BERTaggedObject) + { + return new BERSet(false, elements); } + + return new DLSet(false, elements); } - throw new IllegalArgumentException("unknown object in getInstance: " + obj.getClass().getName()); + throw new IllegalArgumentException("unknown object in getInstance: " + taggedObject.getClass().getName()); } protected ASN1Set() { + this.elements = ASN1EncodableVector.EMPTY_ELEMENTS; + this.isSorted = true; } /** * Create a SET containing one object - * @param obj object to be added to the SET. + * @param element object to be added to the SET. */ - protected ASN1Set( - ASN1Encodable obj) + protected ASN1Set(ASN1Encodable element) { - set.addElement(obj); + if (null == element) + { + throw new NullPointerException("'element' cannot be null"); + } + + this.elements = new ASN1Encodable[]{ element }; + this.isSorted = true; } /** * Create a SET containing a vector of objects. - * @param v a vector of objects to make up the SET. + * @param elementVector a vector of objects to make up the SET. * @param doSort true if should be sorted DER style, false otherwise. */ - protected ASN1Set( - ASN1EncodableVector v, - boolean doSort) + protected ASN1Set(ASN1EncodableVector elementVector, boolean doSort) { - for (int i = 0; i != v.size(); i++) + if (null == elementVector) { - set.addElement(v.get(i)); + throw new NullPointerException("'elementVector' cannot be null"); } - if (doSort) + ASN1Encodable[] tmp; + if (doSort && elementVector.size() >= 2) { - this.sort(); + tmp = elementVector.copyElements(); + sort(tmp); } + else + { + tmp = elementVector.takeElements(); + } + + this.elements = tmp; + this.isSorted = doSort || tmp.length < 2; } /** * Create a SET containing an array of objects. - * @param array an array of objects to make up the SET. + * @param elements an array of objects to make up the SET. * @param doSort true if should be sorted DER style, false otherwise. */ - protected ASN1Set( - ASN1Encodable[] array, - boolean doSort) + protected ASN1Set(ASN1Encodable[] elements, boolean doSort) { - for (int i = 0; i != array.length; i++) + if (Arrays.isNullOrContainsNull(elements)) { - set.addElement(array[i]); + throw new NullPointerException("'elements' cannot be null, or contain null"); } - if (doSort) + ASN1Encodable[] tmp = ASN1EncodableVector.cloneElements(elements); + if (doSort && tmp.length >= 2) { - this.sort(); + sort(tmp); } + + this.elements = tmp; + this.isSorted = doSort || tmp.length < 2; + } + + ASN1Set(boolean isSorted, ASN1Encodable[] elements) + { + this.elements = elements; + this.isSorted = isSorted || elements.length < 2; } public Enumeration getObjects() { - return set.elements(); + return new Enumeration() + { + private int pos = 0; + + public boolean hasMoreElements() + { + return pos < elements.length; + } + + public Object nextElement() + { + if (pos >= elements.length) + { + throw new NoSuchElementException("ASN1Set Enumeration"); + } + return elements[pos++]; + } + }; } /** @@ -288,10 +327,9 @@ public abstract class ASN1Set * @param index the set number (starting at zero) of the object * @return the object at the set position indicated by index. */ - public ASN1Encodable getObjectAt( - int index) + public ASN1Encodable getObjectAt(int index) { - return (ASN1Encodable)set.elementAt(index); + return elements[index]; } /** @@ -301,39 +339,30 @@ public abstract class ASN1Set */ public int size() { - return set.size(); + return elements.length; } public ASN1Encodable[] toArray() { - ASN1Encodable[] values = new ASN1Encodable[this.size()]; - - for (int i = 0; i != this.size(); i++) - { - values[i] = this.getObjectAt(i); - } - - return values; + return ASN1EncodableVector.cloneElements(elements); } public ASN1SetParser parser() { - final ASN1Set outer = this; + final int count = size(); return new ASN1SetParser() { - private final int max = size(); - - private int index; + private int pos = 0; public ASN1Encodable readObject() throws IOException { - if (index == max) + if (count == pos) { return null; } - ASN1Encodable obj = getObjectAt(index++); + ASN1Encodable obj = elements[pos++]; if (obj instanceof ASN1Sequence) { return ((ASN1Sequence)obj).parser(); @@ -348,30 +377,29 @@ public abstract class ASN1Set public ASN1Primitive getLoadedObject() { - return outer; + return ASN1Set.this; } public ASN1Primitive toASN1Primitive() { - return outer; + return ASN1Set.this; } }; } public int hashCode() { - Enumeration e = this.getObjects(); - int hashCode = size(); +// return Arrays.hashCode(elements); + int i = elements.length; + int hc = i + 1; - while (e.hasMoreElements()) + // NOTE: Order-independent contribution of elements to avoid sorting + while (--i >= 0) { - Object o = getNext(e); - hashCode *= 17; - - hashCode ^= o.hashCode(); + hc += elements[i].toASN1Primitive().hashCode(); } - return hashCode; + return hc; } /** @@ -380,31 +408,18 @@ public abstract class ASN1Set */ ASN1Primitive toDERObject() { + ASN1Encodable[] tmp; if (isSorted) { - ASN1Set derSet = new DERSet(); - - derSet.set = this.set; - - return derSet; + tmp = elements; } else { - Vector v = new Vector(); - - for (int i = 0; i != set.size(); i++) - { - v.addElement(set.elementAt(i)); - } - - ASN1Set derSet = new DERSet(); - - derSet.set = v; - - derSet.sort(); - - return derSet; + tmp = (ASN1Encodable[])elements.clone(); + sort(tmp); } + + return new DERSet(true, tmp); } /** @@ -413,83 +428,77 @@ public abstract class ASN1Set */ ASN1Primitive toDLObject() { - ASN1Set derSet = new DLSet(); - - derSet.set = this.set; - - return derSet; + return new DLSet(isSorted, elements); } - boolean asn1Equals( - ASN1Primitive o) + boolean asn1Equals(ASN1Primitive other) { - if (!(o instanceof ASN1Set)) + if (!(other instanceof ASN1Set)) { return false; } - ASN1Set other = (ASN1Set)o; + ASN1Set that = (ASN1Set)other; - if (this.size() != other.size()) + int count = this.size(); + if (that.size() != count) { return false; } - Enumeration s1 = this.getObjects(); - Enumeration s2 = other.getObjects(); + DERSet dis = (DERSet)this.toDERObject(); + DERSet dat = (DERSet)that.toDERObject(); - while (s1.hasMoreElements()) + for (int i = 0; i < count; ++i) { - ASN1Encodable obj1 = getNext(s1); - ASN1Encodable obj2 = getNext(s2); + ASN1Primitive p1 = dis.elements[i].toASN1Primitive(); + ASN1Primitive p2 = dat.elements[i].toASN1Primitive(); - ASN1Primitive o1 = obj1.toASN1Primitive(); - ASN1Primitive o2 = obj2.toASN1Primitive(); - - if (o1 == o2 || o1.equals(o2)) + if (p1 != p2 && !p1.asn1Equals(p2)) { - continue; + return false; } - - return false; } return true; } - private ASN1Encodable getNext(Enumeration e) + boolean isConstructed() { - ASN1Encodable encObj = (ASN1Encodable)e.nextElement(); + return true; + } + + abstract void encode(ASN1OutputStream out, boolean withTag) throws IOException; - // unfortunately null was allowed as a substitute for DER null - if (encObj == null) + public String toString() + { + int count = size(); + if (0 == count) { - return DERNull.INSTANCE; + return "[]"; } - return encObj; - } - - /** - * return true if a <= b (arrays are assumed padded with zeros). - */ - private boolean lessThanOrEqual( - byte[] a, - byte[] b) - { - int len = Math.min(a.length, b.length); - for (int i = 0; i != len; ++i) + StringBuffer sb = new StringBuffer(); + sb.append('['); + for (int i = 0;;) { - if (a[i] != b[i]) + sb.append(elements[i]); + if (++i >= count) { - return (a[i] & 0xff) < (b[i] & 0xff); + break; } + sb.append(", "); } - return len == a.length; + sb.append(']'); + return sb.toString(); + } + + public Iterator iterator() + { + return new Arrays.Iterator(toArray()); } - private byte[] getDEREncoded( - ASN1Encodable obj) + private static byte[] getDEREncoded(ASN1Encodable obj) { try { @@ -501,67 +510,98 @@ public abstract class ASN1Set } } - protected void sort() + /** + * return true if a <= b (arrays are assumed padded with zeros). + */ + private static boolean lessThanOrEqual(byte[] a, byte[] b) { - if (!isSorted) +// assert a.length >= 2 && b.length >= 2; + + /* + * NOTE: Set elements in DER encodings are ordered first according to their tags (class and + * number); the CONSTRUCTED bit is not part of the tag. + * + * For SET-OF, this is unimportant. All elements have the same tag and DER requires them to + * either all be in constructed form or all in primitive form, according to that tag. The + * elements are effectively ordered according to their content octets. + * + * For SET, the elements will have distinct tags, and each will be in constructed or + * primitive form accordingly. Failing to ignore the CONSTRUCTED bit could therefore lead to + * ordering inversions. + */ + int a0 = a[0] & ~BERTags.CONSTRUCTED; + int b0 = b[0] & ~BERTags.CONSTRUCTED; + if (a0 != b0) + { + return a0 < b0; + } + + int last = Math.min(a.length, b.length) - 1; + for (int i = 1; i < last; ++i) { - isSorted = true; - if (set.size() > 1) + if (a[i] != b[i]) { - boolean swapped = true; - int lastSwap = set.size() - 1; + return (a[i] & 0xFF) < (b[i] & 0xFF); + } + } + return (a[last] & 0xFF) <= (b[last] & 0xFF); + } - while (swapped) - { - int index = 0; - int swapIndex = 0; - byte[] a = getDEREncoded((ASN1Encodable)set.elementAt(0)); + private static void sort(ASN1Encodable[] t) + { + int count = t.length; + if (count < 2) + { + return; + } - swapped = false; + ASN1Encodable eh = t[0], ei = t[1]; + byte[] bh = getDEREncoded(eh), bi = getDEREncoded(ei);; - while (index != lastSwap) - { - byte[] b = getDEREncoded((ASN1Encodable)set.elementAt(index + 1)); + if (lessThanOrEqual(bi, bh)) + { + ASN1Encodable et = ei; ei = eh; eh = et; + byte[] bt = bi; bi = bh; bh = bt; + } - if (lessThanOrEqual(a, b)) - { - a = b; - } - else - { - Object o = set.elementAt(index); + for (int i = 2; i < count; ++i) + { + ASN1Encodable e2 = t[i]; + byte[] b2 = getDEREncoded(e2); - set.setElementAt(set.elementAt(index + 1), index); - set.setElementAt(o, index + 1); + if (lessThanOrEqual(bi, b2)) + { + t[i - 2] = eh; + eh = ei; bh = bi; + ei = e2; bi = b2; + continue; + } - swapped = true; - swapIndex = index; - } + if (lessThanOrEqual(bh, b2)) + { + t[i - 2] = eh; + eh = e2; bh = b2; + continue; + } - index++; - } + int j = i - 1; + while (--j > 0) + { + ASN1Encodable e1 = t[j - 1]; + byte[] b1 = getDEREncoded(e1); - lastSwap = swapIndex; + if (lessThanOrEqual(b1, b2)) + { + break; } - } - } - } - - boolean isConstructed() - { - return true; - } - abstract void encode(ASN1OutputStream out) - throws IOException; + t[j] = e1; + } - public String toString() - { - return set.toString(); - } + t[j] = e2; + } - public Iterator iterator() - { - return new Arrays.Iterator(toArray()); + t[count - 2] = eh; + t[count - 1] = ei; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1StreamParser.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1StreamParser.java index 00a3b3cd0..d090c0320 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1StreamParser.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1StreamParser.java @@ -72,9 +72,9 @@ public class ASN1StreamParser switch (tag) { case BERTags.SET: - return new DERSetParser(this); + return new DLSetParser(this); case BERTags.SEQUENCE: - return new DERSequenceParser(this); + return new DLSequenceParser(this); case BERTags.OCTET_STRING: return new BEROctetStringParser(this); } @@ -101,7 +101,7 @@ public class ASN1StreamParser { // Note: !CONSTRUCTED => IMPLICIT DefiniteLengthInputStream defIn = (DefiniteLengthInputStream)_in; - return new DERTaggedObject(false, tag, new DEROctetString(defIn.toByteArray())); + return new DLTaggedObject(false, tag, new DEROctetString(defIn.toByteArray())); } ASN1EncodableVector v = readVector(); @@ -114,8 +114,8 @@ public class ASN1StreamParser } return v.size() == 1 - ? new DERTaggedObject(true, tag, v.get(0)) - : new DERTaggedObject(false, tag, DERFactory.createSequence(v)); + ? new DLTaggedObject(true, tag, v.get(0)) + : new DLTaggedObject(false, tag, DLFactory.createSequence(v)); } public ASN1Encodable readObject() @@ -142,7 +142,8 @@ public class ASN1StreamParser // // calculate length // - int length = ASN1InputStream.readLength(_in, _limit); + int length = ASN1InputStream.readLength(_in, _limit, + tagNo == BERTags.OCTET_STRING || tagNo == BERTags.SEQUENCE || tagNo == BERTags.SET || tagNo == BERTags.EXTERNAL); if (length < 0) // indefinite-length method { @@ -168,11 +169,11 @@ public class ASN1StreamParser } else { - DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length); + DefiniteLengthInputStream defIn = new DefiniteLengthInputStream(_in, length, _limit); if ((tag & BERTags.APPLICATION) != 0) { - return new DERApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); + return new DLApplicationSpecific(isConstructed, tagNo, defIn.toByteArray()); } if ((tag & BERTags.TAGGED) != 0) @@ -191,9 +192,9 @@ public class ASN1StreamParser // return new BEROctetStringParser(new ASN1StreamParser(defIn)); case BERTags.SEQUENCE: - return new DERSequenceParser(new ASN1StreamParser(defIn)); + return new DLSequenceParser(new ASN1StreamParser(defIn)); case BERTags.SET: - return new DERSetParser(new ASN1StreamParser(defIn)); + return new DLSetParser(new ASN1StreamParser(defIn)); case BERTags.EXTERNAL: return new DERExternalParser(new ASN1StreamParser(defIn)); default: @@ -229,10 +230,14 @@ public class ASN1StreamParser ASN1EncodableVector readVector() throws IOException { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1Encodable obj = readObject(); + if (null == obj) + { + return new ASN1EncodableVector(0); + } - ASN1Encodable obj; - while ((obj = readObject()) != null) + ASN1EncodableVector v = new ASN1EncodableVector(); + do { if (obj instanceof InMemoryRepresentable) { @@ -243,7 +248,7 @@ public class ASN1StreamParser v.add(obj.toASN1Primitive()); } } - + while ((obj = readObject()) != null); return v; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1TaggedObject.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1TaggedObject.java index c5efac01c..b2ae1a2c7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1TaggedObject.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1TaggedObject.java @@ -11,10 +11,9 @@ public abstract class ASN1TaggedObject extends ASN1Primitive implements ASN1TaggedObjectParser { - int tagNo; - boolean empty = false; - boolean explicit = true; - ASN1Encodable obj = null; + final int tagNo; + final boolean explicit; + final ASN1Encodable obj; static public ASN1TaggedObject getInstance( ASN1TaggedObject obj, @@ -22,7 +21,7 @@ public abstract class ASN1TaggedObject { if (explicit) { - return (ASN1TaggedObject)obj.getObject(); + return getInstance(obj.getObject()); } throw new IllegalArgumentException("implicitly tagged tagged object"); @@ -33,7 +32,7 @@ public abstract class ASN1TaggedObject { if (obj == null || obj instanceof ASN1TaggedObject) { - return (ASN1TaggedObject)obj; + return (ASN1TaggedObject)obj; } else if (obj instanceof byte[]) { @@ -65,82 +64,39 @@ public abstract class ASN1TaggedObject int tagNo, ASN1Encodable obj) { - if (obj instanceof ASN1Choice) + if (null == obj) { - this.explicit = true; + throw new NullPointerException("'obj' cannot be null"); } - else - { - this.explicit = explicit; - } - - this.tagNo = tagNo; - if (this.explicit) - { - this.obj = obj; - } - else - { - ASN1Primitive prim = obj.toASN1Primitive(); - - if (prim instanceof ASN1Set) - { - ASN1Set s = null; - } - - this.obj = obj; - } + this.tagNo = tagNo; + this.explicit = explicit || (obj instanceof ASN1Choice); + this.obj = obj; } - - boolean asn1Equals( - ASN1Primitive o) + + boolean asn1Equals(ASN1Primitive other) { - if (!(o instanceof ASN1TaggedObject)) + if (!(other instanceof ASN1TaggedObject)) { return false; } - - ASN1TaggedObject other = (ASN1TaggedObject)o; - - if (tagNo != other.tagNo || empty != other.empty || explicit != other.explicit) + + ASN1TaggedObject that = (ASN1TaggedObject)other; + + if (this.tagNo != that.tagNo || this.explicit != that.explicit) { return false; } - - if(obj == null) - { - if (other.obj != null) - { - return false; - } - } - else - { - if (!(obj.toASN1Primitive().equals(other.obj.toASN1Primitive()))) - { - return false; - } - } - - return true; + + ASN1Primitive p1 = this.obj.toASN1Primitive(); + ASN1Primitive p2 = that.obj.toASN1Primitive(); + + return p1 == p2 || p1.asn1Equals(p2); } - + public int hashCode() { - int code = tagNo; - - // TODO: actually this is wrong - the problem is that a re-encoded - // object may end up with a different hashCode due to implicit - // tagging. As implicit tagging is ambiguous if a sequence is involved - // it seems the only correct method for both equals and hashCode is to - // compare the encodings... - if (obj != null) - { - code ^= obj.hashCode(); - } - - return code; + return tagNo ^ (explicit ? 0x0F : 0xF0) ^ obj.toASN1Primitive().hashCode(); } /** @@ -167,9 +123,12 @@ public abstract class ASN1TaggedObject return explicit; } + /** + * @deprecated Will be removed (always returns false). + */ public boolean isEmpty() { - return empty; + return false; } /** @@ -181,12 +140,7 @@ public abstract class ASN1TaggedObject */ public ASN1Primitive getObject() { - if (obj != null) - { - return obj.toASN1Primitive(); - } - - return null; + return obj.toASN1Primitive(); } /** @@ -232,8 +186,7 @@ public abstract class ASN1TaggedObject return new DLTaggedObject(explicit, tagNo, obj); } - abstract void encode(ASN1OutputStream out) - throws IOException; + abstract void encode(ASN1OutputStream out, boolean withTag) throws IOException; public String toString() { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1UTCTime.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1UTCTime.java index 70c0499dc..b5ea629cc 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1UTCTime.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ASN1UTCTime.java @@ -88,7 +88,7 @@ public class ASN1UTCTime } else { - return new ASN1UTCTime(((ASN1OctetString)o).getOctets()); + return new ASN1UTCTime(ASN1OctetString.getInstance(o).getOctets()); } } @@ -123,7 +123,7 @@ public class ASN1UTCTime public ASN1UTCTime( Date time) { - SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'"); + SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmss'Z'", DateUtil.EN_Locale); dateF.setTimeZone(new SimpleTimeZone(0,"Z")); @@ -151,7 +151,15 @@ public class ASN1UTCTime ASN1UTCTime( byte[] time) { + if (time.length < 2) + { + throw new IllegalArgumentException("UTCTime string too short"); + } this.time = time; + if (!(isDigit(0) && isDigit(1))) + { + throw new IllegalArgumentException("illegal characters in UTCTime string"); + } } /** @@ -166,7 +174,7 @@ public class ASN1UTCTime { SimpleDateFormat dateF = new SimpleDateFormat("yyMMddHHmmssz"); - return dateF.parse(getTime()); + return DateUtil.epochAdjust(dateF.parse(getTime())); } /** @@ -181,9 +189,9 @@ public class ASN1UTCTime { SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); - dateF.setTimeZone(new SimpleTimeZone(0, "Z")); - - return dateF.parse(getAdjustedTime()); + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + return DateUtil.epochAdjust(dateF.parse(getAdjustedTime())); } /** @@ -263,6 +271,11 @@ public class ASN1UTCTime } } + private boolean isDigit(int pos) + { + return time.length > pos && time[pos] >= '0' && time[pos] <= '9'; + } + boolean isConstructed() { return false; @@ -275,20 +288,9 @@ public class ASN1UTCTime return 1 + StreamUtil.calculateBodyLength(length) + length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.write(BERTags.UTC_TIME); - - int length = time.length; - - out.writeLength(length); - - for (int i = 0; i != length; i++) - { - out.write((byte)time[i]); - } + out.writeEncoded(withTag, BERTags.UTC_TIME, time); } boolean asn1Equals( diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERApplicationSpecific.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERApplicationSpecific.java index f44852765..694c4da61 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERApplicationSpecific.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERApplicationSpecific.java @@ -97,18 +97,14 @@ public class BERApplicationSpecific /* (non-Javadoc) * @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#encode(com.fr.third.org.bouncycastle.asn1.DEROutputStream) */ - void encode(ASN1OutputStream out) throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - int classBits = BERTags.APPLICATION; + int flags = BERTags.APPLICATION; if (isConstructed) { - classBits |= BERTags.CONSTRUCTED; + flags |= BERTags.CONSTRUCTED; } - out.writeTag(classBits, tag); - out.write(0x80); - out.write(octets); - out.write(0x00); - out.write(0x00); + out.writeEncodedIndef(withTag, flags, tag, octets); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERFactory.java index 0ee0b68de..7743f4d22 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERFactory.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERFactory.java @@ -7,11 +7,21 @@ class BERFactory static BERSequence createSequence(ASN1EncodableVector v) { - return v.size() < 1 ? EMPTY_SEQUENCE : new BERSequence(v); + if (v.size() < 1) + { + return EMPTY_SEQUENCE; + } + + return new BERSequence(v); } static BERSet createSet(ASN1EncodableVector v) { - return v.size() < 1 ? EMPTY_SET : new BERSet(v); + if (v.size() < 1) + { + return EMPTY_SET; + } + + return new BERSet(v); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROctetString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROctetString.java index cd1aa3231..5fd99fe88 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROctetString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROctetString.java @@ -191,37 +191,28 @@ public class BEROctetString return 2 + length + 2; } - public void encode( - ASN1OutputStream out) + /** + * @deprecated + */ + public void encode(ASN1OutputStream out) throws IOException { - out.write(BERTags.CONSTRUCTED | BERTags.OCTET_STRING); - - out.write(0x80); - - // - // write out the octet array - // - for (Enumeration e = getObjects(); e.hasMoreElements();) - { - out.writeObject((ASN1Encodable)e.nextElement()); - } + out.writeObject(this); + } - out.write(0x00); - out.write(0x00); + void encode(ASN1OutputStream out, boolean withTag) throws IOException + { + out.writeEncodedIndef(withTag, BERTags.CONSTRUCTED | BERTags.OCTET_STRING, getObjects()); } static BEROctetString fromSequence(ASN1Sequence seq) { - ASN1OctetString[] v = new ASN1OctetString[seq.size()]; - Enumeration e = seq.getObjects(); - int index = 0; - - while (e.hasMoreElements()) + int count = seq.size(); + ASN1OctetString[] v = new ASN1OctetString[count]; + for (int i = 0; i < count; ++i) { - v[index++] = (ASN1OctetString)e.nextElement(); + v[i] = ASN1OctetString.getInstance(seq.getObjectAt(i)); } - return new BEROctetString(v); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROctetStringGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROctetStringGenerator.java index 31f78ba02..f4ee38386 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROctetStringGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROctetStringGenerator.java @@ -20,7 +20,7 @@ public class BEROctetStringGenerator throws IOException { super(out); - + writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING); } @@ -40,7 +40,7 @@ public class BEROctetStringGenerator throws IOException { super(out, tagNo, isExplicit); - + writeBERHeader(BERTags.CONSTRUCTED | BERTags.OCTET_STRING); } @@ -65,7 +65,7 @@ public class BEROctetStringGenerator { return new BufferedBEROctetStream(buf); } - + private class BufferedBEROctetStream extends OutputStream { @@ -80,7 +80,7 @@ public class BEROctetStringGenerator _off = 0; _derOut = new DEROutputStream(_out); } - + public void write( int b) throws IOException @@ -89,7 +89,7 @@ public class BEROctetStringGenerator if (_off == _buf.length) { - DEROctetString.encode(_derOut, _buf); + DEROctetString.encode(_derOut, true, _buf, 0, _buf.length); _off = 0; } } @@ -107,7 +107,7 @@ public class BEROctetStringGenerator break; } - DEROctetString.encode(_derOut, _buf); + DEROctetString.encode(_derOut, true, _buf, 0, _buf.length); _off = 0; off += numToCopy; @@ -115,17 +115,16 @@ public class BEROctetStringGenerator } } - public void close() + public void close() throws IOException { if (_off != 0) { - byte[] bytes = new byte[_off]; - System.arraycopy(_buf, 0, bytes, 0, _off); - - DEROctetString.encode(_derOut, bytes); + DEROctetString.encode(_derOut, true, _buf, 0, _off); } - + + _derOut.flushInternal(); + writeBEREnd(); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROutputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROutputStream.java index 4618cf931..acb28ae85 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROutputStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BEROutputStream.java @@ -1,51 +1,27 @@ package com.fr.third.org.bouncycastle.asn1; -import java.io.IOException; import java.io.OutputStream; /** - * A class which writes indefinite and definite length objects. Objects which specify DER will be encoded accordingly, but DL or BER - * objects will be encoded as defined. + * A class which writes indefinite and definite length objects. Objects which specify DER will be + * encoded accordingly, but DL or BER objects will be encoded as defined. + * + * @deprecated Will be removed from public API. */ public class BEROutputStream - extends DEROutputStream + extends ASN1OutputStream { /** * Base constructor. * - * @param os target output stream. - */ - public BEROutputStream( - OutputStream os) - { - super(os); - } - - /** - * Write out an ASN.1 object. + * @param os + * target output stream. * - * @param obj the object to be encoded. - * @throws IOException if there is an issue on encoding or output of the object. + * @deprecated Use {@link ASN1OutputStream#create(OutputStream, String)} with + * {@link ASN1Encoding#BER} instead. */ - public void writeObject( - Object obj) - throws IOException + public BEROutputStream(OutputStream os) { - if (obj == null) - { - writeNull(); - } - else if (obj instanceof ASN1Primitive) - { - ((ASN1Primitive)obj).encode(this); - } - else if (obj instanceof ASN1Encodable) - { - ((ASN1Encodable)obj).toASN1Primitive().encode(this); - } - else - { - throw new IOException("object not BEREncodable"); - } + super(os); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSequence.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSequence.java index a7ed7aac1..f6a118af6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSequence.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSequence.java @@ -1,7 +1,6 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; -import java.util.Enumeration; /** * Indefinite length SEQUENCE of objects. @@ -24,56 +23,43 @@ public class BERSequence /** * Create a sequence containing one object */ - public BERSequence( - ASN1Encodable obj) + public BERSequence(ASN1Encodable element) { - super(obj); + super(element); } /** * Create a sequence containing a vector of objects. */ - public BERSequence( - ASN1EncodableVector v) + public BERSequence(ASN1EncodableVector elementVector) { - super(v); + super(elementVector); } /** * Create a sequence containing an array of objects. */ - public BERSequence( - ASN1Encodable[] array) + public BERSequence(ASN1Encodable[] elements) { - super(array); + super(elements); } - int encodedLength() - throws IOException + int encodedLength() throws IOException { - int length = 0; - for (Enumeration e = getObjects(); e.hasMoreElements();) + int count = elements.length; + int totalLength = 0; + + for (int i = 0; i < count; ++i) { - length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength(); + ASN1Primitive p = elements[i].toASN1Primitive(); + totalLength += p.encodedLength(); } - return 2 + length + 2; + return 2 + totalLength + 2; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); - out.write(0x80); - - Enumeration e = getObjects(); - while (e.hasMoreElements()) - { - out.writeObject((ASN1Encodable)e.nextElement()); - } - - out.write(0x00); - out.write(0x00); + out.writeEncodedIndef(withTag, BERTags.SEQUENCE | BERTags.CONSTRUCTED, elements); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSequenceGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSequenceGenerator.java index f86435c6b..46a7c37b4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSequenceGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSequenceGenerator.java @@ -55,7 +55,7 @@ public class BERSequenceGenerator ASN1Encodable object) throws IOException { - object.toASN1Primitive().encode(new BEROutputStream(_out)); + object.toASN1Primitive().encodeTo(_out); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSet.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSet.java index a5f203c30..4adda408d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSet.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERSet.java @@ -1,7 +1,6 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; -import java.util.Enumeration; /** * Indefinite length SET and SET OF constructs. @@ -30,60 +29,52 @@ public class BERSet /** * Create a SET containing one object. * - * @param obj - a single object that makes up the set. + * @param element - a single object that makes up the set. */ - public BERSet( - ASN1Encodable obj) + public BERSet(ASN1Encodable element) { - super(obj); + super(element); } /** * Create a SET containing multiple objects. - * @param v a vector of objects making up the set. + * @param elementVector a vector of objects making up the set. */ - public BERSet( - ASN1EncodableVector v) + public BERSet(ASN1EncodableVector elementVector) { - super(v, false); + super(elementVector, false); } /** * Create a SET from an array of objects. - * @param a an array of ASN.1 objects. + * @param elements an array of ASN.1 objects. */ - public BERSet( - ASN1Encodable[] a) + public BERSet(ASN1Encodable[] elements) { - super(a, false); + super(elements, false); } - int encodedLength() - throws IOException + BERSet(boolean isSorted, ASN1Encodable[] elements) { - int length = 0; - for (Enumeration e = getObjects(); e.hasMoreElements();) - { - length += ((ASN1Encodable)e.nextElement()).toASN1Primitive().encodedLength(); - } - - return 2 + length + 2; + super(isSorted, elements); } - void encode( - ASN1OutputStream out) - throws IOException + int encodedLength() throws IOException { - out.write(BERTags.SET | BERTags.CONSTRUCTED); - out.write(0x80); + int count = elements.length; + int totalLength = 0; - Enumeration e = getObjects(); - while (e.hasMoreElements()) + for (int i = 0; i < count; ++i) { - out.writeObject((ASN1Encodable)e.nextElement()); + ASN1Primitive p = elements[i].toASN1Primitive(); + totalLength += p.encodedLength(); } - out.write(0x00); - out.write(0x00); + return 2 + totalLength + 2; + } + + void encode(ASN1OutputStream out, boolean withTag) throws IOException + { + out.writeEncodedIndef(withTag, BERTags.SET | BERTags.CONSTRUCTED, elements); } -} \ No newline at end of file +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERTaggedObject.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERTaggedObject.java index c266812ea..8e9eeec32 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERTaggedObject.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/BERTaggedObject.java @@ -47,101 +47,92 @@ public class BERTaggedObject boolean isConstructed() { - if (!empty) - { - if (explicit) - { - return true; - } - else - { - ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); - - return primitive.isConstructed(); - } - } - else - { - return true; - } + return explicit || obj.toASN1Primitive().isConstructed(); } int encodedLength() throws IOException { - if (!empty) - { - ASN1Primitive primitive = obj.toASN1Primitive(); - int length = primitive.encodedLength(); + ASN1Primitive primitive = obj.toASN1Primitive(); + int length = primitive.encodedLength(); - if (explicit) - { - return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; - } - else - { - // header length already in calculation - length = length - 1; - - return StreamUtil.calculateTagLength(tagNo) + length; - } + if (explicit) + { + return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; } else { - return StreamUtil.calculateTagLength(tagNo) + 1; + // header length already in calculation + length = length - 1; + + return StreamUtil.calculateTagLength(tagNo) + length; } } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo); + out.writeTag(withTag, BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo); out.write(0x80); - if (!empty) + if (!explicit) { - if (!explicit) + Enumeration e; + if (obj instanceof ASN1OctetString) { - Enumeration e; - if (obj instanceof ASN1OctetString) + if (obj instanceof BEROctetString) { - if (obj instanceof BEROctetString) - { - e = ((BEROctetString)obj).getObjects(); - } - else - { - ASN1OctetString octs = (ASN1OctetString)obj; - BEROctetString berO = new BEROctetString(octs.getOctets()); - e = berO.getObjects(); - } - } - else if (obj instanceof ASN1Sequence) - { - e = ((ASN1Sequence)obj).getObjects(); - } - else if (obj instanceof ASN1Set) - { - e = ((ASN1Set)obj).getObjects(); + e = ((BEROctetString)obj).getObjects(); } else { - throw new ASN1Exception("not implemented: " + obj.getClass().getName()); - } - - while (e.hasMoreElements()) - { - out.writeObject((ASN1Encodable)e.nextElement()); + ASN1OctetString octs = (ASN1OctetString)obj; + BEROctetString berO = new BEROctetString(octs.getOctets()); + e = berO.getObjects(); } } + else if (obj instanceof ASN1Sequence) + { + e = ((ASN1Sequence)obj).getObjects(); + } + else if (obj instanceof ASN1Set) + { + e = ((ASN1Set)obj).getObjects(); + } else { - out.writeObject(obj); + throw new ASN1Exception("not implemented: " + obj.getClass().getName()); } + + out.writeElements(e); + } + else + { + out.writePrimitive(obj.toASN1Primitive(), true); } out.write(0x00); out.write(0x00); + +// ASN1Primitive primitive = obj.toASN1Primitive(); +// +// int flags = BERTags.TAGGED; +// if (explicit || primitive.isConstructed()) +// { +// flags |= BERTags.CONSTRUCTED; +// } +// +// out.writeTag(withTag, flags, tagNo); +// +// if (explicit) +// { +// out.write(0x80); +// out.writePrimitive(obj.toASN1Primitive(), true); +// out.write(0x00); +// out.write(0x00); +// } +// else +// { +// out.writePrimitive(obj.toASN1Primitive(), false); +// } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ConstructedOctetStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ConstructedOctetStream.java index 288b77af0..cd0d17251 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ConstructedOctetStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ConstructedOctetStream.java @@ -26,13 +26,19 @@ class ConstructedOctetStream return -1; } - ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject(); - - if (s == null) + ASN1Encodable asn1Obj = _parser.readObject(); + if (asn1Obj == null) { return -1; } + if (!(asn1Obj instanceof ASN1OctetStringParser)) + { + throw new IOException("unknown object encountered: " + asn1Obj.getClass()); + } + + ASN1OctetStringParser s = (ASN1OctetStringParser)asn1Obj; + _first = false; _currentStream = s.getOctetStream(); } @@ -54,14 +60,21 @@ class ConstructedOctetStream } else { - ASN1OctetStringParser aos = (ASN1OctetStringParser)_parser.readObject(); + ASN1Encodable asn1Obj = _parser.readObject(); - if (aos == null) + if (asn1Obj == null) { _currentStream = null; return totalRead < 1 ? -1 : totalRead; } + if (!(asn1Obj instanceof ASN1OctetStringParser)) + { + throw new IOException("unknown object encountered: " + asn1Obj.getClass()); + } + + ASN1OctetStringParser aos = (ASN1OctetStringParser)asn1Obj; + _currentStream = aos.getOctetStream(); } } @@ -77,13 +90,20 @@ class ConstructedOctetStream return -1; } - ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject(); + ASN1Encodable asn1Obj = _parser.readObject(); - if (s == null) + if (asn1Obj == null) { return -1; } - + + if (!(asn1Obj instanceof ASN1OctetStringParser)) + { + throw new IOException("unknown object encountered: " + asn1Obj.getClass()); + } + + ASN1OctetStringParser s = (ASN1OctetStringParser)asn1Obj; + _first = false; _currentStream = s.getOctetStream(); } @@ -97,14 +117,21 @@ class ConstructedOctetStream return b; } - ASN1OctetStringParser s = (ASN1OctetStringParser)_parser.readObject(); + ASN1Encodable asn1Obj = _parser.readObject(); - if (s == null) + if (asn1Obj == null) { _currentStream = null; return -1; } + if (!(asn1Obj instanceof ASN1OctetStringParser)) + { + throw new IOException("unknown object encountered: " + asn1Obj.getClass()); + } + + ASN1OctetStringParser s = (ASN1OctetStringParser)asn1Obj; + _currentStream = s.getOctetStream(); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERApplicationSpecific.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERApplicationSpecific.java index 7a8a20297..580b67a1a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERApplicationSpecific.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERApplicationSpecific.java @@ -3,8 +3,6 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.ByteArrayOutputStream; import java.io.IOException; -import com.fr.third.org.bouncycastle.util.encoders.Hex; - /** * A DER encoding version of an application specific object. */ @@ -113,39 +111,14 @@ public class DERApplicationSpecific /* (non-Javadoc) * @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#encode(com.fr.third.org.bouncycastle.asn1.DEROutputStream) */ - void encode(ASN1OutputStream out) throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - int classBits = BERTags.APPLICATION; + int flags = BERTags.APPLICATION; if (isConstructed) { - classBits |= BERTags.CONSTRUCTED; + flags |= BERTags.CONSTRUCTED; } - out.writeEncoded(classBits, tag, octets); - } - - public String toString() - { - StringBuffer sb = new StringBuffer(); - sb.append("["); - if (isConstructed()) - { - sb.append("CONSTRUCTED "); - } - sb.append("APPLICATION "); - sb.append(Integer.toString(getApplicationTag())); - sb.append("]"); - // @todo content encoding somehow? - if (this.octets != null) - { - sb.append(" #"); - sb.append(Hex.toHexString(this.octets)); - } - else - { - sb.append(" #null"); - } - sb.append(" "); - return sb.toString(); + out.writeEncoded(withTag, flags, tag, octets); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBMPString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBMPString.java index 96a692847..b6011f1db 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBMPString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBMPString.java @@ -145,18 +145,49 @@ public class DERBMPString } void encode( - ASN1OutputStream out) + ASN1OutputStream out, boolean withTag) throws IOException { - out.write(BERTags.BMP_STRING); - out.writeLength(string.length * 2); + int count = string.length; + if (withTag) + { + out.write(BERTags.BMP_STRING); + } + out.writeLength(count * 2); - for (int i = 0; i != string.length; i++) + byte[] buf = new byte[8]; + + int i = 0, limit = count & -4; + while (i < limit) + { + char c0 = string[i], c1 = string[i + 1], c2 = string[i + 2], c3 = string[i + 3]; + i += 4; + + buf[0] = (byte)(c0 >> 8); + buf[1] = (byte)c0; + buf[2] = (byte)(c1 >> 8); + buf[3] = (byte)c1; + buf[4] = (byte)(c2 >> 8); + buf[5] = (byte)c2; + buf[6] = (byte)(c3 >> 8); + buf[7] = (byte)c3; + + out.write(buf, 0, 8); + } + if (i < count) { - char c = string[i]; + int bufPos = 0; + do + { + char c0 = string[i]; + i += 1; + + buf[bufPos++] = (byte)(c0 >> 8); + buf[bufPos++] = (byte)c0; + } + while (i < count); - out.write((byte)(c >> 8)); - out.write((byte)c); + out.write(buf, 0, bufPos); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBitString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBitString.java index f1b8fa290..c446c5c6d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBitString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBitString.java @@ -63,24 +63,13 @@ public class DERBitString } else { - return fromOctetString(((ASN1OctetString)o).getOctets()); + return fromOctetString(ASN1OctetString.getInstance(o).getOctets()); } } - - protected DERBitString( - byte data, - int padBits) - { - this(toByteArray(data), padBits); - } - private static byte[] toByteArray(byte data) + protected DERBitString(byte data, int padBits) { - byte[] rv = new byte[1]; - - rv[0] = data; - - return rv; + super(data, padBits); } /** @@ -123,17 +112,30 @@ public class DERBitString return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - byte[] string = derForm(data, padBits); - byte[] bytes = new byte[string.length + 1]; + int len = data.length; + if (0 == len + || 0 == padBits + || (data[len - 1] == (byte)(data[len - 1] & (0xFF << padBits)))) + { + out.writeEncoded(withTag, BERTags.BIT_STRING, (byte)padBits, data); + } + else + { + byte der = (byte)(data[len - 1] & (0xFF << padBits)); + out.writeEncoded(withTag, BERTags.BIT_STRING, (byte)padBits, data, 0, len - 1, der); + } + } - bytes[0] = (byte)getPadBits(); - System.arraycopy(string, 0, bytes, 1, bytes.length - 1); + ASN1Primitive toDERObject() + { + return this; + } - out.writeEncoded(BERTags.BIT_STRING, bytes); + ASN1Primitive toDLObject() + { + return this; } static DERBitString fromOctetString(byte[] bytes) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBoolean.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBoolean.java deleted file mode 100644 index d523af315..000000000 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERBoolean.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.fr.third.org.bouncycastle.asn1; - -/** - * @deprecated use ASN1Boolean - */ -public class DERBoolean - extends ASN1Boolean -{ - /** - * @deprecated use getInstance(boolean) method. - * @param value - */ - public DERBoolean(boolean value) - { - super(value); - } - - DERBoolean(byte[] value) - { - super(value); - } -} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERExternal.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERExternal.java index 12c64348a..63f1a0092 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERExternal.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERExternal.java @@ -7,14 +7,8 @@ import java.io.IOException; * Class representing the DER-type External */ public class DERExternal - extends ASN1Primitive + extends ASN1External { - private ASN1ObjectIdentifier directReference; - private ASN1Integer indirectReference; - private ASN1Primitive dataValueDescriptor; - private int encoding; - private ASN1Primitive externalContent; - /** * Construct a DER EXTERNAL object, the input encoding vector must have exactly two elements on it. *

@@ -29,51 +23,9 @@ public class DERExternal */ public DERExternal(ASN1EncodableVector vector) { - int offset = 0; - - ASN1Primitive enc = getObjFromVector(vector, offset); - if (enc instanceof ASN1ObjectIdentifier) - { - directReference = (ASN1ObjectIdentifier)enc; - offset++; - enc = getObjFromVector(vector, offset); - } - if (enc instanceof ASN1Integer) - { - indirectReference = (ASN1Integer) enc; - offset++; - enc = getObjFromVector(vector, offset); - } - if (!(enc instanceof ASN1TaggedObject)) - { - dataValueDescriptor = (ASN1Primitive) enc; - offset++; - enc = getObjFromVector(vector, offset); - } - - if (vector.size() != offset + 1) - { - throw new IllegalArgumentException("input vector too large"); - } - - if (!(enc instanceof ASN1TaggedObject)) - { - throw new IllegalArgumentException("No tagged object found in vector. Structure doesn't seem to be of type External"); - } - ASN1TaggedObject obj = (ASN1TaggedObject)enc; - setEncoding(obj.getTagNo()); - externalContent = obj.getObject(); + super(vector); } - private ASN1Primitive getObjFromVector(ASN1EncodableVector v, int index) - { - if (v.size() <= index) - { - throw new IllegalArgumentException("too few objects in input vector"); - } - - return v.get(index).toASN1Primitive(); - } /** * Creates a new instance of DERExternal * See X.690 for more informations about the meaning of these parameters @@ -98,38 +50,17 @@ public class DERExternal */ public DERExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData) { - setDirectReference(directReference); - setIndirectReference(indirectReference); - setDataValueDescriptor(dataValueDescriptor); - setEncoding(encoding); - setExternalContent(externalData.toASN1Primitive()); + super(directReference, indirectReference, dataValueDescriptor, encoding, externalData); } - /* (non-Javadoc) - * @see java.lang.Object#hashCode() - */ - public int hashCode() + ASN1Primitive toDERObject() { - int ret = 0; - if (directReference != null) - { - ret = directReference.hashCode(); - } - if (indirectReference != null) - { - ret ^= indirectReference.hashCode(); - } - if (dataValueDescriptor != null) - { - ret ^= dataValueDescriptor.hashCode(); - } - ret ^= externalContent.hashCode(); - return ret; + return this; } - boolean isConstructed() + ASN1Primitive toDLObject() { - return true; + return this; } int encodedLength() @@ -141,8 +72,7 @@ public class DERExternal /* (non-Javadoc) * @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#encode(com.fr.third.org.bouncycastle.asn1.DEROutputStream) */ - void encode(ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); if (directReference != null) @@ -159,148 +89,7 @@ public class DERExternal } DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent); baos.write(obj.getEncoded(ASN1Encoding.DER)); - out.writeEncoded(BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray()); - } - - /* (non-Javadoc) - * @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#asn1Equals(com.fr.third.org.bouncycastle.asn1.ASN1Primitive) - */ - boolean asn1Equals(ASN1Primitive o) - { - if (!(o instanceof DERExternal)) - { - return false; - } - if (this == o) - { - return true; - } - DERExternal other = (DERExternal)o; - if (directReference != null) - { - if (other.directReference == null || !other.directReference.equals(directReference)) - { - return false; - } - } - if (indirectReference != null) - { - if (other.indirectReference == null || !other.indirectReference.equals(indirectReference)) - { - return false; - } - } - if (dataValueDescriptor != null) - { - if (other.dataValueDescriptor == null || !other.dataValueDescriptor.equals(dataValueDescriptor)) - { - return false; - } - } - return externalContent.equals(other.externalContent); - } - /** - * Returns the data value descriptor - * @return The descriptor - */ - public ASN1Primitive getDataValueDescriptor() - { - return dataValueDescriptor; - } - - /** - * Returns the direct reference of the external element - * @return The reference - */ - public ASN1ObjectIdentifier getDirectReference() - { - return directReference; - } - - /** - * Returns the encoding of the content. Valid values are - *

    - *
  • 0 single-ASN1-type
  • - *
  • 1 OCTET STRING
  • - *
  • 2 BIT STRING
  • - *
- * @return The encoding - */ - public int getEncoding() - { - return encoding; - } - - /** - * Returns the content of this element - * @return The content - */ - public ASN1Primitive getExternalContent() - { - return externalContent; - } - - /** - * Returns the indirect reference of this element - * @return The reference - */ - public ASN1Integer getIndirectReference() - { - return indirectReference; - } - - /** - * Sets the data value descriptor - * @param dataValueDescriptor The descriptor - */ - private void setDataValueDescriptor(ASN1Primitive dataValueDescriptor) - { - this.dataValueDescriptor = dataValueDescriptor; - } - - /** - * Sets the direct reference of the external element - * @param directReferemce The reference - */ - private void setDirectReference(ASN1ObjectIdentifier directReferemce) - { - this.directReference = directReferemce; - } - - /** - * Sets the encoding of the content. Valid values are - *
    - *
  • 0 single-ASN1-type
  • - *
  • 1 OCTET STRING
  • - *
  • 2 BIT STRING
  • - *
- * @param encoding The encoding - */ - private void setEncoding(int encoding) - { - if (encoding < 0 || encoding > 2) - { - throw new IllegalArgumentException("invalid encoding value: " + encoding); - } - this.encoding = encoding; - } - - /** - * Sets the content of this element - * @param externalContent The content - */ - private void setExternalContent(ASN1Primitive externalContent) - { - this.externalContent = externalContent; - } - - /** - * Sets the indirect reference of this element - * @param indirectReference The reference - */ - private void setIndirectReference(ASN1Integer indirectReference) - { - this.indirectReference = indirectReference; + out.writeEncoded(withTag, BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray()); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERExternalParser.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERExternalParser.java index 5ea2114fd..159722a98 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERExternalParser.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERExternalParser.java @@ -37,7 +37,7 @@ public class DERExternalParser { try { - return new DERExternal(_parser.readVector()); + return new DLExternal(_parser.readVector()); } catch (IllegalArgumentException e) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERFactory.java index 962b74013..9e5f77da9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERFactory.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERFactory.java @@ -7,11 +7,21 @@ class DERFactory static ASN1Sequence createSequence(ASN1EncodableVector v) { - return v.size() < 1 ? EMPTY_SEQUENCE : new DLSequence(v); + if (v.size() < 1) + { + return EMPTY_SEQUENCE; + } + + return new DERSequence(v); } static ASN1Set createSet(ASN1EncodableVector v) { - return v.size() < 1 ? EMPTY_SET : new DLSet(v); + if (v.size() < 1) + { + return EMPTY_SET; + } + + return new DERSet(v); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGeneralString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGeneralString.java index 0281727ca..1a90dbbf8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGeneralString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGeneralString.java @@ -71,7 +71,7 @@ public class DERGeneralString } else { - return new DERGeneralString(((ASN1OctetString)o).getOctets()); + return new DERGeneralString(ASN1OctetString.getInstance(o).getOctets()); } } @@ -125,12 +125,11 @@ public class DERGeneralString return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode(ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.GENERAL_STRING, string); + out.writeEncoded(withTag, BERTags.GENERAL_STRING, string); } - + public int hashCode() { return Arrays.hashCode(string); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGeneralizedTime.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGeneralizedTime.java index 2793e22de..7ce6a6669 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGeneralizedTime.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGeneralizedTime.java @@ -107,10 +107,18 @@ public class DERGeneralizedTime return 1 + StreamUtil.calculateBodyLength(length) + length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.GENERALIZED_TIME, getDERTime()); + out.writeEncoded(withTag, BERTags.GENERALIZED_TIME, getDERTime()); + } + + ASN1Primitive toDERObject() + { + return this; + } + + ASN1Primitive toDLObject() + { + return this; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGraphicString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGraphicString.java index ca6eb20f1..09f1c13e6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGraphicString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERGraphicString.java @@ -63,7 +63,7 @@ public class DERGraphicString } else { - return new DERGraphicString(((ASN1OctetString)o).getOctets()); + return new DERGraphicString(ASN1OctetString.getInstance(o).getOctets()); } } @@ -92,11 +92,9 @@ public class DERGraphicString return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.GRAPHIC_STRING, string); + out.writeEncoded(withTag, BERTags.GRAPHIC_STRING, string); } public int hashCode() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERIA5String.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERIA5String.java index bea21f98d..cbe11914d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERIA5String.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERIA5String.java @@ -69,7 +69,7 @@ public class DERIA5String } else { - return new DERIA5String(((ASN1OctetString)o).getOctets()); + return new DERIA5String(ASN1OctetString.getInstance(o).getOctets()); } } @@ -107,11 +107,11 @@ public class DERIA5String { if (string == null) { - throw new NullPointerException("string cannot be null"); + throw new NullPointerException("'string' cannot be null"); } if (validate && !isIA5String(string)) { - throw new IllegalArgumentException("string contains illegal characters"); + throw new IllegalArgumentException("'string' contains illegal characters"); } this.string = Strings.toByteArray(string); @@ -142,11 +142,9 @@ public class DERIA5String return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.IA5_STRING, string); + out.writeEncoded(withTag, BERTags.IA5_STRING, string); } public int hashCode() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERNull.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERNull.java index f5a06c198..0a5a934eb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERNull.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERNull.java @@ -31,10 +31,8 @@ public class DERNull return 2; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.NULL, zeroBytes); + out.writeEncoded(withTag, BERTags.NULL, zeroBytes); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERNumericString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERNumericString.java index 1ae02d483..b9622fe2a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERNumericString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERNumericString.java @@ -140,11 +140,9 @@ public class DERNumericString return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.NUMERIC_STRING, string); + out.writeEncoded(withTag, BERTags.NUMERIC_STRING, string); } public int hashCode() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DEROctetString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DEROctetString.java index 13064d0ac..dc6247b71 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DEROctetString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DEROctetString.java @@ -41,18 +41,23 @@ public class DEROctetString return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.OCTET_STRING, string); + out.writeEncoded(withTag, BERTags.OCTET_STRING, string); } - static void encode( - DEROutputStream derOut, - byte[] bytes) - throws IOException + ASN1Primitive toDERObject() + { + return this; + } + + ASN1Primitive toDLObject() + { + return this; + } + + static void encode(ASN1OutputStream derOut, boolean withTag, byte[] buf, int off, int len) throws IOException { - derOut.writeEncoded(BERTags.OCTET_STRING, bytes); + derOut.writeEncoded(withTag, BERTags.OCTET_STRING, buf, off, len); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DEROutputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DEROutputStream.java index 1a999c125..3951e0021 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DEROutputStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DEROutputStream.java @@ -5,31 +5,27 @@ import java.io.OutputStream; /** * Stream that outputs encoding based on distinguished encoding rules. + * + * @deprecated Will be removed from public API. */ public class DEROutputStream extends ASN1OutputStream { - public DEROutputStream( - OutputStream os) + /** + * @deprecated Use {@link ASN1OutputStream#create(OutputStream, String)} with + * {@link ASN1Encoding#DER} instead. + */ + public DEROutputStream(OutputStream os) { super(os); } - public void writeObject( - ASN1Encodable obj) - throws IOException + void writePrimitive(ASN1Primitive primitive, boolean withTag) throws IOException { - if (obj != null) - { - obj.toASN1Primitive().toDERObject().encode(this); - } - else - { - throw new IOException("null object detected"); - } + primitive.toDERObject().encode(this, withTag); } - ASN1OutputStream getDERSubStream() + DEROutputStream getDERSubStream() { return this; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERPrintableString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERPrintableString.java index 45c031d97..9ea9ce3c5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERPrintableString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERPrintableString.java @@ -151,11 +151,9 @@ public class DERPrintableString return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.PRINTABLE_STRING, string); + out.writeEncoded(withTag, BERTags.PRINTABLE_STRING, string); } public int hashCode() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequence.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequence.java index 56673d903..970c3d091 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequence.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequence.java @@ -1,7 +1,7 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; -import java.util.Enumeration; +import java.io.OutputStream; /** * Definite length SEQUENCE, encoding tells explicit number of bytes @@ -12,6 +12,11 @@ import java.util.Enumeration; public class DERSequence extends ASN1Sequence { + public static DERSequence convert(ASN1Sequence seq) + { + return (DERSequence)seq.toDERObject(); + } + private int bodyLength = -1; /** @@ -23,56 +28,56 @@ public class DERSequence /** * Create a sequence containing one object - * @param obj the object to go in the sequence. + * @param element the object to go in the sequence. */ - public DERSequence( - ASN1Encodable obj) + public DERSequence(ASN1Encodable element) { - super(obj); + super(element); } /** * Create a sequence containing a vector of objects. - * @param v the vector of objects to make up the sequence. + * @param elementVector the vector of objects to make up the sequence. */ - public DERSequence( - ASN1EncodableVector v) + public DERSequence(ASN1EncodableVector elementVector) { - super(v); + super(elementVector); } /** * Create a sequence containing an array of objects. - * @param array the array of objects to make up the sequence. + * @param elements the array of objects to make up the sequence. */ - public DERSequence( - ASN1Encodable[] array) + public DERSequence(ASN1Encodable[] elements) { - super(array); + super(elements); } - private int getBodyLength() - throws IOException + DERSequence(ASN1Encodable[] elements, boolean clone) + { + super(elements, clone); + } + + private int getBodyLength() throws IOException { if (bodyLength < 0) { - int length = 0; + int count = elements.length; + int totalLength = 0; - for (Enumeration e = this.getObjects(); e.hasMoreElements();) + for (int i = 0; i < count; ++i) { - Object obj = e.nextElement(); - - length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength(); + ASN1Primitive derObject = elements[i].toASN1Primitive().toDERObject(); + totalLength += derObject.encodedLength(); } - bodyLength = length; + this.bodyLength = totalLength; } return bodyLength; } - int encodedLength() - throws IOException + int encodedLength() throws IOException { int length = getBodyLength(); @@ -87,21 +92,55 @@ public class DERSequence * ASN.1 descriptions given. Rather than just outputting SEQUENCE, * we also have to specify CONSTRUCTED, and the objects length. */ - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - ASN1OutputStream dOut = out.getDERSubStream(); - int length = getBodyLength(); + if (withTag) + { + out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); + } + + DEROutputStream derOut = out.getDERSubStream(); - out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); - out.writeLength(length); + int count = elements.length; + if (bodyLength >= 0 || count > 16) + { + out.writeLength(getBodyLength()); - for (Enumeration e = this.getObjects(); e.hasMoreElements();) + for (int i = 0; i < count; ++i) + { + ASN1Primitive derObject = elements[i].toASN1Primitive().toDERObject(); + derObject.encode(derOut, true); + } + } + else { - Object obj = e.nextElement(); + int totalLength = 0; + + ASN1Primitive[] derObjects = new ASN1Primitive[count]; + for (int i = 0; i < count; ++i) + { + ASN1Primitive derObject = elements[i].toASN1Primitive().toDERObject(); + derObjects[i] = derObject; + totalLength += derObject.encodedLength(); + } - dOut.writeObject((ASN1Encodable)obj); + this.bodyLength = totalLength; + out.writeLength(totalLength); + + for (int i = 0; i < count; ++i) + { + derObjects[i].encode(derOut, true); + } } } + + ASN1Primitive toDERObject() + { + return this; + } + + ASN1Primitive toDLObject() + { + return this; + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequenceGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequenceGenerator.java index dcbb8213d..d95927d6c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequenceGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequenceGenerator.java @@ -53,7 +53,7 @@ public class DERSequenceGenerator ASN1Encodable object) throws IOException { - object.toASN1Primitive().encode(new DEROutputStream(_bOut)); + object.toASN1Primitive().encodeTo(_bOut, ASN1Encoding.DER); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequenceParser.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequenceParser.java index b84677e3f..7b9acafe2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequenceParser.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSequenceParser.java @@ -3,7 +3,7 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; /** - * Parser class for DER SEQUENCEs. + * @deprecated Use DLSequenceParser instead */ public class DERSequenceParser implements ASN1SequenceParser @@ -36,7 +36,7 @@ public class DERSequenceParser public ASN1Primitive getLoadedObject() throws IOException { - return new DERSequence(_parser.readVector()); + return new DLSequence(_parser.readVector()); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSet.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSet.java index 9dcb77789..9149201be 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSet.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSet.java @@ -1,7 +1,7 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; -import java.util.Enumeration; +import java.io.OutputStream; /** * A DER encoded SET object @@ -16,6 +16,11 @@ import java.util.Enumeration; public class DERSet extends ASN1Set { + public static DERSet convert(ASN1Set set) + { + return (DERSet)set.toDERObject(); + } + private int bodyLength = -1; /** @@ -27,63 +32,56 @@ public class DERSet /** * create a set containing one object - * @param obj the object to go in the set + * @param element the object to go in the set */ - public DERSet( - ASN1Encodable obj) + public DERSet(ASN1Encodable element) { - super(obj); + super(element); } /** * create a set containing a vector of objects. - * @param v the vector of objects to make up the set. + * @param elementVector the vector of objects to make up the set. */ - public DERSet( - ASN1EncodableVector v) + public DERSet(ASN1EncodableVector elementVector) { - super(v, true); + super(elementVector, true); } - + /** * create a set containing an array of objects. - * @param a the array of objects to make up the set. + * @param elements the array of objects to make up the set. */ - public DERSet( - ASN1Encodable[] a) + public DERSet(ASN1Encodable[] elements) { - super(a, true); + super(elements, true); } - DERSet( - ASN1EncodableVector v, - boolean doSort) + DERSet(boolean isSorted, ASN1Encodable[] elements) { - super(v, doSort); + super(checkSorted(isSorted), elements); } - private int getBodyLength() - throws IOException + private int getBodyLength() throws IOException { if (bodyLength < 0) { - int length = 0; + int count = elements.length; + int totalLength = 0; - for (Enumeration e = this.getObjects(); e.hasMoreElements();) + for (int i = 0; i < count; ++i) { - Object obj = e.nextElement(); - - length += ((ASN1Encodable)obj).toASN1Primitive().toDERObject().encodedLength(); + ASN1Primitive derObject = elements[i].toASN1Primitive().toDERObject(); + totalLength += derObject.encodedLength(); } - bodyLength = length; + this.bodyLength = totalLength; } return bodyLength; } - int encodedLength() - throws IOException + int encodedLength() throws IOException { int length = getBodyLength(); @@ -98,21 +96,64 @@ public class DERSet * ASN.1 descriptions given. Rather than just outputting SET, * we also have to specify CONSTRUCTED, and the objects length. */ - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - ASN1OutputStream dOut = out.getDERSubStream(); - int length = getBodyLength(); + if (withTag) + { + out.write(BERTags.SET | BERTags.CONSTRUCTED); + } - out.write(BERTags.SET | BERTags.CONSTRUCTED); - out.writeLength(length); + DEROutputStream derOut = out.getDERSubStream(); - for (Enumeration e = this.getObjects(); e.hasMoreElements();) + int count = elements.length; + if (bodyLength >= 0 || count > 16) { - Object obj = e.nextElement(); + out.writeLength(getBodyLength()); + + for (int i = 0; i < count; ++i) + { + ASN1Primitive derObject = elements[i].toASN1Primitive().toDERObject(); + derObject.encode(derOut, true); + } + } + else + { + int totalLength = 0; + + ASN1Primitive[] derObjects = new ASN1Primitive[count]; + for (int i = 0; i < count; ++i) + { + ASN1Primitive derObject = elements[i].toASN1Primitive().toDERObject(); + derObjects[i] = derObject; + totalLength += derObject.encodedLength(); + } - dOut.writeObject((ASN1Encodable)obj); + this.bodyLength = totalLength; + out.writeLength(totalLength); + + for (int i = 0; i < count; ++i) + { + derObjects[i].encode(derOut, true); + } + } + } + + ASN1Primitive toDERObject() + { + return isSorted ? this : super.toDERObject(); + } + + ASN1Primitive toDLObject() + { + return this; + } + + private static boolean checkSorted(boolean isSorted) + { + if (!isSorted) + { + throw new IllegalStateException("DERSet elements should always be in sorted order"); } + return isSorted; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSetParser.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSetParser.java index 310fa5059..34b768833 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSetParser.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERSetParser.java @@ -3,7 +3,7 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; /** - * Parser class for DER SETs. + * @deprecated Use DLSetParser instead */ public class DERSetParser implements ASN1SetParser @@ -36,7 +36,7 @@ public class DERSetParser public ASN1Primitive getLoadedObject() throws IOException { - return new DERSet(_parser.readVector(), false); + return new DLSet(_parser.readVector()); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERT61String.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERT61String.java index 10cd86479..f6dec6139 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERT61String.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERT61String.java @@ -117,11 +117,9 @@ public class DERT61String return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.T61_STRING, string); + out.writeEncoded(withTag, BERTags.T61_STRING, string); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERT61UTF8String.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERT61UTF8String.java index c80c3ea94..ad775e486 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERT61UTF8String.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERT61UTF8String.java @@ -120,11 +120,9 @@ public class DERT61UTF8String return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.T61_STRING, string); + out.writeEncoded(withTag, BERTags.T61_STRING, string); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERTaggedObject.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERTaggedObject.java index 00df03a07..c5d14dd38 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERTaggedObject.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERTaggedObject.java @@ -10,8 +10,6 @@ import java.io.IOException; public class DERTaggedObject extends ASN1TaggedObject { - private static final byte[] ZERO_BYTES = new byte[0]; - /** * @param explicit true if an explicitly tagged object. * @param tagNo the tag number for this object. @@ -32,87 +30,55 @@ public class DERTaggedObject boolean isConstructed() { - if (!empty) - { - if (explicit) - { - return true; - } - else - { - ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); - - return primitive.isConstructed(); - } - } - else - { - return true; - } + return explicit || obj.toASN1Primitive().toDERObject().isConstructed(); } int encodedLength() throws IOException { - if (!empty) - { - ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); - int length = primitive.encodedLength(); - - if (explicit) - { - return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; - } - else - { - // header length already in calculation - length = length - 1; + ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); + int length = primitive.encodedLength(); - return StreamUtil.calculateTagLength(tagNo) + length; - } + if (explicit) + { + return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; } else { - return StreamUtil.calculateTagLength(tagNo) + 1; + // header length already in calculation + length = length - 1; + + return StreamUtil.calculateTagLength(tagNo) + length; } } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - if (!empty) + ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); + + int flags = BERTags.TAGGED; + if (explicit || primitive.isConstructed()) { - ASN1Primitive primitive = obj.toASN1Primitive().toDERObject(); + flags |= BERTags.CONSTRUCTED; + } - if (explicit) - { - out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo); - out.writeLength(primitive.encodedLength()); - out.writeObject(primitive); - } - else - { - // - // need to mark constructed types... - // - int flags; - if (primitive.isConstructed()) - { - flags = BERTags.CONSTRUCTED | BERTags.TAGGED; - } - else - { - flags = BERTags.TAGGED; - } + out.writeTag(withTag, flags, tagNo); - out.writeTag(flags, tagNo); - out.writeImplicitObject(primitive); - } - } - else + if (explicit) { - out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES); + out.writeLength(primitive.encodedLength()); } + + primitive.encode(out.getDERSubStream(), explicit); + } + + ASN1Primitive toDERObject() + { + return this; + } + + ASN1Primitive toDLObject() + { + return this; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERUTF8String.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERUTF8String.java index d8c8b6f5b..b4b7103f3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERUTF8String.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERUTF8String.java @@ -129,9 +129,8 @@ public class DERUTF8String return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode(ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.UTF8_STRING, string); + out.writeEncoded(withTag, BERTags.UTF8_STRING, string); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERUniversalString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERUniversalString.java index 3455b47e4..4c8450580 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERUniversalString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERUniversalString.java @@ -1,6 +1,5 @@ package com.fr.third.org.bouncycastle.asn1; -import java.io.ByteArrayOutputStream; import java.io.IOException; import com.fr.third.org.bouncycastle.util.Arrays; @@ -68,7 +67,7 @@ public class DERUniversalString } else { - return new DERUniversalString(((ASN1OctetString)o).getOctets()); + return new DERUniversalString(ASN1OctetString.getInstance(o).getOctets()); } } @@ -85,21 +84,18 @@ public class DERUniversalString public String getString() { - StringBuffer buf = new StringBuffer("#"); - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - + StringBuffer buf = new StringBuffer("#"); + + byte[] string; try { - aOut.writeObject(this); + string = getEncoded(); } catch (IOException e) { throw new ASN1ParsingException("internal error encoding UniversalString"); } - - byte[] string = bOut.toByteArray(); - + for (int i = 0; i != string.length; i++) { buf.append(table[(string[i] >>> 4) & 0xf]); @@ -129,13 +125,11 @@ public class DERUniversalString return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.UNIVERSAL_STRING, this.getOctets()); + out.writeEncoded(withTag, BERTags.UNIVERSAL_STRING, string); } - + boolean asn1Equals( ASN1Primitive o) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERVideotexString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERVideotexString.java index 9c38495b4..3bb354238 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERVideotexString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERVideotexString.java @@ -63,7 +63,7 @@ public class DERVideotexString } else { - return new DERVideotexString(((ASN1OctetString)o).getOctets()); + return new DERVideotexString(ASN1OctetString.getInstance(o).getOctets()); } } @@ -92,11 +92,9 @@ public class DERVideotexString return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.VIDEOTEX_STRING, string); + out.writeEncoded(withTag, BERTags.VIDEOTEX_STRING, string); } public int hashCode() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERVisibleString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERVisibleString.java index 105ff972c..6fadd4beb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERVisibleString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DERVisibleString.java @@ -118,13 +118,11 @@ public class DERVisibleString return 1 + StreamUtil.calculateBodyLength(string.length) + string.length; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - out.writeEncoded(BERTags.VISIBLE_STRING, this.string); + out.writeEncoded(withTag, BERTags.VISIBLE_STRING, this.string); } - + boolean asn1Equals( ASN1Primitive o) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLApplicationSpecific.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLApplicationSpecific.java new file mode 100644 index 000000000..2f17d6e79 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLApplicationSpecific.java @@ -0,0 +1,124 @@ +package com.fr.third.org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * A DER encoding version of an application specific object. + */ +public class DLApplicationSpecific + extends ASN1ApplicationSpecific +{ + DLApplicationSpecific( + boolean isConstructed, + int tag, + byte[] octets) + { + super(isConstructed, tag, octets); + } + + /** + * Create an application specific object from the passed in data. This will assume + * the data does not represent a constructed object. + * + * @param tag the tag number for this object. + * @param octets the encoding of the object's body. + */ + public DLApplicationSpecific( + int tag, + byte[] octets) + { + this(false, tag, octets); + } + + /** + * Create an application specific object with a tagging of explicit/constructed. + * + * @param tag the tag number for this object. + * @param object the object to be contained. + */ + public DLApplicationSpecific( + int tag, + ASN1Encodable object) + throws IOException + { + this(true, tag, object); + } + + /** + * Create an application specific object with the tagging style given by the value of constructed. + * + * @param constructed true if the object is constructed. + * @param tag the tag number for this object. + * @param object the object to be contained. + */ + public DLApplicationSpecific( + boolean constructed, + int tag, + ASN1Encodable object) + throws IOException + { + super(constructed || object.toASN1Primitive().isConstructed(), tag, getEncoding(constructed, object)); + } + + private static byte[] getEncoding(boolean explicit, ASN1Encodable object) + throws IOException + { + byte[] data = object.toASN1Primitive().getEncoded(ASN1Encoding.DL); + + if (explicit) + { + return data; + } + else + { + int lenBytes = getLengthOfHeader(data); + byte[] tmp = new byte[data.length - lenBytes]; + System.arraycopy(data, lenBytes, tmp, 0, tmp.length); + return tmp; + } + } + + /** + * Create an application specific object which is marked as constructed + * + * @param tagNo the tag number for this object. + * @param vec the objects making up the application specific object. + */ + public DLApplicationSpecific(int tagNo, ASN1EncodableVector vec) + { + super(true, tagNo, getEncodedVector(vec)); + } + + private static byte[] getEncodedVector(ASN1EncodableVector vec) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + for (int i = 0; i != vec.size(); i++) + { + try + { + bOut.write(((ASN1Object)vec.get(i)).getEncoded(ASN1Encoding.DL)); + } + catch (IOException e) + { + throw new ASN1ParsingException("malformed object: " + e, e); + } + } + return bOut.toByteArray(); + } + + /* (non-Javadoc) + * @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#encode(com.fr.third.org.bouncycastle.asn1.DEROutputStream) + */ + void encode(ASN1OutputStream out, boolean withTag) throws IOException + { + int flags = BERTags.APPLICATION; + if (isConstructed) + { + flags |= BERTags.CONSTRUCTED; + } + + out.writeEncoded(withTag, flags, tag, octets); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLBitString.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLBitString.java index 90fa6f6c7..b72963fc9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLBitString.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLBitString.java @@ -63,24 +63,13 @@ public class DLBitString } else { - return fromOctetString(((ASN1OctetString)o).getOctets()); + return fromOctetString(ASN1OctetString.getInstance(o).getOctets()); } } - protected DLBitString( - byte data, - int padBits) - { - this(toByteArray(data), padBits); - } - - private static byte[] toByteArray(byte data) + protected DLBitString(byte data, int padBits) { - byte[] rv = new byte[1]; - - rv[0] = data; - - return rv; + super(data, padBits); } /** @@ -123,17 +112,14 @@ public class DLBitString return 1 + StreamUtil.calculateBodyLength(data.length + 1) + data.length + 1; } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - byte[] string = data; - byte[] bytes = new byte[string.length + 1]; - - bytes[0] = (byte)getPadBits(); - System.arraycopy(string, 0, bytes, 1, bytes.length - 1); + out.writeEncoded(withTag, BERTags.BIT_STRING, (byte)padBits, data); + } - out.writeEncoded(BERTags.BIT_STRING, bytes); + ASN1Primitive toDLObject() + { + return this; } static DLBitString fromOctetString(byte[] bytes) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLExternal.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLExternal.java new file mode 100644 index 000000000..201cec5f8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLExternal.java @@ -0,0 +1,90 @@ +package com.fr.third.org.bouncycastle.asn1; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +/** + * Class representing the Definite-Length-type External + */ +public class DLExternal + extends ASN1External +{ + /** + * Construct a Definite-Length EXTERNAL object, the input encoding vector must have exactly two elements on it. + *

+ * Acceptable input formats are: + *

    + *
  • {@link ASN1ObjectIdentifier} + data {@link DERTaggedObject} (direct reference form)
  • + *
  • {@link ASN1Integer} + data {@link DERTaggedObject} (indirect reference form)
  • + *
  • Anything but {@link DERTaggedObject} + data {@link DERTaggedObject} (data value form)
  • + *
+ * + * @throws IllegalArgumentException if input size is wrong, or + */ + public DLExternal(ASN1EncodableVector vector) + { + super(vector); + } + + /** + * Creates a new instance of DERExternal + * See X.690 for more informations about the meaning of these parameters + * @param directReference The direct reference or null if not set. + * @param indirectReference The indirect reference or null if not set. + * @param dataValueDescriptor The data value descriptor or null if not set. + * @param externalData The external data in its encoded form. + */ + public DLExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, DERTaggedObject externalData) + { + this(directReference, indirectReference, dataValueDescriptor, externalData.getTagNo(), externalData.toASN1Primitive()); + } + + /** + * Creates a new instance of Definite-Length External. + * See X.690 for more informations about the meaning of these parameters + * @param directReference The direct reference or null if not set. + * @param indirectReference The indirect reference or null if not set. + * @param dataValueDescriptor The data value descriptor or null if not set. + * @param encoding The encoding to be used for the external data + * @param externalData The external data + */ + public DLExternal(ASN1ObjectIdentifier directReference, ASN1Integer indirectReference, ASN1Primitive dataValueDescriptor, int encoding, ASN1Primitive externalData) + { + super(directReference, indirectReference, dataValueDescriptor, encoding, externalData); + } + + ASN1Primitive toDLObject() + { + return this; + } + + int encodedLength() + throws IOException + { + return this.getEncoded().length; + } + + /* (non-Javadoc) + * @see com.fr.third.org.bouncycastle.asn1.ASN1Primitive#encode(com.fr.third.org.bouncycastle.asn1.DEROutputStream) + */ + void encode(ASN1OutputStream out, boolean withTag) throws IOException + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + if (directReference != null) + { + baos.write(directReference.getEncoded(ASN1Encoding.DL)); + } + if (indirectReference != null) + { + baos.write(indirectReference.getEncoded(ASN1Encoding.DL)); + } + if (dataValueDescriptor != null) + { + baos.write(dataValueDescriptor.getEncoded(ASN1Encoding.DL)); + } + DERTaggedObject obj = new DERTaggedObject(true, encoding, externalContent); + baos.write(obj.getEncoded(ASN1Encoding.DL)); + + out.writeEncoded(withTag, BERTags.CONSTRUCTED, BERTags.EXTERNAL, baos.toByteArray()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLFactory.java new file mode 100644 index 000000000..2ec73c663 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLFactory.java @@ -0,0 +1,27 @@ +package com.fr.third.org.bouncycastle.asn1; + +class DLFactory +{ + static final ASN1Sequence EMPTY_SEQUENCE = new DLSequence(); + static final ASN1Set EMPTY_SET = new DLSet(); + + static ASN1Sequence createSequence(ASN1EncodableVector v) + { + if (v.size() < 1) + { + return EMPTY_SEQUENCE; + } + + return new DLSequence(v); + } + + static ASN1Set createSet(ASN1EncodableVector v) + { + if (v.size() < 1) + { + return EMPTY_SET; + } + + return new DLSet(v); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLOutputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLOutputStream.java index 4ca26459f..d80b0e61e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLOutputStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLOutputStream.java @@ -5,27 +5,28 @@ import java.io.OutputStream; /** * Stream that outputs encoding based on definite length. + * + * @deprecated Will be removed from public API. */ public class DLOutputStream extends ASN1OutputStream { - public DLOutputStream( - OutputStream os) + /** + * @deprecated Use {@link ASN1OutputStream#create(OutputStream, String)} with + * {@link ASN1Encoding#DL} instead. + */ + public DLOutputStream(OutputStream os) { super(os); } - public void writeObject( - ASN1Encodable obj) - throws IOException + void writePrimitive(ASN1Primitive primitive, boolean withTag) throws IOException { - if (obj != null) - { - obj.toASN1Primitive().toDLObject().encode(this); - } - else - { - throw new IOException("null object detected"); - } + primitive.toDLObject().encode(this, withTag); + } + + ASN1OutputStream getDLSubStream() + { + return this; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSequence.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSequence.java index 289b0862e..f11400597 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSequence.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSequence.java @@ -1,7 +1,6 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; -import java.util.Enumeration; /** * The DLSequence encodes a SEQUENCE using definite length form. @@ -20,56 +19,56 @@ public class DLSequence /** * create a sequence containing one object - * @param obj the object to go in the sequence. + * @param element the object to go in the sequence. */ - public DLSequence( - ASN1Encodable obj) + public DLSequence(ASN1Encodable element) { - super(obj); + super(element); } /** * create a sequence containing a vector of objects. - * @param v the vector of objects to make up the sequence. + * @param elementVector the vector of objects to make up the sequence. */ - public DLSequence( - ASN1EncodableVector v) + public DLSequence(ASN1EncodableVector elementVector) { - super(v); + super(elementVector); } /** * create a sequence containing an array of objects. - * @param array the array of objects to make up the sequence. + * @param elements the array of objects to make up the sequence. */ - public DLSequence( - ASN1Encodable[] array) + public DLSequence(ASN1Encodable[] elements) { - super(array); + super(elements); } - private int getBodyLength() - throws IOException + DLSequence(ASN1Encodable[] elements, boolean clone) + { + super(elements, clone); + } + + private int getBodyLength() throws IOException { if (bodyLength < 0) { - int length = 0; + int count = elements.length; + int totalLength = 0; - for (Enumeration e = this.getObjects(); e.hasMoreElements();) + for (int i = 0; i < count; ++i) { - Object obj = e.nextElement(); - - length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength(); + ASN1Primitive dlObject = elements[i].toASN1Primitive().toDLObject(); + totalLength += dlObject.encodedLength(); } - bodyLength = length; + this.bodyLength = totalLength; } return bodyLength; } - int encodedLength() - throws IOException + int encodedLength() throws IOException { int length = getBodyLength(); @@ -84,21 +83,49 @@ public class DLSequence * ASN.1 descriptions given. Rather than just outputting SEQUENCE, * we also have to specify CONSTRUCTED, and the objects length. */ - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - ASN1OutputStream dOut = out.getDLSubStream(); - int length = getBodyLength(); + if (withTag) + { + out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); + } - out.write(BERTags.SEQUENCE | BERTags.CONSTRUCTED); - out.writeLength(length); + ASN1OutputStream dlOut = out.getDLSubStream(); - for (Enumeration e = this.getObjects(); e.hasMoreElements();) + int count = elements.length; + if (bodyLength >= 0 || count > 16) { - Object obj = e.nextElement(); + out.writeLength(getBodyLength()); - dOut.writeObject((ASN1Encodable)obj); + for (int i = 0; i < count; ++i) + { + dlOut.writePrimitive(elements[i].toASN1Primitive(), true); + } } + else + { + int totalLength = 0; + + ASN1Primitive[] dlObjects = new ASN1Primitive[count]; + for (int i = 0; i < count; ++i) + { + ASN1Primitive dlObject = elements[i].toASN1Primitive().toDLObject(); + dlObjects[i] = dlObject; + totalLength += dlObject.encodedLength(); + } + + this.bodyLength = totalLength; + out.writeLength(totalLength); + + for (int i = 0; i < count; ++i) + { + dlOut.writePrimitive(dlObjects[i], true); + } + } + } + + ASN1Primitive toDLObject() + { + return this; } } \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSequenceParser.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSequenceParser.java new file mode 100644 index 000000000..52eaa8b2b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSequenceParser.java @@ -0,0 +1,12 @@ +package com.fr.third.org.bouncycastle.asn1; + +/** + * Parser class for DL SEQUENCEs. + */ +public class DLSequenceParser extends DERSequenceParser +{ + DLSequenceParser(ASN1StreamParser parser) + { + super(parser); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSet.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSet.java index 1be203eb3..0f8352d75 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSet.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSet.java @@ -1,7 +1,6 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; -import java.util.Enumeration; /** * The DLSet encodes ASN.1 SET value without element ordering, @@ -64,54 +63,54 @@ public class DLSet } /** - * @param obj - a single object that makes up the set. + * @param element - a single object that makes up the set. */ - public DLSet( - ASN1Encodable obj) + public DLSet(ASN1Encodable element) { - super(obj); + super(element); } /** - * @param v - a vector of objects making up the set. + * @param elementVector - a vector of objects making up the set. */ - public DLSet( - ASN1EncodableVector v) + public DLSet(ASN1EncodableVector elementVector) { - super(v, false); + super(elementVector, false); } /** * create a set from an array of objects. */ - public DLSet( - ASN1Encodable[] a) + public DLSet(ASN1Encodable[] elements) { - super(a, false); + super(elements, false); } - private int getBodyLength() - throws IOException + DLSet(boolean isSorted, ASN1Encodable[] elements) + { + super(isSorted, elements); + } + + private int getBodyLength() throws IOException { if (bodyLength < 0) { - int length = 0; + int count = elements.length; + int totalLength = 0; - for (Enumeration e = this.getObjects(); e.hasMoreElements();) + for (int i = 0; i < count; ++i) { - Object obj = e.nextElement(); - - length += ((ASN1Encodable)obj).toASN1Primitive().toDLObject().encodedLength(); + ASN1Primitive dlObject = elements[i].toASN1Primitive().toDLObject(); + totalLength += dlObject.encodedLength(); } - bodyLength = length; + this.bodyLength = totalLength; } return bodyLength; } - int encodedLength() - throws IOException + int encodedLength() throws IOException { int length = getBodyLength(); @@ -126,21 +125,49 @@ public class DLSet * ASN.1 descriptions given. Rather than just outputting SET, * we also have to specify CONSTRUCTED, and the objects length. */ - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - ASN1OutputStream dOut = out.getDLSubStream(); - int length = getBodyLength(); + if (withTag) + { + out.write(BERTags.SET | BERTags.CONSTRUCTED); + } - out.write(BERTags.SET | BERTags.CONSTRUCTED); - out.writeLength(length); + ASN1OutputStream dlOut = out.getDLSubStream(); - for (Enumeration e = this.getObjects(); e.hasMoreElements();) + int count = elements.length; + if (bodyLength >= 0 || count > 16) { - Object obj = e.nextElement(); + out.writeLength(getBodyLength()); - dOut.writeObject((ASN1Encodable)obj); + for (int i = 0; i < count; ++i) + { + dlOut.writePrimitive(elements[i].toASN1Primitive(), true); + } } + else + { + int totalLength = 0; + + ASN1Primitive[] dlObjects = new ASN1Primitive[count]; + for (int i = 0; i < count; ++i) + { + ASN1Primitive dlObject = elements[i].toASN1Primitive().toDLObject(); + dlObjects[i] = dlObject; + totalLength += dlObject.encodedLength(); + } + + this.bodyLength = totalLength; + out.writeLength(totalLength); + + for (int i = 0; i < count; ++i) + { + dlOut.writePrimitive(dlObjects[i], true); + } + } + } + + ASN1Primitive toDLObject() + { + return this; } } \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSetParser.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSetParser.java new file mode 100644 index 000000000..121efef20 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLSetParser.java @@ -0,0 +1,12 @@ +package com.fr.third.org.bouncycastle.asn1; + +/** + * Parser class for DL SETs. + */ +public class DLSetParser extends DERSetParser +{ + DLSetParser(ASN1StreamParser parser) + { + super(parser); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLTaggedObject.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLTaggedObject.java index fbf05eb6e..9b82f1dc6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLTaggedObject.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DLTaggedObject.java @@ -10,8 +10,6 @@ import java.io.IOException; public class DLTaggedObject extends ASN1TaggedObject { - private static final byte[] ZERO_BYTES = new byte[0]; - /** * @param explicit true if an explicitly tagged object. * @param tagNo the tag number for this object. @@ -27,86 +25,49 @@ public class DLTaggedObject boolean isConstructed() { - if (!empty) - { - if (explicit) - { - return true; - } - else - { - ASN1Primitive primitive = obj.toASN1Primitive().toDLObject(); - - return primitive.isConstructed(); - } - } - else - { - return true; - } + return explicit || obj.toASN1Primitive().toDLObject().isConstructed(); } int encodedLength() throws IOException { - if (!empty) - { - int length = obj.toASN1Primitive().toDLObject().encodedLength(); + int length = obj.toASN1Primitive().toDLObject().encodedLength(); - if (explicit) - { - return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; - } - else - { - // header length already in calculation - length = length - 1; - - return StreamUtil.calculateTagLength(tagNo) + length; - } + if (explicit) + { + return StreamUtil.calculateTagLength(tagNo) + StreamUtil.calculateBodyLength(length) + length; } else { - return StreamUtil.calculateTagLength(tagNo) + 1; + // header length already in calculation + length = length - 1; + + return StreamUtil.calculateTagLength(tagNo) + length; } } - void encode( - ASN1OutputStream out) - throws IOException + void encode(ASN1OutputStream out, boolean withTag) throws IOException { - if (!empty) + ASN1Primitive primitive = obj.toASN1Primitive().toDLObject(); + + int flags = BERTags.TAGGED; + if (explicit || primitive.isConstructed()) { - ASN1Primitive primitive = obj.toASN1Primitive().toDLObject(); + flags |= BERTags.CONSTRUCTED; + } - if (explicit) - { - out.writeTag(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo); - out.writeLength(primitive.encodedLength()); - out.writeObject(primitive); - } - else - { - // - // need to mark constructed types... - // - int flags; - if (primitive.isConstructed()) - { - flags = BERTags.CONSTRUCTED | BERTags.TAGGED; - } - else - { - flags = BERTags.TAGGED; - } + out.writeTag(withTag, flags, tagNo); - out.writeTag(flags, tagNo); - out.writeImplicitObject(primitive); - } - } - else + if (explicit) { - out.writeEncoded(BERTags.CONSTRUCTED | BERTags.TAGGED, tagNo, ZERO_BYTES); + out.writeLength(primitive.encodedLength()); } + + out.getDLSubStream().writePrimitive(primitive, explicit); + } + + ASN1Primitive toDLObject() + { + return this; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DateUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DateUtil.java new file mode 100644 index 000000000..0b3f51fa2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DateUtil.java @@ -0,0 +1,80 @@ +package com.fr.third.org.bouncycastle.asn1; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.Map; + +class DateUtil +{ + private static Long ZERO = longValueOf(0); + + private static final Map localeCache = new HashMap(); + + static Locale EN_Locale = forEN(); + + private static Locale forEN() + { + if ("en".equalsIgnoreCase(Locale.getDefault().getLanguage())) + { + return Locale.getDefault(); + } + + Locale[] locales = Locale.getAvailableLocales(); + for (int i = 0; i != locales.length; i++) + { + if ("en".equalsIgnoreCase(locales[i].getLanguage())) + { + return locales[i]; + } + } + + return Locale.getDefault(); + } + + static Date epochAdjust(Date date) + throws ParseException + { + Locale locale = Locale.getDefault(); + if (locale == null) + { + return date; + } + + synchronized (localeCache) + { + Long adj = (Long)localeCache.get(locale); + + if (adj == null) + { + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmssz"); + long v = dateF.parse("19700101000000GMT+00:00").getTime(); + + if (v == 0) + { + adj = ZERO; + } + else + { + adj = longValueOf(v); + } + + localeCache.put(locale, adj); + } + + if (adj != ZERO) + { + return new Date(date.getTime() - adj.longValue()); + } + + return date; + } + } + + private static Long longValueOf(long v) + { + return Long.valueOf(v); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DefiniteLengthInputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DefiniteLengthInputStream.java index eead95790..96f7fa4a1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DefiniteLengthInputStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/DefiniteLengthInputStream.java @@ -15,13 +15,15 @@ class DefiniteLengthInputStream private static final byte[] EMPTY_BYTES = new byte[0]; private final int _originalLength; + private int _remaining; DefiniteLengthInputStream( InputStream in, - int length) + int length, + int limit) { - super(in, length); + super(in, limit, length); if (length < 0) { @@ -97,6 +99,12 @@ class DefiniteLengthInputStream return EMPTY_BYTES; } + // make sure it's safe to do this! + if (_remaining >= this.getLimit()) + { + throw new IOException("corrupted stream - out of bounds length found: " + _remaining + " >= " + this.getLimit()); + } + byte[] bytes = new byte[_remaining]; if ((_remaining -= Streams.readFully(_in, bytes)) != 0) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/IndefiniteLengthInputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/IndefiniteLengthInputStream.java index 1c3bfc70a..30f6757bd 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/IndefiniteLengthInputStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/IndefiniteLengthInputStream.java @@ -17,7 +17,7 @@ class IndefiniteLengthInputStream int limit) throws IOException { - super(in, limit); + super(in, limit, limit); _b1 = in.read(); _b2 = in.read(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/LazyEncodedSequence.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/LazyEncodedSequence.java index 040f6e983..641c0904a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/LazyEncodedSequence.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/LazyEncodedSequence.java @@ -2,6 +2,7 @@ package com.fr.third.org.bouncycastle.asn1; import java.io.IOException; import java.util.Enumeration; +import java.util.Iterator; /** * Note: this class is for processing DER/DL encoded sequences only. @@ -11,99 +12,117 @@ class LazyEncodedSequence { private byte[] encoded; - LazyEncodedSequence( - byte[] encoded) - throws IOException + LazyEncodedSequence(byte[] encoded) throws IOException { + // NOTE: Initially, the actual 'elements' will be empty + super(); + this.encoded = encoded; } - private void parse() + public synchronized ASN1Encodable getObjectAt(int index) { - Enumeration en = new LazyConstructionEnumeration(encoded); + force(); + + return super.getObjectAt(index); + } - while (en.hasMoreElements()) + public synchronized Enumeration getObjects() + { + if (null != encoded) { - seq.addElement(en.nextElement()); + return new LazyConstructionEnumeration(encoded); } - encoded = null; + return super.getObjects(); } - public synchronized ASN1Encodable getObjectAt(int index) + public synchronized int hashCode() { - if (encoded != null) - { - parse(); - } + force(); - return super.getObjectAt(index); + return super.hashCode(); } - public synchronized Enumeration getObjects() + public synchronized Iterator iterator() { - if (encoded == null) - { - return super.getObjects(); - } + force(); - return new LazyConstructionEnumeration(encoded); + return super.iterator(); } public synchronized int size() { - if (encoded != null) - { - parse(); - } + force(); return super.size(); } - ASN1Primitive toDERObject() + public synchronized ASN1Encodable[] toArray() { - if (encoded != null) - { - parse(); - } + force(); - return super.toDERObject(); + return super.toArray(); } - ASN1Primitive toDLObject() + ASN1Encodable[] toArrayInternal() { - if (encoded != null) - { - parse(); - } + force(); - return super.toDLObject(); + return super.toArrayInternal(); } - int encodedLength() + synchronized int encodedLength() throws IOException { - if (encoded != null) + if (null != encoded) { return 1 + StreamUtil.calculateBodyLength(encoded.length) + encoded.length; } - else - { - return super.toDLObject().encodedLength(); - } + + return super.toDLObject().encodedLength(); } - void encode( - ASN1OutputStream out) - throws IOException + synchronized void encode(ASN1OutputStream out, boolean withTag) throws IOException { - if (encoded != null) + if (null != encoded) { - out.writeEncoded(BERTags.SEQUENCE | BERTags.CONSTRUCTED, encoded); + out.writeEncoded(withTag, BERTags.SEQUENCE | BERTags.CONSTRUCTED, encoded); } else { - super.toDLObject().encode(out); + super.toDLObject().encode(out, withTag); + } + } + + synchronized ASN1Primitive toDERObject() + { + force(); + + return super.toDERObject(); + } + + synchronized ASN1Primitive toDLObject() + { + force(); + + return super.toDLObject(); + } + + private void force() + { + if (null != encoded) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + Enumeration en = new LazyConstructionEnumeration(encoded); + while (en.hasMoreElements()) + { + v.add((ASN1Primitive)en.nextElement()); + } + + this.elements = v.takeElements(); + this.encoded = null; } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/LimitedInputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/LimitedInputStream.java index e4554f1c5..372cec878 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/LimitedInputStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/LimitedInputStream.java @@ -10,19 +10,27 @@ abstract class LimitedInputStream { protected final InputStream _in; private int _limit; + private int _length; LimitedInputStream( InputStream in, - int limit) + int limit, + int length) { this._in = in; this._limit = limit; + this._length = length; + } + + int getLimit() + { + return _limit; } int getRemaining() { // TODO: maybe one day this can become more accurate - return _limit; + return _length; } protected void setParentEofDetect(boolean on) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/StreamUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/StreamUtil.java index 9d3f2c055..3adb0e2d6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/StreamUtil.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/StreamUtil.java @@ -11,7 +11,7 @@ class StreamUtil private static final long MAX_MEMORY = Runtime.getRuntime().maxMemory(); /** - * Find out possible longest length... + * Find out possible longest length, capped by available memory. * * @param in input stream of interest * @return length calculation or MAX_VALUE. @@ -20,7 +20,7 @@ class StreamUtil { if (in instanceof LimitedInputStream) { - return ((LimitedInputStream)in).getRemaining(); + return ((LimitedInputStream)in).getLimit(); } else if (in instanceof ASN1InputStream) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/anssi/ANSSINamedCurves.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/anssi/ANSSINamedCurves.java index c45799b86..651f91470 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/anssi/ANSSINamedCurves.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/anssi/ANSSINamedCurves.java @@ -9,6 +9,7 @@ import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParametersHolder; import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.WNafUtil; import com.fr.third.org.bouncycastle.util.Strings; import com.fr.third.org.bouncycastle.util.encoders.Hex; @@ -17,15 +18,21 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; */ public class ANSSINamedCurves { + private static X9ECPoint configureBasepoint(ECCurve curve, String encoding) + { + X9ECPoint G = new X9ECPoint(curve, Hex.decodeStrict(encoding)); + WNafUtil.configureBasepoint(G.getPoint()); + return G; + } + private static ECCurve configureCurve(ECCurve curve) { return curve; } - private static BigInteger fromHex( - String hex) + private static BigInteger fromHex(String hex) { - return new BigInteger(1, Hex.decode(hex)); + return new BigInteger(1, Hex.decodeStrict(hex)); } /* @@ -43,9 +50,8 @@ public class ANSSINamedCurves BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "B6B3D4C356C139EB31183D4749D423958C27D2DCAF98B70164C97A2DD98F5CFF" - + "6142E0F7C8B204911F9271F0F3ECEF8C2701C307E8E4C9E183115A1554062CFB")); + X9ECPoint G = configureBasepoint(curve, + "04B6B3D4C356C139EB31183D4749D423958C27D2DCAF98B70164C97A2DD98F5CFF6142E0F7C8B204911F9271F0F3ECEF8C2701C307E8E4C9E183115A1554062CFB"); return new X9ECParameters(curve, G, n, h, S); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/anssi/ANSSIObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/anssi/ANSSIObjectIdentifiers.java index c968285b0..94313b6ea 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/anssi/ANSSIObjectIdentifiers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/anssi/ANSSIObjectIdentifiers.java @@ -7,5 +7,5 @@ import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; */ public interface ANSSIObjectIdentifiers { - static final ASN1ObjectIdentifier FRP256v1 = new ASN1ObjectIdentifier("1.2.250.1.223.101.256.1"); + ASN1ObjectIdentifier FRP256v1 = new ASN1ObjectIdentifier("1.2.250.1.223.101.256.1"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java index b24db009e..642e0c36e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/BCObjectIdentifiers.java @@ -83,20 +83,78 @@ public interface BCObjectIdentifiers /** * XMSS */ - public static final ASN1ObjectIdentifier xmss = bc_sig.branch("2"); - public static final ASN1ObjectIdentifier xmss_with_SHA256 = xmss.branch("1"); - public static final ASN1ObjectIdentifier xmss_with_SHA512 = xmss.branch("2"); - public static final ASN1ObjectIdentifier xmss_with_SHAKE128 = xmss.branch("3"); - public static final ASN1ObjectIdentifier xmss_with_SHAKE256 = xmss.branch("4"); + public static final ASN1ObjectIdentifier xmss = bc_sig.branch("2"); + public static final ASN1ObjectIdentifier xmss_SHA256ph = xmss.branch("1"); + public static final ASN1ObjectIdentifier xmss_SHA512ph = xmss.branch("2"); + public static final ASN1ObjectIdentifier xmss_SHAKE128ph = xmss.branch("3"); + public static final ASN1ObjectIdentifier xmss_SHAKE256ph = xmss.branch("4"); + public static final ASN1ObjectIdentifier xmss_SHA256 = xmss.branch("5"); + public static final ASN1ObjectIdentifier xmss_SHA512 = xmss.branch("6"); + public static final ASN1ObjectIdentifier xmss_SHAKE128 = xmss.branch("7"); + public static final ASN1ObjectIdentifier xmss_SHAKE256 = xmss.branch("8"); /** * XMSS^MT */ - public static final ASN1ObjectIdentifier xmss_mt = bc_sig.branch("3"); - public static final ASN1ObjectIdentifier xmss_mt_with_SHA256 = xmss_mt.branch("1"); - public static final ASN1ObjectIdentifier xmss_mt_with_SHA512 = xmss_mt.branch("2"); - public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE128 = xmss_mt.branch("3"); - public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE256 = xmss_mt.branch("4"); + public static final ASN1ObjectIdentifier xmss_mt = bc_sig.branch("3"); + public static final ASN1ObjectIdentifier xmss_mt_SHA256ph = xmss_mt.branch("1"); + public static final ASN1ObjectIdentifier xmss_mt_SHA512ph = xmss_mt.branch("2"); + public static final ASN1ObjectIdentifier xmss_mt_SHAKE128ph = xmss_mt.branch("3"); + public static final ASN1ObjectIdentifier xmss_mt_SHAKE256ph = xmss_mt.branch("4"); + public static final ASN1ObjectIdentifier xmss_mt_SHA256 = xmss_mt.branch("5"); + public static final ASN1ObjectIdentifier xmss_mt_SHA512 = xmss_mt.branch("6"); + public static final ASN1ObjectIdentifier xmss_mt_SHAKE128 = xmss_mt.branch("7"); + public static final ASN1ObjectIdentifier xmss_mt_SHAKE256 = xmss_mt.branch("8"); + + // old OIDs. + /** + * @deprecated use xmss_SHA256ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHA256 = xmss_SHA256ph; + /** + * @deprecated use xmss_SHA512ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHA512 = xmss_SHA512ph; + /** + * @deprecated use xmss_SHAKE128ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHAKE128 = xmss_SHAKE128ph; + /** + * @deprecated use xmss_SHAKE256ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHAKE256 = xmss_SHAKE256ph; + + /** + * @deprecated use xmss_mt_SHA256ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHA256 = xmss_mt_SHA256ph; + /** + * @deprecated use xmss_mt_SHA512ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHA512 = xmss_mt_SHA512ph; + /** + * @deprecated use xmss_mt_SHAKE128ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE128 = xmss_mt_SHAKE128; + /** + * @deprecated use xmss_mt_SHAKE256ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE256 = xmss_mt_SHAKE256; + + /** + * qTESLA + */ + public static final ASN1ObjectIdentifier qTESLA = bc_sig.branch("4"); + + public static final ASN1ObjectIdentifier qTESLA_Rnd1_I = qTESLA.branch("1"); + public static final ASN1ObjectIdentifier qTESLA_Rnd1_III_size = qTESLA.branch("2"); + public static final ASN1ObjectIdentifier qTESLA_Rnd1_III_speed = qTESLA.branch("3"); + public static final ASN1ObjectIdentifier qTESLA_Rnd1_p_I = qTESLA.branch("4"); + public static final ASN1ObjectIdentifier qTESLA_Rnd1_p_III = qTESLA.branch("5"); + + + public static final ASN1ObjectIdentifier qTESLA_p_I = qTESLA.branch("11"); + public static final ASN1ObjectIdentifier qTESLA_p_III = qTESLA.branch("12"); /** * key_exchange(3) algorithms @@ -107,4 +165,13 @@ public interface BCObjectIdentifiers * NewHope */ public static final ASN1ObjectIdentifier newHope = bc_exch.branch("1"); + + /** + * X.509 extension(4) values + *

+ * 1.3.6.1.4.1.22554.4 + */ + public static final ASN1ObjectIdentifier bc_ext = bc.branch("4"); + + public static final ASN1ObjectIdentifier linkedCertificate = bc_ext.branch("1"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java index f226f690e..5ac6413bb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedObjectStoreData.java @@ -61,7 +61,7 @@ public class EncryptedObjectStoreData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(encryptionAlgorithm); v.add(encryptedContent); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java index 16e26d0d6..910fdb9cd 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedPrivateKeyData.java @@ -70,7 +70,7 @@ public class EncryptedPrivateKeyData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(encryptedPrivateKeyInfo); v.add(new DERSequence(certificateChain)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java index ca24a57e2..faa4790e6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/EncryptedSecretKeyData.java @@ -63,7 +63,7 @@ public class EncryptedSecretKeyData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(keyEncryptionAlgorithm); v.add(encryptedKeyData); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/LinkedCertificate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/LinkedCertificate.java new file mode 100644 index 000000000..e46494658 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/LinkedCertificate.java @@ -0,0 +1,126 @@ +package com.fr.third.org.bouncycastle.asn1.bc; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Object; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.DigestInfo; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames; + +/** + * Extension to tie an alternate certificate to the containing certificate. + *

+ *     LinkedCertificate := SEQUENCE {
+ *         digest        DigestInfo,                   -- digest of PQC certificate
+ *         certLocation  GeneralName,                  -- location of PQC certificate
+ *         certIssuer    [0] Name OPTIONAL,            -- issuer of PQC cert (if different from current certificate)
+ *         cACerts       [1] GeneralNames OPTIONAL,    -- CA certificates for PQC cert (one of more locations)
+ * }
+ * 
+ */ +public class LinkedCertificate + extends ASN1Object +{ + private final DigestInfo digest; + private final GeneralName certLocation; + + private X500Name certIssuer; + private GeneralNames cACerts; + + public LinkedCertificate(DigestInfo digest, GeneralName certLocation) + { + this(digest, certLocation, null, null); + } + + public LinkedCertificate(DigestInfo digest, GeneralName certLocation, X500Name certIssuer, GeneralNames cACerts) + { + this.digest = digest; + this.certLocation = certLocation; + this.certIssuer = certIssuer; + this.cACerts = cACerts; + } + + private LinkedCertificate(ASN1Sequence seq) + { + this.digest = DigestInfo.getInstance(seq.getObjectAt(0)); + this.certLocation = GeneralName.getInstance(seq.getObjectAt(1)); + + if (seq.size() > 2) + { + for (int i = 2; i != seq.size(); i++) + { + ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(seq.getObjectAt(i)); + + switch (tagged.getTagNo()) + { + case 0: + certIssuer = X500Name.getInstance(tagged, false); + break; + case 1: + cACerts = GeneralNames.getInstance(tagged, false); + break; + default: + throw new IllegalArgumentException("unknown tag in tagged field"); + } + } + } + } + + public static LinkedCertificate getInstance(Object o) + { + if (o instanceof LinkedCertificate) + { + return (LinkedCertificate)o; + } + else if (o != null) + { + return new LinkedCertificate(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public DigestInfo getDigest() + { + return digest; + } + + public GeneralName getCertLocation() + { + return certLocation; + } + + public X500Name getCertIssuer() + { + return certIssuer; + } + + public GeneralNames getCACerts() + { + return cACerts; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(4); + + v.add(digest); + v.add(certLocation); + + if (certIssuer != null) + { + v.add(new DERTaggedObject(false, 0, certIssuer)); + } + if (cACerts != null) + { + v.add(new DERTaggedObject(false, 1, cACerts)); + } + + return new DERSequence(v); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectData.java index f3f77c148..7b79490e1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectData.java @@ -105,7 +105,7 @@ public class ObjectData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); v.add(new ASN1Integer(type)); v.add(new DERUTF8String(identifier)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStore.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStore.java index 7577dddda..4e8c95460 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStore.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStore.java @@ -96,7 +96,7 @@ public class ObjectStore public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(storeData); v.add(integrityCheck); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStoreData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStoreData.java index 379fe2048..b1a5af411 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStoreData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStoreData.java @@ -103,7 +103,7 @@ public class ObjectStoreData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); v.add(new ASN1Integer(version)); v.add(integrityAlgorithm); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java index ff845b774..81f47399d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/ObjectStoreIntegrityCheck.java @@ -7,11 +7,14 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1Object; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; /** *
  * ObjectStoreIntegrityCheck ::= CHOICE {
- *     PbeMacIntegrityCheck
+ *     PbkdMacIntegrityCheck
+ *     [0] EXPLICIT SignatureCheck
  * }
  * 
*/ @@ -20,6 +23,7 @@ public class ObjectStoreIntegrityCheck implements ASN1Choice { public static final int PBKD_MAC_CHECK = 0; + public static final int SIG_CHECK = 1; private final int type; private final ASN1Object integrityCheck; @@ -29,6 +33,11 @@ public class ObjectStoreIntegrityCheck this((ASN1Encodable)macIntegrityCheck); } + public ObjectStoreIntegrityCheck(SignatureCheck signatureCheck) + { + this(new DERTaggedObject(0, signatureCheck)); + } + private ObjectStoreIntegrityCheck(ASN1Encodable obj) { if (obj instanceof ASN1Sequence || obj instanceof PbkdMacIntegrityCheck) @@ -36,6 +45,11 @@ public class ObjectStoreIntegrityCheck this.type = PBKD_MAC_CHECK; this.integrityCheck = PbkdMacIntegrityCheck.getInstance(obj); } + else if (obj instanceof ASN1TaggedObject) + { + this.type = SIG_CHECK; + this.integrityCheck = SignatureCheck.getInstance(((ASN1TaggedObject)obj).getObject()); + } else { throw new IllegalArgumentException("Unknown check object in integrity check."); @@ -80,6 +94,10 @@ public class ObjectStoreIntegrityCheck public ASN1Primitive toASN1Primitive() { + if (integrityCheck instanceof SignatureCheck) + { + return new DERTaggedObject(0, integrityCheck); + } return integrityCheck.toASN1Primitive(); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java index 1fa5c3f41..b9e1b2ee0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/PbkdMacIntegrityCheck.java @@ -72,7 +72,7 @@ public class PbkdMacIntegrityCheck public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(macAlgorithm); v.add(pbkdAlgorithm); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/SecretKeyData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/SecretKeyData.java index d0f1ef092..74733a24f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/SecretKeyData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/SecretKeyData.java @@ -62,7 +62,7 @@ public class SecretKeyData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(keyAlgorithm); v.add(keyBytes); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/SignatureCheck.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/SignatureCheck.java new file mode 100644 index 000000000..cee1d2ca3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bc/SignatureCheck.java @@ -0,0 +1,117 @@ +package com.fr.third.org.bouncycastle.asn1.bc; + +import com.fr.third.org.bouncycastle.asn1.ASN1BitString; +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Object; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.util.Arrays; + +/** + *
+ * SignatureCheck ::= SEQUENCE {
+ *        signatureAlgorithm   AlgorithmIdentifier,
+ *        certificates         [0] EXPLICIT Certificates OPTIONAL,
+ *        signatureValue       BIT STRING
+ * }
+ *
+ * Certificates ::= SEQUENCE OF Certificate
+ * 
+ */ +public class SignatureCheck + extends ASN1Object +{ + private final AlgorithmIdentifier signatureAlgorithm; + private final ASN1Sequence certificates; + private final ASN1BitString signatureValue; + + public SignatureCheck(AlgorithmIdentifier signatureAlgorithm, byte[] signature) + { + this.signatureAlgorithm = signatureAlgorithm; + this.certificates = null; + this.signatureValue = new DERBitString(Arrays.clone(signature)); + } + + public SignatureCheck(AlgorithmIdentifier signatureAlgorithm, Certificate[] certificates, byte[] signature) + { + this.signatureAlgorithm = signatureAlgorithm; + this.certificates = new DERSequence(certificates); + this.signatureValue = new DERBitString(Arrays.clone(signature)); + } + + private SignatureCheck(ASN1Sequence seq) + { + this.signatureAlgorithm = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + int index = 1; + if (seq.getObjectAt(1) instanceof ASN1TaggedObject) + { + this.certificates = ASN1Sequence.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(index++)).getObject()); + } + else + { + this.certificates = null; + } + this.signatureValue = DERBitString.getInstance(seq.getObjectAt(index)); + } + + public static SignatureCheck getInstance(Object o) + { + if (o instanceof SignatureCheck) + { + return (SignatureCheck)o; + } + else if (o != null) + { + return new SignatureCheck(ASN1Sequence.getInstance(o)); + } + + return null; + } + + public ASN1BitString getSignature() + { + return new DERBitString(signatureValue.getBytes(), signatureValue.getPadBits()); + } + + public AlgorithmIdentifier getSignatureAlgorithm() + { + return signatureAlgorithm; + } + + public Certificate[] getCertificates() + { + if (certificates == null) + { + return null; + } + + Certificate[] certs = new Certificate[certificates.size()]; + + for (int i = 0; i != certs.length; i++) + { + certs[i] = Certificate.getInstance(certificates.getObjectAt(i)); + } + + return certs; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(3); + + v.add(signatureAlgorithm); + if (certificates != null) + { + v.add(new DERTaggedObject(0, certificates)); + } + v.add(signatureValue); + + return new DERSequence(v); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bsi/BSIObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bsi/BSIObjectIdentifiers.java index a69ed0405..15707d5b9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bsi/BSIObjectIdentifiers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/bsi/BSIObjectIdentifiers.java @@ -83,22 +83,22 @@ public interface BSIObjectIdentifiers /** AES encryption (CBC) and authentication (CMAC) * OID: 0.4.0.127.0.7.1.x */ - //FIXME replace "1" with correct OID - static final ASN1ObjectIdentifier aes_cbc_cmac = algorithm.branch("1"); + //TODO: replace "1" with correct OID + //static final ASN1ObjectIdentifier aes_cbc_cmac = algorithm.branch("1"); /** AES encryption (CBC) and authentication (CMAC) with 128 bit * OID: 0.4.0.127.0.7.1.x.y1 */ - //FIXME replace "1" with correct OID - static final ASN1ObjectIdentifier id_aes128_CBC_CMAC = aes_cbc_cmac.branch("1"); + //TODO: replace "1" with correct OID + //static final ASN1ObjectIdentifier id_aes128_CBC_CMAC = aes_cbc_cmac.branch("1"); /** AES encryption (CBC) and authentication (CMAC) with 192 bit * OID: 0.4.0.127.0.7.1.x.y2 */ - //FIXME replace "1" with correct OID - static final ASN1ObjectIdentifier id_aes192_CBC_CMAC = aes_cbc_cmac.branch("1"); + //TODO: replace "1" with correct OID + //static final ASN1ObjectIdentifier id_aes192_CBC_CMAC = aes_cbc_cmac.branch("1"); /** AES encryption (CBC) and authentication (CMAC) with 256 bit * OID: 0.4.0.127.0.7.1.x.y3 */ - //FIXME replace "1" with correct OID - static final ASN1ObjectIdentifier id_aes256_CBC_CMAC = aes_cbc_cmac.branch("1"); + //TODO: replace "1" with correct OID + //static final ASN1ObjectIdentifier id_aes256_CBC_CMAC = aes_cbc_cmac.branch("1"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCPublicationInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCPublicationInfo.java index cbabf3185..c25a3ae11 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCPublicationInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCPublicationInfo.java @@ -32,7 +32,7 @@ public class CMCPublicationInfo { this.hashAlg = hashAlg; - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(anchorHashes.length); for (int i = 0; i != anchorHashes.length; i++) { v.add(new DEROctetString(Arrays.clone(anchorHashes[i]))); @@ -92,7 +92,7 @@ public class CMCPublicationInfo public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(hashAlg); v.add(certHashes); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCStatusInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCStatusInfo.java index 6c00e76d2..069802c47 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCStatusInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCStatusInfo.java @@ -93,7 +93,7 @@ public class CMCStatusInfo public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(cMCStatus); v.add(bodyList); if (statusString != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCStatusInfoV2.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCStatusInfoV2.java index 2248bfa52..be3e551e4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCStatusInfoV2.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCStatusInfoV2.java @@ -131,7 +131,7 @@ public class CMCStatusInfoV2 public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(cMCStatus); v.add(bodyList); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCUnsignedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCUnsignedData.java index 393a05020..2643486d2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCUnsignedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CMCUnsignedData.java @@ -61,7 +61,7 @@ public class CMCUnsignedData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(bodyPartPath); v.add(identifier); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CertificationRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CertificationRequest.java index bfd92b1c6..e6c493f90 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CertificationRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/CertificationRequest.java @@ -130,7 +130,7 @@ public class CertificationRequest public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(certificationRequestInfo); v.add(signatureAlgorithm); @@ -201,7 +201,7 @@ public class CertificationRequest public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(version); v.add(subject); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/DecryptedPOP.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/DecryptedPOP.java index 06fb219ad..f0e11e159 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/DecryptedPOP.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/DecryptedPOP.java @@ -79,7 +79,7 @@ public class DecryptedPOP public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(bodyPartID); v.add(thePOPAlgID); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/EncryptedPOP.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/EncryptedPOP.java index 4672cc10a..674de5cac 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/EncryptedPOP.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/EncryptedPOP.java @@ -103,7 +103,7 @@ public class EncryptedPOP public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); v.add(request); v.add(cms); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/GetCRL.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/GetCRL.java index e645388e9..04c7e2234 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/GetCRL.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/GetCRL.java @@ -100,7 +100,7 @@ public class GetCRL public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(issuerName); if (cRLName != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/GetCert.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/GetCert.java index a2aa7d4db..1f03ff97f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/GetCert.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/GetCert.java @@ -67,7 +67,7 @@ public class GetCert extends ASN1Object public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(issuerName); v.add(new ASN1Integer(serialNumber)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/IdentityProofV2.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/IdentityProofV2.java index 04679353e..a77da176f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/IdentityProofV2.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/IdentityProofV2.java @@ -77,7 +77,7 @@ public class IdentityProofV2 public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(proofAlgID); v.add(macAlgId); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/LraPopWitness.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/LraPopWitness.java index 04fa9bb3a..a5b8ffa95 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/LraPopWitness.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/LraPopWitness.java @@ -73,7 +73,7 @@ public class LraPopWitness public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(pkiDataBodyid); v.add(bodyIds); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/ModCertTemplate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/ModCertTemplate.java index 8fed2b0f7..c636e59cc 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/ModCertTemplate.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/ModCertTemplate.java @@ -94,7 +94,7 @@ public class ModCertTemplate public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(pkiDataReference); v.add(certReferences); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/OtherMsg.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/OtherMsg.java index 6ec14d359..e648ad150 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/OtherMsg.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/OtherMsg.java @@ -66,7 +66,7 @@ public class OtherMsg public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(bodyPartID); v.add(otherMsgType); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PKIData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PKIData.java index 8537e2f4d..7b43abde0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PKIData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PKIData.java @@ -31,10 +31,10 @@ public class PKIData TaggedContentInfo[] cmsSequence, OtherMsg[] otherMsgSequence) { - this.controlSequence = controlSequence; - this.reqSequence = reqSequence; - this.cmsSequence = cmsSequence; - this.otherMsgSequence = otherMsgSequence; + this.controlSequence = copy(controlSequence); + this.reqSequence = copy(reqSequence); + this.cmsSequence = copy(cmsSequence); + this.otherMsgSequence = copy(otherMsgSequence); } private PKIData(ASN1Sequence seq) @@ -99,21 +99,57 @@ public class PKIData public TaggedAttribute[] getControlSequence() { - return controlSequence; + return copy(controlSequence); + } + + private TaggedAttribute[] copy(TaggedAttribute[] taggedAtts) + { + TaggedAttribute[] tmp = new TaggedAttribute[taggedAtts.length]; + + System.arraycopy(taggedAtts, 0, tmp, 0, tmp.length); + + return tmp; } public TaggedRequest[] getReqSequence() { - return reqSequence; + return copy(reqSequence); + } + + private TaggedRequest[] copy(TaggedRequest[] taggedReqs) + { + TaggedRequest[] tmp = new TaggedRequest[taggedReqs.length]; + + System.arraycopy(taggedReqs, 0, tmp, 0, tmp.length); + + return tmp; } public TaggedContentInfo[] getCmsSequence() { - return cmsSequence; + return copy(cmsSequence); + } + + private TaggedContentInfo[] copy(TaggedContentInfo[] taggedConts) + { + TaggedContentInfo[] tmp = new TaggedContentInfo[taggedConts.length]; + + System.arraycopy(taggedConts, 0, tmp, 0, tmp.length); + + return tmp; } public OtherMsg[] getOtherMsgSequence() { - return otherMsgSequence; + return copy(otherMsgSequence); + } + + private OtherMsg[] copy(OtherMsg[] otherMsgs) + { + OtherMsg[] tmp = new OtherMsg[otherMsgs.length]; + + System.arraycopy(otherMsgs, 0, tmp, 0, tmp.length); + + return tmp; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PKIResponse.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PKIResponse.java index f4dc2e354..ddf2dd262 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PKIResponse.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PKIResponse.java @@ -64,7 +64,7 @@ public class PKIResponse public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(controlSequence); v.add(cmsSequence); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PendInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PendInfo.java index f08fab58f..be20972c0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PendInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PendInfo.java @@ -57,7 +57,7 @@ public class PendInfo public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(new DEROctetString(pendToken)); v.add(pendTime); @@ -67,7 +67,7 @@ public class PendInfo public byte[] getPendToken() { - return pendToken; + return Arrays.clone(pendToken); } public ASN1GeneralizedTime getPendTime() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PopLinkWitnessV2.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PopLinkWitnessV2.java index b6be424db..bd724e07a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PopLinkWitnessV2.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PopLinkWitnessV2.java @@ -77,7 +77,7 @@ public class PopLinkWitnessV2 public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(keyGenAlgorithm); v.add(macAlgorithm); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PublishTrustAnchors.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PublishTrustAnchors.java index 339c008c3..3b9c2b38b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PublishTrustAnchors.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/PublishTrustAnchors.java @@ -35,7 +35,7 @@ public class PublishTrustAnchors this.seqNumber = new ASN1Integer(seqNumber); this.hashAlgorithm = hashAlgorithm; - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(anchorHashes.length); for (int i = 0; i != anchorHashes.length; i++) { v.add(new DEROctetString(Arrays.clone(anchorHashes[i]))); @@ -93,7 +93,7 @@ public class PublishTrustAnchors public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(seqNumber); v.add(hashAlgorithm); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/RevokeRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/RevokeRequest.java index c690e36ee..4dae0d41d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/RevokeRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/RevokeRequest.java @@ -148,7 +148,7 @@ public class RevokeRequest public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); v.add(name); v.add(serialNumber); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/TaggedCertificationRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/TaggedCertificationRequest.java index ac254378c..80d86aa9e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/TaggedCertificationRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/TaggedCertificationRequest.java @@ -61,7 +61,7 @@ public class TaggedCertificationRequest public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(bodyPartID); v.add(certificationRequest); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/TaggedContentInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/TaggedContentInfo.java index b8139c1b2..bb03a132c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/TaggedContentInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmc/TaggedContentInfo.java @@ -62,7 +62,7 @@ public class TaggedContentInfo public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(bodyPartID); v.add(contentInfo); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CAKeyUpdAnnContent.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CAKeyUpdAnnContent.java index 611ac8ba2..632d99784 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CAKeyUpdAnnContent.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CAKeyUpdAnnContent.java @@ -69,7 +69,7 @@ public class CAKeyUpdAnnContent */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(oldWithNew); v.add(newWithOld); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertRepMessage.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertRepMessage.java index b228d5ed0..049b8b84d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertRepMessage.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertRepMessage.java @@ -50,22 +50,10 @@ public class CertRepMessage if (caPubs != null) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i = 0; i < caPubs.length; i++) - { - v.add(caPubs[i]); - } - this.caPubs = new DERSequence(v); + this.caPubs = new DERSequence(caPubs); } - { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i = 0; i < response.length; i++) - { - v.add(response[i]); - } - this.response = new DERSequence(v); - } + this.response = new DERSequence(response); } public CMPCertificate[] getCaPubs() @@ -109,7 +97,7 @@ public class CertRepMessage */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (caPubs != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertResponse.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertResponse.java index 47b102c72..b8c54c922 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertResponse.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertResponse.java @@ -119,7 +119,7 @@ public class CertResponse */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(certReqId); v.add(status); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertStatus.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertStatus.java index 82e805b6e..95f44e010 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertStatus.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertStatus.java @@ -87,7 +87,7 @@ public class CertStatus */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(certHash); v.add(certReqId); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java index 2f042d892..2b6945752 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/CertifiedKeyPair.java @@ -10,6 +10,16 @@ import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; import com.fr.third.org.bouncycastle.asn1.crmf.EncryptedValue; import com.fr.third.org.bouncycastle.asn1.crmf.PKIPublicationInfo; +/** + *
+ * CertifiedKeyPair ::= SEQUENCE {
+ *                                  certOrEncCert       CertOrEncCert,
+ *                                  privateKey      [0] EncryptedValue      OPTIONAL,
+ *                                  -- see [CRMF] for comment on encoding
+ *                                  publicationInfo [1] PKIPublicationInfo  OPTIONAL
+ *       }
+ * 
+ */ public class CertifiedKeyPair extends ASN1Object { @@ -37,8 +47,8 @@ public class CertifiedKeyPair } else { - privateKey = EncryptedValue.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(1))); - publicationInfo = PKIPublicationInfo.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(2))); + privateKey = EncryptedValue.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(1)).getObject()); + publicationInfo = PKIPublicationInfo.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(2)).getObject()); } } } @@ -67,8 +77,7 @@ public class CertifiedKeyPair public CertifiedKeyPair( CertOrEncCert certOrEncCert, EncryptedValue privateKey, - PKIPublicationInfo publicationInfo - ) + PKIPublicationInfo publicationInfo) { if (certOrEncCert == null) { @@ -96,19 +105,13 @@ public class CertifiedKeyPair } /** - *
-     * CertifiedKeyPair ::= SEQUENCE {
-     *                                  certOrEncCert       CertOrEncCert,
-     *                                  privateKey      [0] EncryptedValue      OPTIONAL,
-     *                                  -- see [CRMF] for comment on encoding
-     *                                  publicationInfo [1] PKIPublicationInfo  OPTIONAL
-     *       }
-     * 
+ * Return the primitive representation of PKIPublicationInfo. + * * @return a basic ASN.1 object representation. */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(certOrEncCert); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/Challenge.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/Challenge.java index e2d87acb9..77ae48d8e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/Challenge.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/Challenge.java @@ -101,7 +101,7 @@ public class Challenge */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); addOptional(v, owf); v.add(witness); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/ErrorMsgContent.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/ErrorMsgContent.java index 4112880a2..889dc2d75 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/ErrorMsgContent.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/ErrorMsgContent.java @@ -102,7 +102,7 @@ public class ErrorMsgContent */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(pkiStatusInfo); addOptional(v, errorCode); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/GenMsgContent.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/GenMsgContent.java index b1ed115ba..d293fd8de 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/GenMsgContent.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/GenMsgContent.java @@ -36,14 +36,9 @@ public class GenMsgContent content = new DERSequence(itv); } - public GenMsgContent(InfoTypeAndValue[] itv) + public GenMsgContent(InfoTypeAndValue[] itvs) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i = 0; i < itv.length; i++) - { - v.add(itv[i]); - } - content = new DERSequence(v); + content = new DERSequence(itvs); } public InfoTypeAndValue[] toInfoTypeAndValueArray() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/GenRepContent.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/GenRepContent.java index ba41c3f3a..15ffb09ae 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/GenRepContent.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/GenRepContent.java @@ -36,14 +36,9 @@ public class GenRepContent content = new DERSequence(itv); } - public GenRepContent(InfoTypeAndValue[] itv) + public GenRepContent(InfoTypeAndValue[] itvs) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i = 0; i < itv.length; i++) - { - v.add(itv[i]); - } - content = new DERSequence(v); + content = new DERSequence(itvs); } public InfoTypeAndValue[] toInfoTypeAndValueArray() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/InfoTypeAndValue.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/InfoTypeAndValue.java index 4291d2240..7998ef6d6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/InfoTypeAndValue.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/InfoTypeAndValue.java @@ -118,7 +118,7 @@ public class InfoTypeAndValue */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(infoType); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/KeyRecRepContent.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/KeyRecRepContent.java index 2722ea1ec..4667b6443 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/KeyRecRepContent.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/KeyRecRepContent.java @@ -121,7 +121,7 @@ public class KeyRecRepContent */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(status); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/OOBCertHash.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/OOBCertHash.java index 365b08c4a..f3e01777b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/OOBCertHash.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/OOBCertHash.java @@ -97,7 +97,7 @@ public class OOBCertHash */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); addOptional(v, 0, hashAlg); addOptional(v, 1, certId); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PBMParameter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PBMParameter.java index 1bb329984..6585389c3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PBMParameter.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PBMParameter.java @@ -105,7 +105,7 @@ public class PBMParameter */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(salt); v.add(owf); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIFreeText.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIFreeText.java index 24454b5c1..fcbbde130 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIFreeText.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIFreeText.java @@ -73,7 +73,7 @@ public class PKIFreeText public PKIFreeText( String[] strs) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(strs.length); for (int i = 0; i < strs.length; i++) { v.add(new DERUTF8String(strs[i])); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIHeader.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIHeader.java index 427184afe..6832d31ae 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIHeader.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIHeader.java @@ -232,7 +232,7 @@ public class PKIHeader */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(12); v.add(pvno); v.add(sender); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java index 1673df485..14a955ce7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIHeaderBuilder.java @@ -155,12 +155,7 @@ public class PKIHeaderBuilder ASN1Sequence genInfoSeq = null; if (generalInfos != null) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i = 0; i < generalInfos.length; i++) - { - v.add(generalInfos[i]); - } - genInfoSeq = new DERSequence(v); + genInfoSeq = new DERSequence(generalInfos); } return genInfoSeq; } @@ -205,7 +200,7 @@ public class PKIHeaderBuilder */ public PKIHeader build() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(12); v.add(pvno); v.add(sender); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIMessage.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIMessage.java index 929c46907..110a6f37b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIMessage.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIMessage.java @@ -75,12 +75,7 @@ public class PKIMessage this.protection = protection; if (extraCerts != null) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i = 0; i < extraCerts.length; i++) - { - v.add(extraCerts[i]); - } - this.extraCerts = new DERSequence(v); + this.extraCerts = new DERSequence(extraCerts); } } @@ -145,7 +140,7 @@ public class PKIMessage */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(header); v.add(body); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIMessages.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIMessages.java index 0a28487d3..6b2765888 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIMessages.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIMessages.java @@ -38,12 +38,7 @@ public class PKIMessages public PKIMessages(PKIMessage[] msgs) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i = 0; i < msgs.length; i++) - { - v.add(msgs[i]); - } - content = new DERSequence(v); + content = new DERSequence(msgs); } public PKIMessage[] toPKIMessageArray() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIStatusInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIStatusInfo.java index 326c2286d..7be2ab822 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIStatusInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PKIStatusInfo.java @@ -146,7 +146,7 @@ public class PKIStatusInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(status); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PollRepContent.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PollRepContent.java index 786f401ae..646e255da 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PollRepContent.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/PollRepContent.java @@ -97,11 +97,11 @@ public class PollRepContent */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector outer = new ASN1EncodableVector(); + ASN1EncodableVector outer = new ASN1EncodableVector(certReqId.length); for (int i = 0; i != certReqId.length; i++) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(certReqId[i]); v.add(checkAfter[i]); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/ProtectedPart.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/ProtectedPart.java index 3b844aa61..b60a31713 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/ProtectedPart.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/ProtectedPart.java @@ -60,7 +60,7 @@ public class ProtectedPart */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(header); v.add(body); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevAnnContent.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevAnnContent.java index 10673e2e6..e3118dd54 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevAnnContent.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevAnnContent.java @@ -86,7 +86,7 @@ public class RevAnnContent */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); v.add(status); v.add(certId); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevDetails.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevDetails.java index 61a42a227..062e2e327 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevDetails.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevDetails.java @@ -86,7 +86,7 @@ public class RevDetails */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(certDetails); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevRepContent.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevRepContent.java index f80a29a45..db9f5590d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevRepContent.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevRepContent.java @@ -117,7 +117,7 @@ public class RevRepContent */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(status); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevRepContentBuilder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevRepContentBuilder.java index 920bb4052..155cbf595 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevRepContentBuilder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevRepContentBuilder.java @@ -40,7 +40,7 @@ public class RevRepContentBuilder public RevRepContent build() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(new DERSequence(status)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevReqContent.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevReqContent.java index 1a1fa67af..c31f4fde1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevReqContent.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cmp/RevReqContent.java @@ -1,6 +1,5 @@ package com.fr.third.org.bouncycastle.asn1.cmp; -import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; import com.fr.third.org.bouncycastle.asn1.ASN1Object; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; @@ -38,14 +37,7 @@ public class RevReqContent public RevReqContent(RevDetails[] revDetailsArray) { - ASN1EncodableVector v = new ASN1EncodableVector(); - - for (int i = 0; i != revDetailsArray.length; i++) - { - v.add(revDetailsArray[i]); - } - - this.content = new DERSequence(v); + this.content = new DERSequence(revDetailsArray); } public RevDetails[] toRevDetailsArray() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Attribute.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Attribute.java index e4ce0beb0..736d60a3a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Attribute.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Attribute.java @@ -100,7 +100,7 @@ public class Attribute */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(attrType); v.add(attrValues); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Attributes.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Attributes.java index d74a85981..4161404d7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Attributes.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Attributes.java @@ -4,6 +4,7 @@ import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; import com.fr.third.org.bouncycastle.asn1.ASN1Object; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Set; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; import com.fr.third.org.bouncycastle.asn1.DLSet; /** @@ -63,6 +64,13 @@ public class Attributes return null; } + public static Attributes getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Set.getInstance(obj, explicit)); + } + public Attribute[] getAttributes() { Attribute[] rv = new Attribute[attributes.size()]; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthEnvelopedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthEnvelopedData.java index c65737898..796bcd4a2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthEnvelopedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthEnvelopedData.java @@ -93,8 +93,8 @@ public class AuthEnvelopedData // "It MUST be set to 0." ASN1Primitive tmp = seq.getObjectAt(index++).toASN1Primitive(); - version = (ASN1Integer)tmp; - if (this.version.getValue().intValue() != 0) + version = ASN1Integer.getInstance(tmp); + if (version.intValueExact() != 0) { throw new IllegalArgumentException("AuthEnvelopedData version number must be 0"); } @@ -237,7 +237,7 @@ public class AuthEnvelopedData */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(7); v.add(version); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java index ccc0e60c8..581a0a44e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthEnvelopedDataParser.java @@ -39,7 +39,7 @@ public class AuthEnvelopedDataParser // "It MUST be set to 0." this.version = ASN1Integer.getInstance(seq.readObject()); - if (this.version.getValue().intValue() != 0) + if (version.intValueExact() != 0) { throw new ASN1ParsingException("AuthEnvelopedData version number must be 0"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthenticatedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthenticatedData.java index de94b7813..d4847fe5e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthenticatedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthenticatedData.java @@ -220,7 +220,7 @@ public class AuthenticatedData */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(9); v.add(version); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthenticatedDataParser.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthenticatedDataParser.java index 2a12372aa..d3652f495 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthenticatedDataParser.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/AuthenticatedDataParser.java @@ -127,15 +127,6 @@ public class AuthenticatedDataParser return null; } - /** - * @deprecated use getEncapsulatedContentInfo() - */ - public ContentInfoParser getEnapsulatedContentInfo() - throws IOException - { - return getEncapsulatedContentInfo(); - } - public ContentInfoParser getEncapsulatedContentInfo() throws IOException { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CCMParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CCMParameters.java index 30dd7390b..affeb25a6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CCMParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CCMParameters.java @@ -60,7 +60,7 @@ public class CCMParameters if (seq.size() == 2) { - this.icvLen = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().intValue(); + this.icvLen = ASN1Integer.getInstance(seq.getObjectAt(1)).intValueExact(); } else { @@ -88,7 +88,7 @@ public class CCMParameters public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(new DEROctetString(nonce)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CMSAlgorithmProtection.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CMSAlgorithmProtection.java index 32985be90..4fb8f9835 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CMSAlgorithmProtection.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CMSAlgorithmProtection.java @@ -119,7 +119,7 @@ public class CMSAlgorithmProtection public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(digestAlgorithm); if (signatureAlgorithm != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CMSAttributes.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CMSAttributes.java index 77549e928..b48563f67 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CMSAttributes.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CMSAttributes.java @@ -3,6 +3,7 @@ package com.fr.third.org.bouncycastle.asn1.cms; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; + /** * RFC 5652 CMS attribute OID constants. * and RFC 6211 Algorithm Identifier Protection Attribute. @@ -20,16 +21,16 @@ import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; public interface CMSAttributes { /** PKCS#9: 1.2.840.113549.1.9.3 */ - public static final ASN1ObjectIdentifier contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType; + ASN1ObjectIdentifier contentType = PKCSObjectIdentifiers.pkcs_9_at_contentType; /** PKCS#9: 1.2.840.113549.1.9.4 */ - public static final ASN1ObjectIdentifier messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest; + ASN1ObjectIdentifier messageDigest = PKCSObjectIdentifiers.pkcs_9_at_messageDigest; /** PKCS#9: 1.2.840.113549.1.9.5 */ - public static final ASN1ObjectIdentifier signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime; + ASN1ObjectIdentifier signingTime = PKCSObjectIdentifiers.pkcs_9_at_signingTime; /** PKCS#9: 1.2.840.113549.1.9.6 */ - public static final ASN1ObjectIdentifier counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature; + ASN1ObjectIdentifier counterSignature = PKCSObjectIdentifiers.pkcs_9_at_counterSignature; /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See RFC 2634 */ - public static final ASN1ObjectIdentifier contentHint = PKCSObjectIdentifiers.id_aa_contentHint; + ASN1ObjectIdentifier contentHint = PKCSObjectIdentifiers.id_aa_contentHint; - public static final ASN1ObjectIdentifier cmsAlgorithmProtect = PKCSObjectIdentifiers.id_aa_cmsAlgorithmProtect; + ASN1ObjectIdentifier cmsAlgorithmProtect = PKCSObjectIdentifiers.id_aa_cmsAlgorithmProtect; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CompressedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CompressedData.java index ce35075fc..9d916c352 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CompressedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/CompressedData.java @@ -106,7 +106,7 @@ public class CompressedData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(version); v.add(compressionAlgorithm); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ContentInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ContentInfo.java index f394e6d42..65c5fbd4e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ContentInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ContentInfo.java @@ -116,7 +116,7 @@ public class ContentInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(contentType); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/DigestedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/DigestedData.java index 692f62cbb..1c328c4ec 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/DigestedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/DigestedData.java @@ -111,7 +111,7 @@ public class DigestedData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(version); v.add(digestAlgorithm); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EncryptedContentInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EncryptedContentInfo.java index 740d827f1..0e2361af9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EncryptedContentInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EncryptedContentInfo.java @@ -105,7 +105,7 @@ public class EncryptedContentInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(contentType); v.add(contentEncryptionAlgorithm); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EncryptedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EncryptedData.java index f0858e13e..c06081002 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EncryptedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EncryptedData.java @@ -98,7 +98,7 @@ public class EncryptedData */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(version); v.add(encryptedContentInfo); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EnvelopedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EnvelopedData.java index 3ff26cbb0..a5e2c955e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EnvelopedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/EnvelopedData.java @@ -164,7 +164,7 @@ public class EnvelopedData */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); v.add(version); @@ -202,7 +202,7 @@ public class EnvelopedData { RecipientInfo ri = RecipientInfo.getInstance(e.nextElement()); - if (ri.getVersion().getValue().intValue() != version) + if (ri.getVersion().intValueExact() != version) { version = 2; break; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Evidence.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Evidence.java index ca5d9c2ae..7238506ad 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Evidence.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/Evidence.java @@ -3,8 +3,10 @@ package com.fr.third.org.bouncycastle.asn1.cms; import com.fr.third.org.bouncycastle.asn1.ASN1Choice; import com.fr.third.org.bouncycastle.asn1.ASN1Object; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.tsp.EvidenceRecord; /** * RFC 5544: @@ -23,18 +25,37 @@ public class Evidence implements ASN1Choice { private TimeStampTokenEvidence tstEvidence; + private EvidenceRecord ersEvidence; + private ASN1Sequence otherEvidence; public Evidence(TimeStampTokenEvidence tstEvidence) { this.tstEvidence = tstEvidence; } + public Evidence(EvidenceRecord ersEvidence) + { + this.ersEvidence = ersEvidence; + } + private Evidence(ASN1TaggedObject tagged) { if (tagged.getTagNo() == 0) { this.tstEvidence = TimeStampTokenEvidence.getInstance(tagged, false); } + else if (tagged.getTagNo() == 1) + { + this.ersEvidence = EvidenceRecord.getInstance(tagged, false); + } + else if (tagged.getTagNo() == 2) + { + this.otherEvidence = ASN1Sequence.getInstance(tagged, false); + } + else + { + throw new IllegalArgumentException("unknown tag in Evidence"); + } } /** @@ -63,18 +84,34 @@ public class Evidence throw new IllegalArgumentException("unknown object in getInstance"); } + public static Evidence getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(obj.getObject()); // must be explicitly tagged + } + public TimeStampTokenEvidence getTstEvidence() { return tstEvidence; } + public EvidenceRecord getErsEvidence() + { + return ersEvidence; + } + public ASN1Primitive toASN1Primitive() { - if (tstEvidence != null) - { - return new DERTaggedObject(false, 0, tstEvidence); - } + if (tstEvidence != null) + { + return new DERTaggedObject(false, 0, tstEvidence); + } + if (ersEvidence != null) + { + return new DERTaggedObject(false, 1, ersEvidence); + } - return null; + return new DERTaggedObject(false, 2, otherEvidence); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/GCMParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/GCMParameters.java index 6041d1ccf..0bcd25c6a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/GCMParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/GCMParameters.java @@ -60,7 +60,7 @@ public class GCMParameters if (seq.size() == 2) { - this.icvLen = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().intValue(); + this.icvLen = ASN1Integer.getInstance(seq.getObjectAt(1)).intValueExact(); } else { @@ -88,7 +88,7 @@ public class GCMParameters public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(new DEROctetString(nonce)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/GenericHybridParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/GenericHybridParameters.java index f1858588e..e2fdb2206 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/GenericHybridParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/GenericHybridParameters.java @@ -69,7 +69,7 @@ public class GenericHybridParameters public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(kem); v.add(dem); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java index a02678973..6f08e319d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/IssuerAndSerialNumber.java @@ -128,7 +128,7 @@ public class IssuerAndSerialNumber public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(name); v.add(serialNumber); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KEKIdentifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KEKIdentifier.java index 06230e9c6..94c8fecaf 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KEKIdentifier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KEKIdentifier.java @@ -132,7 +132,7 @@ public class KEKIdentifier */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(keyIdentifier); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KEKRecipientInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KEKRecipientInfo.java index 7f8ae3f08..551c6c658 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KEKRecipientInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KEKRecipientInfo.java @@ -121,7 +121,7 @@ public class KEKRecipientInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(version); v.add(kekid); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java index eaa9c5a07..8912d0878 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KeyAgreeRecipientInfo.java @@ -148,7 +148,7 @@ public class KeyAgreeRecipientInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); v.add(version); v.add(new DERTaggedObject(true, 0, originator)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java index a3a6a92c2..cc9daa790 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/KeyTransRecipientInfo.java @@ -115,7 +115,7 @@ public class KeyTransRecipientInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(version); v.add(rid); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/MetaData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/MetaData.java index e4a8eaf0d..dc29a4e20 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/MetaData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/MetaData.java @@ -91,7 +91,7 @@ public class MetaData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(hashProtected); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OriginatorInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OriginatorInfo.java index 067e5a0b2..6cfdfe95f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OriginatorInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OriginatorInfo.java @@ -142,7 +142,7 @@ public class OriginatorInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (certs != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OriginatorPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OriginatorPublicKey.java index ee886cfda..6714f6bd6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OriginatorPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OriginatorPublicKey.java @@ -104,7 +104,7 @@ public class OriginatorPublicKey */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(algorithm); v.add(publicKey); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherKeyAttribute.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherKeyAttribute.java index c5828931c..67d0ebb7c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherKeyAttribute.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherKeyAttribute.java @@ -53,10 +53,7 @@ public class OtherKeyAttribute return null; } - /** - * @deprecated use getInstance() - */ - public OtherKeyAttribute( + private OtherKeyAttribute( ASN1Sequence seq) { keyAttrId = (ASN1ObjectIdentifier)seq.getObjectAt(0); @@ -86,7 +83,7 @@ public class OtherKeyAttribute */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(keyAttrId); v.add(keyAttr); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherRecipientInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherRecipientInfo.java index 2bd6e5fa8..bc857aecf 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherRecipientInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherRecipientInfo.java @@ -31,11 +31,8 @@ public class OtherRecipientInfo this.oriType = oriType; this.oriValue = oriValue; } - - /** - * @deprecated use getInstance(). - */ - public OtherRecipientInfo( + + private OtherRecipientInfo( ASN1Sequence seq) { oriType = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0)); @@ -102,7 +99,7 @@ public class OtherRecipientInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(oriType); v.add(oriValue); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java index 33dc9e6e7..4a039ebd2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/OtherRevocationInfoFormat.java @@ -99,7 +99,7 @@ public class OtherRevocationInfoFormat */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(otherRevInfoFormat); v.add(otherRevInfo); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java index e4287808a..d72d25876 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/PasswordRecipientInfo.java @@ -141,7 +141,7 @@ public class PasswordRecipientInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(version); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java index 8bf576a19..92dae9c1a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RecipientEncryptedKey.java @@ -99,7 +99,7 @@ public class RecipientEncryptedKey */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(identifier); v.add(encryptedKey); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java index 093cbd832..8304b5341 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RecipientKeyIdentifier.java @@ -152,7 +152,7 @@ public class RecipientKeyIdentifier */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(subjectKeyIdentifier); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RsaKemParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RsaKemParameters.java index ca32f7ba5..8fd44dc44 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RsaKemParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/RsaKemParameters.java @@ -77,7 +77,7 @@ public class RsaKemParameters public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(keyDerivationFunction); v.add(new ASN1Integer(keyLength)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SCVPReqRes.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SCVPReqRes.java index 8d1abaac6..ec33d531d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SCVPReqRes.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SCVPReqRes.java @@ -94,7 +94,7 @@ public class SCVPReqRes */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (request != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SignedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SignedData.java index c68df8d66..3276aad7b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SignedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SignedData.java @@ -206,7 +206,7 @@ public class SignedData { SignerInfo s = SignerInfo.getInstance(e.nextElement()); - if (s.getVersion().getValue().intValue() == 3) + if (s.getVersion().intValueExact() == 3) { return true; } @@ -293,7 +293,7 @@ public class SignedData */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); v.add(version); v.add(digestAlgorithms); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SignerInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SignerInfo.java index 5af2d2e78..48363186f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SignerInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/SignerInfo.java @@ -258,7 +258,7 @@ public class SignerInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(7); v.add(version); v.add(sid); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampAndCRL.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampAndCRL.java index 287d8dbcf..60fd27a4e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampAndCRL.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampAndCRL.java @@ -82,7 +82,7 @@ public class TimeStampAndCRL public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(timeStamp); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampTokenEvidence.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampTokenEvidence.java index 3356ed1ad..9bb70b8fb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampTokenEvidence.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampTokenEvidence.java @@ -24,7 +24,7 @@ public class TimeStampTokenEvidence public TimeStampTokenEvidence(TimeStampAndCRL[] timeStampAndCRLs) { - this.timeStampAndCRLs = timeStampAndCRLs; + this.timeStampAndCRLs = copy(timeStampAndCRLs); } public TimeStampTokenEvidence(TimeStampAndCRL timeStampAndCRL) @@ -80,12 +80,21 @@ public class TimeStampTokenEvidence public TimeStampAndCRL[] toTimeStampAndCRLArray() { - return timeStampAndCRLs; + return copy(timeStampAndCRLs); } - + + private TimeStampAndCRL[] copy(TimeStampAndCRL[] tsAndCrls) + { + TimeStampAndCRL[] tmp = new TimeStampAndCRL[tsAndCrls.length]; + + System.arraycopy(tsAndCrls, 0, tmp, 0, tmp.length); + + return tmp; + } + public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(timeStampAndCRLs.length); for (int i = 0; i != timeStampAndCRLs.length; i++) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampedData.java index 90225a4e5..0cd3cb5d7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/TimeStampedData.java @@ -105,7 +105,7 @@ public class TimeStampedData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); v.add(version); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ecc/ECCCMSSharedInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ecc/ECCCMSSharedInfo.java index af51eacc8..604056fb2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ecc/ECCCMSSharedInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ecc/ECCCMSSharedInfo.java @@ -101,7 +101,7 @@ public class ECCCMSSharedInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(keyInfo); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java index 8fb555693..70d0ed3f4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cms/ecc/MQVuserKeyingMaterial.java @@ -114,7 +114,7 @@ public class MQVuserKeyingMaterial */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(ephemeralPublicKey); if (addedukm != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/AttributeTypeAndValue.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/AttributeTypeAndValue.java index 69595cf21..353fef282 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/AttributeTypeAndValue.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/AttributeTypeAndValue.java @@ -70,7 +70,7 @@ public class AttributeTypeAndValue */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(type); v.add(value); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertId.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertId.java index a60dd8605..0e0575b4d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertId.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertId.java @@ -74,7 +74,7 @@ public class CertId */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(issuer); v.add(serialNumber); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertReqMessages.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertReqMessages.java index 7e5210308..8e89c1e95 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertReqMessages.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertReqMessages.java @@ -40,12 +40,7 @@ public class CertReqMessages public CertReqMessages( CertReqMsg[] msgs) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i = 0; i < msgs.length; i++) - { - v.add(msgs[i]); - } - content = new DERSequence(v); + content = new DERSequence(msgs); } public CertReqMsg[] toCertReqMsgArray() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertReqMsg.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertReqMsg.java index 2f9abf03c..f2099dec6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertReqMsg.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertReqMsg.java @@ -132,7 +132,7 @@ public class CertReqMsg */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(certReq); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertRequest.java index 5ce544830..64149f2ef 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertRequest.java @@ -82,7 +82,7 @@ public class CertRequest */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(certReqId); v.add(certTemplate); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertTemplate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertTemplate.java index 00392dffd..4884ef3fb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertTemplate.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertTemplate.java @@ -99,7 +99,7 @@ public class CertTemplate { if (version != null) { - return version.getValue().intValue(); + return version.intValueExact(); } return -1; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java index 58b9e667f..7335d3cfd 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/CertTemplateBuilder.java @@ -124,7 +124,7 @@ public class CertTemplateBuilder */ public CertTemplate build() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(10); addOptional(v, 0, false, version); addOptional(v, 1, false, serialNumber); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/Controls.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/Controls.java index 8e9cee8cc..c5c29939f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/Controls.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/Controls.java @@ -1,6 +1,5 @@ package com.fr.third.org.bouncycastle.asn1.crmf; -import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; import com.fr.third.org.bouncycastle.asn1.ASN1Object; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; @@ -38,12 +37,7 @@ public class Controls public Controls(AttributeTypeAndValue[] atvs) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i = 0; i < atvs.length; i++) - { - v.add(atvs[i]); - } - content = new DERSequence(v); + content = new DERSequence(atvs); } public AttributeTypeAndValue[] toAttributeTypeAndValueArray() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/DhSigStatic.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/DhSigStatic.java index 51411a49e..bbbfabbfc 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/DhSigStatic.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/DhSigStatic.java @@ -80,7 +80,7 @@ public class DhSigStatic public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (issuerAndSerial != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/EncKeyWithID.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/EncKeyWithID.java index de39239f1..3eb1cccb8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/EncKeyWithID.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/EncKeyWithID.java @@ -99,11 +99,11 @@ public class EncKeyWithID * } OPTIONAL * } * - * @return a DERSequence representing the value in this object. + * @return an ASN.1 primitive composition of this EncKeyWithID. */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(privKeyInfo); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/EncryptedValue.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/EncryptedValue.java index df19d1123..42e0aa28f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/EncryptedValue.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/EncryptedValue.java @@ -143,7 +143,7 @@ public class EncryptedValue */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); addOptional(v, 0, intendedAlg); addOptional(v, 1, symmAlg); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/OptionalValidity.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/OptionalValidity.java index cb5f3300d..44e3f9dd5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/OptionalValidity.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/OptionalValidity.java @@ -81,7 +81,7 @@ public class OptionalValidity */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (notBefore != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java index c397752a0..e6f6fb46c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/PKIPublicationInfo.java @@ -1,5 +1,7 @@ package com.fr.third.org.bouncycastle.asn1.crmf; +import java.math.BigInteger; + import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; import com.fr.third.org.bouncycastle.asn1.ASN1Object; @@ -7,16 +9,34 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.DERSequence; +/** + *
+ * PKIPublicationInfo ::= SEQUENCE {
+ *                  action     INTEGER {
+ *                                 dontPublish (0),
+ *                                 pleasePublish (1) },
+ *                  pubInfos  SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL }
+ * -- pubInfos MUST NOT be present if action is "dontPublish"
+ * -- (if action is "pleasePublish" and pubInfos is omitted,
+ * -- "dontCare" is assumed)
+ * 
+ */ public class PKIPublicationInfo extends ASN1Object { + public static final ASN1Integer dontPublish = new ASN1Integer(0); + public static final ASN1Integer pleasePublish = new ASN1Integer(1); + private ASN1Integer action; private ASN1Sequence pubInfos; private PKIPublicationInfo(ASN1Sequence seq) { action = ASN1Integer.getInstance(seq.getObjectAt(0)); - pubInfos = ASN1Sequence.getInstance(seq.getObjectAt(1)); + if (seq.size() > 1) + { + pubInfos = ASN1Sequence.getInstance(seq.getObjectAt(1)); + } } public static PKIPublicationInfo getInstance(Object o) @@ -34,6 +54,45 @@ public class PKIPublicationInfo return null; } + public PKIPublicationInfo(BigInteger action) + { + this(new ASN1Integer(action)); + } + + public PKIPublicationInfo(ASN1Integer action) + { + this.action = action; + } + + /** + * Constructor with a single pubInfo, assumes pleasePublish as the action. + * + * @param pubInfo the pubInfo to be published (can be null if don't care is required). + */ + public PKIPublicationInfo(SinglePubInfo pubInfo) + { + this(pubInfo != null ? new SinglePubInfo[] { pubInfo } : (SinglePubInfo[])null); + } + + /** + * Constructor with multiple pubInfo, assumes pleasePublish as the action. + * + * @param pubInfos the pubInfos to be published (can be null if don't care is required). + */ + public PKIPublicationInfo(SinglePubInfo[] pubInfos) + { + this.action = pleasePublish; + + if (pubInfos != null) + { + this.pubInfos = new DERSequence(pubInfos); + } + else + { + this.pubInfos = null; + } + } + public ASN1Integer getAction() { return action; @@ -57,24 +116,20 @@ public class PKIPublicationInfo } /** - *
-     * PKIPublicationInfo ::= SEQUENCE {
-     *                  action     INTEGER {
-     *                                 dontPublish (0),
-     *                                 pleasePublish (1) },
-     *                  pubInfos  SEQUENCE SIZE (1..MAX) OF SinglePubInfo OPTIONAL }
-     * -- pubInfos MUST NOT be present if action is "dontPublish"
-     * -- (if action is "pleasePublish" and pubInfos is omitted,
-     * -- "dontCare" is assumed)
-     * 
+ * Return the primitive representation of PKIPublicationInfo. + * * @return a basic ASN.1 object representation. */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(action); - v.add(pubInfos); + + if (pubInfos != null) + { + v.add(pubInfos); + } return new DERSequence(v); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/PKMACValue.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/PKMACValue.java index 398e62810..051b0461b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/PKMACValue.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/PKMACValue.java @@ -94,7 +94,7 @@ public class PKMACValue */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(algId); v.add(value); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOPrivKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOPrivKey.java index a1507175e..c2c41076b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOPrivKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOPrivKey.java @@ -33,7 +33,7 @@ public class POPOPrivKey this.obj = DERBitString.getInstance(obj, false); break; case subsequentMessage: - this.obj = SubsequentMessage.valueOf(ASN1Integer.getInstance(obj, false).getValue().intValue()); + this.obj = SubsequentMessage.valueOf(ASN1Integer.getInstance(obj, false).intValueExact()); break; case dhMAC: this.obj = DERBitString.getInstance(obj, false); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOSigningKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOSigningKey.java index 35cfd2b78..966542228 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOSigningKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOSigningKey.java @@ -112,7 +112,7 @@ public class POPOSigningKey */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (poposkInput != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOSigningKeyInput.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOSigningKeyInput.java index 3e78af2b6..32da88ab1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOSigningKeyInput.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/POPOSigningKeyInput.java @@ -116,7 +116,7 @@ public class POPOSigningKeyInput */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (sender != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/SinglePubInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/SinglePubInfo.java index a12f0852e..9195b46b9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/SinglePubInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/crmf/SinglePubInfo.java @@ -8,9 +8,25 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +/** + *
+ * SinglePubInfo ::= SEQUENCE {
+ *        pubMethod    INTEGER {
+ *           dontCare    (0),
+ *           x500        (1),
+ *           web         (2),
+ *           ldap        (3) },
+ *       pubLocation  GeneralName OPTIONAL }
+ * 
+ */ public class SinglePubInfo extends ASN1Object { + public static final ASN1Integer dontCare = new ASN1Integer(0); + public static final ASN1Integer x500 = new ASN1Integer(1); + public static final ASN1Integer web = new ASN1Integer(2); + public static final ASN1Integer ldap = new ASN1Integer(3); + private ASN1Integer pubMethod; private GeneralName pubLocation; @@ -39,26 +55,30 @@ public class SinglePubInfo return null; } + public SinglePubInfo(ASN1Integer pubMethod, GeneralName pubLocation) + { + this.pubMethod = pubMethod; + this.pubLocation = pubLocation; + } + + public ASN1Integer getPubMethod() + { + return pubMethod; + } + public GeneralName getPubLocation() { return pubLocation; } /** - *
-     * SinglePubInfo ::= SEQUENCE {
-     *        pubMethod    INTEGER {
-     *           dontCare    (0),
-     *           x500        (1),
-     *           web         (2),
-     *           ldap        (3) },
-     *       pubLocation  GeneralName OPTIONAL }
-     * 
+ * Return the primitive representation of SinglePubInfo. + * * @return a basic ASN.1 object representation. */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(pubMethod); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptlib/CryptlibObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptlib/CryptlibObjectIdentifiers.java new file mode 100644 index 000000000..4c5872dd3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptlib/CryptlibObjectIdentifiers.java @@ -0,0 +1,12 @@ +package com.fr.third.org.bouncycastle.asn1.cryptlib; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public class CryptlibObjectIdentifiers +{ + public static final ASN1ObjectIdentifier cryptlib = new ASN1ObjectIdentifier("1.3.6.1.4.1.3029"); + + public static final ASN1ObjectIdentifier ecc = cryptlib.branch("1").branch("5"); + + public static final ASN1ObjectIdentifier curvey25519 = ecc.branch("1"); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java index 0c1ffa0ce..74574f75f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/ECGOST3410NamedCurves.java @@ -9,13 +9,26 @@ import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifie import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; -import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.ec.WNafUtil; /** * table of the available named parameters for GOST 3410-2001 / 2012. */ public class ECGOST3410NamedCurves { + private static ECPoint configureBasepoint(ECCurve curve, BigInteger x, BigInteger y) + { + ECPoint G = curve.createPoint(x, y); + WNafUtil.configureBasepoint(G); + return G; + } + + private static ECCurve configureCurve(ECCurve curve) + { + return curve; + } + static final Hashtable objIds = new Hashtable(); static final Hashtable params = new Hashtable(); static final Hashtable names = new Hashtable(); @@ -25,164 +38,160 @@ public class ECGOST3410NamedCurves BigInteger mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); BigInteger mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); - ECCurve.Fp curve = new ECCurve.Fp( + ECCurve curve = configureCurve(new ECCurve.Fp( mod_p, // p new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a new BigInteger("166"), // b - mod_q, - ECConstants.ONE); + mod_q, ECConstants.ONE)); ECDomainParameters ecParams = new ECDomainParameters( curve, - curve.createPoint( + configureBasepoint(curve, new BigInteger("1"), // x new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y - mod_q); + mod_q, ECConstants.ONE); params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A, ecParams); mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); - curve = new ECCurve.Fp( + curve = configureCurve(new ECCurve.Fp( mod_p, // p new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), new BigInteger("166"), - mod_q, - ECConstants.ONE); + mod_q, ECConstants.ONE)); ecParams = new ECDomainParameters( curve, - curve.createPoint( + configureBasepoint(curve, new BigInteger("1"), // x new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y - mod_q); + mod_q, ECConstants.ONE); params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA, ecParams); mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823193"); //p mod_q = new BigInteger("57896044618658097711785492504343953927102133160255826820068844496087732066703"); //q - curve = new ECCurve.Fp( + curve = configureCurve(new ECCurve.Fp( mod_p, // p new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595"), // b - mod_q, - ECConstants.ONE); + mod_q, ECConstants.ONE)); ecParams = new ECDomainParameters( curve, - curve.createPoint( + configureBasepoint(curve, new BigInteger("1"), // x new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124")), // y - mod_q); // q + mod_q, ECConstants.ONE); params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B, ecParams); mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); - curve = new ECCurve.Fp( + curve = configureCurve(new ECCurve.Fp( mod_p, // p new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), new BigInteger("32858"), - mod_q, - ECConstants.ONE); + mod_q, ECConstants.ONE)); ecParams = new ECDomainParameters( curve, - curve.createPoint( + configureBasepoint(curve, new BigInteger("0"), new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), - mod_q); + mod_q, ECConstants.ONE); params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB, ecParams); mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); //p mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); //q - curve = new ECCurve.Fp( + + curve = configureCurve(new ECCurve.Fp( mod_p, // p new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a new BigInteger("32858"), // b - mod_q, - ECConstants.ONE); + mod_q, ECConstants.ONE)); ecParams = new ECDomainParameters( curve, - curve.createPoint( + configureBasepoint(curve, new BigInteger("0"), // x new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), // y - mod_q); // q + mod_q, ECConstants.ONE); params.put(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C, ecParams); //GOST34.10 2012 mod_p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97", 16); //p mod_q = new BigInteger("400000000000000000000000000000000FD8CDDFC87B6635C115AF556C360C67", 16); //q - curve = new ECCurve.Fp( - mod_p, // p - new BigInteger("C2173F1513981673AF4892C23035A27CE25E2013BF95AA33B22C656F277E7335", 16), // a - new BigInteger("295F9BAE7428ED9CCC20E7C359A9D41A22FCCD9108E17BF7BA9337A6F8AE9513", 16), // b - mod_q, - ECConstants.ONE); + + curve = configureCurve(new ECCurve.Fp( + mod_p, // p + new BigInteger("C2173F1513981673AF4892C23035A27CE25E2013BF95AA33B22C656F277E7335", 16), // a + new BigInteger("295F9BAE7428ED9CCC20E7C359A9D41A22FCCD9108E17BF7BA9337A6F8AE9513", 16), // b + mod_q, ECConstants.FOUR)); ecParams = new ECDomainParameters( - curve, - curve.createPoint( - new BigInteger("91E38443A5E82C0D880923425712B2BB658B9196932E02C78B2582FE742DAA28", 16), // x - new BigInteger("32879423AB1A0375895786C4BB46E9565FDE0B5344766740AF268ADB32322E5C", 16)), // y - mod_q); // q + curve, + configureBasepoint(curve, + new BigInteger("91E38443A5E82C0D880923425712B2BB658B9196932E02C78B2582FE742DAA28", 16), // x + new BigInteger("32879423AB1A0375895786C4BB46E9565FDE0B5344766740AF268ADB32322E5C", 16)), // y + mod_q, ECConstants.FOUR); params.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetA, ecParams); mod_p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",16); //p mod_q = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF27E69532F48D89116FF22B8D4E0560609B4B38ABFAD2B85DCACDB1411F10B275",16); //q - curve = new ECCurve.Fp( - mod_p, // p - new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",16), // a - new BigInteger("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760",16), // b - mod_q, - ECConstants.ONE); + + curve = configureCurve(new ECCurve.Fp( + mod_p, // p + new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC4",16), // a + new BigInteger("E8C2505DEDFC86DDC1BD0B2B6667F1DA34B82574761CB0E879BD081CFD0B6265EE3CB090F30D27614CB4574010DA90DD862EF9D4EBEE4761503190785A71C760",16), // b + mod_q, ECConstants.ONE)); ecParams = new ECDomainParameters( - curve, - curve.createPoint( - new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"), // x - new BigInteger("7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4",16)), // y - mod_q); // q + curve, + configureBasepoint(curve, + new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003"), // x + new BigInteger("7503CFE87A836AE3A61B8816E25450E6CE5E1C93ACF1ABC1778064FDCBEFA921DF1626BE4FD036E93D75E6A50E3A41E98028FE5FC235F5B889A589CB5215F2A4",16)), // y + mod_q, ECConstants.ONE); params.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetA, ecParams); mod_p = new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006F",16); //p mod_q = new BigInteger("800000000000000000000000000000000000000000000000000000000000000149A1EC142565A545ACFDB77BD9D40CFA8B996712101BEA0EC6346C54374F25BD",16); //q - curve = new ECCurve.Fp( - mod_p, // p - new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C",16), // a - new BigInteger("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116",16), // b - mod_q, - ECConstants.ONE); + + curve = configureCurve(new ECCurve.Fp( + mod_p, // p + new BigInteger("8000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006C",16), // a + new BigInteger("687D1B459DC841457E3E06CF6F5E2517B97C7D614AF138BCBF85DC806C4B289F3E965D2DB1416D217F8B276FAD1AB69C50F78BEE1FA3106EFB8CCBC7C5140116",16), // b + mod_q, ECConstants.ONE)); ecParams = new ECDomainParameters( - curve, - curve.createPoint( - new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"), // x - new BigInteger("1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD",16)), // y - mod_q); // q + curve, + configureBasepoint(curve, + new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002"), // x + new BigInteger("1A8F7EDA389B094C2C071E3647A8940F3C123B697578C213BE6DD9E6C8EC7335DCB228FD1EDF4A39152CBCAAF8C0398828041055F94CEEEC7E21340780FE41BD",16)), // y + mod_q, ECConstants.ONE); params.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetB, ecParams); mod_p = new BigInteger("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFDC7",16); //p mod_q = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC98CDBA46506AB004C33A9FF5147502CC8EDA9E7A769A12694623CEF47F023ED",16); //q - curve = new ECCurve.Fp( - mod_p, // p - new BigInteger("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3",16), // a - new BigInteger("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1",16), // b - mod_q, - ECConstants.ONE); + + curve = configureCurve(new ECCurve.Fp( + mod_p, // p + new BigInteger("DC9203E514A721875485A529D2C722FB187BC8980EB866644DE41C68E143064546E861C0E2C9EDD92ADE71F46FCF50FF2AD97F951FDA9F2A2EB6546F39689BD3",16), // a + new BigInteger("B4C4EE28CEBC6C2C8AC12952CF37F16AC7EFB6A9F69F4B57FFDA2E4F0DE5ADE038CBC2FFF719D2C18DE0284B8BFEF3B52B8CC7A5F5BF0A3C8D2319A5312557E1",16), // b + mod_q, ECConstants.FOUR)); ecParams = new ECDomainParameters( - curve, - curve.createPoint( - new BigInteger("E2E31EDFC23DE7BDEBE241CE593EF5DE2295B7A9CBAEF021D385F7074CEA043AA27272A7AE602BF2A7B9033DB9ED3610C6FB85487EAE97AAC5BC7928C1950148", 16), // x - new BigInteger("F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F",16)), // y - mod_q); // q + curve, + configureBasepoint(curve, + new BigInteger("E2E31EDFC23DE7BDEBE241CE593EF5DE2295B7A9CBAEF021D385F7074CEA043AA27272A7AE602BF2A7B9033DB9ED3610C6FB85487EAE97AAC5BC7928C1950148", 16), // x + new BigInteger("F5CE40D95B5EB899ABBCCFF5911CB8577939804D6527378B8C108C3D2090FF9BE18E2D33E3021ED2EF32D85822423B6304F726AA854BAE07D0396E9A9ADDC40F",16)), // y + mod_q, ECConstants.FOUR); params.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetC, ecParams); @@ -255,9 +264,4 @@ public class ECGOST3410NamedCurves { return (ASN1ObjectIdentifier)objIds.get(name); } - - public static void main(String[] args) - { - System.err.println(new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFD97"))); - } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java index c00cfcf8c..71cc7e375 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/ECGOST3410ParamSetParameters.java @@ -85,7 +85,7 @@ public class ECGOST3410ParamSetParameters public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); v.add(a); v.add(b); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java index ed038983a..0a71941ee 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST28147Parameters.java @@ -53,10 +53,7 @@ public class GOST28147Parameters this.paramSet = paramSet; } - /** - * @deprecated use the getInstance() method. This constructor will vanish! - */ - public GOST28147Parameters( + private GOST28147Parameters( ASN1Sequence seq) { Enumeration e = seq.getObjects(); @@ -78,7 +75,7 @@ public class GOST28147Parameters */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(iv); v.add(paramSet); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java index a46f2c21c..fa959bee8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST3410ParamSetParameters.java @@ -57,7 +57,7 @@ public class GOST3410ParamSetParameters { Enumeration e = seq.getObjects(); - keySize = ((ASN1Integer)e.nextElement()).getValue().intValue(); + keySize = ((ASN1Integer)e.nextElement()).intValueExact(); p = (ASN1Integer)e.nextElement(); q = (ASN1Integer)e.nextElement(); a = (ASN1Integer)e.nextElement(); @@ -93,7 +93,7 @@ public class GOST3410ParamSetParameters public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(new ASN1Integer(keySize)); v.add(p); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java index 189b4ea00..69641700b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GOST3410PublicKeyAlgParameters.java @@ -57,10 +57,7 @@ public class GOST3410PublicKeyAlgParameters this.encryptionParamSet = encryptionParamSet; } - /** - * @deprecated use getInstance() - */ - public GOST3410PublicKeyAlgParameters( + private GOST3410PublicKeyAlgParameters( ASN1Sequence seq) { this.publicKeyParamSet = (ASN1ObjectIdentifier)seq.getObjectAt(0); @@ -89,7 +86,7 @@ public class GOST3410PublicKeyAlgParameters public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(publicKeyParamSet); v.add(digestParamSet); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/Gost2814789EncryptedKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/Gost2814789EncryptedKey.java index 6400bb201..349585c73 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/Gost2814789EncryptedKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/Gost2814789EncryptedKey.java @@ -78,22 +78,22 @@ public class Gost2814789EncryptedKey public byte[] getEncryptedKey() { - return encryptedKey; + return Arrays.clone(encryptedKey); } public byte[] getMaskKey() { - return maskKey; + return Arrays.clone(maskKey); } public byte[] getMacKey() { - return macKey; + return Arrays.clone(macKey); } public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(new DEROctetString(encryptedKey)); if (maskKey != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/Gost2814789KeyWrapParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/Gost2814789KeyWrapParameters.java index 97abe9f1c..0a2f80dde 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/Gost2814789KeyWrapParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/Gost2814789KeyWrapParameters.java @@ -68,12 +68,12 @@ public class Gost2814789KeyWrapParameters public byte[] getUkm() { - return ukm; + return Arrays.clone(ukm); } public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(encryptionParamSet); if (ukm != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GostR3410KeyTransport.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GostR3410KeyTransport.java index 291504a53..7fd0a1661 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GostR3410KeyTransport.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GostR3410KeyTransport.java @@ -63,7 +63,7 @@ public class GostR3410KeyTransport public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(sessionEncryptedKey); if (transportParameters != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GostR3410TransportParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GostR3410TransportParameters.java index 375cc4100..f4c188e62 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GostR3410TransportParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/cryptopro/GostR3410TransportParameters.java @@ -97,7 +97,7 @@ public class GostR3410TransportParameters public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(encryptionParamSet); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java index 8e9a58073..7bdb5c1fd 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSCertInfo.java @@ -73,7 +73,7 @@ public class DVCSCertInfo try { ASN1Integer encVersion = ASN1Integer.getInstance(x); - this.version = encVersion.getValue().intValue(); + this.version = encVersion.intValueExact(); x = seq.getObjectAt(i++); } catch (IllegalArgumentException e) @@ -154,8 +154,7 @@ public class DVCSCertInfo public ASN1Primitive toASN1Primitive() { - - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(10); if (version != DEFAULT_VERSION) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java index b26619daf..4ed5d2830 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSCertInfoBuilder.java @@ -63,8 +63,7 @@ public class DVCSCertInfoBuilder public DVCSCertInfo build() { - - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(10); if (version != DEFAULT_VERSION) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSErrorNotice.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSErrorNotice.java index fa011967d..036b618f4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSErrorNotice.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSErrorNotice.java @@ -66,7 +66,7 @@ public class DVCSErrorNotice public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(transactionStatus); if (transactionIdentifier != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequest.java index 7b5e8237f..597e2f400 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequest.java @@ -71,7 +71,7 @@ public class DVCSRequest public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(requestInformation); v.add(data); if (transactionIdentifier != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java index a676788c3..d18dfbc7c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequestInformation.java @@ -59,7 +59,7 @@ public class DVCSRequestInformation if (seq.getObjectAt(0) instanceof ASN1Integer) { ASN1Integer encVersion = ASN1Integer.getInstance(seq.getObjectAt(i++)); - this.version = encVersion.getValue().intValue(); + this.version = encVersion.intValueExact(); } else { @@ -138,7 +138,7 @@ public class DVCSRequestInformation public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(9); if (version != DEFAULT_VERSION) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java index 6d9e16046..f3b07249f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/DVCSRequestInformationBuilder.java @@ -69,7 +69,7 @@ public class DVCSRequestInformationBuilder public DVCSRequestInformation build() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(9); if (version != DEFAULT_VERSION) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/PathProcInput.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/PathProcInput.java index cb26bf017..fde3170ff 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/PathProcInput.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/PathProcInput.java @@ -1,6 +1,3 @@ -/***************************************************************/ -/****** DO NOT EDIT THIS CLASS bc-java SOURCE FILE ******/ -/***************************************************************/ package com.fr.third.org.bouncycastle.asn1.dvcs; import java.util.Arrays; @@ -29,7 +26,6 @@ import com.fr.third.org.bouncycastle.asn1.x509.PolicyInformation; public class PathProcInput extends ASN1Object { - private PolicyInformation[] acceptablePolicySet; private boolean inhibitPolicyMapping = false; private boolean explicitPolicyReqd = false; @@ -37,12 +33,12 @@ public class PathProcInput public PathProcInput(PolicyInformation[] acceptablePolicySet) { - this.acceptablePolicySet = acceptablePolicySet; + this.acceptablePolicySet = copy(acceptablePolicySet); } public PathProcInput(PolicyInformation[] acceptablePolicySet, boolean inhibitPolicyMapping, boolean explicitPolicyReqd, boolean inhibitAnyPolicy) { - this.acceptablePolicySet = acceptablePolicySet; + this.acceptablePolicySet = copy(acceptablePolicySet); this.inhibitPolicyMapping = inhibitPolicyMapping; this.explicitPolicyReqd = explicitPolicyReqd; this.inhibitAnyPolicy = inhibitAnyPolicy; @@ -115,16 +111,18 @@ public class PathProcInput public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); - ASN1EncodableVector pV = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); - for (int i = 0; i != acceptablePolicySet.length; i++) { - pV.add(acceptablePolicySet[i]); + ASN1EncodableVector pV = new ASN1EncodableVector(acceptablePolicySet.length); + for (int i = 0; i != acceptablePolicySet.length; i++) + { + pV.add(acceptablePolicySet[i]); + } + + v.add(new DERSequence(pV)); } - v.add(new DERSequence(pV)); - if (inhibitPolicyMapping) { v.add(ASN1Boolean.getInstance(inhibitPolicyMapping)); @@ -153,7 +151,7 @@ public class PathProcInput public PolicyInformation[] getAcceptablePolicySet() { - return acceptablePolicySet; + return copy(acceptablePolicySet); } public boolean isInhibitPolicyMapping() @@ -185,4 +183,13 @@ public class PathProcInput { this.inhibitAnyPolicy = inhibitAnyPolicy; } + + private PolicyInformation[] copy(PolicyInformation[] policySet) + { + PolicyInformation[] rv = new PolicyInformation[policySet.length]; + + System.arraycopy(policySet, 0, rv, 0, rv.length); + + return rv; + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/ServiceType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/ServiceType.java index 563cc4036..f66537949 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/ServiceType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/ServiceType.java @@ -80,12 +80,12 @@ public class ServiceType public String toString() { - int num = value.getValue().intValue(); + int num = value.intValueExact(); return "" + num + ( - num == CPD.getValue().intValue() ? "(CPD)" : - num == VSD.getValue().intValue() ? "(VSD)" : - num == VPKC.getValue().intValue() ? "(VPKC)" : - num == CCPD.getValue().intValue() ? "(CCPD)" : + num == CPD.value.intValueExact() ? "(CPD)" : + num == VSD.value.intValueExact() ? "(VSD)" : + num == VPKC.value.intValueExact() ? "(VPKC)" : + num == CCPD.value.intValueExact() ? "(CCPD)" : "?"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/TargetEtcChain.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/TargetEtcChain.java index dfe88acc7..307fbb576 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/TargetEtcChain.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/dvcs/TargetEtcChain.java @@ -115,7 +115,7 @@ public class TargetEtcChain public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(target); if (chain != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CVCertificate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CVCertificate.java index 5d8105551..5a4fa249f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CVCertificate.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CVCertificate.java @@ -49,10 +49,10 @@ public class CVCertificate ASN1Primitive tmpObj; while ((tmpObj = content.readObject()) != null) { - DERApplicationSpecific aSpe; - if (tmpObj instanceof DERApplicationSpecific) + ASN1ApplicationSpecific aSpe; + if (tmpObj instanceof ASN1ApplicationSpecific) { - aSpe = (DERApplicationSpecific)tmpObj; + aSpe = (ASN1ApplicationSpecific)tmpObj; switch (aSpe.getApplicationTag()) { case EACTags.CERTIFICATE_CONTENT_TEMPLATE: @@ -103,9 +103,9 @@ public class CVCertificate ASN1Primitive obj; while ((obj = aIS.readObject()) != null) { - if (obj instanceof DERApplicationSpecific) + if (obj instanceof ASN1ApplicationSpecific) { - setPrivateData((DERApplicationSpecific)obj); + setPrivateData((ASN1ApplicationSpecific)obj); } else { @@ -115,10 +115,10 @@ public class CVCertificate } /** - * Create an iso7816Certificate structure from a DERApplicationSpecific. + * Create an iso7816Certificate structure from a ASN1ApplicationSpecific. * - * @param appSpe the DERApplicationSpecific object. - * @return the Iso7816CertificateStructure represented by the DERApplicationSpecific object. + * @param appSpe the ASN1ApplicationSpecific object. + * @return the Iso7816CertificateStructure represented by the ASN1ApplicationSpecific object. * @throws IOException if there is a problem parsing the data. */ private CVCertificate(ASN1ApplicationSpecific appSpe) @@ -160,7 +160,7 @@ public class CVCertificate { try { - return new CVCertificate(DERApplicationSpecific.getInstance(obj)); + return new CVCertificate(ASN1ApplicationSpecific.getInstance(obj)); } catch (IOException e) { @@ -197,7 +197,7 @@ public class CVCertificate */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(certificateBody); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CVCertificateRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CVCertificateRequest.java index 28cdebcae..89be1f060 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CVCertificateRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CVCertificateRequest.java @@ -144,7 +144,7 @@ public class CVCertificateRequest } else { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(certificateBody); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CertificateBody.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CertificateBody.java index 21254f514..2fb82b7c6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CertificateBody.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CertificateBody.java @@ -17,24 +17,24 @@ import com.fr.third.org.bouncycastle.asn1.DEROctetString; *
  *  CertificateBody ::= SEQUENCE {
  *      // version of the certificate format. Must be 0 (version 1)
- *      CertificateProfileIdentifer         DERApplicationSpecific,
+ *      CertificateProfileIdentifer         ASN1ApplicationSpecific,
  *      //uniquely identifies the issuinng CA's signature key pair
  *      // contains the iso3166-1 alpha2 encoded country code, the
  *      // name of issuer and the sequence number of the key pair.
- *      CertificationAuthorityReference        DERApplicationSpecific,
+ *      CertificationAuthorityReference        ASN1ApplicationSpecific,
  *      // stores the encoded public key
  *      PublicKey                            Iso7816PublicKey,
  *      //associates the public key contained in the certificate with a unique name
  *      // contains the iso3166-1 alpha2 encoded country code, the
  *      // name of the holder and the sequence number of the key pair.
- *      certificateHolderReference            DERApplicationSpecific,
+ *      certificateHolderReference            ASN1ApplicationSpecific,
  *      // Encodes the role of the holder (i.e. CVCA, DV, IS) and assigns read/write
  *      // access rights to data groups storing sensitive data
  *      certificateHolderAuthorization        Iso7816CertificateHolderAuthorization,
  *      // the date of the certificate generation
- *      CertificateEffectiveDate            DERApplicationSpecific,
+ *      CertificateEffectiveDate            ASN1ApplicationSpecific,
  *      // the date after wich the certificate expires
- *      certificateExpirationDate            DERApplicationSpecific
+ *      certificateExpirationDate            ASN1ApplicationSpecific
  *  }
  * 
*/ @@ -42,13 +42,13 @@ public class CertificateBody extends ASN1Object { ASN1InputStream seq; - private DERApplicationSpecific certificateProfileIdentifier;// version of the certificate format. Must be 0 (version 1) - private DERApplicationSpecific certificationAuthorityReference;//uniquely identifies the issuinng CA's signature key pair + private ASN1ApplicationSpecific certificateProfileIdentifier;// version of the certificate format. Must be 0 (version 1) + private ASN1ApplicationSpecific certificationAuthorityReference;//uniquely identifies the issuinng CA's signature key pair private PublicKeyDataObject publicKey;// stores the encoded public key - private DERApplicationSpecific certificateHolderReference;//associates the public key contained in the certificate with a unique name + private ASN1ApplicationSpecific certificateHolderReference;//associates the public key contained in the certificate with a unique name private CertificateHolderAuthorization certificateHolderAuthorization;// Encodes the role of the holder (i.e. CVCA, DV, IS) and assigns read/write access rights to data groups storing sensitive data - private DERApplicationSpecific certificateEffectiveDate;// the date of the certificate generation - private DERApplicationSpecific certificateExpirationDate;// the date after wich the certificate expires + private ASN1ApplicationSpecific certificateEffectiveDate;// the date of the certificate generation + private ASN1ApplicationSpecific certificateExpirationDate;// the date after wich the certificate expires private int certificateType = 0;// bit field of initialized data. This will tell us if the data are valid. private static final int CPI = 0x01;//certificate Profile Identifier private static final int CAR = 0x02;//certification Authority Reference @@ -77,15 +77,15 @@ public class CertificateBody ASN1Primitive obj; while ((obj = aIS.readObject()) != null) { - DERApplicationSpecific aSpe; + ASN1ApplicationSpecific aSpe; - if (obj instanceof DERApplicationSpecific) + if (obj instanceof ASN1ApplicationSpecific) { - aSpe = (DERApplicationSpecific)obj; + aSpe = (ASN1ApplicationSpecific)obj; } else { - throw new IOException("Not a valid iso7816 content : not a DERApplicationSpecific Object :" + EACTags.encodeTag(appSpe) + obj.getClass()); + throw new IOException("Not a valid iso7816 content : not a ASN1ApplicationSpecific Object :" + EACTags.encodeTag(appSpe) + obj.getClass()); } switch (aSpe.getApplicationTag()) { @@ -112,7 +112,7 @@ public class CertificateBody break; default: certificateType = 0; - throw new IOException("Not a valid iso7816 DERApplicationSpecific tag " + aSpe.getApplicationTag()); + throw new IOException("Not a valid iso7816 ASN1ApplicationSpecific tag " + aSpe.getApplicationTag()); } } aIS.close(); @@ -131,7 +131,7 @@ public class CertificateBody * @param certificateExpirationDate */ public CertificateBody( - DERApplicationSpecific certificateProfileIdentifier, + ASN1ApplicationSpecific certificateProfileIdentifier, CertificationAuthorityReference certificationAuthorityReference, PublicKeyDataObject publicKey, CertificateHolderReference certificateHolderReference, @@ -163,7 +163,7 @@ public class CertificateBody /** * builds an Iso7816CertificateBody with an ASN1InputStream. * - * @param obj DERApplicationSpecific containing the whole body. + * @param obj ASN1ApplicationSpecific containing the whole body. * @throws IOException if the body is not valid. */ private CertificateBody(ASN1ApplicationSpecific obj) @@ -176,12 +176,12 @@ public class CertificateBody * create a profile type Iso7816CertificateBody. * * @return return the "profile" type certificate body. - * @throws IOException if the DERApplicationSpecific cannot be created. + * @throws IOException if the ASN1ApplicationSpecific cannot be created. */ private ASN1Primitive profileToASN1Object() throws IOException { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(7); v.add(certificateProfileIdentifier); v.add(certificationAuthorityReference); @@ -193,7 +193,7 @@ public class CertificateBody return new DERApplicationSpecific(EACTags.CERTIFICATE_CONTENT_TEMPLATE, v); } - private void setCertificateProfileIdentifier(DERApplicationSpecific certificateProfileIdentifier) + private void setCertificateProfileIdentifier(ASN1ApplicationSpecific certificateProfileIdentifier) throws IllegalArgumentException { if (certificateProfileIdentifier.getApplicationTag() == EACTags.INTERCHANGE_PROFILE) @@ -207,7 +207,7 @@ public class CertificateBody } } - private void setCertificateHolderReference(DERApplicationSpecific certificateHolderReference) + private void setCertificateHolderReference(ASN1ApplicationSpecific certificateHolderReference) throws IllegalArgumentException { if (certificateHolderReference.getApplicationTag() == EACTags.CARDHOLDER_NAME) @@ -225,11 +225,11 @@ public class CertificateBody * set the CertificationAuthorityReference. * * @param certificationAuthorityReference - * the DERApplicationSpecific containing the CertificationAuthorityReference. - * @throws IllegalArgumentException if the DERApplicationSpecific is not valid. + * the ASN1ApplicationSpecific containing the CertificationAuthorityReference. + * @throws IllegalArgumentException if the ASN1ApplicationSpecific is not valid. */ private void setCertificationAuthorityReference( - DERApplicationSpecific certificationAuthorityReference) + ASN1ApplicationSpecific certificationAuthorityReference) throws IllegalArgumentException { if (certificationAuthorityReference.getApplicationTag() == EACTags.ISSUER_IDENTIFICATION_NUMBER) @@ -246,7 +246,7 @@ public class CertificateBody /** * set the public Key * - * @param publicKey : the DERApplicationSpecific containing the public key + * @param publicKey : the ASN1ApplicationSpecific containing the public key * @throws java.io.IOException */ private void setPublicKey(PublicKeyDataObject publicKey) @@ -259,12 +259,12 @@ public class CertificateBody * create a request type Iso7816CertificateBody. * * @return return the "request" type certificate body. - * @throws IOException if the DERApplicationSpecific cannot be created. + * @throws IOException if the ASN1ApplicationSpecific cannot be created. */ private ASN1Primitive requestToASN1Object() throws IOException { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(certificateProfileIdentifier); v.add(new DERApplicationSpecific(false, EACTags.CARDHOLDER_PUBLIC_KEY_TEMPLATE, publicKey)); @@ -345,10 +345,10 @@ public class CertificateBody /** * set the date of the certificate generation * - * @param ced DERApplicationSpecific containing the date of the certificate generation + * @param ced ASN1ApplicationSpecific containing the date of the certificate generation * @throws IllegalArgumentException if the tag is not Iso7816Tags.APPLICATION_EFFECTIVE_DATE */ - private void setCertificateEffectiveDate(DERApplicationSpecific ced) + private void setCertificateEffectiveDate(ASN1ApplicationSpecific ced) throws IllegalArgumentException { if (ced.getApplicationTag() == EACTags.APPLICATION_EFFECTIVE_DATE) @@ -379,10 +379,10 @@ public class CertificateBody /** * set the date after wich the certificate expires * - * @param ced DERApplicationSpecific containing the date after wich the certificate expires + * @param ced ASN1ApplicationSpecific containing the date after wich the certificate expires * @throws IllegalArgumentException if the tag is not Iso7816Tags.APPLICATION_EXPIRATION_DATE */ - private void setCertificateExpirationDate(DERApplicationSpecific ced) + private void setCertificateExpirationDate(ASN1ApplicationSpecific ced) throws IllegalArgumentException { if (ced.getApplicationTag() == EACTags.APPLICATION_EXPIRATION_DATE) @@ -442,7 +442,7 @@ public class CertificateBody * * @return the CertificateProfileIdentifier */ - public DERApplicationSpecific getCertificateProfileIdentifier() + public ASN1ApplicationSpecific getCertificateProfileIdentifier() { return certificateProfileIdentifier; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CertificateHolderAuthorization.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CertificateHolderAuthorization.java index 6921ca2d6..819f4a6f6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CertificateHolderAuthorization.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/CertificateHolderAuthorization.java @@ -3,6 +3,7 @@ package com.fr.third.org.bouncycastle.asn1.eac; import java.io.IOException; import java.util.Hashtable; +import com.fr.third.org.bouncycastle.asn1.ASN1ApplicationSpecific; import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; import com.fr.third.org.bouncycastle.asn1.ASN1Object; @@ -27,7 +28,7 @@ public class CertificateHolderAuthorization extends ASN1Object { ASN1ObjectIdentifier oid; - DERApplicationSpecific accessRights; + ASN1ApplicationSpecific accessRights; public static final ASN1ObjectIdentifier id_role_EAC = EACObjectIdentifiers.bsi_de.branch("3.1.2.1"); public static final int CVCA = 0xC0; public static final int DV_DOMESTIC = 0x80; @@ -89,9 +90,9 @@ public class CertificateHolderAuthorization throw new IllegalArgumentException("no Oid in CerticateHolderAuthorization"); } obj = cha.readObject(); - if (obj instanceof DERApplicationSpecific) + if (obj instanceof ASN1ApplicationSpecific) { - this.accessRights = (DERApplicationSpecific)obj; + this.accessRights = (ASN1ApplicationSpecific)obj; } else { @@ -116,12 +117,12 @@ public class CertificateHolderAuthorization } /** - * create an Iso7816CertificateHolderAuthorization according to the {@link DERApplicationSpecific} + * create an Iso7816CertificateHolderAuthorization according to the {@link ASN1ApplicationSpecific} * * @param aSpe the DERApplicationSpecific containing the data * @throws IOException */ - public CertificateHolderAuthorization(DERApplicationSpecific aSpe) + public CertificateHolderAuthorization(ASN1ApplicationSpecific aSpe) throws IOException { if (aSpe.getApplicationTag() == EACTags.CERTIFICATE_HOLDER_AUTHORIZATION_TEMPLATE) @@ -173,7 +174,7 @@ public class CertificateHolderAuthorization */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(oid); v.add(accessRights); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/EACTags.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/EACTags.java index 036a218f8..a066fe936 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/EACTags.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/EACTags.java @@ -166,6 +166,7 @@ public class EACTags retValue <<= 8; currentByte = tag & 0x7F; + retValue |= currentByte; tag >>= 7; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/ECDSAPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/ECDSAPublicKey.java index 2c98a4b8b..866b3829f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/ECDSAPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/ECDSAPublicKey.java @@ -314,7 +314,7 @@ public class ECDSAPublicKey public ASN1EncodableVector getASN1EncodableVector(ASN1ObjectIdentifier oid, boolean publicPointOnly) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(8); v.add(oid); if (!publicPointOnly) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/Flags.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/Flags.java index 2bdee8d67..1fe53b295 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/Flags.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/Flags.java @@ -62,7 +62,7 @@ public class Flags return joiner.toString(); } - private class StringJoiner + private static class StringJoiner { String mSeparator; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/RSAPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/RSAPublicKey.java index f6b2f89b9..1c42c3b18 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/RSAPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/eac/RSAPublicKey.java @@ -109,7 +109,7 @@ public class RSAPublicKey public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(usage); v.add(new UnsignedInteger(0x01, getModulus())); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/edec/EdECObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/edec/EdECObjectIdentifiers.java new file mode 100644 index 000000000..f7b13baef --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/edec/EdECObjectIdentifiers.java @@ -0,0 +1,16 @@ +package com.fr.third.org.bouncycastle.asn1.edec; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; + +/** + * Edwards Elliptic Curve Object Identifiers (RFC 8410) + */ +public interface EdECObjectIdentifiers +{ + ASN1ObjectIdentifier id_edwards_curve_algs = new ASN1ObjectIdentifier("1.3.101"); + + ASN1ObjectIdentifier id_X25519 = id_edwards_curve_algs.branch("110").intern(); + ASN1ObjectIdentifier id_X448 = id_edwards_curve_algs.branch("111").intern(); + ASN1ObjectIdentifier id_Ed25519 = id_edwards_curve_algs.branch("112").intern(); + ASN1ObjectIdentifier id_Ed448 = id_edwards_curve_algs.branch("113").intern(); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java index b36de2615..9b3cb111b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CommitmentTypeIndication.java @@ -69,7 +69,7 @@ public class CommitmentTypeIndication */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(commitmentTypeId); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java index 93087da02..dc68aaa6c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CommitmentTypeQualifier.java @@ -96,7 +96,7 @@ public class CommitmentTypeQualifier */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector dev = new ASN1EncodableVector(); + ASN1EncodableVector dev = new ASN1EncodableVector(2); dev.add(commitmentTypeIdentifier); if (qualifier != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlIdentifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlIdentifier.java index 2a9752929..b78846524 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlIdentifier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlIdentifier.java @@ -93,7 +93,7 @@ public class CrlIdentifier public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(this.crlIssuer.toASN1Primitive()); v.add(this.crlIssuedTime); if (null != this.crlNumber) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlOcspRef.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlOcspRef.java index fe66cf08d..8678969f1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlOcspRef.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlOcspRef.java @@ -89,7 +89,7 @@ public class CrlOcspRef public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (null != this.crlids) { v.add(new DERTaggedObject(true, 0, this.crlids.toASN1Primitive())); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlValidatedID.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlValidatedID.java index c884d8cf7..3dab43e79 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlValidatedID.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/CrlValidatedID.java @@ -71,7 +71,7 @@ public class CrlValidatedID public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(this.crlHash.toASN1Primitive()); if (null != this.crlIdentifier) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OcspIdentifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OcspIdentifier.java index ca3a96453..6121150d2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OcspIdentifier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OcspIdentifier.java @@ -65,7 +65,7 @@ public class OcspIdentifier public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(this.ocspResponderID); v.add(this.producedAt); return new DERSequence(v); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OcspResponsesID.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OcspResponsesID.java index 97d67eece..2aba28610 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OcspResponsesID.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OcspResponsesID.java @@ -72,7 +72,7 @@ public class OcspResponsesID public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(this.ocspIdentifier); if (null != this.ocspRepHash) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherHashAlgAndValue.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherHashAlgAndValue.java index 0709f6584..3649e648d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherHashAlgAndValue.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherHashAlgAndValue.java @@ -71,7 +71,7 @@ public class OtherHashAlgAndValue */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(hashAlgorithm); v.add(hashValue); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherRevRefs.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherRevRefs.java index fff1fd01f..7a4e7cbd7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherRevRefs.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherRevRefs.java @@ -79,7 +79,7 @@ public class OtherRevRefs public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(this.otherRevRefType); v.add(this.otherRevRefs); return new DERSequence(v); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherRevVals.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherRevVals.java index 92e77185d..45941e574 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherRevVals.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/OtherRevVals.java @@ -81,7 +81,7 @@ public class OtherRevVals public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(this.otherRevValType); v.add(this.otherRevVals); return new DERSequence(v); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/RevocationValues.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/RevocationValues.java index d9998f9ff..8f70a3b99 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/RevocationValues.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/RevocationValues.java @@ -134,7 +134,7 @@ public class RevocationValues public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (null != this.crlVals) { v.add(new DERTaggedObject(true, 0, this.crlVals)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SPUserNotice.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SPUserNotice.java index e9b2c3d68..b990cabde 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SPUserNotice.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SPUserNotice.java @@ -82,7 +82,7 @@ public class SPUserNotice */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (noticeRef != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SigPolicyQualifierInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SigPolicyQualifierInfo.java index 8cc6122bf..68cc21787 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SigPolicyQualifierInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SigPolicyQualifierInfo.java @@ -65,7 +65,7 @@ public class SigPolicyQualifierInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(sigPolicyQualifierId); v.add(sigQualifier); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SigPolicyQualifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SigPolicyQualifiers.java index 75b614709..8452875bf 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SigPolicyQualifiers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SigPolicyQualifiers.java @@ -1,6 +1,5 @@ package com.fr.third.org.bouncycastle.asn1.esf; -import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; import com.fr.third.org.bouncycastle.asn1.ASN1Object; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; @@ -35,12 +34,7 @@ public class SigPolicyQualifiers public SigPolicyQualifiers( SigPolicyQualifierInfo[] qualifierInfos) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i=0; i < qualifierInfos.length; i++) - { - v.add(qualifierInfos[i]); - } - qualifiers = new DERSequence(v); + qualifiers = new DERSequence(qualifierInfos); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignaturePolicyId.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignaturePolicyId.java index 441dc1a8a..499415f02 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignaturePolicyId.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignaturePolicyId.java @@ -89,7 +89,7 @@ public class SignaturePolicyId */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(sigPolicyId); v.add(sigPolicyHash); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignerAttribute.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignerAttribute.java index 6d2c605fc..25fce09cd 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignerAttribute.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignerAttribute.java @@ -108,7 +108,7 @@ public class SignerAttribute */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(values.length); for (int i = 0; i != values.length; i++) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignerLocation.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignerLocation.java index d147f740b..c19626793 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignerLocation.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/esf/SignerLocation.java @@ -199,7 +199,7 @@ public class SignerLocation */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (countryName != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ContentHints.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ContentHints.java index 79a5ce43b..6edda02a7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ContentHints.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ContentHints.java @@ -80,7 +80,7 @@ public class ContentHints */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (contentDescription != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ESSCertID.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ESSCertID.java index 0df3347d7..c359fae13 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ESSCertID.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ESSCertID.java @@ -81,7 +81,7 @@ public class ESSCertID */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(certHash); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ESSCertIDv2.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ESSCertIDv2.java index f350ca495..0a342aeb9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ESSCertIDv2.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/ESSCertIDv2.java @@ -136,7 +136,7 @@ public class ESSCertIDv2 */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (!hashAlgorithm.equals(DEFAULT_ALG_ID)) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/OtherCertID.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/OtherCertID.java index eeb942b98..dbb94b8ed 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/OtherCertID.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/OtherCertID.java @@ -3,7 +3,6 @@ package com.fr.third.org.bouncycastle.asn1.ess; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; import com.fr.third.org.bouncycastle.asn1.ASN1Object; -import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; @@ -125,7 +124,7 @@ public class OtherCertID */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(otherCertHash); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/OtherSigningCertificate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/OtherSigningCertificate.java index 8e01d5e16..5e165ff44 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/OtherSigningCertificate.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/OtherSigningCertificate.java @@ -95,7 +95,7 @@ public class OtherSigningCertificate */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(certs); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/SigningCertificate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/SigningCertificate.java index 673c60a40..e3e77c3a4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/SigningCertificate.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/SigningCertificate.java @@ -95,7 +95,7 @@ public class SigningCertificate */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(certs); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/SigningCertificateV2.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/SigningCertificateV2.java index d081b9736..e3a6af2ae 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/SigningCertificateV2.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ess/SigningCertificateV2.java @@ -53,33 +53,18 @@ public class SigningCertificateV2 public SigningCertificateV2( ESSCertIDv2[] certs) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i=0; i < certs.length; i++) - { - v.add(certs[i]); - } - this.certs = new DERSequence(v); + this.certs = new DERSequence(certs); } public SigningCertificateV2( ESSCertIDv2[] certs, PolicyInformation[] policies) { - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i=0; i < certs.length; i++) - { - v.add(certs[i]); - } - this.certs = new DERSequence(v); + this.certs = new DERSequence(certs); if (policies != null) { - v = new ASN1EncodableVector(); - for (int i=0; i < policies.length; i++) - { - v.add(policies[i]); - } - this.policies = new DERSequence(v); + this.policies = new DERSequence(policies); } } @@ -122,7 +107,7 @@ public class SigningCertificateV2 */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(certs); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/gm/GMNamedCurves.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/gm/GMNamedCurves.java index 01f8273f1..610bdb235 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/gm/GMNamedCurves.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/gm/GMNamedCurves.java @@ -9,6 +9,7 @@ import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParametersHolder; import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.WNafUtil; import com.fr.third.org.bouncycastle.util.Strings; import com.fr.third.org.bouncycastle.util.encoders.Hex; @@ -17,15 +18,21 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; */ public class GMNamedCurves { + private static X9ECPoint configureBasepoint(ECCurve curve, String encoding) + { + X9ECPoint G = new X9ECPoint(curve, Hex.decodeStrict(encoding)); + WNafUtil.configureBasepoint(G.getPoint()); + return G; + } + private static ECCurve configureCurve(ECCurve curve) { return curve; } - private static BigInteger fromHex( - String hex) + private static BigInteger fromHex(String hex) { - return new BigInteger(1, Hex.decode(hex)); + return new BigInteger(1, Hex.decodeStrict(hex)); } /* @@ -35,7 +42,6 @@ public class GMNamedCurves { protected X9ECParameters createParameters() { - BigInteger p = fromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF"); BigInteger a = fromHex("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"); BigInteger b = fromHex("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"); @@ -44,9 +50,8 @@ public class GMNamedCurves BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" - + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0")); + X9ECPoint G = configureBasepoint(curve, + "0432C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"); return new X9ECParameters(curve, G, n, h, S); } @@ -64,14 +69,14 @@ public class GMNamedCurves BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "4AD5F7048DE709AD51236DE6" + "5E4D4B482C836DC6E4106640" - + "02BB3A02D4AAADACAE24817A" + "4CA3A1B014B5270432DB27D2")); + X9ECPoint G = configureBasepoint(curve, + "044AD5F7048DE709AD51236DE65E4D4B482C836DC6E410664002BB3A02D4AAADACAE24817A4CA3A1B014B5270432DB27D2"); return new X9ECParameters(curve, G, n, h, S); } }; - + + static final Hashtable objIds = new Hashtable(); static final Hashtable curves = new Hashtable(); static final Hashtable names = new Hashtable(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java index fa2d49623..b62f6ce01 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/gnu/GNUObjectIdentifiers.java @@ -3,61 +3,109 @@ package com.fr.third.org.bouncycastle.asn1.gnu; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; /** - * GNU project OID collection

- * { iso(1) identifier-organization(3) dod(6) internet(1) private(4) } == IETF defined things + * GNU project OID collection

+ * { iso(1) identifier-organization(3) dod(6) internet(1) private(4) } == IETF defined things */ public interface GNUObjectIdentifiers { - /** 1.3.6.1.4.1.11591.1 -- used by GNU Radius */ - public static final ASN1ObjectIdentifier GNU = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.1"); // GNU Radius - /** 1.3.6.1.4.1.11591.2 -- used by GNU PG */ - public static final ASN1ObjectIdentifier GnuPG = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2"); // GnuPG (Ägypten) - /** 1.3.6.1.4.1.11591.2.1 -- notation */ - public static final ASN1ObjectIdentifier notation = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2.1"); // notation - /** 1.3.6.1.4.1.11591.2.1.1 -- pkaAddress */ - public static final ASN1ObjectIdentifier pkaAddress = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2.1.1"); // pkaAddress - /** 1.3.6.1.4.1.11591.3 -- GNU Radar */ - public static final ASN1ObjectIdentifier GnuRadar = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.3"); // GNU Radar - /** 1.3.6.1.4.1.11591.12 -- digestAlgorithm */ - public static final ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.12"); // digestAlgorithm - /** 1.3.6.1.4.1.11591.12.2 -- TIGER/192 */ - public static final ASN1ObjectIdentifier Tiger_192 = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.12.2"); // TIGER/192 - /** 1.3.6.1.4.1.11591.13 -- encryptionAlgorithm */ - public static final ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13"); // encryptionAlgorithm - /** 1.3.6.1.4.1.11591.13.2 -- Serpent */ - public static final ASN1ObjectIdentifier Serpent = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2"); // Serpent - /** 1.3.6.1.4.1.11591.13.2.1 -- Serpent-128-ECB */ - public static final ASN1ObjectIdentifier Serpent_128_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.1"); // Serpent-128-ECB - /** 1.3.6.1.4.1.11591.13.2.2 -- Serpent-128-CBC */ - public static final ASN1ObjectIdentifier Serpent_128_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.2"); // Serpent-128-CBC - /** 1.3.6.1.4.1.11591.13.2.3 -- Serpent-128-OFB */ - public static final ASN1ObjectIdentifier Serpent_128_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.3"); // Serpent-128-OFB - /** 1.3.6.1.4.1.11591.13.2.4 -- Serpent-128-CFB */ - public static final ASN1ObjectIdentifier Serpent_128_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.4"); // Serpent-128-CFB - /** 1.3.6.1.4.1.11591.13.2.21 -- Serpent-192-ECB */ - public static final ASN1ObjectIdentifier Serpent_192_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.21"); // Serpent-192-ECB - /** 1.3.6.1.4.1.11591.13.2.22 -- Serpent-192-CCB */ - public static final ASN1ObjectIdentifier Serpent_192_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.22"); // Serpent-192-CBC - /** 1.3.6.1.4.1.11591.13.2.23 -- Serpent-192-OFB */ - public static final ASN1ObjectIdentifier Serpent_192_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.23"); // Serpent-192-OFB - /** 1.3.6.1.4.1.11591.13.2.24 -- Serpent-192-CFB */ - public static final ASN1ObjectIdentifier Serpent_192_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.24"); // Serpent-192-CFB - /** 1.3.6.1.4.1.11591.13.2.41 -- Serpent-256-ECB */ - public static final ASN1ObjectIdentifier Serpent_256_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.41"); // Serpent-256-ECB - /** 1.3.6.1.4.1.11591.13.2.42 -- Serpent-256-CBC */ - public static final ASN1ObjectIdentifier Serpent_256_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.42"); // Serpent-256-CBC - /** 1.3.6.1.4.1.11591.13.2.43 -- Serpent-256-OFB */ - public static final ASN1ObjectIdentifier Serpent_256_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.43"); // Serpent-256-OFB - /** 1.3.6.1.4.1.11591.13.2.44 -- Serpent-256-CFB */ - public static final ASN1ObjectIdentifier Serpent_256_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB + /** + * 1.3.6.1.4.1.11591.1 -- used by GNU Radius + */ + ASN1ObjectIdentifier GNU = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.1"); // GNU Radius + /** + * 1.3.6.1.4.1.11591.2 -- used by GNU PG + */ + ASN1ObjectIdentifier GnuPG = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2"); // GnuPG (Ägypten) + /** + * 1.3.6.1.4.1.11591.2.1 -- notation + */ + ASN1ObjectIdentifier notation = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2.1"); // notation + /** + * 1.3.6.1.4.1.11591.2.1.1 -- pkaAddress + */ + ASN1ObjectIdentifier pkaAddress = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.2.1.1"); // pkaAddress + /** + * 1.3.6.1.4.1.11591.3 -- GNU Radar + */ + ASN1ObjectIdentifier GnuRadar = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.3"); // GNU Radar + /** + * 1.3.6.1.4.1.11591.12 -- digestAlgorithm + */ + ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.12"); // digestAlgorithm + /** + * 1.3.6.1.4.1.11591.12.2 -- TIGER/192 + */ + ASN1ObjectIdentifier Tiger_192 = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.12.2"); // TIGER/192 + /** + * 1.3.6.1.4.1.11591.13 -- encryptionAlgorithm + */ + ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13"); // encryptionAlgorithm + /** + * 1.3.6.1.4.1.11591.13.2 -- Serpent + */ + ASN1ObjectIdentifier Serpent = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2"); // Serpent + /** + * 1.3.6.1.4.1.11591.13.2.1 -- Serpent-128-ECB + */ + ASN1ObjectIdentifier Serpent_128_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.1"); // Serpent-128-ECB + /** + * 1.3.6.1.4.1.11591.13.2.2 -- Serpent-128-CBC + */ + ASN1ObjectIdentifier Serpent_128_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.2"); // Serpent-128-CBC + /** + * 1.3.6.1.4.1.11591.13.2.3 -- Serpent-128-OFB + */ + ASN1ObjectIdentifier Serpent_128_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.3"); // Serpent-128-OFB + /** + * 1.3.6.1.4.1.11591.13.2.4 -- Serpent-128-CFB + */ + ASN1ObjectIdentifier Serpent_128_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.4"); // Serpent-128-CFB + /** + * 1.3.6.1.4.1.11591.13.2.21 -- Serpent-192-ECB + */ + ASN1ObjectIdentifier Serpent_192_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.21"); // Serpent-192-ECB + /** + * 1.3.6.1.4.1.11591.13.2.22 -- Serpent-192-CCB + */ + ASN1ObjectIdentifier Serpent_192_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.22"); // Serpent-192-CBC + /** + * 1.3.6.1.4.1.11591.13.2.23 -- Serpent-192-OFB + */ + ASN1ObjectIdentifier Serpent_192_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.23"); // Serpent-192-OFB + /** + * 1.3.6.1.4.1.11591.13.2.24 -- Serpent-192-CFB + */ + ASN1ObjectIdentifier Serpent_192_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.24"); // Serpent-192-CFB + /** + * 1.3.6.1.4.1.11591.13.2.41 -- Serpent-256-ECB + */ + ASN1ObjectIdentifier Serpent_256_ECB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.41"); // Serpent-256-ECB + /** + * 1.3.6.1.4.1.11591.13.2.42 -- Serpent-256-CBC + */ + ASN1ObjectIdentifier Serpent_256_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.42"); // Serpent-256-CBC + /** + * 1.3.6.1.4.1.11591.13.2.43 -- Serpent-256-OFB + */ + ASN1ObjectIdentifier Serpent_256_OFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.43"); // Serpent-256-OFB + /** + * 1.3.6.1.4.1.11591.13.2.44 -- Serpent-256-CFB + */ + ASN1ObjectIdentifier Serpent_256_CFB = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.13.2.44"); // Serpent-256-CFB - /** 1.3.6.1.4.1.11591.14 -- CRC algorithms */ - public static final ASN1ObjectIdentifier CRC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms - /** 1.3.6.1.4.1.11591.14,1 -- CRC32 */ - public static final ASN1ObjectIdentifier CRC32 = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32 + /** + * 1.3.6.1.4.1.11591.14 -- CRC algorithms + */ + ASN1ObjectIdentifier CRC = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.14"); // CRC algorithms + /** + * 1.3.6.1.4.1.11591.14,1 -- CRC32 + */ + ASN1ObjectIdentifier CRC32 = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.14.1"); // CRC 32 - /** 1.3.6.1.4.1.11591.15 - ellipticCurve */ - public static final ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.15"); + /** + * 1.3.6.1.4.1.11591.15 - ellipticCurve + */ + ASN1ObjectIdentifier ellipticCurve = new ASN1ObjectIdentifier("1.3.6.1.4.1.11591.15"); - public static final ASN1ObjectIdentifier Ed25519 = ellipticCurve.branch("1"); + ASN1ObjectIdentifier Ed25519 = ellipticCurve.branch("1"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/CscaMasterList.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/CscaMasterList.java index e935c1e42..fe753b2c4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/CscaMasterList.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/CscaMasterList.java @@ -76,7 +76,7 @@ public class CscaMasterList public int getVersion() { - return version.getValue().intValue(); + return version.intValueExact(); } public Certificate[] getCertStructs() @@ -98,16 +98,10 @@ public class CscaMasterList public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector seq = new ASN1EncodableVector(); + ASN1EncodableVector seq = new ASN1EncodableVector(2); seq.add(version); - - ASN1EncodableVector certSet = new ASN1EncodableVector(); - for (int i = 0; i < certList.length; i++) - { - certSet.add(certList[i]); - } - seq.add(new DERSet(certSet)); + seq.add(new DERSet(certList)); return new DERSequence(seq); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/DataGroupHash.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/DataGroupHash.java index 4e73dd92e..cafc89e6a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/DataGroupHash.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/DataGroupHash.java @@ -78,7 +78,7 @@ public class DataGroupHash public int getDataGroupNumber() { - return dataGroupNumber.getValue().intValue(); + return dataGroupNumber.intValueExact(); } public ASN1OctetString getDataGroupHashValue() @@ -88,7 +88,7 @@ public class DataGroupHash public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector seq = new ASN1EncodableVector(); + ASN1EncodableVector seq = new ASN1EncodableVector(2); seq.add(dataGroupNumber); seq.add(dataGroupHashValue); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/LDSSecurityObject.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/LDSSecurityObject.java index b4f3d3bee..c52984d73 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/LDSSecurityObject.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/LDSSecurityObject.java @@ -19,19 +19,18 @@ import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; * dataGroupHashValues SEQUENCE SIZE (2..ub-DataGroups) OF DataHashGroup, * ldsVersionInfo LDSVersionInfo OPTIONAL * -- if present, version MUST be v1 } - * + * * DigestAlgorithmIdentifier ::= AlgorithmIdentifier, - * + * * LDSSecurityObjectVersion :: INTEGER {V0(0)} * */ - -public class LDSSecurityObject +public class LDSSecurityObject extends ASN1Object - implements ICAOObjectIdentifiers + implements ICAOObjectIdentifiers { public static final int ub_DataGroups = 16; - + private ASN1Integer version = new ASN1Integer(0); private AlgorithmIdentifier digestAlgorithmIdentifier; private DataGroupHash[] datagroupHash; @@ -46,12 +45,12 @@ public class LDSSecurityObject } else if (obj != null) { - return new LDSSecurityObject(ASN1Sequence.getInstance(obj)); + return new LDSSecurityObject(ASN1Sequence.getInstance(obj)); } - + return null; - } - + } + private LDSSecurityObject( ASN1Sequence seq) { @@ -59,49 +58,49 @@ public class LDSSecurityObject { throw new IllegalArgumentException("null or empty sequence passed."); } - + Enumeration e = seq.getObjects(); // version version = ASN1Integer.getInstance(e.nextElement()); // digestAlgorithmIdentifier digestAlgorithmIdentifier = AlgorithmIdentifier.getInstance(e.nextElement()); - + ASN1Sequence datagroupHashSeq = ASN1Sequence.getInstance(e.nextElement()); - if (version.getValue().intValue() == 1) + if (version.intValueExact() == 1) { versionInfo = LDSVersionInfo.getInstance(e.nextElement()); } - checkDatagroupHashSeqSize(datagroupHashSeq.size()); - + checkDatagroupHashSeqSize(datagroupHashSeq.size()); + datagroupHash = new DataGroupHash[datagroupHashSeq.size()]; - for (int i= 0; i< datagroupHashSeq.size();i++) + for (int i = 0; i < datagroupHashSeq.size(); i++) { datagroupHash[i] = DataGroupHash.getInstance(datagroupHashSeq.getObjectAt(i)); } } public LDSSecurityObject( - AlgorithmIdentifier digestAlgorithmIdentifier, - DataGroupHash[] datagroupHash) + AlgorithmIdentifier digestAlgorithmIdentifier, + DataGroupHash[] datagroupHash) { this.version = new ASN1Integer(0); this.digestAlgorithmIdentifier = digestAlgorithmIdentifier; - this.datagroupHash = datagroupHash; - - checkDatagroupHashSeqSize(datagroupHash.length); - } + this.datagroupHash = copy(datagroupHash); + + checkDatagroupHashSeqSize(datagroupHash.length); + } public LDSSecurityObject( AlgorithmIdentifier digestAlgorithmIdentifier, - DataGroupHash[] datagroupHash, - LDSVersionInfo versionInfo) + DataGroupHash[] datagroupHash, + LDSVersionInfo versionInfo) { this.version = new ASN1Integer(1); this.digestAlgorithmIdentifier = digestAlgorithmIdentifier; - this.datagroupHash = datagroupHash; + this.datagroupHash = copy(datagroupHash); this.versionInfo = versionInfo; checkDatagroupHashSeqSize(datagroupHash.length); @@ -111,23 +110,23 @@ public class LDSSecurityObject { if ((size < 2) || (size > ub_DataGroups)) { - throw new IllegalArgumentException("wrong size in DataGroupHashValues : not in (2.."+ ub_DataGroups +")"); + throw new IllegalArgumentException("wrong size in DataGroupHashValues : not in (2.." + ub_DataGroups + ")"); } - } + } public int getVersion() { - return version.getValue().intValue(); + return version.intValueExact(); } public AlgorithmIdentifier getDigestAlgorithmIdentifier() { return digestAlgorithmIdentifier; } - + public DataGroupHash[] getDatagroupHash() { - return datagroupHash; + return copy(datagroupHash); } public LDSVersionInfo getVersionInfo() @@ -137,17 +136,11 @@ public class LDSSecurityObject public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector seq = new ASN1EncodableVector(); - + ASN1EncodableVector seq = new ASN1EncodableVector(4); + seq.add(version); seq.add(digestAlgorithmIdentifier); - - ASN1EncodableVector seqname = new ASN1EncodableVector(); - for (int i = 0; i < datagroupHash.length; i++) - { - seqname.add(datagroupHash[i]); - } - seq.add(new DERSequence(seqname)); + seq.add(new DERSequence(datagroupHash)); if (versionInfo != null) { @@ -156,4 +149,13 @@ public class LDSSecurityObject return new DERSequence(seq); } + + private DataGroupHash[] copy(DataGroupHash[] dgHash) + { + DataGroupHash[] rv = new DataGroupHash[dgHash.length]; + + System.arraycopy(dgHash, 0, rv, 0, rv.length); + + return rv; + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/LDSVersionInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/LDSVersionInfo.java index c3034369a..b905ed387 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/LDSVersionInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/icao/LDSVersionInfo.java @@ -65,7 +65,7 @@ public class LDSVersionInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(ldsVersion); v.add(unicodeVersion); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/ocsp/CertHash.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/ocsp/CertHash.java index 6eb8df433..0a8abc623 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/ocsp/CertHash.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/ocsp/CertHash.java @@ -7,6 +7,7 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.DEROctetString; import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.util.Arrays; /** * ISIS-MTT PROFILE: The responder may include this extension in a response to @@ -94,7 +95,7 @@ public class CertHash public byte[] getCertificateHash() { - return certificateHash; + return Arrays.clone(certificateHash); } /** @@ -112,7 +113,7 @@ public class CertHash */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector vec = new ASN1EncodableVector(); + ASN1EncodableVector vec = new ASN1EncodableVector(2); vec.add(hashAlgorithm); vec.add(new DEROctetString(certificateHash)); return new DERSequence(vec); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java index f3a3e09b4..65862fba0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/ocsp/RequestedCertificate.java @@ -11,6 +11,7 @@ import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; import com.fr.third.org.bouncycastle.asn1.DEROctetString; import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.util.Arrays; /** * ISIS-MTT-Optional: The certificate requested by the client by inserting the @@ -147,9 +148,9 @@ public class RequestedCertificate } if (publicKeyCert != null) { - return publicKeyCert; + return Arrays.clone(publicKeyCert); } - return attributeCert; + return Arrays.clone(attributeCert); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/AdmissionSyntax.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/AdmissionSyntax.java index 70d48fa9e..37d9e04d5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/AdmissionSyntax.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/AdmissionSyntax.java @@ -242,7 +242,7 @@ public class AdmissionSyntax */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector vec = new ASN1EncodableVector(); + ASN1EncodableVector vec = new ASN1EncodableVector(2); if (admissionAuthority != null) { vec.add(admissionAuthority); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/Admissions.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/Admissions.java index d60687afb..50f595fd0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/Admissions.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/Admissions.java @@ -167,7 +167,7 @@ public class Admissions */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector vec = new ASN1EncodableVector(); + ASN1EncodableVector vec = new ASN1EncodableVector(3); if (admissionAuthority != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java index 7edf11419..791b52724 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/DeclarationOfMajority.java @@ -60,7 +60,7 @@ public class DeclarationOfMajority } else { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(ASN1Boolean.FALSE); v.add(new DERPrintableString(country, true)); @@ -138,7 +138,7 @@ public class DeclarationOfMajority return -1; } - return ASN1Integer.getInstance(declaration, false).getValue().intValue(); + return ASN1Integer.getInstance(declaration, false).intValueExact(); } public ASN1Sequence fullAgeAtCountry() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java index f101046b9..d8cbdd365 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/MonetaryLimit.java @@ -117,7 +117,7 @@ public class MonetaryLimit */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector seq = new ASN1EncodableVector(); + ASN1EncodableVector seq = new ASN1EncodableVector(3); seq.add(currency); seq.add(amount); seq.add(exponent); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java index 26588bec0..7d4f1274b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/NamingAuthority.java @@ -204,7 +204,7 @@ public class NamingAuthority */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector vec = new ASN1EncodableVector(); + ASN1EncodableVector vec = new ASN1EncodableVector(3); if (namingAuthorityId != null) { vec.add(namingAuthorityId); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java index 42b14ac88..81b8b2a67 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/ProcurationSyntax.java @@ -213,7 +213,7 @@ public class ProcurationSyntax */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector vec = new ASN1EncodableVector(); + ASN1EncodableVector vec = new ASN1EncodableVector(3); if (country != null) { vec.add(new DERTaggedObject(true, 1, new DERPrintableString(country, true))); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java index db55df122..0548f3b3e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/isismtt/x509/ProfessionInfo.java @@ -288,20 +288,10 @@ public class ProfessionInfo String registrationNumber, ASN1OctetString addProfessionInfo) { this.namingAuthority = namingAuthority; - ASN1EncodableVector v = new ASN1EncodableVector(); - for (int i = 0; i != professionItems.length; i++) - { - v.add(professionItems[i]); - } - this.professionItems = new DERSequence(v); + this.professionItems = new DERSequence(professionItems); if (professionOIDs != null) { - v = new ASN1EncodableVector(); - for (int i = 0; i != professionOIDs.length; i++) - { - v.add(professionOIDs[i]); - } - this.professionOIDs = new DERSequence(v); + this.professionOIDs = new DERSequence(professionOIDs); } this.registrationNumber = registrationNumber; this.addProfessionInfo = addProfessionInfo; @@ -326,7 +316,7 @@ public class ProfessionInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector vec = new ASN1EncodableVector(); + ASN1EncodableVector vec = new ASN1EncodableVector(5); if (namingAuthority != null) { vec.add(new DERTaggedObject(true, 0, namingAuthority)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/CAST5CBCParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/CAST5CBCParameters.java index 9b5290e9f..8118db663 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/CAST5CBCParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/CAST5CBCParameters.java @@ -39,7 +39,7 @@ public class CAST5CBCParameters this.keyLength = new ASN1Integer(keyLength); } - public CAST5CBCParameters( + private CAST5CBCParameters( ASN1Sequence seq) { iv = (ASN1OctetString)seq.getObjectAt(0); @@ -53,7 +53,7 @@ public class CAST5CBCParameters public int getKeyLength() { - return keyLength.getValue().intValue(); + return keyLength.intValueExact(); } /** @@ -69,7 +69,7 @@ public class CAST5CBCParameters */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(iv); v.add(keyLength); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/IDEACBCPar.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/IDEACBCPar.java index 2f4201a77..a54474b25 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/IDEACBCPar.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/IDEACBCPar.java @@ -35,7 +35,7 @@ public class IDEACBCPar this.iv = new DEROctetString(iv); } - public IDEACBCPar( + private IDEACBCPar( ASN1Sequence seq) { if (seq.size() == 1) @@ -70,7 +70,7 @@ public class IDEACBCPar */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(1); if (iv != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java index c740ff1b0..3eb4814f6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/MiscObjectIdentifiers.java @@ -8,64 +8,98 @@ public interface MiscObjectIdentifiers // Netscape // iso/itu(2) joint-assign(16) us(840) uscompany(1) netscape(113730) cert-extensions(1) } // - /** Netscape cert extensions OID base: 2.16.840.1.113730.1 */ - static final ASN1ObjectIdentifier netscape = new ASN1ObjectIdentifier("2.16.840.1.113730.1"); - /** Netscape cert CertType OID: 2.16.840.1.113730.1.1 */ - static final ASN1ObjectIdentifier netscapeCertType = netscape.branch("1"); - /** Netscape cert BaseURL OID: 2.16.840.1.113730.1.2 */ - static final ASN1ObjectIdentifier netscapeBaseURL = netscape.branch("2"); - /** Netscape cert RevocationURL OID: 2.16.840.1.113730.1.3 */ - static final ASN1ObjectIdentifier netscapeRevocationURL = netscape.branch("3"); - /** Netscape cert CARevocationURL OID: 2.16.840.1.113730.1.4 */ - static final ASN1ObjectIdentifier netscapeCARevocationURL = netscape.branch("4"); - /** Netscape cert RenewalURL OID: 2.16.840.1.113730.1.7 */ - static final ASN1ObjectIdentifier netscapeRenewalURL = netscape.branch("7"); - /** Netscape cert CApolicyURL OID: 2.16.840.1.113730.1.8 */ - static final ASN1ObjectIdentifier netscapeCApolicyURL = netscape.branch("8"); - /** Netscape cert SSLServerName OID: 2.16.840.1.113730.1.12 */ - static final ASN1ObjectIdentifier netscapeSSLServerName = netscape.branch("12"); - /** Netscape cert CertComment OID: 2.16.840.1.113730.1.13 */ - static final ASN1ObjectIdentifier netscapeCertComment = netscape.branch("13"); - + /** + * Netscape cert extensions OID base: 2.16.840.1.113730.1 + */ + ASN1ObjectIdentifier netscape = new ASN1ObjectIdentifier("2.16.840.1.113730.1"); + /** + * Netscape cert CertType OID: 2.16.840.1.113730.1.1 + */ + ASN1ObjectIdentifier netscapeCertType = netscape.branch("1"); + /** + * Netscape cert BaseURL OID: 2.16.840.1.113730.1.2 + */ + ASN1ObjectIdentifier netscapeBaseURL = netscape.branch("2"); + /** + * Netscape cert RevocationURL OID: 2.16.840.1.113730.1.3 + */ + ASN1ObjectIdentifier netscapeRevocationURL = netscape.branch("3"); + /** + * Netscape cert CARevocationURL OID: 2.16.840.1.113730.1.4 + */ + ASN1ObjectIdentifier netscapeCARevocationURL = netscape.branch("4"); + /** + * Netscape cert RenewalURL OID: 2.16.840.1.113730.1.7 + */ + ASN1ObjectIdentifier netscapeRenewalURL = netscape.branch("7"); + /** + * Netscape cert CApolicyURL OID: 2.16.840.1.113730.1.8 + */ + ASN1ObjectIdentifier netscapeCApolicyURL = netscape.branch("8"); + /** + * Netscape cert SSLServerName OID: 2.16.840.1.113730.1.12 + */ + ASN1ObjectIdentifier netscapeSSLServerName = netscape.branch("12"); + /** + * Netscape cert CertComment OID: 2.16.840.1.113730.1.13 + */ + ASN1ObjectIdentifier netscapeCertComment = netscape.branch("13"); + // // Verisign // iso/itu(2) joint-assign(16) us(840) uscompany(1) verisign(113733) cert-extensions(1) } // - /** Verisign OID base: 2.16.840.1.113733.1 */ - static final ASN1ObjectIdentifier verisign = new ASN1ObjectIdentifier("2.16.840.1.113733.1"); + /** + * Verisign OID base: 2.16.840.1.113733.1 + */ + ASN1ObjectIdentifier verisign = new ASN1ObjectIdentifier("2.16.840.1.113733.1"); - /** Verisign CZAG (Country,Zip,Age,Gender) Extension OID: 2.16.840.1.113733.1.6.3 */ - static final ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3"); + /** + * Verisign CZAG (Country,Zip,Age,Gender) Extension OID: 2.16.840.1.113733.1.6.3 + */ + ASN1ObjectIdentifier verisignCzagExtension = verisign.branch("6.3"); - static final ASN1ObjectIdentifier verisignPrivate_6_9 = verisign.branch("6.9"); - static final ASN1ObjectIdentifier verisignOnSiteJurisdictionHash = verisign.branch("6.11"); - static final ASN1ObjectIdentifier verisignBitString_6_13 = verisign.branch("6.13"); + ASN1ObjectIdentifier verisignPrivate_6_9 = verisign.branch("6.9"); + ASN1ObjectIdentifier verisignOnSiteJurisdictionHash = verisign.branch("6.11"); + ASN1ObjectIdentifier verisignBitString_6_13 = verisign.branch("6.13"); - /** Verisign D&B D-U-N-S number Extension OID: 2.16.840.1.113733.1.6.15 */ - static final ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15"); + /** + * Verisign D&B D-U-N-S number Extension OID: 2.16.840.1.113733.1.6.15 + */ + ASN1ObjectIdentifier verisignDnbDunsNumber = verisign.branch("6.15"); - static final ASN1ObjectIdentifier verisignIssStrongCrypto = verisign.branch("8.1"); + ASN1ObjectIdentifier verisignIssStrongCrypto = verisign.branch("8.1"); // // Novell // iso/itu(2) country(16) us(840) organization(1) novell(113719) // - /** Novell OID base: 2.16.840.1.113719 */ - static final ASN1ObjectIdentifier novell = new ASN1ObjectIdentifier("2.16.840.1.113719"); - /** Novell SecurityAttribs OID: 2.16.840.1.113719.1.9.4.1 */ - static final ASN1ObjectIdentifier novellSecurityAttribs = novell.branch("1.9.4.1"); + /** + * Novell OID base: 2.16.840.1.113719 + */ + ASN1ObjectIdentifier novell = new ASN1ObjectIdentifier("2.16.840.1.113719"); + /** + * Novell SecurityAttribs OID: 2.16.840.1.113719.1.9.4.1 + */ + ASN1ObjectIdentifier novellSecurityAttribs = novell.branch("1.9.4.1"); // // Entrust // iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7) // - /** NortelNetworks Entrust OID base: 1.2.840.113533.7 */ - static final ASN1ObjectIdentifier entrust = new ASN1ObjectIdentifier("1.2.840.113533.7"); - /** NortelNetworks Entrust VersionExtension OID: 1.2.840.113533.7.65.0 */ - static final ASN1ObjectIdentifier entrustVersionExtension = entrust.branch("65.0"); - - /** cast5CBC OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) nt(113533) nsn(7) algorithms(66) 10} SEE RFC 2984 */ - ASN1ObjectIdentifier cast5CBC = entrust.branch("66.10"); + /** + * NortelNetworks Entrust OID base: 1.2.840.113533.7 + */ + ASN1ObjectIdentifier entrust = new ASN1ObjectIdentifier("1.2.840.113533.7"); + /** + * NortelNetworks Entrust VersionExtension OID: 1.2.840.113533.7.65.0 + */ + ASN1ObjectIdentifier entrustVersionExtension = entrust.branch("65.0"); + + /** + * cast5CBC OBJECT IDENTIFIER ::= {iso(1) member-body(2) us(840) nt(113533) nsn(7) algorithms(66) 10} SEE RFC 2984 + */ + ASN1ObjectIdentifier cast5CBC = entrust.branch("66.10"); // // Ascom diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/ScryptParams.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/ScryptParams.java index ed1a25ba0..d9110f49e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/ScryptParams.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/misc/ScryptParams.java @@ -131,7 +131,7 @@ public class ScryptParams public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); v.add(new DEROctetString(salt)); v.add(new ASN1Integer(costParameter)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/mozilla/SignedPublicKeyAndChallenge.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/mozilla/SignedPublicKeyAndChallenge.java index ae65de9cd..f5625d084 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/mozilla/SignedPublicKeyAndChallenge.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/mozilla/SignedPublicKeyAndChallenge.java @@ -7,7 +7,7 @@ import com.fr.third.org.bouncycastle.asn1.DERBitString; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; /** - *

+ * 
  *  SignedPublicKeyAndChallenge ::= SEQUENCE {
  *    publicKeyAndChallenge PublicKeyAndChallenge,
  *    signatureAlgorithm AlgorithmIdentifier,
@@ -20,7 +20,7 @@ public class SignedPublicKeyAndChallenge
     extends ASN1Object
 {
     private final PublicKeyAndChallenge pubKeyAndChal;
-    private final ASN1Sequence          pkacSeq;
+    private final ASN1Sequence pkacSeq;
 
     public static SignedPublicKeyAndChallenge getInstance(Object obj)
     {
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java
index 218498c25..8d1dd817b 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/nsri/NSRIObjectIdentifiers.java
@@ -4,55 +4,55 @@ import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
 
 public interface NSRIObjectIdentifiers
 {
-    static final ASN1ObjectIdentifier   nsri                = new ASN1ObjectIdentifier("1.2.410.200046");
+    ASN1ObjectIdentifier nsri = new ASN1ObjectIdentifier("1.2.410.200046");
 
-    static final ASN1ObjectIdentifier   id_algorithm        = nsri.branch("1");
+    ASN1ObjectIdentifier id_algorithm = nsri.branch("1");
 
-    static final ASN1ObjectIdentifier   id_sea              = id_algorithm.branch("1");
-    static final ASN1ObjectIdentifier   id_pad              = id_algorithm.branch("2");
+    ASN1ObjectIdentifier id_sea = id_algorithm.branch("1");
+    ASN1ObjectIdentifier id_pad = id_algorithm.branch("2");
 
-    static final ASN1ObjectIdentifier   id_pad_null         = id_algorithm.branch("0");
-    static final ASN1ObjectIdentifier   id_pad_1            = id_algorithm.branch("1");
+    ASN1ObjectIdentifier id_pad_null = id_algorithm.branch("0");
+    ASN1ObjectIdentifier id_pad_1 = id_algorithm.branch("1");
 
-    static final ASN1ObjectIdentifier   id_aria128_ecb      = id_sea.branch("1");
-    static final ASN1ObjectIdentifier   id_aria128_cbc      = id_sea.branch("2");
-    static final ASN1ObjectIdentifier   id_aria128_cfb      = id_sea.branch("3");
-    static final ASN1ObjectIdentifier   id_aria128_ofb      = id_sea.branch("4");
-    static final ASN1ObjectIdentifier   id_aria128_ctr      = id_sea.branch("5");
+    ASN1ObjectIdentifier id_aria128_ecb = id_sea.branch("1");
+    ASN1ObjectIdentifier id_aria128_cbc = id_sea.branch("2");
+    ASN1ObjectIdentifier id_aria128_cfb = id_sea.branch("3");
+    ASN1ObjectIdentifier id_aria128_ofb = id_sea.branch("4");
+    ASN1ObjectIdentifier id_aria128_ctr = id_sea.branch("5");
 
-    static final ASN1ObjectIdentifier   id_aria192_ecb      = id_sea.branch("6");
-    static final ASN1ObjectIdentifier   id_aria192_cbc      = id_sea.branch("7");
-    static final ASN1ObjectIdentifier   id_aria192_cfb      = id_sea.branch("8");
-    static final ASN1ObjectIdentifier   id_aria192_ofb      = id_sea.branch("9");
-    static final ASN1ObjectIdentifier   id_aria192_ctr      = id_sea.branch("10");
+    ASN1ObjectIdentifier id_aria192_ecb = id_sea.branch("6");
+    ASN1ObjectIdentifier id_aria192_cbc = id_sea.branch("7");
+    ASN1ObjectIdentifier id_aria192_cfb = id_sea.branch("8");
+    ASN1ObjectIdentifier id_aria192_ofb = id_sea.branch("9");
+    ASN1ObjectIdentifier id_aria192_ctr = id_sea.branch("10");
 
-    static final ASN1ObjectIdentifier   id_aria256_ecb      = id_sea.branch("11");
-    static final ASN1ObjectIdentifier   id_aria256_cbc      = id_sea.branch("12");
-    static final ASN1ObjectIdentifier   id_aria256_cfb      = id_sea.branch("13");
-    static final ASN1ObjectIdentifier   id_aria256_ofb      = id_sea.branch("14");
-    static final ASN1ObjectIdentifier   id_aria256_ctr      = id_sea.branch("15");
+    ASN1ObjectIdentifier id_aria256_ecb = id_sea.branch("11");
+    ASN1ObjectIdentifier id_aria256_cbc = id_sea.branch("12");
+    ASN1ObjectIdentifier id_aria256_cfb = id_sea.branch("13");
+    ASN1ObjectIdentifier id_aria256_ofb = id_sea.branch("14");
+    ASN1ObjectIdentifier id_aria256_ctr = id_sea.branch("15");
 
-    static final ASN1ObjectIdentifier   id_aria128_cmac     = id_sea.branch("21");
-    static final ASN1ObjectIdentifier   id_aria192_cmac     = id_sea.branch("22");
-    static final ASN1ObjectIdentifier   id_aria256_cmac     = id_sea.branch("23");
+    ASN1ObjectIdentifier id_aria128_cmac = id_sea.branch("21");
+    ASN1ObjectIdentifier id_aria192_cmac = id_sea.branch("22");
+    ASN1ObjectIdentifier id_aria256_cmac = id_sea.branch("23");
 
-    static final ASN1ObjectIdentifier   id_aria128_ocb2     = id_sea.branch("31");
-    static final ASN1ObjectIdentifier   id_aria192_ocb2     = id_sea.branch("32");
-    static final ASN1ObjectIdentifier   id_aria256_ocb2     = id_sea.branch("33");
+    ASN1ObjectIdentifier id_aria128_ocb2 = id_sea.branch("31");
+    ASN1ObjectIdentifier id_aria192_ocb2 = id_sea.branch("32");
+    ASN1ObjectIdentifier id_aria256_ocb2 = id_sea.branch("33");
 
-    static final ASN1ObjectIdentifier   id_aria128_gcm      = id_sea.branch("34");
-    static final ASN1ObjectIdentifier   id_aria192_gcm      = id_sea.branch("35");
-    static final ASN1ObjectIdentifier   id_aria256_gcm      = id_sea.branch("36");
+    ASN1ObjectIdentifier id_aria128_gcm = id_sea.branch("34");
+    ASN1ObjectIdentifier id_aria192_gcm = id_sea.branch("35");
+    ASN1ObjectIdentifier id_aria256_gcm = id_sea.branch("36");
 
-    static final ASN1ObjectIdentifier   id_aria128_ccm      = id_sea.branch("37");
-    static final ASN1ObjectIdentifier   id_aria192_ccm      = id_sea.branch("38");
-    static final ASN1ObjectIdentifier   id_aria256_ccm      = id_sea.branch("39");
+    ASN1ObjectIdentifier id_aria128_ccm = id_sea.branch("37");
+    ASN1ObjectIdentifier id_aria192_ccm = id_sea.branch("38");
+    ASN1ObjectIdentifier id_aria256_ccm = id_sea.branch("39");
 
-    static final ASN1ObjectIdentifier   id_aria128_kw       = id_sea.branch("40");
-    static final ASN1ObjectIdentifier   id_aria192_kw       = id_sea.branch("41");
-    static final ASN1ObjectIdentifier   id_aria256_kw       = id_sea.branch("42");
+    ASN1ObjectIdentifier id_aria128_kw = id_sea.branch("40");
+    ASN1ObjectIdentifier id_aria192_kw = id_sea.branch("41");
+    ASN1ObjectIdentifier id_aria256_kw = id_sea.branch("42");
 
-    static final ASN1ObjectIdentifier   id_aria128_kwp      = id_sea.branch("43");
-    static final ASN1ObjectIdentifier   id_aria192_kwp      = id_sea.branch("44");
-    static final ASN1ObjectIdentifier   id_aria256_kwp      = id_sea.branch("45");
+    ASN1ObjectIdentifier id_aria128_kwp = id_sea.branch("43");
+    ASN1ObjectIdentifier id_aria192_kwp = id_sea.branch("44");
+    ASN1ObjectIdentifier id_aria256_kwp = id_sea.branch("45");
 }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java
index 196ffbad3..177b4c5a8 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/BasicOCSPResponse.java
@@ -10,6 +10,16 @@ import com.fr.third.org.bouncycastle.asn1.DERSequence;
 import com.fr.third.org.bouncycastle.asn1.DERTaggedObject;
 import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
 
+/**
+ * OCSP RFC 2560, RFC 6960
+ * 
+ * BasicOCSPResponse       ::= SEQUENCE {
+ *    tbsResponseData      ResponseData,
+ *    signatureAlgorithm   AlgorithmIdentifier,
+ *    signature            BIT STRING,
+ *    certs                [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
+ * 
+ */ public class BasicOCSPResponse extends ASN1Object { @@ -97,7 +107,7 @@ public class BasicOCSPResponse */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(tbsResponseData); v.add(signatureAlgorithm); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CertID.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CertID.java index 955569434..a90cbcbfe 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CertID.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CertID.java @@ -93,7 +93,7 @@ public class CertID */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(hashAlgorithm); v.add(issuerNameHash); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CertStatus.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CertStatus.java index bfe9b4df2..7ced79eb7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CertStatus.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CertStatus.java @@ -13,7 +13,7 @@ public class CertStatus implements ASN1Choice { private int tagNo; - private ASN1Encodable value; + private ASN1Encodable value; /** * create a CertStatus object with a tag of zero. diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CrlID.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CrlID.java index f78e323cf..feeaf7df9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CrlID.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/CrlID.java @@ -88,7 +88,7 @@ public class CrlID */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (crlUrl != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPRequest.java index 87e9f7194..32e9211ff 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPRequest.java @@ -76,7 +76,7 @@ public class OCSPRequest */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(tbsRequest); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPResponse.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPResponse.java index 2d1b6ec92..33c484eda 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPResponse.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPResponse.java @@ -8,6 +8,17 @@ import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +/** + * OCSP RFC 2560, RFC 6960 + *
+ * OCSPResponse ::= SEQUENCE {
+ *     responseStatus         OCSPResponseStatus,
+ *     responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
+ * 
+ * @see OCSPResponseStatus + * @see ResponseBytes + */ + public class OCSPResponse extends ASN1Object { @@ -76,7 +87,7 @@ public class OCSPResponse */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(responseStatus); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java index 9135668b5..3960e603c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/OCSPResponseStatus.java @@ -6,6 +6,23 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Enumerated; import com.fr.third.org.bouncycastle.asn1.ASN1Object; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; + +/** + * OCSP RFC 2560, RFC 6960 + *

+ * The OCSPResponseStatus enumeration. + *

+ * OCSPResponseStatus ::= ENUMERATED {
+ *     successful            (0),  --Response has valid confirmations
+ *     malformedRequest      (1),  --Illegal confirmation request
+ *     internalError         (2),  --Internal error in issuer
+ *     tryLater              (3),  --Try again later
+ *                                 --(4) is not used
+ *     sigRequired           (5),  --Must sign the request
+ *     unauthorized          (6)   --Request unauthorized
+ * }
+ * 
+ */ public class OCSPResponseStatus extends ASN1Object { @@ -19,6 +36,8 @@ public class OCSPResponseStatus private ASN1Enumerated value; /** + * RFC 2560, RFC 6960 + *

* The OCSPResponseStatus enumeration. *

      * OCSPResponseStatus ::= ENUMERATED {
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/Request.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/Request.java
index e8b55e05d..064c0b750 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/Request.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/Request.java
@@ -77,7 +77,7 @@ public class Request
      */
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector    v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(2);
 
         v.add(reqCert);
 
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ResponseBytes.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ResponseBytes.java
index abb621300..48cafa6b5 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ResponseBytes.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ResponseBytes.java
@@ -9,6 +9,14 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Sequence;
 import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject;
 import com.fr.third.org.bouncycastle.asn1.DERSequence;
 
+/**
+ * OCSP RFC 2560, RFC 6960
+ * 
+ * ResponseBytes ::=       SEQUENCE {
+ *     responseType   OBJECT IDENTIFIER,
+ *     response       OCTET STRING }
+ * 
+ */ public class ResponseBytes extends ASN1Object { @@ -75,7 +83,7 @@ public class ResponseBytes */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(responseType); v.add(response); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ResponseData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ResponseData.java index aba66af12..6ea75c270 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ResponseData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ResponseData.java @@ -12,6 +12,17 @@ import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; import com.fr.third.org.bouncycastle.asn1.x509.Extensions; import com.fr.third.org.bouncycastle.asn1.x509.X509Extensions; +/** + * OCSP RFC 2560, RFC 6960 + *
+ * ResponseData ::= SEQUENCE {
+ *     version              [0] EXPLICIT Version DEFAULT v1,
+ *     responderID              ResponderID,
+ *     producedAt               GeneralizedTime,
+ *     responses                SEQUENCE OF SingleResponse,
+ *     responseExtensions   [1] EXPLICIT Extensions OPTIONAL }
+ * 
+ */ public class ResponseData extends ASN1Object { @@ -161,7 +172,7 @@ public class ResponseData */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); if (versionPresent || !version.equals(V1)) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/RevokedInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/RevokedInfo.java index c63eaaacd..58a7c7446 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/RevokedInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/RevokedInfo.java @@ -79,7 +79,7 @@ public class RevokedInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(revocationTime); if (revocationReason != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ServiceLocator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ServiceLocator.java index cacf4986c..732affa69 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ServiceLocator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/ServiceLocator.java @@ -63,7 +63,7 @@ public class ServiceLocator */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(issuer); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/Signature.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/Signature.java index d0c3283f5..78850ce47 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/Signature.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/Signature.java @@ -96,7 +96,7 @@ public class Signature */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(signatureAlgorithm); v.add(signature); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/SingleResponse.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/SingleResponse.java index 118606109..cf19789c5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/SingleResponse.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/SingleResponse.java @@ -141,7 +141,7 @@ public class SingleResponse */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); v.add(certID); v.add(certStatus); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/TBSRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/TBSRequest.java index a9a115781..d3656f7f3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/TBSRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ocsp/TBSRequest.java @@ -144,7 +144,7 @@ public class TBSRequest */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); // // if default don't include - unless explicitly provided. Not strictly correct diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/oiw/ElGamalParameter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/oiw/ElGamalParameter.java index 913dc546d..29adc6e5f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/oiw/ElGamalParameter.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/oiw/ElGamalParameter.java @@ -58,7 +58,7 @@ public class ElGamalParameter public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(p); v.add(g); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/Attribute.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/Attribute.java index c105a2586..a9c9842a1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/Attribute.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/Attribute.java @@ -78,7 +78,7 @@ public class Attribute */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(attrType); v.add(attrValues); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java index 5518f3ee2..0695b5fe7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/AuthenticatedSafe.java @@ -45,30 +45,32 @@ public class AuthenticatedSafe public AuthenticatedSafe( ContentInfo[] info) { - this.info = info; + this.info = copy(info); } public ContentInfo[] getContentInfo() { - return info; + return copy(info); } - public ASN1Primitive toASN1Primitive() + private ContentInfo[] copy(ContentInfo[] infos) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ContentInfo[] tmp = new ContentInfo[infos.length]; - for (int i = 0; i != info.length; i++) - { - v.add(info[i]); - } + System.arraycopy(infos, 0, tmp, 0, tmp.length); + return tmp; + } + + public ASN1Primitive toASN1Primitive() + { if (isBer) { - return new BERSequence(v); + return new BERSequence(info); } else { - return new DLSequence(v); + return new DLSequence(info); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CRLBag.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CRLBag.java index 7f19025d0..d52168fdf 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CRLBag.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CRLBag.java @@ -76,7 +76,7 @@ public class CRLBag */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(crlId); v.add(new DERTaggedObject(0, crlValue)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertBag.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertBag.java index b1a353217..f633a247c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertBag.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertBag.java @@ -6,6 +6,7 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Object; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; @@ -19,7 +20,7 @@ public class CertBag ASN1Sequence seq) { this.certId = (ASN1ObjectIdentifier)seq.getObjectAt(0); - this.certValue = ((DERTaggedObject)seq.getObjectAt(1)).getObject(); + this.certValue = ASN1TaggedObject.getInstance(seq.getObjectAt(1)).getObject(); } public static CertBag getInstance(Object o) @@ -56,7 +57,7 @@ public class CertBag public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(certId); v.add(new DERTaggedObject(0, certValue)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertificationRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertificationRequest.java index 91a782fb7..f40861952 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertificationRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertificationRequest.java @@ -83,7 +83,7 @@ public class CertificationRequest public ASN1Primitive toASN1Primitive() { // Construct the CertificateRequest - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(reqInfo); v.add(sigAlgId); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java index ff4f8aca2..0355718f6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/CertificationRequestInfo.java @@ -148,7 +148,7 @@ public class CertificationRequestInfo public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(version); v.add(subject); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/ContentInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/ContentInfo.java index 2e79b09c6..98c2bc473 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/ContentInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/ContentInfo.java @@ -81,7 +81,7 @@ public class ContentInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(contentType); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/DHParameter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/DHParameter.java index 0200532c2..3f10e9b5c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/DHParameter.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/DHParameter.java @@ -89,7 +89,7 @@ public class DHParameter public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(p); v.add(g); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptedData.java index ed9a835f4..7cde40aaa 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptedData.java @@ -35,8 +35,6 @@ public class EncryptedData extends ASN1Object { ASN1Sequence data; - ASN1ObjectIdentifier bagId; - ASN1Primitive bagValue; public static EncryptedData getInstance( Object obj) @@ -57,7 +55,7 @@ public class EncryptedData private EncryptedData( ASN1Sequence seq) { - int version = ((ASN1Integer)seq.getObjectAt(0)).getValue().intValue(); + int version = ((ASN1Integer)seq.getObjectAt(0)).intValueExact(); if (version != 0) { @@ -72,7 +70,7 @@ public class EncryptedData AlgorithmIdentifier encryptionAlgorithm, ASN1Encodable content) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(contentType); v.add(encryptionAlgorithm.toASN1Primitive()); @@ -105,7 +103,7 @@ public class EncryptedData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(new ASN1Integer(0)); v.add(data); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java index dc90238b5..4a6dd5155 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptedPrivateKeyInfo.java @@ -76,7 +76,7 @@ public class EncryptedPrivateKeyInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(algId); v.add(data); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptionScheme.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptionScheme.java index 991ef63af..4648c0350 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptionScheme.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/EncryptionScheme.java @@ -12,6 +12,12 @@ public class EncryptionScheme { private AlgorithmIdentifier algId; + public EncryptionScheme( + ASN1ObjectIdentifier objectId) + { + this.algId = new AlgorithmIdentifier(objectId); + } + public EncryptionScheme( ASN1ObjectIdentifier objectId, ASN1Encodable parameters) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java index c77f47db8..eba3683c5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/IssuerAndSerialNumber.java @@ -75,7 +75,7 @@ public class IssuerAndSerialNumber public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(name); v.add(certSerialNumber); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/MacData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/MacData.java index 101a48137..f1df807c5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/MacData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/MacData.java @@ -42,11 +42,11 @@ public class MacData { this.digInfo = DigestInfo.getInstance(seq.getObjectAt(0)); - this.salt = Arrays.clone(((ASN1OctetString)seq.getObjectAt(1)).getOctets()); + this.salt = Arrays.clone(ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets()); if (seq.size() == 3) { - this.iterationCount = ((ASN1Integer)seq.getObjectAt(2)).getValue(); + this.iterationCount = ASN1Integer.getInstance(seq.getObjectAt(2)).getValue(); } else { @@ -92,7 +92,7 @@ public class MacData */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(digInfo); v.add(new DEROctetString(salt)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBEParameter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBEParameter.java index b06e12faf..5ce6dc734 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBEParameter.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBEParameter.java @@ -63,7 +63,7 @@ public class PBEParameter public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(salt); v.add(iterations); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBES2Parameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBES2Parameters.java index b701db260..55504c18f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBES2Parameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBES2Parameters.java @@ -67,7 +67,7 @@ public class PBES2Parameters public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(func); v.add(scheme); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBKDF2Params.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBKDF2Params.java index 2f069c562..56c5faed2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBKDF2Params.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PBKDF2Params.java @@ -243,7 +243,7 @@ public class PBKDF2Params */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(octStr); v.add(iterationCount); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java index b586707e6..15aae0e5b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PKCS12PBEParams.java @@ -59,7 +59,7 @@ public class PKCS12PBEParams public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(iv); v.add(iterations); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java index 4d972b39e..15a0f518f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PKCSObjectIdentifiers.java @@ -10,198 +10,198 @@ import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; public interface PKCSObjectIdentifiers { /** PKCS#1: 1.2.840.113549.1.1 */ - static final ASN1ObjectIdentifier pkcs_1 = new ASN1ObjectIdentifier("1.2.840.113549.1.1"); + ASN1ObjectIdentifier pkcs_1 = new ASN1ObjectIdentifier("1.2.840.113549.1.1"); /** PKCS#1: 1.2.840.113549.1.1.1 */ - static final ASN1ObjectIdentifier rsaEncryption = pkcs_1.branch("1"); + ASN1ObjectIdentifier rsaEncryption = pkcs_1.branch("1"); /** PKCS#1: 1.2.840.113549.1.1.2 */ - static final ASN1ObjectIdentifier md2WithRSAEncryption = pkcs_1.branch("2"); + ASN1ObjectIdentifier md2WithRSAEncryption = pkcs_1.branch("2"); /** PKCS#1: 1.2.840.113549.1.1.3 */ - static final ASN1ObjectIdentifier md4WithRSAEncryption = pkcs_1.branch("3"); + ASN1ObjectIdentifier md4WithRSAEncryption = pkcs_1.branch("3"); /** PKCS#1: 1.2.840.113549.1.1.4 */ - static final ASN1ObjectIdentifier md5WithRSAEncryption = pkcs_1.branch("4"); + ASN1ObjectIdentifier md5WithRSAEncryption = pkcs_1.branch("4"); /** PKCS#1: 1.2.840.113549.1.1.5 */ - static final ASN1ObjectIdentifier sha1WithRSAEncryption = pkcs_1.branch("5"); + ASN1ObjectIdentifier sha1WithRSAEncryption = pkcs_1.branch("5"); /** PKCS#1: 1.2.840.113549.1.1.6 */ - static final ASN1ObjectIdentifier srsaOAEPEncryptionSET = pkcs_1.branch("6"); + ASN1ObjectIdentifier srsaOAEPEncryptionSET = pkcs_1.branch("6"); /** PKCS#1: 1.2.840.113549.1.1.7 */ - static final ASN1ObjectIdentifier id_RSAES_OAEP = pkcs_1.branch("7"); + ASN1ObjectIdentifier id_RSAES_OAEP = pkcs_1.branch("7"); /** PKCS#1: 1.2.840.113549.1.1.8 */ - static final ASN1ObjectIdentifier id_mgf1 = pkcs_1.branch("8"); + ASN1ObjectIdentifier id_mgf1 = pkcs_1.branch("8"); /** PKCS#1: 1.2.840.113549.1.1.9 */ - static final ASN1ObjectIdentifier id_pSpecified = pkcs_1.branch("9"); + ASN1ObjectIdentifier id_pSpecified = pkcs_1.branch("9"); /** PKCS#1: 1.2.840.113549.1.1.10 */ - static final ASN1ObjectIdentifier id_RSASSA_PSS = pkcs_1.branch("10"); + ASN1ObjectIdentifier id_RSASSA_PSS = pkcs_1.branch("10"); /** PKCS#1: 1.2.840.113549.1.1.11 */ - static final ASN1ObjectIdentifier sha256WithRSAEncryption = pkcs_1.branch("11"); + ASN1ObjectIdentifier sha256WithRSAEncryption = pkcs_1.branch("11"); /** PKCS#1: 1.2.840.113549.1.1.12 */ - static final ASN1ObjectIdentifier sha384WithRSAEncryption = pkcs_1.branch("12"); + ASN1ObjectIdentifier sha384WithRSAEncryption = pkcs_1.branch("12"); /** PKCS#1: 1.2.840.113549.1.1.13 */ - static final ASN1ObjectIdentifier sha512WithRSAEncryption = pkcs_1.branch("13"); + ASN1ObjectIdentifier sha512WithRSAEncryption = pkcs_1.branch("13"); /** PKCS#1: 1.2.840.113549.1.1.14 */ - static final ASN1ObjectIdentifier sha224WithRSAEncryption = pkcs_1.branch("14"); + ASN1ObjectIdentifier sha224WithRSAEncryption = pkcs_1.branch("14"); /** PKCS#1: 1.2.840.113549.1.1.15 */ - static final ASN1ObjectIdentifier sha512_224WithRSAEncryption = pkcs_1.branch("15"); + ASN1ObjectIdentifier sha512_224WithRSAEncryption = pkcs_1.branch("15"); /** PKCS#1: 1.2.840.113549.1.1.16 */ - static final ASN1ObjectIdentifier sha512_256WithRSAEncryption = pkcs_1.branch("16"); + ASN1ObjectIdentifier sha512_256WithRSAEncryption = pkcs_1.branch("16"); // // pkcs-3 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 3 } // /** PKCS#3: 1.2.840.113549.1.3 */ - static final ASN1ObjectIdentifier pkcs_3 = new ASN1ObjectIdentifier("1.2.840.113549.1.3"); + ASN1ObjectIdentifier pkcs_3 = new ASN1ObjectIdentifier("1.2.840.113549.1.3"); /** PKCS#3: 1.2.840.113549.1.3.1 */ - static final ASN1ObjectIdentifier dhKeyAgreement = pkcs_3.branch("1"); + ASN1ObjectIdentifier dhKeyAgreement = pkcs_3.branch("1"); // // pkcs-5 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 5 } // /** PKCS#5: 1.2.840.113549.1.5 */ - static final ASN1ObjectIdentifier pkcs_5 = new ASN1ObjectIdentifier("1.2.840.113549.1.5"); + ASN1ObjectIdentifier pkcs_5 = new ASN1ObjectIdentifier("1.2.840.113549.1.5"); /** PKCS#5: 1.2.840.113549.1.5.1 */ - static final ASN1ObjectIdentifier pbeWithMD2AndDES_CBC = pkcs_5.branch("1"); + ASN1ObjectIdentifier pbeWithMD2AndDES_CBC = pkcs_5.branch("1"); /** PKCS#5: 1.2.840.113549.1.5.4 */ - static final ASN1ObjectIdentifier pbeWithMD2AndRC2_CBC = pkcs_5.branch("4"); + ASN1ObjectIdentifier pbeWithMD2AndRC2_CBC = pkcs_5.branch("4"); /** PKCS#5: 1.2.840.113549.1.5.3 */ - static final ASN1ObjectIdentifier pbeWithMD5AndDES_CBC = pkcs_5.branch("3"); + ASN1ObjectIdentifier pbeWithMD5AndDES_CBC = pkcs_5.branch("3"); /** PKCS#5: 1.2.840.113549.1.5.6 */ - static final ASN1ObjectIdentifier pbeWithMD5AndRC2_CBC = pkcs_5.branch("6"); + ASN1ObjectIdentifier pbeWithMD5AndRC2_CBC = pkcs_5.branch("6"); /** PKCS#5: 1.2.840.113549.1.5.10 */ - static final ASN1ObjectIdentifier pbeWithSHA1AndDES_CBC = pkcs_5.branch("10"); + ASN1ObjectIdentifier pbeWithSHA1AndDES_CBC = pkcs_5.branch("10"); /** PKCS#5: 1.2.840.113549.1.5.11 */ - static final ASN1ObjectIdentifier pbeWithSHA1AndRC2_CBC = pkcs_5.branch("11"); + ASN1ObjectIdentifier pbeWithSHA1AndRC2_CBC = pkcs_5.branch("11"); /** PKCS#5: 1.2.840.113549.1.5.13 */ - static final ASN1ObjectIdentifier id_PBES2 = pkcs_5.branch("13"); + ASN1ObjectIdentifier id_PBES2 = pkcs_5.branch("13"); /** PKCS#5: 1.2.840.113549.1.5.12 */ - static final ASN1ObjectIdentifier id_PBKDF2 = pkcs_5.branch("12"); + ASN1ObjectIdentifier id_PBKDF2 = pkcs_5.branch("12"); // // encryptionAlgorithm OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) 3 } // /** 1.2.840.113549.3 */ - static final ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.3"); + ASN1ObjectIdentifier encryptionAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.3"); /** 1.2.840.113549.3.7 */ - static final ASN1ObjectIdentifier des_EDE3_CBC = encryptionAlgorithm.branch("7"); + ASN1ObjectIdentifier des_EDE3_CBC = encryptionAlgorithm.branch("7"); /** 1.2.840.113549.3.2 */ - static final ASN1ObjectIdentifier RC2_CBC = encryptionAlgorithm.branch("2"); + ASN1ObjectIdentifier RC2_CBC = encryptionAlgorithm.branch("2"); /** 1.2.840.113549.3.4 */ - static final ASN1ObjectIdentifier rc4 = encryptionAlgorithm.branch("4"); + ASN1ObjectIdentifier rc4 = encryptionAlgorithm.branch("4"); // // object identifiers for digests // /** 1.2.840.113549.2 */ - static final ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.2"); + ASN1ObjectIdentifier digestAlgorithm = new ASN1ObjectIdentifier("1.2.840.113549.2"); // // md2 OBJECT IDENTIFIER ::= // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 2} // /** 1.2.840.113549.2.2 */ - static final ASN1ObjectIdentifier md2 = digestAlgorithm.branch("2"); + ASN1ObjectIdentifier md2 = digestAlgorithm.branch("2"); // // md4 OBJECT IDENTIFIER ::= // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 4} // /** 1.2.840.113549.2.4 */ - static final ASN1ObjectIdentifier md4 = digestAlgorithm.branch("4"); + ASN1ObjectIdentifier md4 = digestAlgorithm.branch("4"); // // md5 OBJECT IDENTIFIER ::= // {iso(1) member-body(2) US(840) rsadsi(113549) digestAlgorithm(2) 5} // /** 1.2.840.113549.2.5 */ - static final ASN1ObjectIdentifier md5 = digestAlgorithm.branch("5"); + ASN1ObjectIdentifier md5 = digestAlgorithm.branch("5"); /** 1.2.840.113549.2.7 */ - static final ASN1ObjectIdentifier id_hmacWithSHA1 = digestAlgorithm.branch("7").intern(); + ASN1ObjectIdentifier id_hmacWithSHA1 = digestAlgorithm.branch("7").intern(); /** 1.2.840.113549.2.8 */ - static final ASN1ObjectIdentifier id_hmacWithSHA224 = digestAlgorithm.branch("8").intern(); + ASN1ObjectIdentifier id_hmacWithSHA224 = digestAlgorithm.branch("8").intern(); /** 1.2.840.113549.2.9 */ - static final ASN1ObjectIdentifier id_hmacWithSHA256 = digestAlgorithm.branch("9").intern(); + ASN1ObjectIdentifier id_hmacWithSHA256 = digestAlgorithm.branch("9").intern(); /** 1.2.840.113549.2.10 */ - static final ASN1ObjectIdentifier id_hmacWithSHA384 = digestAlgorithm.branch("10").intern(); + ASN1ObjectIdentifier id_hmacWithSHA384 = digestAlgorithm.branch("10").intern(); /** 1.2.840.113549.2.11 */ - static final ASN1ObjectIdentifier id_hmacWithSHA512 = digestAlgorithm.branch("11").intern(); + ASN1ObjectIdentifier id_hmacWithSHA512 = digestAlgorithm.branch("11").intern(); // // pkcs-7 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 7 } // /** pkcs#7: 1.2.840.113549.1.7 */ - static final ASN1ObjectIdentifier pkcs_7 = new ASN1ObjectIdentifier("1.2.840.113549.1.7").intern(); + ASN1ObjectIdentifier pkcs_7 = new ASN1ObjectIdentifier("1.2.840.113549.1.7").intern(); /** PKCS#7: 1.2.840.113549.1.7.1 */ - static final ASN1ObjectIdentifier data = new ASN1ObjectIdentifier("1.2.840.113549.1.7.1").intern(); + ASN1ObjectIdentifier data = new ASN1ObjectIdentifier("1.2.840.113549.1.7.1").intern(); /** PKCS#7: 1.2.840.113549.1.7.2 */ - static final ASN1ObjectIdentifier signedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.2").intern(); + ASN1ObjectIdentifier signedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.2").intern(); /** PKCS#7: 1.2.840.113549.1.7.3 */ - static final ASN1ObjectIdentifier envelopedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.3").intern(); + ASN1ObjectIdentifier envelopedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.3").intern(); /** PKCS#7: 1.2.840.113549.1.7.4 */ - static final ASN1ObjectIdentifier signedAndEnvelopedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.4").intern(); + ASN1ObjectIdentifier signedAndEnvelopedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.4").intern(); /** PKCS#7: 1.2.840.113549.1.7.5 */ - static final ASN1ObjectIdentifier digestedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.5").intern(); + ASN1ObjectIdentifier digestedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.5").intern(); /** PKCS#7: 1.2.840.113549.1.7.76 */ - static final ASN1ObjectIdentifier encryptedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.6").intern(); + ASN1ObjectIdentifier encryptedData = new ASN1ObjectIdentifier("1.2.840.113549.1.7.6").intern(); // // pkcs-9 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 9 } // /** PKCS#9: 1.2.840.113549.1.9 */ - static final ASN1ObjectIdentifier pkcs_9 = new ASN1ObjectIdentifier("1.2.840.113549.1.9"); + ASN1ObjectIdentifier pkcs_9 = new ASN1ObjectIdentifier("1.2.840.113549.1.9"); /** PKCS#9: 1.2.840.113549.1.9.1 */ - static final ASN1ObjectIdentifier pkcs_9_at_emailAddress = pkcs_9.branch("1").intern(); + ASN1ObjectIdentifier pkcs_9_at_emailAddress = pkcs_9.branch("1").intern(); /** PKCS#9: 1.2.840.113549.1.9.2 */ - static final ASN1ObjectIdentifier pkcs_9_at_unstructuredName = pkcs_9.branch("2").intern(); + ASN1ObjectIdentifier pkcs_9_at_unstructuredName = pkcs_9.branch("2").intern(); /** PKCS#9: 1.2.840.113549.1.9.3 */ - static final ASN1ObjectIdentifier pkcs_9_at_contentType = pkcs_9.branch("3").intern(); + ASN1ObjectIdentifier pkcs_9_at_contentType = pkcs_9.branch("3").intern(); /** PKCS#9: 1.2.840.113549.1.9.4 */ - static final ASN1ObjectIdentifier pkcs_9_at_messageDigest = pkcs_9.branch("4").intern(); + ASN1ObjectIdentifier pkcs_9_at_messageDigest = pkcs_9.branch("4").intern(); /** PKCS#9: 1.2.840.113549.1.9.5 */ - static final ASN1ObjectIdentifier pkcs_9_at_signingTime = pkcs_9.branch("5").intern(); + ASN1ObjectIdentifier pkcs_9_at_signingTime = pkcs_9.branch("5").intern(); /** PKCS#9: 1.2.840.113549.1.9.6 */ - static final ASN1ObjectIdentifier pkcs_9_at_counterSignature = pkcs_9.branch("6").intern(); + ASN1ObjectIdentifier pkcs_9_at_counterSignature = pkcs_9.branch("6").intern(); /** PKCS#9: 1.2.840.113549.1.9.7 */ - static final ASN1ObjectIdentifier pkcs_9_at_challengePassword = pkcs_9.branch("7").intern(); + ASN1ObjectIdentifier pkcs_9_at_challengePassword = pkcs_9.branch("7").intern(); /** PKCS#9: 1.2.840.113549.1.9.8 */ - static final ASN1ObjectIdentifier pkcs_9_at_unstructuredAddress = pkcs_9.branch("8").intern(); + ASN1ObjectIdentifier pkcs_9_at_unstructuredAddress = pkcs_9.branch("8").intern(); /** PKCS#9: 1.2.840.113549.1.9.9 */ - static final ASN1ObjectIdentifier pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9").intern(); + ASN1ObjectIdentifier pkcs_9_at_extendedCertificateAttributes = pkcs_9.branch("9").intern(); /** PKCS#9: 1.2.840.113549.1.9.13 */ - static final ASN1ObjectIdentifier pkcs_9_at_signingDescription = pkcs_9.branch("13").intern(); + ASN1ObjectIdentifier pkcs_9_at_signingDescription = pkcs_9.branch("13").intern(); /** PKCS#9: 1.2.840.113549.1.9.14 */ - static final ASN1ObjectIdentifier pkcs_9_at_extensionRequest = pkcs_9.branch("14").intern(); + ASN1ObjectIdentifier pkcs_9_at_extensionRequest = pkcs_9.branch("14").intern(); /** PKCS#9: 1.2.840.113549.1.9.15 */ - static final ASN1ObjectIdentifier pkcs_9_at_smimeCapabilities = pkcs_9.branch("15").intern(); + ASN1ObjectIdentifier pkcs_9_at_smimeCapabilities = pkcs_9.branch("15").intern(); /** PKCS#9: 1.2.840.113549.1.9.16 */ - static final ASN1ObjectIdentifier id_smime = pkcs_9.branch("16").intern(); + ASN1ObjectIdentifier id_smime = pkcs_9.branch("16").intern(); /** PKCS#9: 1.2.840.113549.1.9.20 */ - static final ASN1ObjectIdentifier pkcs_9_at_friendlyName = pkcs_9.branch("20").intern(); + ASN1ObjectIdentifier pkcs_9_at_friendlyName = pkcs_9.branch("20").intern(); /** PKCS#9: 1.2.840.113549.1.9.21 */ - static final ASN1ObjectIdentifier pkcs_9_at_localKeyId = pkcs_9.branch("21").intern(); + ASN1ObjectIdentifier pkcs_9_at_localKeyId = pkcs_9.branch("21").intern(); /** PKCS#9: 1.2.840.113549.1.9.22.1 * @deprecated use x509Certificate instead */ - static final ASN1ObjectIdentifier x509certType = pkcs_9.branch("22.1"); + ASN1ObjectIdentifier x509certType = pkcs_9.branch("22.1"); /** PKCS#9: 1.2.840.113549.1.9.22 */ - static final ASN1ObjectIdentifier certTypes = pkcs_9.branch("22"); + ASN1ObjectIdentifier certTypes = pkcs_9.branch("22"); /** PKCS#9: 1.2.840.113549.1.9.22.1 */ - static final ASN1ObjectIdentifier x509Certificate = certTypes.branch("1").intern(); + ASN1ObjectIdentifier x509Certificate = certTypes.branch("1").intern(); /** PKCS#9: 1.2.840.113549.1.9.22.2 */ - static final ASN1ObjectIdentifier sdsiCertificate = certTypes.branch("2").intern(); + ASN1ObjectIdentifier sdsiCertificate = certTypes.branch("2").intern(); /** PKCS#9: 1.2.840.113549.1.9.23 */ - static final ASN1ObjectIdentifier crlTypes = pkcs_9.branch("23"); + ASN1ObjectIdentifier crlTypes = pkcs_9.branch("23"); /** PKCS#9: 1.2.840.113549.1.9.23.1 */ - static final ASN1ObjectIdentifier x509Crl = crlTypes.branch("1").intern(); + ASN1ObjectIdentifier x509Crl = crlTypes.branch("1").intern(); /** RFC 6211 - id-aa-cmsAlgorithmProtect OBJECT IDENTIFIER ::= { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) @@ -212,38 +212,38 @@ public interface PKCSObjectIdentifiers // SMIME capability sub oids. // /** PKCS#9: 1.2.840.113549.1.9.15.1 -- smime capability */ - static final ASN1ObjectIdentifier preferSignedData = pkcs_9.branch("15.1"); + ASN1ObjectIdentifier preferSignedData = pkcs_9.branch("15.1"); /** PKCS#9: 1.2.840.113549.1.9.15.2 -- smime capability */ - static final ASN1ObjectIdentifier canNotDecryptAny = pkcs_9.branch("15.2"); + ASN1ObjectIdentifier canNotDecryptAny = pkcs_9.branch("15.2"); /** PKCS#9: 1.2.840.113549.1.9.15.3 -- smime capability */ - static final ASN1ObjectIdentifier sMIMECapabilitiesVersions = pkcs_9.branch("15.3"); + ASN1ObjectIdentifier sMIMECapabilitiesVersions = pkcs_9.branch("15.3"); // // id-ct OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) ct(1)} // /** PKCS#9: 1.2.840.113549.1.9.16.1 -- smime ct */ - static final ASN1ObjectIdentifier id_ct = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1"); + ASN1ObjectIdentifier id_ct = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.1"); /** PKCS#9: 1.2.840.113549.1.9.16.1.2 -- smime ct authData */ - static final ASN1ObjectIdentifier id_ct_authData = id_ct.branch("2"); + ASN1ObjectIdentifier id_ct_authData = id_ct.branch("2"); /** PKCS#9: 1.2.840.113549.1.9.16.1.4 -- smime ct TSTInfo*/ - static final ASN1ObjectIdentifier id_ct_TSTInfo = id_ct.branch("4"); + ASN1ObjectIdentifier id_ct_TSTInfo = id_ct.branch("4"); /** PKCS#9: 1.2.840.113549.1.9.16.1.9 -- smime ct compressedData */ - static final ASN1ObjectIdentifier id_ct_compressedData = id_ct.branch("9"); + ASN1ObjectIdentifier id_ct_compressedData = id_ct.branch("9"); /** PKCS#9: 1.2.840.113549.1.9.16.1.23 -- smime ct authEnvelopedData */ - static final ASN1ObjectIdentifier id_ct_authEnvelopedData = id_ct.branch("23"); + ASN1ObjectIdentifier id_ct_authEnvelopedData = id_ct.branch("23"); /** PKCS#9: 1.2.840.113549.1.9.16.1.31 -- smime ct timestampedData*/ - static final ASN1ObjectIdentifier id_ct_timestampedData = id_ct.branch("31"); + ASN1ObjectIdentifier id_ct_timestampedData = id_ct.branch("31"); /** S/MIME: Algorithm Identifiers ; 1.2.840.113549.1.9.16.3 */ - static final ASN1ObjectIdentifier id_alg = id_smime.branch("3"); + ASN1ObjectIdentifier id_alg = id_smime.branch("3"); /** PKCS#9: 1.2.840.113549.1.9.16.3.9 */ - static final ASN1ObjectIdentifier id_alg_PWRI_KEK = id_alg.branch("9"); + ASN1ObjectIdentifier id_alg_PWRI_KEK = id_alg.branch("9"); /** *
-     * -- RSA-KEM Key Transport Algorithm
+     * -- RSA-KEM Key Transport Algorithm  RFC 5990
      *
      * id-rsa-kem OID ::= {
      *      iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
@@ -251,114 +251,125 @@ public interface PKCSObjectIdentifiers
      *   }
      * 
*/ - static final ASN1ObjectIdentifier id_rsa_KEM = id_alg.branch("14"); + ASN1ObjectIdentifier id_rsa_KEM = id_alg.branch("14"); + + /** + *
+     * id-alg-AEADChaCha20Poly1305 OBJECT IDENTIFIER ::=
+     * { iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
+     *    pkcs9(9) smime(16) alg(3) 18 }
+     *
+     * AEADChaCha20Poly1305Nonce ::= OCTET STRING (SIZE(12))
+     * 
+ */ + ASN1ObjectIdentifier id_alg_AEADChaCha20Poly1305 = id_alg.branch("18"); // // id-cti OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) cti(6)} // /** PKCS#9: 1.2.840.113549.1.9.16.6 -- smime cti */ - static final ASN1ObjectIdentifier id_cti = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.6"); + ASN1ObjectIdentifier id_cti = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.6"); /** PKCS#9: 1.2.840.113549.1.9.16.6.1 -- smime cti proofOfOrigin */ - static final ASN1ObjectIdentifier id_cti_ets_proofOfOrigin = id_cti.branch("1"); + ASN1ObjectIdentifier id_cti_ets_proofOfOrigin = id_cti.branch("1"); /** PKCS#9: 1.2.840.113549.1.9.16.6.2 -- smime cti proofOfReceipt*/ - static final ASN1ObjectIdentifier id_cti_ets_proofOfReceipt = id_cti.branch("2"); + ASN1ObjectIdentifier id_cti_ets_proofOfReceipt = id_cti.branch("2"); /** PKCS#9: 1.2.840.113549.1.9.16.6.3 -- smime cti proofOfDelivery */ - static final ASN1ObjectIdentifier id_cti_ets_proofOfDelivery = id_cti.branch("3"); + ASN1ObjectIdentifier id_cti_ets_proofOfDelivery = id_cti.branch("3"); /** PKCS#9: 1.2.840.113549.1.9.16.6.4 -- smime cti proofOfSender */ - static final ASN1ObjectIdentifier id_cti_ets_proofOfSender = id_cti.branch("4"); + ASN1ObjectIdentifier id_cti_ets_proofOfSender = id_cti.branch("4"); /** PKCS#9: 1.2.840.113549.1.9.16.6.5 -- smime cti proofOfApproval */ - static final ASN1ObjectIdentifier id_cti_ets_proofOfApproval = id_cti.branch("5"); + ASN1ObjectIdentifier id_cti_ets_proofOfApproval = id_cti.branch("5"); /** PKCS#9: 1.2.840.113549.1.9.16.6.6 -- smime cti proofOfCreation */ - static final ASN1ObjectIdentifier id_cti_ets_proofOfCreation = id_cti.branch("6"); + ASN1ObjectIdentifier id_cti_ets_proofOfCreation = id_cti.branch("6"); // // id-aa OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) // rsadsi(113549) pkcs(1) pkcs-9(9) smime(16) attributes(2)} // - /** PKCS#9: 1.2.840.113549.1.9.16.6.2 - smime attributes */ - static final ASN1ObjectIdentifier id_aa = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.2"); + /** PKCS#9: 1.2.840.113549.1.9.16.2 - smime attributes */ + ASN1ObjectIdentifier id_aa = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.2"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.1 -- smime attribute receiptRequest */ - static final ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.1 -- smime attribute receiptRequest */ + ASN1ObjectIdentifier id_aa_receiptRequest = id_aa.branch("1"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.4 - See RFC 2634 */ - static final ASN1ObjectIdentifier id_aa_contentHint = id_aa.branch("4"); // See RFC 2634 - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.5 */ - static final ASN1ObjectIdentifier id_aa_msgSigDigest = id_aa.branch("5"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.10 */ - static final ASN1ObjectIdentifier id_aa_contentReference = id_aa.branch("10"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.4 - See RFC 2634 */ + ASN1ObjectIdentifier id_aa_contentHint = id_aa.branch("4"); // See RFC 2634 + /** PKCS#9: 1.2.840.113549.1.9.16.2.5 */ + ASN1ObjectIdentifier id_aa_msgSigDigest = id_aa.branch("5"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.10 */ + ASN1ObjectIdentifier id_aa_contentReference = id_aa.branch("10"); /* * id-aa-encrypKeyPref OBJECT IDENTIFIER ::= {id-aa 11} * */ - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.11 */ - static final ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch("11"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.12 */ - static final ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch("12"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.47 */ - static final ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch("47"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.11 */ + ASN1ObjectIdentifier id_aa_encrypKeyPref = id_aa.branch("11"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.12 */ + ASN1ObjectIdentifier id_aa_signingCertificate = id_aa.branch("12"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.47 */ + ASN1ObjectIdentifier id_aa_signingCertificateV2 = id_aa.branch("47"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.7 - See RFC 2634 */ - static final ASN1ObjectIdentifier id_aa_contentIdentifier = id_aa.branch("7"); // See RFC 2634 + /** PKCS#9: 1.2.840.113549.1.9.16.2.7 - See RFC 2634 */ + ASN1ObjectIdentifier id_aa_contentIdentifier = id_aa.branch("7"); // See RFC 2634 /* * RFC 3126 */ - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.14 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_signatureTimeStampToken = id_aa.branch("14"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.14 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_signatureTimeStampToken = id_aa.branch("14"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.15 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch("15"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.16 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch("16"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.17 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch("17"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.18 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_signerAttr = id_aa.branch("18"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.15 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_sigPolicyId = id_aa.branch("15"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.16 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_commitmentType = id_aa.branch("16"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.17 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_signerLocation = id_aa.branch("17"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.18 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_signerAttr = id_aa.branch("18"); /** PKCS#9: 1.2.840.113549.1.9.16.6.2.19 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch("19"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.20 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch("20"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.21 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch("21"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.22 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch("22"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.23 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch("23"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.24 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch("24"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.25 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch("25"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.26 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch("26"); - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.27 - RFC 3126 */ - static final ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch("27"); - - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.37 - RFC 4108 */ - static final ASN1ObjectIdentifier id_aa_decryptKeyID = id_aa.branch("37"); - - /** PKCS#9: 1.2.840.113549.1.9.16.6.2.38 - RFC 4108 */ - static final ASN1ObjectIdentifier id_aa_implCryptoAlgs = id_aa.branch("38"); + ASN1ObjectIdentifier id_aa_ets_otherSigCert = id_aa.branch("19"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.20 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_contentTimestamp = id_aa.branch("20"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.21 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_certificateRefs = id_aa.branch("21"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.22 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_revocationRefs = id_aa.branch("22"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.23 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_certValues = id_aa.branch("23"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.24 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_revocationValues = id_aa.branch("24"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.25 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_escTimeStamp = id_aa.branch("25"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.26 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_certCRLTimestamp = id_aa.branch("26"); + /** PKCS#9: 1.2.840.113549.1.9.16.2.27 - RFC 3126 */ + ASN1ObjectIdentifier id_aa_ets_archiveTimestamp = id_aa.branch("27"); + + /** PKCS#9: 1.2.840.113549.1.9.16.2.37 - RFC 4108 */ + ASN1ObjectIdentifier id_aa_decryptKeyID = id_aa.branch("37"); + + /** PKCS#9: 1.2.840.113549.1.9.16.2.38 - RFC 4108 */ + ASN1ObjectIdentifier id_aa_implCryptoAlgs = id_aa.branch("38"); /** PKCS#9: 1.2.840.113549.1.9.16.2.54 RFC7030*/ - static final ASN1ObjectIdentifier id_aa_asymmDecryptKeyID = id_aa.branch("54"); + ASN1ObjectIdentifier id_aa_asymmDecryptKeyID = id_aa.branch("54"); /** PKCS#9: 1.2.840.113549.1.9.16.2.43 RFC7030*/ - static final ASN1ObjectIdentifier id_aa_implCompressAlgs = id_aa.branch("43"); + ASN1ObjectIdentifier id_aa_implCompressAlgs = id_aa.branch("43"); /** PKCS#9: 1.2.840.113549.1.9.16.2.40 RFC7030*/ - static final ASN1ObjectIdentifier id_aa_communityIdentifiers = id_aa.branch("40"); + ASN1ObjectIdentifier id_aa_communityIdentifiers = id_aa.branch("40"); /** @deprecated use id_aa_ets_sigPolicyId instead */ - static final ASN1ObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId; + ASN1ObjectIdentifier id_aa_sigPolicyId = id_aa_ets_sigPolicyId; /** @deprecated use id_aa_ets_commitmentType instead */ - static final ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType; + ASN1ObjectIdentifier id_aa_commitmentType = id_aa_ets_commitmentType; /** @deprecated use id_aa_ets_signerLocation instead */ - static final ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation; + ASN1ObjectIdentifier id_aa_signerLocation = id_aa_ets_signerLocation; /** @deprecated use id_aa_ets_otherSigCert instead */ - static final ASN1ObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert; + ASN1ObjectIdentifier id_aa_otherSigCert = id_aa_ets_otherSigCert; /** * id-spq OBJECT IDENTIFIER ::= {iso(1) member-body(2) usa(840) @@ -368,61 +379,61 @@ public interface PKCSObjectIdentifiers final String id_spq = "1.2.840.113549.1.9.16.5"; /** SMIME SPQ URI: 1.2.840.113549.1.9.16.5.1 */ - static final ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + ".1"); + ASN1ObjectIdentifier id_spq_ets_uri = new ASN1ObjectIdentifier(id_spq + ".1"); /** SMIME SPQ UNOTICE: 1.2.840.113549.1.9.16.5.2 */ - static final ASN1ObjectIdentifier id_spq_ets_unotice = new ASN1ObjectIdentifier(id_spq + ".2"); + ASN1ObjectIdentifier id_spq_ets_unotice = new ASN1ObjectIdentifier(id_spq + ".2"); // // pkcs-12 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 12 } // /** PKCS#12: 1.2.840.113549.1.12 */ - static final ASN1ObjectIdentifier pkcs_12 = new ASN1ObjectIdentifier("1.2.840.113549.1.12"); + ASN1ObjectIdentifier pkcs_12 = new ASN1ObjectIdentifier("1.2.840.113549.1.12"); /** PKCS#12: 1.2.840.113549.1.12.10.1 */ - static final ASN1ObjectIdentifier bagtypes = pkcs_12.branch("10.1"); + ASN1ObjectIdentifier bagtypes = pkcs_12.branch("10.1"); /** PKCS#12: 1.2.840.113549.1.12.10.1.1 */ - static final ASN1ObjectIdentifier keyBag = bagtypes.branch("1"); + ASN1ObjectIdentifier keyBag = bagtypes.branch("1"); /** PKCS#12: 1.2.840.113549.1.12.10.1.2 */ - static final ASN1ObjectIdentifier pkcs8ShroudedKeyBag = bagtypes.branch("2"); + ASN1ObjectIdentifier pkcs8ShroudedKeyBag = bagtypes.branch("2"); /** PKCS#12: 1.2.840.113549.1.12.10.1.3 */ - static final ASN1ObjectIdentifier certBag = bagtypes.branch("3"); + ASN1ObjectIdentifier certBag = bagtypes.branch("3"); /** PKCS#12: 1.2.840.113549.1.12.10.1.4 */ - static final ASN1ObjectIdentifier crlBag = bagtypes.branch("4"); + ASN1ObjectIdentifier crlBag = bagtypes.branch("4"); /** PKCS#12: 1.2.840.113549.1.12.10.1.5 */ - static final ASN1ObjectIdentifier secretBag = bagtypes.branch("5"); + ASN1ObjectIdentifier secretBag = bagtypes.branch("5"); /** PKCS#12: 1.2.840.113549.1.12.10.1.6 */ - static final ASN1ObjectIdentifier safeContentsBag = bagtypes.branch("6"); + ASN1ObjectIdentifier safeContentsBag = bagtypes.branch("6"); /** PKCS#12: 1.2.840.113549.1.12.1 */ - static final ASN1ObjectIdentifier pkcs_12PbeIds = pkcs_12.branch("1"); + ASN1ObjectIdentifier pkcs_12PbeIds = pkcs_12.branch("1"); /** PKCS#12: 1.2.840.113549.1.12.1.1 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1"); + ASN1ObjectIdentifier pbeWithSHAAnd128BitRC4 = pkcs_12PbeIds.branch("1"); /** PKCS#12: 1.2.840.113549.1.12.1.2 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC4 = pkcs_12PbeIds.branch("2"); + ASN1ObjectIdentifier pbeWithSHAAnd40BitRC4 = pkcs_12PbeIds.branch("2"); /** PKCS#12: 1.2.840.113549.1.12.1.3 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3"); + ASN1ObjectIdentifier pbeWithSHAAnd3_KeyTripleDES_CBC = pkcs_12PbeIds.branch("3"); /** PKCS#12: 1.2.840.113549.1.12.1.4 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4"); + ASN1ObjectIdentifier pbeWithSHAAnd2_KeyTripleDES_CBC = pkcs_12PbeIds.branch("4"); /** PKCS#12: 1.2.840.113549.1.12.1.5 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch("5"); + ASN1ObjectIdentifier pbeWithSHAAnd128BitRC2_CBC = pkcs_12PbeIds.branch("5"); /** PKCS#12: 1.2.840.113549.1.12.1.6 */ - static final ASN1ObjectIdentifier pbeWithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); + ASN1ObjectIdentifier pbeWithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); /** * PKCS#12: 1.2.840.113549.1.12.1.6 * @deprecated use pbeWithSHAAnd40BitRC2_CBC */ - static final ASN1ObjectIdentifier pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); + ASN1ObjectIdentifier pbewithSHAAnd40BitRC2_CBC = pkcs_12PbeIds.branch("6"); /** PKCS#9: 1.2.840.113549.1.9.16.3.6 */ - static final ASN1ObjectIdentifier id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"); + ASN1ObjectIdentifier id_alg_CMS3DESwrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.6"); /** PKCS#9: 1.2.840.113549.1.9.16.3.7 */ - static final ASN1ObjectIdentifier id_alg_CMSRC2wrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"); + ASN1ObjectIdentifier id_alg_CMSRC2wrap = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.7"); /** PKCS#9: 1.2.840.113549.1.9.16.3.5 */ - static final ASN1ObjectIdentifier id_alg_ESDH = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.5"); + ASN1ObjectIdentifier id_alg_ESDH = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.5"); /** PKCS#9: 1.2.840.113549.1.9.16.3.10 */ - static final ASN1ObjectIdentifier id_alg_SSDH = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.10"); + ASN1ObjectIdentifier id_alg_SSDH = new ASN1ObjectIdentifier("1.2.840.113549.1.9.16.3.10"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/Pfx.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/Pfx.java index 6b651cd36..8f05ccf9a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/Pfx.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/Pfx.java @@ -1,7 +1,5 @@ package com.fr.third.org.bouncycastle.asn1.pkcs; -import java.math.BigInteger; - import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; import com.fr.third.org.bouncycastle.asn1.ASN1Object; @@ -22,8 +20,8 @@ public class Pfx private Pfx( ASN1Sequence seq) { - BigInteger version = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue(); - if (version.intValue() != 3) + ASN1Integer version = ASN1Integer.getInstance(seq.getObjectAt(0)); + if (version.intValueExact() != 3) { throw new IllegalArgumentException("wrong version for PFX PDU"); } @@ -72,7 +70,7 @@ public class Pfx public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(new ASN1Integer(3)); v.add(contentInfo); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java index f88081b2c..424054c82 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/PrivateKeyInfo.java @@ -4,9 +4,9 @@ import java.io.IOException; import java.math.BigInteger; import java.util.Enumeration; +import com.fr.third.org.bouncycastle.asn1.ASN1BitString; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; -import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; import com.fr.third.org.bouncycastle.asn1.ASN1Object; import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; @@ -14,27 +14,65 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.ASN1Set; import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERBitString; import com.fr.third.org.bouncycastle.asn1.DEROctetString; import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; - +import com.fr.third.org.bouncycastle.util.BigIntegers; + +/** + * RFC 5958 + * + *
+ *  [IMPLICIT TAGS]
+ *
+ *  OneAsymmetricKey ::= SEQUENCE {
+ *      version                   Version,
+ *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
+ *      privateKey                PrivateKey,
+ *      attributes            [0] Attributes OPTIONAL,
+ *      ...,
+ *      [[2: publicKey        [1] PublicKey OPTIONAL ]],
+ *      ...
+ *  }
+ *
+ *  PrivateKeyInfo ::= OneAsymmetricKey
+ *
+ *  Version ::= INTEGER { v1(0), v2(1) } (v1, ..., v2)
+ *
+ *  PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ *                                     { PUBLIC-KEY,
+ *                                       { PrivateKeyAlgorithms } }
+ *
+ *  PrivateKey ::= OCTET STRING
+ *                     -- Content varies based on type of key.  The
+ *                     -- algorithm identifier dictates the format of
+ *                     -- the key.
+ *
+ *  PublicKey ::= BIT STRING
+ *                     -- Content varies based on type of key.  The
+ *                     -- algorithm identifier dictates the format of
+ *                     -- the key.
+ *
+ *  Attributes ::= SET OF Attribute { { OneAsymmetricKeyAttributes } }
+ *  
+ */ public class PrivateKeyInfo extends ASN1Object { - private ASN1OctetString privKey; - private AlgorithmIdentifier algId; - private ASN1Set attributes; + private ASN1Integer version; + private AlgorithmIdentifier privateKeyAlgorithm; + private ASN1OctetString privateKey; + private ASN1Set attributes; + private ASN1BitString publicKey; - public static PrivateKeyInfo getInstance( - ASN1TaggedObject obj, - boolean explicit) + public static PrivateKeyInfo getInstance(ASN1TaggedObject obj, boolean explicit) { return getInstance(ASN1Sequence.getInstance(obj, explicit)); } - public static PrivateKeyInfo getInstance( - Object obj) + public static PrivateKeyInfo getInstance(Object obj) { if (obj instanceof PrivateKeyInfo) { @@ -47,118 +85,165 @@ public class PrivateKeyInfo return null; } - + + private static int getVersionValue(ASN1Integer version) + { + int versionValue = version.intValueExact(); + if (versionValue < 0 || versionValue > 1) + { + throw new IllegalArgumentException("invalid version for private key info"); + } + return versionValue; + } + public PrivateKeyInfo( - AlgorithmIdentifier algId, - ASN1Encodable privateKey) + AlgorithmIdentifier privateKeyAlgorithm, + ASN1Encodable privateKey) throws IOException { - this(algId, privateKey, null); + this(privateKeyAlgorithm, privateKey, null, null); } public PrivateKeyInfo( - AlgorithmIdentifier algId, - ASN1Encodable privateKey, - ASN1Set attributes) + AlgorithmIdentifier privateKeyAlgorithm, + ASN1Encodable privateKey, + ASN1Set attributes) throws IOException { - this.privKey = new DEROctetString(privateKey.toASN1Primitive().getEncoded(ASN1Encoding.DER)); - this.algId = algId; - this.attributes = attributes; + this(privateKeyAlgorithm, privateKey, attributes, null); } - /** - * @deprecated use PrivateKeyInfo.getInstance() - * @param seq - */ public PrivateKeyInfo( - ASN1Sequence seq) + AlgorithmIdentifier privateKeyAlgorithm, + ASN1Encodable privateKey, + ASN1Set attributes, + byte[] publicKey) + throws IOException + { + this.version = new ASN1Integer(publicKey != null ? BigIntegers.ONE : BigIntegers.ZERO); + this.privateKeyAlgorithm = privateKeyAlgorithm; + this.privateKey = new DEROctetString(privateKey); + this.attributes = attributes; + this.publicKey = publicKey == null ? null : new DERBitString(publicKey); + } + + private PrivateKeyInfo(ASN1Sequence seq) { Enumeration e = seq.getObjects(); - BigInteger version = ((ASN1Integer)e.nextElement()).getValue(); - if (version.intValue() != 0) - { - throw new IllegalArgumentException("wrong version for private key info"); - } + this.version = ASN1Integer.getInstance(e.nextElement()); + + int versionValue = getVersionValue(version); - algId = AlgorithmIdentifier.getInstance(e.nextElement()); - privKey = ASN1OctetString.getInstance(e.nextElement()); - - if (e.hasMoreElements()) + this.privateKeyAlgorithm = AlgorithmIdentifier.getInstance(e.nextElement()); + this.privateKey = ASN1OctetString.getInstance(e.nextElement()); + + int lastTag = -1; + while (e.hasMoreElements()) { - attributes = ASN1Set.getInstance((ASN1TaggedObject)e.nextElement(), false); + ASN1TaggedObject tagged = (ASN1TaggedObject)e.nextElement(); + + int tag = tagged.getTagNo(); + if (tag <= lastTag) + { + throw new IllegalArgumentException("invalid optional field in private key info"); + } + + lastTag = tag; + + switch (tag) + { + case 0: + { + this.attributes = ASN1Set.getInstance(tagged, false); + break; + } + case 1: + { + if (versionValue < 1) + { + throw new IllegalArgumentException("'publicKey' requires version v2(1) or later"); + } + + this.publicKey = DERBitString.getInstance(tagged, false); + break; + } + default: + { + throw new IllegalArgumentException("unknown optional field in private key info"); + } + } } } - public AlgorithmIdentifier getPrivateKeyAlgorithm() + public ASN1Set getAttributes() { - return algId; + return attributes; } - /** - * @deprecated use getPrivateKeyAlgorithm() - */ - public AlgorithmIdentifier getAlgorithmId() + + public AlgorithmIdentifier getPrivateKeyAlgorithm() { - return algId; + return privateKeyAlgorithm; } public ASN1Encodable parsePrivateKey() throws IOException { - return ASN1Primitive.fromByteArray(privKey.getOctets()); + return ASN1Primitive.fromByteArray(privateKey.getOctets()); } /** - * @deprecated use parsePrivateKey() + * Return true if a public key is present, false otherwise. + * + * @return true if public included, otherwise false. */ - public ASN1Primitive getPrivateKey() + public boolean hasPublicKey() { - try - { - return parsePrivateKey().toASN1Primitive(); - } - catch (IOException e) - { - throw new IllegalStateException("unable to parse private key"); - } + return publicKey != null; } - - public ASN1Set getAttributes() + + /** + * for when the public key is an encoded object - if the bitstring + * can't be decoded this routine throws an IOException. + * + * @return the public key as an ASN.1 primitive. + * @throws IOException - if the bit string doesn't represent a DER + * encoded object. + */ + public ASN1Encodable parsePublicKey() + throws IOException { - return attributes; + return publicKey == null ? null : ASN1Primitive.fromByteArray(publicKey.getOctets()); } /** - * write out an RSA private key with its associated information - * as described in PKCS8. - *
-     *      PrivateKeyInfo ::= SEQUENCE {
-     *                              version Version,
-     *                              privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
-     *                              privateKey PrivateKey,
-     *                              attributes [0] IMPLICIT Attributes OPTIONAL 
-     *                          }
-     *      Version ::= INTEGER {v1(0)} (v1,...)
+     * for when the public key is raw bits.
      *
-     *      PrivateKey ::= OCTET STRING
-     *
-     *      Attributes ::= SET OF Attribute
-     * 
+ * @return the public key as the raw bit string... */ + public ASN1BitString getPublicKeyData() + { + return publicKey; + } + public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); - v.add(new ASN1Integer(0)); - v.add(algId); - v.add(privKey); + v.add(version); + v.add(privateKeyAlgorithm); + v.add(privateKey); if (attributes != null) { v.add(new DERTaggedObject(false, 0, attributes)); } - + + if (publicKey != null) + { + v.add(new DERTaggedObject(false, 1, publicKey)); + } + return new DERSequence(v); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java index 92905832f..946ae73e2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RC2CBCParameter.java @@ -79,7 +79,7 @@ public class RC2CBCParameter public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (version != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java index 65f44a96f..fd9852e30 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAESOAEPparams.java @@ -133,7 +133,7 @@ public class RSAESOAEPparams */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM)) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java index 042475484..5f53963ea 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPrivateKey.java @@ -74,13 +74,14 @@ public class RSAPrivateKey { Enumeration e = seq.getObjects(); - BigInteger v = ((ASN1Integer)e.nextElement()).getValue(); - if (v.intValue() != 0 && v.intValue() != 1) + ASN1Integer v = (ASN1Integer)e.nextElement(); + int versionValue = v.intValueExact(); + if (versionValue < 0 || versionValue > 1) { throw new IllegalArgumentException("wrong version for RSA private key"); } - version = v; + version = v.getValue(); modulus = ((ASN1Integer)e.nextElement()).getValue(); publicExponent = ((ASN1Integer)e.nextElement()).getValue(); privateExponent = ((ASN1Integer)e.nextElement()).getValue(); @@ -165,7 +166,7 @@ public class RSAPrivateKey */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(10); v.add(new ASN1Integer(version)); // version v.add(new ASN1Integer(getModulus())); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java index 4c663f833..020052371 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPrivateKeyStructure.java @@ -76,13 +76,14 @@ public class RSAPrivateKeyStructure { Enumeration e = seq.getObjects(); - BigInteger v = ((ASN1Integer)e.nextElement()).getValue(); - if (v.intValue() != 0 && v.intValue() != 1) + ASN1Integer v = (ASN1Integer)e.nextElement(); + int versionValue = v.intValueExact(); + if (versionValue < 0 || versionValue > 1) { throw new IllegalArgumentException("wrong version for RSA private key"); } - version = v.intValue(); + version = versionValue; modulus = ((ASN1Integer)e.nextElement()).getValue(); publicExponent = ((ASN1Integer)e.nextElement()).getValue(); privateExponent = ((ASN1Integer)e.nextElement()).getValue(); @@ -167,7 +168,7 @@ public class RSAPrivateKeyStructure */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(10); v.add(new ASN1Integer(version)); // version v.add(new ASN1Integer(getModulus())); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPublicKey.java index 88c7ae15f..65f27b11d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSAPublicKey.java @@ -85,7 +85,7 @@ public class RSAPublicKey */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(new ASN1Integer(getModulus())); v.add(new ASN1Integer(getPublicExponent())); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java index 41eefd578..6d3f91040 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/RSASSAPSSparams.java @@ -145,7 +145,7 @@ public class RSASSAPSSparams */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); if (!hashAlgorithm.equals(DEFAULT_HASH_ALGORITHM)) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SafeBag.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SafeBag.java index b61dab2b2..e7bbf11c8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SafeBag.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SafeBag.java @@ -81,7 +81,7 @@ public class SafeBag public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(bagId); v.add(new DLTaggedObject(true, 0, bagValue)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SignedData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SignedData.java index 5f06266bc..f664bcc48 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SignedData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SignedData.java @@ -144,7 +144,7 @@ public class SignedData */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); v.add(version); v.add(digestAlgorithms); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SignerInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SignerInfo.java index b94a79a85..f8405b049 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SignerInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/pkcs/SignerInfo.java @@ -154,7 +154,7 @@ public class SignerInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(7); v.add(version); v.add(issuerAndSerialNumber); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/ECPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/ECPrivateKey.java index 5d9c52991..fd38627b9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/ECPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/ECPrivateKey.java @@ -68,7 +68,7 @@ public class ECPrivateKey { byte[] bytes = BigIntegers.asUnsignedByteArray((orderBitLength + 7) / 8, key); - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(new ASN1Integer(1)); v.add(new DEROctetString(bytes)); @@ -113,7 +113,7 @@ public class ECPrivateKey { byte[] bytes = BigIntegers.asUnsignedByteArray((orderBitLength + 7) / 8, key); - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(new ASN1Integer(1)); v.add(new DEROctetString(bytes)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java index 137d039b7..e2e922fbe 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/ECPrivateKeyStructure.java @@ -37,7 +37,7 @@ public class ECPrivateKeyStructure { byte[] bytes = BigIntegers.asUnsignedByteArray(key); - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(new ASN1Integer(1)); v.add(new DEROctetString(bytes)); @@ -59,7 +59,7 @@ public class ECPrivateKeyStructure { byte[] bytes = BigIntegers.asUnsignedByteArray(key); - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(new ASN1Integer(1)); v.add(new DEROctetString(bytes)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/SECNamedCurves.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/SECNamedCurves.java index ca2e3a028..74818c461 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/SECNamedCurves.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/SECNamedCurves.java @@ -10,13 +10,22 @@ import com.fr.third.org.bouncycastle.asn1.x9.X9ECParametersHolder; import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.WNafUtil; import com.fr.third.org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism; import com.fr.third.org.bouncycastle.math.ec.endo.GLVTypeBParameters; +import com.fr.third.org.bouncycastle.math.ec.endo.ScalarSplitParameters; import com.fr.third.org.bouncycastle.util.Strings; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SECNamedCurves { + private static X9ECPoint configureBasepoint(ECCurve curve, String encoding) + { + X9ECPoint G = new X9ECPoint(curve, Hex.decodeStrict(encoding)); + WNafUtil.configureBasepoint(G.getPoint()); + return G; + } + private static ECCurve configureCurve(ECCurve curve) { return curve; @@ -27,10 +36,9 @@ public class SECNamedCurves return c.configure().setEndomorphism(new GLVTypeBEndomorphism(c, p)).create(); } - private static BigInteger fromHex( - String hex) + private static BigInteger fromHex(String hex) { - return new BigInteger(1, Hex.decode(hex)); + return new BigInteger(1, Hex.decodeStrict(hex)); } /* @@ -44,16 +52,14 @@ public class SECNamedCurves BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B"); BigInteger a = fromHex("DB7C2ABF62E35E668076BEAD2088"); BigInteger b = fromHex("659EF8BA043916EEDE8911702B22"); - byte[] S = Hex.decode("00F50B028E4D696E676875615175290472783FB1"); + byte[] S = Hex.decodeStrict("00F50B028E4D696E676875615175290472783FB1"); BigInteger n = fromHex("DB7C2ABF62E35E7628DFAC6561C5"); BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("02" - //+ "09487239995A5EE76B55F9C2F098")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "09487239995A5EE76B55F9C2F098" - + "A89CE5AF8724C0A23E0E0FF77500")); + + X9ECPoint G = configureBasepoint(curve, + "0409487239995A5EE76B55F9C2F098A89CE5AF8724C0A23E0E0FF77500"); return new X9ECParameters(curve, G, n, h, S); } @@ -70,16 +76,14 @@ public class SECNamedCurves BigInteger p = fromHex("DB7C2ABF62E35E668076BEAD208B"); BigInteger a = fromHex("6127C24C05F38A0AAAF65C0EF02C"); BigInteger b = fromHex("51DEF1815DB5ED74FCC34C85D709"); - byte[] S = Hex.decode("002757A1114D696E6768756151755316C05E0BD4"); + byte[] S = Hex.decodeStrict("002757A1114D696E6768756151755316C05E0BD4"); BigInteger n = fromHex("36DF0AAFD8B8D7597CA10520D04B"); BigInteger h = BigInteger.valueOf(4); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "4BA30AB5E892B4E1649DD0928643")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "4BA30AB5E892B4E1649DD0928643" - + "ADCD46F5882E3747DEF36E956E97")); + + X9ECPoint G = configureBasepoint(curve, + "044BA30AB5E892B4E1649DD0928643ADCD46F5882E3747DEF36E956E97"); return new X9ECParameters(curve, G, n, h, S); } @@ -96,16 +100,14 @@ public class SECNamedCurves BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"); BigInteger a = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC"); BigInteger b = fromHex("E87579C11079F43DD824993C2CEE5ED3"); - byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679"); + byte[] S = Hex.decodeStrict("000E0D4D696E6768756151750CC03A4473D03679"); BigInteger n = fromHex("FFFFFFFE0000000075A30D1B9038A115"); BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "161FF7528B899B2D0C28607CA52C5B86")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "161FF7528B899B2D0C28607CA52C5B86" - + "CF5AC8395BAFEB13C02DA292DDED7A83")); + + X9ECPoint G = configureBasepoint(curve, + "04161FF7528B899B2D0C28607CA52C5B86CF5AC8395BAFEB13C02DA292DDED7A83"); return new X9ECParameters(curve, G, n, h, S); } @@ -122,16 +124,14 @@ public class SECNamedCurves BigInteger p = fromHex("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF"); BigInteger a = fromHex("D6031998D1B3BBFEBF59CC9BBFF9AEE1"); BigInteger b = fromHex("5EEEFCA380D02919DC2C6558BB6D8A5D"); - byte[] S = Hex.decode("004D696E67687561517512D8F03431FCE63B88F4"); + byte[] S = Hex.decodeStrict("004D696E67687561517512D8F03431FCE63B88F4"); BigInteger n = fromHex("3FFFFFFF7FFFFFFFBE0024720613B5A3"); BigInteger h = BigInteger.valueOf(4); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("02" - //+ "7B6AA5D85E572983E6FB32A7CDEBC140")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "7B6AA5D85E572983E6FB32A7CDEBC140" - + "27B6916A894D3AEE7106FE805FC34B44")); + + X9ECPoint G = configureBasepoint(curve, + "047B6AA5D85E572983E6FB32A7CDEBC14027B6916A894D3AEE7106FE805FC34B44"); return new X9ECParameters(curve, G, n, h, S); } @@ -155,22 +155,21 @@ public class SECNamedCurves GLVTypeBParameters glv = new GLVTypeBParameters( new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16), new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16), - new BigInteger[]{ - new BigInteger("9162fbe73984472a0a9e", 16), - new BigInteger("-96341f1138933bc2f505", 16) }, - new BigInteger[]{ - new BigInteger("127971af8721782ecffa3", 16), - new BigInteger("9162fbe73984472a0a9e", 16) }, - new BigInteger("9162fbe73984472a0a9d0590", 16), - new BigInteger("96341f1138933bc2f503fd44", 16), - 176); + new ScalarSplitParameters( + new BigInteger[]{ + new BigInteger("9162fbe73984472a0a9e", 16), + new BigInteger("-96341f1138933bc2f505", 16) }, + new BigInteger[]{ + new BigInteger("127971af8721782ecffa3", 16), + new BigInteger("9162fbe73984472a0a9e", 16) }, + new BigInteger("9162fbe73984472a0a9d0590", 16), + new BigInteger("96341f1138933bc2f503fd44", 16), + 176)); ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); -// ECPoint G = curve.decodePoint(Hex.decode("02" -// + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB" - + "938CF935318FDCED6BC28286531733C3F03C4FEE")); + + X9ECPoint G = configureBasepoint(curve, + "043B4C382CE37AA192A4019E763036F4F5DD4D7EBB938CF935318FDCED6BC28286531733C3F03C4FEE"); return new X9ECParameters(curve, G, n, h, S); } @@ -187,16 +186,14 @@ public class SECNamedCurves BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF"); BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC"); BigInteger b = fromHex("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45"); - byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345"); + byte[] S = Hex.decodeStrict("1053CDE42C14D696E67687561517533BF3F83345"); BigInteger n = fromHex("0100000000000000000001F4C8F927AED3CA752257"); BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("02" - //+ "4A96B5688EF573284664698968C38BB913CBFC82")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "4A96B5688EF573284664698968C38BB913CBFC82" - + "23A628553168947D59DCC912042351377AC5FB32")); + + X9ECPoint G = configureBasepoint(curve, + "044A96B5688EF573284664698968C38BB913CBFC8223A628553168947D59DCC912042351377AC5FB32"); return new X9ECParameters(curve, G, n, h, S); } @@ -213,16 +210,14 @@ public class SECNamedCurves BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73"); BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70"); BigInteger b = fromHex("B4E134D3FB59EB8BAB57274904664D5AF50388BA"); - byte[] S = Hex.decode("B99B99B099B323E02709A4D696E6768756151751"); + byte[] S = Hex.decodeStrict("B99B99B099B323E02709A4D696E6768756151751"); BigInteger n = fromHex("0100000000000000000000351EE786A818F3A1A16B"); BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("02" - //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "52DCB034293A117E1F4FF11B30F7199D3144CE6D" - + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E")); + + X9ECPoint G = configureBasepoint(curve, + "0452DCB034293A117E1F4FF11B30F7199D3144CE6DFEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"); return new X9ECParameters(curve, G, n, h, S); } @@ -246,22 +241,21 @@ public class SECNamedCurves GLVTypeBParameters glv = new GLVTypeBParameters( new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16), new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16), - new BigInteger[]{ - new BigInteger("71169be7330b3038edb025f1", 16), - new BigInteger("-b3fb3400dec5c4adceb8655c", 16) }, - new BigInteger[]{ - new BigInteger("12511cfe811d0f4e6bc688b4d", 16), - new BigInteger("71169be7330b3038edb025f1", 16) }, - new BigInteger("71169be7330b3038edb025f1d0f9", 16), - new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16), - 208); + new ScalarSplitParameters( + new BigInteger[]{ + new BigInteger("71169be7330b3038edb025f1", 16), + new BigInteger("-b3fb3400dec5c4adceb8655c", 16) }, + new BigInteger[]{ + new BigInteger("12511cfe811d0f4e6bc688b4d", 16), + new BigInteger("71169be7330b3038edb025f1", 16) }, + new BigInteger("71169be7330b3038edb025f1d0f9", 16), + new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16), + 208)); ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D" - + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D")); + + X9ECPoint G = configureBasepoint(curve, + "04DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"); return new X9ECParameters(curve, G, n, h, S); } @@ -278,16 +272,14 @@ public class SECNamedCurves BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"); BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC"); BigInteger b = fromHex("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"); - byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5"); + byte[] S = Hex.decodeStrict("3045AE6FC8422F64ED579528D38120EAE12196D5"); BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831"); BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012" - + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")); + + X9ECPoint G = configureBasepoint(curve, + "04188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E794811"); return new X9ECParameters(curve, G, n, h, S); } @@ -311,22 +303,21 @@ public class SECNamedCurves GLVTypeBParameters glv = new GLVTypeBParameters( new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16), new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16), - new BigInteger[]{ - new BigInteger("6b8cf07d4ca75c88957d9d670591", 16), - new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) }, - new BigInteger[]{ - new BigInteger("1243ae1b4d71613bc9f780a03690e", 16), - new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) }, - new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16), - new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16), - 240); + new ScalarSplitParameters( + new BigInteger[]{ + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16), + new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) }, + new BigInteger[]{ + new BigInteger("1243ae1b4d71613bc9f780a03690e", 16), + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) }, + new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16), + new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16), + 240)); ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C" - + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5")); + + X9ECPoint G = configureBasepoint(curve, + "04A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"); return new X9ECParameters(curve, G, n, h, S); } @@ -343,16 +334,14 @@ public class SECNamedCurves BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001"); BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"); BigInteger b = fromHex("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"); - byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5"); + byte[] S = Hex.decodeStrict("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5"); BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D"); BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("02" - //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21" - + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")); + + X9ECPoint G = configureBasepoint(curve, + "04B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"); return new X9ECParameters(curve, G, n, h, S); } @@ -376,22 +365,21 @@ public class SECNamedCurves GLVTypeBParameters glv = new GLVTypeBParameters( new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16), new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16), - new BigInteger[]{ - new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16), - new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) }, - new BigInteger[]{ - new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16), - new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) }, - new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16), - new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16), - 272); + new ScalarSplitParameters( + new BigInteger[]{ + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16), + new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) }, + new BigInteger[]{ + new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16), + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) }, + new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16), + new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16), + 272)); ECCurve curve = configureCurveGLV(new ECCurve.Fp(p, a, b, n, h), glv); - //ECPoint G = curve.decodePoint(Hex.decode("02" - //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" - + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")); + + X9ECPoint G = configureBasepoint(curve, + "0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"); return new X9ECParameters(curve, G, n, h, S); } @@ -408,16 +396,14 @@ public class SECNamedCurves BigInteger p = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"); BigInteger a = fromHex("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"); BigInteger b = fromHex("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"); - byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90"); + byte[] S = Hex.decodeStrict("C49D360886E704936A6678E1139D26B7819F7E90"); BigInteger n = fromHex("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"); BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" - + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")); + + X9ECPoint G = configureBasepoint(curve, + "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"); return new X9ECParameters(curve, G, n, h, S); } @@ -434,16 +420,15 @@ public class SECNamedCurves BigInteger p = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF"); BigInteger a = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"); BigInteger b = fromHex("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"); - byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73"); + byte[] S = Hex.decodeStrict("A335926AA319A27A1D00896A6773A4827ACDAC73"); BigInteger n = fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973"); BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + X9ECPoint G = configureBasepoint(curve, "04" + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" - + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); + + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"); return new X9ECParameters(curve, G, n, h, S); } @@ -460,17 +445,15 @@ public class SECNamedCurves BigInteger p = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); BigInteger a = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"); BigInteger b = fromHex("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"); - byte[] S = Hex.decode("D09E8800291CB85396CC6717393284AAA0DA64BA"); + byte[] S = Hex.decodeStrict("D09E8800291CB85396CC6717393284AAA0DA64BA"); BigInteger n = fromHex("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409"); BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp(p, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("02" - //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + X9ECPoint G = configureBasepoint(curve, "04" + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66" - + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650")); + + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"); return new X9ECParameters(curve, G, n, h, S); } @@ -488,16 +471,14 @@ public class SECNamedCurves BigInteger a = fromHex("003088250CA6E7C7FE649CE85820F7"); BigInteger b = fromHex("00E8BEE4D3E2260744188BE0E9C723"); - byte[] S = Hex.decode("10E723AB14D696E6768756151756FEBF8FCB49A9"); + byte[] S = Hex.decodeStrict("10E723AB14D696E6768756151756FEBF8FCB49A9"); BigInteger n = fromHex("0100000000000000D9CCEC8A39E56F"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "009D73616F35F4AB1407D73562C10F")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "009D73616F35F4AB1407D73562C10F" - + "00A52830277958EE84D1315ED31886")); + + X9ECPoint G = configureBasepoint(curve, + "04009D73616F35F4AB1407D73562C10F00A52830277958EE84D1315ED31886"); return new X9ECParameters(curve, G, n, h, S); } @@ -515,16 +496,14 @@ public class SECNamedCurves BigInteger a = fromHex("00689918DBEC7E5A0DD6DFC0AA55C7"); BigInteger b = fromHex("0095E9A9EC9B297BD4BF36E059184F"); - byte[] S = Hex.decode("10C0FB15760860DEF1EEF4D696E676875615175D"); + byte[] S = Hex.decodeStrict("10C0FB15760860DEF1EEF4D696E676875615175D"); BigInteger n = fromHex("010000000000000108789B2496AF93"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "01A57A6A7B26CA5EF52FCDB8164797")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "01A57A6A7B26CA5EF52FCDB8164797" - + "00B3ADC94ED1FE674C06E695BABA1D")); + + X9ECPoint G = configureBasepoint(curve, + "0401A57A6A7B26CA5EF52FCDB816479700B3ADC94ED1FE674C06E695BABA1D"); return new X9ECParameters(curve, G, n, h, S); } @@ -544,16 +523,14 @@ public class SECNamedCurves BigInteger a = fromHex("07A11B09A76B562144418FF3FF8C2570B8"); BigInteger b = fromHex("0217C05610884B63B9C6C7291678F9D341"); - byte[] S = Hex.decode("4D696E676875615175985BD3ADBADA21B43A97E2"); + byte[] S = Hex.decodeStrict("4D696E676875615175985BD3ADBADA21B43A97E2"); BigInteger n = fromHex("0400000000000000023123953A9464B54D"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "0081BAF91FDF9833C40F9C181343638399")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "0081BAF91FDF9833C40F9C181343638399" - + "078C6E7EA38C001F73C8134B1B4EF9E150")); + + X9ECPoint G = configureBasepoint(curve, + "040081BAF91FDF9833C40F9C181343638399078C6E7EA38C001F73C8134B1B4EF9E150"); return new X9ECParameters(curve, G, n, h, S); } @@ -573,16 +550,14 @@ public class SECNamedCurves BigInteger a = fromHex("03E5A88919D7CAFCBF415F07C2176573B2"); BigInteger b = fromHex("04B8266A46C55657AC734CE38F018F2192"); - byte[] S = Hex.decode("985BD3ADBAD4D696E676875615175A21B43A97E3"); + byte[] S = Hex.decodeStrict("985BD3ADBAD4D696E676875615175A21B43A97E3"); BigInteger n = fromHex("0400000000000000016954A233049BA98F"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "0356DCD8F2F95031AD652D23951BB366A8")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "0356DCD8F2F95031AD652D23951BB366A8" - + "0648F06D867940A5366D9E265DE9EB240F")); + + X9ECPoint G = configureBasepoint(curve, + "040356DCD8F2F95031AD652D23951BB366A80648F06D867940A5366D9E265DE9EB240F"); return new X9ECParameters(curve, G, n, h, S); } @@ -607,11 +582,9 @@ public class SECNamedCurves BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8" - + "0289070FB05D38FF58321F2E800536D538CCDAA3D9")); + + X9ECPoint G = configureBasepoint(curve, + "0402FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE80289070FB05D38FF58321F2E800536D538CCDAA3D9"); return new X9ECParameters(curve, G, n, h, S); } @@ -631,16 +604,14 @@ public class SECNamedCurves BigInteger a = fromHex("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2"); BigInteger b = fromHex("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9"); - byte[] S = Hex.decode("24B7B137C8A14D696E6768756151756FD0DA2E5C"); + byte[] S = Hex.decodeStrict("24B7B137C8A14D696E6768756151756FD0DA2E5C"); BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "0369979697AB43897789566789567F787A7876A654")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "0369979697AB43897789566789567F787A7876A654" - + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883")); + + X9ECPoint G = configureBasepoint(curve, + "040369979697AB43897789566789567F787A7876A65400435EDB42EFAFB2989D51FEFCE3C80988F41FF883"); return new X9ECParameters(curve, G, n, h, S); } @@ -660,16 +631,14 @@ public class SECNamedCurves BigInteger a = BigInteger.valueOf(1); BigInteger b = fromHex("020A601907B8C953CA1481EB10512F78744A3205FD"); - byte[] S = Hex.decode("85E25BFE5C86226CDB12016F7553F9D0E693A268"); + byte[] S = Hex.decodeStrict("85E25BFE5C86226CDB12016F7553F9D0E693A268"); BigInteger n = fromHex("040000000000000000000292FE77E70C12A4234C33"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "03F0EBA16286A2D57EA0991168D4994637E8343E36" - + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1")); + + X9ECPoint G = configureBasepoint(curve, + "0403F0EBA16286A2D57EA0991168D4994637E8343E3600D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"); return new X9ECParameters(curve, G, n, h, S); } @@ -687,16 +656,14 @@ public class SECNamedCurves BigInteger a = fromHex("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01"); BigInteger b = fromHex("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814"); - byte[] S = Hex.decode("103FAEC74D696E676875615175777FC5B191EF30"); + byte[] S = Hex.decodeStrict("103FAEC74D696E676875615175777FC5B191EF30"); BigInteger n = fromHex("01000000000000000000000000C7F34A778F443ACC920EBA49"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1" - + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05")); + + X9ECPoint G = configureBasepoint(curve, + "0401F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E10025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"); return new X9ECParameters(curve, G, n, h, S); } @@ -714,16 +681,14 @@ public class SECNamedCurves BigInteger a = fromHex("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B"); BigInteger b = fromHex("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE"); - byte[] S = Hex.decode("10B7B4D696E676875615175137C8A16FD0DA2211"); + byte[] S = Hex.decodeStrict("10B7B4D696E676875615175137C8A16FD0DA2211"); BigInteger n = fromHex("010000000000000000000000015AAB561B005413CCD4EE99D5"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F" - + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C")); + + X9ECPoint G = configureBasepoint(curve, + "0400D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"); return new X9ECParameters(curve, G, n, h, S); } @@ -746,11 +711,9 @@ public class SECNamedCurves BigInteger h = BigInteger.valueOf(4); ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("02" - //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126" - + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3")); + + X9ECPoint G = configureBasepoint(curve, + "04017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD612601DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"); return new X9ECParameters(curve, G, n, h, S); } @@ -768,16 +731,14 @@ public class SECNamedCurves BigInteger a = BigInteger.valueOf(1); BigInteger b = fromHex("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD"); - byte[] S = Hex.decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3"); + byte[] S = Hex.decodeStrict("74D59FF07F6B413D0EA14B344B20A2DB049B50C3"); BigInteger n = fromHex("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B" - + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052")); + + X9ECPoint G = configureBasepoint(curve, + "0400FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"); return new X9ECParameters(curve, G, n, h, S); } @@ -800,11 +761,9 @@ public class SECNamedCurves BigInteger h = BigInteger.valueOf(4); ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC" - + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA")); + + X9ECPoint G = configureBasepoint(curve, + "0429A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"); return new X9ECParameters(curve, G, n, h, S); } @@ -829,11 +788,10 @@ public class SECNamedCurves BigInteger h = BigInteger.valueOf(4); ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("02" - //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + X9ECPoint G = configureBasepoint(curve, "04" + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836" - + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259")); + + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"); return new X9ECParameters(curve, G, n, h, S); } @@ -853,16 +811,15 @@ public class SECNamedCurves BigInteger a = BigInteger.valueOf(1); BigInteger b = fromHex("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5"); - byte[] S = Hex.decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE"); + byte[] S = Hex.decodeStrict("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE"); BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + X9ECPoint G = configureBasepoint(curve, "04" + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053" - + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4")); + + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"); return new X9ECParameters(curve, G, n, h, S); } @@ -885,11 +842,10 @@ public class SECNamedCurves BigInteger h = BigInteger.valueOf(4); ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + X9ECPoint G = configureBasepoint(curve, "04" + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746" - + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B")); + + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"); return new X9ECParameters(curve, G, n, h, S); } @@ -907,16 +863,15 @@ public class SECNamedCurves BigInteger a = BigInteger.valueOf(1); BigInteger b = fromHex("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F"); - byte[] S = Hex.decode("4099B5A457F9D69F79213D094C4BCD4D4262210B"); + byte[] S = Hex.decodeStrict("4099B5A457F9D69F79213D094C4BCD4D4262210B"); BigInteger n = fromHex("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + X9ECPoint G = configureBasepoint(curve, "04" + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7" - + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706")); + + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"); return new X9ECParameters(curve, G, n, h, S); } @@ -941,11 +896,10 @@ public class SECNamedCurves BigInteger h = BigInteger.valueOf(4); ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("02" - //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + X9ECPoint G = configureBasepoint(curve, "04" + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972" - + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3")); + + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"); return new X9ECParameters(curve, G, n, h, S); } @@ -965,16 +919,15 @@ public class SECNamedCurves BigInteger a = BigInteger.valueOf(1); BigInteger b = fromHex("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A"); - byte[] S = Hex.decode("2AA058F73A0E33AB486B0F610410C53A7F132310"); + byte[] S = Hex.decodeStrict("2AA058F73A0E33AB486B0F610410C53A7F132310"); BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47"); BigInteger h = BigInteger.valueOf(2); ECCurve curve = configureCurve(new ECCurve.F2m(m, k1, k2, k3, a, b, n, h)); - //ECPoint G = curve.decodePoint(Hex.decode("03" - //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19")); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + + X9ECPoint G = configureBasepoint(curve, "04" + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19" - + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B")); + + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"); return new X9ECParameters(curve, G, n, h, S); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java index a9ff74bd1..8072018f4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/sec/SECObjectIdentifiers.java @@ -9,6 +9,8 @@ import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; * ellipticCurve OBJECT IDENTIFIER ::= { * iso(1) identified-organization(3) certicom(132) curve(0) * } + * secg-scheme OBJECT IDENTIFIER ::= { + * iso(1) identified-organization(3) certicom(132) schemes(1) } *
*/ public interface SECObjectIdentifiers diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMEAttributes.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMEAttributes.java index 1d1f1e186..eb069dcb5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMEAttributes.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMEAttributes.java @@ -5,6 +5,6 @@ import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; public interface SMIMEAttributes { - public static final ASN1ObjectIdentifier smimeCapabilities = PKCSObjectIdentifiers.pkcs_9_at_smimeCapabilities; - public static final ASN1ObjectIdentifier encrypKeyPref = PKCSObjectIdentifiers.id_aa_encrypKeyPref; + ASN1ObjectIdentifier smimeCapabilities = PKCSObjectIdentifiers.pkcs_9_at_smimeCapabilities; + ASN1ObjectIdentifier encrypKeyPref = PKCSObjectIdentifiers.id_aa_encrypKeyPref; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMECapability.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMECapability.java index d42a27297..a05028c7a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMECapability.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMECapability.java @@ -89,7 +89,7 @@ public class SMIMECapability */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(capabilityID); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java index 828069e54..39fc72161 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/smime/SMIMECapabilityVector.java @@ -23,7 +23,7 @@ public class SMIMECapabilityVector ASN1ObjectIdentifier capability, int value) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(capability); v.add(new ASN1Integer(value)); @@ -35,7 +35,7 @@ public class SMIMECapabilityVector ASN1ObjectIdentifier capability, ASN1Encodable params) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(capability); v.add(params); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java index f57d35c3f..109bb95cf 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/teletrust/TeleTrusTNamedCurves.java @@ -9,6 +9,7 @@ import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParametersHolder; import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.WNafUtil; import com.fr.third.org.bouncycastle.util.Strings; import com.fr.third.org.bouncycastle.util.encoders.Hex; @@ -18,28 +19,40 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; */ public class TeleTrusTNamedCurves { + private static X9ECPoint configureBasepoint(ECCurve curve, String encoding) + { + X9ECPoint G = new X9ECPoint(curve, Hex.decodeStrict(encoding)); + WNafUtil.configureBasepoint(G.getPoint()); + return G; + } + private static ECCurve configureCurve(ECCurve curve) { return curve; } + private static BigInteger fromHex(String hex) + { + return new BigInteger(1, Hex.decodeStrict(hex)); + } + static X9ECParametersHolder brainpoolP160r1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("E95E4A5F737059DC60DF5991D45029409E60FC09"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q - new BigInteger("340E7BE2A280EB74E2BE61BADA745D97E8F7C300", 16), // a - new BigInteger("1E589A8595423412134FAA2DBDEC95C8D8675E58", 16), // b + fromHex("E95E4A5F737059DC60DFC7AD95B3D8139515620F"), // q + fromHex("340E7BE2A280EB74E2BE61BADA745D97E8F7C300"), // a + fromHex("1E589A8595423412134FAA2DBDEC95C8D8675E58"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G - n, h); + X9ECPoint G = configureBasepoint(curve, + "04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -47,20 +60,20 @@ public class TeleTrusTNamedCurves { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("E95E4A5F737059DC60DF5991D45029409E60FC09", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("E95E4A5F737059DC60DF5991D45029409E60FC09"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - // new BigInteger("24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B", 16), // Z - new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620F", 16), // q - new BigInteger("E95E4A5F737059DC60DFC7AD95B3D8139515620C", 16), // a' - new BigInteger("7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380", 16), // b' + //fromHex("24DBFF5DEC9B986BBFE5295A29BFBAE45E0F5D0B"), // Z + fromHex("E95E4A5F737059DC60DFC7AD95B3D8139515620F"), // q + fromHex("E95E4A5F737059DC60DFC7AD95B3D8139515620C"), // a + fromHex("7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G - n, h); + X9ECPoint G = configureBasepoint(curve, + "04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -68,19 +81,19 @@ public class TeleTrusTNamedCurves { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q - new BigInteger("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF", 16), // a - new BigInteger("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9", 16), // b + fromHex("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297"), // q + fromHex("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF"), // a + fromHex("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G - n, h); + X9ECPoint G = configureBasepoint(curve, + "04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -88,20 +101,20 @@ public class TeleTrusTNamedCurves { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("C302F41D932A36CDA7A3462F9E9E916B5BE8F1029AC4ACC1"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - //new BigInteger("1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB") //Z - new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297", 16), // q - new BigInteger("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294", 16), // a' - new BigInteger("13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79", 16), // b' + //fromHex("1B6F5CC8DB4DC7AF19458A9CB80DC2295E5EB9C3732104CB"), //Z + fromHex("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297"), // q + fromHex("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294"), // a + fromHex("13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G' - n, h); + X9ECPoint G = configureBasepoint(curve, + "043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -109,198 +122,208 @@ public class TeleTrusTNamedCurves { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q - new BigInteger("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43", 16), // a - new BigInteger("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B", 16), // b + fromHex("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF"), // q + fromHex("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43"), // a + fromHex("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G - n, h); + X9ECPoint G = configureBasepoint(curve, + "040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD"); + + return new X9ECParameters(curve, G, n, h); } }; + static X9ECParametersHolder brainpoolP224t1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - //new BigInteger("2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F") //Z - new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF", 16), // q - new BigInteger("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC", 16), // a' - new BigInteger("4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D", 16), // b' + //fromHex("2DF271E14427A346910CF7A2E6CFA7B3F484E5C2CCE1C8B730E28B3F"), // Z + fromHex("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF"), // q + fromHex("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC"), // a + fromHex("4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G' - n, h); + X9ECPoint G = configureBasepoint(curve, + "046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C"); + + return new X9ECParameters(curve, G, n, h); } }; + static X9ECParametersHolder brainpoolP256r1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q - new BigInteger("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9", 16), // a - new BigInteger("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6", 16), // b + fromHex("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377"), // q + fromHex("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9"), // a + fromHex("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G - n, h); + X9ECPoint G = configureBasepoint(curve, + "048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997"); + + return new X9ECParameters(curve, G, n, h); } }; + static X9ECParametersHolder brainpoolP256t1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("A9FB57DBA1EEA9BC3E660A909D838D718C397AA3B561A6F7901E0E82974856A7"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - //new BigInteger("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0") //Z - new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377", 16), // q - new BigInteger("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374", 16), // a' - new BigInteger("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04", 16), // b' + //fromHex("3E2D4BD9597B58639AE7AA669CAB9837CF5CF20A2C852D10F655668DFC150EF0"), // Z + fromHex("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377"), // q + fromHex("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374"), // a + fromHex("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G' - n, h); + X9ECPoint G = configureBasepoint(curve, + "04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE"); + + return new X9ECParameters(curve, G, n, h); } }; + static X9ECParametersHolder brainpoolP320r1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q - new BigInteger("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4", 16), // a - new BigInteger("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6", 16), // b + fromHex("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27"), // q + fromHex("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4"), // a + fromHex("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G - n, h); + X9ECPoint G = configureBasepoint(curve, + "0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1"); + + return new X9ECParameters(curve, G, n, h); } }; + static X9ECParametersHolder brainpoolP320t1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("D35E472036BC4FB7E13C785ED201E065F98FCFA5B68F12A32D482EC7EE8658E98691555B44C59311"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - //new BigInteger("15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18FEFC3E5AB7496F3C7B1") //Z - new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27", 16), // q - new BigInteger("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24", 16), // a' - new BigInteger("A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353", 16), // b' + //fromHex("15F75CAF668077F7E85B42EB01F0A81FF56ECD6191D55CB82B7D861458A18FEFC3E5AB7496F3C7B1"), // Z + fromHex("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27"), // q + fromHex("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24"), // a + fromHex("A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G' - n, h); + X9ECPoint G = configureBasepoint(curve, + "04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3"); + + return new X9ECParameters(curve, G, n, h); } }; + static X9ECParametersHolder brainpoolP384r1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q - new BigInteger("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826", 16), // a - new BigInteger("4A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11", 16), // b + fromHex("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53"), // q + fromHex("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826"), // a + fromHex("04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G - n, h); + X9ECPoint G = configureBasepoint(curve, + "041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315"); + + return new X9ECParameters(curve, G, n, h); } }; + static X9ECParametersHolder brainpoolP384t1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B31F166E6CAC0425A7CF3AB6AF6B7FC3103B883202E9046565"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - //new BigInteger("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C") //Z - new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53", 16), // q - new BigInteger("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50", 16), // a' - new BigInteger("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE", 16), // b' + //fromHex("41DFE8DD399331F7166A66076734A89CD0D2BCDB7D068E44E1F378F41ECBAE97D2D63DBC87BCCDDCCC5DA39E8589291C"), // Z + fromHex("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53"), // q + fromHex("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50"), // a + fromHex("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G' - n, h); + X9ECPoint G = configureBasepoint(curve, + "0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928"); + + return new X9ECParameters(curve, G, n, h); } }; + static X9ECParametersHolder brainpoolP512r1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q - new BigInteger("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA", 16), // a - new BigInteger("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723", 16), // b + fromHex("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3"), // q + fromHex("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA"), // a + fromHex("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G - n, h); + X9ECPoint G = configureBasepoint(curve, + "0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892"); + + return new X9ECParameters(curve, G, n, h); } }; + static X9ECParametersHolder brainpoolP512t1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069", 16); - BigInteger h = new BigInteger("01", 16); + BigInteger n = fromHex("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA70330870553E5C414CA92619418661197FAC10471DB1D381085DDADDB58796829CA90069"); + BigInteger h = BigInteger.valueOf(1); ECCurve curve = configureCurve(new ECCurve.Fp( - //new BigInteger("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB") //Z - new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3", 16), // q - new BigInteger("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0", 16), // a' - new BigInteger("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E", 16), // b' + //fromHex("12EE58E6764838B69782136F0F2D3BA06E27695716054092E60A80BEDB212B64E585D90BCE13761F85C3F1D2A64E3BE8FEA2220F01EBA5EEB0F35DBD29D922AB"), // Z + fromHex("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3"), // q + fromHex("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0"), // a + fromHex("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E"), // b n, h)); - return new X9ECParameters( - curve, - new X9ECPoint(curve, Hex.decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G' - n, h); + X9ECPoint G = configureBasepoint(curve, + "04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332"); + + return new X9ECParameters(curve, G, n, h); } }; + static final Hashtable objIds = new Hashtable(); static final Hashtable curves = new Hashtable(); static final Hashtable names = new Hashtable(); @@ -388,7 +411,7 @@ public class TeleTrusTNamedCurves * contained in this structure. */ public static Enumeration getNames() - { + { // we need to use names so we get the mixed case names. return names.elements(); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ASN1IntegerTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ASN1IntegerTest.java new file mode 100644 index 000000000..49ca27489 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ASN1IntegerTest.java @@ -0,0 +1,365 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1Enumerated; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Properties; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ASN1IntegerTest + extends SimpleTest +{ + private static final byte[] suspectKey = Base64.decode( + "MIGJAoGBAHNc+iExm94LUrJdPSJ4QJ9tDRuvaNmGVHpJ4X7a5zKI02v+2E7RotuiR2MHDJfVJkb9LUs2kb3XBlyENhtMLsbeH+3Muy3" + + "hGDlh/mLJSh1s4c5jDKBRYOHom7Uc8wP0P2+zBCA+OEdikNDFBaP5PbR2Xq9okG2kPh35M2quAiMTAgMBAAE="); + + public String getName() + { + return "ASN1Integer"; + } + + public void performTest() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + + ASN1Sequence.getInstance(suspectKey); + + testValidEncodingSingleByte(); + testValidEncodingMultiByte(); + testInvalidEncoding_00(); + testInvalidEncoding_ff(); + testInvalidEncoding_00_32bits(); + testInvalidEncoding_ff_32bits(); + //testLooseInvalidValidEncoding_FF_32B(); + //testLooseInvalidValidEncoding_zero_32B(); + testLooseValidEncoding_zero_32BAligned(); + testLooseValidEncoding_FF_32BAligned(); + testLooseValidEncoding_FF_32BAligned_1not0(); + testLooseValidEncoding_FF_32BAligned_2not0(); + testOversizedEncoding(); + + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + + new ASN1Integer(Hex.decode("ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e")); + + new ASN1Enumerated(Hex.decode("005a47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e")); + + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + + try + { + new ASN1Integer(Hex.decode("ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b")); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("malformed integer", e.getMessage()); + } + + isTrue(!Properties.setThreadOverride("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", true)); + + new ASN1Integer(Hex.decode("ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b")); + + isTrue(Properties.removeThreadOverride("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer")); + + try + { + ASN1Sequence.getInstance(suspectKey); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("test 1", "failed to construct sequence from byte[]: corrupted stream detected", e.getMessage()); + } + + try + { + new ASN1Integer(Hex.decode("ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e")); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("malformed integer", e.getMessage()); + } + + try + { + new ASN1Enumerated(Hex.decode("ffda47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e")); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("malformed enumerated", e.getMessage()); + } + + try + { + new ASN1Enumerated(Hex.decode("005a47bfc776bcd269da4832626ac332adfca6dd835e8ecd83cd1ebe7d709b0e")); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("malformed enumerated", e.getMessage()); + } + } + + /** + * Ensure existing single byte behavior. + */ + public void testValidEncodingSingleByte() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Without property, single byte. + // + byte[] rawInt = Hex.decode("10"); + ASN1Integer i = new ASN1Integer(rawInt); + isEquals(i.getValue().intValue(), 16); + isEquals(i.intValueExact(), 16); + + // + // With property set. + // + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + + rawInt = Hex.decode("10"); + i = new ASN1Integer(rawInt); + isEquals(i.getValue().intValue(), 16); + isEquals(i.intValueExact(), 16); + } + + public void testValidEncodingMultiByte() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Without property, single byte. + // + byte[] rawInt = Hex.decode("10FF"); + ASN1Integer i = new ASN1Integer(rawInt); + isEquals(i.getValue().intValue(), 4351); + isEquals(i.intValueExact(), 4351); + + // + // With property set. + // + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + + rawInt = Hex.decode("10FF"); + i = new ASN1Integer(rawInt); + isEquals(i.getValue().intValue(), 4351); + isEquals(i.intValueExact(), 4351); + } + + public void testInvalidEncoding_00() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + try + { + byte[] rawInt = Hex.decode("0010FF"); + new ASN1Integer(rawInt); + fail("Expecting illegal argument exception."); + } + catch (IllegalArgumentException e) + { + isEquals("malformed integer", e.getMessage()); + } + } + + public void testInvalidEncoding_ff() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + try + { + byte[] rawInt = Hex.decode("FF81FF"); + new ASN1Integer(rawInt); + fail("Expecting illegal argument exception."); + } + catch (IllegalArgumentException e) + { + isEquals("malformed integer", e.getMessage()); + } + } + + public void testInvalidEncoding_00_32bits() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Check what would pass loose validation fails outside of loose validation. + // + try + { + byte[] rawInt = Hex.decode("0000000010FF"); + new ASN1Integer(rawInt); + fail("Expecting illegal argument exception."); + } + catch (IllegalArgumentException e) + { + isEquals("malformed integer", e.getMessage()); + } + } + + public void testInvalidEncoding_ff_32bits() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Check what would pass loose validation fails outside of loose validation. + // + try + { + byte[] rawInt = Hex.decode("FFFFFFFF01FF"); + new ASN1Integer(rawInt); + fail("Expecting illegal argument exception."); + } + catch (IllegalArgumentException e) + { + isEquals("malformed integer", e.getMessage()); + } + } + + /* + Unfortunately it turns out that integers stored without sign bits that are assumed to be + unsigned.. this means a string of FF may occur and then the user will call getPositiveValue(). + Sigh.. + public void testLooseInvalidValidEncoding_zero_32B() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Should still fail as loose validation only permits 3 leading 0x00 bytes. + // + try + { + System.getProperties().put("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + byte[] rawInt = Hex.decode("0000000010FF"); + ASN1Integer i = new ASN1Integer(rawInt); + fail("Expecting illegal argument exception."); + } + catch (IllegalArgumentException e) + { + isEquals("malformed integer", e.getMessage()); + } + } + + public void testLooseInvalidValidEncoding_FF_32B() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Should still fail as loose validation only permits 3 leading 0xFF bytes. + // + try + { + System.getProperties().put("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + byte[] rawInt = Hex.decode("FFFFFFFF10FF"); + ASN1Integer i = new ASN1Integer(rawInt); + fail("Expecting illegal argument exception."); + } + catch (IllegalArgumentException e) + { + isEquals("malformed integer", e.getMessage()); + } + } + */ + + public void testLooseValidEncoding_zero_32BAligned() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Should pass as loose validation permits 3 leading 0x00 bytes. + // + + System.getProperties().put("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + byte[] rawInt = Hex.decode("00000010FF000000"); + ASN1Integer i = new ASN1Integer(rawInt); + isEquals(72997666816L, BigIntegers.longValueExact(i.getValue())); + } + + public void testLooseValidEncoding_FF_32BAligned() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Should pass as loose validation permits 3 + + System.getProperties().put("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + byte[] rawInt = Hex.decode("FFFFFF10FF000000"); + ASN1Integer i = new ASN1Integer(rawInt); + isEquals(-1026513960960L, BigIntegers.longValueExact(i.getValue())); + } + + public void testLooseValidEncoding_FF_32BAligned_1not0() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Should pass as loose validation permits 3 leading 0xFF bytes. + // + + System.getProperties().put("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + byte[] rawInt = Hex.decode("FFFEFF10FF000000"); + ASN1Integer i = new ASN1Integer(rawInt); + isEquals(-282501490671616L, BigIntegers.longValueExact(i.getValue())); + } + + public void testLooseValidEncoding_FF_32BAligned_2not0() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Should pass as loose validation permits 3 leading 0xFF bytes. + // + + System.getProperties().put("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + byte[] rawInt = Hex.decode("FFFFFE10FF000000"); + ASN1Integer i = new ASN1Integer(rawInt); + isEquals(-2126025588736L, BigIntegers.longValueExact(i.getValue())); + } + + public void testOversizedEncoding() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "false"); + // + // Should pass as loose validation permits 3 leading 0xFF bytes. + // + + System.getProperties().put("com.fr.third.org.bouncycastle.asn1.allow_unsafe_integer", "true"); + byte[] rawInt = Hex.decode("FFFFFFFE10FF000000000000"); + ASN1Integer i = new ASN1Integer(rawInt); + isEquals(new BigInteger(Hex.decode("FFFFFFFE10FF000000000000")), i.getValue()); + + rawInt = Hex.decode("FFFFFFFFFE10FF000000000000"); + try + { + new ASN1Integer(rawInt); + } + catch (IllegalArgumentException e) + { + isEquals("malformed integer", e.getMessage()); + } + } + + public static void main( + String[] args) + { + runTest(new ASN1IntegerTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ASN1UnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ASN1UnitTest.java new file mode 100644 index 000000000..168c0798a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ASN1UnitTest.java @@ -0,0 +1,89 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +import java.math.BigInteger; + +public abstract class ASN1UnitTest + extends SimpleTest +{ + protected void checkMandatoryField(String name, ASN1Encodable expected, ASN1Encodable present) + { + if (!expected.equals(present)) + { + fail(name + " field doesn't match."); + } + } + + protected void checkMandatoryField(String name, String expected, String present) + { + if (!expected.equals(present)) + { + fail(name + " field doesn't match."); + } + } + + protected void checkMandatoryField(String name, byte[] expected, byte[] present) + { + if (!areEqual(expected, present)) + { + fail(name + " field doesn't match."); + } + } + + protected void checkMandatoryField(String name, int expected, int present) + { + if (expected != present) + { + fail(name + " field doesn't match."); + } + } + + protected void checkOptionalField(String name, ASN1Encodable expected, ASN1Encodable present) + { + if (expected != null) + { + if (!expected.equals(present)) + { + fail(name + " field doesn't match."); + } + } + else if (present != null) + { + fail(name + " field found when none expected."); + } + } + + protected void checkOptionalField(String name, String expected, String present) + { + if (expected != null) + { + if (!expected.equals(present)) + { + fail(name + " field doesn't match."); + } + } + else if (present != null) + { + fail(name + " field found when none expected."); + } + } + + protected void checkOptionalField(String name, BigInteger expected, BigInteger present) + { + if (expected != null) + { + if (!expected.equals(present)) + { + fail(name + " field doesn't match."); + } + } + else if (present != null) + { + fail(name + " field found when none expected."); + } + } + + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AdditionalInformationSyntaxUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AdditionalInformationSyntaxUnitTest.java new file mode 100644 index 000000000..53b35e52d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AdditionalInformationSyntaxUnitTest.java @@ -0,0 +1,69 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1String; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.AdditionalInformationSyntax; +import com.fr.third.org.bouncycastle.asn1.x500.DirectoryString; + +public class AdditionalInformationSyntaxUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "AdditionalInformationSyntax"; + } + + public void performTest() + throws Exception + { + AdditionalInformationSyntax syntax = new AdditionalInformationSyntax("hello world"); + + checkConstruction(syntax, new DirectoryString("hello world")); + + try + { + AdditionalInformationSyntax.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + AdditionalInformationSyntax syntax, + DirectoryString information) + throws IOException + { + checkValues(syntax, information); + + syntax = AdditionalInformationSyntax.getInstance(syntax); + + checkValues(syntax, information); + + ASN1InputStream aIn = new ASN1InputStream(syntax.toASN1Primitive().getEncoded()); + + ASN1String info = (ASN1String)aIn.readObject(); + + syntax = AdditionalInformationSyntax.getInstance(info); + + checkValues(syntax, information); + } + + private void checkValues( + AdditionalInformationSyntax syntax, + DirectoryString information) + { + checkMandatoryField("information", information, syntax.getInformation()); + } + + public static void main( + String[] args) + { + runTest(new AdditionalInformationSyntaxUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AdmissionSyntaxUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AdmissionSyntaxUnitTest.java new file mode 100644 index 000000000..a79ca5012 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AdmissionSyntaxUnitTest.java @@ -0,0 +1,97 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.AdmissionSyntax; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.Admissions; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.NamingAuthority; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.ProfessionInfo; +import com.fr.third.org.bouncycastle.asn1.x500.DirectoryString; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; + +public class AdmissionSyntaxUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "AdmissionSyntax"; + } + + public void performTest() + throws Exception + { + GeneralName name = new GeneralName(new X500Name("CN=hello world")); + ASN1Sequence admissions = new DERSequence( + new Admissions(name, + new NamingAuthority(new ASN1ObjectIdentifier("1.2.3"), "url", new DirectoryString("fred")), + new ProfessionInfo[0])); + AdmissionSyntax syntax = new AdmissionSyntax(name, admissions); + + checkConstruction(syntax, name, admissions); + + syntax = AdmissionSyntax.getInstance(null); + + if (syntax != null) + { + fail("null getInstance() failed."); + } + + try + { + AdmissionSyntax.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + AdmissionSyntax syntax, + GeneralName authority, + ASN1Sequence admissions) + throws IOException + { + checkValues(syntax, authority, admissions); + + syntax = AdmissionSyntax.getInstance(syntax); + + checkValues(syntax, authority, admissions); + + ASN1InputStream aIn = new ASN1InputStream(syntax.toASN1Primitive().getEncoded()); + + ASN1Sequence info = (ASN1Sequence)aIn.readObject(); + + syntax = AdmissionSyntax.getInstance(info); + + checkValues(syntax, authority, admissions); + } + + private void checkValues( + AdmissionSyntax syntax, + GeneralName authority, + ASN1Sequence admissions) + { + checkMandatoryField("admissionAuthority", authority, syntax.getAdmissionAuthority()); + + Admissions[] adm = syntax.getContentsOfAdmissions(); + + if (adm.length != 1 || !adm[0].equals(admissions.getObjectAt(0))) + { + fail("admissions check failed"); + } + } + + public static void main( + String[] args) + { + runTest(new AdmissionSyntaxUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AdmissionsUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AdmissionsUnitTest.java new file mode 100644 index 000000000..cc17b56b2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AdmissionsUnitTest.java @@ -0,0 +1,86 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.Admissions; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.NamingAuthority; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.ProfessionInfo; +import com.fr.third.org.bouncycastle.asn1.x500.DirectoryString; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; + +public class AdmissionsUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "Admissions"; + } + + public void performTest() + throws Exception + { + GeneralName name = new GeneralName(new X500Name("CN=hello world")); + NamingAuthority auth = new NamingAuthority(new ASN1ObjectIdentifier("1.2.3"), "url", new DirectoryString("fred")); + Admissions admissions = new Admissions(name, auth, new ProfessionInfo[0]); + + checkConstruction(admissions, name, auth); + + admissions = Admissions.getInstance(null); + + if (admissions != null) + { + fail("null getInstance() failed."); + } + + try + { + Admissions.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + Admissions admissions, + GeneralName name, + NamingAuthority auth) + throws IOException + { + checkValues(admissions, name, auth); + + admissions = Admissions.getInstance(admissions); + + checkValues(admissions, name, auth); + + ASN1InputStream aIn = new ASN1InputStream(admissions.toASN1Primitive().getEncoded()); + + ASN1Sequence info = (ASN1Sequence)aIn.readObject(); + + admissions = Admissions.getInstance(info); + + checkValues(admissions, name, auth); + } + + private void checkValues( + Admissions admissions, + GeneralName name, + NamingAuthority auth) + { + checkMandatoryField("admissionAuthority", name, admissions.getAdmissionAuthority()); + checkMandatoryField("namingAuthority", auth, admissions.getNamingAuthority()); + } + + public static void main( + String[] args) + { + runTest(new AdmissionsUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AttributeTableUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AttributeTableUnitTest.java new file mode 100644 index 000000000..f16f25e6a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/AttributeTableUnitTest.java @@ -0,0 +1,144 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.util.Hashtable; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.cms.Attribute; +import com.fr.third.org.bouncycastle.asn1.cms.AttributeTable; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class AttributeTableUnitTest + extends SimpleTest +{ + private static final ASN1ObjectIdentifier type1 = new ASN1ObjectIdentifier("1.1.1"); + private static final ASN1ObjectIdentifier type2 = new ASN1ObjectIdentifier("1.1.2"); + private static final ASN1ObjectIdentifier type3 = new ASN1ObjectIdentifier("1.1.3"); + + public String getName() + { + return "AttributeTable"; + } + + public void performTest() + throws Exception + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new Attribute(type1, new DERSet(type1))); + v.add(new Attribute(type2, new DERSet(type2))); + + AttributeTable table = new AttributeTable(v); + + Attribute a = table.get(type1); + if (a == null) + { + fail("type1 attribute not found."); + } + if (!a.getAttrValues().equals(new DERSet(type1))) + { + fail("wrong value retrieved for type1!"); + } + + a = table.get(type2); + if (a == null) + { + fail("type2 attribute not found."); + } + if (!a.getAttrValues().equals(new DERSet(type2))) + { + fail("wrong value retrieved for type2!"); + } + + a = table.get(type3); + if (a != null) + { + fail("type3 attribute found when none expected."); + } + + ASN1EncodableVector vec = table.getAll(type1); + if (vec.size() != 1) + { + fail("wrong vector size for type1."); + } + + vec = table.getAll(type3); + if (vec.size() != 0) + { + fail("wrong vector size for type3."); + } + + vec = table.toASN1EncodableVector(); + if (vec.size() != 2) + { + fail("wrong vector size for single."); + } + + Hashtable t = table.toHashtable(); + + if (t.size() != 2) + { + fail("hashtable wrong size."); + } + + // multiple + + v = new ASN1EncodableVector(); + + v.add(new Attribute(type1, new DERSet(type1))); + v.add(new Attribute(type1, new DERSet(type2))); + v.add(new Attribute(type1, new DERSet(type3))); + v.add(new Attribute(type2, new DERSet(type2))); + + table = new AttributeTable(v); + + a = table.get(type1); + if (!a.getAttrValues().equals(new DERSet(type1))) + { + fail("wrong value retrieved for type1 multi get!"); + } + + vec = table.getAll(type1); + if (vec.size() != 3) + { + fail("wrong vector size for multiple type1."); + } + + a = (Attribute)vec.get(0); + if (!a.getAttrValues().equals(new DERSet(type1))) + { + fail("wrong value retrieved for type1(0)!"); + } + + a = (Attribute)vec.get(1); + if (!a.getAttrValues().equals(new DERSet(type2))) + { + fail("wrong value retrieved for type1(1)!"); + } + + a = (Attribute)vec.get(2); + if (!a.getAttrValues().equals(new DERSet(type3))) + { + fail("wrong value retrieved for type1(2)!"); + } + + vec = table.getAll(type2); + if (vec.size() != 1) + { + fail("wrong vector size for multiple type2."); + } + + vec = table.toASN1EncodableVector(); + if (vec.size() != 4) + { + fail("wrong vector size for multiple."); + } + } + + public static void main( + String[] args) + { + runTest(new AttributeTableUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BiometricDataUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BiometricDataUnitTest.java new file mode 100644 index 000000000..c06712f0e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BiometricDataUnitTest.java @@ -0,0 +1,133 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DERIA5String; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.qualified.BiometricData; +import com.fr.third.org.bouncycastle.asn1.x509.qualified.TypeOfBiometricData; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class BiometricDataUnitTest + extends SimpleTest +{ + public String getName() + { + return "BiometricData"; + } + + private byte[] generateHash() + { + SecureRandom rand = new SecureRandom(); + byte[] bytes = new byte[20]; + + rand.nextBytes(bytes); + + return bytes; + } + + public void performTest() + throws Exception + { + TypeOfBiometricData dataType = new TypeOfBiometricData(TypeOfBiometricData.HANDWRITTEN_SIGNATURE); + AlgorithmIdentifier hashAlgorithm = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE); + ASN1OctetString dataHash = new DEROctetString(generateHash()); + BiometricData bd = new BiometricData(dataType, hashAlgorithm, dataHash); + + checkConstruction(bd, dataType, hashAlgorithm, dataHash, null); + + DERIA5String dataUri = new DERIA5String("http://test"); + + bd = new BiometricData(dataType, hashAlgorithm, dataHash, dataUri); + + checkConstruction(bd, dataType, hashAlgorithm, dataHash, dataUri); + + bd = BiometricData.getInstance(null); + + if (bd != null) + { + fail("null getInstance() failed."); + } + + try + { + BiometricData.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + BiometricData bd, + TypeOfBiometricData dataType, + AlgorithmIdentifier hashAlgorithm, + ASN1OctetString dataHash, + DERIA5String dataUri) + throws Exception + { + checkValues(bd, dataType, hashAlgorithm, dataHash, dataUri); + + bd = BiometricData.getInstance(bd); + + checkValues(bd, dataType, hashAlgorithm, dataHash, dataUri); + + ASN1InputStream aIn = new ASN1InputStream(bd.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + bd = BiometricData.getInstance(seq); + + checkValues(bd, dataType, hashAlgorithm, dataHash, dataUri); + } + + private void checkValues( + BiometricData bd, + TypeOfBiometricData dataType, + AlgorithmIdentifier algID, + ASN1OctetString dataHash, + DERIA5String sourceDataURI) + { + if (!bd.getTypeOfBiometricData().equals(dataType)) + { + fail("types don't match."); + } + + if (!bd.getHashAlgorithm().equals(algID)) + { + fail("hash algorithms don't match."); + } + + if (!bd.getBiometricDataHash().equals(dataHash)) + { + fail("hash algorithms don't match."); + } + + if (sourceDataURI != null) + { + if (!bd.getSourceDataUri().equals(sourceDataURI)) + { + fail("data uris don't match."); + } + } + else if (bd.getSourceDataUri() != null) + { + fail("data uri found when none expected."); + } + } + + public static void main( + String[] args) + { + runTest(new BiometricDataUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BitStringConstantTester.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BitStringConstantTester.java new file mode 100644 index 000000000..260e44f1d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BitStringConstantTester.java @@ -0,0 +1,22 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +public class BitStringConstantTester +{ + private static final int[] bits = + { + 1 << 7, 1 << 6, 1 << 5, 1 << 4, 1 << 3, 1 << 2, 1 << 1, 1 << 0, + 1 << 15, 1 << 14, 1 << 13, 1 << 12, 1 << 11, 1 << 10, 1 << 9, 1 << 8, + 1 << 23, 1 << 22, 1 << 21, 1 << 20, 1 << 19, 1 << 18, 1 << 17, 1 << 16, + 1 << 31, 1 << 30, 1 << 29, 1 << 28, 1 << 27, 1 << 26, 1 << 25, 1 << 24 + }; + + public static void testFlagValueCorrect( + int bitNo, + int value) + { + if (bits[bitNo] != value) + { + throw new IllegalArgumentException("bit value " + bitNo + " wrong"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BitStringTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BitStringTest.java new file mode 100644 index 000000000..1143c95ec --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BitStringTest.java @@ -0,0 +1,185 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1BitString; +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DLBitString; +import com.fr.third.org.bouncycastle.asn1.x509.KeyUsage; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class BitStringTest + extends SimpleTest +{ + private void testZeroLengthStrings() + throws Exception + { + // basic construction + DERBitString s1 = new DERBitString(new byte[0], 0); + + // check getBytes() + s1.getBytes(); + + // check encoding/decoding + DERBitString derBit = (DERBitString)ASN1Primitive.fromByteArray(s1.getEncoded()); + + if (!Arrays.areEqual(s1.getEncoded(), Hex.decode("030100"))) + { + fail("zero encoding wrong"); + } + + try + { + new DERBitString(null, 1); + fail("exception not thrown"); + } + catch (NullPointerException e) + { + if (!"'data' cannot be null".equals(e.getMessage())) + { + fail("Unexpected exception: " + e.getMessage()); + } + } + + try + { + new DERBitString(new byte[0], 1); + fail("exception not thrown"); + } + catch (IllegalArgumentException e) + { + if (!"zero length data with non-zero pad bits".equals(e.getMessage())) + { + fail("Unexpected exception"); + } + } + + try + { + new DERBitString(new byte[1], 8); + fail("exception not thrown"); + } + catch (IllegalArgumentException e) + { + if (!"pad bits cannot be greater than 7 or less than 0".equals(e.getMessage())) + { + fail("Unexpected exception"); + } + } + + DERBitString s2 = new DERBitString(0); + if (!Arrays.areEqual(s1.getEncoded(), s2.getEncoded())) + { + fail("zero encoding wrong"); + } + } + + private void testRandomPadBits() + throws Exception + { + byte[] test = Hex.decode("030206c0"); + + byte[] test1 = Hex.decode("030206f0"); + byte[] test2 = Hex.decode("030206c1"); + byte[] test3 = Hex.decode("030206c7"); + byte[] test4 = Hex.decode("030206d1"); + + encodingCheck(test, test1); + encodingCheck(test, test2); + encodingCheck(test, test3); + encodingCheck(test, test4); + } + + private void encodingCheck(byte[] derData, byte[] dlData) + throws IOException + { + if (Arrays.areEqual(derData, ASN1Primitive.fromByteArray(dlData).getEncoded())) + { + fail("failed DL check"); + } + ASN1BitString dl = DLBitString.getInstance(dlData); + + isTrue("DL test failed", dl instanceof DLBitString); + if (!Arrays.areEqual(derData, ASN1Primitive.fromByteArray(dlData).getEncoded(ASN1Encoding.DER))) + { + fail("failed DER check"); + } + try + { + DERBitString.getInstance(dlData); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + // ignore + } + ASN1BitString der = DERBitString.getInstance(derData); + isTrue("DER test failed", der instanceof DERBitString); + } + + public void performTest() + throws Exception + { + KeyUsage k = new KeyUsage(KeyUsage.digitalSignature); + if ((k.getBytes()[0] != (byte)KeyUsage.digitalSignature) || (k.getPadBits() != 7)) + { + fail("failed digitalSignature"); + } + + k = new KeyUsage(KeyUsage.nonRepudiation); + if ((k.getBytes()[0] != (byte)KeyUsage.nonRepudiation) || (k.getPadBits() != 6)) + { + fail("failed nonRepudiation"); + } + + k = new KeyUsage(KeyUsage.keyEncipherment); + if ((k.getBytes()[0] != (byte)KeyUsage.keyEncipherment) || (k.getPadBits() != 5)) + { + fail("failed keyEncipherment"); + } + + k = new KeyUsage(KeyUsage.cRLSign); + if ((k.getBytes()[0] != (byte)KeyUsage.cRLSign) || (k.getPadBits() != 1)) + { + fail("failed cRLSign"); + } + + k = new KeyUsage(KeyUsage.decipherOnly); + if ((k.getBytes()[1] != (byte)(KeyUsage.decipherOnly >> 8)) || (k.getPadBits() != 7)) + { + fail("failed decipherOnly"); + } + + // test for zero length bit string + try + { + ASN1Primitive.fromByteArray(new DERBitString(new byte[0], 0).getEncoded()); + } + catch (IOException e) + { + fail(e.toString()); + } + + testRandomPadBits(); + testZeroLengthStrings(); + } + + public String getName() + { + return "BitString"; + } + + public static void main( + String[] args) + { + BitStringTest test = new BitStringTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartIDTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartIDTest.java new file mode 100644 index 000000000..075cba782 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartIDTest.java @@ -0,0 +1,97 @@ +package com.fr.third.org.bouncycastle.asn1.test; + + +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class BodyPartIDTest + extends SimpleTest +{ + + + public void performTest() + throws Exception + { + // Test correct encode / decode + + + { + // Test encode and decode from Long and from other instance of BodyPartID + BodyPartID bpd = new BodyPartID(10L); + byte[] b = bpd.getEncoded(); + BodyPartID resBpd = BodyPartID.getInstance(b); + isEquals("Correct / Encode byte array", resBpd.getID(), bpd.getID()); + + BodyPartID rootPartID = new BodyPartID(12L); + bpd = BodyPartID.getInstance(rootPartID); + b = bpd.getEncoded(); + resBpd = BodyPartID.getInstance(b); + isEquals("Correct / Encode byte array", resBpd.getID(), rootPartID.getID()); + } + + + { + // Test lower limit, should not throw exception + try + { + new BodyPartID(0); + } + catch (Throwable t) + { + fail("Unexpected exception: " + t.getMessage(), t); + } + + // Test below lower range + try + { + new BodyPartID(-1); + fail("Expecting IllegalArgumentException because of outside lower range"); + } + catch (Throwable e) + { + if (!(e instanceof IllegalArgumentException)) + { + fail("Expecting only IllegalArgumentException, got:" + e.getMessage(), e); + } + } + } + + { + // Test upper limit, should not throw exception. + try + { + new BodyPartID(4294967295L); + } + catch (Throwable t) + { + fail("Unexpected exception: " + t.getMessage(), t); + } + + // Test above upper range + try + { + new BodyPartID(4294967296L); + fail("Expecting IllegalArgumentException because of outside upper range"); + } + catch (Throwable e) + { + if (!(e instanceof IllegalArgumentException)) + { + fail("Expecting only IllegalArgumentException, got:" + e.getMessage(), e); + } + } + } + } + + public String getName() + { + return "BodyPartIDTest"; + } + + public static void main(String[] args) + throws Exception + { + runTest(new BodyPartIDTest()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartListTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartListTest.java new file mode 100644 index 000000000..699843d10 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartListTest.java @@ -0,0 +1,71 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.util.Random; + +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartList; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +/** + * Test the creation of BodyPartListTest and encoding and decoding. + */ +public class BodyPartListTest + extends SimpleTest +{ + + public void performTest() + throws Exception + { + Random rand = new Random(); + { + BodyPartID[] bpid = new BodyPartID[Math.abs(rand.nextInt()) % 20]; + for (int t = 0; t < bpid.length; t++) + { + bpid[t] = new BodyPartID(Math.abs(rand.nextLong() % 4294967295L)); + } + BodyPartList bpl = new BodyPartList(bpid); + DERSequence _bpl = (DERSequence)bpl.toASN1Primitive(); + byte[] b = bpl.getEncoded(); + + // + // Decode and compare results. + // + + BodyPartList resList = BodyPartList.getInstance(b); + DERSequence _resList = (DERSequence)resList.toASN1Primitive(); + + isEquals(_bpl.size(), _resList.size()); + + for (int j = 0; j < _bpl.size(); j++) + { + isEquals(_resList.getObjectAt(j), _bpl.getObjectAt(j)); + } + } + { + // + // Compare when same thing instantiated via different constructors. + // + + BodyPartID bpid = new BodyPartID(Math.abs(rand.nextLong() % 4294967295L)); + BodyPartList bpidList = new BodyPartList(bpid); // Single entry constructor. + BodyPartList resList = new BodyPartList(new BodyPartID[]{bpid}); // Array constructor. + + DERSequence _bpidList = (DERSequence)bpidList.toASN1Primitive(); + DERSequence _resList = (DERSequence)resList.toASN1Primitive(); + + isEquals(_bpidList, _resList); + } + } + + public String getName() + { + return "BodyPartListTest"; + } + + public static void main(String[] args) + { + runTest(new BodyPartListTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartPathTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartPathTest.java new file mode 100644 index 000000000..9468f3275 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartPathTest.java @@ -0,0 +1,69 @@ +package com.fr.third.org.bouncycastle.asn1.test; + + +import java.util.Random; + +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartPath; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class BodyPartPathTest + extends SimpleTest +{ + + public void performTest() + throws Exception + { + Random rand = new Random(); + { + BodyPartID[] bpid = new BodyPartID[Math.abs(rand.nextInt()) % 20]; + for (int t = 0; t < bpid.length; t++) + { + bpid[t] = new BodyPartID(Math.abs(rand.nextLong() % 4294967295L)); + } + BodyPartPath bpp = new BodyPartPath(bpid); + DERSequence _bpp = (DERSequence)bpp.toASN1Primitive(); + byte[] b = bpp.getEncoded(); + + // + // Decode and compare results. + // + + BodyPartPath resList = BodyPartPath.getInstance(b); + DERSequence _resList = (DERSequence)resList.toASN1Primitive(); + + isEquals(_bpp.size(), _resList.size()); + + for (int j = 0; j < _bpp.size(); j++) + { + isEquals(_resList.getObjectAt(j), _bpp.getObjectAt(j)); + } + } + { + // + // Compare when same thing instantiated via different constructors. + // + + BodyPartID bpid = new BodyPartID(Math.abs(rand.nextLong() % 4294967295L)); + BodyPartPath bpidList = new BodyPartPath(bpid); // Single entry constructor. + BodyPartPath resList = new BodyPartPath(new BodyPartID[]{bpid}); // Array constructor. + + DERSequence _bpidList = (DERSequence)bpidList.toASN1Primitive(); + DERSequence _resList = (DERSequence)resList.toASN1Primitive(); + + isEquals(_bpidList, _resList); + } + } + + public String getName() + { + return "BodyPartPathTest"; + } + + public static void main(String[] args) + { + runTest(new BodyPartPathTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartReferenceTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartReferenceTest.java new file mode 100644 index 000000000..cfa26542a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/BodyPartReferenceTest.java @@ -0,0 +1,79 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.util.Random; + +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartPath; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartReference; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class BodyPartReferenceTest + extends SimpleTest +{ + + public String getName() + { + return "BodyPartReferenceTest"; + } + + public void performTest() + throws Exception + { + Random rand = new Random(); + BodyPartReference ch0 = null; + BodyPartReference ch1 = null; + { + // Choice 1 + BodyPartID id = new BodyPartID(Math.abs(rand.nextLong() % 4294967295L)); + + ch0 = new BodyPartReference(id); + byte[] b = ch0.getEncoded(); + + BodyPartReference brRes = BodyPartReference.getInstance(b); + isEquals(brRes, ch0); + } + + { + // Choice 2 + + BodyPartID[] bpid = new BodyPartID[Math.abs(rand.nextInt()) % 20]; + for (int t = 0; t < bpid.length; t++) + { + bpid[t] = new BodyPartID(Math.abs(rand.nextLong() % 4294967295L)); + } + + ch1 = new BodyPartReference(new BodyPartPath(bpid)); + byte[] b = ch1.getEncoded(); + + BodyPartReference brRes = BodyPartReference.getInstance(b); + isEquals(brRes, ch1); + } + + + { + // Test choice alternatives are not equal. + BodyPartID id = new BodyPartID(Math.abs(rand.nextLong() % 4294967295L)); + + ch0 = new BodyPartReference(id); + ch1 = new BodyPartReference(new BodyPartPath(id)); + + try + { + isEquals(ch0, ch1); + fail("Must not be equal."); + } + catch (Throwable t) + { + // Ignored + } + } + + } + + public static void main(String[] args) + { + runTest(new BodyPartReferenceTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/CMCCertificationRequestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/CMCCertificationRequestTest.java new file mode 100644 index 000000000..b5717db6d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/CMCCertificationRequestTest.java @@ -0,0 +1,76 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.cmc.CertificationRequest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class CMCCertificationRequestTest + extends SimpleTest +{ + byte[] req1 = Base64.decode( + "MIHoMIGTAgEAMC4xDjAMBgNVBAMTBVRlc3QyMQ8wDQYDVQQKEwZBbmFUb20xCzAJBgNVBAYTAlNF" + + "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALlEt31Tzt2MlcOljvacJgzQVhmlMoqAOgqJ9Pgd3Gux" + + "Z7/WcIlgW4QCB7WZT21O1YoghwBhPDMcNGrHei9kHQkCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA0EA" + + "NDEI4ecNtJ3uHwGGlitNFq9WxcoZ0djbQJ5hABMotav6gtqlrwKXY2evaIrsNwkJtNdwwH18aQDU" + + "KCjOuBL38Q=="); + + byte[] req2 = Base64.decode( + "MIIB6TCCAVICAQAwgagxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQH" + + "EwtTYW50YSBDbGFyYTEMMAoGA1UEChMDQUJCMVEwTwYDVQQLHEhQAAAAAAAAAG8AAAAAAAAAdwAA" + + "AAAAAABlAAAAAAAAAHIAAAAAAAAAIAAAAAAAAABUAAAAAAAAABxIAAAAAAAARAAAAAAAAAAxDTAL" + + "BgNVBAMTBGJsdWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANETRZ+6occCOrFxNhfKIp4C" + + "mMkxwhBNb7TnnahpbM9O0r4hrBPcfYuL7u9YX/jN0YNUP+/CiT39HhSe/bikaBPDEyNsl988I8vX" + + "piEdgxYq/+LTgGHbjRsRYCkPtmzwBbuBldNF8bV7pu0v4UScSsExmGqqDlX1TbPU8KkPU1iTAgMB" + + "AAGgADANBgkqhkiG9w0BAQQFAAOBgQAFbrs9qUwh93CtETk7DeUD5HcdCnxauo1bck44snSV6MZV" + + "OCIGaYu1501kmhEvAtVVRr6SEHwimfQDDIjnrWwYsEr/DT6tkTZAbfRd3qUu3iKjT0H0vlUZp0hJ" + + "66mINtBM84uZFBfoXiWY8M3FuAnGmvy6ah/dYtJorTxLKiGkew=="); + + public String getName() + { + return "CMCCertificationRequestTest"; + } + + public void certReqTest( + String testName, + byte[] req) + throws Exception + { + CertificationRequest r = CertificationRequest.getInstance(req); + + byte[] bytes = r.getEncoded(ASN1Encoding.DER); + + if (bytes.length != req.length) + { + fail(testName + " failed length test"); + } + + for (int i = 0; i != req.length; i++) + { + if (bytes[i] != req[i]) + { + fail(testName + " failed comparison test"); + } + } + } + + public void performTest() + throws Exception + { + certReqTest("req1", req1); + certReqTest("req2", req2); + + CertificationRequest a = CertificationRequest.getInstance(req1); + CertificationRequest b = new CertificationRequest(a.getSubject(), a.getSubjectPublicKeyAlgorithm(), a.getSubjectPublicKey(), a.getAttributes(), a.getSignatureAlgorithm(), a.getSignature()); + + isTrue(Arrays.areEqual(a.getEncoded(), b.getEncoded())); + } + + + public static void main( + String[] args) + { + runTest(new CMCCertificationRequestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/CMCFailInfoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/CMCFailInfoTest.java new file mode 100644 index 000000000..6a8bf930d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/CMCFailInfoTest.java @@ -0,0 +1,96 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.lang.reflect.Field; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.cmc.CMCFailInfo; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class CMCFailInfoTest + extends SimpleTest +{ + + // From Page 68, CMC: Structures RFC 5272 + private static Object[][] types = new Object[][]{ + {"badAlg", new Long(0L) }, + {"badMessageCheck", new Long(1L) }, + {"badRequest", new Long(2L) }, + {"badTime", new Long(3L) }, + {"badCertId", new Long(4L) }, + {"unsupportedExt", new Long(5L) }, + {"mustArchiveKeys", new Long(6L) }, + {"badIdentity", new Long(7L) }, + {"popRequired", new Long(8L) }, + {"popFailed", new Long(9L) }, + {"noKeyReuse", new Long(10L) }, + {"internalCAError", new Long(11L) }, + {"tryLater", new Long(12L) }, + {"authDataFail", new Long(13L)} + }; + private static Map typesMap = new HashMap(); + + static + { + for (int t = 0; t < types.length; t++) + { + typesMap.put(types[t][1], types[t][0]); + } + } + + + public void performTest() + throws Exception + { + + // + // Check that range has changed and this test has not been updated or vice versa. + // It is intended to act as a double check on the addition of CMCFailInfo presets by + // requiring this test to be updated equally to ensure it will pass. + // + + Field rangeField = CMCFailInfo.class.getDeclaredField("range"); + rangeField.setAccessible(true); + + Map range = (Map)rangeField.get(null); + + isEquals("Range in CMCFailInfo does not match test data.",range.size(), types.length); + + for (Iterator rangeKeys = range.keySet().iterator(); rangeKeys.hasNext(); ) + { Object j = rangeKeys.next(); + if (!typesMap.containsKey(new Long(((ASN1Integer)j).getValue().longValue()))) { + fail("The 'range' map in CMCFailInfo contains a value not in the test ('typesMap') map, value was: "+j.toString()); + } + } + + + for (Iterator typeKeys = typesMap.keySet().iterator(); typeKeys.hasNext(); ) + { Object j = typeKeys.next(); + if (!range.containsKey(new ASN1Integer(((Long)j).longValue()))) { + fail("The 'typesMap' map in CMCFailInfoTest contains a value not in the CMCFailInfo ('range') map, value was: "+j.toString()); + } + } + + + // + // Test encoding / decoding + // + + byte[] b = CMCFailInfo.authDataFail.getEncoded(); + CMCFailInfo r = CMCFailInfo.getInstance(b); + isEquals(r,CMCFailInfo.authDataFail); + + } + + public String getName() + { + return "CMCFailInfoTest"; + } + + public static void main(String[] args) + { + runTest(new CMCFailInfoTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/CMCPublicationInfoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/CMCPublicationInfoTest.java new file mode 100644 index 000000000..274b2cbfa --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/CMCPublicationInfoTest.java @@ -0,0 +1,67 @@ +package com.fr.third.org.bouncycastle.asn1.test; + + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.CMCPublicationInfo; +import com.fr.third.org.bouncycastle.asn1.crmf.PKIPublicationInfo; +import com.fr.third.org.bouncycastle.asn1.crmf.SinglePubInfo; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class CMCPublicationInfoTest + extends SimpleTest +{ + + public void performTest() + throws Exception + { + SecureRandom secureRandom = new SecureRandom(); + + // + // Test encode and decode. + // + + // Not a real AlgorithmIdentifier + AlgorithmIdentifier testIA = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.1.2.3"), DERNull.INSTANCE); + byte[][] hashes = new byte[5][64]; + for(int i =0; i + * RSA's PKCS5 Page. + *
+ * The vectors are Base 64 encoded and encrypted using the password "password" + * (without quotes). They should all yield the same PrivateKeyInfo object. + */ +public class EncryptedPrivateKeyInfoTest + extends SimpleTest +{ + static byte[] sample1 = Base64.decode( + "MIIBozA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIfWBDXwLp4K4CAggA" + + "MBEGBSsOAwIHBAiaCF/AvOgQ6QSCAWDWX4BdAzCRNSQSANSuNsT5X8mWYO27mr3Y" + + "9c9LoBVXGNmYWKA77MI4967f7SmjNcgXj3xNE/jmnVz6hhsjS8E5VPT3kfyVkpdZ" + + "0lr5e9Yk2m3JWpPU7++v5zBkZmC4V/MwV/XuIs6U+vykgzMgpxQg0oZKS9zgmiZo" + + "f/4dOCL0UtCDnyOSvqT7mCVIcMDIEKu8QbVlgZYBop08l60EuEU3gARUo8WsYQmO" + + "Dz/ldx0Z+znIT0SXVuOwc+RVItC5T/Qx+aijmmpt+9l14nmaGBrEkmuhmtdvU/4v" + + "aptewGRgmjOfD6cqK+zs0O5NrrJ3P/6ZSxXj91CQgrThGfOv72bUncXEMNtc8pks" + + "2jpHFjGMdKufnadAD7XuMgzkkaklEXZ4f5tU6heIIwr51g0GBEGF96gYPFnjnSQM" + + "75JE02Clo+DfcfXpcybPTwwFg2jd6JTTOfkdf6OdSlA/1XNK43FA"); + + static byte[] sample2 = Base64.decode( + "MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeFeOWl1jywYCAggA" + + "MBQGCCqGSIb3DQMHBAjUJ5eGBhQGtQSCAWBrHrRgqO8UUMLcWzZEtpk1l3mjxiF/" + + "koCMkHsFwowgyWhEbgIkTgbSViK54LVK8PskekcGNLph+rB6bGZ7pPbL5pbXASJ8" + + "+MkQcG3FZdlS4Ek9tTJDApj3O1UubZGFG4uvTlJJFbF1BOJ3MkY3XQ9Gl1qwv7j5" + + "6e103Da7Cq9+oIDKmznza78XXQYrUsPo8mJGjUxPskEYlzwvHjKubRnYm/K6RKhi" + + "5f4zX4BQ/Dt3H812ZjRXrsjAJP0KrD/jyD/jCT7zNBVPH1izBds+RwizyQAHwfNJ" + + "BFR78TH4cgzB619X47FDVOnT0LqQNVd0O3cSwnPrXE9XR3tPayE+iOB15llFSmi8" + + "z0ByOXldEpkezCn92Umk++suzIVj1qfsK+bv2phZWJPbLEIWPDRHUbYf76q5ArAr" + + "u4xtxT/hoK3krEs/IN3d70qjlUJ36SEw1UaZ82PWhakQbdtu39ZraMJB"); + + static byte[] sample3 = Base64.decode( + "MIIBrjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIrHyQPBZqWLUCAggA" + + "AgEQMBkGCCqGSIb3DQMCMA0CAToECEhbh7YZKiPSBIIBYCT1zp6o5jpFlIkgwPop" + + "7bW1+8ACr4exqzkeb3WflQ8cWJ4cURxzVdvxUnXeW1VJdaQZtjS/QHs5GhPTG/0f" + + "wtvnaPfwrIJ3FeGaZfcg2CrYhalOFmEb4xrE4KyoEQmUN8tb/Cg94uzd16BOPw21" + + "RDnE8bnPdIGY7TyL95kbkqH23mK53pi7h+xWIgduW+atIqDyyt55f7WMZcvDvlj6" + + "VpN/V0h+qxBHL274WA4dj6GYgeyUFpi60HdGCK7By2TBy8h1ZvKGjmB9h8jZvkx1" + + "MkbRumXxyFsowTZawyYvO8Um6lbfEDP9zIEUq0IV8RqH2MRyblsPNSikyYhxX/cz" + + "tdDxRKhilySbSBg5Kr8OfcwKp9bpinN96nmG4xr3Tch1bnVvqJzOQ5+Vva2WwVvH" + + "2JkWvYm5WaANg4Q6bRxu9vz7DuhbJjQdZbxFezIAgrJdSe92B00jO/0Kny1WjiVO" + + "6DA="); + + public String getName() + { + return "EncryptedPrivateKeyInfoTest"; + } + + private void test( + int id, + byte[] sample) + { + ByteArrayInputStream bIn = new ByteArrayInputStream(sample); + ASN1InputStream aIn = new ASN1InputStream(bIn); + EncryptedPrivateKeyInfo info = null; + + try + { + info = EncryptedPrivateKeyInfo.getInstance(aIn.readObject()); + } + catch (Exception e) + { + fail("test " + id + " failed construction - exception " + e.toString(), e); + } + + byte[] bytes = null; + try + { + bytes = info.getEncoded(ASN1Encoding.DER); + } + catch (Exception e) + { + fail("test " + id + " failed writing - exception " + e.toString(), e); + } + + if (bytes.length != sample.length) + { + try + { + bIn = new ByteArrayInputStream(bytes); + aIn = new ASN1InputStream(bIn); + + ASN1Primitive obj = aIn.readObject(); + + fail("test " + id + " length mismatch - expected " + sample.length + Strings.lineSeparator() + ASN1Dump.dumpAsString(info) + " got " + bytes.length + Strings.lineSeparator() + ASN1Dump.dumpAsString(obj)); + } + catch (Exception e) + { + fail("test " + id + " length mismatch - exception " + e.toString()); + } + } + + for (int i = 0; i != bytes.length; i++) + { + if (bytes[i] != sample[i]) + { + fail("test " + id + " data mismatch"); + } + } + } + + public void performTest() + { + test(0, sample1); + test(1, sample2); + test(2, sample3); + } + + + public static void main( + String[] args) + { + runTest(new EncryptedPrivateKeyInfoTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/EqualsAndHashCodeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/EqualsAndHashCodeTest.java new file mode 100644 index 000000000..c079cba50 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/EqualsAndHashCodeTest.java @@ -0,0 +1,131 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.util.Date; + +import com.fr.third.org.bouncycastle.asn1.ASN1Boolean; +import com.fr.third.org.bouncycastle.asn1.ASN1Enumerated; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1OutputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.BERConstructedOctetString; +import com.fr.third.org.bouncycastle.asn1.BERSequence; +import com.fr.third.org.bouncycastle.asn1.BERSet; +import com.fr.third.org.bouncycastle.asn1.BERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERApplicationSpecific; +import com.fr.third.org.bouncycastle.asn1.DERBMPString; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DERGeneralString; +import com.fr.third.org.bouncycastle.asn1.DERGeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.DERGraphicString; +import com.fr.third.org.bouncycastle.asn1.DERIA5String; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DERNumericString; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.DERPrintableString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.DERT61String; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERUTCTime; +import com.fr.third.org.bouncycastle.asn1.DERUTF8String; +import com.fr.third.org.bouncycastle.asn1.DERUniversalString; +import com.fr.third.org.bouncycastle.asn1.DERVideotexString; +import com.fr.third.org.bouncycastle.asn1.DERVisibleString; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class EqualsAndHashCodeTest + implements Test +{ + public TestResult perform() + { + byte[] data = { 0, 1, 0, 1, 0, 0, 1 }; + + ASN1Primitive values[] = { + new BERConstructedOctetString(data), + new BERSequence(new DERPrintableString("hello world")), + new BERSet(new DERPrintableString("hello world")), + new BERTaggedObject(0, new DERPrintableString("hello world")), + new DERApplicationSpecific(0, data), + new DERBitString(data), + new DERBMPString("hello world"), + ASN1Boolean.getInstance(true), + ASN1Boolean.getInstance(false), + new ASN1Enumerated(100), + new DERGeneralizedTime("20070315173729Z"), + new DERGeneralString("hello world"), + new DERIA5String("hello"), + new ASN1Integer(1000), + new DERNull(), + new DERNumericString("123456"), + new ASN1ObjectIdentifier("1.1.1.10000.1"), + new DEROctetString(data), + new DERPrintableString("hello world"), + new DERSequence(new DERPrintableString("hello world")), + new DERSet(new DERPrintableString("hello world")), + new DERT61String("hello world"), + new DERTaggedObject(0, new DERPrintableString("hello world")), + new DERUniversalString(data), + new DERUTCTime(new Date()), + new DERUTF8String("hello world"), + new DERVisibleString("hello world") , + new DERGraphicString(Hex.decode("deadbeef")), + new DERVideotexString(Strings.toByteArray("Hello World")) + }; + + try + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = ASN1OutputStream.create(bOut); + + for (int i = 0; i != values.length; i++) + { + aOut.writeObject(values[i]); + } + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + ASN1InputStream aIn = new ASN1InputStream(bIn); + + for (int i = 0; i != values.length; i++) + { + ASN1Primitive o = aIn.readObject(); + if (!o.equals(values[i])) + { + return new SimpleTestResult(false, getName() + ": Failed equality test for " + o.getClass()); + } + + if (o.hashCode() != values[i].hashCode()) + { + return new SimpleTestResult(false, getName() + ": Failed hashCode test for " + o.getClass()); + } + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": Failed - exception " + e.toString(), e); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public String getName() + { + return "EqualsAndHashCode"; + } + + public static void main( + String[] args) + { + EqualsAndHashCodeTest test = new EqualsAndHashCodeTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ExtendedFailInfoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ExtendedFailInfoTest.java new file mode 100644 index 000000000..7597da4f7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ExtendedFailInfoTest.java @@ -0,0 +1,48 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.ExtendedFailInfo; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class ExtendedFailInfoTest + extends SimpleTest +{ + + public static void main(String[] args) + { + runTest(new ExtendedFailInfoTest()); + } + + public String getName() + { + return "ExtendedFailInfo"; + } + + public void performTest() + throws Exception + { + // OID not real + ExtendedFailInfo extendedFailInfo = new ExtendedFailInfo( + new ASN1ObjectIdentifier("1.2.3.2"), + new ASN1Integer(10L)); + byte[] b = extendedFailInfo.getEncoded(); + ExtendedFailInfo extendedFailInfoResult = ExtendedFailInfo.getInstance(b); + + isEquals("failInfoOID", extendedFailInfo.getFailInfoOID(), extendedFailInfoResult.getFailInfoOID()); + isEquals("failInfoValue", extendedFailInfo.getFailInfoValue(), extendedFailInfoResult.getFailInfoValue()); + + try + { + ExtendedFailInfo.getInstance(new DERSequence(new ASN1Integer(10L))); + fail("Sequence must be 2 elements."); + } + catch (Throwable t) + { + isEquals("Wrong exception type",t.getClass(), IllegalArgumentException.class); + } + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ExtensionReqTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ExtensionReqTest.java new file mode 100644 index 000000000..cff240c90 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ExtensionReqTest.java @@ -0,0 +1,39 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Boolean; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.cmc.ExtensionReq; +import com.fr.third.org.bouncycastle.asn1.x509.Extension; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class ExtensionReqTest + extends SimpleTest +{ + public String getName() + { + return "ExtensionReqTest"; + } + + public void performTest() + throws Exception + { + ExtensionReq extensionReq = new ExtensionReq( + new Extension( + new ASN1ObjectIdentifier("1.2.4"), ASN1Boolean.FALSE, new DEROctetString("abcdef".getBytes()) + )); + byte[] b = extensionReq.getEncoded(); + + ExtensionReq extensionReqResult = ExtensionReq.getInstance(b); + + isEquals("Extensions", extensionReq.getExtensions()[0], extensionReqResult.getExtensions()[0]); + + } + + public static void main(String[] args) + { + runTest(new ExtensionReqTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GeneralNameTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GeneralNameTest.java new file mode 100644 index 000000000..27eb0ddfe --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GeneralNameTest.java @@ -0,0 +1,173 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralNamesBuilder; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class GeneralNameTest + extends SimpleTest +{ + private static final byte[] ipv4 = Hex.decode("87040a090800"); + private static final byte[] ipv4WithMask1 = Hex.decode("87080a090800ffffff00"); + private static final byte[] ipv4WithMask2 = Hex.decode("87080a090800ffff8000"); + private static final byte[] ipv4WithMask3 = Hex.decode("87080a090800ffffc000"); + + private static final byte[] ipv6a = Hex.decode("871020010db885a308d313198a2e03707334"); + private static final byte[] ipv6b = Hex.decode("871020010db885a3000013198a2e03707334"); + private static final byte[] ipv6c = Hex.decode("871000000000000000000000000000000001"); + private static final byte[] ipv6d = Hex.decode("871020010db885a3000000008a2e03707334"); + private static final byte[] ipv6e = Hex.decode("871020010db885a3000000008a2e0a090800"); + private static final byte[] ipv6f = Hex.decode("872020010db885a3000000008a2e0a090800ffffffffffff00000000000000000000"); + private static final byte[] ipv6g = Hex.decode("872020010db885a3000000008a2e0a090800ffffffffffffffffffffffffffffffff"); + private static final byte[] ipv6h = Hex.decode("872020010db885a300000000000000000000ffffffffffff00000000000000000000"); + private static final byte[] ipv6i = Hex.decode("872020010db885a300000000000000000000fffffffffffe00000000000000000000"); + private static final byte[] ipv6j = Hex.decode("872020010db885a300000000000000000000ffffffffffff80000000000000000000"); + + public String getName() + { + return "GeneralName"; + } + + public void performTest() + throws Exception + { + GeneralName nm = new GeneralName(GeneralName.iPAddress, "10.9.8.0"); + if (!Arrays.areEqual(nm.getEncoded(), ipv4)) + { + fail("ipv4 encoding failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "10.9.8.0/255.255.255.0"); + if (!Arrays.areEqual(nm.getEncoded(), ipv4WithMask1)) + { + fail("ipv4 with netmask 1 encoding failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "10.9.8.0/24"); + if (!Arrays.areEqual(nm.getEncoded(), ipv4WithMask1)) + { + fail("ipv4 with netmask 2 encoding failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "10.9.8.0/255.255.128.0"); + if (!Arrays.areEqual(nm.getEncoded(), ipv4WithMask2)) + { + fail("ipv4 with netmask 3a encoding failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "10.9.8.0/17"); + if (!Arrays.areEqual(nm.getEncoded(), ipv4WithMask2)) + { + fail("ipv4 with netmask 3b encoding failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "10.9.8.0/255.255.192.0"); + if (!Arrays.areEqual(nm.getEncoded(), ipv4WithMask3)) + { + fail("ipv4 with netmask 3a encoding failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "10.9.8.0/18"); + if (!Arrays.areEqual(nm.getEncoded(), ipv4WithMask3)) + { + fail("ipv4 with netmask 3b encoding failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3:08d3:1319:8a2e:0370:7334"); + if (!Arrays.areEqual(nm.getEncoded(), ipv6a)) + { + fail("ipv6 with netmask encoding failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::1319:8a2e:0370:7334"); + if (!Arrays.areEqual(nm.getEncoded(), ipv6b)) + { + fail("ipv6b encoding failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "::1"); + if (!Arrays.areEqual(nm.getEncoded(), ipv6c)) + { + fail("ipv6c failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::8a2e:0370:7334"); + if (!Arrays.areEqual(nm.getEncoded(), ipv6d)) + { + fail("ipv6d failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::8a2e:10.9.8.0"); + if (!Arrays.areEqual(nm.getEncoded(), ipv6e)) + { + fail("ipv6e failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::8a2e:10.9.8.0/ffff:ffff:ffff::0000"); + if (!Arrays.areEqual(nm.getEncoded(), ipv6f)) + { + fail("ipv6f failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::8a2e:10.9.8.0/128"); + if (!Arrays.areEqual(nm.getEncoded(), ipv6g)) + { + fail("ipv6g failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::/48"); + if (!Arrays.areEqual(nm.getEncoded(), ipv6h)) + { + fail("ipv6h failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::/47"); + if (!Arrays.areEqual(nm.getEncoded(), ipv6i)) + { + fail("ipv6i failed"); + } + + nm = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::/49"); + if (!Arrays.areEqual(nm.getEncoded(), ipv6j)) + { + fail("ipv6j failed"); + } + + GeneralNamesBuilder genNamesBuilder = new GeneralNamesBuilder(); + + GeneralName name1 = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::8a2e:0370:7334"); + + genNamesBuilder.addName(name1); + + if (!genNamesBuilder.build().equals(new GeneralNames(name1))) + { + fail("single build failed"); + } + + GeneralName nm1 = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::/48"); + GeneralName nm2 = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::/47"); + GeneralName nm3 = new GeneralName(GeneralName.iPAddress, "2001:0db8:85a3::/49"); + + genNamesBuilder = new GeneralNamesBuilder(); + + genNamesBuilder.addName(name1); + + genNamesBuilder.addNames(new GeneralNames(new GeneralName[]{nm1, nm2})); + + genNamesBuilder.addName(nm3); + + if (!genNamesBuilder.build().equals(new GeneralNames(new GeneralName[] { name1, nm1, nm2, nm3 }))) + { + fail("multi build failed"); + } + } + + public static void main( + String[] args) + { + runTest(new GeneralNameTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GeneralizedTimeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GeneralizedTimeTest.java new file mode 100644 index 000000000..6791a8dad --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GeneralizedTimeTest.java @@ -0,0 +1,269 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.SimpleTimeZone; +import java.util.TimeZone; + +import com.fr.third.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.DERGeneralizedTime; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * X.690 test example + */ +public class GeneralizedTimeTest + extends SimpleTest +{ + String[] input = + { + "20020122122220", + "20020122122220Z", + "20020122122220-1000", + "20020122122220+00", + "20020122122220.1", + "20020122122220.1Z", + "20020122122220.1-1000", + "20020122122220.1+00", + "20020122122220.01", + "20020122122220.01Z", + "20020122122220.01-1000", + "20020122122220.01+00", + "20020122122220.001", + "20020122122220.001Z", + "20020122122220.001-1000", + "20020122122220.001+00", + "20020122122220.0001", + "20020122122220.0001Z", + "20020122122220.0001-1000", + "20020122122220.0001+00", + "20020122122220.0001+1000" + }; + + String[] output = { + "20020122122220", + "20020122122220GMT+00:00", + "20020122122220GMT-10:00", + "20020122122220GMT+00:00", + "20020122122220.1", + "20020122122220.1GMT+00:00", + "20020122122220.1GMT-10:00", + "20020122122220.1GMT+00:00", + "20020122122220.01", + "20020122122220.01GMT+00:00", + "20020122122220.01GMT-10:00", + "20020122122220.01GMT+00:00", + "20020122122220.001", + "20020122122220.001GMT+00:00", + "20020122122220.001GMT-10:00", + "20020122122220.001GMT+00:00", + "20020122122220.0001", + "20020122122220.0001GMT+00:00", + "20020122122220.0001GMT-10:00", + "20020122122220.0001GMT+00:00", + "20020122122220.0001GMT+10:00" }; + + String[] zOutput = { + "20020122122220Z", + "20020122122220Z", + "20020122222220Z", + "20020122122220Z", + "20020122122220Z", + "20020122122220Z", + "20020122222220Z", + "20020122122220Z", + "20020122122220Z", + "20020122122220Z", + "20020122222220Z", + "20020122122220Z", + "20020122122220Z", + "20020122122220Z", + "20020122222220Z", + "20020122122220Z", + "20020122122220Z", + "20020122122220Z", + "20020122222220Z", + "20020122122220Z", + "20020122022220Z" + }; + + String[] mzOutput = { + "20020122122220.000Z", + "20020122122220.000Z", + "20020122222220.000Z", + "20020122122220.000Z", + "20020122122220.100Z", + "20020122122220.100Z", + "20020122222220.100Z", + "20020122122220.100Z", + "20020122122220.010Z", + "20020122122220.010Z", + "20020122222220.010Z", + "20020122122220.010Z", + "20020122122220.001Z", + "20020122122220.001Z", + "20020122222220.001Z", + "20020122122220.001Z", + "20020122122220.000Z", + "20020122122220.000Z", + "20020122222220.000Z", + "20020122122220.000Z", + "20020122022220.000Z" + }; + + String[] derMzOutput = { + "20020122122220Z", + "20020122122220Z", + "20020122222220Z", + "20020122122220Z", + "20020122122220.1Z", + "20020122122220.1Z", + "20020122222220.1Z", + "20020122122220.1Z", + "20020122122220.01Z", + "20020122122220.01Z", + "20020122222220.01Z", + "20020122122220.01Z", + "20020122122220.001Z", + "20020122122220.001Z", + "20020122222220.001Z", + "20020122122220.001Z", + "20020122122220Z", + "20020122122220Z", + "20020122222220Z", + "20020122122220Z", + "20020122022220Z" + }; + + String[] truncOutput = { + "200201221222Z", + "2002012212Z" + }; + + String[] derTruncOutput = { + "20020122122200Z", + "20020122120000Z" + }; + + public String getName() + { + return "GeneralizedTime"; + } + + public void performTest() + throws Exception + { + SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + for (int i = 0; i != input.length; i++) + { + ASN1GeneralizedTime t = new ASN1GeneralizedTime(input[i]); + if (output[i].indexOf('G') > 0) // don't check local time the same way + { + if (!t.getTime().equals(output[i])) + { + fail("failed GMT conversion test got " + t.getTime() + " expected " + output[i]); + } + if (!dateF.format(t.getDate()).equals(zOutput[i])) + { + fail("failed date conversion test"); + } + } + else + { + String offset = calculateGMTOffset(t.getDate()); + if (!t.getTime().equals(output[i] + offset)) + { + fail("failed conversion test got " + t.getTime() + " expected " + output[i] + offset); + } + } + } + + dateF = new SimpleDateFormat("yyyyMMddHHmmss.SSS'Z'"); + + dateF.setTimeZone(new SimpleTimeZone(0,"Z")); + + for (int i = 0; i != input.length; i++) + { + ASN1GeneralizedTime t = new ASN1GeneralizedTime(input[i]); + + if (!dateF.format(t.getDate()).equals(mzOutput[i])) + { + fail("failed long date conversion test"); + } + } + + for (int i = 0; i != mzOutput.length; i++) + { + ASN1GeneralizedTime t = new DERGeneralizedTime(mzOutput[i]); + + if (!areEqual(t.getEncoded(), new ASN1GeneralizedTime(derMzOutput[i]).getEncoded())) + { + fail("der encoding wrong"); + } + } + + for (int i = 0; i != truncOutput.length; i++) + { + DERGeneralizedTime t = new DERGeneralizedTime(truncOutput[i]); + + if (!areEqual(t.getEncoded(), new ASN1GeneralizedTime(derTruncOutput[i]).getEncoded())) + { + fail("trunc der encoding wrong"); + } + } + + // check an actual GMT string comes back untampered + ASN1GeneralizedTime time = new ASN1GeneralizedTime("20190704031318GMT+00:00"); + + isTrue("20190704031318GMT+00:00".equals(time.getTime())); + + try + { + new DERGeneralizedTime(new byte[0]); + } + catch (IllegalArgumentException e) + { + isTrue(e.getMessage().equals("GeneralizedTime string too short")); + } + } + + private String calculateGMTOffset(Date date) + { + String sign = "+"; + TimeZone timeZone = TimeZone.getDefault(); + int offset = timeZone.getRawOffset(); + if (offset < 0) + { + sign = "-"; + offset = -offset; + } + int hours = offset / (60 * 60 * 1000); + int minutes = (offset - (hours * 60 * 60 * 1000)) / (60 * 1000); + + if (timeZone.useDaylightTime() && timeZone.inDaylightTime(date)) + { + hours += sign.equals("+") ? 1 : -1; + } + + return "GMT" + sign + convert(hours) + ":" + convert(minutes); + } + + private String convert(int time) + { + if (time < 10) + { + return "0" + time; + } + + return Integer.toString(time); + } + + public static void main( + String[] args) + { + runTest(new GeneralizedTimeTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GenerationTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GenerationTest.java new file mode 100644 index 000000000..ef60dc670 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GenerationTest.java @@ -0,0 +1,406 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; +import java.math.BigInteger; +import java.text.ParseException; +import java.util.Date; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.oiw.ElGamalParameter; +import com.fr.third.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.RSAPublicKey; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.CRLReason; +import com.fr.third.org.bouncycastle.asn1.x509.Extension; +import com.fr.third.org.bouncycastle.asn1.x509.Extensions; +import com.fr.third.org.bouncycastle.asn1.x509.ExtensionsGenerator; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames; +import com.fr.third.org.bouncycastle.asn1.x509.IssuingDistributionPoint; +import com.fr.third.org.bouncycastle.asn1.x509.KeyUsage; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectKeyIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x509.TBSCertList; +import com.fr.third.org.bouncycastle.asn1.x509.TBSCertificate; +import com.fr.third.org.bouncycastle.asn1.x509.Time; +import com.fr.third.org.bouncycastle.asn1.x509.V1TBSCertificateGenerator; +import com.fr.third.org.bouncycastle.asn1.x509.V2TBSCertListGenerator; +import com.fr.third.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class GenerationTest + extends SimpleTest +{ + private byte[] v1Cert = Base64.decode( + "MIGtAgEBMA0GCSqGSIb3DQEBBAUAMCUxCzAJBgNVBAMMAkFVMRYwFAYDVQQKDA1Cb" + + "3VuY3kgQ2FzdGxlMB4XDTcwMDEwMTAwMDAwMVoXDTcwMDEwMTAwMDAxMlowNjELMA" + + "kGA1UEAwwCQVUxFjAUBgNVBAoMDUJvdW5jeSBDYXN0bGUxDzANBgNVBAsMBlRlc3Q" + + "gMTAaMA0GCSqGSIb3DQEBAQUAAwkAMAYCAQECAQI="); + + private byte[] v3Cert = Base64.decode( + "MIIBSKADAgECAgECMA0GCSqGSIb3DQEBBAUAMCUxCzAJBgNVBAMMAkFVMRYwFAYD" + + "VQQKDA1Cb3VuY3kgQ2FzdGxlMB4XDTcwMDEwMTAwMDAwMVoXDTcwMDEwMTAwMDAw" + + "MlowNjELMAkGA1UEAwwCQVUxFjAUBgNVBAoMDUJvdW5jeSBDYXN0bGUxDzANBgNV" + + "BAsMBlRlc3QgMjAYMBAGBisOBwIBATAGAgEBAgECAwQAAgEDo4GVMIGSMGEGA1Ud" + + "IwEB/wRXMFWAFDZPdpHPzKi7o8EJokkQU2uqCHRRoTqkODA2MQswCQYDVQQDDAJB" + + "VTEWMBQGA1UECgwNQm91bmN5IENhc3RsZTEPMA0GA1UECwwGVGVzdCAyggECMCAG" + + "A1UdDgEB/wQWBBQ2T3aRz8you6PBCaJJEFNrqgh0UTALBgNVHQ8EBAMCBBA="); + + private byte[] v3CertNullSubject = Base64.decode( + "MIHGoAMCAQICAQIwDQYJKoZIhvcNAQEEBQAwJTELMAkGA1UEAwwCQVUxFjAUBgNVB" + + "AoMDUJvdW5jeSBDYXN0bGUwHhcNNzAwMTAxMDAwMDAxWhcNNzAwMTAxMDAwMDAyWj" + + "AAMBgwEAYGKw4HAgEBMAYCAQECAQIDBAACAQOjSjBIMEYGA1UdEQEB/wQ8MDqkODA" + + "2MQswCQYDVQQDDAJBVTEWMBQGA1UECgwNQm91bmN5IENhc3RsZTEPMA0GA1UECwwG" + + "VGVzdCAy"); + + private byte[] v2CertList = Base64.decode( + "MIIBQwIBATANBgkqhkiG9w0BAQUFADAlMQswCQYDVQQDDAJBVTEWMBQGA1UECgwN" + + "Qm91bmN5IENhc3RsZRcNNzAwMTAxMDAwMDAwWhcNNzAwMTAxMDAwMDAyWjAiMCAC" + + "AQEXDTcwMDEwMTAwMDAwMVowDDAKBgNVHRUEAwoBCqCBxTCBwjBhBgNVHSMBAf8E" + + "VzBVgBQ2T3aRz8you6PBCaJJEFNrqgh0UaE6pDgwNjELMAkGA1UEAwwCQVUxFjAU" + + "BgNVBAoMDUJvdW5jeSBDYXN0bGUxDzANBgNVBAsMBlRlc3QgMoIBAjBDBgNVHRIE" + + "PDA6pDgwNjELMAkGA1UEAwwCQVUxFjAUBgNVBAoMDUJvdW5jeSBDYXN0bGUxDzAN" + + "BgNVBAsMBlRlc3QgMzAKBgNVHRQEAwIBATAMBgNVHRwBAf8EAjAA"); + + private void tbsV1CertGen() + throws IOException + { + V1TBSCertificateGenerator gen = new V1TBSCertificateGenerator(); + Date startDate = new Date(1000); + Date endDate = new Date(12000); + + gen.setSerialNumber(new ASN1Integer(1)); + + gen.setStartDate(new Time(startDate)); + gen.setEndDate(new Time(endDate)); + + gen.setIssuer(new X500Name("CN=AU,O=Bouncy Castle")); + gen.setSubject(new X500Name("CN=AU,O=Bouncy Castle,OU=Test 1")); + + gen.setSignature(new AlgorithmIdentifier(PKCSObjectIdentifiers.md5WithRSAEncryption, DERNull.INSTANCE)); + + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), + new RSAPublicKey(BigInteger.valueOf(1), BigInteger.valueOf(2))); + + gen.setSubjectPublicKeyInfo(info); + + TBSCertificate tbs = gen.generateTBSCertificate(); + + byte[] encoding = tbs.getEncoded(); + if (!Arrays.areEqual(encoding, v1Cert)) + { + fail("failed v1 cert generation"); + } + + // + // read back test + // + ASN1Primitive o = ASN1Primitive.fromByteArray(v1Cert); + + encoding = o.getEncoded(); + if (!Arrays.areEqual(encoding, v1Cert)) + { + fail("failed v1 cert read back test"); + } + } + + private AuthorityKeyIdentifier createAuthorityKeyId( + SubjectPublicKeyInfo info, + X500Name name, + int sNumber) + { + GeneralName genName = new GeneralName(name); + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(genName); + + return new AuthorityKeyIdentifier( + info, GeneralNames.getInstance(new DERSequence(v)), BigInteger.valueOf(sNumber)); + } + + private void tbsV3CertGen() + throws IOException + { + V3TBSCertificateGenerator gen = new V3TBSCertificateGenerator(); + Date startDate = new Date(1000); + Date endDate = new Date(2000); + + gen.setSerialNumber(new ASN1Integer(2)); + + gen.setStartDate(new Time(startDate)); + gen.setEndDate(new Time(endDate)); + + gen.setIssuer(new X500Name("CN=AU,O=Bouncy Castle")); + gen.setSubject(new X500Name("CN=AU,O=Bouncy Castle,OU=Test 2")); + + gen.setSignature(new AlgorithmIdentifier(PKCSObjectIdentifiers.md5WithRSAEncryption, DERNull.INSTANCE)); + + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(BigInteger.valueOf(1), BigInteger.valueOf(2))), new ASN1Integer(3)); + + gen.setSubjectPublicKeyInfo(info); + + // + // add extensions + // + Extensions ex = new Extensions(new Extension[] { + new Extension(Extension.authorityKeyIdentifier, true, new DEROctetString(createAuthorityKeyId(info, new X500Name("CN=AU,O=Bouncy Castle,OU=Test 2"), 2))), + new Extension(Extension.subjectKeyIdentifier, true, new DEROctetString(new SubjectKeyIdentifier(getDigest(info)))), + new Extension(Extension.keyUsage, false, new DEROctetString(new KeyUsage(KeyUsage.dataEncipherment))) + }); + + gen.setExtensions(ex); + + TBSCertificate tbs = gen.generateTBSCertificate(); + + byte[] encoding = tbs.getEncoded(); + if (!Arrays.areEqual(encoding, v3Cert)) + { + fail("failed v3 cert generation"); + } + + // + // read back test + // + ASN1Primitive o = ASN1Primitive.fromByteArray(v3Cert); + + encoding = o.getEncoded(); + if (!Arrays.areEqual(encoding, v3Cert)) + { + fail("failed v3 cert read back test"); + } + } + + private void tbsV3CertGenWithNullSubject() + throws IOException + { + V3TBSCertificateGenerator gen = new V3TBSCertificateGenerator(); + Date startDate = new Date(1000); + Date endDate = new Date(2000); + + gen.setSerialNumber(new ASN1Integer(2)); + + gen.setStartDate(new Time(startDate)); + gen.setEndDate(new Time(endDate)); + + gen.setIssuer(new X500Name("CN=AU,O=Bouncy Castle")); + + gen.setSignature(new AlgorithmIdentifier(PKCSObjectIdentifiers.md5WithRSAEncryption, DERNull.INSTANCE)); + + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(BigInteger.valueOf(1), BigInteger.valueOf(2))), new ASN1Integer(3)); + + gen.setSubjectPublicKeyInfo(info); + + try + { + gen.generateTBSCertificate(); + fail("null subject not caught!"); + } + catch (IllegalStateException e) + { + if (!e.getMessage().equals("not all mandatory fields set in V3 TBScertificate generator")) + { + fail("unexpected exception", e); + } + } + + // + // add extensions + // + + Extensions ex = new Extensions(new Extension(Extension.subjectAlternativeName, true, + new DEROctetString(new GeneralNames(new GeneralName(new X500Name("CN=AU,O=Bouncy Castle,OU=Test 2")))))); + + gen.setExtensions(ex); + + TBSCertificate tbs = gen.generateTBSCertificate(); + + byte[] encoding = tbs.getEncoded(); + if (!Arrays.areEqual(encoding, v3CertNullSubject)) + { + fail("failed v3 null sub cert generation"); + } + + // + // read back test + // + ASN1Primitive o = ASN1Primitive.fromByteArray(v3CertNullSubject); + + encoding = o.getEncoded(); + if (!Arrays.areEqual(encoding, v3CertNullSubject)) + { + fail("failed v3 null sub cert read back test"); + } + } + + private void tbsV2CertListGen() + throws IOException + { + V2TBSCertListGenerator gen = new V2TBSCertListGenerator(); + + gen.setIssuer(new X500Name("CN=AU,O=Bouncy Castle")); + + gen.addCRLEntry(new ASN1Integer(1), new Time(new Date(1000)), CRLReason.aACompromise); + + gen.setNextUpdate(new Time(new Date(2000))); + + gen.setThisUpdate(new Time(new Date(500))); + + gen.setSignature(new AlgorithmIdentifier(PKCSObjectIdentifiers.sha1WithRSAEncryption, DERNull.INSTANCE)); + + // + // extensions + // + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(OIWObjectIdentifiers.elGamalAlgorithm, new ElGamalParameter(BigInteger.valueOf(1), BigInteger.valueOf(2))), new ASN1Integer(3)); + + ExtensionsGenerator extGen = new ExtensionsGenerator(); + + extGen.addExtension(Extension.authorityKeyIdentifier, true, createAuthorityKeyId(info, new X500Name("CN=AU,O=Bouncy Castle,OU=Test 2"), 2)); + extGen.addExtension(Extension.issuerAlternativeName, false, new GeneralNames(new GeneralName(new X500Name("CN=AU,O=Bouncy Castle,OU=Test 3")))); + extGen.addExtension(Extension.cRLNumber, false, new ASN1Integer(1)); + extGen.addExtension(Extension.issuingDistributionPoint, true, IssuingDistributionPoint.getInstance(new DERSequence())); + + isTrue(extGen.hasExtension(Extension.cRLNumber)); + isTrue(!extGen.hasExtension(Extension.freshestCRL)); + + isEquals(new Extension(Extension.cRLNumber, false, new ASN1Integer(1).getEncoded()), extGen.getExtension(Extension.cRLNumber)); + + Extensions ex = extGen.generate(); + + gen.setExtensions(ex); + + TBSCertList tbs = gen.generateTBSCertList(); + + byte[] encoding = tbs.getEncoded(); + if (!Arrays.areEqual(encoding, v2CertList)) + { + System.out.println(new String(Base64.encode(encoding))); + fail("failed v2 cert list generation"); + } + + // extGen - check replacement. + extGen.replaceExtension(Extension.cRLNumber, false, new ASN1Integer(2)); + + isEquals(new Extension(Extension.cRLNumber, false, new ASN1Integer(2).getEncoded()), extGen.getExtension(Extension.cRLNumber)); + + // extGen - check remove. + extGen.removeExtension(Extension.cRLNumber); + + isTrue(!extGen.hasExtension(Extension.cRLNumber)); + + // check we can still generate + ex = extGen.generate(); + + // + // read back test + // + ASN1Primitive o = ASN1Primitive.fromByteArray(v2CertList); + + encoding = o.getEncoded(); + if (!Arrays.areEqual(encoding, v2CertList)) + { + fail("failed v2 cert list read back test"); + } + + // + // check we can add a custom reason + // + gen.addCRLEntry(new ASN1Integer(1), new Time(new Date(1000)), CRLReason.aACompromise); + + // + // check invalidity date + gen.addCRLEntry(new ASN1Integer(2), new Time(new Date(1000)), CRLReason.affiliationChanged, new ASN1GeneralizedTime(new Date(2000))); + + TBSCertList crl = gen.generateTBSCertList(); + + TBSCertList.CRLEntry[] entries = crl.getRevokedCertificates(); + for (int i = 0; i != entries.length; i++) + { + TBSCertList.CRLEntry entry = entries[i]; + + if (entry.getUserCertificate().equals(new ASN1Integer(1))) + { + Extensions extensions = entry.getExtensions(); + Extension ext = extensions.getExtension(Extension.reasonCode); + + CRLReason r = CRLReason.getInstance(ext.getParsedValue()); + + if (r.getValue().intValue() != CRLReason.aACompromise) + { + fail("reason code mismatch"); + } + } + else if (entry.getUserCertificate().equals(new ASN1Integer(2))) + { + Extensions extensions = entry.getExtensions(); + Extension ext = extensions.getExtension(Extension.reasonCode); + + CRLReason r = CRLReason.getInstance(ext.getParsedValue()); + + if (r.getValue().intValue() != CRLReason.affiliationChanged) + { + fail("reason code mismatch"); + } + + ext = extensions.getExtension(Extension.invalidityDate); + + ASN1GeneralizedTime t = ASN1GeneralizedTime.getInstance(ext.getParsedValue()); + + try + { + if (!t.getDate().equals(new Date(2000))) + { + fail("invalidity date mismatch"); + } + } + catch (ParseException e) + { + fail("can't parse date", e); + } + } + } + } + + public void performTest() + throws Exception + { + tbsV1CertGen(); + tbsV3CertGen(); + tbsV3CertGenWithNullSubject(); + tbsV2CertListGen(); + } + + public String getName() + { + return "Generation"; + } + + private static byte[] getDigest(SubjectPublicKeyInfo spki) + { + Digest digest = new SHA1Digest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + + byte[] bytes = spki.getPublicKeyData().getBytes(); + digest.update(bytes, 0, bytes.length); + digest.doFinal(resBuf, 0); + return resBuf; + } + + public static void main( + String[] args) + { + runTest(new GenerationTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GetCRLTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GetCRLTest.java new file mode 100644 index 000000000..9156ce4d2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GetCRLTest.java @@ -0,0 +1,122 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.util.Date; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.GetCRL; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.X500NameBuilder; +import com.fr.third.org.bouncycastle.asn1.x500.style.BCStyle; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.ReasonFlags; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class GetCRLTest + extends SimpleTest +{ + + public static void main(String[] args) + { + runTest(new GetCRLTest()); + } + + public String getName() + { + return "GetCRLTest"; + } + + public void performTest() + throws Exception + { + + { + X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE); + builder.addRDN(BCStyle.C, "AU"); + X500Name name = new X500Name(builder.build().toString()); + + GetCRL crl = new GetCRL( + name, + new GeneralName(GeneralName.rfc822Name, "/"), + new ASN1GeneralizedTime(new Date()), + new ReasonFlags(ReasonFlags.affiliationChanged) + ); + + byte[] b = crl.getEncoded(); + + GetCRL crlResp = GetCRL.getInstance(b); + + isEquals("IssuerName", crl.getIssuerName(), crlResp.getIssuerName()); + isEquals("cRLName", crl.getcRLName(), crlResp.getcRLName()); + isEquals("time", crl.getTime(), crlResp.getTime()); + isEquals("reasons", crl.getReasons(), crlResp.getReasons()); + + try + { + GetCRL.getInstance(new DERSequence(new ASN1Encodable[0])); + fail("Must not accept sequence less than 1"); + } + catch (Throwable t) + { + isEquals("", t.getClass(), IllegalArgumentException.class); + } + + try + { + GetCRL.getInstance(new DERSequence(new ASN1Encodable[5])); + fail("Must not accept sequence larger than 5"); + } + catch (Throwable t) + { + isEquals("", t.getClass(), IllegalArgumentException.class); + } + } + + { // Permutate on options test all possible combinations. + + X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE); + builder.addRDN(BCStyle.C, "AU"); + X500Name name = new X500Name(builder.build().toString()); + GeneralName generalName = null; + ASN1GeneralizedTime generalizedTime = null; + ReasonFlags flags = null; + + for (int t = 0; t < 8; t++) + { + if ((t & 1) == 1) + { + generalName = new GeneralName(GeneralName.rfc822Name, "/"); + } + if ((t & 2) == 2) + { + generalizedTime = new ASN1GeneralizedTime(new Date()); + } + + if ((t & 4) == 4) + { + flags = new ReasonFlags(ReasonFlags.affiliationChanged); + } + + + GetCRL crl = new GetCRL( + name, + generalName, + generalizedTime, + flags + ); + + byte[] b = crl.getEncoded(); + + GetCRL crlResp = GetCRL.getInstance(b); + + isEquals("IssuerName", crl.getIssuerName(), crlResp.getIssuerName()); + isEquals("cRLName", crl.getcRLName(), crlResp.getcRLName()); + isEquals("time", crl.getTime(), crlResp.getTime()); + isEquals("reasons", crl.getReasons(), crlResp.getReasons()); + + } + } + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GetCertTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GetCertTest.java new file mode 100644 index 000000000..b5844813a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/GetCertTest.java @@ -0,0 +1,41 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.GetCert; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class GetCertTest extends SimpleTest +{ + public static void main(String[] args) { + runTest(new GetCertTest()); + } + + public String getName() + { + return "GetCertTest"; + } + + public void performTest() + throws Exception + { + GetCert gs = new GetCert(new GeneralName(GeneralName.dNSName,"fish"),new BigInteger("109")); + byte[] b = gs.getEncoded(); + GetCert gsResp = GetCert.getInstance(b); + + isEquals("Issuer Name",gs.getIssuerName(), gsResp.getIssuerName()); + isEquals("Serial Number",gs.getSerialNumber(), gsResp.getSerialNumber()); + + try { + GetCert.getInstance(new DERSequence(new ASN1Integer(1L))); + fail("Sequence must be length of 2"); + } catch (Throwable t) { + isEquals("Wrong exception",t.getClass(), IllegalArgumentException.class); + } + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/IdentityProofV2Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/IdentityProofV2Test.java new file mode 100644 index 000000000..2fd1a4efa --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/IdentityProofV2Test.java @@ -0,0 +1,52 @@ +package com.fr.third.org.bouncycastle.asn1.test; + + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.IdentityProofV2; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class IdentityProofV2Test + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new IdentityProofV2Test()); + } + + public String getName() + { + return "IdentityProofV2"; + } + + public void performTest() + throws Exception + { + IdentityProofV2 proofV2 = new IdentityProofV2( + new AlgorithmIdentifier(PKCSObjectIdentifiers.encryptionAlgorithm, new ASN1Integer(10L)), + new AlgorithmIdentifier(PKCSObjectIdentifiers.bagtypes, new ASN1Integer(10L)), + "Cats".getBytes() + ); + + byte[] b = proofV2.getEncoded(); + IdentityProofV2 proofV2Res = IdentityProofV2.getInstance(b); + + isEquals("proofAldID", proofV2.getProofAlgID(), proofV2Res.getProofAlgID()); + isEquals("macAlgId", proofV2.getMacAlgId(), proofV2Res.getMacAlgId()); + isTrue("witness", areEqual(proofV2.getWitness(), proofV2Res.getWitness())); + + + try + { + IdentityProofV2.getInstance(new DERSequence(new ASN1Encodable[0])); + fail("Sequence must be length of 3"); + } + catch (Throwable t) + { + isEquals("Exception incorrect", t.getClass(), IllegalArgumentException.class); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/InputStreamTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/InputStreamTest.java new file mode 100644 index 000000000..0274bb4cd --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/InputStreamTest.java @@ -0,0 +1,112 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class InputStreamTest + extends SimpleTest +{ + private static final byte[] outOfBoundsLength = new byte[]{(byte)0x30, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}; + private static final byte[] negativeLength = new byte[]{(byte)0x30, (byte)0x84, (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff}; + private static final byte[] outsideLimitLength = new byte[]{(byte)0x30, (byte)0x83, (byte)0x0f, (byte)0xff, (byte)0xff}; + + private static final byte[] classCast1 = Base64.decode("p1AkHmYAvfOEIrL4ESfrNg=="); + private static final byte[] classCast2 = Base64.decode("JICNbaBUTTq7uxj5mg=="); + private static final byte[] classCast3 = Base64.decode("JAKzADNCxhrrBSVS"); + private static final byte[] memoryError1 = Base64.decode("vm66gOiEe+FV/NvujMwSkUp5Lffw5caQlaRU5sdMPC70IGWmyK2/"); + private static final byte[] memoryError2 = Base64.decode("vm4ogOSEfVGsS3w+KTzb2A0ALYR8VBOQqQeuRwnsPC4AAGWEDLjd"); + + public String getName() + { + return "InputStream"; + } + + public void performTest() + throws Exception + { + ASN1InputStream aIn = new ASN1InputStream(outOfBoundsLength); + + try + { + aIn.readObject(); + fail("out of bounds length not detected."); + } + catch (IOException e) + { + if (!e.getMessage().startsWith("DER length more than 4 bytes")) + { + fail("wrong exception: " + e.getMessage()); + } + } + + aIn = new ASN1InputStream(negativeLength); + + try + { + aIn.readObject(); + fail("negative length not detected."); + } + catch (IOException e) + { + if (!e.getMessage().equals("corrupted stream - negative length found")) + { + fail("wrong exception: " + e.getMessage()); + } + } + + aIn = new ASN1InputStream(outsideLimitLength); + + try + { + aIn.readObject(); + fail("outside limit length not detected."); + } + catch (IOException e) + { + if (!e.getMessage().equals("corrupted stream - out of bounds length found: 1048575 >= 5")) + { + fail("wrong exception: " + e.getMessage()); + } + } + + testWithByteArray(classCast1, "unknown object encountered: class com.fr.third.org.bouncycastle.asn1.DLApplicationSpecific"); + testWithByteArray(classCast2, "unknown object encountered: class com.fr.third.org.bouncycastle.asn1.BERTaggedObjectParser"); + testWithByteArray(classCast3, "unknown object encountered in constructed OCTET STRING: class com.fr.third.org.bouncycastle.asn1.DLTaggedObject"); + + testWithByteArray(memoryError1, "corrupted stream - out of bounds length found: 2078365180 >= 39"); + testWithByteArray(memoryError2, "corrupted stream - out of bounds length found: 2102504523 >= 39"); + } + + private void testWithByteArray(byte[] data, String message) + { + try + { + ASN1InputStream input = new ASN1InputStream(data); + + ASN1Primitive p; + while ((p = input.readObject()) != null) + { + ASN1Sequence asn1 = ASN1Sequence.getInstance(p); + for (int i = 0; i < asn1.size(); i++) + { + asn1.getObjectAt(i); + } + } + } + catch (java.io.IOException e) + { + isEquals(e.getMessage(), message, e.getMessage()); + } + } + + public static void main( + String[] args) + { + runTest(new InputStreamTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/Iso4217CurrencyCodeUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/Iso4217CurrencyCodeUnitTest.java new file mode 100644 index 000000000..27a03252a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/Iso4217CurrencyCodeUnitTest.java @@ -0,0 +1,142 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.x509.qualified.Iso4217CurrencyCode; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Iso4217CurrencyCodeUnitTest + extends SimpleTest +{ + private static final String ALPHABETIC_CURRENCY_CODE = "AUD"; + private static final int NUMERIC_CURRENCY_CODE = 1; + + public String getName() + { + return "Iso4217CurrencyCode"; + } + + public void performTest() + throws Exception + { + // + // alphabetic + // + Iso4217CurrencyCode cc = new Iso4217CurrencyCode(ALPHABETIC_CURRENCY_CODE); + + checkNumeric(cc, ALPHABETIC_CURRENCY_CODE); + + cc = Iso4217CurrencyCode.getInstance(cc); + + checkNumeric(cc, ALPHABETIC_CURRENCY_CODE); + + ASN1Primitive obj = cc.toASN1Primitive(); + + cc = Iso4217CurrencyCode.getInstance(obj); + + checkNumeric(cc, ALPHABETIC_CURRENCY_CODE); + + // + // numeric + // + cc = new Iso4217CurrencyCode(NUMERIC_CURRENCY_CODE); + + checkNumeric(cc, NUMERIC_CURRENCY_CODE); + + cc = Iso4217CurrencyCode.getInstance(cc); + + checkNumeric(cc, NUMERIC_CURRENCY_CODE); + + obj = cc.toASN1Primitive(); + + cc = Iso4217CurrencyCode.getInstance(obj); + + checkNumeric(cc, NUMERIC_CURRENCY_CODE); + + cc = Iso4217CurrencyCode.getInstance(null); + + if (cc != null) + { + fail("null getInstance() failed."); + } + + try + { + Iso4217CurrencyCode.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + new Iso4217CurrencyCode("ABCD"); + + fail("constructor failed to detect out of range currencycode."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + new Iso4217CurrencyCode(0); + + fail("constructor failed to detect out of range small numeric code."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + new Iso4217CurrencyCode(1000); + + fail("constructor failed to detect out of range large numeric code."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkNumeric( + Iso4217CurrencyCode cc, + String code) + { + if (!cc.isAlphabetic()) + { + fail("non-alphabetic code found when one expected."); + } + + if (!cc.getAlphabetic().equals(code)) + { + fail("string codes don't match."); + } + } + + private void checkNumeric( + Iso4217CurrencyCode cc, + int code) + { + if (cc.isAlphabetic()) + { + fail("alphabetic code found when one not expected."); + } + + if (cc.getNumeric() != code) + { + fail("numeric codes don't match."); + } + } + + public static void main( + String[] args) + { + runTest(new Iso4217CurrencyCodeUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/IssuingDistributionPointUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/IssuingDistributionPointUnitTest.java new file mode 100644 index 000000000..57d3a40ab --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/IssuingDistributionPointUnitTest.java @@ -0,0 +1,122 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.DistributionPointName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames; +import com.fr.third.org.bouncycastle.asn1.x509.IssuingDistributionPoint; +import com.fr.third.org.bouncycastle.asn1.x509.ReasonFlags; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class IssuingDistributionPointUnitTest + extends SimpleTest +{ + public String getName() + { + return "IssuingDistributionPoint"; + } + + public void performTest() + throws Exception + { + DistributionPointName name = new DistributionPointName( + new GeneralNames(new GeneralName(new X500Name("cn=test")))); + ReasonFlags reasonFlags = new ReasonFlags(ReasonFlags.cACompromise); + + checkPoint(6, name, true, true, reasonFlags, true, true); + + checkPoint(2, name, false, false, reasonFlags, false, false); + + checkPoint(0, null, false, false, null, false, false); + + try + { + IssuingDistributionPoint.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkPoint( + int size, + DistributionPointName distributionPoint, + boolean onlyContainsUserCerts, + boolean onlyContainsCACerts, + ReasonFlags onlySomeReasons, + boolean indirectCRL, + boolean onlyContainsAttributeCerts) + throws IOException + { + IssuingDistributionPoint point = new IssuingDistributionPoint(distributionPoint, onlyContainsUserCerts, onlyContainsCACerts, onlySomeReasons, indirectCRL, onlyContainsAttributeCerts); + + checkValues(point, distributionPoint, onlyContainsUserCerts, onlyContainsCACerts, onlySomeReasons, indirectCRL, onlyContainsAttributeCerts); + + ASN1Sequence seq = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(point.getEncoded())); + + if (seq.size() != size) + { + fail("size mismatch"); + } + + point = IssuingDistributionPoint.getInstance(seq); + + checkValues(point, distributionPoint, onlyContainsUserCerts, onlyContainsCACerts, onlySomeReasons, indirectCRL, onlyContainsAttributeCerts); + } + + private void checkValues(IssuingDistributionPoint point, DistributionPointName distributionPoint, boolean onlyContainsUserCerts, boolean onlyContainsCACerts, ReasonFlags onlySomeReasons, boolean indirectCRL, boolean onlyContainsAttributeCerts) + { + if (point.onlyContainsUserCerts() != onlyContainsUserCerts) + { + fail("mismatch on onlyContainsUserCerts"); + } + + if (point.onlyContainsCACerts() != onlyContainsCACerts) + { + fail("mismatch on onlyContainsCACerts"); + } + + if (point.isIndirectCRL() != indirectCRL) + { + fail("mismatch on indirectCRL"); + } + + if (point.onlyContainsAttributeCerts() != onlyContainsAttributeCerts) + { + fail("mismatch on onlyContainsAttributeCerts"); + } + + if (!isEquiv(onlySomeReasons, point.getOnlySomeReasons())) + { + fail("mismatch on onlySomeReasons"); + } + + if (!isEquiv(distributionPoint, point.getDistributionPoint())) + { + fail("mismatch on distributionPoint"); + } + } + + private boolean isEquiv(Object o1, Object o2) + { + if (o1 == null) + { + return o2 == null; + } + + return o1.equals(o2); + } + + public static void main( + String[] args) + { + runTest(new IssuingDistributionPointUnitTest()); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/KeyUsageTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/KeyUsageTest.java new file mode 100644 index 000000000..270c52383 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/KeyUsageTest.java @@ -0,0 +1,55 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.x509.KeyUsage; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class KeyUsageTest + extends SimpleTest +{ + public String getName() + { + return "KeyUsage"; + } + + public void performTest() + throws IOException + { + BitStringConstantTester.testFlagValueCorrect(0, KeyUsage.digitalSignature); + BitStringConstantTester.testFlagValueCorrect(1, KeyUsage.nonRepudiation); + BitStringConstantTester.testFlagValueCorrect(2, KeyUsage.keyEncipherment); + BitStringConstantTester.testFlagValueCorrect(3, KeyUsage.dataEncipherment); + BitStringConstantTester.testFlagValueCorrect(4, KeyUsage.keyAgreement); + BitStringConstantTester.testFlagValueCorrect(5, KeyUsage.keyCertSign); + BitStringConstantTester.testFlagValueCorrect(6, KeyUsage.cRLSign); + BitStringConstantTester.testFlagValueCorrect(7, KeyUsage.encipherOnly); + BitStringConstantTester.testFlagValueCorrect(8, KeyUsage.decipherOnly); + + if (!new KeyUsage(KeyUsage.keyCertSign).hasUsages(KeyUsage.keyCertSign)) + { + fail("usages bit test failed 1"); + } + + if (new KeyUsage(KeyUsage.cRLSign).hasUsages(KeyUsage.keyCertSign)) + { + fail("usages bit test failed 2"); + } + + if (!new KeyUsage(KeyUsage.cRLSign | KeyUsage.decipherOnly).hasUsages(KeyUsage.cRLSign | KeyUsage.decipherOnly)) + { + fail("usages bit test failed 3"); + } + + if (new KeyUsage(KeyUsage.cRLSign | KeyUsage.decipherOnly).hasUsages(KeyUsage.cRLSign | KeyUsage.decipherOnly | KeyUsage.keyCertSign)) + { + fail("usages bit test failed 4"); + } + } + + public static void main( + String[] args) + { + runTest(new KeyUsageTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LDSSecurityObjectUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LDSSecurityObjectUnitTest.java new file mode 100644 index 000000000..d4d8e7a78 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LDSSecurityObjectUnitTest.java @@ -0,0 +1,216 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; +import java.util.Random; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.icao.DataGroupHash; +import com.fr.third.org.bouncycastle.asn1.icao.LDSSecurityObject; +import com.fr.third.org.bouncycastle.asn1.icao.LDSVersionInfo; +import com.fr.third.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class LDSSecurityObjectUnitTest + extends SimpleTest +{ + public String getName() + { + return "LDSSecurityObject"; + } + + private byte[] generateHash() + { + Random rand = new Random(); + byte[] bytes = new byte[20]; + + for (int i = 0; i != bytes.length; i++) + { + bytes[i] = (byte)rand.nextInt(); + } + + return bytes; + } + + public void performTest() + throws Exception + { + AlgorithmIdentifier algoId = new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1); + DataGroupHash[] datas = new DataGroupHash[2]; + + datas[0] = new DataGroupHash(1, new DEROctetString(generateHash())); + datas[1] = new DataGroupHash(2, new DEROctetString(generateHash())); + + LDSSecurityObject so = new LDSSecurityObject(algoId, datas); + + checkConstruction(so, algoId, datas); + + LDSVersionInfo versionInfo = new LDSVersionInfo("Hello", "world"); + + so = new LDSSecurityObject(algoId, datas, versionInfo); + + checkConstruction(so, algoId, datas, versionInfo); + + try + { + LDSSecurityObject.getInstance(null); + } + catch (Exception e) + { + fail("getInstance() failed to handle null."); + } + + try + { + LDSSecurityObject.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + LDSSecurityObject.getInstance(new DERSequence(v)); + + fail("constructor failed to detect empty sequence."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + new LDSSecurityObject(algoId, new DataGroupHash[1]); + + fail("constructor failed to detect small DataGroupHash array."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + new LDSSecurityObject(algoId, new DataGroupHash[LDSSecurityObject.ub_DataGroups + 1]); + + fail("constructor failed to out of bounds DataGroupHash array."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + LDSSecurityObject so, + AlgorithmIdentifier digestAlgorithmIdentifier, + DataGroupHash[] datagroupHash) + throws IOException + { + checkStatement(so, digestAlgorithmIdentifier, datagroupHash, null); + + so = LDSSecurityObject.getInstance(so); + + checkStatement(so, digestAlgorithmIdentifier, datagroupHash, null); + + ASN1InputStream aIn = new ASN1InputStream(so.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + so = LDSSecurityObject.getInstance(seq); + + checkStatement(so, digestAlgorithmIdentifier, datagroupHash, null); + } + + private void checkConstruction( + LDSSecurityObject so, + AlgorithmIdentifier digestAlgorithmIdentifier, + DataGroupHash[] datagroupHash, + LDSVersionInfo versionInfo) + throws IOException + { + if (so.getVersion() != 1) + { + fail("version number not 1"); + } + + checkStatement(so, digestAlgorithmIdentifier, datagroupHash, versionInfo); + + so = LDSSecurityObject.getInstance(so); + + checkStatement(so, digestAlgorithmIdentifier, datagroupHash, versionInfo); + + ASN1InputStream aIn = new ASN1InputStream(so.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + so = LDSSecurityObject.getInstance(seq); + + checkStatement(so, digestAlgorithmIdentifier, datagroupHash, versionInfo); + } + + private void checkStatement( + LDSSecurityObject so, + AlgorithmIdentifier digestAlgorithmIdentifier, + DataGroupHash[] datagroupHash, + LDSVersionInfo versionInfo) + { + if (digestAlgorithmIdentifier != null) + { + if (!so.getDigestAlgorithmIdentifier().equals(digestAlgorithmIdentifier)) + { + fail("ids don't match."); + } + } + else if (so.getDigestAlgorithmIdentifier() != null) + { + fail("digest algorithm Id found when none expected."); + } + + if (datagroupHash != null) + { + DataGroupHash[] datas = so.getDatagroupHash(); + + for (int i = 0; i != datas.length; i++) + { + if (!datagroupHash[i].equals(datas[i])) + { + fail("name registration authorities don't match."); + } + } + } + else if (so.getDatagroupHash() != null) + { + fail("data hash groups found when none expected."); + } + + if (versionInfo != null) + { + if (!versionInfo.equals(so.getVersionInfo())) + { + fail("versionInfo doesn't match"); + } + } + else if (so.getVersionInfo() != null) + { + fail("version info found when none expected."); + } + } + + public static void main( + String[] args) + { + runTest(new LDSSecurityObjectUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LinkedCertificateTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LinkedCertificateTest.java new file mode 100644 index 000000000..5ff2c55d6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LinkedCertificateTest.java @@ -0,0 +1,97 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.bc.LinkedCertificate; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.DigestInfo; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames; + +public class LinkedCertificateTest + extends ASN1UnitTest +{ + public String getName() + { + return "LinkedCertificate"; + } + + public void performTest() + throws Exception + { + DigestInfo digInfo = new DigestInfo( + new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256), new byte[32]); + GeneralName certLocation = new GeneralName(GeneralName.uniformResourceIdentifier, "https://www.bouncycastle.org/certs"); + X500Name certIssuer = null; + GeneralNames cACerts = null; + + LinkedCertificate linked = new LinkedCertificate(digInfo, certLocation); + + checkConstruction(linked, digInfo, certLocation, certIssuer, cACerts); + + certIssuer = new X500Name("CN=Test"); + cACerts = new GeneralNames(new GeneralName(new X500Name("CN=CA Test"))); + + linked = new LinkedCertificate(digInfo, certLocation, certIssuer, cACerts); + + checkConstruction(linked, digInfo, certLocation, certIssuer, cACerts); + + linked = LinkedCertificate.getInstance(null); + + if (linked != null) + { + fail("null getInstance() failed."); + } + + try + { + LinkedCertificate.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + LinkedCertificate linked, + DigestInfo digestInfo, GeneralName certLocation, X500Name certIssuer, GeneralNames caCerts) + throws IOException + { + checkValues(linked, digestInfo, certLocation, certIssuer, caCerts); + + linked = LinkedCertificate.getInstance(linked); + + checkValues(linked, digestInfo, certLocation, certIssuer, caCerts); + + ASN1InputStream aIn = new ASN1InputStream(linked.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + linked = LinkedCertificate.getInstance(seq); + + checkValues(linked, digestInfo, certLocation, certIssuer, caCerts); + } + + private void checkValues( + LinkedCertificate linked, + DigestInfo digestInfo, GeneralName certLocation, X500Name certIssuer, GeneralNames caCerts) + { + checkMandatoryField("digest", digestInfo, linked.getDigest()); + checkMandatoryField("certLocatin", certLocation, linked.getCertLocation()); + checkOptionalField("certIssuer", certIssuer, linked.getCertIssuer()); + checkOptionalField("caCerts", caCerts, linked.getCACerts()); + } + + public static void main( + String[] args) + { + runTest(new LinkedCertificateTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LocaleTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LocaleTest.java new file mode 100644 index 000000000..dc3c2a7a1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LocaleTest.java @@ -0,0 +1,63 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.text.DateFormat; +import java.util.Date; +import java.util.Locale; + +import com.fr.third.org.bouncycastle.asn1.DERGeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.DERUTCTime; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class LocaleTest + extends SimpleTest +{ + public String getName() + { + return "LocaleTest"; + } + + private void doTestLocale(Locale l) + throws Exception + { + long time = 1538063166000L; + String timeString = "180927154606GMT+00:00"; + String longTimeString = "20180927154606Z"; + + Locale.setDefault(l); + + isTrue("a", time == new DERUTCTime(timeString).getAdjustedDate().getTime()); + isTrue("b", time == new DERGeneralizedTime(longTimeString).getDate().getTime()); + + isTrue("c", time == new DERUTCTime(new Date(time)).getAdjustedDate().getTime()); + isTrue("d", time == new DERGeneralizedTime(new Date(time)).getDate().getTime()); + + Date d = new Date(); + + isTrue("e", (d.getTime() - (d.getTime() % 1000)) == new DERUTCTime(d).getAdjustedDate().getTime()); + isTrue("f", (d.getTime() - (d.getTime() % 1000)) == new DERGeneralizedTime(d).getDate().getTime()); + } + + public void performTest() + throws Exception + { + Locale defLocale = Locale.getDefault(); + + Locale list[] = DateFormat.getAvailableLocales(); + for (int i = 0; i != list.length; i++) + { + if (!list[i].getCountry().equals("TH") // skip Thailand as it appears the JVM is now a day out on this one. + && !list[i].getCountry().equals("JP")) // and it appears the change in era is causing issues here. + { + doTestLocale(list[i]); + } + } + + Locale.setDefault(defLocale); + } + + public static void main( + String[] args) + { + runTest(new LocaleTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LraPopWitnessTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LraPopWitnessTest.java new file mode 100644 index 000000000..6a1ce3e74 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/LraPopWitnessTest.java @@ -0,0 +1,42 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.LraPopWitness; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class LraPopWitnessTest + extends SimpleTest +{ + + public static void main(String[] args) + { + runTest(new LraPopWitnessTest()); + } + + public String getName() + { + return "LraPopWitnessTest"; + } + + public void performTest() + throws Exception + { + LraPopWitness popWitness = new LraPopWitness(new BodyPartID(10L), new DERSequence(new ASN1Integer(20L))); + byte[] b = popWitness.getEncoded(); + LraPopWitness popWitnessResult = LraPopWitness.getInstance(b); + + isTrue("BodyIds", Arrays.areEqual(popWitness.getBodyIds(), popWitnessResult.getBodyIds())); + isEquals("PkiDataBody", popWitness.getPkiDataBodyid(), popWitnessResult.getPkiDataBodyid()); + + try { + LraPopWitness.getInstance(new DERSequence()); + fail("Sequence length must be 2"); + } catch (Throwable t) { + isEquals("Exception class",t.getClass(), IllegalArgumentException.class); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/MiscTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/MiscTest.java new file mode 100644 index 000000000..980c1d0b8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/MiscTest.java @@ -0,0 +1,149 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Enumerated; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1OutputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.BERSequence; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DERIA5String; +import com.fr.third.org.bouncycastle.asn1.misc.CAST5CBCParameters; +import com.fr.third.org.bouncycastle.asn1.misc.IDEACBCPar; +import com.fr.third.org.bouncycastle.asn1.misc.NetscapeCertType; +import com.fr.third.org.bouncycastle.asn1.misc.NetscapeRevocationURL; +import com.fr.third.org.bouncycastle.asn1.misc.VerisignCzagExtension; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class MiscTest + extends SimpleTest +{ + public void shouldFailOnExtraData() + throws Exception + { + // basic construction + DERBitString s1 = new DERBitString(new byte[0], 0); + + ASN1Primitive.fromByteArray(s1.getEncoded()); + + ASN1Primitive.fromByteArray(new BERSequence(s1).getEncoded()); + + try + { + ASN1Primitive obj = ASN1Primitive.fromByteArray(Arrays.concatenate(s1.getEncoded(), new byte[1])); + fail("no exception"); + } + catch (IOException e) + { + if (!"Extra data detected in stream".equals(e.getMessage())) + { + fail("wrong exception"); + } + } + } + + public void derIntegerTest() + throws Exception + { + try + { + new ASN1Integer(new byte[] { 0, 0, 0, 1}); + } + catch (IllegalArgumentException e) + { + isTrue("wrong exc", "malformed integer".equals(e.getMessage())); + } + + try + { + new ASN1Integer(new byte[] {(byte)0xff, (byte)0x80, 0, 1}); + } + catch (IllegalArgumentException e) + { + isTrue("wrong exc", "malformed integer".equals(e.getMessage())); + } + + try + { + new ASN1Enumerated(new byte[] { 0, 0, 0, 1}); + } + catch (IllegalArgumentException e) + { + isTrue("wrong exc", "malformed enumerated".equals(e.getMessage())); + } + + try + { + new ASN1Enumerated(new byte[] {(byte)0xff, (byte)0x80, 0, 1}); + } + catch (IllegalArgumentException e) + { + isTrue("wrong exc", "malformed enumerated".equals(e.getMessage())); + } + } + + public void performTest() + throws Exception + { + byte[] testIv = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + ASN1Encodable[] values = { + new CAST5CBCParameters(testIv, 128), + new NetscapeCertType(NetscapeCertType.smime), + new VerisignCzagExtension(new DERIA5String("hello")), + new IDEACBCPar(testIv), + new NetscapeRevocationURL(new DERIA5String("http://test")) + }; + + byte[] data = Base64.decode("MA4ECAECAwQFBgcIAgIAgAMCBSAWBWhlbGxvMAoECAECAwQFBgcIFgtodHRwOi8vdGVzdA=="); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = ASN1OutputStream.create(bOut); + + for (int i = 0; i != values.length; i++) + { + aOut.writeObject(values[i].toASN1Primitive()); + } + + if (!areEqual(bOut.toByteArray(), data)) + { + fail("Failed data check"); + } + + ASN1InputStream aIn = new ASN1InputStream(data); + + for (int i = 0; i != values.length; i++) + { + ASN1Primitive o = aIn.readObject(); + if (!values[i].equals(o)) + { + fail("Failed equality test for " + o); + } + + if (o.hashCode() != values[i].hashCode()) + { + fail("Failed hashCode test for " + o); + } + } + + shouldFailOnExtraData(); + derIntegerTest(); + } + + public String getName() + { + return "Misc"; + } + + public static void main( + String[] args) + { + runTest(new MiscTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ModCertTemplateTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ModCertTemplateTest.java new file mode 100644 index 000000000..2522719dc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ModCertTemplateTest.java @@ -0,0 +1,83 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.DLSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartList; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartPath; +import com.fr.third.org.bouncycastle.asn1.cmc.ModCertTemplate; +import com.fr.third.org.bouncycastle.asn1.crmf.CertTemplate; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class ModCertTemplateTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new ModCertTemplateTest()); + } + + public String getName() + { + return "ModCertTemplateTest"; + } + + public void performTest() + throws Exception + { + + BodyPartPath pkiDataReference = new BodyPartPath(new BodyPartID(10L)); + BodyPartList certReferences = new BodyPartList(new BodyPartID(12L)); + boolean replace = false; + CertTemplate certTemplate = CertTemplate.getInstance(new DLSequence(new DERTaggedObject(false, 1, new ASN1Integer(34L)))); + { + ModCertTemplate modCertTemplate = new ModCertTemplate( + pkiDataReference, + certReferences, + replace, + certTemplate + ); + + byte[] b = modCertTemplate.getEncoded(); + + ModCertTemplate modCertTemplateResult = ModCertTemplate.getInstance(b); + + isEquals("pkiDataReference", modCertTemplate.getPkiDataReference(), modCertTemplateResult.getPkiDataReference()); + isEquals("certReference", modCertTemplate.getCertReferences(), modCertTemplateResult.getCertReferences()); + isEquals("replacingFields", modCertTemplate.isReplacingFields(), modCertTemplateResult.isReplacingFields()); + isEquals("certTemplate", modCertTemplate.getCertTemplate().getSerialNumber(), modCertTemplateResult.getCertTemplate().getSerialNumber()); + } + + + { + // Test default 'result' + ModCertTemplate mct = ModCertTemplate.getInstance(new DERSequence(new ASN1Encodable[]{ + pkiDataReference, + certReferences, + certTemplate + })); + + isEquals("pkiDataReference", mct.getPkiDataReference(), pkiDataReference); + isEquals("certReference", mct.getCertReferences(), certReferences); + isEquals("DEFAULT TRUE on replacingFields", mct.isReplacingFields(), true); + isEquals("certTemplate", mct.getCertTemplate().getSerialNumber(), certTemplate.getSerialNumber()); + } + + + try + { + ModCertTemplate.getInstance(new DERSequence()); + fail("Sequence must be 3 or 4."); + } + catch (Throwable t) + { + isEquals(t.getClass(), IllegalArgumentException.class); + } + + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/MonetaryLimitUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/MonetaryLimitUnitTest.java new file mode 100644 index 000000000..3d8b20b75 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/MonetaryLimitUnitTest.java @@ -0,0 +1,85 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.MonetaryLimit; + +public class MonetaryLimitUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "MonetaryLimit"; + } + + public void performTest() + throws Exception + { + String currency = "AUD"; + int amount = 1; + int exponent = 2; + + MonetaryLimit limit = new MonetaryLimit(currency, amount, exponent); + + checkConstruction(limit, currency, amount, exponent); + + limit = MonetaryLimit.getInstance(null); + + if (limit != null) + { + fail("null getInstance() failed."); + } + + try + { + MonetaryLimit.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + MonetaryLimit limit, + String currency, + int amount, + int exponent) + throws IOException + { + checkValues(limit, currency, amount, exponent); + + limit = MonetaryLimit.getInstance(limit); + + checkValues(limit, currency, amount, exponent); + + ASN1InputStream aIn = new ASN1InputStream(limit.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + limit = MonetaryLimit.getInstance(seq); + + checkValues(limit, currency, amount, exponent); + } + + private void checkValues( + MonetaryLimit limit, + String currency, + int amount, + int exponent) + { + checkMandatoryField("currency", currency, limit.getCurrency()); + checkMandatoryField("amount", amount, limit.getAmount().intValue()); + checkMandatoryField("exponent", exponent, limit.getExponent().intValue()); + } + + public static void main( + String[] args) + { + runTest(new MonetaryLimitUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/MonetaryValueUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/MonetaryValueUnitTest.java new file mode 100644 index 000000000..c26197d60 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/MonetaryValueUnitTest.java @@ -0,0 +1,88 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.x509.qualified.Iso4217CurrencyCode; +import com.fr.third.org.bouncycastle.asn1.x509.qualified.MonetaryValue; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class MonetaryValueUnitTest + extends SimpleTest +{ + private static final int TEST_AMOUNT = 100; + private static final int ZERO_EXPONENT = 0; + + private static final String CURRENCY_CODE = "AUD"; + + public String getName() + { + return "MonetaryValue"; + } + + public void performTest() + throws Exception + { + MonetaryValue mv = new MonetaryValue(new Iso4217CurrencyCode(CURRENCY_CODE), TEST_AMOUNT, ZERO_EXPONENT); + + checkValues(mv, TEST_AMOUNT, ZERO_EXPONENT); + + mv = MonetaryValue.getInstance(mv); + + checkValues(mv, TEST_AMOUNT, ZERO_EXPONENT); + + ASN1InputStream aIn = new ASN1InputStream(mv.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + mv = MonetaryValue.getInstance(seq); + + checkValues(mv, TEST_AMOUNT, ZERO_EXPONENT); + + mv = MonetaryValue.getInstance(null); + + if (mv != null) + { + fail("null getInstance() failed."); + } + + try + { + MonetaryValue.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkValues( + MonetaryValue mv, + int amount, + int exponent) + { + if (mv.getAmount().intValue() != amount) + { + fail("amounts don't match."); + } + + if (mv.getExponent().intValue() != exponent) + { + fail("exponents don't match."); + } + + Iso4217CurrencyCode cc = mv.getCurrency(); + + if (!cc.getAlphabetic().equals(CURRENCY_CODE)) + { + fail("currency code wrong"); + } + } + + public static void main( + String[] args) + { + runTest(new MonetaryValueUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/NameOrPseudonymUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/NameOrPseudonymUnitTest.java new file mode 100644 index 000000000..700197202 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/NameOrPseudonymUnitTest.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1String; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.x500.DirectoryString; +import com.fr.third.org.bouncycastle.asn1.x509.sigi.NameOrPseudonym; + +public class NameOrPseudonymUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "NameOrPseudonym"; + } + + public void performTest() + throws Exception + { + String pseudonym = "pseudonym"; + DirectoryString surname = new DirectoryString("surname"); + ASN1Sequence givenName = new DERSequence(new DirectoryString("givenName")); + + NameOrPseudonym id = new NameOrPseudonym(pseudonym); + + checkConstruction(id, pseudonym, null, null); + + id = new NameOrPseudonym(surname, givenName); + + checkConstruction(id, null, surname, givenName); + + id = NameOrPseudonym.getInstance(null); + + if (id != null) + { + fail("null getInstance() failed."); + } + + try + { + NameOrPseudonym.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + NameOrPseudonym id, + String pseudonym, + DirectoryString surname, + ASN1Sequence givenName) + throws IOException + { + checkValues(id, pseudonym, surname, givenName); + + id = NameOrPseudonym.getInstance(id); + + checkValues(id, pseudonym, surname, givenName); + + ASN1InputStream aIn = new ASN1InputStream(id.toASN1Primitive().getEncoded()); + + if (surname != null) + { + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + id = NameOrPseudonym.getInstance(seq); + } + else + { + ASN1String s = (ASN1String)aIn.readObject(); + + id = NameOrPseudonym.getInstance(s); + } + + checkValues(id, pseudonym, surname, givenName); + } + + private void checkValues( + NameOrPseudonym id, + String pseudonym, + DirectoryString surname, + ASN1Sequence givenName) + { + + if (surname != null) + { + checkMandatoryField("surname", surname, id.getSurname()); + checkMandatoryField("givenName", givenName, new DERSequence(id.getGivenName()[0])); + } + else + { + checkOptionalField("pseudonym", new DirectoryString(pseudonym), id.getPseudonym()); + } + } + + public static void main( + String[] args) + { + runTest(new NameOrPseudonymUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/NamingAuthorityUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/NamingAuthorityUnitTest.java new file mode 100644 index 000000000..c06d61a8f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/NamingAuthorityUnitTest.java @@ -0,0 +1,99 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.NamingAuthority; +import com.fr.third.org.bouncycastle.asn1.x500.DirectoryString; + +public class NamingAuthorityUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "NamingAuthority"; + } + + public void performTest() + throws Exception + { + ASN1ObjectIdentifier namingAuthorityID = new ASN1ObjectIdentifier("1.2.3"); + String namingAuthorityURL = "url"; + DirectoryString namingAuthorityText = new DirectoryString("text"); + + NamingAuthority auth = new NamingAuthority(namingAuthorityID, namingAuthorityURL, namingAuthorityText); + + checkConstruction(auth, namingAuthorityID, namingAuthorityURL, namingAuthorityText); + + auth = new NamingAuthority(null, namingAuthorityURL, namingAuthorityText); + + checkConstruction(auth, null, namingAuthorityURL, namingAuthorityText); + + auth = new NamingAuthority(namingAuthorityID, null, namingAuthorityText); + + checkConstruction(auth, namingAuthorityID, null, namingAuthorityText); + + auth = new NamingAuthority(namingAuthorityID, namingAuthorityURL, null); + + checkConstruction(auth, namingAuthorityID, namingAuthorityURL, null); + + auth = NamingAuthority.getInstance(null); + + if (auth != null) + { + fail("null getInstance() failed."); + } + + try + { + NamingAuthority.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + NamingAuthority auth, + ASN1ObjectIdentifier namingAuthorityID, + String namingAuthorityURL, + DirectoryString namingAuthorityText) + throws IOException + { + checkValues(auth, namingAuthorityID, namingAuthorityURL, namingAuthorityText); + + auth = NamingAuthority.getInstance(auth); + + checkValues(auth, namingAuthorityID, namingAuthorityURL, namingAuthorityText); + + ASN1InputStream aIn = new ASN1InputStream(auth.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + auth = NamingAuthority.getInstance(seq); + + checkValues(auth, namingAuthorityID, namingAuthorityURL, namingAuthorityText); + } + + private void checkValues( + NamingAuthority auth, + ASN1ObjectIdentifier namingAuthorityId, + String namingAuthorityURL, + DirectoryString namingAuthorityText) + { + checkOptionalField("namingAuthorityId", namingAuthorityId, auth.getNamingAuthorityId()); + checkOptionalField("namingAuthorityURL", namingAuthorityURL, auth.getNamingAuthorityUrl()); + checkOptionalField("namingAuthorityText", namingAuthorityText, auth.getNamingAuthorityText()); + } + + public static void main( + String[] args) + { + runTest(new NamingAuthorityUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/NetscapeCertTypeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/NetscapeCertTypeTest.java new file mode 100644 index 000000000..b0ccd2808 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/NetscapeCertTypeTest.java @@ -0,0 +1,34 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.misc.NetscapeCertType; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class NetscapeCertTypeTest + extends SimpleTest +{ + public String getName() + { + return "NetscapeCertType"; + } + + public void performTest() + throws IOException + { + BitStringConstantTester.testFlagValueCorrect(0, NetscapeCertType.sslClient); + BitStringConstantTester.testFlagValueCorrect(1, NetscapeCertType.sslServer); + BitStringConstantTester.testFlagValueCorrect(2, NetscapeCertType.smime); + BitStringConstantTester.testFlagValueCorrect(3, NetscapeCertType.objectSigning); + BitStringConstantTester.testFlagValueCorrect(4, NetscapeCertType.reserved); + BitStringConstantTester.testFlagValueCorrect(5, NetscapeCertType.sslCA); + BitStringConstantTester.testFlagValueCorrect(6, NetscapeCertType.smimeCA); + BitStringConstantTester.testFlagValueCorrect(7, NetscapeCertType.objectSigningCA); + } + + public static void main( + String[] args) + { + runTest(new NetscapeCertTypeTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OCSPTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OCSPTest.java new file mode 100644 index 000000000..a43cd80b1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OCSPTest.java @@ -0,0 +1,193 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.ByteArrayInputStream; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.ocsp.BasicOCSPResponse; +import com.fr.third.org.bouncycastle.asn1.ocsp.OCSPRequest; +import com.fr.third.org.bouncycastle.asn1.ocsp.OCSPResponse; +import com.fr.third.org.bouncycastle.asn1.ocsp.ResponseBytes; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; + +public class OCSPTest + implements Test +{ + private byte[] unsignedReq = Base64.decode( + "MEIwQDA+MDwwOjAJBgUrDgMCGgUABBRDb9GODnq7lRhSkEqw4XX24huERwQUkY4j" + + "a6eKuDlkVP9hRgkEvIWqHPECAQE="); + + private byte[] signedReq = Base64.decode( + "MIIC9jBAMD4wPDA6MAkGBSsOAwIaBQAEFENv0Y4OeruVGFKQSrDhdfbiG4RHBBTc" + + "Mr1fP+mZAxbF2ZdehWxn6mtAngIBAaCCArAwggKsMA0GCSqGSIb3DQEBBQUAA4GB" + + "AAzHBm4nL5AcRQB3Jkz7ScNeZF+GbRZ0p4kBDTnqi3IeESuso12yJhpqqyijdnj5" + + "gd4/GsSAgdluLHyYZ6wgozV7G9MDXCnFnG4PBUW05HaVX81JYAp+amVyU0NOgNrG" + + "90npVBsHb0o+UlkxNgMiEbSkp/TeGb6YURsYKhmwp7BgoIICFTCCAhEwggINMIIB" + + "dqADAgECAgEBMA0GCSqGSIb3DQEBBAUAMCUxFjAUBgNVBAoTDUJvdW5jeSBDYXN0" + + "bGUxCzAJBgNVBAYTAkFVMB4XDTA0MTAyNDEzNDc0M1oXDTA1MDIwMTEzNDc0M1ow" + + "JTEWMBQGA1UEChMNQm91bmN5IENhc3RsZTELMAkGA1UEBhMCQVUwgZ8wDQYJKoZI" + + "hvcNAQEBBQADgY0AMIGJAoGBAJBmLeIzthMHUeTkOeJ76iBxcMHY31o/i3a9VT12" + + "y2FcS/ejJmeUCMTdtwl5alOwXY66vF4DyT1VU/nJG3mHpSoqq7qrMXOIFGcXg1Wf" + + "oJRrQgTOLdQ6bod7i9ME/EjEJy70orh0nVS7NGcu0R5TjcbLde2J5zxjb/W9wqfy" + + "RovJAgMBAAGjTTBLMB0GA1UdDgQWBBTcMr1fP+mZAxbF2ZdehWxn6mtAnjAfBgNV" + + "HSMEGDAWgBTcMr1fP+mZAxbF2ZdehWxn6mtAnjAJBgNVHRMEAjAAMA0GCSqGSIb3" + + "DQEBBAUAA4GBAF/4EH1KkNrNxocJPIp7lThmG1KIVYESIadowMowrbok46ESofRF" + + "OIPku07W+e1Y1Y1KXLIiPMG3IGwrBrn04iLsbbBUiN37BcC/VyT4xKJ2MYscGjKL" + + "ua/9bU0lOyeTRAwqb8towWRd5lLYAI3RQ7dhStUTFp3Vqd803PJ/cpR6"); + + private byte[] response = Base64.decode( + "MIIFnAoBAKCCBZUwggWRBgkrBgEFBQcwAQEEggWCMIIFfjCCARehgZ8wgZwx" + + "CzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEgcHJhZGVzaDESMBAGA1UE" + + "BxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAKBgNVBAsTA0FUQzEeMBwG" + + "A1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQwIgYJKoZIhvcNAQkBFhVv" + + "Y3NwQHRjcy1jYS50Y3MuY28uaW4YDzIwMDMwNDAyMTIzNDU4WjBiMGAwOjAJ" + + "BgUrDgMCGgUABBRs07IuoCWNmcEl1oHwIak1BPnX8QQUtGyl/iL9WJ1VxjxF" + + "j0hAwJ/s1AcCAQKhERgPMjAwMjA4MjkwNzA5MjZaGA8yMDAzMDQwMjEyMzQ1" + + "OFowDQYJKoZIhvcNAQEFBQADgYEAfbN0TCRFKdhsmvOdUoiJ+qvygGBzDxD/" + + "VWhXYA+16AphHLIWNABR3CgHB3zWtdy2j7DJmQ/R7qKj7dUhWLSqclAiPgFt" + + "QQ1YvSJAYfEIdyHkxv4NP0LSogxrumANcDyC9yt/W9yHjD2ICPBIqCsZLuLk" + + "OHYi5DlwWe9Zm9VFwCGgggPMMIIDyDCCA8QwggKsoAMCAQICAQYwDQYJKoZI" + + "hvcNAQEFBQAwgZQxFDASBgNVBAMTC1RDUy1DQSBPQ1NQMSYwJAYJKoZIhvcN" + + "AQkBFhd0Y3MtY2FAdGNzLWNhLnRjcy5jby5pbjEMMAoGA1UEChMDVENTMQww" + + "CgYDVQQLEwNBVEMxEjAQBgNVBAcTCUh5ZGVyYWJhZDEXMBUGA1UECBMOQW5k" + + "aHJhIHByYWRlc2gxCzAJBgNVBAYTAklOMB4XDTAyMDgyOTA3MTE0M1oXDTAz" + + "MDgyOTA3MTE0M1owgZwxCzAJBgNVBAYTAklOMRcwFQYDVQQIEw5BbmRocmEg" + + "cHJhZGVzaDESMBAGA1UEBxMJSHlkZXJhYmFkMQwwCgYDVQQKEwNUQ1MxDDAK" + + "BgNVBAsTA0FUQzEeMBwGA1UEAxMVVENTLUNBIE9DU1AgUmVzcG9uZGVyMSQw" + + "IgYJKoZIhvcNAQkBFhVvY3NwQHRjcy1jYS50Y3MuY28uaW4wgZ8wDQYJKoZI" + + "hvcNAQEBBQADgY0AMIGJAoGBAM+XWW4caMRv46D7L6Bv8iwtKgmQu0SAybmF" + + "RJiz12qXzdvTLt8C75OdgmUomxp0+gW/4XlTPUqOMQWv463aZRv9Ust4f8MH" + + "EJh4ekP/NS9+d8vEO3P40ntQkmSMcFmtA9E1koUtQ3MSJlcs441JjbgUaVnm" + + "jDmmniQnZY4bU3tVAgMBAAGjgZowgZcwDAYDVR0TAQH/BAIwADALBgNVHQ8E" + + "BAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwkwNgYIKwYBBQUHAQEEKjAoMCYG" + + "CCsGAQUFBzABhhpodHRwOi8vMTcyLjE5LjQwLjExMDo3NzAwLzAtBgNVHR8E" + + "JjAkMCKgIKAehhxodHRwOi8vMTcyLjE5LjQwLjExMC9jcmwuY3JsMA0GCSqG" + + "SIb3DQEBBQUAA4IBAQB6FovM3B4VDDZ15o12gnADZsIk9fTAczLlcrmXLNN4" + + "PgmqgnwF0Ymj3bD5SavDOXxbA65AZJ7rBNAguLUo+xVkgxmoBH7R2sBxjTCc" + + "r07NEadxM3HQkt0aX5XYEl8eRoifwqYAI9h0ziZfTNes8elNfb3DoPPjqq6V" + + "mMg0f0iMS4W8LjNPorjRB+kIosa1deAGPhq0eJ8yr0/s2QR2/WFD5P4aXc8I" + + "KWleklnIImS3zqiPrq6tl2Bm8DZj7vXlTOwmraSQxUwzCKwYob1yGvNOUQTq" + + "pG6jxn7jgDawHU1+WjWQe4Q34/pWeGLysxTraMa+Ug9kPe+jy/qRX2xwvKBZ"); + + private boolean isSameAs( + byte[] a, + byte[] b) + { + if (a.length != b.length) + { + return false; + } + + for (int i = 0; i != a.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + private TestResult unsignedRequest() + { + try + { + ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(unsignedReq)); + OCSPRequest req = OCSPRequest.getInstance(aIn.readObject()); + + if (!isSameAs(req.getEncoded(), unsignedReq)) + { + return new SimpleTestResult(false, getName() + ": OCSP unsigned request failed to re-encode"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed unsigned exception - " + e.toString(), e); + } + } + + private TestResult signedRequest() + { + try + { + ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(signedReq)); + OCSPRequest req = OCSPRequest.getInstance(aIn.readObject()); + + if (!isSameAs(req.getEncoded(), signedReq)) + { + return new SimpleTestResult(false, getName() + ": OCSP signed request failed to re-encode"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed signed exception - " + e.toString(), e); + } + } + + private TestResult response() + { + try + { + ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(response)); + OCSPResponse resp = OCSPResponse.getInstance(aIn.readObject()); + ResponseBytes rBytes = ResponseBytes.getInstance(resp.getResponseBytes()); + + aIn = new ASN1InputStream(new ByteArrayInputStream(rBytes.getResponse().getOctets())); + + BasicOCSPResponse bResp = BasicOCSPResponse.getInstance(aIn.readObject()); + + resp = new OCSPResponse(resp.getResponseStatus(), new ResponseBytes(rBytes.getResponseType(), new DEROctetString(bResp.getEncoded()))); + + if (!isSameAs(resp.getEncoded(), response)) + { + return new SimpleTestResult(false, getName() + ": OCSP response failed to re-encode"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed response exception - " + e.toString(), e); + } + } + + public TestResult perform() + { + TestResult res = unsignedRequest(); + + if (!res.isSuccessful()) + { + return res; + } + + res = signedRequest(); + if (!res.isSuccessful()) + { + return res; + } + + return response(); + } + + public String getName() + { + return "OCSP"; + } + + public static void main( + String[] args) + { + OCSPTest test = new OCSPTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OIDTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OIDTest.java new file mode 100644 index 000000000..02ac10bc8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OIDTest.java @@ -0,0 +1,161 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1OutputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +/** + * X.690 test example + */ +public class OIDTest + extends SimpleTest +{ + byte[] req1 = Hex.decode("0603813403"); + byte[] req2 = Hex.decode("06082A36FFFFFFDD6311"); + + public String getName() + { + return "OID"; + } + + private void recodeCheck( + String oid, + byte[] enc) + throws IOException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(enc); + ASN1InputStream aIn = new ASN1InputStream(bIn); + + ASN1ObjectIdentifier o = new ASN1ObjectIdentifier(oid); + ASN1ObjectIdentifier encO = (ASN1ObjectIdentifier)aIn.readObject(); + + if (!o.equals(encO)) + { + fail("oid ID didn't match", o, encO); + } + + byte[] bytes = o.getEncoded(ASN1Encoding.DER); + + if (bytes.length != enc.length) + { + fail("failed length test"); + } + + for (int i = 0; i != enc.length; i++) + { + if (bytes[i] != enc[i]) + { + fail("failed comparison test", new String(Hex.encode(enc)), new String(Hex.encode(bytes))); + } + } + } + + private void validOidCheck( + String oid) + throws IOException + { + ASN1ObjectIdentifier o = new ASN1ObjectIdentifier(oid); + o = (ASN1ObjectIdentifier)ASN1Primitive.fromByteArray(o.getEncoded()); + if (!o.getId().equals(oid)) + { + fail("failed oid check for " + oid); + } + } + + private void invalidOidCheck( + String oid) + { + try + { + new ASN1ObjectIdentifier(oid); + fail("failed to catch bad oid: " + oid); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void branchCheck(String stem, String branch) + { + String expected = stem + "." + branch; + String actual = new ASN1ObjectIdentifier(stem).branch(branch).getId(); + + if (!expected.equals(actual)) + { + fail("failed 'branch' check for " + stem + "/" + branch); + } + } + + private void onCheck(String stem, String test, boolean expected) + { + if (expected != new ASN1ObjectIdentifier(test).on(new ASN1ObjectIdentifier(stem))) + { + fail("failed 'on' check for " + stem + "/" + test); + } + } + + public void performTest() + throws IOException + { + recodeCheck("2.100.3", req1); + recodeCheck("1.2.54.34359733987.17", req2); + + validOidCheck(PKCSObjectIdentifiers.pkcs_9_at_contentType.getId()); + validOidCheck("0.1"); + validOidCheck("1.0"); + validOidCheck("1.0.2"); + validOidCheck("1.0.20"); + validOidCheck("1.0.200"); + validOidCheck("1.1.127.32512.8323072.2130706432.545460846592.139637976727552.35747322042253312.9151314442816847872"); + validOidCheck("1.2.123.12345678901.1.1.1"); + validOidCheck("2.25.196556539987194312349856245628873852187.1"); + + invalidOidCheck("0"); + invalidOidCheck("1"); + invalidOidCheck("2"); + invalidOidCheck("3.1"); + invalidOidCheck("0.01"); + invalidOidCheck("00.1"); + invalidOidCheck("1.00.2"); + invalidOidCheck("1.0.02"); + invalidOidCheck("1.2.00"); + invalidOidCheck("..1"); + invalidOidCheck("192.168.1.1"); + invalidOidCheck(".123452"); + invalidOidCheck("1."); + invalidOidCheck("1.345.23.34..234"); + invalidOidCheck("1.345.23.34.234."); + invalidOidCheck(".12.345.77.234"); + invalidOidCheck(".12.345.77.234."); + invalidOidCheck("1.2.3.4.A.5"); + invalidOidCheck("1,2"); + + branchCheck("1.1", "2.2"); + + onCheck("1.1", "1.1", false); + onCheck("1.1", "1.2", false); + onCheck("1.1", "1.2.1", false); + onCheck("1.1", "2.1", false); + onCheck("1.1", "1.11", false); + onCheck("1.12", "1.1.2", false); + onCheck("1.1", "1.1.1", true); + onCheck("1.1", "1.1.2", true); + } + + public static void main( + String[] args) + { + runTest(new OIDTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ObjectIdentifierTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ObjectIdentifierTest.java new file mode 100644 index 000000000..e87db7821 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ObjectIdentifierTest.java @@ -0,0 +1,85 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class ObjectIdentifierTest + extends SimpleTest +{ + public String getName() + { + return "ObjectIdentifier"; + } + + public void performTest() + throws Exception + { + // exercise the object cache + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 100; j++) + { + final ASN1ObjectIdentifier oid1 = new ASN1ObjectIdentifier("1.1." + i + "." + j); + final byte[] encoded1 = oid1.getEncoded(); + final ASN1ObjectIdentifier oid2 = ASN1ObjectIdentifier.getInstance(encoded1); + if (oid1 == oid2) + { + fail("Shouldn't be the same: " + oid1 + " " + oid2); + } + if (!oid1.equals(oid2)) + { + fail("Should be equal: " + oid1 + " " + oid2); + } + final ASN1ObjectIdentifier oid3 = oid2.intern(); + if (oid2 != oid3) + { + fail("Should be the same: " + oid2 + " " + oid3); + } + if (!oid2.equals(oid3)) + { + fail("Should be equal: " + oid2 + " " + oid3); + } + final byte[] encoded2 = oid3.getEncoded(); + final ASN1ObjectIdentifier oid4 = ASN1ObjectIdentifier.getInstance(encoded2); + if (oid3 != oid4) + { + fail("Should be taken from cache: " + oid3 + " " + oid4); + } + if (!oid3.equals(oid4)) + { + fail("Should be equal: " + oid3 + " " + oid4); + } + } + } + + // make sure we're not leaking memory + for (int i = 0; i < 100; i++) + { + for (int j = 0; j < 100; j++) + { + final ASN1ObjectIdentifier oid1 = new ASN1ObjectIdentifier("1.1.2." + i + "." + j); + final byte[] encoded1 = oid1.getEncoded(); + final ASN1ObjectIdentifier oid2 = ASN1ObjectIdentifier.getInstance(encoded1); + final ASN1ObjectIdentifier oid3 = ASN1ObjectIdentifier.getInstance(encoded1); + if (oid1 == oid2) + { + fail("Shouldn't be the same: " + oid1 + " " + oid2); + } + if (oid2 == oid3) + { + fail("Shouldn't be the same: " + oid2 + " " + oid3); + } + } + } + } + + public static void main( + String[] args) + { + ObjectIdentifierTest test = new ObjectIdentifierTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherCertIDUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherCertIDUnitTest.java new file mode 100644 index 000000000..17bad7ece --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherCertIDUnitTest.java @@ -0,0 +1,97 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ess.OtherCertID; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames; +import com.fr.third.org.bouncycastle.asn1.x509.IssuerSerial; + +public class OtherCertIDUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "OtherCertID"; + } + + public void performTest() + throws Exception + { + AlgorithmIdentifier algId = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.2.3")); + byte[] digest = new byte[20]; + IssuerSerial issuerSerial = new IssuerSerial(new GeneralNames(new GeneralName(new X500Name("CN=test"))), new ASN1Integer(1)); + + OtherCertID certID = new OtherCertID(algId, digest); + + checkConstruction(certID, algId, digest, null); + + certID = new OtherCertID(algId, digest, issuerSerial); + + checkConstruction(certID, algId, digest, issuerSerial); + + certID = OtherCertID.getInstance(null); + + if (certID != null) + { + fail("null getInstance() failed."); + } + + try + { + OtherCertID.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + OtherCertID certID, + AlgorithmIdentifier algId, + byte[] digest, + IssuerSerial issuerSerial) + throws IOException + { + checkValues(certID, algId, digest, issuerSerial); + + certID = OtherCertID.getInstance(certID); + + checkValues(certID, algId, digest, issuerSerial); + + ASN1InputStream aIn = new ASN1InputStream(certID.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + certID = OtherCertID.getInstance(seq); + + checkValues(certID, algId, digest, issuerSerial); + } + + private void checkValues( + OtherCertID certID, + AlgorithmIdentifier algId, + byte[] digest, + IssuerSerial issuerSerial) + { + checkMandatoryField("algorithmHash", algId, certID.getAlgorithmHash()); + checkMandatoryField("certHash", digest, certID.getCertHash()); + + checkOptionalField("issuerSerial", issuerSerial, certID.getIssuerSerial()); + } + + public static void main( + String[] args) + { + runTest(new OtherCertIDUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherMsgTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherMsgTest.java new file mode 100644 index 000000000..16b3d3d64 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherMsgTest.java @@ -0,0 +1,42 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERUTF8String; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.OtherMsg; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class OtherMsgTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new OtherMsgTest()); + } + + public String getName() + { + return "OtherMsgTest"; + } + + public void performTest() + throws Exception + { + OtherMsg otherMsg = new OtherMsg(new BodyPartID(10L), PKCSObjectIdentifiers.id_aa, new DERUTF8String("Cats")); + byte[] b = otherMsg.getEncoded(); + OtherMsg otherMsgResult = OtherMsg.getInstance(b); + + isEquals("bodyPartID", otherMsg.getBodyPartID(), otherMsgResult.getBodyPartID()); + isEquals("otherMsgType", otherMsg.getOtherMsgType(), otherMsgResult.getOtherMsgType()); + isEquals("otherMsgValue", otherMsg.getOtherMsgValue(), otherMsgResult.getOtherMsgValue()); + + try { + OtherMsg.getInstance(new DERSequence()); + fail("Sequence should be 3 elements long."); + } catch (Throwable t) { + isEquals("Sequence size",t.getClass(), IllegalArgumentException.class); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherSigningCertificateUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherSigningCertificateUnitTest.java new file mode 100644 index 000000000..d213c2881 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherSigningCertificateUnitTest.java @@ -0,0 +1,86 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ess.OtherCertID; +import com.fr.third.org.bouncycastle.asn1.ess.OtherSigningCertificate; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +public class OtherSigningCertificateUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "OtherSigningCertificate"; + } + + public void performTest() + throws Exception + { + AlgorithmIdentifier algId = new AlgorithmIdentifier(new ASN1ObjectIdentifier("1.2.2.3")); + byte[] digest = new byte[20]; + OtherCertID otherCertID = new OtherCertID(algId, digest); + + OtherSigningCertificate otherCert = new OtherSigningCertificate(otherCertID); + + checkConstruction(otherCert, otherCertID); + + otherCert = OtherSigningCertificate.getInstance(null); + + if (otherCert != null) + { + fail("null getInstance() failed."); + } + + try + { + OtherCertID.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + OtherSigningCertificate otherCert, + OtherCertID otherCertID) + throws IOException + { + checkValues(otherCert, otherCertID); + + otherCert = OtherSigningCertificate.getInstance(otherCert); + + checkValues(otherCert, otherCertID); + + ASN1InputStream aIn = new ASN1InputStream(otherCert.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + otherCert = OtherSigningCertificate.getInstance(seq); + + checkValues(otherCert, otherCertID); + } + + private void checkValues( + OtherSigningCertificate otherCert, + OtherCertID otherCertID) + { + if (otherCert.getCerts().length != 1) + { + fail("getCerts() length wrong"); + } + checkMandatoryField("getCerts()[0]", otherCertID, otherCert.getCerts()[0]); + } + + public static void main( + String[] args) + { + runTest(new OtherSigningCertificateUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherStatusInfoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherStatusInfoTest.java new file mode 100644 index 000000000..e6355cc53 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/OtherStatusInfoTest.java @@ -0,0 +1,68 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.util.Date; + +import com.fr.third.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.cmc.CMCFailInfo; +import com.fr.third.org.bouncycastle.asn1.cmc.ExtendedFailInfo; +import com.fr.third.org.bouncycastle.asn1.cmc.OtherStatusInfo; +import com.fr.third.org.bouncycastle.asn1.cmc.PendInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class OtherStatusInfoTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new OtherStatusInfoTest()); + } + + public String getName() + { + return "OtherStatusInfoTest"; + } + + public void performTest() + throws Exception + { + { + OtherStatusInfo ose = OtherStatusInfo.getInstance(CMCFailInfo.badCertId.toASN1Primitive()); + byte[] b = ose.getEncoded(); + OtherStatusInfo oseResult = OtherStatusInfo.getInstance(b); + + isEquals("isFailInfo", oseResult.isFailInfo(), true); + isEquals("isPendInfo", oseResult.isPendingInfo(), false); + isEquals("isExtendedFailInfo", oseResult.isExtendedFailInfo(), false); + + isEquals(ose, oseResult); + } + + { + OtherStatusInfo ose = OtherStatusInfo.getInstance(new PendInfo("Fish".getBytes(), new ASN1GeneralizedTime(new Date()))); + byte[] b = ose.getEncoded(); + OtherStatusInfo oseResult = OtherStatusInfo.getInstance(b); + + isEquals("isFailInfo", oseResult.isFailInfo(), false); + isEquals("isPendInfo", oseResult.isPendingInfo(), true); + isEquals("isExtendedFailInfo", oseResult.isExtendedFailInfo(), false); + + isEquals(ose, oseResult); + } + + { + OtherStatusInfo ose = OtherStatusInfo.getInstance( + new ExtendedFailInfo(PKCSObjectIdentifiers.canNotDecryptAny, new ASN1Integer(10L))); + byte[] b = ose.getEncoded(); + OtherStatusInfo oseResult = OtherStatusInfo.getInstance(b); + + isEquals("isFailInfo", oseResult.isFailInfo(), false); + isEquals("isPendInfo", oseResult.isPendingInfo(), false); + isEquals("isExtendedFailInfo", oseResult.isExtendedFailInfo(), true); + + isEquals(ose, oseResult); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKCS10Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKCS10Test.java new file mode 100644 index 000000000..285525167 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKCS10Test.java @@ -0,0 +1,95 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.ByteArrayInputStream; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.pkcs.CertificationRequest; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class PKCS10Test + implements Test +{ + byte[] req1 = Base64.decode( + "MIHoMIGTAgEAMC4xDjAMBgNVBAMTBVRlc3QyMQ8wDQYDVQQKEwZBbmFUb20xCzAJBgNVBAYTAlNF" + + "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALlEt31Tzt2MlcOljvacJgzQVhmlMoqAOgqJ9Pgd3Gux" + + "Z7/WcIlgW4QCB7WZT21O1YoghwBhPDMcNGrHei9kHQkCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA0EA" + + "NDEI4ecNtJ3uHwGGlitNFq9WxcoZ0djbQJ5hABMotav6gtqlrwKXY2evaIrsNwkJtNdwwH18aQDU" + + "KCjOuBL38Q=="); + + byte[] req2 = Base64.decode( + "MIIB6TCCAVICAQAwgagxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRQwEgYDVQQH" + + "EwtTYW50YSBDbGFyYTEMMAoGA1UEChMDQUJCMVEwTwYDVQQLHEhQAAAAAAAAAG8AAAAAAAAAdwAA" + + "AAAAAABlAAAAAAAAAHIAAAAAAAAAIAAAAAAAAABUAAAAAAAAABxIAAAAAAAARAAAAAAAAAAxDTAL" + + "BgNVBAMTBGJsdWUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANETRZ+6occCOrFxNhfKIp4C" + + "mMkxwhBNb7TnnahpbM9O0r4hrBPcfYuL7u9YX/jN0YNUP+/CiT39HhSe/bikaBPDEyNsl988I8vX" + + "piEdgxYq/+LTgGHbjRsRYCkPtmzwBbuBldNF8bV7pu0v4UScSsExmGqqDlX1TbPU8KkPU1iTAgMB" + + "AAGgADANBgkqhkiG9w0BAQQFAAOBgQAFbrs9qUwh93CtETk7DeUD5HcdCnxauo1bck44snSV6MZV" + + "OCIGaYu1501kmhEvAtVVRr6SEHwimfQDDIjnrWwYsEr/DT6tkTZAbfRd3qUu3iKjT0H0vlUZp0hJ" + + "66mINtBM84uZFBfoXiWY8M3FuAnGmvy6ah/dYtJorTxLKiGkew=="); + + public String getName() + { + return "PKCS10"; + } + + public TestResult pkcs10Test( + String testName, + byte[] req) + { + try + { + ByteArrayInputStream bIn = new ByteArrayInputStream(req); + ASN1InputStream aIn = new ASN1InputStream(bIn); + + CertificationRequest r = new CertificationRequest((ASN1Sequence)aIn.readObject()); + + byte[] bytes = r.getEncoded(ASN1Encoding.DER); + + if (bytes.length != req.length) + { + return new SimpleTestResult(false, getName() + ": " + testName + " failed length test"); + } + + for (int i = 0; i != req.length; i++) + { + if (bytes[i] != req[i]) + { + return new SimpleTestResult(false, getName() + ": " + testName + " failed comparison test"); + } + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": Exception - " + testName + " " + e.toString()); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public TestResult perform() + { + TestResult res = pkcs10Test("basic CR", req1); + + if (!res.isSuccessful()) + { + return res; + } + + return pkcs10Test("Universal CR", req2); + } + + public static void main( + String[] args) + { + Test test = new PKCS10Test(); + + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKCS12Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKCS12Test.java new file mode 100644 index 000000000..84df8172b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKCS12Test.java @@ -0,0 +1,214 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.ByteArrayInputStream; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.BEROctetString; +import com.fr.third.org.bouncycastle.asn1.DLSequence; +import com.fr.third.org.bouncycastle.asn1.pkcs.AuthenticatedSafe; +import com.fr.third.org.bouncycastle.asn1.pkcs.ContentInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.EncryptedData; +import com.fr.third.org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.MacData; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.Pfx; +import com.fr.third.org.bouncycastle.asn1.pkcs.SafeBag; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.DigestInfo; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class PKCS12Test + extends SimpleTest +{ + byte[] pkcs12 = Base64.decode( + "MIACAQMwgAYJKoZIhvcNAQcBoIAkgASCA+gwgDCABgkqhkiG9w0BBwGggCSA" + + "BIIDRDCCA0AwggM8BgsqhkiG9w0BDAoBAqCCArEwggKtMCcGCiqGSIb3DQEM" + + "AQMwGQQUFlnNVpQoEHc+J3UEGxARipkHu5kCAWQEggKAAH9tmy40lly6QDoc" + + "1TfmY9y2qysD+lrgk+dnxP04RfoJfycTRDeaz2sPLImZtio9nsqCFqtzU/sl" + + "eWigbH34BpKU1sC0Gq1cyik0GO65sW95S6YjKtGcGOBfQCPk1oQjfiqnfU3G" + + "oeOaG3COQJukMFj8unv55u0xbX1hwO8SsZmr9RjPzLrVaeY6BP5+CCzOKBaj" + + "GxneIDqnQW7/kBIVWK7M+JXGdgQyiKhD6NvXL/zD8oKEne0nIX7IokQuWEn6" + + "8Sglv5OSclsSdvHTk57bCuV5lVzoIzczA4J/LZWdrtITeVefBLQSalBzpRde" + + "rSTMj485z2x5ChizhjE627/KQ5vkKQkQVqXYYXVyeTvKZRpL7vz13C4DUCwN" + + "im1XvNSCNebXS1yHJRtcONDhGJN3UsrVjHr+2kCfE5SCEeSU/dqgNLuLa1tk" + + "5+jwZFNj/HjO88wlOwPCol1uuJjDpaEW7dxu5qsVSfZhEXWHs8rZAMttFMzi" + + "yxsEkZe8kqngRbNJOY6KpppYedsMWDusUJGfIHo+8zymiw3gv/z+lmFOlDGt" + + "CKMk9Es/MgfjpbfhbTVYHOBKS6Qyrz7LdTuBMI8XdsZMuN+Uf73690ggLmKW" + + "IELUg8h1RX0ra2n6jOc/1rnebAifMhiMkL1ABQvqOobfOrG/9h9XcXoi64Qr" + + "htc3T7yMAHafBX5KUcNkbcn6kssYhpvd8bPADoLBnbx3GxGh/uziB0zKQEI0" + + "GnaY4SL7aR4C5xNNi41lYtsR6ohKyfPEGslhrhd4axx0cKxC2sHgVl0k+r8B" + + "8Vu44XHbW8LqdspjOHN9qg2erES1Dvgj05SfHDup+V6a3ogJo2YKXOiu3DF4" + + "MFEGCSqGSIb3DQEJFDFEHkIARABhAHYAaQBkACAARwAuACAASABvAG8AawAn" + + "AHMAIABWAGUAcgBpAFMAaQBnAG4ALAAgAEkAbgBjAC4AIABJAEQwIwYJKoZI" + + "hvcNAQkVMRYEFKEcMJ798oZLFkH0OnpbUBnrTLgWAAAAAAAAMIAGCSqGSIb3" + + "DQEHBqCAMIACAQAwgAYJKoZIhvcNAQcBMCcGCiqGSIb3DQEMAQYwGQQUTErH" + + "kWZ8nBXZYWO53FH4yqRZZsECAWSggASCDGCreuCr6/azcOv5w04bN3jkg4G2" + + "dsvTPAjL8bichaEOQCykhuNPt1dv3FsjUsdFC550K0+Y48RyBIID6JTiN9Gj" + + "K+a5aLPaXgTRdY74Toof1hYtZ4DIcVyq25LezVQHoe/++pAgEpWjqHTxVDIv" + + "YFAgT2oDB+2vkeXM61XnNWOjwCY3pXpk/VGjyN4USkD7Q/Y6tPjQOywvQE7c" + + "Ab1z62k9iMia7Yk/qmh+zJu4SSneo0/RLLdMZOlGZv89MResVG038TC8MTA9" + + "Uf+wDRcS20d7XDbTaBAgju8TpFIw5/lbDi0feUVlk6L+jkT1ktaTc1Pwtxn7" + + "psXMFW6HAWB4exOi09297R9BCOQX6vcetK/iA/3jIC6NuTdizYof0DWetdGy" + + "haIkMiEnERYE3unJocH4fq585Rw6mE+BYssPVPkVWZZInF3l69bKduuxsQt+" + + "pcApgBVsTjsU+1FOiUxuW2wWKi70RcQprPv5Ef1A5FRNxPFp+7IzLNlE4qCo" + + "wvC6NTpeuRw3aGsXSfqHmSddrHugNPmghNgG5lv1Ef7A8MUuyp8fyjAgxCDk" + + "4Hpb8PCHGj5t//Fr6Cd0MygJMIFQmv4kUd2LVHxQ9A9WFNCqTz/nBe+ZRLJL" + + "NghTv6gGpjGJiBnXYv6Sod2fs+5J2GIvex4qbdh6gzZIU2YTAwpj6Aca3SjA" + + "X8+m8AXt2SC3Z6T5+m8SxyiNp2P511paV/TZKtLWXQGKeEX1JXhQkaM6Q5W/" + + "IhSgC8/gppk1gbIraBqrW8bEnGBnC03wi0OnMz3ohM4CVHyaW3dQquT2+u6F" + + "8VeGXAYHU022NkrpPl/VlfNNEAyisU2+oJqpPZkqL6FsDWF3k6Fq2jXBLL+/" + + "a0WA82jIpgjNeXze/cgoHtU023V9E9Qcu+5nPBYdCTR4sRxvHLANii0W8lPv" + + "tvU5XO1UsEjHDfKL4E1bhGzGpb/OU5yg/98EN95r/xdFL5G+XVyHeR0UtkcB" + + "IuvyBdhkwoprCjkcgLZe8FPIBNw84HRe7Ye6f2gDW/F5uej6rBehJS1VFvCh" + + "DXzkajGmK40Gc2APS1/1vZqPu68polgw9dT84rem36PLEOq4KuU7n4QE0g7T" + + "YR2G8+4FNgQTjjg/qw3lX+sj6yLn1lYt1dOVvkiM8i8tdZg/3pCKKAW1uV7a" + + "astlBxVSkFfn1BrFTc2oFGkTrlUg90a+parOfGHTfDiaHX8ouEg63fk0+Xdi" + + "FCarXsqHNPDbpmWLKw8TAmdeneGipyScntJJk4ajy+jROQBgGew3ofOmfkqm" + + "oJFNwUvKOXN2ucViLZgsdK/7YgV1OR7oiTh8knQNPk3d5fRYSMFf9GJTjQRV" + + "y2CLdICAVzvrUXf9k7miWYkjIp2/HGD7pOH018sX9MrpfJKqvdPFOssZiFd0" + + "I2FUbgcEggPotvnT0XoabEiurTm8EPPpw66NKmK/H1kQL0hEtdIazPxfLmm/" + + "ZUDokwa7d4bE3BwFh0weQfEvMzJu6Y5E7ir2MqD33XaGMOGys1nst1SPPyDB" + + "WpOWD9w7Ng3yU1JVzqFWuVXaXDYbfnlG7AGevKF5PYNZj/RIQBBf5Xle9hTd" + + "c9CtxPkrsJwA8DeAwKl2WIfbXGzAYLSnXoYUcoTkWn/O81BlUFgAXv80gLe8" + + "NUrH7bhsnyGaPY953NyDk8IWUYrsn/sXvxTy5B0/7/WGMh3CSZrLX3p7TcFY" + + "yBrL6SRas4q9rrcwuhBq0tUUbbgWi92nhZl4bOGmx7ehHnwuUId2HWXyVGoB" + + "qToee/2E4PZFxSZwKCY6dahswFq5QGDrQKN2/qpOLZcJib6SvSGyEZl2pqr0" + + "lqk7tVPzBkN/4uP0qrcbZCDbGW6IXwu3RGMRehqj/HEJcs92lZKfVrk/U07X" + + "MBAiQHqV+kLw7kStECR/MGJG1c0xhqqBrf0W74+LpJiv/Q9iFNdWbXvE/cAk" + + "G7+OTUABd2kI88uA43T0UoRuPOi5KnLuD3AG+7IuyGyP69Xncd4u0srMg2fn" + + "DiLLZUy6vWmxwRFsSMCEfQNLtZaggukoPIihQvbX3mQS9izwLs6D89WtEcZ5" + + "6DVbIlUqUinnNKsT8vW1DZo5FMJkUxB666YIPVmkQbbJOEUU89dZg5Gw0og6" + + "rn4irEr4xHFdx+S7iqJXhzs9THg/9e4/k8KQ136z7LALOqDookcSdBzW6H8c" + + "STjs4qKQyNimsLB90mEuIEApzhseAaLFl+kgORGJv/2a+uoukZchMsJ98MVo" + + "sEPS1oBXJl2m9AshkWfON2GDeJatgcw6CyC1mSx++Gg602ZKUZZUaWxkz1Sw" + + "zTj3nhiJe+SZsdfxhsojNq7zfxqgY/Rq7BwvphU3StjnxvkB4rTkbmbiGOBO" + + "cvTFg4yOtQGRcifk2/XH/bgYiPqQrYSXpO3WRASV005RaSGufcpTtj3YlHGe" + + "8FUgZfDtfiGezhNET9KO3/Q0i34bGEpoIb/9uOWH4ZHULIlfdSm1ynV50nE4" + + "mJTXccrF6BE80KZI5GWGhqXdfPFaHTK1S20+XCw7bRJCGeiwVxvGfB+C0SZ4" + + "ndtqx165dKG5JwFukcygiIZN6foh0/PhwzmFxmPtZuPQt9dtuIQ35Y7PSDsy" + + "IH2Ot0Hh0YIN99lHJ6n9HomSjpwcgDXGssEuevbpz27u/MI/Uhq4Gfx0k5RF" + + "0pcRYtk1dYSx44a+8WgqZLF8DUNtyjSE/H8P5iGa6tqOl7kNyeeEkfoTtKst" + + "asGFwL4Qxxus4GC7repyVi7IJgSCA+iopiqKQJ2IqUHvoIEuD//sZooDx0Je" + + "oFRO5VakkTO6WHd8JpOOEU2f6Zjg++HdIl0QK7xcUaRH075LzEfqgn1vyw6J" + + "N6ex8D76sf/nAy01NvDPij48Z50XDwXu4kJGJvv0AJwId8BpjziBF0j3K/DI" + + "YOOpd6nW4EvdivCgaCnxqlIU/u1OP4BwpO+AUjJh6RKlKviGihQpi103DFhR" + + "yXNDhh55pqgCCCuNeEB+ovRt7UxzlGAVRSxJh1Zbjp/+iQun0E32RlSR4Diz" + + "p5vDk8NBZpIiKRqI+8GWZc3G1igp7dvViTLw4OdWMKwhccV5+3Ll/W72aNVm" + + "azYUoYOVn+OYS1NJkER0tjFOCozRGm5hfkxGlP+02wbH5uu/AQoJMqWIxT6l" + + "46IWC24lmAnDCXuM+gWmwUvyXLwuBdejVK8iG1Lnfg1qztoLpYRbBROgRdpt" + + "2cbPRm+9seqrth3eJbtmxCvuh3bZ3pR2e0/r5Tob/fDcOc5Kp+j4ndXWkwpa" + + "OuH1yxam7zNJR+mcYp1Wiujia5qIeY1QCAEY5QgAWaSHtjlEprwUuootA2Xm" + + "V7D8Vsr9BValhm9zMKj6IzsPmM+HZJWlhHcoucuAmPK6Lnys3Kv/mbkSgNOq" + + "fJDY901veFfKeqiCbAm6hZjNWoQDNJKFhjXUALrcOv9VCFPA3bMW3Xul/sB4" + + "Mq595e+x/1HkNOgZorBv97C6X7ENVDaAFcyZvrRU/ZeDnvFhisfxS4EJhzxl" + + "cWWnQhzD+ur1FTTlkmUFzgoB/rW+i3XigiHOuRRnkcoMy1uV17rwH8eELHJu" + + "Yni5vu2QUaD4jNEhliE2XCsn8Sm6bcXnfzBa7FXC39QvAcdJHzqcD6iIwjIz" + + "hKLu+/XoWFMFFNsgV78AwzPAn6TRya8LLCYPoIZkEP4qBoeZtUZ8PIS/Y7M9" + + "QStMwa/NI9SPswb3iScTGvor/obUEQS4QM6mVxFMpQWfwJfyU6jingX4EHRE" + + "mqvZ3ehzU8ZLOdKzRKuk022YDT7hwEQ+VL0Fg0Ld9oexqT96nQpUTHZtDRMV" + + "iTuJoUYTneDs2c9tsY4mWBqamZQSfTegj4sLMZagkuSUp/SpPM2zSGuD3nY6" + + "u3553gIM9jYhvLBEXwjGudVCwMd3bqo/4EhnKb2PcwUzdaMkipQlNteHZjBT" + + "1ici63xjJva+di0qTV+W9cyYyHwg1927X2qcMh06BhbHlcXQKbgmbL18KJEt" + + "K+GGhGNkP7mtPyHHgBb6vref/z8p7oxT2CG+oBuN/z+xQoYfe9c4IC3e/kNN" + + "DIoyYvPyEzAdfMS2aL8qDxzc5GH9UE9kcusJ/2dNEFTzBH2GK1CItL3IACv/" + + "LwX1SkI0w7oIQTL127CSnuTrUUkvJ/+rOYScQTMD/ntZPdLdu2ffszg3SzhN" + + "ELgojK8ss1OBlruWRHw/fP736Nx8MNsuOvXMnO8lruz+uyuEhF3BLv96oTcg" + + "XVHdWhPmOoqNdBQdRgAAAAAAAAAAAAAAAAAAAAAAADA8MCEwCQYFKw4DAhoF" + + "AAQUJMZn7MEKv4vW/+voCVyHBa6B0EMEFJOzH/BEjRtNNsZWlo/4L840aE5r" + + "AgFkAAA="); + + public void performTest() + throws Exception + { + ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(pkcs12)); + ASN1Sequence obj = (ASN1Sequence)aIn.readObject(); + Pfx bag = Pfx.getInstance(obj); + ContentInfo info = bag.getAuthSafe(); + MacData mData = bag.getMacData(); + DigestInfo dInfo = mData.getMac(); + AlgorithmIdentifier algId = dInfo.getAlgorithmId(); + byte[] salt = mData.getSalt(); + int itCount = mData.getIterationCount().intValue(); + + aIn = new ASN1InputStream(new ByteArrayInputStream(((ASN1OctetString)info.getContent()).getOctets())); + + AuthenticatedSafe authSafe = AuthenticatedSafe.getInstance(aIn.readObject()); + ContentInfo[] c = authSafe.getContentInfo(); + + // + // private key section + // + if (!c[0].getContentType().equals(PKCSObjectIdentifiers.data)) + { + fail("failed comparison data test"); + } + + aIn = new ASN1InputStream(new ByteArrayInputStream(((ASN1OctetString)c[0].getContent()).getOctets())); + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + SafeBag b = SafeBag.getInstance(seq.getObjectAt(0)); + if (!b.getBagId().equals(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag)) + { + fail("failed comparison shroudedKeyBag test"); + } + + EncryptedPrivateKeyInfo encInfo = EncryptedPrivateKeyInfo.getInstance(b.getBagValue()); + + encInfo = new EncryptedPrivateKeyInfo(encInfo.getEncryptionAlgorithm(), encInfo.getEncryptedData()); + + b = new SafeBag(PKCSObjectIdentifiers.pkcs8ShroudedKeyBag, encInfo.toASN1Primitive(), b.getBagAttributes()); + + byte[] contentOctets = new DLSequence(b).getEncoded(); + + c[0] = new ContentInfo(PKCSObjectIdentifiers.data, new BEROctetString(contentOctets)); + + // + // certificates + // + if (!c[1].getContentType().equals(PKCSObjectIdentifiers.encryptedData)) + { + fail("failed comparison encryptedData test"); + } + + EncryptedData eData = EncryptedData.getInstance(c[1].getContent()); + + c[1] = new ContentInfo(PKCSObjectIdentifiers.encryptedData, eData); + + // + // create an octet stream represent the BER encoding of authSafe + // + authSafe = new AuthenticatedSafe(c); + + contentOctets = authSafe.getEncoded(); + + info = new ContentInfo(PKCSObjectIdentifiers.data, new BEROctetString(contentOctets)); + + mData = new MacData(new DigestInfo(algId, dInfo.getDigest()), salt, itCount); + + bag = new Pfx(info, mData); + + // + // comparison test + // + byte[] pfxEncoding = bag.getEncoded(); + if (!Arrays.areEqual(pfxEncoding, pkcs12)) + { + fail("failed comparison test"); + } + } + + public String getName() + { + return "PKCS12"; + } + + public static void main( + String[] args) + { + runTest(new PKCS12Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIDataTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIDataTest.java new file mode 100644 index 000000000..8bef695b5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIDataTest.java @@ -0,0 +1,73 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.CertificationRequest; +import com.fr.third.org.bouncycastle.asn1.cmc.OtherMsg; +import com.fr.third.org.bouncycastle.asn1.cmc.PKIData; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedAttribute; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedCertificationRequest; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedContentInfo; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedRequest; +import com.fr.third.org.bouncycastle.asn1.cms.ContentInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class PKIDataTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new PKIDataTest()); + } + + public String getName() + { + return "PKIDataTest"; + } + + public void performTest() + throws Exception + { + + byte[] req1 = Base64.decode( + "MIHoMIGTAgEAMC4xDjAMBgNVBAMTBVRlc3QyMQ8wDQYDVQQKEwZBbmFUb20xCzAJBgNVBAYTAlNF" + + "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALlEt31Tzt2MlcOljvacJgzQVhmlMoqAOgqJ9Pgd3Gux" + + "Z7/WcIlgW4QCB7WZT21O1YoghwBhPDMcNGrHei9kHQkCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA0EA" + + "NDEI4ecNtJ3uHwGGlitNFq9WxcoZ0djbQJ5hABMotav6gtqlrwKXY2evaIrsNwkJtNdwwH18aQDU" + + "KCjOuBL38Q=="); + + + PKIData pkiData = new PKIData( + new TaggedAttribute[]{new TaggedAttribute(new BodyPartID(10L), PKCSObjectIdentifiers.id_aa, new DERSet())}, + new TaggedRequest[]{new TaggedRequest(new TaggedCertificationRequest(new BodyPartID(10L), CertificationRequest.getInstance(req1)))}, + new TaggedContentInfo[]{new TaggedContentInfo(new BodyPartID(10L), new ContentInfo(PKCSObjectIdentifiers.id_aa_ets_commitmentType, new ASN1Integer(10L)))}, + new OtherMsg[]{new OtherMsg(new BodyPartID(10L), PKCSObjectIdentifiers.pkcs_9, new ASN1Integer(10L))}); + + + byte[] b = pkiData.getEncoded(); + + PKIData pkiDataResult = PKIData.getInstance(b); + + isTrue("controlSequence", Arrays.areEqual(pkiData.getControlSequence(), pkiDataResult.getControlSequence())); + isTrue("reqSequence", Arrays.areEqual(pkiData.getReqSequence(), pkiDataResult.getReqSequence())); + isTrue("cmsSequence", Arrays.areEqual(pkiData.getCmsSequence(), pkiDataResult.getCmsSequence())); + isTrue("otherMsgSequence", Arrays.areEqual(pkiData.getOtherMsgSequence(), pkiDataResult.getOtherMsgSequence())); + + try + { + PKIData.getInstance(new DERSequence()); + fail("Sequence must be 4."); + } + catch (Throwable t) + { + isEquals("Exception type", t.getClass(), IllegalArgumentException.class); + } + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIFailureInfoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIFailureInfoTest.java new file mode 100644 index 000000000..8e7a7f1c5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIFailureInfoTest.java @@ -0,0 +1,80 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.cmp.PKIFailureInfo; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +/** + * PKIFailureInfoTest + */ +public class PKIFailureInfoTest + extends SimpleTest +{ + // A correct hex encoded BAD_DATA_FORMAT PKIFailureInfo + private static final byte[] CORRECT_FAILURE_INFO = Base64.decode("AwIANQ=="); + + public String getName() + { + return "PKIFailureInfo"; + } + + private void testEncoding() + throws IOException + { + DERBitString bitString = (DERBitString)new ASN1InputStream(CORRECT_FAILURE_INFO).readObject(); + PKIFailureInfo correct = new PKIFailureInfo(bitString); + + PKIFailureInfo bug = new PKIFailureInfo(PKIFailureInfo.badRequest | PKIFailureInfo.badTime |PKIFailureInfo.badDataFormat | PKIFailureInfo.incorrectData); + + if (!areEqual(correct.getEncoded(ASN1Encoding.DER),bug.getEncoded(ASN1Encoding.DER))) + { + fail("encoding doesn't match"); + } + } + + public void performTest() + throws IOException + { + BitStringConstantTester.testFlagValueCorrect(0, PKIFailureInfo.badAlg); + BitStringConstantTester.testFlagValueCorrect(1, PKIFailureInfo.badMessageCheck); + BitStringConstantTester.testFlagValueCorrect(2, PKIFailureInfo.badRequest); + BitStringConstantTester.testFlagValueCorrect(3, PKIFailureInfo.badTime); + BitStringConstantTester.testFlagValueCorrect(4, PKIFailureInfo.badCertId); + BitStringConstantTester.testFlagValueCorrect(5, PKIFailureInfo.badDataFormat); + BitStringConstantTester.testFlagValueCorrect(6, PKIFailureInfo.wrongAuthority); + BitStringConstantTester.testFlagValueCorrect(7, PKIFailureInfo.incorrectData); + BitStringConstantTester.testFlagValueCorrect(8, PKIFailureInfo.missingTimeStamp); + BitStringConstantTester.testFlagValueCorrect(9, PKIFailureInfo.badPOP); + BitStringConstantTester.testFlagValueCorrect(10, PKIFailureInfo.certRevoked); + BitStringConstantTester.testFlagValueCorrect(11, PKIFailureInfo.certConfirmed); + BitStringConstantTester.testFlagValueCorrect(12, PKIFailureInfo.wrongIntegrity); + BitStringConstantTester.testFlagValueCorrect(13, PKIFailureInfo.badRecipientNonce); + BitStringConstantTester.testFlagValueCorrect(14, PKIFailureInfo.timeNotAvailable); + BitStringConstantTester.testFlagValueCorrect(15, PKIFailureInfo.unacceptedPolicy); + BitStringConstantTester.testFlagValueCorrect(16, PKIFailureInfo.unacceptedExtension); + BitStringConstantTester.testFlagValueCorrect(17, PKIFailureInfo.addInfoNotAvailable); + BitStringConstantTester.testFlagValueCorrect(18, PKIFailureInfo.badSenderNonce); + BitStringConstantTester.testFlagValueCorrect(19, PKIFailureInfo.badCertTemplate); + BitStringConstantTester.testFlagValueCorrect(20, PKIFailureInfo.signerNotTrusted); + BitStringConstantTester.testFlagValueCorrect(21, PKIFailureInfo.transactionIdInUse); + BitStringConstantTester.testFlagValueCorrect(22, PKIFailureInfo.unsupportedVersion); + BitStringConstantTester.testFlagValueCorrect(23, PKIFailureInfo.notAuthorized); + BitStringConstantTester.testFlagValueCorrect(24, PKIFailureInfo.systemUnavail); + BitStringConstantTester.testFlagValueCorrect(25, PKIFailureInfo.systemFailure); + BitStringConstantTester.testFlagValueCorrect(26, PKIFailureInfo.duplicateCertReq); + + testEncoding(); + } + + public static void main( + String[] args) + { + runTest(new PKIFailureInfoTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIPublicationInfoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIPublicationInfoTest.java new file mode 100644 index 000000000..255c64311 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIPublicationInfoTest.java @@ -0,0 +1,84 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.crmf.PKIPublicationInfo; +import com.fr.third.org.bouncycastle.asn1.crmf.SinglePubInfo; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class PKIPublicationInfoTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new PKIPublicationInfoTest()); + } + + public String getName() + { + return "PKIPublicationInfoTest"; + } + + public void performTest() + throws Exception + { + PKIPublicationInfo pkiPubInfo = new PKIPublicationInfo(PKIPublicationInfo.dontPublish); + + isEquals(PKIPublicationInfo.dontPublish, pkiPubInfo.getAction()); + + encEqualTest(pkiPubInfo); + + pkiPubInfo = new PKIPublicationInfo(PKIPublicationInfo.dontPublish.getValue()); + + isEquals(PKIPublicationInfo.dontPublish, pkiPubInfo.getAction()); + + encEqualTest(pkiPubInfo); + + SinglePubInfo singlePubInfo1 = new SinglePubInfo(SinglePubInfo.x500, new GeneralName(new X500Name("CN=TEST"))); + pkiPubInfo = new PKIPublicationInfo(singlePubInfo1); + + isEquals(PKIPublicationInfo.pleasePublish, pkiPubInfo.getAction()); + isEquals(1, pkiPubInfo.getPubInfos().length); + isEquals(singlePubInfo1, pkiPubInfo.getPubInfos()[0]); + + encEqualTest(pkiPubInfo); + + SinglePubInfo singlePubInfo2 = new SinglePubInfo(SinglePubInfo.x500, new GeneralName(new X500Name("CN=BLOOT"))); + + pkiPubInfo = new PKIPublicationInfo(new SinglePubInfo[] { singlePubInfo1, singlePubInfo2 }); + + isEquals(PKIPublicationInfo.pleasePublish, pkiPubInfo.getAction()); + isEquals(2, pkiPubInfo.getPubInfos().length); + isEquals(singlePubInfo1, pkiPubInfo.getPubInfos()[0]); + isEquals(singlePubInfo2, pkiPubInfo.getPubInfos()[1]); + + encEqualTest(pkiPubInfo); + + pkiPubInfo = new PKIPublicationInfo((SinglePubInfo)null); + + isEquals(PKIPublicationInfo.pleasePublish, pkiPubInfo.getAction()); + isTrue(null == pkiPubInfo.getPubInfos()); + + encEqualTest(pkiPubInfo); + + pkiPubInfo = new PKIPublicationInfo((SinglePubInfo[])null); + + isEquals(PKIPublicationInfo.pleasePublish, pkiPubInfo.getAction()); + isTrue(null == pkiPubInfo.getPubInfos()); + + encEqualTest(pkiPubInfo); + } + + private void encEqualTest(PKIPublicationInfo pubInfo) + throws IOException + { + byte[] b = pubInfo.getEncoded(); + + PKIPublicationInfo pubInfoResult = PKIPublicationInfo.getInstance(b); + + isEquals(pubInfo, pubInfoResult); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIResponseTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIResponseTest.java new file mode 100644 index 000000000..bccf86311 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PKIResponseTest.java @@ -0,0 +1,47 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.DERUTF8String; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.OtherMsg; +import com.fr.third.org.bouncycastle.asn1.cmc.PKIResponse; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedAttribute; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedContentInfo; +import com.fr.third.org.bouncycastle.asn1.cms.ContentInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class PKIResponseTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new PKIResponseTest()); + } + + public String getName() + { + return "PKIResponseTest"; + } + + public void performTest() + throws Exception + { + PKIResponse pkiResponse = PKIResponse.getInstance(new DERSequence(new ASN1Encodable[]{ + new DERSequence(new TaggedAttribute(new BodyPartID(10L), PKCSObjectIdentifiers.bagtypes, new DERSet())), + new DERSequence(new TaggedContentInfo(new BodyPartID(12L), new ContentInfo(PKCSObjectIdentifiers.id_aa, new ASN1Integer(10L)))), + new DERSequence(new OtherMsg(new BodyPartID(12), PKCSObjectIdentifiers.id_aa_msgSigDigest, new DERUTF8String("foo"))) + })); + + byte[] b = pkiResponse.getEncoded(); + + PKIResponse pkiResponseResult = PKIResponse.getInstance(b); + + isEquals(pkiResponse, pkiResponseResult); + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ParsingTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ParsingTest.java new file mode 100644 index 000000000..6594abb05 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ParsingTest.java @@ -0,0 +1,99 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1StreamParser; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ParsingTest + extends SimpleTest +{ + String[] streams = { + "oRNphCO0F+jcMQKC1uMO8qFBPikDDYmtfVGeB45xvbfj1qu696YGjdW2igRnePYM/KkQtADG7gMHIhqBRcl7dBtkejNeolOklPNA3NgsACTiVN9JFUsYq0a5842+TU+U2/6Kt/D0kvz0WmwWFRPHWEWVM9PYOWabGsh28Iucc6s7eEqmr8NEzWUx/jM3dmjpFYVpSpxt2KbbT+yUO0EqFQyy8hQ7JvKRgv1AoWQfPjMsfjkKgxnA8DjenmwXaZnDaKEvQIKQl46L1Yyu3boN082SQliSJMJVgNuNNLFIt5QSUdG1ant5O6f9Yr0niAkAoqGzmqz+LZE1S7RrGHWiQ3DowE9NzviBuaAoI4WdCn1ClMwb9fdEmBMU4C7DJSgs3qaJzPUuaAT9vU3GhZqZ0wcTV5DHxSRzGLqg9JEJRi4qyeuG3Qkg3YBtathl+FiLJ7mVoO3dFIccRuuqp2MpMhfuP1DxHLNLNiUZEhLMQ0CLTGabUISBuyQudVFlKBZIpcLD0k7fKpMPuywrYiDrTinMc2ZP3fOGevoR5fnZ6kZAE5oMTtMNokzBuctGqVapblXNrVMLYbriT538oYz5", + "KEKVhHxtyUR9D3v5K4IJbVQLAMiVKoK9z7wFWUjzvLFNLg9C/r8zKfBa3YgZrt0Nq64+MxBePMbiNLCnfditc2qUcQZUHnvNnhwT6uGK37JmXg7MvQiKwvi31EIYt6ghqBZVs1iaqc0ep7wuQ16uwSQMlaDdXc9Qf1L0dGO/6eLyREz+p4UR4NOXK+GooQLfMxYL40zJlYcwNyR0rigvIr84WP2IMS2hZjqXtyS6HMM4yUv70hkIorjr7+JC4GtU1MyWuPuNSAGen0AZTaEEXd5sMbqXMqWg3jeM4mzRH1Kb3WdAChO5vMJZPBj9jZZKgXzmxkUh5GlIhUdYgztoNceBzQ3PIc7slCDUw9I2PjB87xsfy7jA5tFtFADs2EUyxUTMCuhilP664jSHgwbrr80k9Xc4sU+MCwCq2nQmcZYcPgKb4M31VJMlKwnZF3JUU2Jtqgg4gbErw58YoBwSkEcMJ2Juhiyx9U36MzxHs9OcTURfpsilMy+mDL8arCDx1knM1KkAHCLjWuJI+p1PvuIypgCwVc+MtGfd7wW8iR1JPJLBiuoZyNJ+xx9htd/HVB+rLtB57H8Gz8W+R00f", + "Ol9I/rXMwbLpxTY97v70B+HCl2+cojz2574x/cC56A7KGVF13La8RdzOOvSkl338ct9T/blEFa6QwNz3GmF+MoPdH9lncwz+tqixIqGU02Bp5swH0qjbp/Yjaeq91eR6B+9fl+KKrpglBr8S1BrI4Ey5v3AxxJdCWP8Gd+6Sp15/HMYanwlHBpCsW4+Kq8sGJoJXUXpQ/GBUJKs+WjX1zE6PsvF7/B8cByuqE3NJt7x4Oa+qZtF8qNc0CFDNj31Yhdt7JkAoD30IAd+ue9OhImQMCWwFwySRIRJXU3865K2dBR+VhLuI2aKzLh7MlgVKJk6b2P/ZIkc86ksR1sOUiHrs9EdoYuIssAgMc8QGzn4VN8lxopdzQYVG6pbXGS/VQlHkGdyLd+OHt4srz/NTUWiOquVTRxa6GgtlBFfIXikPTb+iT2pZKyKUlBvpgo0BY9vVUadsteHAI5qrFZBrL5ecK/Qtl9hf/M8qEjyjt2aCXe9B96Hg2QR5A53qW2PJW5VzS0AeB3g+zJSPCTpygrBs20q5Xrna0ux2l17r6HT9Q/AXIOkwPZUXXn0d02igS4D6Hxrg3Fhdp+OTXL8G", + "o3eXWpwAGmUkxHEKm/pGkDb1ZQQctCQ06lltZjeMXDp9AkowmA0KXjPQCQwyWE/nqEvk2g/58AxNU0TWSujo5uU0h4/hdMZ7Mrj33NSskWvDpKe7lE5tUjPi74Rmc5RRS+1T/EQobpNxoic3+tTO7NBbZfJtcUYeZ3jqxL+3YQL3PrGe/Zpno9TnQW8mWbbhKhDRtKY4p3Pgk9hPSpJCM9xYo3EMAOAIiH2P6RKH6uX/gSaUY2b6DE/TT0V6v/jdSmYM4+cnYiTyJCi5txI35jfCqIlVCXJd7klirvUMg9SXBhGR25AgQ5Z8yjd7lbB8FvD8JQAXZrp6xiHxbLIW7G11fWEo7RGLFtALI6H38Ud0vKjsEN7N5AibJcxS2A/CWk9R00sTHRBHFUP8o5mz8nE7FeCiwJPs/+tCt04nGb9wxBFMsmWcPEDfIzphCaO6U/D/tQHlA846gbKoikv/6LI0ussSR/i85XBclNcvzTctxylSbCR02lZ+go6fe5rmMouiel/0Tndz8t1YpQGilVeOQ3mqAFyAJk3dgfTNKZuOhNzVIZ5GWScKQ5ZtNcWrg6siR+6YwKvLiRb/TJZk", + "PwRUnW4yU8PI7ggbI1BIO9fcTup8optkqCirodyHCiqsPOMZ4g28bJ2+kpfQRujWGlKFYQzA1ZT32s9hdci+fvXPX0KAjcUgcxsGzMABFbEm04BwDF2WLgg9s4/x71r5JrgME1S08I3mCo4N0eFHWDeLJL1b5YNNo6tfO5V2WpIE867N9zdAgvp1gijVjUNWqEB3A/NLb3reLMu2hYgqRFTCVBfcFclD46k0XEfUJqwWdQhOz92WNl/3g53bjKX1hDZgjLIzK6m+SU6+J/h4NidrS7E0gOBevZW8gRYdKMVqNWxzUfxv6kgG+kIeF9JqMcO6jdh/Zu/0tpZoHFeCweZ1jT1eEtltFu1FcTTPc1UT0pT+ZNVgefrBONoGnvn8+dBjPese6F2TmRCExJq9taKlIh/kHdkbpaa7vwrBpYRgVGfARPyM9SSCaE7pVBDuwkFeYiGU4tamm5Gq10ojRQgetJ3UOg/PGTJcxo97GBiG5zAST9NdHdgK3eI4FAbWpGwmWxNpPWOst0a7zuGKAzYU+1IQh8XA3IgJ2vy3+w0JihU6G+12LUzsL2aQtpG7d1PqLhwOqHq3Qqv3SDsB", + "ZIAKizvGzbvqvqOlxOeVgHGHV9TfKNjjqyzbCj8tggv2yp7kkq1D3yRlC349tuul3zN9g4u83Ctio9Gg3HiLzMULxoOImF/hKRDhJpPLbLm0jSq1fyF+N7/YvyLeFhGoPhYEBUihDcxo1NIcWy66aBt3EuOlTyDQWrDe0Za3mrTrrl10uLHVKcQMgeD+UMgjQqmHzQJR8wdNjHPKHWVvZEdiwI031nV2giHJHXv08Jvf4vmw4dAlH2drCl6cBgg33jy7ohK8IiXz6eCw6iY9Ri8YaMzxOhgE2BOHzEz5ZC2hilL4xO/ambTER4bhb4+9VTUIehHP18FcXm8TKPQRMqyKP2fMlzWW3/uelYfPP5SHlyLAULa1KjDCkLIDunEKZDpv2ljGB6JPrTlNwFsvlZcihfOAwjbr2jW3MwP704OA8xzd/dynBU47unIZEu0LAvQ3TUz3PLga0GGO1LZGtg0Foo9zFG2wuVCdgYHmozOQ+8I3gRguW1CjGy7ZCTBuN1GZ510ERhae+bRQtldHsLeiHTghnkU1xEX1+W0iEf3csDYrgpuq3NaBYRGirovDiPBYFHmru0AMclhFnpcX", + "uG0wQ55kMlfZtJFAqTl0bnYW/oy9NFOi0e4FqAYwsvMxGO4JtGzXgkVwEUAC0AUDItRUjxBl+TkoPTYaprgn0M/NQvKPpXJ+yzI7Ssi+F2alLR0T6eF/4rQ32AVjnANJaghXZm0ZKduckbhSxk5lilJVJRuzXKchZRtlPluvlj448bq+iThktsEQoNP8NMpi7n/EVxovp+dow4Q6t7msSRP4cGXtyYoWKbf/7e5XzBKOZZ1/f3s86uJke4dcKIaljpJfBrtuFxZC6NYXzX6PkoDoBgqQ8RBrxsX54S9cBDAPxxmkq8zviAOW3oqPMULGGmQzHBiRwE8oeDFoMnzF5aR/lkbNuTLOxhbIkosgLWlDNVEFYx9bVhdLzO7VwaAK829dimlPOo5loKB7Pd2G7ekRKXwu7wNvJBq8KRkhtLKbKoS8D6TaRWUMb9VBJ1CMy4mrw+YwTmAKURQ6Dko9J/RgzRg5Y/sUlwdMYS9HOnvKiTVu5I/ha35wwkhIPVm+FCn05tstntZaXXXu4xExHeugAKNBhkcc/SQt+GFdxXDd+R4C2LfKxGDSyZKVTFYojHTdZUo8Gx6SZLY6b2SZ", + "sH0kIwIq1THAfTLfqUKJfG1YauCQKPc9/mk3l39yK6zgxSpCH2IjZIwhhJtGm3F+8PTneT725OuyR617nxqrgqMGkkZkyY4DA5CjsikpBo5mo8TspX1g+vtXXtxymJMTMo8JwX3nSH4gSb3vPia+gwOW2TcJmxVdp3ITPA4gJpMfqoMBqRM+eDWO6QXW5ijVL4+wnp40u5bU4fQLVzpg25+QGLqBHD6PZTQaN6F9Vy5XpsAGDlncCklVuX3Lkp3Xb9cTiNa/4ii04uwZqx0juszjwFAMPPb6u56crvN1x4FXfXzabWECHbdQLlKazowvU9bEnqG2i4H44Ae+v8Iw8HK5mbZ6ercLTD9oPgs7Ogal037l2WwLApUz/fmD5fV8SxHh+vKDpfOzv6xcQxynS82jAJw9AdUwE/4ndGzzHPIu2M81gbAgZQ02EurMMU62hYgiXeridrtyh+H5R+CiwQdEyX7/op6WVihsYj2O3O/1hgjhGQRFD6sGwnko50jgWRxaMMfJGNlyGoT8WT5k931jU7547u7Ovr7XP/t8r3G7ceCiCcYjQgdwXdvIStzPvvV7Yy02isZjiJF8TLJQ", + "tycxf1mOz1yLE6cT/ZlCxMeTxlEEHFeIdw0+nF/40Tsw4vLco+4kR2A6cVml611CSpN6l/RMKk2LnAkprrbJ/Uam902WBnQ+I6Vsl6GkFFq7362bdixojqMFVKYytXLCT8I78f6s8M6a3jSALQloD6Ftvn+cc+cctO3weaaaPgAlrz+f2MFs8bqpnLQYbbY/JS9IAYJFH+yVtLz7eKcedEp9JMlJ3/43szU2fDN9ZMxBoQnxEmF3WZv6GF0WRc8VhTblXRgk4mlz6Fu3IXvwW/rbn+VCYYIk/XaVLrxFAnnw6mBozAF7vmV0OrIYBlSDU8rMb+F7AvE7pwErO9TJtCE8IUvQf8TsJYRoYv21/X57pzcBedtqVeU3DnTlmESHxG6H1uJbadSFLWSxKS4svfp8T9FWqX5815yD/UplAKEIeorLTAlPIC2ASKDU6SQW260biNAfY8FYQCWa8btaTwFuY8NMwSHzyqgU0aoPKnagi/4hOIWNO5rZ8Xcnzx+ELtEl33hQnzc4OUlT5eeVYQWkz2IWVQ6Re4JWF3L4OXzNZWgefKGMzZU6IHoBeCgfi+popLRJpaOx0dcvwGjk", + "oDsoFvUA+sGOoMyZY6w1UhY3NBkeoozzjEkDSRN1golyXJ1dC5CtYNEjvAJYKj+sqNwg9mBlYyybYpnI3GSP125zMeBHPCoy5CoNOkJW4OH/oLyjVeQbFNic/b2Jcz6lTguYhep8hq9EM2XuFV8T1rm5+4ucI7fH1UiOqRZyuHBAJ0Cna5kv6D3efsa9rd+swybiMIUjmPWpyxzNOOihCYuf4JqRh/D5eZKm6x0Zj2uRhTAYYxI7Q3czd0R9490ufG8VbF8ASBMireMONNNAA/OZCpxJh6xnIANBqV6YDeysws3NBWY2QuNumvg5Kr3/g+VMzJHi4wGuJjraKWi9+ylMfelHF5h/h+pAQVxCotq8JU3OTnMUW4rQp2a8BR5S+mZqPSPlb87tDG9r0+yqb1uO4UIo71C7Xxwoq4M0tXjk6mSmtP/sm+Lh14qfUzKRhTHVdz91TK104mbTJNXbK+jGPD/2BJO9fiaXY8IYanpfDLBfJo06VYbm6HehRZTwnDHnN50j7ki4aMS3COZvffjRInXD8dS5h9zmtKNpoqg//lPg4gpS+4Th2sJ3SGtBV0Ne89r7AfZMAVa26PMK", + "MIDLuZTrtZnEBOB6l14iSEyokAg5Wf5JviumhfPeL7WSFTHfOodU2hrvhyvM6oAlRHY1blTj7mw+Tcf9Tmc+/FHT6PGu0NT5UAqaqChX0gS9jizgAE2Yfhd4X/DoeQySMAixKuhu8TbvDxb54jeW9+7LVkmlntJ/0SkMgsT+WQ31OfpwDmEGDczYc+Ol14aJS+EW+rnGv9d38bo/cy+EnpNh8iV2rGGoC8fDzFHKU4gqGFSZF/tnD2OfCne0Vjr/GD6kyp2MVcHig19DBg2toGRkHnuY5kLkwOanztXA80IaAmv8e6s62U8CE8ozUZeDBcvBigEkSGx79Vsyiks8+9Kq9xLHLeS5kRT6zSl8whe8U1fIfrgic34KPlozcQVahwCru1XWyQ+9uevih8x4zMftkJ3JBZhPrnlgtx9McntH/Ss9fdUEkNwWpDnq8Xby8/5gMMMwQ13XDB73vqqteDiltMq8i7LRez4iIHfSBBfIkZIzMZAblQXaSm029iBcAAUes7wcGHUl7KOpRy18jNtI3+h7e1Ri6sT2vJYQaove0nzZ5xAjpBKnbJX+lpGVlI00fC2YSTfyNqFA0jkL", + "MG4QbKLbQR3enPn6Z/kEUtHrzWBIqYKR7Gvs5QHLPF6417p1O58suZq38Bb8dO5udtgOqNEVAPGmOuidYygWWfWOP5ReggTUk5XlrkvRxCU0MHWbkSKkJ+T4nLjozreqTJ0io41sFVrpxuOugAvXJ6QtMmixSABUaNgU9SkkWf9pOEiJI8dfND51HxJCbXHwsMCMBp5FbaMZmlWPwirRdAox4wbLk9ZLmoWUcorUjdaWhKvT/LnjMgPmwnwwKpN/4MOnRDdAPdzXX3aWHdkzpfsQnqt3UJsTsSaJlzeUja5C5L4CXGyt99qmfcwB8OB9TL4EYTIl3maD/gUWBfckOsji8x2E2c2iuKKrcmMmcChYr4wCjtTjEeVKOAZ2m9mU2MKc2z2hDw3AuZxsY6aOtdAjnrwl5QXGRg9I5LVl5SI5RwnLwk90pJzDGuSSCtSmzh9DUZ4WpfN+1393aTGRqCMOsB4KxbXjspUbVMFJbnXXlsSNWaoFTpHjK6b6Ghi2/re7KJpoKElM3nGs3qvxdvGTKu7LKr/sgKDL6uQLRKoyk8AHSIGX9c8ZUTk7Sq9jV9p4QfV1WFVpaBxSsEmw", + "MR0BACgWKis9/AKwG9/ARgGWJn1aM3nU8YXzWG+b7aeRUkVCjl4WxeL38E3FAMLW4UcyLzxeb+CskOqhPPTglmxhK7jQcrNILsWcZvdZfApYIvk5uKqA5FKuUuL48uvD0aKGRENe/VEUFlkQru5YX4Xnp+ZThrJJlgn7ANat/qAdP6ULEcLaOQlLYcGRh5ttsJTRT4+cZQggTJjWt+9idUQ66HfC6zQ1qHcMuochy7GHiUmNXAs0AgwOF9Jwet/Qh74KGMtmppJ9gkEqiYECFQA2gVgKc1AufHJS6S6Re72FfH/UkL41L2hvlwktkD5/hZrUZ1R+RG12Eip2zKgus4g/aGl0V8B/JvkcnFUsZJ6uxs24arOBDJOuzzxky5F5B/hwVGPEdcfHunqndUcx26/KCK72hOljlqTXl8yEbXlcMqVFNByZLr7TnGzGGUlO7kuHPW/ItZUJvrHokpsLLrb3ZhEZ8pTQd75gFcf0Ve8CYzEtk2ISHtNJQV6Iz4AZHWssU6F6YWM/OlJz5JGTtPHfGMJXgl4oxbBjeenS3JQ0X7vWXYMwPe3U1dat6m5hrRC1KzI6e6w+gPDtF8GQ", + "DH2WX6XoIseX6lHIey3seUr3DAz82fyk0jL7xc5IDTrDfqS64QBhHDpqHETF/81MrPXsM3IANBfjDOl9g/gua8wWPpPNxuWZMNh0GLcAr6PJ939TCbjE3soZHF2wiA82nZEO8jIZosDVRWFUfJS6Y3nrJz63SExqB6OUdBfvSfz1Y1M/90ofBxkfeuS85deMdn+1rZdsnZJYwz2Z6lCDvYjUTfrSwfVFJBP8Y2BXr8WClUYkfGG4eNG7IPNBRuMmhrhHj5y9z+5Jor+EbbTi5F5Jvdu2/bDM7s32XsaMNLYuVtNYONrbQ+3QZ746/yKZM4hDREvxyGLgDx3Apz7pyvwKm0//iTCY3yJLxZifGLh2uc28cFBln7IH1x8oui4Xq9vF+Z2EH4Ow48Ln5pzggBKMGy4dsfW6266TNYd/Z3SZUi28sxondqhGCSGUo7ZVPAOoYDcYKvjdI/cJ688PHliyZSYBYVmR5HBxZ57sqWwgZQ7zVvwv4CHHysvb92sPrXijHxBIkwpNuK56UMyQCcywlTRLDCMAMNAEGi4fWbDQIoPfn+NixMhEieg3Zh7GXPwHxW8morlgBW5aF76P", + "AwClK6Tq9R2DYGf8RAHu9dEttLeOfUVmS4WPwX0NehsnyM7y7n2sgGnXsiva3yFqK1hKZICkVukvHF7/bpgEEm/jRwcAhQUoG+c1qVde38eHJXj58YOBGTveruc+021or9/tHBtenmYPO6+arLQtONi43NKm7+I6ugkgQlp6iBr4haa0XMDTzMX9c8Qm/O+MrVo3qESYKkVtoSSK7SGZTBaRWNF/dOM0NQxeMP+XTVOuroqE23ZNsubBTEZnd4vUilFb/iKnhyT9XnIo7gM/Yz7HLVU5yc3yIj2sFUE+DcwpvcNO5EnPhj3bHsJvf3N4r72+5my2KjoR3KAJE1Imabd54o4xZ/9UaR93qLkVuXMkLRCCU/zlZDtfbJDsRR0C5rSYd2k6IPlNcl7PgmUpsNPUyoDYqvhuRUZxgoUAfKbogzJX8FU/QpllsKVtt68ucBi0bqC5pVKu23j79nDvYQsSlYY3JwJQaM5M558J5qpP1yEF2p4kSRphnB9UR29wWgch5eWZ4a02LlHVM5Msl6W5PdmHt+eFARBRv6edIyYDFzxm4WZroH5F/GxBhM0KObgawkxa5VWsYm0VhhXb", + "KACwq8rZuOLHuNnZJA07WzI7kppCwptbcYU2B7t86QcZrnadCtxoM5QNcl9rsbMA26iWCPV3VlDAmLSWcxtMoSKWuo4edJpk8K915xkFU5U6I/901vx5hqAECQDy/Q+QDWmWTXDoVHqFV9wvIj3wCJPpJL/Ewpl0NZd+68jjOjUhjIdNebLrWNK2nhTPiIjFjkcVqEgashpOmnbHT+2MV/CHoixmUEiuRI1B0dvSf7FHGRgbXGBubisuu60g8XTens5zyRo4Qn/LTxIu2aj4LTtyLonV3sXr+y35A1zq5mCrE1f1nOINVzwYYY76iJGIaBkZuMU3366FPIbYkmXwla6RQU1FA0Y7n05qczw7Ie5TveRTByKFtUqW8OAb9vH+H2ezJ4CXE3AGbu/nTj64KClO/zL499GA+97g+X6tTN6xOJdNknlqw6ZnFNtCL8+A3hL4OyOgWD0IGC+xFvcKjDUaaJenCtQvprCJaFrvoOS+yYmixnFqglnPYL/64/Lca8NmDVpPzlHI8HNwUDzKiXTw3q7GnQZWmUYzu1vLIEi6/hyqrULRN1vLdd/8HCMNQFj4ot61UftHtOG8MCKa", + "rUABPQ3SEWE5rY16pM+o+7EObLNM1jEa5YCMQM/aen0PWajWNax3Pyo6TZL8aGDXZF0yWqDM3b2m6UHOr6yqsUSrD+0jXPT48QN1VdBmh+AFRK+UcaYO383a0nvtv0c9uHt4yfceXLPGWrNjW+uTnS/lKpCdpE4GfLF1SFHIUcMxT+3At7hwDHNkLXllEXqbgDP8LyQSlYwT5jQUDCOzwc8CSxAryUOj6fN+iLKAiw4haPV/WZDG+JOmDMG2azo8SoBMi3y6Z2Le2fz2dMuvn5DUvCUvazrUmWYx4NEdSzc9GfBc6cXkduMqCs+lT2Ik2GHO0WjhrEB6j5NULOaCtbrislM85P6QutN4Pj9l18pcD6vZCcDTOwMj/BznclH342jeMn7rBgpW1YSzbNGP6KC4NeNW1H2xqNtuyhcJvasx4dwhzO18A36H6HtkiQyJNnfnVHh1oviO6mi3atmnh9B/55ugXM1Wf/6Kv8kJyaKtK8cWo+jCAR0/P/EsPtzToJM9Yk2+qxaPFd3k7T2KXvCQ9D1jLeECxL59L+WDvdBtxOEBD7W0a/Mn/9LuQPOiwARKJSTU+blJ6ezTeo83", + "poA1hF4zRh7HF0xVglYoLFqkUR7Pru/qYFnfMKBPuEOOGdgO3MMcAvIZ+w+Ug4THr/6+Vux0TN3wdOB+beObOboLgNE2zaD65lyMFbaulzrEnWjUgIg63CdpQJ2ESaimHGg/GmsipUCndRJ37TbUtn8W112SehsAgrsjiBcuJhw61i4bVfAZEcycq4Y/FlEDxtzoH8WzDoESNbl+r5agLcHGr37BFi81IXS8TLihC1T8b7d6tLb6lpXT+9IR4xAyZTw1IFMDZZEzVmHgYE/Et20/WhkX/oGghkWSpCxR0kynDplk+BEK2oyGKnl+rf4vymhsse2iQ/C99PhaodZjDfuGVSwPLoU0AYyAKaEwmgHPOFbDlrAmNk4iBp+IZYm9guZM2hcQ4GeA5WQyZzw4C1yMywWbdjtL9ZhpClmmPZ28nmwNORAat7tXPJoBBdXFB0gNT/wU7UYIKU5GnAiDIFJ0o8ijnuAMat3AsBki2vxwdypuBq5M6OF9DVA0HRUjOA0l4JHjK8Y282mz3U34PDPQvwCT342uD9cO3uXoSr3T2FnDmsVHz4Q9zYpSjioLmZk9ZTnQWgN5V5Oyat6m" + }; + + public String getName() + { + return "ParsingTest"; + } + + public void performTest() + throws Exception + { + inputStreamTest(); + parserTest(); + } + + private void parserTest() + { + for (int i = 0; i != streams.length; i++) + { + ASN1StreamParser aIn = new ASN1StreamParser(Base64.decode(streams[i])); + + try + { + Object obj; + + while ((obj = aIn.readObject()) != null) + { + + } + + fail("bad stream parsed successfully!"); + } + catch (IOException e) + { + // ignore + } + } + } + + private void inputStreamTest() + { + for (int i = 0; i != streams.length; i++) + { + ASN1InputStream aIn = new ASN1InputStream(Base64.decode(streams[i])); + + try + { + Object obj; + + while ((obj = aIn.readObject()) != null) + { + + } + + fail("bad stream parsed successfully!"); + } + catch (IOException e) + { + // ignore + } + } + } + + public static void main( + String[] args) + { + runTest(new ParsingTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PendInfoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PendInfoTest.java new file mode 100644 index 000000000..c36435f0a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PendInfoTest.java @@ -0,0 +1,45 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.util.Date; + +import com.fr.third.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.PendInfo; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class PendInfoTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new PendInfoTest()); + } + + public String getName() + { + return "PendInfoTest"; + } + + public void performTest() + throws Exception + { + PendInfo info = new PendInfo("".getBytes(), new ASN1GeneralizedTime(new Date())); + byte[] b = info.getEncoded(); + PendInfo infoResult = PendInfo.getInstance(b); + + isTrue("pendToken", areEqual(info.getPendToken(), infoResult.getPendToken())); + isEquals("pendTime", info.getPendTime(), infoResult.getPendTime()); + + try + { + PendInfo.getInstance(new DERSequence()); + fail("Sequence length not 2"); + } + catch (Throwable t) + { + isEquals("Exception type", t.getClass(), IllegalArgumentException.class); + } + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PersonalDataUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PersonalDataUnitTest.java new file mode 100644 index 000000000..c23f62c16 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PersonalDataUnitTest.java @@ -0,0 +1,121 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.x500.DirectoryString; +import com.fr.third.org.bouncycastle.asn1.x509.sigi.NameOrPseudonym; +import com.fr.third.org.bouncycastle.asn1.x509.sigi.PersonalData; + +public class PersonalDataUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "PersonalData"; + } + + public void performTest() + throws Exception + { + NameOrPseudonym nameOrPseudonym = new NameOrPseudonym("pseudonym"); + BigInteger nameDistinguisher = BigInteger.valueOf(10); + ASN1GeneralizedTime dateOfBirth= new ASN1GeneralizedTime("20070315173729Z"); + DirectoryString placeOfBirth = new DirectoryString("placeOfBirth"); + String gender = "M"; + DirectoryString postalAddress = new DirectoryString("address"); + + PersonalData data = new PersonalData(nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, postalAddress); + + checkConstruction(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, postalAddress); + + data = new PersonalData(nameOrPseudonym, null, dateOfBirth, placeOfBirth, gender, postalAddress); + + checkConstruction(data, nameOrPseudonym, null, dateOfBirth, placeOfBirth, gender, postalAddress); + + data = new PersonalData(nameOrPseudonym, nameDistinguisher, null, placeOfBirth, gender, postalAddress); + + checkConstruction(data, nameOrPseudonym, nameDistinguisher, null, placeOfBirth, gender, postalAddress); + + data = new PersonalData(nameOrPseudonym, nameDistinguisher, dateOfBirth, null, gender, postalAddress); + + checkConstruction(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, null, gender, postalAddress); + + data = new PersonalData(nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, null, postalAddress); + + checkConstruction(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, null, postalAddress); + + data = new PersonalData(nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, null); + + checkConstruction(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, null); + + data = PersonalData.getInstance(null); + + if (data != null) + { + fail("null getInstance() failed."); + } + + try + { + PersonalData.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + PersonalData data, + NameOrPseudonym nameOrPseudonym, + BigInteger nameDistinguisher, + ASN1GeneralizedTime dateOfBirth, + DirectoryString placeOfBirth, + String gender, + DirectoryString postalAddress) + throws IOException + { + checkValues(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, postalAddress); + + data = PersonalData.getInstance(data); + + checkValues(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, postalAddress); + + ASN1InputStream aIn = new ASN1InputStream(data.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + data = PersonalData.getInstance(seq); + + checkValues(data, nameOrPseudonym, nameDistinguisher, dateOfBirth, placeOfBirth, gender, postalAddress); + } + + private void checkValues( + PersonalData data, + NameOrPseudonym nameOrPseudonym, + BigInteger nameDistinguisher, + ASN1GeneralizedTime dateOfBirth, + DirectoryString placeOfBirth, + String gender, + DirectoryString postalAddress) + { + checkMandatoryField("nameOrPseudonym", nameOrPseudonym, data.getNameOrPseudonym()); + checkOptionalField("nameDistinguisher", nameDistinguisher, data.getNameDistinguisher()); + checkOptionalField("dateOfBirth", dateOfBirth, data.getDateOfBirth()); + checkOptionalField("placeOfBirth", placeOfBirth, data.getPlaceOfBirth()); + checkOptionalField("gender", gender, data.getGender()); + checkOptionalField("postalAddress", postalAddress, data.getPostalAddress()); + } + + public static void main( + String[] args) + { + runTest(new PersonalDataUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PolicyConstraintsTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PolicyConstraintsTest.java new file mode 100644 index 000000000..7850e2c45 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PolicyConstraintsTest.java @@ -0,0 +1,55 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.x509.PolicyConstraints; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class PolicyConstraintsTest + extends SimpleTest +{ + public String getName() + { + return "PolicyConstraints"; + } + + public void performTest() + throws Exception + { + PolicyConstraints constraints = new PolicyConstraints(BigInteger.valueOf(1), BigInteger.valueOf(2)); + + PolicyConstraints c = PolicyConstraints.getInstance(constraints.getEncoded()); + + isTrue("1 requireExplicitPolicyMapping", c.getRequireExplicitPolicyMapping().equals(BigInteger.valueOf(1))); + isTrue("2 inhibitPolicyMapping", c.getInhibitPolicyMapping().equals(BigInteger.valueOf(2))); + + constraints = new PolicyConstraints(BigInteger.valueOf(3), null); + + c = PolicyConstraints.getInstance(constraints.getEncoded()); + + isTrue("3 requireExplicitPolicyMapping", c.getRequireExplicitPolicyMapping().equals(BigInteger.valueOf(3))); + isTrue("4 inhibitPolicyMapping", c.getInhibitPolicyMapping() == null); + + + constraints = new PolicyConstraints(null, BigInteger.valueOf(4)); + + c = PolicyConstraints.getInstance(constraints.getEncoded()); + + isTrue("5 inhibitPolicyMapping", c.getInhibitPolicyMapping().equals(BigInteger.valueOf(4))); + isTrue("6 requireExplicitPolicyMapping", c.getRequireExplicitPolicyMapping() == null); + + isTrue("encoding test", Arrays.areEqual( + new PolicyConstraints(BigInteger.valueOf(1), null).getEncoded(), + new DERSequence(new DERTaggedObject(false, 0, new ASN1Integer(1))).getEncoded())); + } + + public static void main( + String[] args) + { + runTest(new PolicyConstraintsTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PollReqContentTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PollReqContentTest.java new file mode 100644 index 000000000..00e185c12 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PollReqContentTest.java @@ -0,0 +1,55 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.cmp.PollReqContent; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class PollReqContentTest + extends SimpleTest +{ + public String getName() + { + return "PollReqContentTest"; + } + + public void performTest() + throws Exception + { + BigInteger one = BigInteger.valueOf(1), two = BigInteger.valueOf(2); + BigInteger[] ids = new BigInteger[] { one, two }; + + PollReqContent c = new PollReqContent(ids); + + ASN1Integer[][] vs = c.getCertReqIds(); + + isTrue(vs.length == 2); + for (int i = 0; i != vs.length; i++) + { + isTrue(vs[i].length == 1); + isTrue(vs[i][0].getValue().equals(ids[i])); + } + + BigInteger[] values = c.getCertReqIdValues(); + + isTrue(values.length == 2); + for (int i = 0; i != values.length; i++) + { + isTrue(values[i].equals(ids[i])); + } + + c = new PollReqContent(two); + vs = c.getCertReqIds(); + + isTrue(vs.length == 1); + + isTrue(vs[0].length == 1); + isTrue(vs[0][0].getValue().equals(two)); + } + + public static void main(String[] args) + { + runTest(new PollReqContentTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PopLinkWitnessV2Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PopLinkWitnessV2Test.java new file mode 100644 index 000000000..3dd7b9586 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PopLinkWitnessV2Test.java @@ -0,0 +1,49 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.PopLinkWitnessV2; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class PopLinkWitnessV2Test + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new PopLinkWitnessV2Test()); + } + + public String getName() + { + return "PopLinkWitnessV2Test"; + } + + public void performTest() + throws Exception + { + // Object identifiers real but not correct in this context. + PopLinkWitnessV2 popLinkWitnessV2 = new PopLinkWitnessV2( + new AlgorithmIdentifier(PKCSObjectIdentifiers.bagtypes, new ASN1Integer(10L)), + new AlgorithmIdentifier(PKCSObjectIdentifiers.crlTypes, new ASN1Integer(12L)), + "cats".getBytes() + ); + + byte[] b = popLinkWitnessV2.getEncoded(); + PopLinkWitnessV2 popLinkWitnessV2Result = PopLinkWitnessV2.getInstance(b); + + isEquals(popLinkWitnessV2, popLinkWitnessV2Result); + + try + { + PopLinkWitnessV2.getInstance(new DERSequence()); + fail("Length must be 3"); + } + catch (Throwable t) + { + isEquals(t.getClass(), IllegalArgumentException.class); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PrivateKeyInfoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PrivateKeyInfoTest.java new file mode 100644 index 000000000..ba1ff2cc7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PrivateKeyInfoTest.java @@ -0,0 +1,49 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class PrivateKeyInfoTest + extends SimpleTest +{ + private static final byte[] priv = Base64.decode( + "MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC"); + + private static final byte[] privWithPub = Base64.decode( + "MHICAQEwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC" + + "oB8wHQYKKoZIhvcNAQkJFDEPDA1DdXJkbGUgQ2hhaXJzgSEAGb9ECWmEzf6FQbrB" + + "Z9w7lshQhqowtrbLDFw4rXAxZuE="); + + + public String getName() + { + return "PrivateKeyInfoTest"; + } + + public void performTest() + throws Exception + { + PrivateKeyInfo privInfo1 = PrivateKeyInfo.getInstance(priv); + + isTrue(!privInfo1.hasPublicKey()); + + PrivateKeyInfo privInfo2 = new PrivateKeyInfo(privInfo1.getPrivateKeyAlgorithm(), privInfo1.parsePrivateKey()); + + isTrue("enc 1 failed", areEqual(priv, privInfo2.getEncoded())); + + privInfo1 = PrivateKeyInfo.getInstance(privWithPub); + + isTrue(privInfo1.hasPublicKey()); + + privInfo2 = new PrivateKeyInfo(privInfo1.getPrivateKeyAlgorithm(), privInfo1.parsePrivateKey(), privInfo1.getAttributes(), privInfo1.getPublicKeyData().getOctets()); + + isTrue("enc 2 failed", areEqual(privWithPub, privInfo2.getEncoded())); + } + + public static void main( + String[] args) + { + runTest(new PrivateKeyInfoTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ProcurationSyntaxUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ProcurationSyntaxUnitTest.java new file mode 100644 index 000000000..442771e1a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ProcurationSyntaxUnitTest.java @@ -0,0 +1,107 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.ProcurationSyntax; +import com.fr.third.org.bouncycastle.asn1.x500.DirectoryString; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames; +import com.fr.third.org.bouncycastle.asn1.x509.IssuerSerial; + +public class ProcurationSyntaxUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "ProcurationSyntax"; + } + + public void performTest() + throws Exception + { + String country = "AU"; + DirectoryString typeOfSubstitution = new DirectoryString("substitution"); + GeneralName thirdPerson = new GeneralName(new X500Name("CN=thirdPerson")); + IssuerSerial certRef = new IssuerSerial(new GeneralNames(new GeneralName(new X500Name("CN=test"))), new ASN1Integer(1)); + + ProcurationSyntax procuration = new ProcurationSyntax(country, typeOfSubstitution, thirdPerson); + + checkConstruction(procuration, country, typeOfSubstitution, thirdPerson, null); + + procuration = new ProcurationSyntax(country, typeOfSubstitution, certRef); + + checkConstruction(procuration, country, typeOfSubstitution, null, certRef); + + procuration = new ProcurationSyntax(null, typeOfSubstitution, certRef); + + checkConstruction(procuration, null, typeOfSubstitution, null, certRef); + + procuration = new ProcurationSyntax(country, null, certRef); + + checkConstruction(procuration, country, null, null, certRef); + + procuration = ProcurationSyntax.getInstance(null); + + if (procuration != null) + { + fail("null getInstance() failed."); + } + + try + { + ProcurationSyntax.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + ProcurationSyntax procuration, + String country, + DirectoryString typeOfSubstitution, + GeneralName thirdPerson, + IssuerSerial certRef) + throws IOException + { + checkValues(procuration, country, typeOfSubstitution, thirdPerson, certRef); + + procuration = ProcurationSyntax.getInstance(procuration); + + checkValues(procuration, country, typeOfSubstitution, thirdPerson, certRef); + + ASN1InputStream aIn = new ASN1InputStream(procuration.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + procuration = ProcurationSyntax.getInstance(seq); + + checkValues(procuration, country, typeOfSubstitution, thirdPerson, certRef); + } + + private void checkValues( + ProcurationSyntax procuration, + String country, + DirectoryString typeOfSubstitution, + GeneralName thirdPerson, + IssuerSerial certRef) + { + checkOptionalField("country", country, procuration.getCountry()); + checkOptionalField("typeOfSubstitution", typeOfSubstitution, procuration.getTypeOfSubstitution()); + checkOptionalField("thirdPerson", thirdPerson, procuration.getThirdPerson()); + checkOptionalField("certRef", certRef, procuration.getCertRef()); + } + + public static void main( + String[] args) + { + runTest(new ProcurationSyntaxUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ProfessionInfoUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ProfessionInfoUnitTest.java new file mode 100644 index 000000000..3c514c0b6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ProfessionInfoUnitTest.java @@ -0,0 +1,117 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.NamingAuthority; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.ProcurationSyntax; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.ProfessionInfo; +import com.fr.third.org.bouncycastle.asn1.x500.DirectoryString; + +public class ProfessionInfoUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "ProfessionInfo"; + } + + public void performTest() + throws Exception + { + NamingAuthority auth = new NamingAuthority(new ASN1ObjectIdentifier("1.2.3"), "url", new DirectoryString("fred")); + DirectoryString[] professionItems = { new DirectoryString("substitution") }; + ASN1ObjectIdentifier[] professionOids = { new ASN1ObjectIdentifier("1.2.3") }; + String registrationNumber = "12345"; + DEROctetString addProfInfo = new DEROctetString(new byte[20]); + + ProfessionInfo info = new ProfessionInfo(auth, professionItems, professionOids, registrationNumber, addProfInfo); + + checkConstruction(info, auth, professionItems, professionOids, registrationNumber, addProfInfo); + + info = new ProfessionInfo(null, professionItems, professionOids, registrationNumber, addProfInfo); + + checkConstruction(info, null, professionItems, professionOids, registrationNumber, addProfInfo); + + info = new ProfessionInfo(auth, professionItems, null, registrationNumber, addProfInfo); + + checkConstruction(info, auth, professionItems, null, registrationNumber, addProfInfo); + + info = new ProfessionInfo(auth, professionItems, professionOids, null, addProfInfo); + + checkConstruction(info, auth, professionItems, professionOids, null, addProfInfo); + + info = new ProfessionInfo(auth, professionItems, professionOids, registrationNumber, null); + + checkConstruction(info, auth, professionItems, professionOids, registrationNumber, null); + + info = ProfessionInfo.getInstance(null); + + if (info != null) + { + fail("null getInstance() failed."); + } + + try + { + ProcurationSyntax.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + ProfessionInfo profInfo, + NamingAuthority auth, + DirectoryString[] professionItems, + ASN1ObjectIdentifier[] professionOids, + String registrationNumber, + DEROctetString addProfInfo) + throws IOException + { + checkValues(profInfo, auth, professionItems, professionOids, registrationNumber, addProfInfo); + + profInfo = ProfessionInfo.getInstance(profInfo); + + checkValues(profInfo, auth, professionItems, professionOids, registrationNumber, addProfInfo); + + ASN1InputStream aIn = new ASN1InputStream(profInfo.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + profInfo = ProfessionInfo.getInstance(seq); + + checkValues(profInfo, auth, professionItems, professionOids, registrationNumber, addProfInfo); + } + + private void checkValues( + ProfessionInfo profInfo, + NamingAuthority auth, + DirectoryString[] professionItems, + ASN1ObjectIdentifier[] professionOids, + String registrationNumber, + DEROctetString addProfInfo) + { + checkOptionalField("auth", auth, profInfo.getNamingAuthority()); + checkMandatoryField("professionItems", professionItems[0], profInfo.getProfessionItems()[0]); + if (professionOids != null) + { + checkOptionalField("professionOids", professionOids[0], profInfo.getProfessionOIDs()[0]); + } + checkOptionalField("registrationNumber", registrationNumber, profInfo.getRegistrationNumber()); + checkOptionalField("addProfessionInfo", addProfInfo, profInfo.getAddProfessionInfo()); + } + + public static void main( + String[] args) + { + runTest(new ProfessionInfoUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PublishTrustAnchorsTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PublishTrustAnchorsTest.java new file mode 100644 index 000000000..67adf2252 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/PublishTrustAnchorsTest.java @@ -0,0 +1,51 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cmc.PublishTrustAnchors; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class PublishTrustAnchorsTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new PublishTrustAnchorsTest()); + } + + public String getName() + { + return "PublishTrustAnchorsTest"; + } + + public void performTest() + throws Exception + { + PublishTrustAnchors publishTrustAnchors = new PublishTrustAnchors( + new BigInteger("10"), new AlgorithmIdentifier(PKCSObjectIdentifiers.crlTypes, + new ASN1Integer(5L)), new byte[][]{"cats".getBytes()}); + + byte[] b = publishTrustAnchors.getEncoded(); + + PublishTrustAnchors publishTrustAnchorsResult = PublishTrustAnchors.getInstance(b); + + isEquals("seqNumber", publishTrustAnchors.getSeqNumber(), publishTrustAnchorsResult.getSeqNumber()); + isEquals("hashAlgorithm", publishTrustAnchors.getHashAlgorithm(), publishTrustAnchorsResult.getHashAlgorithm()); + isTrue("anchorHashes", areEqual(publishTrustAnchors.getAnchorHashes(), publishTrustAnchorsResult.getAnchorHashes())); + + try + { + PublishTrustAnchors.getInstance(new DERSequence()); + fail("Sequence must be 3"); + } + catch (Throwable t) + { + isEquals("Expect IllegalArgumentException", t.getClass(), IllegalArgumentException.class); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/QCStatementUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/QCStatementUnitTest.java new file mode 100644 index 000000000..b285fa9e6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/QCStatementUnitTest.java @@ -0,0 +1,104 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.x509.qualified.QCStatement; +import com.fr.third.org.bouncycastle.asn1.x509.qualified.RFC3739QCObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.qualified.SemanticsInformation; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class QCStatementUnitTest + extends SimpleTest +{ + public String getName() + { + return "QCStatement"; + } + + public void performTest() + throws Exception + { + QCStatement mv = new QCStatement(RFC3739QCObjectIdentifiers.id_qcs_pkixQCSyntax_v1); + + checkConstruction(mv, RFC3739QCObjectIdentifiers.id_qcs_pkixQCSyntax_v1, null); + + ASN1Encodable info = new SemanticsInformation(new ASN1ObjectIdentifier("1.2")); + + mv = new QCStatement(RFC3739QCObjectIdentifiers.id_qcs_pkixQCSyntax_v1, info); + + checkConstruction(mv, RFC3739QCObjectIdentifiers.id_qcs_pkixQCSyntax_v1, info); + + mv = QCStatement.getInstance(null); + + if (mv != null) + { + fail("null getInstance() failed."); + } + + try + { + QCStatement.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + QCStatement mv, + ASN1ObjectIdentifier statementId, + ASN1Encodable statementInfo) + throws IOException + { + checkStatement(mv, statementId, statementInfo); + + mv = QCStatement.getInstance(mv); + + checkStatement(mv, statementId, statementInfo); + + ASN1InputStream aIn = new ASN1InputStream(mv.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + mv = QCStatement.getInstance(seq); + + checkStatement(mv, statementId, statementInfo); + } + + private void checkStatement( + QCStatement qcs, + ASN1ObjectIdentifier statementId, + ASN1Encodable statementInfo) + throws IOException + { + if (!qcs.getStatementId().equals(statementId)) + { + fail("statementIds don't match."); + } + + if (statementInfo != null) + { + if (!qcs.getStatementInfo().equals(statementInfo)) + { + fail("statementInfos don't match."); + } + } + else if (qcs.getStatementInfo() != null) + { + fail("statementInfo found when none expected."); + } + } + + public static void main( + String[] args) + { + runTest(new QCStatementUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RFC4519Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RFC4519Test.java new file mode 100644 index 000000000..e21176f3d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RFC4519Test.java @@ -0,0 +1,149 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.X500NameStyle; +import com.fr.third.org.bouncycastle.asn1.x500.style.RFC4519Style; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class RFC4519Test + extends SimpleTest +{ + static String[] attributeTypes = + { + "businessCategory", + "c", + "cn", + "dc", + "description", + "destinationIndicator", + "distinguishedName", + "dnQualifier", + "enhancedSearchGuide", + "facsimileTelephoneNumber", + "generationQualifier", + "givenName", + "houseIdentifier", + "initials", + "internationalISDNNumber", + "l", + "member", + "name", + "o", + "ou", + "owner", + "physicalDeliveryOfficeName", + "postalAddress", + "postalCode", + "postOfficeBox", + "preferredDeliveryMethod", + "registeredAddress", + "roleOccupant", + "searchGuide", + "seeAlso", + "serialNumber", + "sn", + "st", + "street", + "telephoneNumber", + "teletexTerminalIdentifier", + "telexNumber", + "title", + "uid", + "uniqueMember", + "userPassword", + "x121Address", + "x500UniqueIdentifier" + }; + + static ASN1ObjectIdentifier[] attributeTypeOIDs = + { + new ASN1ObjectIdentifier("2.5.4.15"), + new ASN1ObjectIdentifier("2.5.4.6"), + new ASN1ObjectIdentifier("2.5.4.3"), + new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.25"), + new ASN1ObjectIdentifier("2.5.4.13"), + new ASN1ObjectIdentifier("2.5.4.27"), + new ASN1ObjectIdentifier("2.5.4.49"), + new ASN1ObjectIdentifier("2.5.4.46"), + new ASN1ObjectIdentifier("2.5.4.47"), + new ASN1ObjectIdentifier("2.5.4.23"), + new ASN1ObjectIdentifier("2.5.4.44"), + new ASN1ObjectIdentifier("2.5.4.42"), + new ASN1ObjectIdentifier("2.5.4.51"), + new ASN1ObjectIdentifier("2.5.4.43"), + new ASN1ObjectIdentifier("2.5.4.25"), + new ASN1ObjectIdentifier("2.5.4.7"), + new ASN1ObjectIdentifier("2.5.4.31"), + new ASN1ObjectIdentifier("2.5.4.41"), + new ASN1ObjectIdentifier("2.5.4.10"), + new ASN1ObjectIdentifier("2.5.4.11"), + new ASN1ObjectIdentifier("2.5.4.32"), + new ASN1ObjectIdentifier("2.5.4.19"), + new ASN1ObjectIdentifier("2.5.4.16"), + new ASN1ObjectIdentifier("2.5.4.17"), + new ASN1ObjectIdentifier("2.5.4.18"), + new ASN1ObjectIdentifier("2.5.4.28"), + new ASN1ObjectIdentifier("2.5.4.26"), + new ASN1ObjectIdentifier("2.5.4.33"), + new ASN1ObjectIdentifier("2.5.4.14"), + new ASN1ObjectIdentifier("2.5.4.34"), + new ASN1ObjectIdentifier("2.5.4.5"), + new ASN1ObjectIdentifier("2.5.4.4"), + new ASN1ObjectIdentifier("2.5.4.8"), + new ASN1ObjectIdentifier("2.5.4.9"), + new ASN1ObjectIdentifier("2.5.4.20"), + new ASN1ObjectIdentifier("2.5.4.22"), + new ASN1ObjectIdentifier("2.5.4.21"), + new ASN1ObjectIdentifier("2.5.4.12"), + new ASN1ObjectIdentifier("0.9.2342.19200300.100.1.1"), + new ASN1ObjectIdentifier("2.5.4.50"), + new ASN1ObjectIdentifier("2.5.4.35"), + new ASN1ObjectIdentifier("2.5.4.24"), + new ASN1ObjectIdentifier("2.5.4.45") + }; + + public String getName() + { + return "RFC4519Test"; + } + + public void performTest() + throws Exception + { + X500NameStyle style = RFC4519Style.INSTANCE; + + for (int i = 0; i != attributeTypes.length; i++) + { + if (!attributeTypeOIDs[i].equals(style.attrNameToOID(attributeTypes[i]))) + { + fail("mismatch for " + attributeTypes[i]); + } + } + + byte[] enc = Hex.decode("305e310b300906035504061302415531283026060355040a0c1f546865204c6567696f6e206f662074686520426f756e637920436173746c653125301006035504070c094d656c626f75726e653011060355040b0c0a4173636f742056616c65"); + + X500Name n = X500Name.getInstance(style, X500Name.getInstance(enc)); + + if (!n.toString().equals("l=Melbourne+ou=Ascot Vale,o=The Legion of the Bouncy Castle,c=AU")) + { + fail("Failed composite to string test got: " + n.toString()); + } + + n = new X500Name(style, "l=Melbourne+ou=Ascot Vale,o=The Legion of the Bouncy Castle,c=AU"); + + if (!Arrays.areEqual(n.getEncoded(), enc)) + { + fail("re-encoding test after parse failed"); + } + } + + + public static void main( + String[] args) + { + runTest(new RFC4519Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ReasonFlagsTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ReasonFlagsTest.java new file mode 100644 index 000000000..e300f7ad7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/ReasonFlagsTest.java @@ -0,0 +1,35 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.x509.ReasonFlags; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ReasonFlagsTest + extends SimpleTest +{ + public String getName() + { + return "ReasonFlags"; + } + + public void performTest() + throws IOException + { + BitStringConstantTester.testFlagValueCorrect(0, ReasonFlags.unused); + BitStringConstantTester.testFlagValueCorrect(1, ReasonFlags.keyCompromise); + BitStringConstantTester.testFlagValueCorrect(2, ReasonFlags.cACompromise); + BitStringConstantTester.testFlagValueCorrect(3, ReasonFlags.affiliationChanged); + BitStringConstantTester.testFlagValueCorrect(4, ReasonFlags.superseded); + BitStringConstantTester.testFlagValueCorrect(5, ReasonFlags.cessationOfOperation); + BitStringConstantTester.testFlagValueCorrect(6, ReasonFlags.certificateHold); + BitStringConstantTester.testFlagValueCorrect(7, ReasonFlags.privilegeWithdrawn); + BitStringConstantTester.testFlagValueCorrect(8, ReasonFlags.aACompromise); + } + + public static void main( + String[] args) + { + runTest(new ReasonFlagsTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RegressionTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RegressionTest.java new file mode 100644 index 000000000..33f0e6d08 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RegressionTest.java @@ -0,0 +1,89 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.Test; + +public class RegressionTest +{ + public static Test[] tests = { + new InputStreamTest(), + new EqualsAndHashCodeTest(), + new TagTest(), + new SetTest(), + new ASN1IntegerTest(), + new DERUTF8StringTest(), + new CertificateTest(), + new GenerationTest(), + new CMSTest(), + new OCSPTest(), + new OIDTest(), + new PKCS10Test(), + new PKCS12Test(), + new X509NameTest(), + new X500NameTest(), + new X509ExtensionsTest(), + new GeneralizedTimeTest(), + new BitStringTest(), + new MiscTest(), + new SMIMETest(), + new X9Test(), + new MonetaryValueUnitTest(), + new BiometricDataUnitTest(), + new Iso4217CurrencyCodeUnitTest(), + new SemanticsInformationUnitTest(), + new QCStatementUnitTest(), + new TypeOfBiometricDataUnitTest(), + new SignerLocationUnitTest(), + new CommitmentTypeQualifierUnitTest(), + new CommitmentTypeIndicationUnitTest(), + new EncryptedPrivateKeyInfoTest(), + new DataGroupHashUnitTest(), + new LDSSecurityObjectUnitTest(), + new CscaMasterListTest(), + new AttributeTableUnitTest(), + new ReasonFlagsTest(), + new NetscapeCertTypeTest(), + new PKIFailureInfoTest(), + new KeyUsageTest(), + new StringTest(), + new UTCTimeTest(), + new RequestedCertificateUnitTest(), + new OtherCertIDUnitTest(), + new OtherSigningCertificateUnitTest(), + new ContentHintsUnitTest(), + new CertHashUnitTest(), + new AdditionalInformationSyntaxUnitTest(), + new AdmissionSyntaxUnitTest(), + new AdmissionsUnitTest(), + new DeclarationOfMajorityUnitTest(), + new ProcurationSyntaxUnitTest(), + new ProfessionInfoUnitTest(), + new RestrictionUnitTest(), + new NamingAuthorityUnitTest(), + new MonetaryLimitUnitTest(), + new NameOrPseudonymUnitTest(), + new PersonalDataUnitTest(), + new DERApplicationSpecificTest(), + new IssuingDistributionPointUnitTest(), + new TargetInformationTest(), + new SubjectKeyIdentifierTest(), + new ESSCertIDv2UnitTest(), + new ParsingTest(), + new GeneralNameTest(), + new ObjectIdentifierTest(), + new RFC4519Test(), + new PolicyConstraintsTest(), + new PollReqContentTest(), + new DhSigStaticTest(), + new PKIPublicationInfoTest(), + new CertifiedKeyPairTest(), + new PrivateKeyInfoTest(), + new LocaleTest(), + new LinkedCertificateTest() + }; + + public static void main(String[] args) + { + SimpleTest.runTests(tests); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RequestedCertificateUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RequestedCertificateUnitTest.java new file mode 100644 index 000000000..77bf64419 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RequestedCertificateUnitTest.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.isismtt.ocsp.RequestedCertificate; +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.util.encoders.Base64; + +public class RequestedCertificateUnitTest + extends ASN1UnitTest +{ + byte[] certBytes = Base64.decode( + "MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV" + + "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz" + + "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM" + + "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF" + + "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO" + + "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE" + + "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ" + + "zl9HYIMxATFyqSiD9jsx"); + + public String getName() + { + return "RequestedCertificate"; + } + + public void performTest() + throws Exception + { + int type = 1; + byte[] certOctets = new byte[20]; + Certificate cert = Certificate.getInstance(certBytes); + + RequestedCertificate requested = new RequestedCertificate(type, certOctets); + + checkConstruction(requested, type, certOctets, null); + + requested = new RequestedCertificate(cert); + + checkConstruction(requested, RequestedCertificate.certificate, null, cert); + + requested = RequestedCertificate.getInstance(null); + + if (requested != null) + { + fail("null getInstance() failed."); + } + + try + { + RequestedCertificate.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + RequestedCertificate requested, + int type, + byte[] certOctets, + Certificate cert) + throws IOException + { + checkValues(requested, type, certOctets, cert); + + requested = RequestedCertificate.getInstance(requested); + + checkValues(requested, type, certOctets, cert); + + ASN1InputStream aIn = new ASN1InputStream(requested.toASN1Primitive().getEncoded()); + + Object obj = aIn.readObject(); + + requested = RequestedCertificate.getInstance(obj); + + checkValues(requested, type, certOctets, cert); + } + + private void checkValues( + RequestedCertificate requested, + int type, + byte[] certOctets, + Certificate cert) + throws IOException + { + checkMandatoryField("certType", type, requested.getType()); + + if (requested.getType() == RequestedCertificate.certificate) + { + checkMandatoryField("certificate", cert.getEncoded(), requested.getCertificateBytes()); + } + else + { + checkMandatoryField("certificateOctets", certOctets, requested.getCertificateBytes()); + } + } + + public static void main( + String[] args) + { + runTest(new RequestedCertificateUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RestrictionUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RestrictionUnitTest.java new file mode 100644 index 000000000..c870d14ac --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RestrictionUnitTest.java @@ -0,0 +1,70 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1String; +import com.fr.third.org.bouncycastle.asn1.isismtt.x509.Restriction; +import com.fr.third.org.bouncycastle.asn1.x500.DirectoryString; + +public class RestrictionUnitTest + extends ASN1UnitTest +{ + public String getName() + { + return "Restriction"; + } + + public void performTest() + throws Exception + { + DirectoryString res = new DirectoryString("test"); + Restriction restriction = new Restriction(res.getString()); + + checkConstruction(restriction, res); + + try + { + Restriction.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + Restriction restriction, + DirectoryString res) + throws IOException + { + checkValues(restriction, res); + + restriction = Restriction.getInstance(restriction); + + checkValues(restriction, res); + + ASN1InputStream aIn = new ASN1InputStream(restriction.toASN1Primitive().getEncoded()); + + ASN1String str = (ASN1String)aIn.readObject(); + + restriction = Restriction.getInstance(str); + + checkValues(restriction, res); + } + + private void checkValues( + Restriction restriction, + DirectoryString res) + { + checkMandatoryField("restriction", res, restriction.getRestriction()); + } + + public static void main( + String[] args) + { + runTest(new RestrictionUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RevokeRequestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RevokeRequestTest.java new file mode 100644 index 000000000..554cd66fa --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/RevokeRequestTest.java @@ -0,0 +1,93 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.util.Date; + +import com.fr.third.org.bouncycastle.asn1.ASN1Enumerated; +import com.fr.third.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERUTF8String; +import com.fr.third.org.bouncycastle.asn1.cmc.RevokeRequest; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.X500NameBuilder; +import com.fr.third.org.bouncycastle.asn1.x500.style.BCStyle; +import com.fr.third.org.bouncycastle.asn1.x509.CRLReason; +import com.fr.third.org.bouncycastle.util.Pack; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class RevokeRequestTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new RevokeRequestTest()); + } + + public String getName() + { + return "RevokeRequestTest"; + } + + public void performTest() + throws Exception + { + + + X500NameBuilder builder = new X500NameBuilder(); + builder.addRDN(BCStyle.OU, "Bouncycastle"); + + X500Name name = builder.build(); + + for (int t = 0; t < 8; t++) + { + ASN1GeneralizedTime invalidityDate = null; + ASN1OctetString passphrase = null; + DERUTF8String comment = null; + + if ((t & 1) == 1) + { + invalidityDate = new ASN1GeneralizedTime(new Date()); + } + if ((t & 2) == 2) + { + passphrase = new DEROctetString(Pack.longToBigEndian(System.currentTimeMillis())); + } + if ((t & 4) == 4) + { + comment = new DERUTF8String("T" + Long.toOctalString(System.currentTimeMillis())); + } + + RevokeRequest rr = new RevokeRequest( + name, + new ASN1Integer(12L), + CRLReason.getInstance(new ASN1Enumerated(CRLReason.certificateHold)), + invalidityDate, + passphrase, + comment); + byte[] b = rr.getEncoded(); + RevokeRequest rrResp = RevokeRequest.getInstance(b); + + isEquals("issuerName", rr.getName(), rrResp.getName()); + isEquals("serialNumber", rr.getSerialNumber(), rrResp.getSerialNumber()); + isEquals("reason", rr.getReason(), rrResp.getReason()); + isEquals("invalidityDate", rr.getInvalidityDate(), rrResp.getInvalidityDate()); + isTrue("passphrase", areEqual(rr.getPassPhrase(), rrResp.getPassPhrase())); + isEquals("comment", rr.getComment(), rrResp.getComment()); + + } + + try + { + RevokeRequest.getInstance(new DERSequence()); + fail("Sequence is less that 3"); + } + catch (Throwable t) + { + isEquals("Exception type", t.getClass(), IllegalArgumentException.class); + } + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SMIMETest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SMIMETest.java new file mode 100644 index 000000000..20bf3fafc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SMIMETest.java @@ -0,0 +1,109 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.ByteArrayInputStream; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.DERGeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.cms.RecipientKeyIdentifier; +import com.fr.third.org.bouncycastle.asn1.smime.SMIMECapabilitiesAttribute; +import com.fr.third.org.bouncycastle.asn1.smime.SMIMECapability; +import com.fr.third.org.bouncycastle.asn1.smime.SMIMECapabilityVector; +import com.fr.third.org.bouncycastle.asn1.smime.SMIMEEncryptionKeyPreferenceAttribute; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class SMIMETest + implements Test +{ + byte[] attrBytes = Base64.decode("MDQGCSqGSIb3DQEJDzEnMCUwCgYIKoZIhvcNAwcwDgYIKoZIhvcNAwICAgCAMAcGBSsOAwIH"); + byte[] prefBytes = Base64.decode("MCwGCyqGSIb3DQEJEAILMR2hGwQIAAAAAAAAAAAYDzIwMDcwMzE1MTczNzI5Wg=="); + + private boolean isSameAs( + byte[] a, + byte[] b) + { + if (a.length != b.length) + { + return false; + } + + for (int i = 0; i != a.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + public TestResult perform() + { + SMIMECapabilityVector caps = new SMIMECapabilityVector(); + + caps.addCapability(SMIMECapability.dES_EDE3_CBC); + caps.addCapability(SMIMECapability.rC2_CBC, 128); + caps.addCapability(SMIMECapability.dES_CBC); + + SMIMECapabilitiesAttribute attr = new SMIMECapabilitiesAttribute(caps); + + SMIMEEncryptionKeyPreferenceAttribute pref = new SMIMEEncryptionKeyPreferenceAttribute( + new RecipientKeyIdentifier(new DEROctetString(new byte[8]), new DERGeneralizedTime("20070315173729Z"), null)); + + try + { + if (!isSameAs(attr.getEncoded(), attrBytes)) + { + return new SimpleTestResult(false, getName() + ": Failed attr data check"); + } + + ByteArrayInputStream bIn = new ByteArrayInputStream(attrBytes); + ASN1InputStream aIn = new ASN1InputStream(bIn); + + ASN1Primitive o = aIn.readObject(); + if (!attr.equals(o)) + { + return new SimpleTestResult(false, getName() + ": Failed equality test for attr"); + } + + if (!isSameAs(pref.getEncoded(), prefBytes)) + { + return new SimpleTestResult(false, getName() + ": Failed attr data check"); + } + + bIn = new ByteArrayInputStream(prefBytes); + aIn = new ASN1InputStream(bIn); + + o = aIn.readObject(); + if (!pref.equals(o)) + { + return new SimpleTestResult(false, getName() + ": Failed equality test for pref"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": Failed - exception " + e.toString(), e); + } + } + + public String getName() + { + return "SMIME"; + } + + public static void main( + String[] args) + { + SMIMETest test = new SMIMETest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SemanticsInformationUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SemanticsInformationUnitTest.java new file mode 100644 index 000000000..3efa5c06a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SemanticsInformationUnitTest.java @@ -0,0 +1,135 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.qualified.SemanticsInformation; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SemanticsInformationUnitTest + extends SimpleTest +{ + public String getName() + { + return "SemanticsInformation"; + } + + public void performTest() + throws Exception + { + ASN1ObjectIdentifier statementId = new ASN1ObjectIdentifier("1.1"); + SemanticsInformation mv = new SemanticsInformation(statementId); + + checkConstruction(mv, statementId, null); + + GeneralName[] names = new GeneralName[2]; + + names[0] = new GeneralName(GeneralName.rfc822Name, "test@test.org"); + names[1] = new GeneralName(new X500Name("cn=test")); + + mv = new SemanticsInformation(statementId, names); + + checkConstruction(mv, statementId, names); + + mv = new SemanticsInformation(names); + + checkConstruction(mv, null, names); + + mv = SemanticsInformation.getInstance(null); + + if (mv != null) + { + fail("null getInstance() failed."); + } + + try + { + SemanticsInformation.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + SemanticsInformation.getInstance(new DERSequence(v)); + + fail("constructor failed to detect empty sequence."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + SemanticsInformation mv, + ASN1ObjectIdentifier semanticsIdentifier, + GeneralName[] names) + throws Exception + { + checkStatement(mv, semanticsIdentifier, names); + + mv = SemanticsInformation.getInstance(mv); + + checkStatement(mv, semanticsIdentifier, names); + + ASN1InputStream aIn = new ASN1InputStream(mv.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + mv = SemanticsInformation.getInstance(seq); + + checkStatement(mv, semanticsIdentifier, names); + } + + private void checkStatement( + SemanticsInformation si, + ASN1ObjectIdentifier id, + GeneralName[] names) + { + if (id != null) + { + if (!si.getSemanticsIdentifier().equals(id)) + { + fail("ids don't match."); + } + } + else if (si.getSemanticsIdentifier() != null) + { + fail("statementId found when none expected."); + } + + if (names != null) + { + GeneralName[] siNames = si.getNameRegistrationAuthorities(); + + for (int i = 0; i != siNames.length; i++) + { + if (!names[i].equals(siNames[i])) + { + fail("name registration authorities don't match."); + } + } + } + else if (si.getNameRegistrationAuthorities() != null) + { + fail("name registration authorities found when none expected."); + } + } + + public static void main( + String[] args) + { + runTest(new SemanticsInformationUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SetTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SetTest.java new file mode 100644 index 000000000..6d836cf77 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SetTest.java @@ -0,0 +1,115 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1Boolean; +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Set; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.BERSet; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Set sorting test example + */ +public class SetTest + extends SimpleTest +{ + + public String getName() + { + return "Set"; + } + + private void checkedSortedSet(int attempt, ASN1Set s) + { + if (s.getObjectAt(0) instanceof ASN1Boolean + && s.getObjectAt(1) instanceof ASN1Integer + && s.getObjectAt(2) instanceof DERBitString + && s.getObjectAt(3) instanceof DEROctetString) + { + return; + } + + fail("sorting failed on attempt: " + attempt); + } + + public void performTest() + { + ASN1EncodableVector v = new ASN1EncodableVector(); + byte[] data = new byte[10]; + + v.add(new DEROctetString(data)); + v.add(new DERBitString(data)); + v.add(new ASN1Integer(100)); + v.add(ASN1Boolean.getInstance(true)); + + checkedSortedSet(0, new DERSet(v)); + + v = new ASN1EncodableVector(); + v.add(new ASN1Integer(100)); + v.add(ASN1Boolean.getInstance(true)); + v.add(new DEROctetString(data)); + v.add(new DERBitString(data)); + + checkedSortedSet(1, new DERSet(v)); + + v = new ASN1EncodableVector(); + v.add(ASN1Boolean.getInstance(true)); + v.add(new DEROctetString(data)); + v.add(new DERBitString(data)); + v.add(new ASN1Integer(100)); + + + checkedSortedSet(2, new DERSet(v)); + + v = new ASN1EncodableVector(); + v.add(new DERBitString(data)); + v.add(new DEROctetString(data)); + v.add(new ASN1Integer(100)); + v.add(ASN1Boolean.getInstance(true)); + + checkedSortedSet(3, new DERSet(v)); + + v = new ASN1EncodableVector(); + v.add(new DEROctetString(data)); + v.add(new DERBitString(data)); + v.add(new ASN1Integer(100)); + v.add(ASN1Boolean.getInstance(true)); + + ASN1Set s = new BERSet(v); + + if (!(s.getObjectAt(0) instanceof DEROctetString)) + { + fail("BER set sort order changed."); + } + + // create an implicitly tagged "set" without sorting + ASN1TaggedObject tag = new DERTaggedObject(false, 1, new DERSequence(v)); + s = ASN1Set.getInstance(tag, false); + + if (s.getObjectAt(0) instanceof ASN1Boolean) + { + fail("sorted when shouldn't be."); + } + + // equality test + v = new ASN1EncodableVector(); + + v.add(ASN1Boolean.getInstance(true)); + v.add(ASN1Boolean.getInstance(true)); + v.add(ASN1Boolean.getInstance(true)); + + s = new DERSet(v); + } + + public static void main( + String[] args) + { + runTest(new SetTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SignerLocationUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SignerLocationUnitTest.java new file mode 100644 index 000000000..17f7ad46b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SignerLocationUnitTest.java @@ -0,0 +1,198 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERUTF8String; +import com.fr.third.org.bouncycastle.asn1.esf.SignerLocation; +import com.fr.third.org.bouncycastle.asn1.x500.DirectoryString; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SignerLocationUnitTest + extends SimpleTest +{ + public String getName() + { + return "SignerLocation"; + } + + public void performTest() + throws Exception + { + DERUTF8String countryName = new DERUTF8String("Australia"); + + SignerLocation sl = new SignerLocation(countryName, null, null); + + checkConstruction(sl, DirectoryString.getInstance(countryName), null, null); + + DERUTF8String localityName = new DERUTF8String("Melbourne"); + + sl = new SignerLocation(null, localityName, null); + + checkConstruction(sl, null, DirectoryString.getInstance(localityName), null); + + sl = new SignerLocation(countryName, localityName, null); + + checkConstruction(sl, DirectoryString.getInstance(countryName), DirectoryString.getInstance(localityName), null); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new DERUTF8String("line 1")); + v.add(new DERUTF8String("line 2")); + + ASN1Sequence postalAddress = new DERSequence(v); + + sl = new SignerLocation(null, null, postalAddress); + + checkConstruction(sl, null, null, postalAddress); + + sl = new SignerLocation(countryName, null, postalAddress); + + checkConstruction(sl, DirectoryString.getInstance(countryName), null, postalAddress); + + sl = new SignerLocation(countryName, localityName, postalAddress); + + checkConstruction(sl, DirectoryString.getInstance(countryName), DirectoryString.getInstance(localityName), postalAddress); + + sl = SignerLocation.getInstance(null); + + if (sl != null) + { + fail("null getInstance() failed."); + } + + try + { + SignerLocation.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + + // + // out of range postal address + // + v = new ASN1EncodableVector(); + + v.add(new DERUTF8String("line 1")); + v.add(new DERUTF8String("line 2")); + v.add(new DERUTF8String("line 3")); + v.add(new DERUTF8String("line 4")); + v.add(new DERUTF8String("line 5")); + v.add(new DERUTF8String("line 6")); + v.add(new DERUTF8String("line 7")); + + postalAddress = new DERSequence(v); + + try + { + new SignerLocation(null, null, postalAddress); + + fail("constructor failed to detect bad postalAddress."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + SignerLocation.getInstance(new DERSequence(new DERTaggedObject(2, postalAddress))); + + fail("sequence constructor failed to detect bad postalAddress."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + SignerLocation.getInstance(new DERSequence(new DERTaggedObject(5, postalAddress))); + + fail("sequence constructor failed to detect bad tag."); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + private void checkConstruction( + SignerLocation sl, + DirectoryString countryName, + DirectoryString localityName, + ASN1Sequence postalAddress) + throws IOException + { + checkValues(sl, countryName, localityName, postalAddress); + + sl = SignerLocation.getInstance(sl); + + checkValues(sl, countryName, localityName, postalAddress); + + ASN1InputStream aIn = new ASN1InputStream(sl.toASN1Primitive().getEncoded()); + + ASN1Sequence seq = (ASN1Sequence)aIn.readObject(); + + sl = SignerLocation.getInstance(seq); + + checkValues(sl, countryName, localityName, postalAddress); + } + + private void checkValues( + SignerLocation sl, + DirectoryString countryName, + DirectoryString localityName, + ASN1Sequence postalAddress) + { + if (countryName != null) + { + if (!countryName.equals(sl.getCountryName())) + { + fail("countryNames don't match."); + } + } + else if (sl.getCountryName() != null) + { + fail("countryName found when none expected."); + } + + if (localityName != null) + { + if (!localityName.equals(sl.getLocalityName())) + { + fail("localityNames don't match."); + } + } + else if (sl.getLocalityName() != null) + { + fail("localityName found when none expected."); + } + + if (postalAddress != null) + { + if (!postalAddress.equals(sl.getPostalAddress())) + { + fail("postalAddresses don't match."); + } + } + else if (sl.getPostalAddress() != null) + { + fail("postalAddress found when none expected."); + } + } + + public static void main( + String[] args) + { + runTest(new SignerLocationUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/StringTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/StringTest.java new file mode 100644 index 000000000..0432ea1e8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/StringTest.java @@ -0,0 +1,161 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1String; +import com.fr.third.org.bouncycastle.asn1.DERBMPString; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DERGeneralString; +import com.fr.third.org.bouncycastle.asn1.DERIA5String; +import com.fr.third.org.bouncycastle.asn1.DERNumericString; +import com.fr.third.org.bouncycastle.asn1.DERPrintableString; +import com.fr.third.org.bouncycastle.asn1.DERT61String; +import com.fr.third.org.bouncycastle.asn1.DERUTF8String; +import com.fr.third.org.bouncycastle.asn1.DERUniversalString; +import com.fr.third.org.bouncycastle.asn1.DERVisibleString; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * X.690 test example + */ +public class StringTest + extends SimpleTest +{ + public String getName() + { + return "String"; + } + + public void performTest() + throws IOException + { + DERBitString bs = new DERBitString( + new byte[] { (byte)0x01,(byte)0x23,(byte)0x45,(byte)0x67,(byte)0x89,(byte)0xab,(byte)0xcd,(byte)0xef }); + + if (!bs.getString().equals("#0309000123456789ABCDEF")) + { + fail("DERBitString.getString() result incorrect"); + } + + if (!bs.toString().equals("#0309000123456789ABCDEF")) + { + fail("DERBitString.toString() result incorrect"); + } + + bs = new DERBitString( + new byte[] { (byte)0xfe,(byte)0xdc,(byte)0xba,(byte)0x98,(byte)0x76,(byte)0x54,(byte)0x32,(byte)0x10 }); + + if (!bs.getString().equals("#030900FEDCBA9876543210")) + { + fail("DERBitString.getString() result incorrect"); + } + + if (!bs.toString().equals("#030900FEDCBA9876543210")) + { + fail("DERBitString.toString() result incorrect"); + } + + DERUniversalString us = new DERUniversalString( + new byte[] { (byte)0x01,(byte)0x23,(byte)0x45,(byte)0x67,(byte)0x89,(byte)0xab,(byte)0xcd,(byte)0xef }); + + if (!us.getString().equals("#1C080123456789ABCDEF")) + { + fail("DERUniversalString.getString() result incorrect"); + } + + if (!us.toString().equals("#1C080123456789ABCDEF")) + { + fail("DERUniversalString.toString() result incorrect"); + } + + us = new DERUniversalString( + new byte[] { (byte)0xfe,(byte)0xdc,(byte)0xba,(byte)0x98,(byte)0x76,(byte)0x54,(byte)0x32,(byte)0x10 }); + + if (!us.getString().equals("#1C08FEDCBA9876543210")) + { + fail("DERUniversalString.getString() result incorrect"); + } + + if (!us.toString().equals("#1C08FEDCBA9876543210")) + { + fail("DERUniversalString.toString() result incorrect"); + } + + byte[] t61Bytes = new byte[] { -1, -2, -3, -4, -5, -6, -7, -8 }; + String t61String = new String(t61Bytes, "iso-8859-1"); + DERT61String t61 = new DERT61String(Strings.fromByteArray(t61Bytes)); + + if (!t61.getString().equals(t61String)) + { + fail("DERT61String.getString() result incorrect"); + } + + if (!t61.toString().equals(t61String)) + { + fail("DERT61String.toString() result incorrect"); + } + + char[] shortChars = new char[] { 'a', 'b', 'c', 'd', 'e'}; + char[] longChars = new char[1000]; + + for (int i = 0; i != longChars.length; i++) + { + longChars[i] = 'X'; + } + + checkString(new DERBMPString(new String(shortChars)), new DERBMPString(new String(longChars))); + checkString(new DERUTF8String(new String(shortChars)), new DERUTF8String(new String(longChars))); + checkString(new DERIA5String(new String(shortChars)), new DERIA5String(new String(longChars))); + checkString(new DERPrintableString(new String(shortChars)), new DERPrintableString(new String(longChars))); + checkString(new DERVisibleString(new String(shortChars)), new DERVisibleString(new String(longChars))); + checkString(new DERGeneralString(new String(shortChars)), new DERGeneralString(new String(longChars))); + checkString(new DERT61String(new String(shortChars)), new DERT61String(new String(longChars))); + + shortChars = new char[] { '1', '2', '3', '4', '5'}; + longChars = new char[1000]; + + for (int i = 0; i != longChars.length; i++) + { + longChars[i] = '1'; + } + + checkString(new DERNumericString(new String(shortChars)), new DERNumericString(new String(longChars))); + + byte[] shortBytes = new byte[] { (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e'}; + byte[] longBytes = new byte[1000]; + + for (int i = 0; i != longChars.length; i++) + { + longBytes[i] = (byte)'X'; + } + + checkString(new DERUniversalString(shortBytes), new DERUniversalString(longBytes)); + + } + + private void checkString(ASN1String shortString, ASN1String longString) + throws IOException + { + ASN1String short2 = (ASN1String)ASN1Primitive.fromByteArray(((ASN1Primitive)shortString).getEncoded()); + + if (!shortString.toString().equals(short2.toString())) + { + fail(short2.getClass().getName() + " shortBytes result incorrect"); + } + + ASN1String long2 = (ASN1String)ASN1Primitive.fromByteArray(((ASN1Primitive)longString).getEncoded()); + + if (!longString.toString().equals(long2.toString())) + { + fail(long2.getClass().getName() + " longBytes result incorrect"); + } + } + + public static void main( + String[] args) + { + runTest(new StringTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SubjectKeyIdentifierTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SubjectKeyIdentifierTest.java new file mode 100644 index 000000000..ba1ef54b3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/SubjectKeyIdentifierTest.java @@ -0,0 +1,48 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SubjectKeyIdentifierTest + extends SimpleTest +{ + private static byte[] pubKeyInfo = Base64.decode( + "MFgwCwYJKoZIhvcNAQEBA0kAMEYCQQC6wMMmHYMZszT/7bNFMn+gaZoiWJLVP8ODRuu1C2jeAe" + + "QpxM+5Oe7PaN2GNy3nBE4EOYkB5pMJWA0y9n04FX8NAgED"); + + private static byte[] shaID = Hex.decode("d8128a06d6c2feb0865994a2936e7b75b836a021"); + private static byte[] shaTruncID = Hex.decode("436e7b75b836a021"); + + public String getName() + { + return "SubjectKeyIdentifier"; + } + + public void performTest() + throws IOException + { +// SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pubKeyInfo)); +// SubjectKeyIdentifier ski = SubjectKeyIdentifier.createSHA1KeyIdentifier(pubInfo); +// +// if (!Arrays.areEqual(shaID, ski.getKeyIdentifier())) +// { +// fail("SHA-1 ID does not match"); +// } +// +// ski = SubjectKeyIdentifier.createTruncatedSHA1KeyIdentifier(pubInfo); +// +// if (!Arrays.areEqual(shaTruncID, ski.getKeyIdentifier())) +// { +// fail("truncated SHA-1 ID does not match"); +// } + } + + public static void main( + String[] args) + { + runTest(new SubjectKeyIdentifierTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TagTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TagTest.java new file mode 100644 index 000000000..3bc524fc9 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TagTest.java @@ -0,0 +1,114 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.ASN1ApplicationSpecific; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERApplicationSpecific; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +/** + * X.690 test example + */ +public class TagTest + extends SimpleTest +{ + byte[] longTagged = Base64.decode( + "ZSRzIp8gEEZFRENCQTk4NzY1NDMyMTCfIQwyMDA2MDQwMTEyMzSUCCAFERVz" + + "A4kCAHEXGBkalAggBRcYGRqUCCAFZS6QAkRFkQlURUNITklLRVKSBQECAwQF" + + "kxAREhMUFRYXGBkalAggBREVcwOJAgBxFxgZGpQIIAUXGBkalAggBWUukAJE" + + "RZEJVEVDSE5JS0VSkgUBAgMEBZMQERITFBUWFxgZGpQIIAURFXMDiQIAcRcY" + + "GRqUCCAFFxgZGpQIIAVlLpACREWRCVRFQ0hOSUtFUpIFAQIDBAWTEBESExQV" + + "FhcYGRqUCCAFERVzA4kCAHEXGBkalAggBRcYGRqUCCAFFxgZGpQIIAUXGBka" + + "lAg="); + + byte[] longAppSpecificTag = Hex.decode("5F610101"); + + public String getName() + { + return "Tag"; + } + + public void performTest() + throws IOException + { + ASN1InputStream aIn = new ASN1InputStream(longTagged); + + ASN1ApplicationSpecific app = (ASN1ApplicationSpecific)aIn.readObject(); + + aIn = new ASN1InputStream(app.getContents()); + + app = (ASN1ApplicationSpecific)aIn.readObject(); + + aIn = new ASN1InputStream(app.getContents()); + + ASN1TaggedObject tagged = (ASN1TaggedObject)aIn.readObject(); + + if (tagged.getTagNo() != 32) + { + fail("unexpected tag value found - not 32"); + } + + tagged = (ASN1TaggedObject)ASN1Primitive.fromByteArray(tagged.getEncoded()); + + if (tagged.getTagNo() != 32) + { + fail("unexpected tag value found on recode - not 32"); + } + + tagged = (ASN1TaggedObject)aIn.readObject(); + + if (tagged.getTagNo() != 33) + { + fail("unexpected tag value found - not 33"); + } + + tagged = (ASN1TaggedObject)ASN1Primitive.fromByteArray(tagged.getEncoded()); + + if (tagged.getTagNo() != 33) + { + fail("unexpected tag value found on recode - not 33"); + } + + aIn = new ASN1InputStream(longAppSpecificTag); + + app = (ASN1ApplicationSpecific)aIn.readObject(); + + if (app.getApplicationTag() != 97) + { + fail("incorrect tag number read"); + } + + app = (ASN1ApplicationSpecific)ASN1Primitive.fromByteArray(app.getEncoded()); + + if (app.getApplicationTag() != 97) + { + fail("incorrect tag number read on recode"); + } + + SecureRandom sr = new SecureRandom(); + for (int i = 0; i < 100; ++i) + { + int testTag = sr.nextInt() >>> (1 + (sr.nextInt() >>> 1) % 26); + app = new DERApplicationSpecific(testTag, new byte[]{ 1 }); + app = (ASN1ApplicationSpecific)ASN1Primitive.fromByteArray(app.getEncoded()); + + if (app.getApplicationTag() != testTag) + { + fail("incorrect tag number read on recode (random test value: " + testTag + ")"); + } + } + } + + public static void main( + String[] args) + { + runTest(new TagTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedAttributeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedAttributeTest.java new file mode 100644 index 000000000..99e1ca92a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedAttributeTest.java @@ -0,0 +1,82 @@ +package com.fr.third.org.bouncycastle.asn1.test; + + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DERIA5String; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.CMCObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedAttribute; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class TaggedAttributeTest + extends SimpleTest +{ + public String getName() + { + return "TaggedAttributeTest"; + } + + public void performTest() + throws Exception + { + // + // This creates and tests the various get instance methods. + // + TaggedAttribute ta = new TaggedAttribute( + new BodyPartID(10L), + CMCObjectIdentifiers.id_cct_PKIData, + new DERSet(new DERIA5String("Cats"))); + + byte[] d = ta.getEncoded(); + + { + TaggedAttribute res1 = TaggedAttribute.getInstance(d); + isEquals(ta.getBodyPartID(), res1.getBodyPartID()); + isEquals(ta.getAttrType(), res1.getAttrType()); + isEquals(ta.getAttrValues().getObjectAt(0), res1.getAttrValues().getObjectAt(0)); + isTrue(Arrays.areEqual(res1.getEncoded(), d)); + } + + // + // Where sequence is too short. + // + try + { + ASN1Sequence seq = new DERSequence(new ASN1Encodable[] { new BodyPartID(10) }); + + TaggedAttribute.getInstance(seq); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("incorrect sequence size", e.getMessage()); + } + + // + // Where sequence is too long. + // + try + { + ASN1Sequence seq = new DERSequence(new ASN1Encodable[] { ta.getBodyPartID(), ta.getAttrType(), ta.getAttrValues(), new ASN1Integer(0)}); + + TaggedAttribute.getInstance(seq); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("incorrect sequence size", e.getMessage()); + } + } + + public static void main(String[] args) + throws Exception + { + runTest(new TaggedAttributeTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedCertificationRequestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedCertificationRequestTest.java new file mode 100644 index 000000000..98103e5bd --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedCertificationRequestTest.java @@ -0,0 +1,41 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.CertificationRequest; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedCertificationRequest; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +public class TaggedCertificationRequestTest extends SimpleTest +{ + public static void main(String[] args) { + runTest(new TaggedCertificationRequestTest()); + } + + public String getName() + { + return "TaggedCertificationRequestTest"; + } + + + private static byte[] req1 = Base64.decode( + "MIHoMIGTAgEAMC4xDjAMBgNVBAMTBVRlc3QyMQ8wDQYDVQQKEwZBbmFUb20xCzAJBgNVBAYTAlNF" + + "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALlEt31Tzt2MlcOljvacJgzQVhmlMoqAOgqJ9Pgd3Gux" + + "Z7/WcIlgW4QCB7WZT21O1YoghwBhPDMcNGrHei9kHQkCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA0EA" + + "NDEI4ecNtJ3uHwGGlitNFq9WxcoZ0djbQJ5hABMotav6gtqlrwKXY2evaIrsNwkJtNdwwH18aQDU" + + "KCjOuBL38Q=="); + + + public void performTest() + throws Exception + { + CertificationRequest r = CertificationRequest.getInstance(req1); + TaggedCertificationRequest tcr = new TaggedCertificationRequest(new BodyPartID(10L), r); + + byte[] b = tcr.getEncoded(); + TaggedCertificationRequest tcrResp = TaggedCertificationRequest.getInstance(b); + + isEquals(tcrResp,tcr); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedContentInfoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedContentInfoTest.java new file mode 100644 index 000000000..39aec8268 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedContentInfoTest.java @@ -0,0 +1,49 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERUTF8String; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedContentInfo; +import com.fr.third.org.bouncycastle.asn1.cms.ContentInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class TaggedContentInfoTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new TaggedContentInfoTest()); + } + + public String getName() + { + return "TaggedContentInfoTest"; + } + + public void performTest() + throws Exception + { + TaggedContentInfo tci = new TaggedContentInfo( + new BodyPartID(10L), + new ContentInfo(PKCSObjectIdentifiers.pkcs_9_at_contentType, new DERUTF8String("Cats"))); + + byte[] b = tci.getEncoded(); + + TaggedContentInfo tciResp = TaggedContentInfo.getInstance(b); + + isEquals("bodyPartID", tci.getBodyPartID(), tciResp.getBodyPartID()); + isEquals("contentInfo", tci.getContentInfo(), tciResp.getContentInfo()); + + try + { + TaggedContentInfo.getInstance(new DERSequence()); + fail("Sequence must be 2"); + } + catch (Throwable t) + { + isEquals("Exception type", t.getClass(), IllegalArgumentException.class); + } + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedRequestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedRequestTest.java new file mode 100644 index 000000000..3e9eee1ad --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TaggedRequestTest.java @@ -0,0 +1,111 @@ +package com.fr.third.org.bouncycastle.asn1.test; + + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.cmc.BodyPartID; +import com.fr.third.org.bouncycastle.asn1.cmc.CertificationRequest; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedCertificationRequest; +import com.fr.third.org.bouncycastle.asn1.cmc.TaggedRequest; +import com.fr.third.org.bouncycastle.asn1.crmf.AttributeTypeAndValue; +import com.fr.third.org.bouncycastle.asn1.crmf.CertReqMsg; +import com.fr.third.org.bouncycastle.asn1.crmf.CertRequest; +import com.fr.third.org.bouncycastle.asn1.crmf.CertTemplate; +import com.fr.third.org.bouncycastle.asn1.crmf.Controls; +import com.fr.third.org.bouncycastle.asn1.crmf.POPOSigningKey; +import com.fr.third.org.bouncycastle.asn1.crmf.POPOSigningKeyInput; +import com.fr.third.org.bouncycastle.asn1.crmf.ProofOfPossession; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class TaggedRequestTest + extends SimpleTest +{ + public static void main(String[] args) + { + runTest(new TaggedRequestTest()); + } + + public String getName() + { + return "TaggedRequestTest"; + } + + private static byte[] req1 = Base64.decode( + "MIHoMIGTAgEAMC4xDjAMBgNVBAMTBVRlc3QyMQ8wDQYDVQQKEwZBbmFUb20xCzAJBgNVBAYTAlNF" + + "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALlEt31Tzt2MlcOljvacJgzQVhmlMoqAOgqJ9Pgd3Gux" + + "Z7/WcIlgW4QCB7WZT21O1YoghwBhPDMcNGrHei9kHQkCAwEAAaAAMA0GCSqGSIb3DQEBBQUAA0EA" + + "NDEI4ecNtJ3uHwGGlitNFq9WxcoZ0djbQJ5hABMotav6gtqlrwKXY2evaIrsNwkJtNdwwH18aQDU" + + "KCjOuBL38Q=="); + + + public void performTest() + throws Exception + { + { // TaggedCertificationRequest + TaggedRequest tr = new TaggedRequest( + new TaggedCertificationRequest( + new BodyPartID(10L), + CertificationRequest.getInstance(req1)) + ); + byte[] b = tr.getEncoded(); + TaggedRequest trResult = TaggedRequest.getInstance(b); + isEquals("Tag", tr.getTagNo(), trResult.getTagNo()); + isEquals("Is TCR tag", TaggedRequest.TCR, tr.getTagNo()); + isEquals("Value", tr.getValue(), trResult.getValue()); + } + + { // CertReqMsg + + POPOSigningKeyInput pski = new POPOSigningKeyInput( + new GeneralName(GeneralName.rfc822Name, "fish"), + new SubjectPublicKeyInfo(new AlgorithmIdentifier( + PKCSObjectIdentifiers.certBag, + new ASN1Integer(5L)), new ASN1Integer(4L) + )); + + AlgorithmIdentifier aid = new AlgorithmIdentifier(PKCSObjectIdentifiers.crlTypes, new ASN1Integer(1L)); + DERBitString dbi = new DERBitString(2); + + POPOSigningKey popoSigningKey = new POPOSigningKey(pski, aid, dbi); + ProofOfPossession proofOfPossession = new ProofOfPossession(new POPOSigningKey(pski, aid, dbi)); + + TaggedRequest tr = new TaggedRequest( + new CertReqMsg(new CertRequest( + new ASN1Integer(1L), + CertTemplate.getInstance(new DERSequence(new DERTaggedObject(0,new ASN1Integer(3L)))), + new Controls(new AttributeTypeAndValue(PKCSObjectIdentifiers.pkcs_9,new ASN1Integer(3)))), + proofOfPossession, + new AttributeTypeAndValue[0]) + ); + byte[] b = tr.getEncoded(); + TaggedRequest trResult = TaggedRequest.getInstance(b); + isEquals("Tag", tr.getTagNo(), trResult.getTagNo()); + isEquals("Is CRM tag", TaggedRequest.CRM, tr.getTagNo()); + isEquals("Value", tr.getValue(), trResult.getValue()); + } + + + { // ORM + TaggedRequest tr = TaggedRequest.getInstance( new DERTaggedObject(TaggedRequest.ORM, new DERSequence(new ASN1Encodable[]{ + new BodyPartID(1L), + PKCSObjectIdentifiers.data, + new DERSet(new ASN1Encodable[]{new ASN1Integer(5L)}) + }))); + byte[] b = tr.getEncoded(); + TaggedRequest trResult = TaggedRequest.getInstance(b); + isEquals("Tag", tr.getTagNo(), trResult.getTagNo()); + isEquals("Is ORM tag", TaggedRequest.ORM, tr.getTagNo()); + isEquals("Value", tr.getValue(), trResult.getValue()); + } + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TargetInformationTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TargetInformationTest.java new file mode 100644 index 000000000..7236a4b09 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TargetInformationTest.java @@ -0,0 +1,48 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.Target; +import com.fr.third.org.bouncycastle.asn1.x509.TargetInformation; +import com.fr.third.org.bouncycastle.asn1.x509.Targets; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class TargetInformationTest + extends SimpleTest +{ + + public String getName() + { + return "TargetInformation"; + } + + public void performTest() throws Exception + { + Target[] targets = new Target[2]; + Target targetName = new Target(Target.targetName, new GeneralName(GeneralName.dNSName, "www.test.com")); + Target targetGroup = new Target(Target.targetGroup, new GeneralName(GeneralName.directoryName, "o=Test, ou=Test")); + targets[0] = targetName; + targets[1] = targetGroup; + Targets targetss = new Targets(targets); + TargetInformation targetInformation1 = new TargetInformation(targetss); + // use an Target array + TargetInformation targetInformation2 = new TargetInformation(targets); + // targetInformation1 and targetInformation2 must have same + // encoding. + if (!targetInformation1.equals(targetInformation2)) + { + fail("targetInformation1 and targetInformation2 should have the same encoding."); + } + TargetInformation targetInformation3 = TargetInformation.getInstance(targetInformation1); + TargetInformation targetInformation4 = TargetInformation.getInstance(targetInformation2); + if (!targetInformation3.equals(targetInformation4)) + { + fail("targetInformation3 and targetInformation4 should have the same encoding."); + } + } + + public static void main(String[] args) + { + runTest(new TargetInformationTest()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TypeOfBiometricDataUnitTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TypeOfBiometricDataUnitTest.java new file mode 100644 index 000000000..b662514b0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/TypeOfBiometricDataUnitTest.java @@ -0,0 +1,144 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.x509.qualified.TypeOfBiometricData; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class TypeOfBiometricDataUnitTest + extends SimpleTest +{ + public String getName() + { + return "TypeOfBiometricData"; + } + + public void performTest() + throws Exception + { + // + // predefined + // + checkPredefinedType(TypeOfBiometricData.PICTURE); + + checkPredefinedType(TypeOfBiometricData.HANDWRITTEN_SIGNATURE); + + // + // non-predefined + // + ASN1ObjectIdentifier localType = new ASN1ObjectIdentifier("1.1"); + + TypeOfBiometricData type = new TypeOfBiometricData(localType); + + checkNonPredefined(type, localType); + + type = TypeOfBiometricData.getInstance(type); + + checkNonPredefined(type, localType); + + ASN1Primitive obj = type.toASN1Primitive(); + + type = TypeOfBiometricData.getInstance(obj); + + checkNonPredefined(type, localType); + + type = TypeOfBiometricData.getInstance(null); + + if (type != null) + { + fail("null getInstance() failed."); + } + + try + { + TypeOfBiometricData.getInstance(new Object()); + + fail("getInstance() failed to detect bad object."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + new TypeOfBiometricData(100); + + fail("constructor failed to detect bad predefined type."); + } + catch (IllegalArgumentException e) + { + // expected + } + + if (TypeOfBiometricData.PICTURE != 0) + { + fail("predefined picture should be 0"); + } + + if (TypeOfBiometricData.HANDWRITTEN_SIGNATURE != 1) + { + fail("predefined handwritten signature should be 1"); + } + } + + private void checkPredefinedType( + int predefinedType) + throws IOException + { + TypeOfBiometricData type = new TypeOfBiometricData(predefinedType); + + checkPredefined(type, predefinedType); + + type = TypeOfBiometricData.getInstance(type); + + checkPredefined(type, predefinedType); + + ASN1InputStream aIn = new ASN1InputStream(type.toASN1Primitive().getEncoded()); + + ASN1Primitive obj = aIn.readObject(); + + type = TypeOfBiometricData.getInstance(obj); + + checkPredefined(type, predefinedType); + } + + private void checkPredefined( + TypeOfBiometricData type, + int value) + { + if (!type.isPredefined()) + { + fail("predefined type expected but not found."); + } + + if (type.getPredefinedBiometricType() != value) + { + fail("predefined type does not match."); + } + } + + private void checkNonPredefined( + TypeOfBiometricData type, + ASN1ObjectIdentifier value) + { + if (type.isPredefined()) + { + fail("predefined type found when not expected."); + } + + if (!type.getBiometricDataOid().equals(value)) + { + fail("data oid does not match."); + } + } + + public static void main( + String[] args) + { + runTest(new TypeOfBiometricDataUnitTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/UTCTimeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/UTCTimeTest.java new file mode 100644 index 000000000..5738a30de --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/UTCTimeTest.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.text.SimpleDateFormat; +import java.util.SimpleTimeZone; + +import com.fr.third.org.bouncycastle.asn1.DERUTCTime; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * X.690 test example + */ +public class UTCTimeTest + extends SimpleTest +{ + String[] input = + { + "020122122220Z", + "020122122220-1000", + "020122122220+1000", + "020122122220+00", + "0201221222Z", + "0201221222-1000", + "0201221222+1000", + "0201221222+00", + "550122122220Z", + "5501221222Z" + }; + + String[] output = { + "20020122122220GMT+00:00", + "20020122122220GMT-10:00", + "20020122122220GMT+10:00", + "20020122122220GMT+00:00", + "20020122122200GMT+00:00", + "20020122122200GMT-10:00", + "20020122122200GMT+10:00", + "20020122122200GMT+00:00", + "19550122122220GMT+00:00", + "19550122122200GMT+00:00" + }; + + String[] zOutput1 = { + "20020122122220Z", + "20020122222220Z", + "20020122022220Z", + "20020122122220Z", + "20020122122200Z", + "20020122222200Z", + "20020122022200Z", + "20020122122200Z", + "19550122122220Z", + "19550122122200Z" + }; + + String[] zOutput2 = { + "20020122122220Z", + "20020122222220Z", + "20020122022220Z", + "20020122122220Z", + "20020122122200Z", + "20020122222200Z", + "20020122022200Z", + "20020122122200Z", + "19550122122220Z", + "19550122122200Z" + }; + + public String getName() + { + return "UTCTime"; + } + + public void performTest() + throws Exception + { + SimpleDateFormat yyyyF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); + SimpleDateFormat yyF = new SimpleDateFormat("yyyyMMddHHmmss'Z'"); + + yyyyF.setTimeZone(new SimpleTimeZone(0,"Z")); + yyF.setTimeZone(new SimpleTimeZone(0,"Z")); + + for (int i = 0; i != input.length; i++) + { + DERUTCTime t = new DERUTCTime(input[i]); + + if (!t.getAdjustedTime().equals(output[i])) + { + fail("failed conversion test " + i); + } + + if (!yyyyF.format(t.getAdjustedDate()).equals(zOutput1[i])) + { + fail("failed date conversion test " + i); + } + + if (!yyF.format(t.getDate()).equals(zOutput2[i])) + { + fail("failed date shortened conversion test " + i); + } + } + } + + public static void main( + String[] args) + { + runTest(new UTCTimeTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X500NameTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X500NameTest.java new file mode 100644 index 000000000..73e89c1cf --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X500NameTest.java @@ -0,0 +1,758 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1Set; +import com.fr.third.org.bouncycastle.asn1.ASN1String; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERIA5String; +import com.fr.third.org.bouncycastle.asn1.DERPrintableString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERUTF8String; +import com.fr.third.org.bouncycastle.asn1.x500.RDN; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.X500NameBuilder; +import com.fr.third.org.bouncycastle.asn1.x500.style.BCStrictStyle; +import com.fr.third.org.bouncycastle.asn1.x500.style.BCStyle; +import com.fr.third.org.bouncycastle.asn1.x500.style.IETFUtils; +import com.fr.third.org.bouncycastle.asn1.x509.X509DefaultEntryConverter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class X500NameTest + extends SimpleTest +{ + String[] subjects = + { + "C=AU,ST=Victoria,L=South Melbourne,O=Connect 4 Pty Ltd,OU=Webserver Team,CN=www2.connect4.com.au,E=webmaster@connect4.com.au", + "C=AU,ST=Victoria,L=South Melbourne,O=Connect 4 Pty Ltd,OU=Certificate Authority,CN=Connect 4 CA,E=webmaster@connect4.com.au", + "C=AU,ST=QLD,CN=SSLeay/rsa test cert", + "C=US,O=National Aeronautics and Space Administration,SERIALNUMBER=16+CN=Steve Schoch", + "E=cooke@issl.atl.hp.com,C=US,OU=Hewlett Packard Company (ISSL),CN=Paul A. Cooke", + "O=Sun Microsystems Inc,CN=store.sun.com", + "unstructuredAddress=192.168.1.33,unstructuredName=pixfirewall.ciscopix.com,CN=pixfirewall.ciscopix.com", + "CN=*.canal-plus.com,OU=Provided by TBS INTERNET http://www.tbs-certificats.com/,OU=\\ CANAL \\+,O=CANAL\\+DISTRIBUTION,L=issy les moulineaux,ST=Hauts de Seine,C=FR", + "O=Bouncy Castle,CN=www.bouncycastle.org\\ ", + "O=Bouncy Castle,CN=c:\\\\fred\\\\bob", + "C=0,O=1,OU=2,T=3,CN=4,SERIALNUMBER=5,STREET=6,SERIALNUMBER=7,L=8,ST=9,SURNAME=10,GIVENNAME=11,INITIALS=12," + + "GENERATION=13,UniqueIdentifier=14,BusinessCategory=15,PostalCode=16,DN=17,Pseudonym=18,PlaceOfBirth=19," + + "Gender=20,CountryOfCitizenship=21,CountryOfResidence=22,NameAtBirth=23,PostalAddress=24,2.5.4.54=25," + + "TelephoneNumber=26,Name=27,E=28,unstructuredName=29,unstructuredAddress=30,E=31,DC=32,UID=33" + + }; + + String[] hexSubjects = + { + "CN=\\20Test\\20X,O=\\20Test,C=GB", // input + "CN=\\ Test X,O=\\ Test,C=GB", // expected + "CN=\\20Test\\20X\\20,O=\\20Test,C=GB", // input + "CN=\\ Test X\\ ,O=\\ Test,C=GB" // expected + }; + + public String getName() + { + return "X500Name"; + } + + private static X500Name fromBytes(byte[] bytes) throws IOException + { + return X500Name.getInstance(ASN1Primitive.fromByteArray(bytes)); + } + + private ASN1Encodable createEntryValue(ASN1ObjectIdentifier oid, String value) + { + X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE); + + builder.addRDN(oid, value); + + X500Name name = builder.build(); + + ASN1Sequence seq = (ASN1Sequence)name.toASN1Primitive(); + ASN1Set set = ASN1Set.getInstance(seq.getObjectAt(0).toASN1Primitive()); + seq = (ASN1Sequence)set.getObjectAt(0); + + return seq.getObjectAt(1); + } + + private ASN1Encodable createEntryValueFromString(ASN1ObjectIdentifier oid, String value) + { + X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE); + + builder.addRDN(oid, value); + + X500Name name = new X500Name(builder.build().toString()); + + ASN1Sequence seq = (ASN1Sequence)name.toASN1Primitive(); + ASN1Set set = ASN1Set.getInstance(seq.getObjectAt(0).toASN1Primitive()); + seq = (ASN1Sequence)set.getObjectAt(0); + + return seq.getObjectAt(1); + } + + private void testEncodingPrintableString(ASN1ObjectIdentifier oid, String value) + { + ASN1Encodable converted = createEntryValue(oid, value); + if (!(converted instanceof DERPrintableString)) + { + fail("encoding for " + oid + " not printable string"); + } + } + + private void testEncodingIA5String(ASN1ObjectIdentifier oid, String value) + { + ASN1Encodable converted = createEntryValue(oid, value); + if (!(converted instanceof DERIA5String)) + { + fail("encoding for " + oid + " not IA5String"); + } + } + + private void testEncodingUTF8String(ASN1ObjectIdentifier oid, String value) + throws IOException + { + ASN1Encodable converted = createEntryValue(oid, value); + if (!(converted instanceof DERUTF8String)) + { + fail("encoding for " + oid + " not IA5String"); + } + if (!value.equals((DERUTF8String.getInstance(converted.toASN1Primitive().getEncoded()).getString()))) + { + fail("decoding not correct"); + } + } + + private void testEncodingGeneralizedTime(ASN1ObjectIdentifier oid, String value) + { + ASN1Encodable converted = createEntryValue(oid, value); + if (!(converted instanceof ASN1GeneralizedTime)) + { + fail("encoding for " + oid + " not GeneralizedTime"); + } + converted = createEntryValueFromString(oid, value); + if (!(converted instanceof ASN1GeneralizedTime)) + { + fail("encoding for " + oid + " not GeneralizedTime"); + } + } + + public void performTest() + throws Exception + { + ietfUtilsTest(); + + testEncodingPrintableString(BCStyle.C, "AU"); + testEncodingPrintableString(BCStyle.SERIALNUMBER, "123456"); + testEncodingPrintableString(BCStyle.DN_QUALIFIER, "123456"); + testEncodingIA5String(BCStyle.EmailAddress, "test@test.com"); + testEncodingIA5String(BCStyle.DC, "test"); + // correct encoding + testEncodingGeneralizedTime(BCStyle.DATE_OF_BIRTH, "#180F32303032303132323132323232305A"); + // compatibility encoding + testEncodingGeneralizedTime(BCStyle.DATE_OF_BIRTH, "20020122122220Z"); + testEncodingUTF8String(BCStyle.CN, "Mörsky"); + testEncodingUTF8String(BCStyle.ORGANIZATION_IDENTIFIER, "Mörsky"); + + // + // composite + // + X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE); + + builder.addRDN(BCStyle.C, "AU"); + builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle"); + builder.addRDN(BCStyle.L, "Melbourne"); + builder.addRDN(BCStyle.ST, "Victoria"); + builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org"); + + X500Name name1 = builder.build(); + + if (!name1.equals(name1)) + { + fail("Failed same object test"); + } + +// if (!name1.equals(name1, true)) +// { +// fail("Failed same object test - in Order"); +// } + + builder = new X500NameBuilder(BCStyle.INSTANCE); + + builder.addRDN(BCStyle.C, "AU"); + builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle"); + builder.addRDN(BCStyle.L, "Melbourne"); + builder.addRDN(BCStyle.ST, "Victoria"); + builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org"); + + X500Name name2 = builder.build(); + + if (!name1.equals(name2)) + { + fail("Failed same name test"); + } + +// if (!name1.equals(name2, true)) +// { +// fail("Failed same name test - in Order"); +// } + + if (name1.hashCode() != name2.hashCode()) + { + fail("Failed same name test - in Order"); + } + + X500NameBuilder builder1 = new X500NameBuilder(BCStyle.INSTANCE); + + builder.addRDN(BCStyle.C, "AU"); + builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle"); + builder.addRDN(BCStyle.L, "Melbourne"); + builder.addRDN(BCStyle.ST, "Victoria"); + builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org"); + + X500NameBuilder builder2 = new X500NameBuilder(BCStyle.INSTANCE); + + builder.addRDN(BCStyle.E, "feedback-crypto@bouncycastle.org"); + builder.addRDN(BCStyle.C, "AU"); + builder.addRDN(BCStyle.O, "The Legion of the Bouncy Castle"); + builder.addRDN(BCStyle.L, "Melbourne"); + builder.addRDN(BCStyle.ST, "Victoria"); + + name1 = builder1.build(); + name2 = builder2.build(); + + if (!name1.equals(name2)) + { + fail("Failed reverse name test"); + } + + if (name1.hashCode() != name2.hashCode()) + { + fail("Failed reverse name test hashCode"); + } + +// if (name1.equals(name2, true)) +// { +// fail("Failed reverse name test - in Order"); +// } +// +// if (!name1.equals(name2, false)) +// { +// fail("Failed reverse name test - in Order false"); +// } + +// Vector oids = name1.getOIDs(); +// if (!compareVectors(oids, ord1)) +// { +// fail("oid comparison test"); +// } + /* + Vector val1 = new Vector(); + + val1.addElement("AU"); + val1.addElement("The Legion of the Bouncy Castle"); + val1.addElement("Melbourne"); + val1.addElement("Victoria"); + val1.addElement("feedback-crypto@bouncycastle.org"); + + name1 = new X500Name(ord1, val1); + + Vector values = name1.getValues(); + if (!compareVectors(values, val1)) + { + fail("value comparison test"); + } + + ord2 = new Vector(); + + ord2.addElement(X500Name.ST); + ord2.addElement(X500Name.ST); + ord2.addElement(X500Name.L); + ord2.addElement(X500Name.O); + ord2.addElement(X500Name.C); + + name1 = new X500Name(ord1, attrs); + name2 = new X500Name(ord2, attrs); + + if (name1.equals(name2)) + { + fail("Failed different name test"); + } + + ord2 = new Vector(); + + ord2.addElement(X500Name.ST); + ord2.addElement(X500Name.L); + ord2.addElement(X500Name.O); + ord2.addElement(X500Name.C); + + name1 = new X500Name(ord1, attrs); + name2 = new X500Name(ord2, attrs); + + if (name1.equals(name2)) + { + fail("Failed subset name test"); + } + + compositeTest(); + */ + /* + // + // getValues test + // + Vector v1 = name1.getValues(X500Name.O); + + if (v1.size() != 1 || !v1.elementAt(0).equals("The Legion of the Bouncy Castle")) + { + fail("O test failed"); + } + + Vector v2 = name1.getValues(X500Name.L); + + if (v2.size() != 1 || !v2.elementAt(0).equals("Melbourne")) + { + fail("L test failed"); + } + */ + // + // general subjects test + // + for (int i = 0; i != subjects.length; i++) + { + X500Name name = new X500Name(subjects[i]); + name = X500Name.getInstance(ASN1Primitive.fromByteArray(name.getEncoded())); + if (!name.toString().equals(subjects[i])) + { + fail("failed regeneration test " + i + " got: " + name.toString() + " expected " + subjects[i]); + } + } + + for (int i = 0; i < hexSubjects.length; i += 2) + { + X500Name name = new X500Name(hexSubjects[i]); + name = X500Name.getInstance(ASN1Primitive.fromByteArray(name.getEncoded())); + if (!name.toString().equals(hexSubjects[i + 1])) + { + fail("failed hex regeneration test " + i + " got: " + name.toString() + " expected " + subjects[i]); + } + } + + // + // sort test + // + X500Name unsorted = new X500Name("SERIALNUMBER=BBB + CN=AA"); + + if (!fromBytes(unsorted.getEncoded()).toString().equals("CN=AA+SERIALNUMBER=BBB")) + { + fail("failed sort test 1"); + } + + unsorted = new X500Name("CN=AA + SERIALNUMBER=BBB"); + + if (!fromBytes(unsorted.getEncoded()).toString().equals("CN=AA+SERIALNUMBER=BBB")) + { + fail("failed sort test 2"); + } + + unsorted = new X500Name("SERIALNUMBER=B + CN=AA"); + + if (!fromBytes(unsorted.getEncoded()).toString().equals("SERIALNUMBER=B+CN=AA")) + { + fail("failed sort test 3"); + } + + unsorted = new X500Name("CN=AA + SERIALNUMBER=B"); + + if (!fromBytes(unsorted.getEncoded()).toString().equals("SERIALNUMBER=B+CN=AA")) + { + fail("failed sort test 4"); + } + + // + // equality tests + // + equalityTest(new X500Name("CN=The Legion"), new X500Name("CN=The Legion")); + equalityTest(new X500Name("CN= The Legion"), new X500Name("CN=The Legion")); + equalityTest(new X500Name("CN=The Legion "), new X500Name("CN=The Legion")); + equalityTest(new X500Name("CN= The Legion "), new X500Name("CN=The Legion")); + equalityTest(new X500Name("CN= the legion "), new X500Name("CN=The Legion")); + + equalityTest(new X500Name("CN= the legion+C=AU, O=Legion "), new X500Name("CN=The Legion+C=AU, O=Legion")); + // # test + + X500Name n1 = new X500Name("SERIALNUMBER=8,O=ABC,CN=ABC Class 3 CA,C=LT"); + X500Name n2 = new X500Name("2.5.4.5=8,O=ABC,CN=ABC Class 3 CA,C=LT"); + X500Name n3 = new X500Name("2.5.4.5=#130138,O=ABC,CN=ABC Class 3 CA,C=LT"); + + equalityTest(n1, n2); + equalityTest(n2, n3); + equalityTest(n3, n1); + + n1 = new X500Name("2.5.4.5=#130138,CN=SSC Class 3 CA,O=UAB Skaitmeninio sertifikavimo centras,C=LT"); + n2 = new X500Name("SERIALNUMBER=#130138,CN=SSC Class 3 CA,O=UAB Skaitmeninio sertifikavimo centras,C=LT"); + n3 = X500Name.getInstance(ASN1Primitive.fromByteArray(Hex.decode("3063310b3009060355040613024c54312f302d060355040a1326" + + "55414220536b6169746d656e696e696f20736572746966696b6176696d6f2063656e74726173311730150603550403130e53534320436c6173732033204341310a30080603550405130138"))); + + equalityTest(n1, n2); + equalityTest(n2, n3); + equalityTest(n3, n1); + + n1 = new X500Name("SERIALNUMBER=8,O=XX,CN=ABC Class 3 CA,C=LT"); + n2 = new X500Name("2.5.4.5=8,O=,CN=ABC Class 3 CA,C=LT"); + +// if (n1.equals(n2)) +// { +// fail("empty inequality check failed"); +// } + + n1 = new X500Name("SERIALNUMBER=8,O=,CN=ABC Class 3 CA,C=LT"); + n2 = new X500Name("2.5.4.5=8,O=,CN=ABC Class 3 CA,C=LT"); + + equalityTest(n1, n2); + + equalityTest(X500Name.getInstance(BCStrictStyle.INSTANCE, n1), X500Name.getInstance(BCStrictStyle.INSTANCE, n2)); + + n2 = new X500Name("C=LT,2.5.4.5=8,O=,CN=ABC Class 3 CA"); + + equalityTest(n1, n2); + + if (X500Name.getInstance(BCStrictStyle.INSTANCE, n1).equals(X500Name.getInstance(BCStrictStyle.INSTANCE, n2))) + { + fail("strict comparison failed"); + } + + // + // inequality to sequences + // + name1 = new X500Name("CN=The Legion"); + + if (name1.equals(new DERSequence())) + { + fail("inequality test with sequence"); + } + + if (name1.equals(new DERSequence(new DERSet()))) + { + fail("inequality test with sequence and set"); + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1ObjectIdentifier("1.1")); + v.add(new ASN1ObjectIdentifier("1.1")); + if (name1.equals(new DERSequence(new DERSet(new DERSet(v))))) + { + fail("inequality test with sequence and bad set"); + } + + if (name1.equals(new DERSequence(new DERSet(new DERSet(v))))) + { + fail("inequality test with sequence and bad set"); + } + + if (name1.equals(new DERSequence(new DERSet(new DERSequence())))) + { + fail("inequality test with sequence and short sequence"); + } + + if (name1.equals(new DERSequence(new DERSet(new DERSequence())))) + { + fail("inequality test with sequence and short sequence"); + } + + v = new ASN1EncodableVector(); + + v.add(new ASN1ObjectIdentifier("1.1")); + v.add(new DERSequence()); + + if (name1.equals(new DERSequence(new DERSet(new DERSequence(v))))) + { + fail("inequality test with sequence and bad sequence"); + } + + if (name1.equals(null)) + { + fail("inequality test with null"); + } + +// if (name1.equals(null, true)) +// { +// fail("inequality test with null"); +// } + + // + // this is contrived but it checks sorting of sets with equal elements + // + unsorted = new X500Name("CN=AA + CN=AA + CN=AA"); + + ASN1ObjectIdentifier[] types = unsorted.getAttributeTypes(); + if (types.length != 3 || !types[0].equals(BCStyle.CN) || !types[1].equals(BCStyle.CN) || !types[2].equals(BCStyle.CN)) + { + fail("types not matched correctly"); + } + + // general type test + X500Name nested = new X500Name("CN=AA + CN=AA, C=AU"); + + types = nested.getAttributeTypes(); + if (types.length != 3 || !types[0].equals(BCStyle.CN) || !types[1].equals(BCStyle.CN) || !types[2].equals(BCStyle.C)) + { + fail("nested types not matched correctly"); + } + // + // tagging test - only works if CHOICE implemented + // + ASN1TaggedObject tag = new DERTaggedObject(false, 1, new X500Name("CN=AA")); + + if (!tag.isExplicit()) + { + fail("failed to explicitly tag CHOICE object"); + } + + X500Name name = X500Name.getInstance(tag, false); + + if (!name.equals(new X500Name("CN=AA"))) + { + fail("failed to recover tagged name"); + } + + DERUTF8String testString = new DERUTF8String("The Legion of the Bouncy Castle"); + byte[] encodedBytes = testString.getEncoded(); + byte[] hexEncodedBytes = Hex.encode(encodedBytes); + String hexEncodedString = "#" + new String(hexEncodedBytes); + + DERUTF8String converted = (DERUTF8String) + new X509DefaultEntryConverter().getConvertedValue( + BCStyle.L , hexEncodedString); + + if (!converted.equals(testString)) + { + fail("failed X509DefaultEntryConverter test"); + } + + // + // try escaped. + // + converted = (DERUTF8String) + new X509DefaultEntryConverter().getConvertedValue( + BCStyle.L , "\\" + hexEncodedString); + + if (!converted.equals(new DERUTF8String(hexEncodedString))) + { + fail("failed X509DefaultEntryConverter test got " + converted + " expected: " + hexEncodedString); + } + + // + // try a weird value + // + X500Name n = new X500Name("CN=\\#nothex#string"); + + if (!n.toString().equals("CN=\\#nothex#string")) + { + fail("# string not properly escaped."); + } + + RDN[] vls = n.getRDNs(BCStyle.CN); + if (vls.length != 1 || !getValue(vls[0]).equals("#nothex#string")) + { + fail("escaped # not reduced properly"); + } + + types = n.getAttributeTypes(); + if (types.length != 1 || !types[0].equals(BCStyle.CN)) + { + fail("type not matched correctly"); + } + + n = new X500Name("CN=\"a+b\""); + + vls = n.getRDNs(BCStyle.CN); + if (vls.length != 1 || !getValue(vls[0]).equals("a+b")) + { + fail("escaped + not reduced properly"); + } + + n = new X500Name("CN=a\\+b"); + + vls = n.getRDNs(BCStyle.CN); + if (vls.length != 1 || !getValue(vls[0]).equals("a+b")) + { + fail("escaped + not reduced properly"); + } + + if (!n.toString().equals("CN=a\\+b")) + { + fail("+ in string not properly escaped."); + } + + n = new X500Name("CN=a\\=b"); + + vls = n.getRDNs(BCStyle.CN); + if (vls.length != 1 || !getValue(vls[0]).equals("a=b")) + { + fail("escaped = not reduced properly"); + } + + if (!n.toString().equals("CN=a\\=b")) + { + fail("= in string not properly escaped."); + } + + n = new X500Name("TELEPHONENUMBER=\"+61999999999\""); + + vls = n.getRDNs(BCStyle.TELEPHONE_NUMBER); + if (vls.length != 1 || !getValue(vls[0]).equals("+61999999999")) + { + fail("telephonenumber escaped + not reduced properly"); + } + + n = new X500Name("TELEPHONENUMBER=\\+61999999999"); + + vls = n.getRDNs(BCStyle.TELEPHONE_NUMBER); + if (vls.length != 1 || !getValue(vls[0]).equals("+61999999999")) + { + fail("telephonenumber escaped + not reduced properly"); + } + + // test query methods + if (!"E".equals(BCStyle.INSTANCE.oidToDisplayName(BCStyle.EmailAddress))) + { + fail("display name for E incorrect"); + } + + String[] aliases = BCStyle.INSTANCE.oidToAttrNames(BCStyle.EmailAddress); + if (aliases.length != 2) + { + fail("no aliases found"); + } + if (!("e".equals(aliases[0]) || "e".equals(aliases[1]))) + { + fail("first alias name for E incorrect"); + } + if (!("emailaddress".equals(aliases[0]) || "emailaddress".equals(aliases[1]))) + { + fail("second alias name for E incorrect"); + } + + if (BCStyle.INSTANCE.oidToDisplayName(new ASN1ObjectIdentifier("1.2.1")) != null) + { + fail("unknown oid matched!"); + } + + if (BCStyle.INSTANCE.oidToAttrNames(new ASN1ObjectIdentifier("1.2.1")).length != 0) + { + fail("unknown oid matched aliases!"); + } + + if (!new X500Name("CN=\" CA1 - CP.04.03\", OU=Testing, OU=Dod, O=U.S. Government, C=US") + .equals(new X500Name("CN=\"ca1 - CP.04.03 \", OU=Testing, OU=Dod, O=U.S. Government, C=US"))) + { + fail("padded equality test failed"); + } + } + + private String getValue(RDN vl) + { + return ((ASN1String)vl.getFirst().getValue()).getString(); + } + + private void ietfUtilsTest() + throws Exception + { + IETFUtils.valueToString(new DERUTF8String(" ")); + } + + /* + private boolean compareVectors(Vector a, Vector b) // for compatibility with early JDKs + { + if (a.size() != b.size()) + { + return false; + } + + for (int i = 0; i != a.size(); i++) + { + if (!a.elementAt(i).equals(b.elementAt(i))) + { + return false; + } + } + + return true; + } + + private void compositeTest() + throws IOException + { + // + // composite test + // + byte[] enc = Hex.decode("305e310b300906035504061302415531283026060355040a0c1f546865204c6567696f6e206f662074686520426f756e637920436173746c653125301006035504070c094d656c626f75726e653011060355040b0c0a4173636f742056616c65"); + ASN1InputStream aIn = new ASN1InputStream(new ByteArrayInputStream(enc)); + + X500Name n = X500Name.getInstance(aIn.readObject()); + + if (!n.toString().equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne+OU=Ascot Vale")) + { + fail("Failed composite to string test got: " + n.toString()); + } + + if (!n.toString(true, X500Name.DefaultSymbols).equals("L=Melbourne+OU=Ascot Vale,O=The Legion of the Bouncy Castle,C=AU")) + { + fail("Failed composite to string test got: " + n.toString(true, X500Name.DefaultSymbols)); + } + + n = new X500Name(true, "L=Melbourne+OU=Ascot Vale,O=The Legion of the Bouncy Castle,C=AU"); + if (!n.toString().equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne+OU=Ascot Vale")) + { + fail("Failed composite to string reversal test got: " + n.toString()); + } + + n = new X500Name("C=AU, O=The Legion of the Bouncy Castle, L=Melbourne + OU=Ascot Vale"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ASN1OutputStream aOut = new ASN1OutputStream(bOut); + + aOut.writeObject(n); + + byte[] enc2 = bOut.toByteArray(); + + if (!Arrays.areEqual(enc, enc2)) + { + fail("Failed composite string to encoding test"); + } + + // + // dud name test - handle empty DN without barfing. + // + n = new X500Name("C=CH,O=,OU=dummy,CN=mail@dummy.com"); + + n = X500Name.getInstance(ASN1Object.fromByteArray(n.getEncoded())); + } + */ + private void equalityTest(X500Name name1, X500Name name2) + { + if (!name1.equals(name2)) + { + fail("equality test failed for " + name1 + " : " + name2); + } + + if (name1.hashCode() != name2.hashCode()) + { + fail("hashCodeTest test failed for " + name1 + " : " + name2); + } + } + + + public static void main( + String[] args) + { + runTest(new X500NameTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X509ExtensionsTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X509ExtensionsTest.java new file mode 100644 index 000000000..47338a352 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X509ExtensionsTest.java @@ -0,0 +1,105 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.X509Extensions; +import com.fr.third.org.bouncycastle.asn1.x509.X509ExtensionsGenerator; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class X509ExtensionsTest + extends SimpleTest +{ + private static final ASN1ObjectIdentifier OID_2 = new ASN1ObjectIdentifier("1.2.2"); + private static final ASN1ObjectIdentifier OID_3 = new ASN1ObjectIdentifier("1.2.3"); + private static final ASN1ObjectIdentifier OID_1 = new ASN1ObjectIdentifier("1.2.1"); + + public String getName() + { + return "X509Extensions"; + } + + public void performTest() throws Exception + { + X509ExtensionsGenerator gen = new X509ExtensionsGenerator(); + + gen.addExtension(OID_1, true, new byte[20]); + gen.addExtension(OID_2, true, new byte[20]); + + X509Extensions ext1 = gen.generate(); + X509Extensions ext2 = gen.generate(); + + if (!ext1.equals(ext2)) + { + fail("equals test failed"); + } + + gen.reset(); + + gen.addExtension(OID_2, true, new byte[20]); + gen.addExtension(OID_1, true, new byte[20]); + + ext2 = gen.generate(); + + if (ext1.equals(ext2)) + { + fail("inequality test failed"); + } + + if (!ext1.equivalent(ext2)) + { + fail("equivalence true failed"); + } + + gen.reset(); + + gen.addExtension(OID_1, true, new byte[22]); + gen.addExtension(OID_2, true, new byte[20]); + + ext2 = gen.generate(); + + if (ext1.equals(ext2)) + { + fail("inequality 1 failed"); + } + + if (ext1.equivalent(ext2)) + { + fail("non-equivalence 1 failed"); + } + + gen.reset(); + + gen.addExtension(OID_3, true, new byte[20]); + gen.addExtension(OID_2, true, new byte[20]); + + ext2 = gen.generate(); + + if (ext1.equals(ext2)) + { + fail("inequality 2 failed"); + } + + if (ext1.equivalent(ext2)) + { + fail("non-equivalence 2 failed"); + } + + try + { + gen.addExtension(OID_2, true, new byte[20]); + fail("repeated oid"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("extension 1.2.2 already added")) + { + fail("wrong exception on repeated oid: " + e.getMessage()); + } + } + } + + public static void main( + String[] args) + { + runTest(new X509ExtensionsTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X509NameTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X509NameTest.java new file mode 100644 index 000000000..8197c9980 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X509NameTest.java @@ -0,0 +1,676 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1GeneralizedTime; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1OutputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1Set; +import com.fr.third.org.bouncycastle.asn1.DERIA5String; +import com.fr.third.org.bouncycastle.asn1.DERPrintableString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.DERUTF8String; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.X500NameBuilder; +import com.fr.third.org.bouncycastle.asn1.x500.style.BCStyle; +import com.fr.third.org.bouncycastle.asn1.x509.X509DefaultEntryConverter; +import com.fr.third.org.bouncycastle.asn1.x509.X509Name; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class X509NameTest + extends SimpleTest +{ + String[] subjects = + { + "C=AU,ST=Victoria,L=South Melbourne,O=Connect 4 Pty Ltd,OU=Webserver Team,CN=www2.connect4.com.au,E=webmaster@connect4.com.au", + "C=AU,ST=Victoria,L=South Melbourne,O=Connect 4 Pty Ltd,OU=Certificate Authority,CN=Connect 4 CA,E=webmaster@connect4.com.au", + "C=AU,ST=QLD,CN=SSLeay/rsa test cert", + "C=US,O=National Aeronautics and Space Administration,SERIALNUMBER=16+CN=Steve Schoch", + "E=cooke@issl.atl.hp.com,C=US,OU=Hewlett Packard Company (ISSL),CN=Paul A. Cooke", + "O=Sun Microsystems Inc,CN=store.sun.com", + "unstructuredAddress=192.168.1.33,unstructuredName=pixfirewall.ciscopix.com,CN=pixfirewall.ciscopix.com", + "CN=*.canal-plus.com,OU=Provided by TBS INTERNET http://www.tbs-certificats.com/,OU=\\ CANAL \\+,O=CANAL\\+DISTRIBUTION,L=issy les moulineaux,ST=Hauts de Seine,C=FR", + "O=Bouncy Castle,CN=www.bouncycastle.org\\ ", + "O=Bouncy Castle,CN=c:\\\\fred\\\\bob" + }; + + public String getName() + { + return "X509Name"; + } + + private static X509Name fromBytes(byte[] bytes) throws IOException + { + return X509Name.getInstance(ASN1Primitive.fromByteArray(bytes)); + } + + private ASN1Encodable createEntryValue(ASN1ObjectIdentifier oid, String value) + { + Hashtable attrs = new Hashtable(); + + attrs.put(oid, value); + + Vector order = new Vector(); + + order.addElement(oid); + + X509Name name = new X509Name(order, attrs); + + ASN1Sequence seq = (ASN1Sequence)name.toASN1Primitive(); + ASN1Set set = (ASN1Set)seq.getObjectAt(0); + seq = (ASN1Sequence)set.getObjectAt(0); + + return seq.getObjectAt(1); + } + + private ASN1Encodable createEntryValueFromString(ASN1ObjectIdentifier oid, String value) + { + Hashtable attrs = new Hashtable(); + + attrs.put(oid, value); + + Vector order = new Vector(); + + order.addElement(oid); + + X509Name name = new X509Name(new X509Name(order, attrs).toString()); + + ASN1Sequence seq = (ASN1Sequence)name.toASN1Primitive(); + ASN1Set set = (ASN1Set)seq.getObjectAt(0); + seq = (ASN1Sequence)set.getObjectAt(0); + + return seq.getObjectAt(1); + } + + private void testEncodingPrintableString(ASN1ObjectIdentifier oid, String value) + { + ASN1Encodable converted = createEntryValue(oid, value); + if (!(converted instanceof DERPrintableString)) + { + fail("encoding for " + oid + " not printable string"); + } + } + + private void testEncodingIA5String(ASN1ObjectIdentifier oid, String value) + { + ASN1Encodable converted = createEntryValue(oid, value); + if (!(converted instanceof DERIA5String)) + { + fail("encoding for " + oid + " not IA5String"); + } + } + + + private void testEncodingUTF8String(ASN1ObjectIdentifier oid, String value) + throws IOException + { + ASN1Encodable converted = createEntryValue(oid, value); + if (!(converted instanceof DERUTF8String)) + { + fail("encoding for " + oid + " not IA5String"); + } + if (!value.equals((DERUTF8String.getInstance(converted.toASN1Primitive().getEncoded()).getString()))) + { + fail("decoding not correct"); + } + } + + private void testEncodingGeneralizedTime(ASN1ObjectIdentifier oid, String value) + { + ASN1Encodable converted = createEntryValue(oid, value); + if (!(converted instanceof ASN1GeneralizedTime)) + { + fail("encoding for " + oid + " not GeneralizedTime"); + } + converted = createEntryValueFromString(oid, value); + if (!(converted instanceof ASN1GeneralizedTime)) + { + fail("encoding for " + oid + " not GeneralizedTime"); + } + } + + public void performTest() + throws Exception + { + testEncodingPrintableString(X509Name.C, "AU"); + testEncodingPrintableString(X509Name.SERIALNUMBER, "123456"); + testEncodingPrintableString(X509Name.DN_QUALIFIER, "123456"); + testEncodingIA5String(X509Name.EmailAddress, "test@test.com"); + testEncodingIA5String(X509Name.DC, "test"); + // correct encoding + testEncodingGeneralizedTime(X509Name.DATE_OF_BIRTH, "#180F32303032303132323132323232305A"); + // compatibility encoding + testEncodingGeneralizedTime(X509Name.DATE_OF_BIRTH, "20020122122220Z"); + testEncodingUTF8String(X509Name.CN, "Mörsky"); + // + // composite + // + Hashtable attrs = new Hashtable(); + + attrs.put(X509Name.C, "AU"); + attrs.put(X509Name.O, "The Legion of the Bouncy Castle"); + attrs.put(X509Name.L, "Melbourne"); + attrs.put(X509Name.ST, "Victoria"); + attrs.put(X509Name.E, "feedback-crypto@bouncycastle.org"); + + Vector order = new Vector(); + + order.addElement(X509Name.C); + order.addElement(X509Name.O); + order.addElement(X509Name.L); + order.addElement(X509Name.ST); + order.addElement(X509Name.E); + + X509Name name1 = new X509Name(order, attrs); + + if (!name1.equals(name1)) + { + fail("Failed same object test"); + } + + if (!name1.equals(name1, true)) + { + fail("Failed same object test - in Order"); + } + + X509Name name2 = new X509Name(order, attrs); + + if (!name1.equals(name2)) + { + fail("Failed same name test"); + } + + if (!name1.equals(name2, true)) + { + fail("Failed same name test - in Order"); + } + + if (name1.hashCode() != name2.hashCode()) + { + fail("Failed same name test - in Order"); + } + + Vector ord1 = new Vector(); + + ord1.addElement(X509Name.C); + ord1.addElement(X509Name.O); + ord1.addElement(X509Name.L); + ord1.addElement(X509Name.ST); + ord1.addElement(X509Name.E); + + Vector ord2 = new Vector(); + + ord2.addElement(X509Name.E); + ord2.addElement(X509Name.ST); + ord2.addElement(X509Name.L); + ord2.addElement(X509Name.O); + ord2.addElement(X509Name.C); + + name1 = new X509Name(ord1, attrs); + name2 = new X509Name(ord2, attrs); + + if (!name1.equals(name2)) + { + fail("Failed reverse name test"); + } + + if (name1.hashCode() != name2.hashCode()) + { + fail("Failed reverse name test hashCode"); + } + + if (name1.equals(name2, true)) + { + fail("Failed reverse name test - in Order"); + } + + if (!name1.equals(name2, false)) + { + fail("Failed reverse name test - in Order false"); + } + + Vector oids = name1.getOIDs(); + if (!compareVectors(oids, ord1)) + { + fail("oid comparison test"); + } + + Vector val1 = new Vector(); + + val1.addElement("AU"); + val1.addElement("The Legion of the Bouncy Castle"); + val1.addElement("Melbourne"); + val1.addElement("Victoria"); + val1.addElement("feedback-crypto@bouncycastle.org"); + + name1 = new X509Name(ord1, val1); + + Vector values = name1.getValues(); + if (!compareVectors(values, val1)) + { + fail("value comparison test"); + } + + ord2 = new Vector(); + + ord2.addElement(X509Name.ST); + ord2.addElement(X509Name.ST); + ord2.addElement(X509Name.L); + ord2.addElement(X509Name.O); + ord2.addElement(X509Name.C); + + name1 = new X509Name(ord1, attrs); + name2 = new X509Name(ord2, attrs); + + if (name1.equals(name2)) + { + fail("Failed different name test"); + } + + ord2 = new Vector(); + + ord2.addElement(X509Name.ST); + ord2.addElement(X509Name.L); + ord2.addElement(X509Name.O); + ord2.addElement(X509Name.C); + + name1 = new X509Name(ord1, attrs); + name2 = new X509Name(ord2, attrs); + + if (name1.equals(name2)) + { + fail("Failed subset name test"); + } + + compositeTest(); + + ByteArrayOutputStream bOut; + ASN1OutputStream aOut; + ASN1InputStream aIn; + + // + // getValues test + // + Vector v1 = name1.getValues(X509Name.O); + + if (v1.size() != 1 || !v1.elementAt(0).equals("The Legion of the Bouncy Castle")) + { + fail("O test failed"); + } + + Vector v2 = name1.getValues(X509Name.L); + + if (v2.size() != 1 || !v2.elementAt(0).equals("Melbourne")) + { + fail("L test failed"); + } + + // + // general subjects test + // + for (int i = 0; i != subjects.length; i++) + { + X509Name name = new X509Name(subjects[i]); + name = X509Name.getInstance(ASN1Primitive.fromByteArray(name.getEncoded())); + if (!name.toString().equals(subjects[i])) + { + fail("failed regeneration test " + i + " got " + name.toString()); + } + } + + // + // sort test + // + X509Name unsorted = new X509Name("SERIALNUMBER=BBB + CN=AA"); + + if (!fromBytes(unsorted.getEncoded()).toString().equals("CN=AA+SERIALNUMBER=BBB")) + { + fail("failed sort test 1"); + } + + unsorted = new X509Name("CN=AA + SERIALNUMBER=BBB"); + + if (!fromBytes(unsorted.getEncoded()).toString().equals("CN=AA+SERIALNUMBER=BBB")) + { + fail("failed sort test 2"); + } + + unsorted = new X509Name("SERIALNUMBER=B + CN=AA"); + + if (!fromBytes(unsorted.getEncoded()).toString().equals("SERIALNUMBER=B+CN=AA")) + { + fail("failed sort test 3"); + } + + unsorted = new X509Name("CN=AA + SERIALNUMBER=B"); + + if (!fromBytes(unsorted.getEncoded()).toString().equals("SERIALNUMBER=B+CN=AA")) + { + fail("failed sort test 4"); + } + + // + // equality tests + // + equalityTest(new X509Name("CN=The Legion"), new X509Name("CN=The Legion")); + equalityTest(new X509Name("CN= The Legion"), new X509Name("CN=The Legion")); + equalityTest(new X509Name("CN=The Legion "), new X509Name("CN=The Legion")); + equalityTest(new X509Name("CN= The Legion "), new X509Name("CN=The Legion")); + equalityTest(new X509Name("CN= the legion "), new X509Name("CN=The Legion")); + + // # test + + X509Name n1 = new X509Name("SERIALNUMBER=8,O=ABC,CN=ABC Class 3 CA,C=LT"); + X509Name n2 = new X509Name("2.5.4.5=8,O=ABC,CN=ABC Class 3 CA,C=LT"); + X509Name n3 = new X509Name("2.5.4.5=#130138,O=ABC,CN=ABC Class 3 CA,C=LT"); + + equalityTest(n1, n2); + equalityTest(n2, n3); + equalityTest(n3, n1); + + n1 = new X509Name(true, "2.5.4.5=#130138,CN=SSC Class 3 CA,O=UAB Skaitmeninio sertifikavimo centras,C=LT"); + n2 = new X509Name(true, "SERIALNUMBER=#130138,CN=SSC Class 3 CA,O=UAB Skaitmeninio sertifikavimo centras,C=LT"); + n3 = X509Name.getInstance(ASN1Primitive.fromByteArray(Hex.decode("3063310b3009060355040613024c54312f302d060355040a1326" + + "55414220536b6169746d656e696e696f20736572746966696b6176696d6f2063656e74726173311730150603550403130e53534320436c6173732033204341310a30080603550405130138"))); + + equalityTest(n1, n2); + equalityTest(n2, n3); + equalityTest(n3, n1); + + n1 = new X509Name("SERIALNUMBER=8,O=XX,CN=ABC Class 3 CA,C=LT"); + n2 = new X509Name("2.5.4.5=8,O=,CN=ABC Class 3 CA,C=LT"); + + if (n1.equals(n2)) + { + fail("empty inequality check failed"); + } + + n1 = new X509Name("SERIALNUMBER=8,O=,CN=ABC Class 3 CA,C=LT"); + n2 = new X509Name("2.5.4.5=8,O=,CN=ABC Class 3 CA,C=LT"); + + equalityTest(n1, n2); + + // + // inequality to sequences + // + name1 = new X509Name("CN=The Legion"); + + if (name1.equals(new DERSequence())) + { + fail("inequality test with sequence"); + } + + if (name1.equals(new DERSequence(new DERSet()))) + { + fail("inequality test with sequence and set"); + } + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(new ASN1ObjectIdentifier("1.1")); + v.add(new ASN1ObjectIdentifier("1.1")); + if (name1.equals(new DERSequence(new DERSet(new DERSet(v))))) + { + fail("inequality test with sequence and bad set"); + } + + if (name1.equals(new DERSequence(new DERSet(new DERSet(v))), true)) + { + fail("inequality test with sequence and bad set"); + } + + if (name1.equals(new DERSequence(new DERSet(new DERSequence())))) + { + fail("inequality test with sequence and short sequence"); + } + + if (name1.equals(new DERSequence(new DERSet(new DERSequence())), true)) + { + fail("inequality test with sequence and short sequence"); + } + + v = new ASN1EncodableVector(); + + v.add(new ASN1ObjectIdentifier("1.1")); + v.add(new DERSequence()); + + if (name1.equals(new DERSequence(new DERSet(new DERSequence(v))))) + { + fail("inequality test with sequence and bad sequence"); + } + + if (name1.equals(null)) + { + fail("inequality test with null"); + } + + if (name1.equals(null, true)) + { + fail("inequality test with null"); + } + + // + // this is contrived but it checks sorting of sets with equal elements + // + unsorted = new X509Name("CN=AA + CN=AA + CN=AA"); + + // + // tagging test - only works if CHOICE implemented + // + /* + ASN1TaggedObject tag = new DERTaggedObject(false, 1, new X509Name("CN=AA")); + + if (!tag.isExplicit()) + { + fail("failed to explicitly tag CHOICE object"); + } + + X509Name name = X509Name.getInstance(tag, false); + + if (!name.equals(new X509Name("CN=AA"))) + { + fail("failed to recover tagged name"); + } + */ + + DERUTF8String testString = new DERUTF8String("The Legion of the Bouncy Castle"); + byte[] encodedBytes = testString.getEncoded(); + byte[] hexEncodedBytes = Hex.encode(encodedBytes); + String hexEncodedString = "#" + new String(hexEncodedBytes); + + DERUTF8String converted = (DERUTF8String) + new X509DefaultEntryConverter().getConvertedValue( + X509Name.L , hexEncodedString); + + if (!converted.equals(testString)) + { + fail("failed X509DefaultEntryConverter test"); + } + + // + // try escaped. + // + converted = (DERUTF8String) + new X509DefaultEntryConverter().getConvertedValue( + X509Name.L , "\\" + hexEncodedString); + + if (!converted.equals(new DERUTF8String(hexEncodedString))) + { + fail("failed X509DefaultEntryConverter test got " + converted + " expected: " + hexEncodedString); + } + + // + // try a weird value + // + X509Name n = new X509Name("CN=\\#nothex#string"); + + if (!n.toString().equals("CN=\\#nothex#string")) + { + fail("# string not properly escaped."); + } + + Vector vls = n.getValues(X509Name.CN); + if (vls.size() != 1 || !vls.elementAt(0).equals("#nothex#string")) + { + fail("escaped # not reduced properly"); + } + + n = new X509Name("CN=\"a+b\""); + + vls = n.getValues(X509Name.CN); + if (vls.size() != 1 || !vls.elementAt(0).equals("a+b")) + { + fail("escaped + not reduced properly"); + } + + n = new X509Name("CN=a\\+b"); + + vls = n.getValues(X509Name.CN); + if (vls.size() != 1 || !vls.elementAt(0).equals("a+b")) + { + fail("escaped + not reduced properly"); + } + + if (!n.toString().equals("CN=a\\+b")) + { + fail("+ in string not properly escaped."); + } + + n = new X509Name("CN=a\\=b"); + + vls = n.getValues(X509Name.CN); + if (vls.size() != 1 || !vls.elementAt(0).equals("a=b")) + { + fail("escaped = not reduced properly"); + } + + if (!n.toString().equals("CN=a\\=b")) + { + fail("= in string not properly escaped."); + } + + n = new X509Name("TELEPHONENUMBER=\"+61999999999\""); + + vls = n.getValues(X509Name.TELEPHONE_NUMBER); + if (vls.size() != 1 || !vls.elementAt(0).equals("+61999999999")) + { + fail("telephonenumber escaped + not reduced properly"); + } + + n = new X509Name("TELEPHONENUMBER=\\+61999999999"); + + vls = n.getValues(X509Name.TELEPHONE_NUMBER); + if (vls.size() != 1 || !vls.elementAt(0).equals("+61999999999")) + { + fail("telephonenumber escaped + not reduced properly"); + } + + // migration + X500NameBuilder builder = new X500NameBuilder(BCStyle.INSTANCE); + builder.addMultiValuedRDN(new ASN1ObjectIdentifier[] { BCStyle.CN, BCStyle.SN }, new String[] { "Thomas", "CVR:12341233-UID:1111" }); + builder.addRDN(BCStyle.O, "Test"); + builder.addRDN(BCStyle.C, "DK"); + + X500Name subject = builder.build(); + ASN1Primitive derObject = subject.toASN1Primitive(); + X509Name instance = X509Name.getInstance(derObject); + } + + private boolean compareVectors(Vector a, Vector b) // for compatibility with early JDKs + { + if (a.size() != b.size()) + { + return false; + } + + for (int i = 0; i != a.size(); i++) + { + if (!a.elementAt(i).equals(b.elementAt(i))) + { + return false; + } + } + + return true; + } + + private void compositeTest() + throws IOException + { + // + // composite test + // + byte[] enc = Hex.decode( + "305e310b300906035504061302415531283026060355040a0c1f546865204c6567696f6e206f662074686520426f756e637920436173746c653125301006035504070c094d656c626f75726e653011060355040b0c0a4173636f742056616c65"); + + X509Name n = X509Name.getInstance(ASN1Primitive.fromByteArray(enc)); + + if (!n.toString().equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne+OU=Ascot Vale")) + { + fail("Failed composite to string test got: " + n.toString()); + } + + if (!n.toString(true, X509Name.DefaultSymbols).equals("L=Melbourne+OU=Ascot Vale,O=The Legion of the Bouncy Castle,C=AU")) + { + fail("Failed composite to string test got: " + n.toString(true, X509Name.DefaultSymbols)); + } + + n = new X509Name(true, "L=Melbourne+OU=Ascot Vale,O=The Legion of the Bouncy Castle,C=AU"); + if (!n.toString().equals("C=AU,O=The Legion of the Bouncy Castle,L=Melbourne+OU=Ascot Vale")) + { + fail("Failed composite to string reversal test got: " + n.toString()); + } + + n = new X509Name("C=AU, O=The Legion of the Bouncy Castle, L=Melbourne + OU=Ascot Vale"); + + byte[] enc2 = n.getEncoded(); + + if (!Arrays.areEqual(enc, enc2)) + { + fail("Failed composite string to encoding test"); + } + + // + // dud name test - handle empty DN without barfing. + // + n = new X509Name("C=CH,O=,OU=dummy,CN=mail@dummy.com"); + + n = X509Name.getInstance(ASN1Primitive.fromByteArray(n.getEncoded())); + } + + private void equalityTest(X509Name x509Name, X509Name x509Name1) + { + if (!x509Name.equals(x509Name1)) + { + fail("equality test failed for " + x509Name + " : " + x509Name1); + } + + if (x509Name.hashCode() != x509Name1.hashCode()) + { + fail("hashCodeTest test failed for " + x509Name + " : " + x509Name1); + } + + if (!x509Name.equals(x509Name1, true)) + { + fail("equality test failed for " + x509Name + " : " + x509Name1); + } + } + + + public static void main( + String[] args) + { + runTest(new X509NameTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X9Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X9Test.java new file mode 100644 index 000000000..e8aa32abf --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/X9Test.java @@ -0,0 +1,174 @@ +package com.fr.third.org.bouncycastle.asn1.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.sec.ECPrivateKey; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x9.X962NamedCurves; +import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; +import com.fr.third.org.bouncycastle.asn1.x9.X9IntegerConverter; +import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class X9Test + extends SimpleTest +{ + private byte[] namedPub = Base64.decode("MDcwEwYHKoZIzj0CAQYIKoZIzj0DAQEDIAADG5xRI+Iki/JrvL20hoDUa7Cggzorv5B9yyqSMjYu"); + private byte[] expPub = Base64.decode( + "MIH8MIHXBgcqhkjOPQIBMIHLAgEBMCkGByqGSM49AQECHn///////////////3///////4AAAA" + + "AAAH///////zBXBB5///////////////9///////+AAAAAAAB///////wEHiVXBfoqMGZUsfTL" + + "A9anUKMMJQEC1JiHF9m6FattPgMVAH1zdBaP/jRxtgqFdoahlHXTv6L/BB8DZ2iujhi7ks/PAF" + + "yUmqLG2UhT0OZgu/hUsclQX+laAh5///////////////9///+XXetBs6YFfDxDIUZSZVECAQED" + + "IAADG5xRI+Iki/JrvL20hoDUa7Cggzorv5B9yyqSMjYu"); + + private byte[] namedPriv = Base64.decode("MDkCAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEHzAdAgEBBB" + + "gAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo="); + + private byte[] expPriv = Base64.decode( + "MIIBBAIBADCB1wYHKoZIzj0CATCBywIBATApBgcqhkjOPQEBAh5///////////////9///////" + + "+AAAAAAAB///////8wVwQef///////////////f///////gAAAAAAAf//////8BB4lVwX6KjBmVL" + + "H0ywPWp1CjDCUBAtSYhxfZuhWrbT4DFQB9c3QWj/40cbYKhXaGoZR107+i/wQfA2doro4Yu5LPzw" + + "BclJqixtlIU9DmYLv4VLHJUF/pWgIef///////////////f///l13rQbOmBXw8QyFGUmVRAgEBBC" + + "UwIwIBAQQeAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAU"); + + private void encodePublicKey() + throws Exception + { + X9ECParameters ecP = X962NamedCurves.getByOID(X9ObjectIdentifiers.prime239v3); + + X9IntegerConverter conv = new X9IntegerConverter(); + + if (conv.getByteLength(ecP.getCurve()) != 30) + { + fail("wrong byte length reported for curve"); + } + + if (ecP.getCurve().getFieldSize() != 239) + { + fail("wrong field size reported for curve"); + } + + // + // named curve + // + X962Parameters params = new X962Parameters(X9ObjectIdentifiers.prime192v1); + ECPoint point = ecP.getG().multiply(BigInteger.valueOf(100)); + + ASN1OctetString p = new DEROctetString(point.getEncoded(true)); + + SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); + if (!areEqual(info.getEncoded(), namedPub)) + { + fail("failed public named generation"); + } + + X9ECPoint x9P = new X9ECPoint(ecP.getCurve(), p); + + if (!Arrays.areEqual(p.getOctets(), x9P.getPointEncoding())) + { + fail("point encoding not preserved"); + } + + ASN1Primitive o = ASN1Primitive.fromByteArray(namedPub); + + if (!info.equals(o)) + { + fail("failed public named equality"); + } + + // + // explicit curve parameters + // + params = new X962Parameters(ecP); + + info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); + + if (!areEqual(info.getEncoded(), expPub)) + { + fail("failed public explicit generation"); + } + + o = ASN1Primitive.fromByteArray(expPub); + + if (!info.equals(o)) + { + fail("failed public explicit equality"); + } + } + + private void encodePrivateKey() + throws Exception + { + X9ECParameters ecP = X962NamedCurves.getByOID(X9ObjectIdentifiers.prime192v1); + + // + // named curve + // + X962Parameters params = new X962Parameters(X9ObjectIdentifiers.prime192v1); + + PrivateKeyInfo info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), + new ECPrivateKey(ecP.getN().bitLength(), BigInteger.valueOf(10))); + + if (!areEqual(info.getEncoded(), namedPriv)) + { + fail("failed private named generation"); + } + + ASN1Primitive o = ASN1Primitive.fromByteArray(namedPriv); + + if (!info.equals(o)) + { + fail("failed private named equality"); + } + + // + // explicit curve parameters + // + ecP = X962NamedCurves.getByOID(X9ObjectIdentifiers.prime239v3); + + params = new X962Parameters(ecP); + + info = new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), + new ECPrivateKey(ecP.getN().bitLength(), BigInteger.valueOf(20))); + + if (!areEqual(info.getEncoded(), expPriv)) + { + fail("failed private explicit generation"); + } + + o = ASN1Primitive.fromByteArray(expPriv); + + if (!info.equals(o)) + { + fail("failed private explicit equality"); + } + } + + public void performTest() + throws Exception + { + encodePublicKey(); + encodePrivateKey(); + } + + public String getName() + { + return "X9"; + } + + public static void main( + String[] args) + { + runTest(new X9Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/package.html b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/package.html new file mode 100644 index 000000000..df45e190e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/test/package.html @@ -0,0 +1,5 @@ + + +Test programs for the ASN.1 package. + + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/Accuracy.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/Accuracy.java index 6d3cf4f42..77e14f1f5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/Accuracy.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/Accuracy.java @@ -37,33 +37,26 @@ public class Accuracy ASN1Integer millis, ASN1Integer micros) { - this.seconds = seconds; - - //Verifications - if (millis != null - && (millis.getValue().intValue() < MIN_MILLIS || millis - .getValue().intValue() > MAX_MILLIS)) - { - throw new IllegalArgumentException( - "Invalid millis field : not in (1..999)"); - } - else - { - this.millis = millis; - } - - if (micros != null - && (micros.getValue().intValue() < MIN_MICROS || micros - .getValue().intValue() > MAX_MICROS)) + if (null != millis) { - throw new IllegalArgumentException( - "Invalid micros field : not in (1..999)"); + int millisValue = millis.intValueExact(); + if (millisValue < MIN_MILLIS || millisValue > MAX_MILLIS) + { + throw new IllegalArgumentException("Invalid millis field : not in (1..999)"); + } } - else + if (null != micros) { - this.micros = micros; + int microsValue = micros.intValueExact(); + if (microsValue < MIN_MICROS || microsValue > MAX_MICROS) + { + throw new IllegalArgumentException("Invalid micros field : not in (1..999)"); + } } + this.seconds = seconds; + this.millis = millis; + this.micros = micros; } private Accuracy(ASN1Sequence seq) @@ -87,24 +80,22 @@ public class Accuracy { case 0: millis = ASN1Integer.getInstance(extra, false); - if (millis.getValue().intValue() < MIN_MILLIS - || millis.getValue().intValue() > MAX_MILLIS) + int millisValue = millis.intValueExact(); + if (millisValue < MIN_MILLIS || millisValue > MAX_MILLIS) { - throw new IllegalArgumentException( - "Invalid millis field : not in (1..999)."); + throw new IllegalArgumentException("Invalid millis field : not in (1..999)"); } break; case 1: micros = ASN1Integer.getInstance(extra, false); - if (micros.getValue().intValue() < MIN_MICROS - || micros.getValue().intValue() > MAX_MICROS) + int microsValue = micros.intValueExact(); + if (microsValue < MIN_MICROS || microsValue > MAX_MICROS) { - throw new IllegalArgumentException( - "Invalid micros field : not in (1..999)."); + throw new IllegalArgumentException("Invalid micros field : not in (1..999)"); } break; default: - throw new IllegalArgumentException("Invalig tag number"); + throw new IllegalArgumentException("Invalid tag number"); } } } @@ -151,8 +142,7 @@ public class Accuracy */ public ASN1Primitive toASN1Primitive() { - - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (seconds != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/ArchiveTimeStamp.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/ArchiveTimeStamp.java new file mode 100644 index 000000000..9fafde65f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/ArchiveTimeStamp.java @@ -0,0 +1,210 @@ +package com.fr.third.org.bouncycastle.asn1.tsp; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Object; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.cms.Attributes; +import com.fr.third.org.bouncycastle.asn1.cms.CMSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.cms.ContentInfo; +import com.fr.third.org.bouncycastle.asn1.cms.SignedData; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * Implementation of the Archive Timestamp type defined in RFC4998. + * {@see RFC 4998} + *

+ * ASN.1 Archive Timestamp + *

+ * ArchiveTimeStamp ::= SEQUENCE { + * digestAlgorithm [Ø] AlgorithmIdentifier OPTIONAL, + * attributes [1] Attributes OPTIONAL, + * reducedHashtree [2] SEQUENCE OF PartialHashtree OPTIONAL, + * timeStamp ContentInfo} + *

+ * PartialHashtree ::= SEQUENCE OF OCTET STRING + *

+ * Attributes ::= SET SIZE (1..MAX) OF Attribute + */ +public class ArchiveTimeStamp + extends ASN1Object +{ + private AlgorithmIdentifier digestAlgorithm; + private Attributes attributes; + private ASN1Sequence reducedHashTree; + private ContentInfo timeStamp; + + /** + * Return an ArchiveTimestamp from the given object. + * + * @param obj the object we want converted. + * @return an ArchiveTimestamp instance, or null. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static ArchiveTimeStamp getInstance(final Object obj) + { + if (obj instanceof ArchiveTimeStamp) + { + return (ArchiveTimeStamp)obj; + } + else if (obj != null) + { + return new ArchiveTimeStamp(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ArchiveTimeStamp( + AlgorithmIdentifier digestAlgorithm, + PartialHashtree[] reducedHashTree, + ContentInfo timeStamp) + { + this.digestAlgorithm = digestAlgorithm; + this.reducedHashTree = new DERSequence(reducedHashTree); + this.timeStamp = timeStamp; + } + + public ArchiveTimeStamp( + AlgorithmIdentifier digestAlgorithm, + Attributes attributes, + PartialHashtree[] reducedHashTree, + ContentInfo timeStamp) + { + this.digestAlgorithm = digestAlgorithm; + this.attributes = attributes; + this.reducedHashTree = new DERSequence(reducedHashTree); + this.timeStamp = timeStamp; + } + + public ArchiveTimeStamp( + ContentInfo timeStamp) + { + this.timeStamp = timeStamp; + } + + private ArchiveTimeStamp(final ASN1Sequence sequence) + { + if (sequence.size() < 1 || sequence.size() > 4) + { + throw new IllegalArgumentException("wrong sequence size in constructor: " + sequence.size()); + } + + for (int i = 0; i < sequence.size() - 1; i++) + { + Object obj = sequence.getObjectAt(i); + + if (obj instanceof ASN1TaggedObject) + { + ASN1TaggedObject taggedObject = ASN1TaggedObject.getInstance(obj); + + switch (taggedObject.getTagNo()) + { + case 0: + digestAlgorithm = AlgorithmIdentifier.getInstance(taggedObject, false); + break; + case 1: + attributes = Attributes.getInstance(taggedObject, false); + break; + case 2: + reducedHashTree = ASN1Sequence.getInstance(taggedObject, false); + break; + default: + throw new IllegalArgumentException("invalid tag no in constructor: " + + taggedObject.getTagNo()); + } + } + } + + timeStamp = ContentInfo.getInstance(sequence.getObjectAt(sequence.size() - 1)); + } + + public AlgorithmIdentifier getDigestAlgorithmIdentifier() + { + if (digestAlgorithm != null) + { + return digestAlgorithm; + } + else + { + if (timeStamp.getContentType().equals(CMSObjectIdentifiers.signedData)) + { + SignedData tsData = SignedData.getInstance(timeStamp.getContent()); + if (tsData.getEncapContentInfo().getContentType().equals(PKCSObjectIdentifiers.id_ct_TSTInfo)) + { + TSTInfo tstData = TSTInfo.getInstance(tsData.getEncapContentInfo()); + + return tstData.getMessageImprint().getHashAlgorithm(); + } + else + { + throw new IllegalStateException("cannot parse time stamp"); + } + } + else + { + throw new IllegalStateException("cannot identify algorithm identifier for digest"); + } + } + } + + /** + * Return the contents of the digestAlgorithm field - null if not set. + * + * @return the contents of the digestAlgorithm field, or null if not set. + */ + public AlgorithmIdentifier getDigestAlgorithm() + { + return digestAlgorithm; + } + + public PartialHashtree[] getReducedHashTree() + { + if (reducedHashTree == null) + { + return null; + } + + PartialHashtree[] rv = new PartialHashtree[reducedHashTree.size()]; + + for (int i = 0; i != rv.length; i++) + { + rv[i] = PartialHashtree.getInstance(reducedHashTree.getObjectAt(i)); + } + + return rv; + } + + public ContentInfo getTimeStamp() + { + return timeStamp; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(4); + + if (digestAlgorithm != null) + { + v.add(new DERTaggedObject(false, 0, digestAlgorithm)); + } + + if (attributes != null) + { + v.add(new DERTaggedObject(false, 1, attributes)); + } + + if (reducedHashTree != null) + { + v.add(new DERTaggedObject(false, 2, reducedHashTree)); + } + + v.add(timeStamp); + + return new DERSequence(v); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/ArchiveTimeStampChain.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/ArchiveTimeStampChain.java new file mode 100644 index 000000000..a6356e349 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/ArchiveTimeStampChain.java @@ -0,0 +1,104 @@ +package com.fr.third.org.bouncycastle.asn1.tsp; + +import java.util.Enumeration; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Object; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DERSequence; + +/** + * Implementation of ArchiveTimeStampChain type, as defined in RFC4998 and RFC6283. + *

+ * An ArchiveTimeStampChain corresponds to a SEQUENCE OF ArchiveTimeStamps, and has the following + * ASN.1 Syntax: + *

+ * ArchiveTimeStampChain ::= SEQUENCE OF ArchiveTimeStamp + */ +public class ArchiveTimeStampChain + extends ASN1Object +{ + private ASN1Sequence archiveTimestamps; + + /** + * Return an ArchiveTimeStampChain from the given object. + * + * @param obj the object we want converted. + * @return an ArchiveTimeStampChain instance, or null. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static ArchiveTimeStampChain getInstance(final Object obj) + { + if (obj instanceof ArchiveTimeStampChain) + { + return (ArchiveTimeStampChain)obj; + } + else if (obj != null) + { + return new ArchiveTimeStampChain(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public ArchiveTimeStampChain(ArchiveTimeStamp archiveTimeStamp) + { + archiveTimestamps = new DERSequence(archiveTimeStamp); + } + + public ArchiveTimeStampChain(ArchiveTimeStamp[] archiveTimeStamps) + { + archiveTimestamps = new DERSequence(archiveTimeStamps); + } + + private ArchiveTimeStampChain(final ASN1Sequence sequence) + { + final ASN1EncodableVector vector = new ASN1EncodableVector(sequence.size()); + + final Enumeration objects = sequence.getObjects(); + while (objects.hasMoreElements()) + { + vector.add(ArchiveTimeStamp.getInstance(objects.nextElement())); + } + + archiveTimestamps = new DERSequence(vector); + } + + public ArchiveTimeStamp[] getArchiveTimestamps() + { + ArchiveTimeStamp[] rv = new ArchiveTimeStamp[archiveTimestamps.size()]; + + for (int i = 0; i != rv.length; i++) + { + rv[i] = ArchiveTimeStamp.getInstance(archiveTimestamps.getObjectAt(i)); + } + + return rv; + } + + /** + * Adds an {@link ArchiveTimeStamp} object to the archive timestamp chain. + * + * @param archiveTimeStamp the {@link ArchiveTimeStamp} to add. + * @return returns the modified chain. + */ + public ArchiveTimeStampChain append(final ArchiveTimeStamp archiveTimeStamp) + { + ASN1EncodableVector v = new ASN1EncodableVector(archiveTimestamps.size() + 1); + + for (int i = 0; i != archiveTimestamps.size(); i++) + { + v.add(archiveTimestamps.getObjectAt(i)); + } + + v.add(archiveTimeStamp); + + return new ArchiveTimeStampChain(new DERSequence(v)); + } + + public ASN1Primitive toASN1Primitive() + { + return archiveTimestamps; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/ArchiveTimeStampSequence.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/ArchiveTimeStampSequence.java new file mode 100644 index 000000000..618948303 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/ArchiveTimeStampSequence.java @@ -0,0 +1,115 @@ +package com.fr.third.org.bouncycastle.asn1.tsp; + +import java.util.Enumeration; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Object; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DERSequence; + +/** + * Implementation of ArchiveTimeStampSequence type, as defined in RFC4998. + *

+ * An ArchiveTimeStampSequence corresponds to a SEQUENCE OF ArchiveTimeStampChains and has the + * following ASN.1 Syntax: + *

+ * ArchiveTimeStampSequence ::= SEQUENCE OF ArchiveTimeStampChain + */ +public class ArchiveTimeStampSequence + extends ASN1Object +{ + private ASN1Sequence archiveTimeStampChains; + + /** + * Return an ArchiveTimestampSequence from the given object. + * + * @param obj the object we want converted. + * @return an ArchiveTimeStampSequence instance, or null. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static ArchiveTimeStampSequence getInstance(final Object obj) + { + if (obj instanceof ArchiveTimeStampChain) + { + return (ArchiveTimeStampSequence)obj; + } + else if (obj != null) + { + return new ArchiveTimeStampSequence(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private ArchiveTimeStampSequence(final ASN1Sequence sequence) + throws IllegalArgumentException + { + final ASN1EncodableVector vector = new ASN1EncodableVector(sequence.size()); + + Enumeration objects = sequence.getObjects(); + while (objects.hasMoreElements()) + { + vector.add(ArchiveTimeStampChain.getInstance(objects.nextElement())); + } + + this.archiveTimeStampChains = new DERSequence(vector); + } + + public ArchiveTimeStampSequence(ArchiveTimeStampChain archiveTimeStampChain) + { + this.archiveTimeStampChains = new DERSequence(archiveTimeStampChain); + } + + public ArchiveTimeStampSequence(ArchiveTimeStampChain[] archiveTimeStampChains) + { + this.archiveTimeStampChains = new DERSequence(archiveTimeStampChains); + } + + /** + * Returns the sequence of ArchiveTimeStamp chains that compose the ArchiveTimeStamp sequence. + * + * @return the {@link ASN1Sequence} containing the ArchiveTimeStamp chains. + */ + public ArchiveTimeStampChain[] getArchiveTimeStampChains() + { + ArchiveTimeStampChain[] rv = new ArchiveTimeStampChain[archiveTimeStampChains.size()]; + + for (int i = 0; i != rv.length; i++) + { + rv[i] = ArchiveTimeStampChain.getInstance(archiveTimeStampChains.getObjectAt(i)); + } + + return rv; + } + + public int size() + { + return archiveTimeStampChains.size(); + } + + /** + * Adds an {@link ArchiveTimeStampChain} to the ArchiveTimeStamp sequence. + * + * @param chain the {@link ArchiveTimeStampChain} to add + * @return returns the modified sequence. + */ + public ArchiveTimeStampSequence append(ArchiveTimeStampChain chain) { + + ASN1EncodableVector v = new ASN1EncodableVector(archiveTimeStampChains.size() + 1); + + for (int i = 0; i != archiveTimeStampChains.size(); i++) + { + v.add(archiveTimeStampChains.getObjectAt(i)); + } + + v.add(chain); + + return new ArchiveTimeStampSequence(new DERSequence(v)); + } + + public ASN1Primitive toASN1Primitive() + { + return archiveTimeStampChains; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/CryptoInfos.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/CryptoInfos.java new file mode 100644 index 000000000..dffab9b0a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/CryptoInfos.java @@ -0,0 +1,67 @@ +package com.fr.third.org.bouncycastle.asn1.tsp; + +import com.fr.third.org.bouncycastle.asn1.ASN1Object; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cms.Attribute; + +/** + * Implementation of the CryptoInfos element defined in RFC 4998: + *

+ * CryptoInfos ::= SEQUENCE SIZE (1..MAX) OF Attribute + */ +public class CryptoInfos + extends ASN1Object +{ + private ASN1Sequence attributes; + + public static CryptoInfos getInstance(final Object obj) + { + if (obj instanceof CryptoInfos) + { + return (CryptoInfos)obj; + } + else if (obj != null) + { + return new CryptoInfos(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static CryptoInfos getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + private CryptoInfos(final ASN1Sequence attributes) + { + this.attributes = attributes; + } + + public CryptoInfos(Attribute[] attrs) + { + attributes = new DERSequence(attrs); + } + + public Attribute[] getAttributes() + { + Attribute[] rv = new Attribute[attributes.size()]; + + for (int i = 0; i != rv.length; i++) + { + rv[i] = Attribute.getInstance(attributes.getObjectAt(i)); + } + + return rv; + } + + public ASN1Primitive toASN1Primitive() + { + return attributes; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/EncryptionInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/EncryptionInfo.java new file mode 100644 index 000000000..dfe762704 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/EncryptionInfo.java @@ -0,0 +1,96 @@ +package com.fr.third.org.bouncycastle.asn1.tsp; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Object; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DLSequence; + +/** + * Implementation of the EncryptionInfo element defined in RFC 4998: + *

+ * 1988 ASN.1 EncryptionInfo + *

+ * EncryptionInfo ::= SEQUENCE { + * encryptionInfoType OBJECT IDENTIFIER, + * encryptionInfoValue ANY DEFINED BY encryptionInfoType + * } + *

+ * 1997-ASN.1 EncryptionInfo + *

+ * EncryptionInfo ::= SEQUENCE { + * encryptionInfoType ENCINFO-TYPE.&id + * ({SupportedEncryptionAlgorithms}), + * encryptionInfoValue ENCINFO-TYPE.&Type + * ({SupportedEncryptionAlgorithms}{@encryptionInfoType}) + * } + *

+ * ENCINFO-TYPE ::= TYPE-IDENTIFIER + *

+ * SupportedEncryptionAlgorithms ENCINFO-TYPE ::= {...} + */ +public class EncryptionInfo + extends ASN1Object +{ + + /** + * The OID for EncryptionInfo type. + */ + private ASN1ObjectIdentifier encryptionInfoType; + + /** + * The value of EncryptionInfo + */ + private ASN1Encodable encryptionInfoValue; + + public static EncryptionInfo getInstance(final ASN1Object obj) + { + if (obj instanceof EncryptionInfo) + { + return (EncryptionInfo)obj; + } + else if (obj != null) + { + return new EncryptionInfo(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static EncryptionInfo getInstance( + ASN1TaggedObject obj, + boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(obj, explicit)); + } + + private EncryptionInfo(ASN1Sequence sequence) + { + if (sequence.size() != 2) + { + throw new IllegalArgumentException("wrong sequence size in constructor: " + sequence.size()); + } + + this.encryptionInfoType = ASN1ObjectIdentifier.getInstance(sequence.getObjectAt(0)); + this.encryptionInfoValue = sequence.getObjectAt(1); + } + + public EncryptionInfo(ASN1ObjectIdentifier encryptionInfoType, + ASN1Encodable encryptionInfoValue) + { + this.encryptionInfoType = encryptionInfoType; + this.encryptionInfoValue = encryptionInfoValue; + } + + public ASN1Primitive toASN1Primitive() + { + ASN1EncodableVector v = new ASN1EncodableVector(2); + v.add(encryptionInfoType); + v.add(encryptionInfoValue); + + return new DLSequence(v); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/EvidenceRecord.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/EvidenceRecord.java new file mode 100644 index 000000000..39ac5c47d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/EvidenceRecord.java @@ -0,0 +1,246 @@ +package com.fr.third.org.bouncycastle.asn1.tsp; + +import java.util.Enumeration; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Object; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +/** + * RFC 4998: + * Evidence Record Syntax (ERS) + *

+ *

+ * EvidenceRecord ::= SEQUENCE {
+ *   version                   INTEGER { v1(1) } ,
+ *   digestAlgorithms          SEQUENCE OF AlgorithmIdentifier,
+ *   cryptoInfos               [0] CryptoInfos OPTIONAL,
+ *   encryptionInfo            [1] EncryptionInfo OPTIONAL,
+ *   archiveTimeStampSequence  ArchiveTimeStampSequence
+ * }
+ *
+ * CryptoInfos ::= SEQUENCE SIZE (1..MAX) OF Attribute
+ * 
+ */ +public class EvidenceRecord + extends ASN1Object +{ + + /** + * ERS {iso(1) identified-organization(3) dod(6) internet(1) security(5) mechanisms(5) ltans(11) + * id-mod(0) id-mod-ers88(2) id-mod-ers88-v1(1) } + */ + private static final ASN1ObjectIdentifier OID = new ASN1ObjectIdentifier("1.3.6.1.5.5.11.0.2.1"); + + private ASN1Integer version = new ASN1Integer(1); + private ASN1Sequence digestAlgorithms; + private CryptoInfos cryptoInfos; + private EncryptionInfo encryptionInfo; + private ArchiveTimeStampSequence archiveTimeStampSequence; + + /** + * Return an EvidenceRecord from the given object. + * + * @param obj the object we want converted. + * @return an EvidenceRecord instance, or null. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static EvidenceRecord getInstance(final Object obj) + { + if (obj instanceof EvidenceRecord) + { + return (EvidenceRecord)obj; + } + else if (obj != null) + { + return new EvidenceRecord(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + public static EvidenceRecord getInstance(ASN1TaggedObject tagged, boolean explicit) + { + return getInstance(ASN1Sequence.getInstance(tagged, explicit)); + } + + private EvidenceRecord( + EvidenceRecord evidenceRecord, + ArchiveTimeStampSequence replacementSequence, + ArchiveTimeStamp newChainTimeStamp) + { + this.version = evidenceRecord.version; + + // check the list of digest algorithms is correct. + if (newChainTimeStamp != null) + { + AlgorithmIdentifier algId = newChainTimeStamp.getDigestAlgorithmIdentifier(); + final ASN1EncodableVector vector = new ASN1EncodableVector(); + final Enumeration enumeration = evidenceRecord.digestAlgorithms.getObjects(); + boolean found = false; + + while (enumeration.hasMoreElements()) + { + final AlgorithmIdentifier algorithmIdentifier = AlgorithmIdentifier.getInstance( + enumeration.nextElement()); + vector.add(algorithmIdentifier); + + if (algorithmIdentifier.equals(algId)) + { + found = true; + break; + } + } + + if (!found) + { + vector.add(algId); + this.digestAlgorithms = new DERSequence(vector); + } + else + { + this.digestAlgorithms = evidenceRecord.digestAlgorithms; + } + } + else + { + this.digestAlgorithms = evidenceRecord.digestAlgorithms; + } + + this.cryptoInfos = evidenceRecord.cryptoInfos; + this.encryptionInfo = evidenceRecord.encryptionInfo; + this.archiveTimeStampSequence = replacementSequence; + } + + public EvidenceRecord( + AlgorithmIdentifier[] digestAlgorithms, + CryptoInfos cryptoInfos, + EncryptionInfo encryptionInfo, + ArchiveTimeStampSequence archiveTimeStampSequence) + { + this.digestAlgorithms = new DERSequence(digestAlgorithms); + this.cryptoInfos = cryptoInfos; + this.encryptionInfo = encryptionInfo; + this.archiveTimeStampSequence = archiveTimeStampSequence; + } + + private EvidenceRecord(final ASN1Sequence sequence) + { + if (sequence.size() < 3 && sequence.size() > 5) + { + throw new IllegalArgumentException("wrong sequence size in constructor: " + sequence.size()); + } + + final ASN1Integer versionNumber = ASN1Integer.getInstance(sequence.getObjectAt(0)); + if (versionNumber.intValueExact() != 1) + { + throw new IllegalArgumentException("incompatible version"); + } + + this.version = versionNumber; + + this.digestAlgorithms = ASN1Sequence.getInstance(sequence.getObjectAt(1)); + for (int i = 2; i != sequence.size() - 1; i++) + { + ASN1Encodable object = sequence.getObjectAt(i); + + if (object instanceof ASN1TaggedObject) + { + ASN1TaggedObject asn1TaggedObject = (ASN1TaggedObject)object; + switch (asn1TaggedObject.getTagNo()) + { + case 0: + cryptoInfos = CryptoInfos.getInstance(asn1TaggedObject, false); + break; + case 1: + encryptionInfo = EncryptionInfo.getInstance(asn1TaggedObject, false); + break; + default: + throw new IllegalArgumentException("unknown tag in getInstance: " + asn1TaggedObject.getTagNo()); + } + } + else + { + throw new IllegalArgumentException("unknown object in getInstance: " + + object.getClass().getName()); + } + } + archiveTimeStampSequence = ArchiveTimeStampSequence.getInstance(sequence.getObjectAt(sequence.size() - 1)); + } + + public AlgorithmIdentifier[] getDigestAlgorithms() + { + AlgorithmIdentifier[] rv = new AlgorithmIdentifier[digestAlgorithms.size()]; + + for (int i = 0; i != rv.length; i++) + { + rv[i] = AlgorithmIdentifier.getInstance(digestAlgorithms.getObjectAt(i)); + } + + return rv; + } + + public ArchiveTimeStampSequence getArchiveTimeStampSequence() + { + return archiveTimeStampSequence; + } + + /** + * Return a new EvidenceRecord with an added ArchiveTimeStamp + * + * @param ats the archive timestamp to add + * @param newChain states whether this new archive timestamp must be added as part of a + * new sequence (i.e. in the case of hashtree renewal) or not (i.e. in the case of timestamp + * renewal) + * @return the new EvidenceRecord + */ + public EvidenceRecord addArchiveTimeStamp(final ArchiveTimeStamp ats, final boolean newChain) + { + if (newChain) + { + ArchiveTimeStampChain chain = new ArchiveTimeStampChain(ats); + + return new EvidenceRecord(this, archiveTimeStampSequence.append(chain), ats); + } + else + { + ArchiveTimeStampChain[] chains = archiveTimeStampSequence.getArchiveTimeStampChains(); + + chains[chains.length - 1] = chains[chains.length - 1].append(ats); + return new EvidenceRecord(this, new ArchiveTimeStampSequence(chains), null); + } + } + + public String toString() + { + return ("EvidenceRecord: Oid(" + OID + ")"); + } + + public ASN1Primitive toASN1Primitive() + { + final ASN1EncodableVector vector = new ASN1EncodableVector(5); + + vector.add(version); + vector.add(digestAlgorithms); + + if (null != cryptoInfos) + { + vector.add(cryptoInfos); + } + if (null != encryptionInfo) + { + vector.add(encryptionInfo); + } + + vector.add(archiveTimeStampSequence); + + return new DERSequence(vector); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/MessageImprint.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/MessageImprint.java index c96b96215..20dd4c0be 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/MessageImprint.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/MessageImprint.java @@ -69,7 +69,7 @@ public class MessageImprint */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(hashAlgorithm); v.add(new DEROctetString(hashedMessage)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/PartialHashtree.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/PartialHashtree.java new file mode 100644 index 000000000..3e4603c50 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/PartialHashtree.java @@ -0,0 +1,94 @@ +package com.fr.third.org.bouncycastle.asn1.tsp; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Object; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.util.Arrays; + +/** + * Implementation of PartialHashtree, as defined in RFC 4998. + *

+ * The ASN.1 notation for a PartialHashTree is: + *

+ * PartialHashtree ::= SEQUENCE OF OCTET STRING + */ +public class PartialHashtree + extends ASN1Object +{ + /** + * Hash values that constitute the hash tree, as ASN.1 Octet Strings. + */ + private ASN1Sequence values; + + /** + * Return a PartialHashtree from the given object. + * + * @param obj the object we want converted. + * @return a PartialHashtree instance, or null. + * @throws IllegalArgumentException if the object cannot be converted. + */ + public static PartialHashtree getInstance(final Object obj) + { + if (obj instanceof PartialHashtree) + { + return (PartialHashtree)obj; + } + else if (obj != null) + { + return new PartialHashtree(ASN1Sequence.getInstance(obj)); + } + + return null; + } + + private PartialHashtree(final ASN1Sequence values) + { + for (int i = 0; i != values.size(); i++) + { + if (!(values.getObjectAt(i) instanceof DEROctetString)) + { + throw new IllegalArgumentException("unknown object in constructor: " + values + .getObjectAt(i).getClass().getName()); + } + } + this.values = values; + } + + public PartialHashtree(byte[] values) + { + this(new byte[][] { values }); + } + + public PartialHashtree(byte[][] values) + { + ASN1EncodableVector v = new ASN1EncodableVector(values.length); + + for (int i = 0; i != values.length; i++) + { + v.add(new DEROctetString(Arrays.clone(values[i]))); + } + + this.values = new DERSequence(v); + } + + public byte[][] getValues() + { + byte[][] rv = new byte[values.size()][]; + + for (int i = 0; i != rv.length; i++) + { + rv[i] = Arrays.clone(ASN1OctetString.getInstance(values.getObjectAt(i)).getOctets()); + } + + return rv; + } + + public ASN1Primitive toASN1Primitive() + { + return values; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TSTInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TSTInfo.java index 5d6738249..bac137981 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TSTInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TSTInfo.java @@ -195,7 +195,7 @@ public class TSTInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector seq = new ASN1EncodableVector(); + ASN1EncodableVector seq = new ASN1EncodableVector(10); seq.add(version); seq.add(tsaPolicyId); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TimeStampReq.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TimeStampReq.java index 174118f42..61201808c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TimeStampReq.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TimeStampReq.java @@ -149,7 +149,7 @@ public class TimeStampReq */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); v.add(version); v.add(messageImprint); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TimeStampResp.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TimeStampResp.java index 2ed8179ee..d11b1c7b8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TimeStampResp.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/tsp/TimeStampResp.java @@ -71,7 +71,7 @@ public class TimeStampResp */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(pkiStatusInfo); if (timeStampToken != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java index e28e1435b..6f90fd65c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145BinaryField.java @@ -10,24 +10,23 @@ import com.fr.third.org.bouncycastle.asn1.DERSequence; public class DSTU4145BinaryField extends ASN1Object { - private int m, k, j, l; private DSTU4145BinaryField(ASN1Sequence seq) { - m = ASN1Integer.getInstance(seq.getObjectAt(0)).getPositiveValue().intValue(); + m = ASN1Integer.getInstance(seq.getObjectAt(0)).intPositiveValueExact(); if (seq.getObjectAt(1) instanceof ASN1Integer) { - k = ((ASN1Integer)seq.getObjectAt(1)).getPositiveValue().intValue(); + k = ((ASN1Integer)seq.getObjectAt(1)).intPositiveValueExact(); } else if (seq.getObjectAt(1) instanceof ASN1Sequence) { ASN1Sequence coefs = ASN1Sequence.getInstance(seq.getObjectAt(1)); - k = ASN1Integer.getInstance(coefs.getObjectAt(0)).getPositiveValue().intValue(); - j = ASN1Integer.getInstance(coefs.getObjectAt(1)).getPositiveValue().intValue(); - l = ASN1Integer.getInstance(coefs.getObjectAt(2)).getPositiveValue().intValue(); + k = ASN1Integer.getInstance(coefs.getObjectAt(0)).intPositiveValueExact(); + j = ASN1Integer.getInstance(coefs.getObjectAt(1)).intPositiveValueExact(); + l = ASN1Integer.getInstance(coefs.getObjectAt(2)).intPositiveValueExact(); } else { @@ -95,8 +94,7 @@ public class DSTU4145BinaryField */ public ASN1Primitive toASN1Primitive() { - - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(new ASN1Integer(m)); if (j == 0) //Trinomial @@ -105,7 +103,7 @@ public class DSTU4145BinaryField } else { - ASN1EncodableVector coefs = new ASN1EncodableVector(); + ASN1EncodableVector coefs = new ASN1EncodableVector(3); coefs.add(new ASN1Integer(k)); coefs.add(new ASN1Integer(j)); coefs.add(new ASN1Integer(l)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java index fc175f4b0..00f73f6c9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145ECBinary.java @@ -139,8 +139,7 @@ public class DSTU4145ECBinary */ public ASN1Primitive toASN1Primitive() { - - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); if (0 != version.compareTo(BigInteger.valueOf(0))) { @@ -154,5 +153,4 @@ public class DSTU4145ECBinary return new DERSequence(v); } - } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145Params.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145Params.java index 28d3a3073..806b3c1e3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145Params.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/ua/DSTU4145Params.java @@ -56,12 +56,12 @@ public class DSTU4145Params public byte[] getDKE() { - return dke; + return Arrays.clone(dke); } public static byte[] getDefaultDKE() { - return DEFAULT_DKE; + return Arrays.clone(DEFAULT_DKE); } public ASN1ObjectIdentifier getNamedCurve() @@ -107,7 +107,7 @@ public class DSTU4145Params public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (namedCurve != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/util/ASN1Dump.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/util/ASN1Dump.java index c3c1789e9..371e4297e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/util/ASN1Dump.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/util/ASN1Dump.java @@ -7,6 +7,7 @@ import com.fr.third.org.bouncycastle.asn1.ASN1ApplicationSpecific; import com.fr.third.org.bouncycastle.asn1.ASN1Boolean; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1Enumerated; +import com.fr.third.org.bouncycastle.asn1.ASN1External; import com.fr.third.org.bouncycastle.asn1.ASN1GeneralizedTime; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; @@ -25,16 +26,17 @@ import com.fr.third.org.bouncycastle.asn1.BERTags; import com.fr.third.org.bouncycastle.asn1.DERApplicationSpecific; import com.fr.third.org.bouncycastle.asn1.DERBMPString; import com.fr.third.org.bouncycastle.asn1.DERBitString; -import com.fr.third.org.bouncycastle.asn1.DERExternal; import com.fr.third.org.bouncycastle.asn1.DERGraphicString; import com.fr.third.org.bouncycastle.asn1.DERIA5String; import com.fr.third.org.bouncycastle.asn1.DERNull; import com.fr.third.org.bouncycastle.asn1.DERPrintableString; import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.DERSet; import com.fr.third.org.bouncycastle.asn1.DERT61String; import com.fr.third.org.bouncycastle.asn1.DERUTF8String; import com.fr.third.org.bouncycastle.asn1.DERVideotexString; import com.fr.third.org.bouncycastle.asn1.DERVisibleString; +import com.fr.third.org.bouncycastle.asn1.DLApplicationSpecific; import com.fr.third.org.bouncycastle.util.Strings; import com.fr.third.org.bouncycastle.util.encoders.Hex; @@ -125,16 +127,7 @@ public class ASN1Dump buf.append(nl); - if (o.isEmpty()) - { - buf.append(tab); - buf.append("EMPTY"); - buf.append(nl); - } - else - { - _dumpAsString(tab, verbose, o.getObject(), buf); - } + _dumpAsString(tab, verbose, o.getObject(), buf); } else if (obj instanceof ASN1Set) { @@ -147,11 +140,14 @@ public class ASN1Dump { buf.append("BER Set"); } - else + else if (obj instanceof DERSet) { buf.append("DER Set"); } - + else + { + buf.append("Set"); + } buf.append(nl); while (e.hasMoreElements()) @@ -268,14 +264,18 @@ public class ASN1Dump { buf.append(outputApplicationSpecific("DER", indent, verbose, obj, nl)); } + else if (obj instanceof DLApplicationSpecific) + { + buf.append(outputApplicationSpecific("", indent, verbose, obj, nl)); + } else if (obj instanceof ASN1Enumerated) { ASN1Enumerated en = (ASN1Enumerated) obj; buf.append(indent + "DER Enumerated(" + en.getValue() + ")" + nl); } - else if (obj instanceof DERExternal) + else if (obj instanceof ASN1External) { - DERExternal ext = (DERExternal) obj; + ASN1External ext = (ASN1External) obj; buf.append(indent + "External " + nl); String tab = indent + TAB; if (ext.getDirectReference() != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java index 1466793e9..b0f94659c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/AttributeTypeAndValue.java @@ -65,7 +65,7 @@ public class AttributeTypeAndValue */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(type); v.add(value); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/RDN.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/RDN.java index 3ea920ceb..535e2172d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/RDN.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/RDN.java @@ -44,7 +44,7 @@ public class RDN */ public RDN(ASN1ObjectIdentifier oid, ASN1Encodable value) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(oid); v.add(value); @@ -104,11 +104,36 @@ public class RDN return tmp; } + int collectAttributeTypes(ASN1ObjectIdentifier[] oids, int oidsOff) + { + int count = values.size(); + for (int i = 0; i < count; ++i) + { + AttributeTypeAndValue attr = AttributeTypeAndValue.getInstance(values.getObjectAt(i)); + oids[oidsOff + i] = attr.getType(); + } + return count; + } + + boolean containsAttributeType(ASN1ObjectIdentifier attributeType) + { + int count = values.size(); + for (int i = 0; i < count; ++i) + { + AttributeTypeAndValue attr = AttributeTypeAndValue.getInstance(values.getObjectAt(i)); + if (attr.getType().equals(attributeType)) + { + return true; + } + } + return false; + } + /** *

      * RelativeDistinguishedName ::=
      *                     SET OF AttributeTypeAndValue
-     *
+
      * AttributeTypeAndValue ::= SEQUENCE {
      *        type     AttributeType,
      *        value    AttributeValue }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/X500Name.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/X500Name.java
index 45920e872..5fd65599a 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/X500Name.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/X500Name.java
@@ -38,14 +38,16 @@ public class X500Name
 
     private X500NameStyle style;
     private RDN[] rdns;
+    private DERSequence rdnSeq;
 
     /**
      * @deprecated use the getInstance() method that takes a style.
      */
     public X500Name(X500NameStyle style, X500Name name)
     {
-        this.rdns = name.rdns;
         this.style = style;
+        this.rdns = name.rdns;
+        this.rdnSeq = name.rdnSeq;
     }
 
     /**
@@ -112,11 +114,24 @@ public class X500Name
         this.style = style;
         this.rdns = new RDN[seq.size()];
 
-        int index = 0;
+        boolean inPlace = true;
 
+        int index = 0;
         for (Enumeration e = seq.getObjects(); e.hasMoreElements();)
         {
-            rdns[index++] = RDN.getInstance(e.nextElement());
+            Object element = e.nextElement();
+            RDN rdn = RDN.getInstance(element);
+            inPlace &= (rdn == element);
+            rdns[index++] = rdn;
+        }
+
+        if (inPlace)
+        {
+            this.rdnSeq = DERSequence.convert(seq);
+        }
+        else
+        {
+            this.rdnSeq = new DERSequence(this.rdns);
         }
     }
 
@@ -130,8 +145,9 @@ public class X500Name
         X500NameStyle style,
         RDN[]         rDNs)
     {
-        this.rdns = rDNs;
         this.style = style;
+        this.rdns = (RDN[])rDNs.clone();
+        this.rdnSeq = new DERSequence(this.rdns);
     }
 
     public X500Name(
@@ -156,11 +172,7 @@ public class X500Name
      */
     public RDN[] getRDNs()
     {
-        RDN[] tmp = new RDN[this.rdns.length];
-
-        System.arraycopy(rdns, 0, tmp, 0, tmp.length);
-
-        return tmp;
+        return (RDN[])rdns.clone();
     }
 
     /**
@@ -170,38 +182,21 @@ public class X500Name
      */
     public ASN1ObjectIdentifier[] getAttributeTypes()
     {
-        int   count = 0;
-
-        for (int i = 0; i != rdns.length; i++)
+        int count = rdns.length, totalSize = 0;
+        for (int i = 0; i < count; ++i)
         {
             RDN rdn = rdns[i];
-
-            count += rdn.size();
+            totalSize += rdn.size();
         }
 
-        ASN1ObjectIdentifier[] res = new ASN1ObjectIdentifier[count];
-
-        count = 0;
-
-        for (int i = 0; i != rdns.length; i++)
+        ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[totalSize];
+        int oidsOff = 0;
+        for (int i = 0; i < count; ++i)
         {
             RDN rdn = rdns[i];
-
-            if (rdn.isMultiValued())
-            {
-                AttributeTypeAndValue[] attr = rdn.getTypesAndValues();
-                for (int j = 0; j != attr.length; j++)
-                {
-                    res[count++] = attr[j].getType();
-                }
-            }
-            else if (rdn.size() != 0)
-            {
-                res[count++] = rdn.getFirst().getType();
-            }
+            oidsOff += rdn.collectAttributeTypes(oids, oidsOff);
         }
-
-        return res;
+        return oids;
     }
 
     /**
@@ -213,43 +208,30 @@ public class X500Name
     public RDN[] getRDNs(ASN1ObjectIdentifier attributeType)
     {
         RDN[] res = new RDN[rdns.length];
-        int   count = 0;
+        int count = 0;
 
         for (int i = 0; i != rdns.length; i++)
         {
             RDN rdn = rdns[i];
-
-            if (rdn.isMultiValued())
-            {
-                AttributeTypeAndValue[] attr = rdn.getTypesAndValues();
-                for (int j = 0; j != attr.length; j++)
-                {
-                    if (attr[j].getType().equals(attributeType))
-                    {
-                        res[count++] = rdn;
-                        break;
-                    }
-                }
-            }
-            else
+            if (rdn.containsAttributeType(attributeType))
             {
-                if (rdn.getFirst().getType().equals(attributeType))
-                {
-                    res[count++] = rdn;
-                }
+                res[count++] = rdn;
             }
         }
 
-        RDN[] tmp = new RDN[count];
-
-        System.arraycopy(res, 0, tmp, 0, tmp.length);
+        if (count < res.length)
+        {
+            RDN[] tmp = new RDN[count];
+            System.arraycopy(res, 0, tmp, 0, tmp.length);
+            res = tmp;
+        }
 
-        return tmp;
+        return res;
     }
 
     public ASN1Primitive toASN1Primitive()
     {
-        return new DERSequence(rdns);
+        return rdnSeq;
     }
 
     public int hashCode()
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java
index e740685dc..7935f36db 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/AbstractX500NameStyle.java
@@ -44,8 +44,7 @@ public abstract class AbstractX500NameStyle
 
     private int calcHashCode(ASN1Encodable enc)
     {
-        String value = IETFUtils.valueToString(enc);
-        value = IETFUtils.canonicalize(value);
+        String value = IETFUtils.canonicalString(enc);
         return value.hashCode();
     }
 
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/BCStyle.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/BCStyle.java
index ade9bd027..f4537a22b 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/BCStyle.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/BCStyle.java
@@ -43,6 +43,7 @@ public class BCStyle
 
     /**
      * device serial number name - StringType(SIZE(1..64))
+     * @deprecated use SERIALNUMBER or SURNAME
      */
     public static final ASN1ObjectIdentifier SN = new ASN1ObjectIdentifier("2.5.4.5").intern();
 
@@ -54,7 +55,7 @@ public class BCStyle
     /**
      * device serial number name - StringType(SIZE(1..64))
      */
-    public static final ASN1ObjectIdentifier SERIALNUMBER = SN;
+    public static final ASN1ObjectIdentifier SERIALNUMBER = new ASN1ObjectIdentifier("2.5.4.5").intern();
 
     /**
      * locality name - StringType(SIZE(1..64))
@@ -203,7 +204,7 @@ public class BCStyle
         DefaultSymbols.put(CN, "CN");
         DefaultSymbols.put(L, "L");
         DefaultSymbols.put(ST, "ST");
-        DefaultSymbols.put(SN, "SERIALNUMBER");
+        DefaultSymbols.put(SERIALNUMBER, "SERIALNUMBER");
         DefaultSymbols.put(EmailAddress, "E");
         DefaultSymbols.put(DC, "DC");
         DefaultSymbols.put(UID, "UID");
@@ -237,8 +238,8 @@ public class BCStyle
         DefaultLookUp.put("cn", CN);
         DefaultLookUp.put("l", L);
         DefaultLookUp.put("st", ST);
-        DefaultLookUp.put("sn", SN);
-        DefaultLookUp.put("serialnumber", SN);
+        DefaultLookUp.put("sn", SURNAME);
+        DefaultLookUp.put("serialnumber", SERIALNUMBER);
         DefaultLookUp.put("street", STREET);
         DefaultLookUp.put("emailaddress", E);
         DefaultLookUp.put("dc", DC);
@@ -254,7 +255,7 @@ public class BCStyle
         DefaultLookUp.put("dn", DN_QUALIFIER);
         DefaultLookUp.put("pseudonym", PSEUDONYM);
         DefaultLookUp.put("postaladdress", POSTAL_ADDRESS);
-        DefaultLookUp.put("nameofbirth", NAME_AT_BIRTH);
+        DefaultLookUp.put("nameatbirth", NAME_AT_BIRTH);
         DefaultLookUp.put("countryofcitizenship", COUNTRY_OF_CITIZENSHIP);
         DefaultLookUp.put("countryofresidence", COUNTRY_OF_RESIDENCE);
         DefaultLookUp.put("gender", GENDER);
@@ -343,6 +344,4 @@ public class BCStyle
 
         return buf.toString();
     }
-
-
 }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/IETFUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/IETFUtils.java
index 657c7f9bd..0e6068cbf 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/IETFUtils.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x500/style/IETFUtils.java
@@ -359,18 +359,17 @@ public class IETFUtils
             String v = ((ASN1String)value).getString();
             if (v.length() > 0 && v.charAt(0) == '#')
             {
-                vBuf.append("\\" + v);
-            }
-            else
-            {
-                vBuf.append(v);
+                vBuf.append('\\');
             }
+
+            vBuf.append(v);
         }
         else
         {
             try
             {
-                vBuf.append("#" + bytesToString(Hex.encode(value.toASN1Primitive().getEncoded(ASN1Encoding.DER))));
+                vBuf.append('#');
+                vBuf.append(Hex.toHexString(value.toASN1Primitive().getEncoded(ASN1Encoding.DER)));
             }
             catch (IOException e)
             {
@@ -378,8 +377,8 @@ public class IETFUtils
             }
         }
 
-        int     end = vBuf.length();
-        int     index = 0;
+        int end = vBuf.length();
+        int index = 0;
 
         if (vBuf.length() >= 2 && vBuf.charAt(0) == '\\' && vBuf.charAt(1) == '#')
         {
@@ -388,21 +387,28 @@ public class IETFUtils
 
         while (index != end)
         {
-            if ((vBuf.charAt(index) == ',')
-               || (vBuf.charAt(index) == '"')
-               || (vBuf.charAt(index) == '\\')
-               || (vBuf.charAt(index) == '+')
-               || (vBuf.charAt(index) == '=')
-               || (vBuf.charAt(index) == '<')
-               || (vBuf.charAt(index) == '>')
-               || (vBuf.charAt(index) == ';'))
+            switch (vBuf.charAt(index))
             {
-                vBuf.insert(index, "\\");
-                index++;
-                end++;
+                case ',':
+                case '"':
+                case '\\':
+                case '+':
+                case '=':
+                case '<':
+                case '>':
+                case ';':
+                {
+                    vBuf.insert(index, "\\");
+                    index += 2;
+                    ++end;
+                    break;
+                }
+                default:
+                {
+                    ++index;
+                    break;
+                }
             }
-
-            index++;
         }
 
         int start = 0;
@@ -426,63 +432,55 @@ public class IETFUtils
         return vBuf.toString();
     }
 
-    private static String bytesToString(
-        byte[] data)
-    {
-        char[]  cs = new char[data.length];
-
-        for (int i = 0; i != cs.length; i++)
-        {
-            cs[i] = (char)(data[i] & 0xff);
-        }
-
-        return new String(cs);
-    }
-
     public static String canonicalize(String s)
     {
-        String value = Strings.toLowerCase(s);
-
-        if (value.length() > 0 && value.charAt(0) == '#')
+        if (s.length() > 0 && s.charAt(0) == '#')
         {
-            ASN1Primitive obj = decodeObject(value);
-
+            ASN1Primitive obj = decodeObject(s);
             if (obj instanceof ASN1String)
             {
-                value = Strings.toLowerCase(((ASN1String)obj).getString());
+                s = ((ASN1String)obj).getString();
             }
         }
 
-        if (value.length() > 1)
+        s = Strings.toLowerCase(s);
+
+        int length = s.length();
+        if (length < 2)
         {
-            int start = 0;
-            while (start + 1 < value.length() && value.charAt(start) == '\\' && value.charAt(start + 1) == ' ')
-            {
-                start += 2;
-            }
+            return s;
+        }
 
-            int end = value.length() - 1;
-            while (end - 1 > 0 && value.charAt(end - 1) == '\\' && value.charAt(end) == ' ')
-            {
-                end -= 2;
-            }
+        int start = 0, last = length - 1;
+        while (start < last && s.charAt(start) == '\\' && s.charAt(start + 1) == ' ')
+        {
+            start += 2;
+        }
 
-            if (start > 0 || end < value.length() - 1)
-            {
-                value = value.substring(start, end + 1);
-            }
+        int end = last, first = start + 1;
+        while (end > first && s.charAt(end - 1) == '\\' && s.charAt(end) == ' ')
+        {
+            end -= 2;
         }
 
-        value = stripInternalSpaces(value);
+        if (start > 0 || end < last)
+        {
+            s = s.substring(start, end + 1);
+        }
+
+        return stripInternalSpaces(s);
+    }
 
-        return value;
+    public static String canonicalString(ASN1Encodable value)
+    {
+        return canonicalize(valueToString(value));
     }
 
     private static ASN1Primitive decodeObject(String oValue)
     {
         try
         {
-            return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1)));
+            return ASN1Primitive.fromByteArray(Hex.decodeStrict(oValue, 1, oValue.length() - 1));
         }
         catch (IOException e)
         {
@@ -493,21 +491,22 @@ public class IETFUtils
     public static String stripInternalSpaces(
         String str)
     {
-        StringBuffer res = new StringBuffer();
-
-        if (str.length() != 0)
+        if (str.indexOf("  ") < 0)
         {
-            char c1 = str.charAt(0);
+            return str;
+        }
 
-            res.append(c1);
+        StringBuffer res = new StringBuffer();
 
-            for (int k = 1; k < str.length(); k++)
+        char c1 = str.charAt(0);
+        res.append(c1);
+
+        for (int k = 1; k < str.length(); k++)
+        {
+            char c2 = str.charAt(k);
+            if (!(c1 == ' ' && c2 == ' '))
             {
-                char c2 = str.charAt(k);
-                if (!(c1 == ' ' && c2 == ' '))
-                {
-                    res.append(c2);
-                }
+                res.append(c2);
                 c1 = c2;
             }
         }
@@ -517,38 +516,22 @@ public class IETFUtils
 
     public static boolean rDNAreEqual(RDN rdn1, RDN rdn2)
     {
-        if (rdn1.isMultiValued())
+        if (rdn1.size() != rdn2.size())
         {
-            if (rdn2.isMultiValued())
-            {
-                AttributeTypeAndValue[] atvs1 = rdn1.getTypesAndValues();
-                AttributeTypeAndValue[] atvs2 = rdn2.getTypesAndValues();
+            return false;
+        }
 
-                if (atvs1.length != atvs2.length)
-                {
-                    return false;
-                }
+        AttributeTypeAndValue[] atvs1 = rdn1.getTypesAndValues();
+        AttributeTypeAndValue[] atvs2 = rdn2.getTypesAndValues();
 
-                for (int i = 0; i != atvs1.length; i++)
-                {
-                    if (!atvAreEqual(atvs1[i], atvs2[i]))
-                    {
-                        return false;
-                    }
-                }
-            }
-            else
-            {
-                return false;
-            }
+        if (atvs1.length != atvs2.length)
+        {
+            return false;
         }
-        else
+
+        for (int i = 0; i != atvs1.length; i++)
         {
-            if (!rdn2.isMultiValued())
-            {
-                return atvAreEqual(rdn1.getFirst(), rdn2.getFirst());
-            }
-            else
+            if (!atvAreEqual(atvs1[i], atvs2[i]))
             {
                 return false;
             }
@@ -564,12 +547,7 @@ public class IETFUtils
             return true;
         }
 
-        if (atv1 == null)
-        {
-            return false;
-        }
-
-        if (atv2 == null)
+        if (null == atv1 || null == atv2)
         {
             return false;
         }
@@ -582,8 +560,8 @@ public class IETFUtils
             return false;
         }
 
-        String v1 = IETFUtils.canonicalize(IETFUtils.valueToString(atv1.getValue()));
-        String v2 = IETFUtils.canonicalize(IETFUtils.valueToString(atv2.getValue()));
+        String v1 = canonicalString(atv1.getValue());
+        String v2 = canonicalString(atv2.getValue());
 
         if (!v1.equals(v2))
         {
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AccessDescription.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AccessDescription.java
index ea408aa29..35f61a96d 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AccessDescription.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AccessDescription.java
@@ -83,7 +83,7 @@ public class AccessDescription
     
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector accessDescription  = new ASN1EncodableVector();
+        ASN1EncodableVector accessDescription  = new ASN1EncodableVector(2);
         
         accessDescription.add(accessMethod);
         accessDescription.add(accessLocation);
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
index 886e3f0cc..f5388f657 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AlgorithmIdentifier.java
@@ -21,7 +21,7 @@ public class AlgorithmIdentifier
     {
         return getInstance(ASN1Sequence.getInstance(obj, explicit));
     }
-
+    
     public static AlgorithmIdentifier getInstance(
         Object  obj)
     {
@@ -59,7 +59,7 @@ public class AlgorithmIdentifier
             throw new IllegalArgumentException("Bad sequence size: "
                     + seq.size());
         }
-
+        
         algorithm = ASN1ObjectIdentifier.getInstance(seq.getObjectAt(0));
 
         if (seq.size() == 2)
@@ -92,7 +92,7 @@ public class AlgorithmIdentifier
      */
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(2);
 
         v.add(algorithm);
 
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
index e44e3c2ea..6f80ff420 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttCertValidityPeriod.java
@@ -74,7 +74,7 @@ public class AttCertValidityPeriod
      */
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(2);
 
         v.add(notBeforeTime);
         v.add(notAfterTime);
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Attribute.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Attribute.java
index d0c4a9c16..1ce8cb65f 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Attribute.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Attribute.java
@@ -83,7 +83,7 @@ public class Attribute
      */
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(2);
 
         v.add(attrType);
         v.add(attrValues);
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttributeCertificate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttributeCertificate.java
index a6785b0b6..46d50d40b 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttributeCertificate.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttributeCertificate.java
@@ -86,7 +86,7 @@ public class AttributeCertificate
      */
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(3);
 
         v.add(acinfo);
         v.add(signatureAlgorithm);
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
index f3d06c165..e5b1277ef 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AttributeCertificateInfo.java
@@ -152,9 +152,9 @@ public class AttributeCertificateInfo
      */
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(9);
 
-        if (version.getValue().intValue() != 0)
+        if (version.intValueExact() != 0)
         {
             v.add(version);
         }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AuthorityInformationAccess.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AuthorityInformationAccess.java
index 93586d737..32d2fd858 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AuthorityInformationAccess.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AuthorityInformationAccess.java
@@ -99,14 +99,7 @@ public class AuthorityInformationAccess
     
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector vec = new ASN1EncodableVector();
-        
-        for (int i = 0; i != descriptions.length; i++)
-        {
-            vec.add(descriptions[i]);
-        }
-        
-        return new DERSequence(vec);
+        return new DERSequence(descriptions);
     }
 
     public String toString()
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
index 7f77a9195..27d7668c5 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/AuthorityKeyIdentifier.java
@@ -15,6 +15,7 @@ import com.fr.third.org.bouncycastle.asn1.DERSequence;
 import com.fr.third.org.bouncycastle.asn1.DERTaggedObject;
 import com.fr.third.org.bouncycastle.crypto.Digest;
 import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest;
+import com.fr.third.org.bouncycastle.util.encoders.Hex;
 
 /**
  * The AuthorityKeyIdentifier object.
@@ -201,7 +202,7 @@ public class AuthorityKeyIdentifier
      */
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(3);
 
         if (keyidentifier != null)
         {
@@ -218,12 +219,11 @@ public class AuthorityKeyIdentifier
             v.add(new DERTaggedObject(false, 2, certserno));
         }
 
-
         return new DERSequence(v);
     }
 
     public String toString()
     {
-        return ("AuthorityKeyIdentifier: KeyID(" + this.keyidentifier.getOctets() + ")");
+        return ("AuthorityKeyIdentifier: KeyID(" + ((keyidentifier != null) ? Hex.toHexString(this.keyidentifier.getOctets()) : "null") + ")");
     }
 }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/BasicConstraints.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/BasicConstraints.java
index 942a56b42..00eb61ccb 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/BasicConstraints.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/BasicConstraints.java
@@ -133,7 +133,7 @@ public class BasicConstraints
      */
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(2);
 
         if (cA != null)
         {
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CRLDistPoint.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CRLDistPoint.java
index de41e50a4..330ab8db3 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CRLDistPoint.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CRLDistPoint.java
@@ -1,6 +1,5 @@
 package com.fr.third.org.bouncycastle.asn1.x509;
 
-import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector;
 import com.fr.third.org.bouncycastle.asn1.ASN1Object;
 import com.fr.third.org.bouncycastle.asn1.ASN1Primitive;
 import com.fr.third.org.bouncycastle.asn1.ASN1Sequence;
@@ -20,6 +19,11 @@ public class CRLDistPoint
         return getInstance(ASN1Sequence.getInstance(obj, explicit));
     }
 
+    public static CRLDistPoint fromExtensions(Extensions extensions)
+    {
+        return CRLDistPoint.getInstance(extensions.getExtensionParsedValue(Extension.cRLDistributionPoints));
+    }
+
     public static CRLDistPoint getInstance(
         Object  obj)
     {
@@ -44,14 +48,7 @@ public class CRLDistPoint
     public CRLDistPoint(
         DistributionPoint[] points)
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
-
-        for (int i = 0; i != points.length; i++)
-        {
-            v.add(points[i]);
-        }
-
-        seq = new DERSequence(v);
+        seq = new DERSequence(points);
     }
 
     /**
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CRLReason.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CRLReason.java
index a999f9a36..9e0437f44 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CRLReason.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CRLReason.java
@@ -100,7 +100,7 @@ public class CRLReason
         }
         else if (o != null)
         {
-            return lookup(ASN1Enumerated.getInstance(o).getValue().intValue());
+            return lookup(ASN1Enumerated.getInstance(o).intValueExact());
         }
 
         return null;
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificateList.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificateList.java
index 1fbe13994..aa8b5b114 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificateList.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificateList.java
@@ -122,7 +122,7 @@ public class CertificateList
 
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(3);
 
         v.add(tbsCertList);
         v.add(sigAlgId);
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificatePair.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificatePair.java
index 69d8b713c..266f9c166 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificatePair.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificatePair.java
@@ -135,7 +135,7 @@ public class CertificatePair
      */
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector vec = new ASN1EncodableVector();
+        ASN1EncodableVector vec = new ASN1EncodableVector(2);
 
         if (forward != null)
         {
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificatePolicies.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificatePolicies.java
index 638732ca7..d02fbdbba 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificatePolicies.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/CertificatePolicies.java
@@ -60,7 +60,7 @@ public class CertificatePolicies
     public CertificatePolicies(
         PolicyInformation[] policyInformation)
     {
-        this.policyInformation = policyInformation;
+        this.policyInformation = copyPolicyInfo(policyInformation);
     }
 
     private CertificatePolicies(
@@ -76,9 +76,14 @@ public class CertificatePolicies
 
     public PolicyInformation[] getPolicyInformation()
     {
-        PolicyInformation[] tmp = new PolicyInformation[policyInformation.length];
+        return copyPolicyInfo(policyInformation);
+    }
+
+    private PolicyInformation[] copyPolicyInfo(PolicyInformation[] policyInfo)
+    {
+        PolicyInformation[] tmp = new PolicyInformation[policyInfo.length];
 
-        System.arraycopy(policyInformation, 0, tmp, 0, policyInformation.length);
+        System.arraycopy(policyInfo, 0, tmp, 0, policyInfo.length);
 
         return tmp;
     }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DSAParameter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DSAParameter.java
index d036d8ecb..104a8a9ba 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DSAParameter.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DSAParameter.java
@@ -81,7 +81,7 @@ public class DSAParameter
 
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(3);
 
         v.add(p);
         v.add(q);
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DigestInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DigestInfo.java
index 61f1ce894..a42e52753 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DigestInfo.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DigestInfo.java
@@ -77,7 +77,7 @@ public class DigestInfo
 
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(2);
 
         v.add(algId);
         v.add(new DEROctetString(digest));
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DistributionPoint.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DistributionPoint.java
index 5b209d552..431e03c94 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DistributionPoint.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/DistributionPoint.java
@@ -100,7 +100,7 @@ public class DistributionPoint
     
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector  v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(3);
         
         if (distributionPoint != null)
         {
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
index a94569c70..8c539afe1 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ExtendedKeyUsage.java
@@ -110,7 +110,7 @@ public class ExtendedKeyUsage
     public ExtendedKeyUsage(
         KeyPurposeId[]  usages)
     {
-        ASN1EncodableVector v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(usages.length);
 
         for (int i = 0; i != usages.length; i++)
         {
@@ -127,12 +127,12 @@ public class ExtendedKeyUsage
     public ExtendedKeyUsage(
         Vector usages)
     {
-        ASN1EncodableVector v = new ASN1EncodableVector();
-        Enumeration         e = usages.elements();
+        ASN1EncodableVector v = new ASN1EncodableVector(usages.size());
 
+        Enumeration e = usages.elements();
         while (e.hasMoreElements())
         {
-            KeyPurposeId  o = KeyPurposeId.getInstance(e.nextElement());
+            KeyPurposeId o = KeyPurposeId.getInstance(e.nextElement());
 
             v.add(o);
             this.usageTable.put(o, o);
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Extension.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Extension.java
index d0c1c3e36..f54209976 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Extension.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Extension.java
@@ -183,6 +183,13 @@ public class Extension
     private boolean             critical;
     private ASN1OctetString      value;
 
+    /**
+     * Constructor using an ASN1Boolean and an OCTET STRING for the value.
+     *
+     * @param extnId the OID associated with this extension.
+     * @param critical will evaluate to true if the extension is critical, false otherwise.
+     * @param value the extension's value wrapped in an OCTET STRING.
+     */
     public Extension(
         ASN1ObjectIdentifier extnId,
         ASN1Boolean critical,
@@ -191,6 +198,13 @@ public class Extension
         this(extnId, critical.isTrue(), value);
     }
 
+    /**
+     * Constructor using a byte[] for the value.
+     *
+     * @param extnId the OID associated with this extension.
+     * @param critical true if the extension is critical, false otherwise.
+     * @param value the extension's value as a byte[] to be wrapped in an OCTET STRING.
+     */
     public Extension(
         ASN1ObjectIdentifier extnId,
         boolean critical,
@@ -199,6 +213,13 @@ public class Extension
         this(extnId, critical, new DEROctetString(value));
     }
 
+    /**
+     * Constructor using an OCTET STRING for the value.
+     *
+     * @param extnId the OID associated with this extension.
+     * @param critical true if the extension is critical, false otherwise.
+     * @param value the extension's value wrapped in an OCTET STRING.
+     */
     public Extension(
         ASN1ObjectIdentifier extnId,
         boolean critical,
@@ -209,6 +230,24 @@ public class Extension
         this.value = value;
     }
 
+    /**
+     * Helper method to create an extension from any ASN.1 encodable object.
+     *
+     * @param extnId the OID associated with this extension.
+     * @param critical true if the extension is critical, false otherwise.
+     * @param value the value to be encoded into the extension's OCTET STRING.
+     * @return a new Extension with the encoding of value in the bytes of the extension's OCTET STRING.
+     * @throws IOException if the value cannot be encoded into bytes.
+     */
+    public static Extension create(
+        ASN1ObjectIdentifier extnId,
+        boolean critical,
+        ASN1Encodable value)
+        throws IOException
+    {
+        return new Extension(extnId, critical, value.toASN1Primitive().getEncoded());
+    }
+
     private Extension(ASN1Sequence seq)
     {
         if (seq.size() == 2)
@@ -290,7 +329,7 @@ public class Extension
 
     public ASN1Primitive toASN1Primitive()
     {
-        ASN1EncodableVector v = new ASN1EncodableVector();
+        ASN1EncodableVector v = new ASN1EncodableVector(3);
 
         v.add(extnId);
 
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Extensions.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Extensions.java
index 09edf137b..9b5adeacc 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Extensions.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Extensions.java
@@ -13,6 +13,16 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Sequence;
 import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject;
 import com.fr.third.org.bouncycastle.asn1.DERSequence;
 
+/**
+ * 
+ *     Extensions        ::=   SEQUENCE SIZE (1..MAX) OF Extension
+ *
+ *     Extension         ::=   SEQUENCE {
+ *        extnId            EXTENSION.&id ({ExtensionSet}),
+ *        critical          BOOLEAN DEFAULT FALSE,
+ *        extnValue         OCTET STRING }
+ * 
+ */ public class Extensions extends ASN1Object { @@ -145,9 +155,9 @@ public class Extensions */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector vec = new ASN1EncodableVector(); - Enumeration e = ordering.elements(); + ASN1EncodableVector vec = new ASN1EncodableVector(ordering.size()); + Enumeration e = ordering.elements(); while (e.hasMoreElements()) { ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ExtensionsGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ExtensionsGenerator.java index d369c9411..c073ea4b0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ExtensionsGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ExtensionsGenerator.java @@ -82,6 +82,94 @@ public class ExtensionsGenerator extensions.put(extension.getExtnId(), extension); } + /** + * Replace an extension with the given oid and the passed in value to be included + * in the OCTET STRING associated with the extension. + * + * @param oid OID for the extension. + * @param critical true if critical, false otherwise. + * @param value the ASN.1 object to be included in the extension. + */ + public void replaceExtension( + ASN1ObjectIdentifier oid, + boolean critical, + ASN1Encodable value) + throws IOException + { + this.replaceExtension(oid, critical, value.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + + /** + * Replace an extension with the given oid and the passed in byte array to be wrapped in the + * OCTET STRING associated with the extension. + * + * @param oid OID for the extension. + * @param critical true if critical, false otherwise. + * @param value the byte array to be wrapped. + */ + public void replaceExtension( + ASN1ObjectIdentifier oid, + boolean critical, + byte[] value) + { + this.replaceExtension(new Extension(oid, critical, value)); + } + + /** + * Replace a given extension. + * + * @param extension the full extension value. + */ + public void replaceExtension( + Extension extension) + { + if (!extensions.containsKey(extension.getExtnId())) + { + throw new IllegalArgumentException("extension " + extension.getExtnId() + " not present"); + } + + extensions.put(extension.getExtnId(), extension); + } + + /** + * Remove a given extension. + * + * @param oid OID for the extension to remove. + */ + public void removeExtension( + ASN1ObjectIdentifier oid) + { + if (!extensions.containsKey(oid)) + { + throw new IllegalArgumentException("extension " + oid + " not present"); + } + + extOrdering.removeElement(oid); + extensions.remove(oid); + } + + /** + * Return if the extension indicated by OID is present. + * + * @param oid the OID for the extension of interest. + * @return the Extension, or null if it is not present. + */ + public boolean hasExtension(ASN1ObjectIdentifier oid) + { + return extensions.containsKey(oid); + } + + /** + * Return the current value of the extension for OID. + * + * @param oid the OID for the extension we want to fetch. + * @return true if a matching extension is present, false otherwise. + */ + public Extension getExtension(ASN1ObjectIdentifier oid) + { + return (Extension)extensions.get(oid); + } + /** * Return true if there are no extension present in this generator. * diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralName.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralName.java index 7fffaa44d..513824b2b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralName.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralName.java @@ -186,24 +186,25 @@ public class GeneralName switch (tag) { + case ediPartyName: case otherName: + case x400Address: return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false)); - case rfc822Name: - return new GeneralName(tag, DERIA5String.getInstance(tagObj, false)); + case dNSName: + case rfc822Name: + case uniformResourceIdentifier: return new GeneralName(tag, DERIA5String.getInstance(tagObj, false)); - case x400Address: - throw new IllegalArgumentException("unknown tag: " + tag); + case directoryName: return new GeneralName(tag, X500Name.getInstance(tagObj, true)); - case ediPartyName: - return new GeneralName(tag, ASN1Sequence.getInstance(tagObj, false)); - case uniformResourceIdentifier: - return new GeneralName(tag, DERIA5String.getInstance(tagObj, false)); case iPAddress: return new GeneralName(tag, ASN1OctetString.getInstance(tagObj, false)); case registeredID: return new GeneralName(tag, ASN1ObjectIdentifier.getInstance(tagObj, false)); + + default: + throw new IllegalArgumentException("unknown tag: " + tag); } } @@ -427,13 +428,9 @@ public class GeneralName public ASN1Primitive toASN1Primitive() { - if (tag == directoryName) // directoryName is explicitly tagged as it is a CHOICE - { - return new DERTaggedObject(true, tag, obj); - } - else - { - return new DERTaggedObject(false, tag, obj); - } + // directoryName is explicitly tagged as it is a CHOICE + boolean explicit = (tag == directoryName); + + return new DERTaggedObject(explicit, tag, obj); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralNames.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralNames.java index 938e8054a..da760fb04 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralNames.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralNames.java @@ -33,7 +33,7 @@ public class GeneralNames ASN1TaggedObject obj, boolean explicit) { - return getInstance(ASN1Sequence.getInstance(obj, explicit)); + return new GeneralNames(ASN1Sequence.getInstance(obj, explicit)); } public static GeneralNames fromExtensions(Extensions extensions, ASN1ObjectIdentifier extOID) @@ -56,7 +56,7 @@ public class GeneralNames public GeneralNames( GeneralName[] names) { - this.names = names; + this.names = copy(names); } private GeneralNames( @@ -72,9 +72,14 @@ public class GeneralNames public GeneralName[] getNames() { - GeneralName[] tmp = new GeneralName[names.length]; + return copy(names); + } + + private GeneralName[] copy(GeneralName[] nms) + { + GeneralName[] tmp = new GeneralName[nms.length]; - System.arraycopy(names, 0, tmp, 0, names.length); + System.arraycopy(nms, 0, tmp, 0, tmp.length); return tmp; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralSubtree.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralSubtree.java index a6b230b22..5c127d39c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralSubtree.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/GeneralSubtree.java @@ -199,11 +199,11 @@ public class GeneralSubtree */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(base); - if (minimum != null && !minimum.getValue().equals(ZERO)) + if (minimum != null && !minimum.hasValue(ZERO)) { v.add(new DERTaggedObject(false, 0, minimum)); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Holder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Holder.java index 77ebc6fb2..a08a019cb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Holder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/Holder.java @@ -211,7 +211,7 @@ public class Holder { if (version == 1) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (baseCertificateID != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IetfAttrSyntax.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IetfAttrSyntax.java index 96de0a6d1..60240a5fc 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IetfAttrSyntax.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IetfAttrSyntax.java @@ -168,21 +168,23 @@ public class IetfAttrSyntax */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (policyAuthority != null) { v.add(new DERTaggedObject(0, policyAuthority)); } - ASN1EncodableVector v2 = new ASN1EncodableVector(); - - for (Enumeration i = values.elements(); i.hasMoreElements();) { - v2.add((ASN1Encodable)i.nextElement()); - } + ASN1EncodableVector v2 = new ASN1EncodableVector(values.size()); - v.add(new DERSequence(v2)); + for (Enumeration i = values.elements(); i.hasMoreElements();) + { + v2.add((ASN1Encodable)i.nextElement()); + } + + v.add(new DERSequence(v2)); + } return new DERSequence(v); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IssuerSerial.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IssuerSerial.java index bee515eee..fcffebc52 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IssuerSerial.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IssuerSerial.java @@ -108,7 +108,7 @@ public class IssuerSerial */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(issuer); v.add(serial); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java index 6742e283c..4d8cb6c06 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/IssuingDistributionPoint.java @@ -90,7 +90,7 @@ public class IssuingDistributionPoint this.onlyContainsUserCerts = onlyContainsUserCerts; this.onlySomeReasons = onlySomeReasons; - ASN1EncodableVector vec = new ASN1EncodableVector(); + ASN1EncodableVector vec = new ASN1EncodableVector(6); if (distributionPoint != null) { // CHOICE item so explicitly tagged vec.add(new DERTaggedObject(true, 0, distributionPoint)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/NameConstraints.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/NameConstraints.java index a3339be61..2d9f50bd4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/NameConstraints.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/NameConstraints.java @@ -96,7 +96,7 @@ public class NameConstraints */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (permitted != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/NoticeReference.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/NoticeReference.java index 930a9a90b..3e848a2a4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/NoticeReference.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/NoticeReference.java @@ -34,10 +34,9 @@ public class NoticeReference private static ASN1EncodableVector convertVector(Vector numbers) { - ASN1EncodableVector av = new ASN1EncodableVector(); + ASN1EncodableVector av = new ASN1EncodableVector(numbers.size()); Enumeration it = numbers.elements(); - while (it.hasMoreElements()) { Object o = it.nextElement(); @@ -162,7 +161,7 @@ public class NoticeReference */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector av = new ASN1EncodableVector(); + ASN1EncodableVector av = new ASN1EncodableVector(2); av.add (organization); av.add (noticeNumbers); return new DERSequence (av); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ObjectDigestInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ObjectDigestInfo.java index d30581fc1..535cba0ab 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ObjectDigestInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/ObjectDigestInfo.java @@ -173,7 +173,7 @@ public class ObjectDigestInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(4); v.add(digestedObjectType); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/OtherName.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/OtherName.java index 96d170a3d..fd8802b63 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/OtherName.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/OtherName.java @@ -82,7 +82,7 @@ public class OtherName public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(typeID); v.add(new DERTaggedObject(true, 0, value)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java index 264881ce3..c51210c96 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PKIXNameConstraintValidator.java @@ -12,7 +12,10 @@ import java.util.Set; import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.DERIA5String; +import com.fr.third.org.bouncycastle.asn1.x500.RDN; import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.style.IETFUtils; +import com.fr.third.org.bouncycastle.asn1.x500.style.RFC4519Style; import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.Integers; import com.fr.third.org.bouncycastle.util.Strings; @@ -84,7 +87,7 @@ public class PKIXNameConstraintValidator checkPermittedIP(permittedSubtreesIP, ip); break; default: - throw new IllegalStateException("Unknown tag encountered: " + name.getTagNo()); + // other tags to be ignored. } } @@ -123,7 +126,7 @@ public class PKIXNameConstraintValidator checkExcludedIP(excludedSubtreesIP, ip); break; default: - throw new IllegalStateException("Unknown tag encountered: " + name.getTagNo()); + // other tags to be ignored. } } @@ -154,7 +157,7 @@ public class PKIXNameConstraintValidator ((Set)subtreesMap.get(tagNo)).add(subtree); } - for (Iterator it = subtreesMap.entrySet().iterator(); it.hasNext(); ) + for (Iterator it = subtreesMap.entrySet().iterator(); it.hasNext();) { Map.Entry entry = (Map.Entry)it.next(); @@ -296,81 +299,13 @@ public class PKIXNameConstraintValidator && collectionsAreEqual(constraintValidator.permittedSubtreesOtherName, permittedSubtreesOtherName); } - public String toString() - { - String temp = ""; - temp += "permitted:\n"; - if (permittedSubtreesDN != null) - { - temp += "DN:\n"; - temp += permittedSubtreesDN.toString() + "\n"; - } - if (permittedSubtreesDNS != null) - { - temp += "DNS:\n"; - temp += permittedSubtreesDNS.toString() + "\n"; - } - if (permittedSubtreesEmail != null) - { - temp += "Email:\n"; - temp += permittedSubtreesEmail.toString() + "\n"; - } - if (permittedSubtreesURI != null) - { - temp += "URI:\n"; - temp += permittedSubtreesURI.toString() + "\n"; - } - if (permittedSubtreesIP != null) - { - temp += "IP:\n"; - temp += stringifyIPCollection(permittedSubtreesIP) + "\n"; - } - if (permittedSubtreesOtherName != null) - { - temp += "OtherName:\n"; - temp += stringifyOtherNameCollection(permittedSubtreesOtherName) + "\n"; - } - temp += "excluded:\n"; - if (!excludedSubtreesDN.isEmpty()) - { - temp += "DN:\n"; - temp += excludedSubtreesDN.toString() + "\n"; - } - if (!excludedSubtreesDNS.isEmpty()) - { - temp += "DNS:\n"; - temp += excludedSubtreesDNS.toString() + "\n"; - } - if (!excludedSubtreesEmail.isEmpty()) - { - temp += "Email:\n"; - temp += excludedSubtreesEmail.toString() + "\n"; - } - if (!excludedSubtreesURI.isEmpty()) - { - temp += "URI:\n"; - temp += excludedSubtreesURI.toString() + "\n"; - } - if (!excludedSubtreesIP.isEmpty()) - { - temp += "IP:\n"; - temp += stringifyIPCollection(excludedSubtreesIP) + "\n"; - } - if (!excludedSubtreesOtherName.isEmpty()) - { - temp += "OtherName:\n"; - temp += stringifyOtherNameCollection(excludedSubtreesOtherName) + "\n"; - } - return temp; - } - - private void checkPermittedDN(X500Name dns) + public void checkPermittedDN(X500Name dns) throws NameConstraintValidatorException { checkPermittedDN(permittedSubtreesDN, ASN1Sequence.getInstance(dns.toASN1Primitive())); } - private void checkExcludedDN(X500Name dns) + public void checkExcludedDN(X500Name dns) throws NameConstraintValidatorException { checkExcludedDN(excludedSubtreesDN, ASN1Sequence.getInstance(dns)); @@ -390,9 +325,56 @@ public class PKIXNameConstraintValidator return false; } - for (int j = subtree.size() - 1; j >= 0; j--) + int start = 0; + RDN subtreeRdnStart = RDN.getInstance(subtree.getObjectAt(0)); + for (int j = 0; j < dns.size(); j++) { - if (!subtree.getObjectAt(j).equals(dns.getObjectAt(j))) + start = j; + RDN dnsRdn = RDN.getInstance(dns.getObjectAt(j)); + if (dnsRdn.equals(subtreeRdnStart)) + { + break; + } + } + + if (subtree.size() > dns.size() - start) + { + return false; + } + + for (int j = 0; j < subtree.size(); j++) + { + // both subtree and dns are a ASN.1 Name and the elements are a RDN + RDN subtreeRdn = RDN.getInstance(subtree.getObjectAt(j)); + RDN dnsRdn = RDN.getInstance(dns.getObjectAt(start + j)); + + // check if types and values of all naming attributes are matching, other types which are not restricted are allowed, see https://tools.ietf.org/html/rfc5280#section-7.1 + if (subtreeRdn.size() == dnsRdn.size()) + { + // Two relative distinguished names + // RDN1 and RDN2 match if they have the same number of naming attributes + // and for each naming attribute in RDN1 there is a matching naming attribute in RDN2. + // NOTE: this is checking the attributes in the same order, which might be not necessary, if this is a problem also IETFUtils.rDNAreEqual mus tbe changed. + // use new RFC 5280 comparison, NOTE: this is now different from with RFC 3280, where only binary comparison is used + // obey RFC 5280 7.1 + // special treatment of serialNumber for GSMA SGP.22 RSP specification + if (!subtreeRdn.getFirst().getType().equals(dnsRdn.getFirst().getType())) + { + return false; + } + if (subtreeRdn.size() == 1 && subtreeRdn.getFirst().getType().equals(RFC4519Style.serialNumber)) + { + if (!dnsRdn.getFirst().getValue().toString().startsWith(subtreeRdn.getFirst().getValue().toString())) + { + return false; + } + } + else if (!IETFUtils.rDNAreEqual(subtreeRdn, dnsRdn)) + { + return false; + } + } + else { return false; } @@ -454,7 +436,7 @@ public class PKIXNameConstraintValidator private Set intersectDN(Set permitted, Set dns) { Set intersect = new HashSet(); - for (Iterator it = dns.iterator(); it.hasNext(); ) + for (Iterator it = dns.iterator(); it.hasNext();) { ASN1Sequence dn = ASN1Sequence.getInstance(((GeneralSubtree)it .next()).getBase().getName().toASN1Primitive()); @@ -528,17 +510,43 @@ public class PKIXNameConstraintValidator private Set intersectOtherName(Set permitted, Set otherNames) { - Set intersect = new HashSet(permitted); + Set intersect = new HashSet(); + for (Iterator it = otherNames.iterator(); it.hasNext();) + { + Object otName = it.next(); - intersect.retainAll(otherNames); + if (permitted == null) + { + if (otName != null) + { + intersect.add(otName); + } + } + else + { + Iterator it2 = permitted.iterator(); + while (it2.hasNext()) + { + String _permitted = (String)it2.next(); + intersectOtherName(otName, _permitted, intersect); + } + } + } return intersect; } + private void intersectOtherName(Object otName1, Object otName2, Set intersect) + { + if (otName1.equals(otName2)) + { + intersect.add(otName1); + } + } private Set unionOtherName(Set permitted, OtherName otherName) { - Set union = new HashSet(permitted); + Set union = permitted != null ? new HashSet(permitted) : new HashSet(); union.add(otherName); @@ -548,7 +556,7 @@ public class PKIXNameConstraintValidator private Set intersectEmail(Set permitted, Set emails) { Set intersect = new HashSet(); - for (Iterator it = emails.iterator(); it.hasNext(); ) + for (Iterator it = emails.iterator(); it.hasNext();) { String email = extractNameAsString(((GeneralSubtree)it.next()) .getBase()); @@ -614,7 +622,7 @@ public class PKIXNameConstraintValidator private Set intersectIP(Set permitted, Set ips) { Set intersect = new HashSet(); - for (Iterator it = ips.iterator(); it.hasNext(); ) + for (Iterator it = ips.iterator(); it.hasNext();) { byte[] ip = ASN1OctetString.getInstance( ((GeneralSubtree)it.next()).getBase().getName()).getOctets(); @@ -700,7 +708,7 @@ public class PKIXNameConstraintValidator } /** - * Calculates the interesction if two IP ranges. + * Calculates the intersection if two IP ranges. * * @param ipWithSubmask1 The first IP address with its subnet mask. * @param ipWithSubmask2 The second IP address with its subnet mask. @@ -1036,6 +1044,10 @@ public class PKIXNameConstraintValidator { return true; } + if (sub.equalsIgnoreCase(constraint.substring(1))) + { + return true; + } } // on particular host else if (!(constraint.charAt(0) == '.')) @@ -1424,7 +1436,7 @@ public class PKIXNameConstraintValidator private Set intersectDNS(Set permitted, Set dnss) { Set intersect = new HashSet(); - for (Iterator it = dnss.iterator(); it.hasNext(); ) + for (Iterator it = dnss.iterator(); it.hasNext();) { String dns = extractNameAsString(((GeneralSubtree)it.next()) .getBase()); @@ -1623,7 +1635,7 @@ public class PKIXNameConstraintValidator private Set intersectURI(Set permitted, Set uris) { Set intersect = new HashSet(); - for (Iterator it = uris.iterator(); it.hasNext(); ) + for (Iterator it = uris.iterator(); it.hasNext();) { String uri = extractNameAsString(((GeneralSubtree)it.next()) .getBase()); @@ -2046,7 +2058,7 @@ public class PKIXNameConstraintValidator { StringBuilder temp = new StringBuilder(); temp.append("["); - for (Iterator it = ips.iterator(); it.hasNext(); ) + for (Iterator it = ips.iterator(); it.hasNext();) { if (temp.length() > 1) { @@ -2062,7 +2074,7 @@ public class PKIXNameConstraintValidator { StringBuilder temp = new StringBuilder(); temp.append("["); - for (Iterator it = otherNames.iterator(); it.hasNext(); ) + for (Iterator it = otherNames.iterator(); it.hasNext();) { if (temp.length() > 1) { @@ -2083,4 +2095,78 @@ public class PKIXNameConstraintValidator temp.append("]"); return temp.toString(); } + + private final void addLine(StringBuilder sb, String str) + { + sb.append(str).append(Strings.lineSeparator()); + } + + public String toString() + { + StringBuilder temp = new StringBuilder(); + + addLine(temp, "permitted:"); + if (permittedSubtreesDN != null) + { + addLine(temp, "DN:"); + addLine(temp, permittedSubtreesDN.toString()); + } + if (permittedSubtreesDNS != null) + { + addLine(temp, "DNS:"); + addLine(temp, permittedSubtreesDNS.toString()); + } + if (permittedSubtreesEmail != null) + { + addLine(temp, "Email:"); + addLine(temp, permittedSubtreesEmail.toString()); + } + if (permittedSubtreesURI != null) + { + addLine(temp, "URI:"); + addLine(temp, permittedSubtreesURI.toString()); + } + if (permittedSubtreesIP != null) + { + addLine(temp, "IP:"); + addLine(temp, stringifyIPCollection(permittedSubtreesIP)); + } + if (permittedSubtreesOtherName != null) + { + addLine(temp, "OtherName:"); + addLine(temp, stringifyOtherNameCollection(permittedSubtreesOtherName)); + } + addLine(temp, "excluded:"); + if (!excludedSubtreesDN.isEmpty()) + { + addLine(temp, "DN:"); + addLine(temp, excludedSubtreesDN.toString()); + } + if (!excludedSubtreesDNS.isEmpty()) + { + addLine(temp, "DNS:"); + addLine(temp, excludedSubtreesDNS.toString()); + } + if (!excludedSubtreesEmail.isEmpty()) + { + addLine(temp, "Email:"); + addLine(temp, excludedSubtreesEmail.toString()); + } + if (!excludedSubtreesURI.isEmpty()) + { + addLine(temp, "URI:"); + addLine(temp, excludedSubtreesURI.toString()); + } + if (!excludedSubtreesIP.isEmpty()) + { + addLine(temp, "IP:"); + addLine(temp, stringifyIPCollection(excludedSubtreesIP)); + } + if (!excludedSubtreesOtherName.isEmpty()) + { + addLine(temp, "OtherName:"); + addLine(temp, stringifyOtherNameCollection(excludedSubtreesOtherName)); + } + return temp.toString(); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyConstraints.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyConstraints.java index 762ba9366..033037ab8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyConstraints.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyConstraints.java @@ -89,7 +89,7 @@ public class PolicyConstraints public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (requireExplicitPolicyMapping != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyInformation.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyInformation.java index 676fcd79b..eaa139f33 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyInformation.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyInformation.java @@ -75,7 +75,7 @@ public class PolicyInformation */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(policyIdentifier); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyMappings.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyMappings.java index bb4c69547..b3170be73 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyMappings.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyMappings.java @@ -60,14 +60,14 @@ public class PolicyMappings */ public PolicyMappings(Hashtable mappings) { - ASN1EncodableVector dev = new ASN1EncodableVector(); - Enumeration it = mappings.keys(); + ASN1EncodableVector dev = new ASN1EncodableVector(mappings.size()); + Enumeration it = mappings.keys(); while (it.hasMoreElements()) { String idp = (String)it.nextElement(); String sdp = (String)mappings.get(idp); - ASN1EncodableVector dv = new ASN1EncodableVector(); + ASN1EncodableVector dv = new ASN1EncodableVector(2); dv.add(new ASN1ObjectIdentifier(idp)); dv.add(new ASN1ObjectIdentifier(sdp)); dev.add(new DERSequence(dv)); @@ -78,7 +78,7 @@ public class PolicyMappings public PolicyMappings(CertPolicyId issuerDomainPolicy, CertPolicyId subjectDomainPolicy) { - ASN1EncodableVector dv = new ASN1EncodableVector(); + ASN1EncodableVector dv = new ASN1EncodableVector(2); dv.add(issuerDomainPolicy); dv.add(subjectDomainPolicy); @@ -87,11 +87,11 @@ public class PolicyMappings public PolicyMappings(CertPolicyId[] issuerDomainPolicy, CertPolicyId[] subjectDomainPolicy) { - ASN1EncodableVector dev = new ASN1EncodableVector(); + ASN1EncodableVector dev = new ASN1EncodableVector(issuerDomainPolicy.length); for (int i = 0; i != issuerDomainPolicy.length; i++) { - ASN1EncodableVector dv = new ASN1EncodableVector(); + ASN1EncodableVector dv = new ASN1EncodableVector(2); dv.add(issuerDomainPolicy[i]); dv.add(subjectDomainPolicy[i]); dev.add(new DERSequence(dv)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java index 7642b8608..107ab94e4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PolicyQualifierInfo.java @@ -108,7 +108,7 @@ public class PolicyQualifierInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector dev = new ASN1EncodableVector(); + ASN1EncodableVector dev = new ASN1EncodableVector(2); dev.add(policyQualifierId); dev.add(qualifier); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PrivateKeyUsagePeriod.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PrivateKeyUsagePeriod.java index 9e4a0f1c5..50dd5f50e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PrivateKeyUsagePeriod.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/PrivateKeyUsagePeriod.java @@ -68,7 +68,7 @@ public class PrivateKeyUsagePeriod public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (_notBefore != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java index c83f26b20..5e17e13f5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/RSAPublicKeyStructure.java @@ -88,7 +88,7 @@ public class RSAPublicKeyStructure */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(new ASN1Integer(getModulus())); v.add(new ASN1Integer(getPublicExponent())); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/RoleSyntax.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/RoleSyntax.java index c82f67256..20fdc1490 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/RoleSyntax.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/RoleSyntax.java @@ -204,7 +204,7 @@ public class RoleSyntax */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if(this.roleAuthority != null) { v.add(new DERTaggedObject(false, 0, roleAuthority)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/SubjectDirectoryAttributes.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/SubjectDirectoryAttributes.java index a0a0e74bf..95c12a28e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/SubjectDirectoryAttributes.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/SubjectDirectoryAttributes.java @@ -122,12 +122,11 @@ public class SubjectDirectoryAttributes */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector vec = new ASN1EncodableVector(); - Enumeration e = attributes.elements(); + ASN1EncodableVector vec = new ASN1EncodableVector(attributes.size()); + Enumeration e = attributes.elements(); while (e.hasMoreElements()) { - vec.add((Attribute)e.nextElement()); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java index 939b6cf55..6a02be46f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/SubjectPublicKeyInfo.java @@ -144,7 +144,7 @@ public class SubjectPublicKeyInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(algId); v.add(keyData); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertList.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertList.java index 915539b63..b33a4ad4e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertList.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertList.java @@ -217,7 +217,7 @@ public class TBSCertList { return 1; } - return version.getValue().intValue() + 1; + return version.intValueExact() + 1; } public ASN1Integer getVersion() @@ -279,7 +279,7 @@ public class TBSCertList public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(7); if (version != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertificate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertificate.java index 1250629ea..4bad201a3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertificate.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertificate.java @@ -8,7 +8,6 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; import com.fr.third.org.bouncycastle.asn1.DERBitString; -import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; import com.fr.third.org.bouncycastle.asn1.x500.X500Name; /** @@ -92,15 +91,15 @@ public class TBSCertificate boolean isV1 = false; boolean isV2 = false; - if (version.getValue().equals(BigInteger.valueOf(0))) + if (version.hasValue(BigInteger.valueOf(0))) { isV1 = true; } - else if (version.getValue().equals(BigInteger.valueOf(1))) + else if (version.hasValue(BigInteger.valueOf(1))) { isV2 = true; } - else if (!version.getValue().equals(BigInteger.valueOf(2))) + else if (!version.hasValue(BigInteger.valueOf(2))) { throw new IllegalArgumentException("version number not recognised"); } @@ -149,6 +148,9 @@ public class TBSCertificate throw new IllegalArgumentException("version 2 certificate cannot contain extensions"); } extensions = Extensions.getInstance(ASN1Sequence.getInstance(extra, true)); + break; + default: + throw new IllegalArgumentException("Unknown tag encountered in structure: " + extra.getTagNo()); } extras--; } @@ -156,7 +158,7 @@ public class TBSCertificate public int getVersionNumber() { - return version.getValue().intValue() + 1; + return version.intValueExact() + 1; } public ASN1Integer getVersion() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertificateStructure.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertificateStructure.java index 6b5fdccec..b8829a098 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertificateStructure.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/TBSCertificateStructure.java @@ -6,7 +6,6 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; import com.fr.third.org.bouncycastle.asn1.DERBitString; -import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x500.X500Name; @@ -80,7 +79,7 @@ public class TBSCertificateStructure // // some certficates don't include a version number - we assume v1 // - if (seq.getObjectAt(0) instanceof DERTaggedObject) + if (seq.getObjectAt(0) instanceof ASN1TaggedObject) { version = ASN1Integer.getInstance((ASN1TaggedObject)seq.getObjectAt(0), true); } @@ -112,7 +111,7 @@ public class TBSCertificateStructure for (int extras = seq.size() - (seqStart + 6) - 1; extras > 0; extras--) { - DERTaggedObject extra = (DERTaggedObject)seq.getObjectAt(seqStart + 6 + extras); + ASN1TaggedObject extra = ASN1TaggedObject.getInstance(seq.getObjectAt(seqStart + 6 + extras)); switch (extra.getTagNo()) { @@ -130,7 +129,7 @@ public class TBSCertificateStructure public int getVersion() { - return version.getValue().intValue() + 1; + return version.intValueExact() + 1; } public ASN1Integer getVersionNumber() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/UserNotice.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/UserNotice.java index 006644fc7..a705a217a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/UserNotice.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/UserNotice.java @@ -122,7 +122,7 @@ public class UserNotice public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector av = new ASN1EncodableVector(); + ASN1EncodableVector av = new ASN1EncodableVector(2); if (noticeRef != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java index 52b95bc87..9b00ae23a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V1TBSCertificateGenerator.java @@ -118,7 +118,7 @@ public class V1TBSCertificateGenerator throw new IllegalStateException("not all mandatory fields set in V1 TBScertificate generator"); } - ASN1EncodableVector seq = new ASN1EncodableVector(); + ASN1EncodableVector seq = new ASN1EncodableVector(6); // seq.add(version); - not required as default value. seq.add(serialNumber); @@ -128,12 +128,13 @@ public class V1TBSCertificateGenerator // // before and after dates // - ASN1EncodableVector validity = new ASN1EncodableVector(); - - validity.add(startDate); - validity.add(endDate); + { + ASN1EncodableVector validity = new ASN1EncodableVector(2); + validity.add(startDate); + validity.add(endDate); - seq.add(new DERSequence(validity)); + seq.add(new DERSequence(validity)); + } seq.add(subject); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java index 4896611df..d0d00d72b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2AttributeCertificateInfoGenerator.java @@ -126,7 +126,7 @@ public class V2AttributeCertificateInfoGenerator throw new IllegalStateException("not all mandatory fields set in V2 AttributeCertificateInfo generator"); } - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(9); v.add(version); v.add(holder); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2Form.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2Form.java index 1e91c3d39..bd507f9da 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2Form.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2Form.java @@ -135,7 +135,7 @@ public class V2Form */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (issuerName != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java index 9942ed7b3..35ec822de 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V2TBSCertListGenerator.java @@ -132,7 +132,7 @@ public class V2TBSCertListGenerator { if (reason != 0) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); if (reason < reasons.length) { @@ -156,11 +156,8 @@ public class V2TBSCertListGenerator } else if (invalidityDate != null) { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(createInvalidityDateExtension(invalidityDate)); - - internalAddCRLEntry(userCertificate, revocationDate, new DERSequence(v)); + internalAddCRLEntry(userCertificate, revocationDate, + new DERSequence(createInvalidityDateExtension(invalidityDate))); } else { @@ -170,7 +167,7 @@ public class V2TBSCertListGenerator private void internalAddCRLEntry(ASN1Integer userCertificate, Time revocationDate, ASN1Sequence extensions) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(userCertificate); v.add(revocationDate); @@ -185,7 +182,7 @@ public class V2TBSCertListGenerator public void addCRLEntry(ASN1Integer userCertificate, Time revocationDate, Extensions extensions) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(userCertificate); v.add(revocationDate); @@ -217,7 +214,7 @@ public class V2TBSCertListGenerator throw new IllegalStateException("Not all mandatory fields set in V2 TBSCertList generator."); } - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(7); v.add(version); v.add(signature); @@ -245,7 +242,7 @@ public class V2TBSCertListGenerator private static ASN1Sequence createReasonExtension(int reasonCode) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); CRLReason crlReason = CRLReason.lookup(reasonCode); @@ -264,7 +261,7 @@ public class V2TBSCertListGenerator private static ASN1Sequence createInvalidityDateExtension(ASN1GeneralizedTime invalidityDate) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); try { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java index 6dff6471d..caf1292f5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/V3TBSCertificateGenerator.java @@ -164,7 +164,7 @@ public class V3TBSCertificateGenerator throw new IllegalStateException("not all mandatory fields set in V3 TBScertificate generator"); } - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(10); v.add(version); v.add(serialNumber); @@ -174,12 +174,13 @@ public class V3TBSCertificateGenerator // // before and after dates // - ASN1EncodableVector validity = new ASN1EncodableVector(); - - validity.add(startDate); - validity.add(endDate); + { + ASN1EncodableVector validity = new ASN1EncodableVector(2); + validity.add(startDate); + validity.add(endDate); - v.add(new DERSequence(validity)); + v.add(new DERSequence(validity)); + } if (subject != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509Extensions.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509Extensions.java index dc02f9edd..8b2165693 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509Extensions.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509Extensions.java @@ -15,7 +15,7 @@ import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; import com.fr.third.org.bouncycastle.asn1.DERSequence; /** - * @deprecated use Extensions + * @deprecated use {@link Extensions} */ public class X509Extensions extends ASN1Object @@ -385,14 +385,15 @@ public class X509Extensions */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector vec = new ASN1EncodableVector(); - Enumeration e = ordering.elements(); + ASN1EncodableVector vec = new ASN1EncodableVector(ordering.size()); + Enumeration e = ordering.elements(); while (e.hasMoreElements()) { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - X509Extension ext = (X509Extension)extensions.get(oid); - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); + + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + X509Extension ext = (X509Extension)extensions.get(oid); v.add(oid); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509Name.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509Name.java index 31505053b..0a6752dc6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509Name.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509Name.java @@ -926,7 +926,7 @@ public class X509Name for (int i = 0; i != ordering.size(); i++) { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)ordering.elementAt(i); v.add(oid); @@ -943,8 +943,8 @@ public class X509Name else { vec.add(new DERSet(sVec)); + sVec = new ASN1EncodableVector(); - sVec.add(new DERSequence(v)); } @@ -1186,7 +1186,7 @@ public class X509Name { try { - return ASN1Primitive.fromByteArray(Hex.decode(oValue.substring(1))); + return ASN1Primitive.fromByteArray(Hex.decodeStrict(oValue, 1, oValue.length() - 1)); } catch (IOException e) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509NameEntryConverter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509NameEntryConverter.java index a9527fd96..c7aee1a85 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509NameEntryConverter.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/X509NameEntryConverter.java @@ -2,11 +2,10 @@ package com.fr.third.org.bouncycastle.asn1.x509; import java.io.IOException; -import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.DERPrintableString; -import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; /** * It turns out that the number of standard ways the fields in a DN should be @@ -62,36 +61,9 @@ public abstract class X509NameEntryConverter int off) throws IOException { - str = Strings.toLowerCase(str); - byte[] data = new byte[(str.length() - off) / 2]; - for (int index = 0; index != data.length; index++) - { - char left = str.charAt((index * 2) + off); - char right = str.charAt((index * 2) + off + 1); - - if (left < 'a') - { - data[index] = (byte)((left - '0') << 4); - } - else - { - data[index] = (byte)((left - 'a' + 10) << 4); - } - if (right < 'a') - { - data[index] |= (byte)(right - '0'); - } - else - { - data[index] |= (byte)(right - 'a' + 10); - } - } - - ASN1InputStream aIn = new ASN1InputStream(data); - - return aIn.readObject(); + return ASN1Primitive.fromByteArray(Hex.decodeStrict(str, off, str.length() - off)); } - + /** * return true if the passed in String can be represented without * loss as a PrintableString, false otherwise. diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/BiometricData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/BiometricData.java index 8889cc74e..96b1e2de1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/BiometricData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/BiometricData.java @@ -107,7 +107,7 @@ public class BiometricData public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector seq = new ASN1EncodableVector(); + ASN1EncodableVector seq = new ASN1EncodableVector(4); seq.add(typeOfBiometricData); seq.add(hashAlgorithm); seq.add(biometricDataHash); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java index 1cbf783cc..8fc76a0da 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/Iso4217CurrencyCode.java @@ -39,7 +39,7 @@ public class Iso4217CurrencyCode if (obj instanceof ASN1Integer) { ASN1Integer numericobj = ASN1Integer.getInstance(obj); - int numeric = numericobj.getValue().intValue(); + int numeric = numericobj.intValueExact(); return new Iso4217CurrencyCode(numeric); } else @@ -83,7 +83,7 @@ public class Iso4217CurrencyCode public int getNumeric() { - return ((ASN1Integer)obj).getValue().intValue(); + return ((ASN1Integer)obj).intValueExact(); } public ASN1Primitive toASN1Primitive() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java index 3d58a14e8..0201e0d12 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/MonetaryValue.java @@ -82,7 +82,7 @@ public class MonetaryValue public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector seq = new ASN1EncodableVector(); + ASN1EncodableVector seq = new ASN1EncodableVector(3); seq.add(currency); seq.add(amount); seq.add(exponent); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/QCStatement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/QCStatement.java index f7c68ee43..aa856755e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/QCStatement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/QCStatement.java @@ -82,7 +82,7 @@ public class QCStatement public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector seq = new ASN1EncodableVector(); + ASN1EncodableVector seq = new ASN1EncodableVector(2); seq.add(qcStatementId); if (qcStatementInfo != null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java index 4c1fb81a6..c3a27cb0e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/SemanticsInformation.java @@ -110,7 +110,7 @@ public class SemanticsInformation public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector seq = new ASN1EncodableVector(); + ASN1EncodableVector seq = new ASN1EncodableVector(2); if (this.semanticsIdentifier != null) { @@ -118,14 +118,9 @@ public class SemanticsInformation } if (this.nameRegistrationAuthorities != null) { - ASN1EncodableVector seqname = new ASN1EncodableVector(); - for (int i = 0; i < nameRegistrationAuthorities.length; i++) - { - seqname.add(nameRegistrationAuthorities[i]); - } - seq.add(new DERSequence(seqname)); + seq.add(new DERSequence(nameRegistrationAuthorities)); } - + return new DERSequence(seq); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java index 3b95f1f83..8dc61a143 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/qualified/TypeOfBiometricData.java @@ -38,7 +38,7 @@ public class TypeOfBiometricData if (obj instanceof ASN1Integer) { ASN1Integer predefinedBiometricTypeObj = ASN1Integer.getInstance(obj); - int predefinedBiometricType = predefinedBiometricTypeObj.getValue().intValue(); + int predefinedBiometricType = predefinedBiometricTypeObj.intValueExact(); return new TypeOfBiometricData(predefinedBiometricType); } @@ -75,7 +75,7 @@ public class TypeOfBiometricData public int getPredefinedBiometricType() { - return ((ASN1Integer)obj).getValue().intValue(); + return ((ASN1Integer)obj).intValueExact(); } public ASN1ObjectIdentifier getBiometricDataOid() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/sigi/NameOrPseudonym.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/sigi/NameOrPseudonym.java index bf49a9835..02afad88c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/sigi/NameOrPseudonym.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/sigi/NameOrPseudonym.java @@ -179,7 +179,7 @@ public class NameOrPseudonym } else { - ASN1EncodableVector vec1 = new ASN1EncodableVector(); + ASN1EncodableVector vec1 = new ASN1EncodableVector(2); vec1.add(surname); vec1.add(givenName); return new DERSequence(vec1); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/sigi/PersonalData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/sigi/PersonalData.java index 3c04ccc49..bde7cc02d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/sigi/PersonalData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x509/sigi/PersonalData.java @@ -185,7 +185,7 @@ public class PersonalData */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector vec = new ASN1EncodableVector(); + ASN1EncodableVector vec = new ASN1EncodableVector(6); vec.add(nameOrPseudonym); if (nameDistinguisher != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DHDomainParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DHDomainParameters.java index 66d9585fd..31ecca7ca 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DHDomainParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DHDomainParameters.java @@ -146,7 +146,7 @@ public class DHDomainParameters public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); v.add(this.p); v.add(this.g); v.add(this.q); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DHValidationParms.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DHValidationParms.java index 6fd9dba36..432b50088 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DHValidationParms.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DHValidationParms.java @@ -74,7 +74,7 @@ public class DHValidationParms extends ASN1Object public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(this.seed); v.add(this.pgenCounter); return new DERSequence(v); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DomainParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DomainParameters.java index 43df4bb1a..711b79624 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DomainParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/DomainParameters.java @@ -203,7 +203,7 @@ public class DomainParameters */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(5); v.add(this.p); v.add(this.g); v.add(this.q); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/ECNamedCurveTable.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/ECNamedCurveTable.java index 9af8b74cc..09258deb1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/ECNamedCurveTable.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/ECNamedCurveTable.java @@ -10,6 +10,7 @@ import com.fr.third.org.bouncycastle.asn1.gm.GMNamedCurves; import com.fr.third.org.bouncycastle.asn1.nist.NISTNamedCurves; import com.fr.third.org.bouncycastle.asn1.sec.SECNamedCurves; import com.fr.third.org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; +import com.fr.third.org.bouncycastle.crypto.ec.CustomNamedCurves; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; /** @@ -148,6 +149,11 @@ public class ECNamedCurveTable name = GMNamedCurves.getName(oid); } + if (name == null) + { + name = CustomNamedCurves.getName(oid); + } + return name; } @@ -225,6 +231,6 @@ public class ECNamedCurveTable private static X9ECParameters fromDomainParameters(ECDomainParameters dp) { - return dp == null ? null : new X9ECParameters(dp.getCurve(), dp.getG(), dp.getN(), dp.getH(), dp.getSeed()); + return dp == null ? null : new X9ECParameters(dp.getCurve(), new X9ECPoint(dp.getG(), false), dp.getN(), dp.getH(), dp.getSeed()); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/KeySpecificInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/KeySpecificInfo.java index 07903e941..561f9884c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/KeySpecificInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/KeySpecificInfo.java @@ -92,15 +92,15 @@ public class KeySpecificInfo /** * Return an ASN.1 primitive representation of this object. * - * @return a DERSequence containing the parameter values. + * @return a DERSequence containing the KeySpecificInfo values. */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(algorithm); v.add(counter); return new DERSequence(v); } -} \ No newline at end of file +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/OtherInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/OtherInfo.java index 04f2ecb4b..5de957921 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/OtherInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/OtherInfo.java @@ -118,7 +118,7 @@ public class OtherInfo */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); v.add(keyInfo); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/ValidationParams.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/ValidationParams.java index 8580247e7..29f370f49 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/ValidationParams.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/ValidationParams.java @@ -94,7 +94,7 @@ public class ValidationParams public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(this.seed); v.add(this.pgenCounter); return new DERSequence(v); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X962NamedCurves.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X962NamedCurves.java index 677dfe8b9..04a94c5aa 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X962NamedCurves.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X962NamedCurves.java @@ -6,6 +6,7 @@ import java.util.Hashtable; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.WNafUtil; import com.fr.third.org.bouncycastle.util.Strings; import com.fr.third.org.bouncycastle.util.encoders.Hex; @@ -15,25 +16,40 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; */ public class X962NamedCurves { + private static X9ECPoint configureBasepoint(ECCurve curve, String encoding) + { + X9ECPoint G = new X9ECPoint(curve, Hex.decodeStrict(encoding)); + WNafUtil.configureBasepoint(G.getPoint()); + return G; + } + + private static ECCurve configureCurve(ECCurve curve) + { + return curve; + } + + private static BigInteger fromHex(String hex) + { + return new BigInteger(1, Hex.decodeStrict(hex)); + } + static X9ECParametersHolder prime192v1 = new X9ECParametersHolder() { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("ffffffffffffffffffffffff99def836146bc9b1b4d22831", 16); + BigInteger n = fromHex("ffffffffffffffffffffffff99def836146bc9b1b4d22831"); BigInteger h = BigInteger.valueOf(1); - ECCurve cFp192v1 = new ECCurve.Fp( - new BigInteger("6277101735386680763835789423207666416083908700390324961279"), - new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), - new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), - n, h); - - return new X9ECParameters( - cFp192v1, - new X9ECPoint(cFp192v1, - Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), - n, h, - Hex.decode("3045AE6FC8422f64ED579528D38120EAE12196D5")); + ECCurve curve = configureCurve(new ECCurve.Fp( + fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"), + fromHex("fffffffffffffffffffffffffffffffefffffffffffffffc"), + fromHex("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"); + + return new X9ECParameters(curve, G, n, h, Hex.decodeStrict("3045AE6FC8422f64ED579528D38120EAE12196D5")); } }; @@ -41,21 +57,19 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31", 16); + BigInteger n = fromHex("fffffffffffffffffffffffe5fb1a724dc80418648d8dd31"); BigInteger h = BigInteger.valueOf(1); - ECCurve cFp192v2 = new ECCurve.Fp( - new BigInteger("6277101735386680763835789423207666416083908700390324961279"), - new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), - new BigInteger("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953", 16), - n, h); - - return new X9ECParameters( - cFp192v2, - new X9ECPoint(cFp192v2, - Hex.decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")), - n, h, - Hex.decode("31a92ee2029fd10d901b113e990710f0d21ac6b6")); + ECCurve curve = configureCurve(new ECCurve.Fp( + fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"), + fromHex("fffffffffffffffffffffffffffffffefffffffffffffffc"), + fromHex("cc22d6dfb95c6b25e49c0d6364a4e5980c393aa21668d953"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a"); + + return new X9ECParameters(curve, G, n, h, Hex.decodeStrict("31a92ee2029fd10d901b113e990710f0d21ac6b6")); } }; @@ -63,21 +77,19 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("ffffffffffffffffffffffff7a62d031c83f4294f640ec13", 16); + BigInteger n = fromHex("ffffffffffffffffffffffff7a62d031c83f4294f640ec13"); BigInteger h = BigInteger.valueOf(1); - ECCurve cFp192v3 = new ECCurve.Fp( - new BigInteger("6277101735386680763835789423207666416083908700390324961279"), - new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), - new BigInteger("22123dc2395a05caa7423daeccc94760a7d462256bd56916", 16), - n, h); - - return new X9ECParameters( - cFp192v3, - new X9ECPoint(cFp192v3, - Hex.decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")), - n, h, - Hex.decode("c469684435deb378c4b65ca9591e2a5763059a2e")); + ECCurve curve = configureCurve(new ECCurve.Fp( + fromHex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF"), + fromHex("fffffffffffffffffffffffffffffffefffffffffffffffc"), + fromHex("22123dc2395a05caa7423daeccc94760a7d462256bd56916"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "027d29778100c65a1da1783716588dce2b8b4aee8e228f1896"); + + return new X9ECParameters(curve, G, n, h, Hex.decodeStrict("c469684435deb378c4b65ca9591e2a5763059a2e")); } }; @@ -85,21 +97,19 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b", 16); + BigInteger n = fromHex("7fffffffffffffffffffffff7fffff9e5e9a9f5d9071fbd1522688909d0b"); BigInteger h = BigInteger.valueOf(1); - ECCurve cFp239v1 = new ECCurve.Fp( + ECCurve curve = configureCurve(new ECCurve.Fp( new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), - new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), - n, h); - - return new X9ECParameters( - cFp239v1, - new X9ECPoint(cFp239v1, - Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), - n, h, - Hex.decode("e43bb460f0b80cc0c0b075798e948060f8321b7d")); + fromHex("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc"), + fromHex("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf"); + + return new X9ECParameters(curve, G, n, h, Hex.decodeStrict("e43bb460f0b80cc0c0b075798e948060f8321b7d")); } }; @@ -107,21 +117,19 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063", 16); + BigInteger n = fromHex("7fffffffffffffffffffffff800000cfa7e8594377d414c03821bc582063"); BigInteger h = BigInteger.valueOf(1); - ECCurve cFp239v2 = new ECCurve.Fp( + ECCurve curve = configureCurve(new ECCurve.Fp( new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), - new BigInteger("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c", 16), - n, h); - - return new X9ECParameters( - cFp239v2, - new X9ECPoint(cFp239v2, - Hex.decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")), - n, h, - Hex.decode("e8b4011604095303ca3b8099982be09fcb9ae616")); + fromHex("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc"), + fromHex("617fab6832576cbbfed50d99f0249c3fee58b94ba0038c7ae84c8c832f2c"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7"); + + return new X9ECParameters(curve, G, n, h, Hex.decodeStrict("e8b4011604095303ca3b8099982be09fcb9ae616")); } }; @@ -129,21 +137,19 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551", 16); + BigInteger n = fromHex("7fffffffffffffffffffffff7fffff975deb41b3a6057c3c432146526551"); BigInteger h = BigInteger.valueOf(1); - ECCurve cFp239v3 = new ECCurve.Fp( + ECCurve curve = configureCurve(new ECCurve.Fp( new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), - new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), - new BigInteger("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e", 16), - n, h); - - return new X9ECParameters( - cFp239v3, - new X9ECPoint(cFp239v3, - Hex.decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")), - n, h, - Hex.decode("7d7374168ffe3471b60a857686a19475d3bfa2ff")); + fromHex("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc"), + fromHex("255705fa2a306654b1f4cb03d6a750a30c250102d4988717d9ba15ab6d3e"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a"); + + return new X9ECParameters(curve, G, n, h, Hex.decodeStrict("7d7374168ffe3471b60a857686a19475d3bfa2ff")); } }; @@ -151,21 +157,19 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger n = new BigInteger("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551", 16); + BigInteger n = fromHex("ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551"); BigInteger h = BigInteger.valueOf(1); - ECCurve cFp256v1 = new ECCurve.Fp( + ECCurve curve = configureCurve(new ECCurve.Fp( new BigInteger("115792089210356248762697446949407573530086143415290314195533631308867097853951"), - new BigInteger("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc", 16), - new BigInteger("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b", 16), - n, h); - - return new X9ECParameters( - cFp256v1, - new X9ECPoint(cFp256v1, - Hex.decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")), - n, h, - Hex.decode("c49d360886e704936a6678e1139d26b7819f7e90")); + fromHex("ffffffff00000001000000000000000000000000fffffffffffffffffffffffc"), + fromHex("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"); + + return new X9ECParameters(curve, G, n, h, Hex.decodeStrict("c49d360886e704936a6678e1139d26b7819f7e90")); } }; @@ -176,22 +180,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m163v1n = new BigInteger("0400000000000000000001E60FC8821CC74DAEAFC1", 16); - BigInteger c2m163v1h = BigInteger.valueOf(2); + BigInteger n = fromHex("0400000000000000000001E60FC8821CC74DAEAFC1"); + BigInteger h = BigInteger.valueOf(2); - ECCurve c2m163v1 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 163, 1, 2, 8, - new BigInteger("072546B5435234A422E0789675F432C89435DE5242", 16), - new BigInteger("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", 16), - c2m163v1n, c2m163v1h); - - return new X9ECParameters( - c2m163v1, - new X9ECPoint(c2m163v1, - Hex.decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")), - c2m163v1n, c2m163v1h, - Hex.decode("D2C0FB15760860DEF1EEF4D696E6768756151754")); + fromHex("072546B5435234A422E0789675F432C89435DE5242"), + fromHex("00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "0307AF69989546103D79329FCC3D74880F33BBE803CB"); + + return new X9ECParameters(curve, G, n, h, Hex.decodeStrict("D2C0FB15760860DEF1EEF4D696E6768756151754")); } }; @@ -199,22 +201,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m163v2n = new BigInteger("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 16); - BigInteger c2m163v2h = BigInteger.valueOf(2); + BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7"); + BigInteger h = BigInteger.valueOf(2); - ECCurve c2m163v2 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 163, 1, 2, 8, - new BigInteger("0108B39E77C4B108BED981ED0E890E117C511CF072", 16), - new BigInteger("0667ACEB38AF4E488C407433FFAE4F1C811638DF20", 16), - c2m163v2n, c2m163v2h); - - return new X9ECParameters( - c2m163v2, - new X9ECPoint(c2m163v2, - Hex.decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")), - c2m163v2n, c2m163v2h, - null); + fromHex("0108B39E77C4B108BED981ED0E890E117C511CF072"), + fromHex("0667ACEB38AF4E488C407433FFAE4F1C811638DF20"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "030024266E4EB5106D0A964D92C4860E2671DB9B6CC5"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -222,22 +222,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m163v3n = new BigInteger("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 16); - BigInteger c2m163v3h = BigInteger.valueOf(2); + BigInteger n = fromHex("03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309"); + BigInteger h = BigInteger.valueOf(2); - ECCurve c2m163v3 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 163, 1, 2, 8, - new BigInteger("07A526C63D3E25A256A007699F5447E32AE456B50E", 16), - new BigInteger("03F7061798EB99E238FD6F1BF95B48FEEB4854252B", 16), - c2m163v3n, c2m163v3h); - - return new X9ECParameters( - c2m163v3, - new X9ECPoint(c2m163v3, - Hex.decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")), - c2m163v3n, c2m163v3h, - null); + fromHex("07A526C63D3E25A256A007699F5447E32AE456B50E"), + fromHex("03F7061798EB99E238FD6F1BF95B48FEEB4854252B"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -245,22 +243,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m176w1n = new BigInteger("010092537397ECA4F6145799D62B0A19CE06FE26AD", 16); - BigInteger c2m176w1h = BigInteger.valueOf(0xFF6E); + BigInteger n = fromHex("010092537397ECA4F6145799D62B0A19CE06FE26AD"); + BigInteger h = BigInteger.valueOf(0xFF6E); - ECCurve c2m176w1 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 176, 1, 2, 43, - new BigInteger("00E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", 16), - new BigInteger("005DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", 16), - c2m176w1n, c2m176w1h); - - return new X9ECParameters( - c2m176w1, - new X9ECPoint(c2m176w1, - Hex.decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")), - c2m176w1n, c2m176w1h, - null); + fromHex("E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B"), + fromHex("5DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "038D16C2866798B600F9F08BB4A8E860F3298CE04A5798"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -268,22 +264,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m191v1n = new BigInteger("40000000000000000000000004A20E90C39067C893BBB9A5", 16); - BigInteger c2m191v1h = BigInteger.valueOf(2); + BigInteger n = fromHex("40000000000000000000000004A20E90C39067C893BBB9A5"); + BigInteger h = BigInteger.valueOf(2); - ECCurve c2m191v1 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 191, 9, - new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16), - new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16), - c2m191v1n, c2m191v1h); - - return new X9ECParameters( - c2m191v1, - new X9ECPoint(c2m191v1, - Hex.decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")), - c2m191v1n, c2m191v1h, - Hex.decode("4E13CA542744D696E67687561517552F279A8C84")); + fromHex("2866537B676752636A68F56554E12640276B649EF7526267"), + fromHex("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D"); + + return new X9ECParameters(curve, G, n, h, Hex.decodeStrict("4E13CA542744D696E67687561517552F279A8C84")); } }; @@ -291,22 +285,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m191v2n = new BigInteger("20000000000000000000000050508CB89F652824E06B8173", 16); - BigInteger c2m191v2h = BigInteger.valueOf(4); + BigInteger n = fromHex("20000000000000000000000050508CB89F652824E06B8173"); + BigInteger h = BigInteger.valueOf(4); - ECCurve c2m191v2 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 191, 9, - new BigInteger("401028774D7777C7B7666D1366EA432071274F89FF01E718", 16), - new BigInteger("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", 16), - c2m191v2n, c2m191v2h); - - return new X9ECParameters( - c2m191v2, - new X9ECPoint(c2m191v2, - Hex.decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")), - c2m191v2n, c2m191v2h, - null); + fromHex("401028774D7777C7B7666D1366EA432071274F89FF01E718"), + fromHex("0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -314,22 +306,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m191v3n = new BigInteger("155555555555555555555555610C0B196812BFB6288A3EA3", 16); - BigInteger c2m191v3h = BigInteger.valueOf(6); + BigInteger n = fromHex("155555555555555555555555610C0B196812BFB6288A3EA3"); + BigInteger h = BigInteger.valueOf(6); - ECCurve c2m191v3 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 191, 9, - new BigInteger("6C01074756099122221056911C77D77E77A777E7E7E77FCB", 16), - new BigInteger("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", 16), - c2m191v3n, c2m191v3h); - - return new X9ECParameters( - c2m191v3, - new X9ECPoint(c2m191v3, - Hex.decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")), - c2m191v3n, c2m191v3h, - null); + fromHex("6C01074756099122221056911C77D77E77A777E7E7E77FCB"), + fromHex("71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "03375D4CE24FDE434489DE8746E71786015009E66E38A926DD"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -337,22 +327,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m208w1n = new BigInteger("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 16); - BigInteger c2m208w1h = BigInteger.valueOf(0xFE48); + BigInteger n = fromHex("0101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D"); + BigInteger h = BigInteger.valueOf(0xFE48); - ECCurve c2m208w1 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 208, 1, 2, 83, - new BigInteger("0", 16), - new BigInteger("00C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", 16), - c2m208w1n, c2m208w1h); - - return new X9ECParameters( - c2m208w1, - new X9ECPoint(c2m208w1, - Hex.decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")), - c2m208w1n, c2m208w1h, - null); + BigInteger.valueOf(0), + fromHex("C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -360,22 +348,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m239v1n = new BigInteger("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 16); - BigInteger c2m239v1h = BigInteger.valueOf(4); + BigInteger n = fromHex("2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447"); + BigInteger h = BigInteger.valueOf(4); - ECCurve c2m239v1 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 239, 36, - new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), - new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16), - c2m239v1n, c2m239v1h); - - return new X9ECParameters( - c2m239v1, - new X9ECPoint(c2m239v1, - Hex.decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")), - c2m239v1n, c2m239v1h, - null); + fromHex("32010857077C5431123A46B808906756F543423E8D27877578125778AC76"), + fromHex("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -383,22 +369,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m239v2n = new BigInteger("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 16); - BigInteger c2m239v2h = BigInteger.valueOf(6); + BigInteger n = fromHex("1555555555555555555555555555553C6F2885259C31E3FCDF154624522D"); + BigInteger h = BigInteger.valueOf(6); - ECCurve c2m239v2 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 239, 36, - new BigInteger("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", 16), - new BigInteger("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", 16), - c2m239v2n, c2m239v2h); - - return new X9ECParameters( - c2m239v2, - new X9ECPoint(c2m239v2, - Hex.decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")), - c2m239v2n, c2m239v2h, - null); + fromHex("4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F"), + fromHex("5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -406,22 +390,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m239v3n = new BigInteger("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 16); - BigInteger c2m239v3h = BigInteger.valueOf(10); + BigInteger n = fromHex("0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF"); + BigInteger h = BigInteger.valueOf(10); - ECCurve c2m239v3 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 239, 36, - new BigInteger("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", 16), - new BigInteger("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", 16), - c2m239v3n, c2m239v3h); - - return new X9ECParameters( - c2m239v3, - new X9ECPoint(c2m239v3, - Hex.decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")), - c2m239v3n, c2m239v3h, - null); + fromHex("01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F"), + fromHex("6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -429,22 +411,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m272w1n = new BigInteger("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", 16); - BigInteger c2m272w1h = BigInteger.valueOf(0xFF06); + BigInteger n = fromHex("0100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521"); + BigInteger h = BigInteger.valueOf(0xFF06); - ECCurve c2m272w1 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 272, 1, 3, 56, - new BigInteger("0091A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", 16), - new BigInteger("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", 16), - c2m272w1n, c2m272w1h); - - return new X9ECParameters( - c2m272w1, - new X9ECPoint(c2m272w1, - Hex.decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")), - c2m272w1n, c2m272w1h, - null); + fromHex("91A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20"), + fromHex("7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -452,22 +432,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m304w1n = new BigInteger("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", 16); - BigInteger c2m304w1h = BigInteger.valueOf(0xFE2E); + BigInteger n = fromHex("0101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D"); + BigInteger h = BigInteger.valueOf(0xFE2E); - ECCurve c2m304w1 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 304, 1, 2, 11, - new BigInteger("00FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", 16), - new BigInteger("00BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", 16), - c2m304w1n, c2m304w1h); - - return new X9ECParameters( - c2m304w1, - new X9ECPoint(c2m304w1, - Hex.decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")), - c2m304w1n, c2m304w1h, - null); + fromHex("FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681"), + fromHex("BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -475,22 +453,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m359v1n = new BigInteger("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", 16); - BigInteger c2m359v1h = BigInteger.valueOf(0x4C); + BigInteger n = fromHex("01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B"); + BigInteger h = BigInteger.valueOf(0x4C); - ECCurve c2m359v1 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 359, 68, - new BigInteger("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", 16), - new BigInteger("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", 16), - c2m359v1n, c2m359v1h); - - return new X9ECParameters( - c2m359v1, - new X9ECPoint(c2m359v1, - Hex.decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")), - c2m359v1n, c2m359v1h, - null); + fromHex("5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557"), + fromHex("2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -498,22 +474,20 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m368w1n = new BigInteger("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", 16); - BigInteger c2m368w1h = BigInteger.valueOf(0xFF70); + BigInteger n = fromHex("010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967"); + BigInteger h = BigInteger.valueOf(0xFF70); - ECCurve c2m368w1 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 368, 1, 2, 85, - new BigInteger("00E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", 16), - new BigInteger("00FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", 16), - c2m368w1n, c2m368w1h); - - return new X9ECParameters( - c2m368w1, - new X9ECPoint(c2m368w1, - Hex.decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")), - c2m368w1n, c2m368w1h, - null); + fromHex("E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D"), + fromHex("FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F"); + + return new X9ECParameters(curve, G, n, h); } }; @@ -521,25 +495,24 @@ public class X962NamedCurves { protected X9ECParameters createParameters() { - BigInteger c2m431r1n = new BigInteger("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", 16); - BigInteger c2m431r1h = BigInteger.valueOf(0x2760); + BigInteger n = fromHex("0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91"); + BigInteger h = BigInteger.valueOf(0x2760); - ECCurve c2m431r1 = new ECCurve.F2m( + ECCurve curve = configureCurve(new ECCurve.F2m( 431, 120, - new BigInteger("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", 16), - new BigInteger("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", 16), - c2m431r1n, c2m431r1h); - - return new X9ECParameters( - c2m431r1, - new X9ECPoint(c2m431r1, - Hex.decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")), - c2m431r1n, c2m431r1h, - null); + fromHex("1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F"), + fromHex("10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618"), + n, h)); + + X9ECPoint G = configureBasepoint(curve, + "02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7"); + + return new X9ECParameters(curve, G, n, h); } }; + static final Hashtable objIds = new Hashtable(); static final Hashtable curves = new Hashtable(); static final Hashtable names = new Hashtable(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X962Parameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X962Parameters.java index 0936d2742..f7251dfc6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X962Parameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X962Parameters.java @@ -1,7 +1,5 @@ package com.fr.third.org.bouncycastle.asn1.x9; -import java.io.IOException; - import com.fr.third.org.bouncycastle.asn1.ASN1Choice; import com.fr.third.org.bouncycastle.asn1.ASN1Null; import com.fr.third.org.bouncycastle.asn1.ASN1Object; @@ -71,11 +69,7 @@ public class X962Parameters this.params = obj; } - /** - * @deprecated use getInstance() - */ - public X962Parameters( - ASN1Primitive obj) + private X962Parameters(ASN1Primitive obj) { this.params = obj; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9Curve.java index 3492f84b5..55725ad28 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9Curve.java @@ -13,6 +13,7 @@ import com.fr.third.org.bouncycastle.asn1.DERBitString; import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.math.ec.ECAlgorithms; import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.Arrays; /** * ASN.1 def for Elliptic-Curve Curve structure. See @@ -29,9 +30,7 @@ public class X9Curve public X9Curve( ECCurve curve) { - this.curve = curve; - this.seed = null; - setFieldIdentifier(); + this(curve, null); } public X9Curve( @@ -39,20 +38,10 @@ public class X9Curve byte[] seed) { this.curve = curve; - this.seed = seed; + this.seed = Arrays.clone(seed); setFieldIdentifier(); } - /** - * @deprecated use constructor including order/cofactor - */ - public X9Curve( - X9FieldID fieldID, - ASN1Sequence seq) - { - this(fieldID, null, null, seq); - } - public X9Curve( X9FieldID fieldID, BigInteger order, @@ -71,10 +60,8 @@ public class X9Curve { // Characteristic two field ASN1Sequence parameters = ASN1Sequence.getInstance(fieldID.getParameters()); - int m = ((ASN1Integer)parameters.getObjectAt(0)).getValue(). - intValue(); - ASN1ObjectIdentifier representation - = (ASN1ObjectIdentifier)parameters.getObjectAt(1); + int m = ((ASN1Integer)parameters.getObjectAt(0)).intValueExact(); + ASN1ObjectIdentifier representation = (ASN1ObjectIdentifier)parameters.getObjectAt(1); int k1 = 0; int k2 = 0; @@ -83,15 +70,15 @@ public class X9Curve if (representation.equals(tpBasis)) { // Trinomial basis representation - k1 = ASN1Integer.getInstance(parameters.getObjectAt(2)).getValue().intValue(); + k1 = ASN1Integer.getInstance(parameters.getObjectAt(2)).intValueExact(); } else if (representation.equals(ppBasis)) { // Pentanomial basis representation ASN1Sequence pentanomial = ASN1Sequence.getInstance(parameters.getObjectAt(2)); - k1 = ASN1Integer.getInstance(pentanomial.getObjectAt(0)).getValue().intValue(); - k2 = ASN1Integer.getInstance(pentanomial.getObjectAt(1)).getValue().intValue(); - k3 = ASN1Integer.getInstance(pentanomial.getObjectAt(2)).getValue().intValue(); + k1 = ASN1Integer.getInstance(pentanomial.getObjectAt(0)).intValueExact(); + k2 = ASN1Integer.getInstance(pentanomial.getObjectAt(1)).intValueExact(); + k3 = ASN1Integer.getInstance(pentanomial.getObjectAt(2)).intValueExact(); } else { @@ -135,7 +122,7 @@ public class X9Curve public byte[] getSeed() { - return seed; + return Arrays.clone(seed); } /** @@ -150,7 +137,7 @@ public class X9Curve */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(3); if (fieldIdentifier.equals(prime_field)) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECParameters.java index ca1e516a0..bfc1ef02e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECParameters.java @@ -13,6 +13,7 @@ import com.fr.third.org.bouncycastle.math.ec.ECAlgorithms; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECPoint; import com.fr.third.org.bouncycastle.math.field.PolynomialExtensionField; +import com.fr.third.org.bouncycastle.util.Arrays; /** * ASN.1 def for Elliptic-Curve ECParameters structure. See @@ -35,7 +36,7 @@ public class X9ECParameters ASN1Sequence seq) { if (!(seq.getObjectAt(0) instanceof ASN1Integer) - || !((ASN1Integer)seq.getObjectAt(0)).getValue().equals(ONE)) + || !((ASN1Integer)seq.getObjectAt(0)).hasValue(ONE)) { throw new IllegalArgumentException("bad version in X9ECParameters"); } @@ -83,7 +84,7 @@ public class X9ECParameters public X9ECParameters( ECCurve curve, - ECPoint g, + X9ECPoint g, BigInteger n) { this(curve, g, n, null, null); @@ -91,32 +92,13 @@ public class X9ECParameters public X9ECParameters( ECCurve curve, - X9ECPoint g, - BigInteger n, - BigInteger h) - { - this(curve, g, n, h, null); - } - - public X9ECParameters( - ECCurve curve, - ECPoint g, + X9ECPoint g, BigInteger n, BigInteger h) { this(curve, g, n, h, null); } - public X9ECParameters( - ECCurve curve, - ECPoint g, - BigInteger n, - BigInteger h, - byte[] seed) - { - this(curve, new X9ECPoint(g), n, h, seed); - } - public X9ECParameters( ECCurve curve, X9ECPoint g, @@ -128,7 +110,7 @@ public class X9ECParameters this.g = g; this.n = n; this.h = h; - this.seed = seed; + this.seed = Arrays.clone(seed); if (ECAlgorithms.isFpCurve(curve)) { @@ -179,7 +161,12 @@ public class X9ECParameters public byte[] getSeed() { - return seed; + return Arrays.clone(seed); + } + + public boolean hasSeed() + { + return null != seed; } /** @@ -227,7 +214,7 @@ public class X9ECParameters */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(6); v.add(new ASN1Integer(ONE)); v.add(fieldID); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECParametersHolder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECParametersHolder.java index 29efc5268..aacda4e95 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECParametersHolder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECParametersHolder.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.asn1.x9; +/** + * A holding class that allows for X9ECParameters to be lazily constructed. + */ public abstract class X9ECParametersHolder { private X9ECParameters params; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECPoint.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECPoint.java index bb8f6bb03..b116615ec 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECPoint.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ECPoint.java @@ -9,7 +9,7 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint; import com.fr.third.org.bouncycastle.util.Arrays; /** - * class for describing an ECPoint as a DER object. + * Class for describing an ECPoint as a DER object. */ public class X9ECPoint extends ASN1Object @@ -19,12 +19,6 @@ public class X9ECPoint private ECCurve c; private ECPoint p; - public X9ECPoint( - ECPoint p) - { - this(p, false); - } - public X9ECPoint( ECPoint p, boolean compressed) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9FieldID.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9FieldID.java index 123aa386a..0020fbdcf 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9FieldID.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9FieldID.java @@ -64,7 +64,7 @@ public class X9FieldID public X9FieldID(int m, int k1, int k2, int k3) { this.id = characteristic_two_field; - ASN1EncodableVector fieldIdParams = new ASN1EncodableVector(); + ASN1EncodableVector fieldIdParams = new ASN1EncodableVector(3); fieldIdParams.add(new ASN1Integer(m)); if (k2 == 0) @@ -85,7 +85,7 @@ public class X9FieldID } fieldIdParams.add(ppBasis); - ASN1EncodableVector pentanomialParams = new ASN1EncodableVector(); + ASN1EncodableVector pentanomialParams = new ASN1EncodableVector(3); pentanomialParams.add(new ASN1Integer(k1)); pentanomialParams.add(new ASN1Integer(k2)); pentanomialParams.add(new ASN1Integer(k3)); @@ -138,7 +138,7 @@ public class X9FieldID */ public ASN1Primitive toASN1Primitive() { - ASN1EncodableVector v = new ASN1EncodableVector(); + ASN1EncodableVector v = new ASN1EncodableVector(2); v.add(this.id); v.add(this.parameters); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java index e354d8ccf..6d786917c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/asn1/x9/X9ObjectIdentifiers.java @@ -4,7 +4,7 @@ import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; /** * - * X9.62 + * Object identifiers for the various X9 standards. *
  * ansi-X9-62 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
  *                                    us(840) ansi-x962(10045) }
@@ -13,129 +13,129 @@ import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
 public interface X9ObjectIdentifiers
 {
     /** Base OID: 1.2.840.10045 */
-    static final ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045");
+    ASN1ObjectIdentifier ansi_X9_62 = new ASN1ObjectIdentifier("1.2.840.10045");
 
     /** OID: 1.2.840.10045.1 */
-    static final ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1");
+    ASN1ObjectIdentifier id_fieldType = ansi_X9_62.branch("1");
 
     /** OID: 1.2.840.10045.1.1 */
-    static final ASN1ObjectIdentifier prime_field = id_fieldType.branch("1");
+    ASN1ObjectIdentifier prime_field = id_fieldType.branch("1");
 
     /** OID: 1.2.840.10045.1.2 */
-    static final ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2");
+    ASN1ObjectIdentifier characteristic_two_field = id_fieldType.branch("2");
 
     /** OID: 1.2.840.10045.1.2.3.1 */
-    static final ASN1ObjectIdentifier gnBasis = characteristic_two_field.branch("3.1");
+    ASN1ObjectIdentifier gnBasis = characteristic_two_field.branch("3.1");
 
     /** OID: 1.2.840.10045.1.2.3.2 */
-    static final ASN1ObjectIdentifier tpBasis = characteristic_two_field.branch("3.2");
+    ASN1ObjectIdentifier tpBasis = characteristic_two_field.branch("3.2");
 
     /** OID: 1.2.840.10045.1.2.3.3 */
-    static final ASN1ObjectIdentifier ppBasis = characteristic_two_field.branch("3.3");
+    ASN1ObjectIdentifier ppBasis = characteristic_two_field.branch("3.3");
 
     /** OID: 1.2.840.10045.4 */
-    static final ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4");
+    ASN1ObjectIdentifier id_ecSigType = ansi_X9_62.branch("4");
 
     /** OID: 1.2.840.10045.4.1 */
-    static final ASN1ObjectIdentifier ecdsa_with_SHA1 = id_ecSigType.branch("1");
+    ASN1ObjectIdentifier ecdsa_with_SHA1 = id_ecSigType.branch("1");
 
     /** OID: 1.2.840.10045.2 */
-    static final ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2");
+    ASN1ObjectIdentifier id_publicKeyType = ansi_X9_62.branch("2");
 
     /** OID: 1.2.840.10045.2.1 */
-    static final ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1");
+    ASN1ObjectIdentifier id_ecPublicKey = id_publicKeyType.branch("1");
 
     /** OID: 1.2.840.10045.4.3 */
-    static final ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3");
+    ASN1ObjectIdentifier ecdsa_with_SHA2 = id_ecSigType.branch("3");
 
     /** OID: 1.2.840.10045.4.3.1 */
-    static final ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1");
+    ASN1ObjectIdentifier ecdsa_with_SHA224 = ecdsa_with_SHA2.branch("1");
 
     /** OID: 1.2.840.10045.4.3.2 */
-    static final ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2");
+    ASN1ObjectIdentifier ecdsa_with_SHA256 = ecdsa_with_SHA2.branch("2");
 
     /** OID: 1.2.840.10045.4.3.3 */
-    static final ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3");
+    ASN1ObjectIdentifier ecdsa_with_SHA384 = ecdsa_with_SHA2.branch("3");
 
     /** OID: 1.2.840.10045.4.3.4 */
-    static final ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4");
+    ASN1ObjectIdentifier ecdsa_with_SHA512 = ecdsa_with_SHA2.branch("4");
 
     /**
      * Named curves base
      * 

* OID: 1.2.840.10045.3 */ - static final ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3"); + ASN1ObjectIdentifier ellipticCurve = ansi_X9_62.branch("3"); /** * Two Curves *

* OID: 1.2.840.10045.3.0 */ - static final ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0"); + ASN1ObjectIdentifier cTwoCurve = ellipticCurve.branch("0"); /** Two Curve c2pnb163v1, OID: 1.2.840.10045.3.0.1 */ - static final ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1"); + ASN1ObjectIdentifier c2pnb163v1 = cTwoCurve.branch("1"); /** Two Curve c2pnb163v2, OID: 1.2.840.10045.3.0.2 */ - static final ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2"); + ASN1ObjectIdentifier c2pnb163v2 = cTwoCurve.branch("2"); /** Two Curve c2pnb163v3, OID: 1.2.840.10045.3.0.3 */ - static final ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3"); + ASN1ObjectIdentifier c2pnb163v3 = cTwoCurve.branch("3"); /** Two Curve c2pnb176w1, OID: 1.2.840.10045.3.0.4 */ - static final ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4"); + ASN1ObjectIdentifier c2pnb176w1 = cTwoCurve.branch("4"); /** Two Curve c2tnb191v1, OID: 1.2.840.10045.3.0.5 */ - static final ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5"); + ASN1ObjectIdentifier c2tnb191v1 = cTwoCurve.branch("5"); /** Two Curve c2tnb191v2, OID: 1.2.840.10045.3.0.6 */ - static final ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6"); + ASN1ObjectIdentifier c2tnb191v2 = cTwoCurve.branch("6"); /** Two Curve c2tnb191v3, OID: 1.2.840.10045.3.0.7 */ - static final ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7"); + ASN1ObjectIdentifier c2tnb191v3 = cTwoCurve.branch("7"); /** Two Curve c2onb191v4, OID: 1.2.840.10045.3.0.8 */ - static final ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8"); + ASN1ObjectIdentifier c2onb191v4 = cTwoCurve.branch("8"); /** Two Curve c2onb191v5, OID: 1.2.840.10045.3.0.9 */ - static final ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9"); + ASN1ObjectIdentifier c2onb191v5 = cTwoCurve.branch("9"); /** Two Curve c2pnb208w1, OID: 1.2.840.10045.3.0.10 */ - static final ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10"); + ASN1ObjectIdentifier c2pnb208w1 = cTwoCurve.branch("10"); /** Two Curve c2tnb239v1, OID: 1.2.840.10045.3.0.11 */ - static final ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11"); + ASN1ObjectIdentifier c2tnb239v1 = cTwoCurve.branch("11"); /** Two Curve c2tnb239v2, OID: 1.2.840.10045.3.0.12 */ - static final ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12"); + ASN1ObjectIdentifier c2tnb239v2 = cTwoCurve.branch("12"); /** Two Curve c2tnb239v3, OID: 1.2.840.10045.3.0.13 */ - static final ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13"); + ASN1ObjectIdentifier c2tnb239v3 = cTwoCurve.branch("13"); /** Two Curve c2onb239v4, OID: 1.2.840.10045.3.0.14 */ - static final ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14"); + ASN1ObjectIdentifier c2onb239v4 = cTwoCurve.branch("14"); /** Two Curve c2onb239v5, OID: 1.2.840.10045.3.0.15 */ - static final ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15"); + ASN1ObjectIdentifier c2onb239v5 = cTwoCurve.branch("15"); /** Two Curve c2pnb272w1, OID: 1.2.840.10045.3.0.16 */ - static final ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16"); + ASN1ObjectIdentifier c2pnb272w1 = cTwoCurve.branch("16"); /** Two Curve c2pnb304w1, OID: 1.2.840.10045.3.0.17 */ - static final ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17"); + ASN1ObjectIdentifier c2pnb304w1 = cTwoCurve.branch("17"); /** Two Curve c2tnb359v1, OID: 1.2.840.10045.3.0.18 */ - static final ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18"); + ASN1ObjectIdentifier c2tnb359v1 = cTwoCurve.branch("18"); /** Two Curve c2pnb368w1, OID: 1.2.840.10045.3.0.19 */ - static final ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19"); + ASN1ObjectIdentifier c2pnb368w1 = cTwoCurve.branch("19"); /** Two Curve c2tnb431r1, OID: 1.2.840.10045.3.0.20 */ - static final ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20"); + ASN1ObjectIdentifier c2tnb431r1 = cTwoCurve.branch("20"); /** * Prime Curves *

* OID: 1.2.840.10045.3.1 */ - static final ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1"); + ASN1ObjectIdentifier primeCurve = ellipticCurve.branch("1"); /** Prime Curve prime192v1, OID: 1.2.840.10045.3.1.1 */ - static final ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1"); + ASN1ObjectIdentifier prime192v1 = primeCurve.branch("1"); /** Prime Curve prime192v2, OID: 1.2.840.10045.3.1.2 */ - static final ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2"); + ASN1ObjectIdentifier prime192v2 = primeCurve.branch("2"); /** Prime Curve prime192v3, OID: 1.2.840.10045.3.1.3 */ - static final ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3"); + ASN1ObjectIdentifier prime192v3 = primeCurve.branch("3"); /** Prime Curve prime239v1, OID: 1.2.840.10045.3.1.4 */ - static final ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4"); + ASN1ObjectIdentifier prime239v1 = primeCurve.branch("4"); /** Prime Curve prime239v2, OID: 1.2.840.10045.3.1.5 */ - static final ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5"); + ASN1ObjectIdentifier prime239v2 = primeCurve.branch("5"); /** Prime Curve prime239v3, OID: 1.2.840.10045.3.1.6 */ - static final ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6"); + ASN1ObjectIdentifier prime239v3 = primeCurve.branch("6"); /** Prime Curve prime256v1, OID: 1.2.840.10045.3.1.7 */ - static final ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7"); + ASN1ObjectIdentifier prime256v1 = primeCurve.branch("7"); /** * DSA @@ -145,7 +145,7 @@ public interface X9ObjectIdentifiers *

* Base OID: 1.2.840.10040.4.1 */ - static final ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1"); + ASN1ObjectIdentifier id_dsa = new ASN1ObjectIdentifier("1.2.840.10040.4.1"); /** *
@@ -154,26 +154,26 @@ public interface X9ObjectIdentifiers
      * 
* OID: 1.2.840.10040.4.3 */ - static final ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3"); + ASN1ObjectIdentifier id_dsa_with_sha1 = new ASN1ObjectIdentifier("1.2.840.10040.4.3"); /** * X9.63 - Signature Specification *

* Base OID: 1.3.133.16.840.63.0 */ - static final ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0"); + ASN1ObjectIdentifier x9_63_scheme = new ASN1ObjectIdentifier("1.3.133.16.840.63.0"); /** OID: 1.3.133.16.840.63.0.2 */ - static final ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2"); + ASN1ObjectIdentifier dhSinglePass_stdDH_sha1kdf_scheme = x9_63_scheme.branch("2"); /** OID: 1.3.133.16.840.63.0.3 */ - static final ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3"); + ASN1ObjectIdentifier dhSinglePass_cofactorDH_sha1kdf_scheme = x9_63_scheme.branch("3"); /** OID: 1.3.133.16.840.63.0.16 */ - static final ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16"); + ASN1ObjectIdentifier mqvSinglePass_sha1kdf_scheme = x9_63_scheme.branch("16"); /** * X9.42 */ - static final ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046"); + ASN1ObjectIdentifier ansi_X9_42 = new ASN1ObjectIdentifier("1.2.840.10046"); /** * Diffie-Hellman @@ -184,26 +184,26 @@ public interface X9ObjectIdentifiers *

* OID: 1.2.840.10046.2.1 */ - static final ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1"); + ASN1ObjectIdentifier dhpublicnumber = ansi_X9_42.branch("2.1"); /** X9.42 schemas base OID: 1.2.840.10046.3 */ - static final ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3"); + ASN1ObjectIdentifier x9_42_schemes = ansi_X9_42.branch("3"); /** X9.42 dhStatic OID: 1.2.840.10046.3.1 */ - static final ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1"); + ASN1ObjectIdentifier dhStatic = x9_42_schemes.branch("1"); /** X9.42 dhEphem OID: 1.2.840.10046.3.2 */ - static final ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2"); + ASN1ObjectIdentifier dhEphem = x9_42_schemes.branch("2"); /** X9.42 dhOneFlow OID: 1.2.840.10046.3.3 */ - static final ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3"); + ASN1ObjectIdentifier dhOneFlow = x9_42_schemes.branch("3"); /** X9.42 dhHybrid1 OID: 1.2.840.10046.3.4 */ - static final ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4"); + ASN1ObjectIdentifier dhHybrid1 = x9_42_schemes.branch("4"); /** X9.42 dhHybrid2 OID: 1.2.840.10046.3.5 */ - static final ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5"); + ASN1ObjectIdentifier dhHybrid2 = x9_42_schemes.branch("5"); /** X9.42 dhHybridOneFlow OID: 1.2.840.10046.3.6 */ - static final ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6"); + ASN1ObjectIdentifier dhHybridOneFlow = x9_42_schemes.branch("6"); /** X9.42 MQV2 OID: 1.2.840.10046.3.7 */ - static final ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7"); + ASN1ObjectIdentifier mqv2 = x9_42_schemes.branch("7"); /** X9.42 MQV1 OID: 1.2.840.10046.3.8 */ - static final ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8"); + ASN1ObjectIdentifier mqv1 = x9_42_schemes.branch("8"); /** * X9.44 diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/CryptoServicesRegistrar.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/CryptoServicesRegistrar.java index 8b496216b..3df331a33 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/CryptoServicesRegistrar.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/CryptoServicesRegistrar.java @@ -28,7 +28,8 @@ public final class CryptoServicesRegistrar private static final ThreadLocal> threadProperties = new ThreadLocal>(); private static final Map globalProperties = Collections.synchronizedMap(new HashMap()); - private static volatile SecureRandom defaultSecureRandom; + private static final Object cacheLock = new Object(); + private static SecureRandom defaultSecureRandom; static { @@ -38,7 +39,7 @@ public final class CryptoServicesRegistrar new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16), new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16), new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16), - new DSAValidationParameters(Hex.decode("b869c82b35d70e1b1ff91b28e37a62ecdc34409b"), 123)); + new DSAValidationParameters(Hex.decodeStrict("b869c82b35d70e1b1ff91b28e37a62ecdc34409b"), 123)); DSAParameters def768Params = new DSAParameters( new BigInteger("e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5" + @@ -50,7 +51,7 @@ public final class CryptoServicesRegistrar "a31d23c4dbbcbe06174544401a5b2c020965d8c2bd2171d366844577" + "1f74ba084d2029d83c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a" + "7064f316933a346d3f529252", 16), - new DSAValidationParameters(Hex.decode("77d0f8c4dad15eb8c4f2f8d6726cefd96d5bb399"), 263)); + new DSAValidationParameters(Hex.decodeStrict("77d0f8c4dad15eb8c4f2f8d6726cefd96d5bb399"), 263)); DSAParameters def1024Params = new DSAParameters( new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80" + @@ -64,7 +65,7 @@ public final class CryptoServicesRegistrar "b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f" + "0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06" + "928b665e807b552564014c3bfecf492a", 16), - new DSAValidationParameters(Hex.decode("8d5155894229d5e689ee01e6018a237e2cae64cd"), 92)); + new DSAValidationParameters(Hex.decodeStrict("8d5155894229d5e689ee01e6018a237e2cae64cd"), 92)); DSAParameters def2048Params = new DSAParameters( new BigInteger("95475cf5d93e596c3fcd1d902add02f427f5f3c7210313bb45fb4d5b" + @@ -88,7 +89,7 @@ public final class CryptoServicesRegistrar "ac819a26ca9b04cb0eb9b7b035988d15bbac65212a55239cfc7e58fa" + "e38d7250ab9991ffbc97134025fe8ce04c4399ad96569be91a546f49" + "78693c7a", 16), - new DSAValidationParameters(Hex.decode("b0b4417601b59cbc9d8ac8f935cadaec4f5fbb2f23785609ae466748d9b5a536"), 497)); + new DSAValidationParameters(Hex.decodeStrict("b0b4417601b59cbc9d8ac8f935cadaec4f5fbb2f23785609ae466748d9b5a536"), 497)); localSetGlobalProperty(Property.DSA_DEFAULT_PARAMS, def512Params, def768Params, def1024Params, def2048Params); localSetGlobalProperty(Property.DH_DEFAULT_PARAMS, toDH(def512Params), toDH(def768Params), toDH(def1024Params), toDH(def2048Params)); @@ -103,16 +104,28 @@ public final class CryptoServicesRegistrar * Return the default source of randomness. * * @return the default SecureRandom - * @throws IllegalStateException if no source of randomness has been provided. */ public static SecureRandom getSecureRandom() { - if (defaultSecureRandom == null) + synchronized (cacheLock) { - return new SecureRandom(); + if (null != defaultSecureRandom) + { + return defaultSecureRandom; + } + } + + SecureRandom tmp = new SecureRandom(); + + synchronized (cacheLock) + { + if (null == defaultSecureRandom) + { + defaultSecureRandom = tmp; + } + + return defaultSecureRandom; } - - return defaultSecureRandom; } /** @@ -124,7 +137,10 @@ public final class CryptoServicesRegistrar { checkPermission(CanSetDefaultRandom); - defaultSecureRandom = secureRandom; + synchronized (cacheLock) + { + defaultSecureRandom = secureRandom; + } } /** @@ -366,7 +382,7 @@ public final class CryptoServicesRegistrar private static int chooseLowerBound(int pSize) { int m = 160; - if (pSize > 512) + if (pSize > 1024) { if (pSize <= 2048) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/DSAExt.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/DSAExt.java new file mode 100644 index 000000000..7edd5342b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/DSAExt.java @@ -0,0 +1,16 @@ +package com.fr.third.org.bouncycastle.crypto; + +import java.math.BigInteger; + +/** + * An "extended" interface for classes implementing DSA-style algorithms, that provides access to + * the group order. + */ +public interface DSAExt + extends DSA +{ + /** + * Get the order of the group that the r, s values in signatures belong to. + */ + public BigInteger getOrder(); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/RawAgreement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/RawAgreement.java new file mode 100644 index 000000000..01e8e14a7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/RawAgreement.java @@ -0,0 +1,10 @@ +package com.fr.third.org.bouncycastle.crypto; + +public interface RawAgreement +{ + void init(CipherParameters parameters); + + int getAgreementSize(); + + void calculateAgreement(CipherParameters publicKey, byte[] buf, int off); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/DHStandardGroups.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/DHStandardGroups.java index b19629114..da7b048b5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/DHStandardGroups.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/DHStandardGroups.java @@ -14,7 +14,7 @@ public class DHStandardGroups private static BigInteger fromHex(String hex) { - return new BigInteger(1, Hex.decode(hex)); + return new BigInteger(1, Hex.decodeStrict(hex)); } private static DHParameters fromPG(String hexP, String hexG) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/X25519Agreement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/X25519Agreement.java new file mode 100644 index 000000000..32cda5d09 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/X25519Agreement.java @@ -0,0 +1,27 @@ +package com.fr.third.org.bouncycastle.crypto.agreement; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.RawAgreement; +import com.fr.third.org.bouncycastle.crypto.params.X25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X25519PublicKeyParameters; + +public final class X25519Agreement + implements RawAgreement +{ + private X25519PrivateKeyParameters privateKey; + + public void init(CipherParameters parameters) + { + this.privateKey = (X25519PrivateKeyParameters)parameters; + } + + public int getAgreementSize() + { + return X25519PrivateKeyParameters.SECRET_SIZE; + } + + public void calculateAgreement(CipherParameters publicKey, byte[] buf, int off) + { + privateKey.generateSecret((X25519PublicKeyParameters)publicKey, buf, off); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/X448Agreement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/X448Agreement.java new file mode 100644 index 000000000..8b27d19de --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/X448Agreement.java @@ -0,0 +1,27 @@ +package com.fr.third.org.bouncycastle.crypto.agreement; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.RawAgreement; +import com.fr.third.org.bouncycastle.crypto.params.X448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448PublicKeyParameters; + +public final class X448Agreement + implements RawAgreement +{ + private X448PrivateKeyParameters privateKey; + + public void init(CipherParameters parameters) + { + this.privateKey = (X448PrivateKeyParameters)parameters; + } + + public int getAgreementSize() + { + return X448PrivateKeyParameters.SECRET_SIZE; + } + + public void calculateAgreement(CipherParameters publicKey, byte[] buf, int off) + { + privateKey.generateSecret((X448PublicKeyParameters)publicKey, buf, off); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/XDHUnifiedAgreement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/XDHUnifiedAgreement.java new file mode 100644 index 000000000..f17e9972e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/XDHUnifiedAgreement.java @@ -0,0 +1,43 @@ +package com.fr.third.org.bouncycastle.crypto.agreement; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.RawAgreement; +import com.fr.third.org.bouncycastle.crypto.params.XDHUPrivateParameters; +import com.fr.third.org.bouncycastle.crypto.params.XDHUPublicParameters; + +public class XDHUnifiedAgreement + implements RawAgreement +{ + private final RawAgreement xAgreement; + + private XDHUPrivateParameters privParams; + + public XDHUnifiedAgreement(RawAgreement xAgreement) + { + this.xAgreement = xAgreement; + } + + public void init( + CipherParameters key) + { + this.privParams = (XDHUPrivateParameters)key; + } + + public int getAgreementSize() + { + return xAgreement.getAgreementSize() * 2; + } + + public void calculateAgreement(CipherParameters publicKey, byte[] buf, int off) + { + XDHUPublicParameters pubParams = (XDHUPublicParameters)publicKey; + + xAgreement.init(privParams.getEphemeralPrivateKey()); + + xAgreement.calculateAgreement(pubParams.getEphemeralPublicKey(), buf, off); + + xAgreement.init(privParams.getStaticPrivateKey()); + + xAgreement.calculateAgreement(pubParams.getStaticPublicKey(), buf, off + xAgreement.getAgreementSize()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/srp/SRP6StandardGroups.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/srp/SRP6StandardGroups.java index f7f7ece91..ff068cc11 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/srp/SRP6StandardGroups.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/agreement/srp/SRP6StandardGroups.java @@ -9,7 +9,7 @@ public class SRP6StandardGroups { private static BigInteger fromHex(String hex) { - return new BigInteger(1, Hex.decode(hex)); + return new BigInteger(1, Hex.decodeStrict(hex)); } private static SRP6GroupParameters fromNG(String hexN, String hexG) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Blake2sDigest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Blake2sDigest.java index 59c2b415d..ef508428b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Blake2sDigest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Blake2sDigest.java @@ -82,16 +82,15 @@ public class Blake2sDigest private byte[] key = null; // Tree hashing parameters: - // Because this class does not implement the Tree Hashing Mode, - // these parameters can be treated as constants (see init() function) - /* - * private int fanout = 1; // 0-255 - * private int depth = 1; // 1 - 255 - * private int leafLength= 0; - * private long nodeOffset = 0L; - * private int nodeDepth = 0; - * private int innerHashLength = 0; - */ + // The Tree Hashing Mode is not supported but these are used for + // the XOF implementation + private int fanout = 1; // 0-255 + private int depth = 1; // 0-255 + private int leafLength= 0; + private long nodeOffset = 0L; + private int nodeDepth = 0; + private int innerHashLength = 0; + /** * Whenever this buffer overflows, it will be processed in the compress() @@ -144,8 +143,19 @@ public class Blake2sDigest this.keyLength = digest.keyLength; this.key = Arrays.clone(digest.key); this.digestLength = digest.digestLength; + this.internalState = Arrays.clone(internalState); this.chainValue = Arrays.clone(digest.chainValue); + this.t0 = digest.t0; + this.t1 = digest.t1; + this.f0 = digest.f0; + this.salt = Arrays.clone(digest.salt); this.personalization = Arrays.clone(digest.personalization); + this.fanout = digest.fanout; + this.depth = digest.depth; + this.leafLength = digest.leafLength; + this.nodeOffset = digest.nodeOffset; + this.nodeDepth = digest.nodeDepth; + this.innerHashLength = digest.innerHashLength; } /** @@ -160,10 +170,9 @@ public class Blake2sDigest throw new IllegalArgumentException( "BLAKE2s digest bit length must be a multiple of 8 and not greater than 256"); } - buffer = new byte[BLOCK_LENGTH_BYTES]; - keyLength = 0; digestLength = digestBits / 8; - init(); + + init(null, null, null); } /** @@ -177,23 +186,7 @@ public class Blake2sDigest */ public Blake2sDigest(byte[] key) { - buffer = new byte[BLOCK_LENGTH_BYTES]; - if (key != null) - { - if (key.length > 32) - { - throw new IllegalArgumentException( - "Keys > 32 are not supported"); - } - this.key = new byte[key.length]; - System.arraycopy(key, 0, this.key, 0, key.length); - - keyLength = key.length; - System.arraycopy(key, 0, buffer, 0, key.length); - bufferPos = BLOCK_LENGTH_BYTES; // zero padding - } - digestLength = 32; - init(); + init(null, null, key); } /** @@ -212,40 +205,48 @@ public class Blake2sDigest public Blake2sDigest(byte[] key, int digestBytes, byte[] salt, byte[] personalization) { - buffer = new byte[BLOCK_LENGTH_BYTES]; if (digestBytes < 1 || digestBytes > 32) { throw new IllegalArgumentException( "Invalid digest length (required: 1 - 32)"); } digestLength = digestBytes; - if (salt != null) - { - if (salt.length != 8) - { - throw new IllegalArgumentException( - "Salt length must be exactly 8 bytes"); - } - this.salt = new byte[8]; - System.arraycopy(salt, 0, this.salt, 0, salt.length); - } - if (personalization != null) - { - if (personalization.length != 8) - { - throw new IllegalArgumentException( - "Personalization length must be exactly 8 bytes"); - } - this.personalization = new byte[8]; - System.arraycopy(personalization, 0, this.personalization, 0, - personalization.length); - } - if (key != null) + + init(salt, personalization, key); + } + + // XOF root hash parameters + Blake2sDigest(int digestBytes, byte[] key, byte[] salt, byte[] personalization, long offset) { + digestLength = digestBytes; + nodeOffset = offset; + + init(salt, personalization, key); + } + + // XOF internal hash parameters + Blake2sDigest(int digestBytes, int hashLength, long offset) { + digestLength = digestBytes; + nodeOffset = offset; + fanout = 0; + depth = 0; + leafLength = hashLength; + innerHashLength = hashLength; + nodeDepth = 0; + + init(null, null, null); + } + + // initialize the digest's parameters + private void init(byte[] salt, byte[] personalization, byte[] key) + { + buffer = new byte[BLOCK_LENGTH_BYTES]; + + if (key != null && key.length > 0) { if (key.length > 32) { throw new IllegalArgumentException( - "Keys > 32 bytes are not supported"); + "Keys > 32 bytes are not supported"); } this.key = new byte[key.length]; System.arraycopy(key, 0, this.key, 0, key.length); @@ -254,30 +255,33 @@ public class Blake2sDigest System.arraycopy(key, 0, buffer, 0, key.length); bufferPos = BLOCK_LENGTH_BYTES; // zero padding } - init(); - } - // initialize chainValue - private void init() - { if (chainValue == null) { chainValue = new int[8]; chainValue[0] = blake2s_IV[0] - ^ (digestLength | (keyLength << 8) | 0x1010000); - // 0x1010000 = ((fanout << 16) | (depth << 24)); - // with fanout = 1; depth = 0; - chainValue[1] = blake2s_IV[1];// ^ leafLength; with leafLength = 0; - chainValue[2] = blake2s_IV[2];// ^ nodeOffset; with nodeOffset = 0; - chainValue[3] = blake2s_IV[3];// ^ ( (nodeOffset << 32) | - // (nodeDepth << 16) | (innerHashLength << 24) ); - // with nodeDepth = 0; innerHashLength = 0; + ^ (digestLength | (keyLength << 8) | ((fanout << 16) | (depth << 24))); + chainValue[1] = blake2s_IV[1] ^ leafLength; + + int nofHi = (int) (nodeOffset >> 32); + int nofLo = (int) nodeOffset; + chainValue[2] = blake2s_IV[2] ^ nofLo; + chainValue[3] = blake2s_IV[3] ^ (nofHi | + (nodeDepth << 16) | (innerHashLength << 24)); chainValue[4] = blake2s_IV[4]; chainValue[5] = blake2s_IV[5]; if (salt != null) { + if (salt.length != 8) + { + throw new IllegalArgumentException( + "Salt length must be exactly 8 bytes"); + } + this.salt = new byte[8]; + System.arraycopy(salt, 0, this.salt, 0, salt.length); + chainValue[4] ^= Pack.littleEndianToInt(salt, 0); chainValue[5] ^= Pack.littleEndianToInt(salt, 4); } @@ -286,6 +290,15 @@ public class Blake2sDigest chainValue[7] = blake2s_IV[7]; if (personalization != null) { + if (personalization.length != 8) + { + throw new IllegalArgumentException( + "Personalization length must be exactly 8 bytes"); + } + this.personalization = new byte[8]; + System.arraycopy(personalization, 0, this.personalization, 0, + personalization.length); + chainValue[6] ^= Pack.littleEndianToInt(personalization, 0); chainValue[7] ^= Pack.littleEndianToInt(personalization, 4); } @@ -457,7 +470,8 @@ public class Blake2sDigest System.arraycopy(key, 0, buffer, 0, key.length); bufferPos = BLOCK_LENGTH_BYTES; // zero padding } - init(); + + init(this.salt, this.personalization, this.key); } private void compress(byte[] message, int messagePos) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Blake2xsDigest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Blake2xsDigest.java new file mode 100644 index 000000000..4ac7b5287 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Blake2xsDigest.java @@ -0,0 +1,318 @@ +package com.fr.third.org.bouncycastle.crypto.digests; + +/* + The BLAKE2 cryptographic hash function was designed by Jean- + Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn, and Christian + Winnerlein. + + Reference Implementation and Description can be found at: https://blake2.net/blake2x.pdf + */ + +import com.fr.third.org.bouncycastle.crypto.Xof; +import com.fr.third.org.bouncycastle.util.Arrays; + +/** + * Implementation of the eXtendable Output Function (XOF) BLAKE2xs. + *

+ * BLAKE2xs offers a built-in keying mechanism to be used directly + * for authentication ("Prefix-MAC") rather than a HMAC construction. + *

+ * BLAKE2xs offers a built-in support for a salt for randomized hashing + * and a personal string for defining a unique hash function for each application. + *

+ * BLAKE2xs is optimized for 32-bit platforms and produces digests of any size + * between 1 and 2^16-2 bytes. The length can also be unknown and then the maximum + * length will be 2^32 blocks of 32 bytes. + */ +public class Blake2xsDigest + implements Xof +{ + /** + * Magic number to indicate an unknown length of digest + */ + public static final int UNKNOWN_DIGEST_LENGTH = 65535; + + private static final int DIGEST_LENGTH = 32; + private static final long MAX_NUMBER_BLOCKS = 1L << 32; + + /** + * Expected digest length for the xof. It can be unknown. + */ + private int digestLength; + + /** + * Root hash that will take the updates + */ + private Blake2sDigest hash; + + /** + * Digest of the root hash + */ + private byte[] h0 = null; + + /** + * Digest of each round of the XOF + */ + private byte[] buf = new byte[32]; + + /** + * Current position for a round + */ + private int bufPos = 32; + + /** + * Overall position of the digest. It is useful when the length is known + * in advance to get last block length. + */ + private int digestPos = 0; + + /** + * Keep track of the round number to detect the end of the digest after + * 2^32 blocks of 32 bytes. + */ + private long blockPos = 0; + + /** + * Current node offset incremented by 1 every round. + */ + private long nodeOffset; + + /** + * BLAKE2xs for hashing with unknown digest length + */ + public Blake2xsDigest() + { + this(Blake2xsDigest.UNKNOWN_DIGEST_LENGTH); + } + + /** + * BLAKE2xs for hashing + * + * @param digestBytes The desired digest length in bytes. Must be above 1 and less than 2^16-1 + */ + public Blake2xsDigest(int digestBytes) + { + this(digestBytes, null, null, null); + } + + /** + * BLAKE2xs with key + * + * @param digestBytes The desired digest length in bytes. Must be above 1 and less than 2^16-1 + * @param key A key up to 32 bytes or null + */ + public Blake2xsDigest(int digestBytes, byte[] key) + { + this(digestBytes, key, null, null); + } + + /** + * BLAKE2xs with key, salt and personalization + * + * @param digestBytes The desired digest length in bytes. Must be above 1 and less than 2^16-1 + * @param key A key up to 32 bytes or null + * @param salt 8 bytes or null + * @param personalization 8 bytes or null + */ + public Blake2xsDigest(int digestBytes, byte[] key, byte[] salt, byte[] personalization) + { + if (digestBytes < 1 || digestBytes > Blake2xsDigest.UNKNOWN_DIGEST_LENGTH) + { + throw new IllegalArgumentException( + "BLAKE2xs digest length must be between 1 and 2^16-1"); + } + + digestLength = digestBytes; + nodeOffset = computeNodeOffset(); + hash = new Blake2sDigest(Blake2xsDigest.DIGEST_LENGTH, key, salt, personalization, nodeOffset); + } + + public Blake2xsDigest(Blake2xsDigest digest) + { + digestLength = digest.digestLength; + hash = new Blake2sDigest(digest.hash); + h0 = Arrays.clone(digest.h0); + buf = Arrays.clone(digest.buf); + bufPos = digest.bufPos; + digestPos = digest.digestPos; + blockPos = digest.blockPos; + nodeOffset = digest.nodeOffset; + } + + /** + * Return the algorithm name. + * + * @return the algorithm name + */ + public String getAlgorithmName() + { + return "BLAKE2xs"; + } + + /** + * Return the size in bytes of the digest produced by this message digest. + * + * @return the size in bytes of the digest produced by this message digest. + */ + public int getDigestSize() + { + return digestLength; + } + + /** + * Return the size in bytes of the internal buffer the digest applies its + * compression function to. + * + * @return byte length of the digest's internal buffer. + */ + public int getByteLength() + { + return hash.getByteLength(); + } + + /** + * Return the maximum size in bytes the digest can produce when the length + * is unknown + * + * @return byte length of the largest digest with unknown length + */ + public long getUnknownMaxLength() + { + return Blake2xsDigest.MAX_NUMBER_BLOCKS * Blake2xsDigest.DIGEST_LENGTH; + } + + /** + * Update the message digest with a single byte. + * + * @param in the input byte to be entered. + */ + public void update(byte in) + { + hash.update(in); + } + + /** + * Update the message digest with a block of bytes. + * + * @param in the byte array containing the data. + * @param inOff the offset into the byte array where the data starts. + * @param len the length of the data. + */ + public void update(byte[] in, int inOff, int len) + { + hash.update(in, inOff, len); + } + + /** + * Reset the digest back to its initial state. The key, the salt and the + * personal string will remain for further computations. + */ + public void reset() + { + hash.reset(); + + h0 = null; + bufPos = Blake2xsDigest.DIGEST_LENGTH; + digestPos = 0; + blockPos = 0; + nodeOffset = computeNodeOffset(); + } + + /** + * Close the digest, producing the final digest value. The doFinal() call + * leaves the digest reset. Key, salt and personal string remain. + * + * @param out the array the digest is to be copied into. + * @param outOffset the offset into the out array the digest is to start at. + */ + public int doFinal(byte[] out, int outOffset) + { + return doFinal(out, outOffset, out.length); + } + + /** + * Close the digest, producing the final digest value. The doFinal() call + * leaves the digest reset. Key, salt, personal string remain. + * + * @param out output array to write the output bytes to. + * @param outOff offset to start writing the bytes at. + * @param outLen the number of output bytes requested. + */ + public int doFinal(byte[] out, int outOff, int outLen) + { + int ret = doOutput(out, outOff, outLen); + + reset(); + + return ret; + } + + /** + * Start outputting the results of the final calculation for this digest. Unlike doFinal, this method + * will continue producing output until the Xof is explicitly reset, or signals otherwise. + * + * @param out output array to write the output bytes to. + * @param outOff offset to start writing the bytes at. + * @param outLen the number of output bytes requested. + * @return the number of bytes written + */ + public int doOutput(byte[] out, int outOff, int outLen) + { + if (h0 == null) + { + h0 = new byte[hash.getDigestSize()]; + hash.doFinal(h0, 0); + } + + if (digestLength != Blake2xsDigest.UNKNOWN_DIGEST_LENGTH) + { + if (digestPos + outLen > digestLength) + { + throw new IllegalArgumentException( + "Output length is above the digest length"); + } + } + else if (blockPos << 5 >= getUnknownMaxLength()) + { + throw new IllegalArgumentException( + "Maximum length is 2^32 blocks of 32 bytes"); + } + + for (int i = 0; i < outLen; i++) + { + if (bufPos >= Blake2xsDigest.DIGEST_LENGTH) + { + Blake2sDigest h = new Blake2sDigest(computeStepLength(), Blake2xsDigest.DIGEST_LENGTH, nodeOffset); + h.update(h0, 0, h0.length); + + Arrays.fill(buf, (byte)0); + h.doFinal(buf, 0); + bufPos = 0; + nodeOffset++; + blockPos++; + } + out[i] = buf[bufPos]; + bufPos++; + digestPos++; + } + + return outLen; + } + + // get the next round length. If the length is unknown, the digest length is + // always the maximum. + private int computeStepLength() + { + if (digestLength == Blake2xsDigest.UNKNOWN_DIGEST_LENGTH) + { + return Blake2xsDigest.DIGEST_LENGTH; + } + + return Math.min(Blake2xsDigest.DIGEST_LENGTH, digestLength - digestPos); + } + + private long computeNodeOffset() + { + return digestLength * 0x100000000L; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/CSHAKEDigest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/CSHAKEDigest.java new file mode 100644 index 000000000..03858dc71 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/CSHAKEDigest.java @@ -0,0 +1,112 @@ +package com.fr.third.org.bouncycastle.crypto.digests; + +import com.fr.third.org.bouncycastle.util.Arrays; + +/** + * Customizable SHAKE function. + */ +public class CSHAKEDigest + extends SHAKEDigest +{ + private static final byte[] padding = new byte[100]; + private final byte[] diff; + + /** + * Base constructor. + * + * @param bitLength bit length of the underlying SHAKE function, 128 or 256. + * @param N the function name string, note this is reserved for use by NIST. Avoid using it if not required. + * @param S the customization string - available for local use. + */ + public CSHAKEDigest(int bitLength, byte[] N, byte[] S) + { + super(bitLength); + + if ((N == null || N.length == 0) && (S == null || S.length == 0)) + { + diff = null; + } + else + { + diff = Arrays.concatenate(leftEncode(rate / 8), encodeString(N), encodeString(S)); + diffPadAndAbsorb(); + } + } + + private void diffPadAndAbsorb() + { + int blockSize = rate / 8; + absorb(diff, 0, diff.length); + + int required = blockSize - (diff.length % blockSize); + + while (required > padding.length) + { + absorb(padding, 0, padding.length); + required -= padding.length; + } + + absorb(padding, 0, required); + } + + private byte[] encodeString(byte[] str) + { + if (str == null || str.length == 0) + { + return leftEncode(0); + } + + return Arrays.concatenate(leftEncode(str.length * 8L), str); + } + + private static byte[] leftEncode(long strLen) + { + byte n = 1; + + long v = strLen; + while ((v >>= 8) != 0) + { + n++; + } + + byte[] b = new byte[n + 1]; + + b[0] = n; + + for (int i = 1; i <= n; i++) + { + b[i] = (byte)(strLen >> (8 * (n - i))); + } + + return b; + } + + public int doOutput(byte[] out, int outOff, int outLen) + { + if (diff != null) + { + if (!squeezing) + { + absorbBits(0x00, 2); + } + + squeeze(out, outOff, ((long)outLen) * 8); + + return outLen; + } + else + { + return super.doOutput(out, outOff, outLen); + } + } + + public void reset() + { + super.reset(); + + if (diff != null) + { + diffPadAndAbsorb(); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Haraka256Digest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Haraka256Digest.java new file mode 100644 index 000000000..a4bafe1ae --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Haraka256Digest.java @@ -0,0 +1,161 @@ +package com.fr.third.org.bouncycastle.crypto.digests; + +import com.fr.third.org.bouncycastle.util.Arrays; + +/** + * Haraka-256 v2, https://eprint.iacr.org/2016/098.pdf + *

+ * Haraka256-256 with reference to Python Reference Impl from: https://github.com/kste/haraka + *

+ */ +public class Haraka256Digest + extends HarakaBase +{ + private static final byte[][] RC = new byte[][]{ + {(byte)0x06, (byte)0x84, (byte)0x70, (byte)0x4c, (byte)0xe6, (byte)0x20, (byte)0xc0, (byte)0x0a, (byte)0xb2, (byte)0xc5, (byte)0xfe, (byte)0xf0, (byte)0x75, (byte)0x81, (byte)0x7b, (byte)0x9d}, + {(byte)0x8b, (byte)0x66, (byte)0xb4, (byte)0xe1, (byte)0x88, (byte)0xf3, (byte)0xa0, (byte)0x6b, (byte)0x64, (byte)0x0f, (byte)0x6b, (byte)0xa4, (byte)0x2f, (byte)0x08, (byte)0xf7, (byte)0x17}, + {(byte)0x34, (byte)0x02, (byte)0xde, (byte)0x2d, (byte)0x53, (byte)0xf2, (byte)0x84, (byte)0x98, (byte)0xcf, (byte)0x02, (byte)0x9d, (byte)0x60, (byte)0x9f, (byte)0x02, (byte)0x91, (byte)0x14}, + {(byte)0x0e, (byte)0xd6, (byte)0xea, (byte)0xe6, (byte)0x2e, (byte)0x7b, (byte)0x4f, (byte)0x08, (byte)0xbb, (byte)0xf3, (byte)0xbc, (byte)0xaf, (byte)0xfd, (byte)0x5b, (byte)0x4f, (byte)0x79}, + {(byte)0xcb, (byte)0xcf, (byte)0xb0, (byte)0xcb, (byte)0x48, (byte)0x72, (byte)0x44, (byte)0x8b, (byte)0x79, (byte)0xee, (byte)0xcd, (byte)0x1c, (byte)0xbe, (byte)0x39, (byte)0x70, (byte)0x44}, + {(byte)0x7e, (byte)0xea, (byte)0xcd, (byte)0xee, (byte)0x6e, (byte)0x90, (byte)0x32, (byte)0xb7, (byte)0x8d, (byte)0x53, (byte)0x35, (byte)0xed, (byte)0x2b, (byte)0x8a, (byte)0x05, (byte)0x7b}, + {(byte)0x67, (byte)0xc2, (byte)0x8f, (byte)0x43, (byte)0x5e, (byte)0x2e, (byte)0x7c, (byte)0xd0, (byte)0xe2, (byte)0x41, (byte)0x27, (byte)0x61, (byte)0xda, (byte)0x4f, (byte)0xef, (byte)0x1b}, + {(byte)0x29, (byte)0x24, (byte)0xd9, (byte)0xb0, (byte)0xaf, (byte)0xca, (byte)0xcc, (byte)0x07, (byte)0x67, (byte)0x5f, (byte)0xfd, (byte)0xe2, (byte)0x1f, (byte)0xc7, (byte)0x0b, (byte)0x3b}, + {(byte)0xab, (byte)0x4d, (byte)0x63, (byte)0xf1, (byte)0xe6, (byte)0x86, (byte)0x7f, (byte)0xe9, (byte)0xec, (byte)0xdb, (byte)0x8f, (byte)0xca, (byte)0xb9, (byte)0xd4, (byte)0x65, (byte)0xee}, + {(byte)0x1c, (byte)0x30, (byte)0xbf, (byte)0x84, (byte)0xd4, (byte)0xb7, (byte)0xcd, (byte)0x64, (byte)0x5b, (byte)0x2a, (byte)0x40, (byte)0x4f, (byte)0xad, (byte)0x03, (byte)0x7e, (byte)0x33}, + {(byte)0xb2, (byte)0xcc, (byte)0x0b, (byte)0xb9, (byte)0x94, (byte)0x17, (byte)0x23, (byte)0xbf, (byte)0x69, (byte)0x02, (byte)0x8b, (byte)0x2e, (byte)0x8d, (byte)0xf6, (byte)0x98, (byte)0x00}, + {(byte)0xfa, (byte)0x04, (byte)0x78, (byte)0xa6, (byte)0xde, (byte)0x6f, (byte)0x55, (byte)0x72, (byte)0x4a, (byte)0xaa, (byte)0x9e, (byte)0xc8, (byte)0x5c, (byte)0x9d, (byte)0x2d, (byte)0x8a}, + {(byte)0xdf, (byte)0xb4, (byte)0x9f, (byte)0x2b, (byte)0x6b, (byte)0x77, (byte)0x2a, (byte)0x12, (byte)0x0e, (byte)0xfa, (byte)0x4f, (byte)0x2e, (byte)0x29, (byte)0x12, (byte)0x9f, (byte)0xd4}, + {(byte)0x1e, (byte)0xa1, (byte)0x03, (byte)0x44, (byte)0xf4, (byte)0x49, (byte)0xa2, (byte)0x36, (byte)0x32, (byte)0xd6, (byte)0x11, (byte)0xae, (byte)0xbb, (byte)0x6a, (byte)0x12, (byte)0xee}, + {(byte)0xaf, (byte)0x04, (byte)0x49, (byte)0x88, (byte)0x4b, (byte)0x05, (byte)0x00, (byte)0x84, (byte)0x5f, (byte)0x96, (byte)0x00, (byte)0xc9, (byte)0x9c, (byte)0xa8, (byte)0xec, (byte)0xa6}, + {(byte)0x21, (byte)0x02, (byte)0x5e, (byte)0xd8, (byte)0x9d, (byte)0x19, (byte)0x9c, (byte)0x4f, (byte)0x78, (byte)0xa2, (byte)0xc7, (byte)0xe3, (byte)0x27, (byte)0xe5, (byte)0x93, (byte)0xec}, + {(byte)0xbf, (byte)0x3a, (byte)0xaa, (byte)0xf8, (byte)0xa7, (byte)0x59, (byte)0xc9, (byte)0xb7, (byte)0xb9, (byte)0x28, (byte)0x2e, (byte)0xcd, (byte)0x82, (byte)0xd4, (byte)0x01, (byte)0x73}, + {(byte)0x62, (byte)0x60, (byte)0x70, (byte)0x0d, (byte)0x61, (byte)0x86, (byte)0xb0, (byte)0x17, (byte)0x37, (byte)0xf2, (byte)0xef, (byte)0xd9, (byte)0x10, (byte)0x30, (byte)0x7d, (byte)0x6b}, + {(byte)0x5a, (byte)0xca, (byte)0x45, (byte)0xc2, (byte)0x21, (byte)0x30, (byte)0x04, (byte)0x43, (byte)0x81, (byte)0xc2, (byte)0x91, (byte)0x53, (byte)0xf6, (byte)0xfc, (byte)0x9a, (byte)0xc6}, + {(byte)0x92, (byte)0x23, (byte)0x97, (byte)0x3c, (byte)0x22, (byte)0x6b, (byte)0x68, (byte)0xbb, (byte)0x2c, (byte)0xaf, (byte)0x92, (byte)0xe8, (byte)0x36, (byte)0xd1, (byte)0x94, (byte)0x3a} + }; + + private void mix256(byte[][] s1, byte[][] s2) + { + System.arraycopy(s1[0], 0, s2[0], 0, 4); + System.arraycopy(s1[1], 0, s2[0], 4, 4); + System.arraycopy(s1[0], 4, s2[0], 8, 4); + System.arraycopy(s1[1], 4, s2[0], 12, 4); + + System.arraycopy(s1[0], 8, s2[1], 0, 4); + System.arraycopy(s1[1], 8, s2[1], 4, 4); + System.arraycopy(s1[0], 12, s2[1], 8, 4); + System.arraycopy(s1[1], 12, s2[1], 12, 4); + } + + private int haraka256256(byte[] msg, byte[] out, int outOff) + { + byte[][] s1 = new byte[2][16]; + byte[][] s2 = new byte[2][16]; + + System.arraycopy(msg, 0, s1[0], 0, 16); + System.arraycopy(msg, 16, s1[1], 0, 16); + + s1[0] = aesEnc(s1[0], RC[0]); + s1[1] = aesEnc(s1[1], RC[1]); + s1[0] = aesEnc(s1[0], RC[2]); + s1[1] = aesEnc(s1[1], RC[3]); + mix256(s1, s2); + + s1[0] = aesEnc(s2[0], RC[4]); + s1[1] = aesEnc(s2[1], RC[5]); + s1[0] = aesEnc(s1[0], RC[6]); + s1[1] = aesEnc(s1[1], RC[7]); + mix256(s1, s2); + + s1[0] = aesEnc(s2[0], RC[8]); + s1[1] = aesEnc(s2[1], RC[9]); + s1[0] = aesEnc(s1[0], RC[10]); + s1[1] = aesEnc(s1[1], RC[11]); + mix256(s1, s2); + + s1[0] = aesEnc(s2[0], RC[12]); + s1[1] = aesEnc(s2[1], RC[13]); + s1[0] = aesEnc(s1[0], RC[14]); + s1[1] = aesEnc(s1[1], RC[15]); + mix256(s1, s2); + + s1[0] = aesEnc(s2[0], RC[16]); + s1[1] = aesEnc(s2[1], RC[17]); + s1[0] = aesEnc(s1[0], RC[18]); + s1[1] = aesEnc(s1[1], RC[19]); + mix256(s1, s2); + + s1[0] = xor(s2[0], msg, 0); + s1[1] = xor(s2[1], msg, 16); + + System.arraycopy(s1[0], 0, out, outOff, 16); + System.arraycopy(s1[1], 0, out, outOff + 16, 16); + + return DIGEST_SIZE; + } + + private final byte[] buffer; + private int off; + + public Haraka256Digest() + { + this.buffer = new byte[32]; + } + + public Haraka256Digest(Haraka256Digest digest) + { + this.buffer = Arrays.clone(digest.buffer); + this.off = digest.off; + } + + public String getAlgorithmName() + { + return "Haraka-256"; + } + + public void update(byte in) + { + if (off + 1 > 32) + { + throw new IllegalArgumentException("total input cannot be more than 32 bytes"); + } + + buffer[off++] = in; + } + + public void update(byte[] in, int inOff, int len) + { + if (off + len > 32) + { + throw new IllegalArgumentException("total input cannot be more than 32 bytes"); + } + + System.arraycopy(in, inOff, buffer, off, len); + off += len; + } + + public int doFinal(byte[] out, int outOff) + { + if (off != 32) + { + throw new IllegalStateException("input must be exactly 32 bytes"); + } + + if (out.length - outOff < 32) + { + throw new IllegalArgumentException("output too short to receive digest"); + } + + int rv = haraka256256(buffer, out, outOff); + + reset(); + + return rv; + } + + public void reset() + { + off = 0; + Arrays.clear(buffer); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Haraka512Digest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Haraka512Digest.java new file mode 100644 index 000000000..d2b7d0ec0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/Haraka512Digest.java @@ -0,0 +1,219 @@ +package com.fr.third.org.bouncycastle.crypto.digests; + +import com.fr.third.org.bouncycastle.util.Arrays; + +/** + * Haraka-512 v2, https://eprint.iacr.org/2016/098.pdf + *

+ * Haraka512-256 with reference to Python Reference Impl from: https://github.com/kste/haraka + *

+ */ +public class Haraka512Digest + extends HarakaBase +{ + private static byte[][] RC = new byte[][]{ + {(byte)0x06, (byte)0x84, (byte)0x70, (byte)0x4c, (byte)0xe6, (byte)0x20, (byte)0xc0, (byte)0x0a, (byte)0xb2, (byte)0xc5, (byte)0xfe, (byte)0xf0, (byte)0x75, (byte)0x81, (byte)0x7b, (byte)0x9d}, + {(byte)0x8b, (byte)0x66, (byte)0xb4, (byte)0xe1, (byte)0x88, (byte)0xf3, (byte)0xa0, (byte)0x6b, (byte)0x64, (byte)0x0f, (byte)0x6b, (byte)0xa4, (byte)0x2f, (byte)0x08, (byte)0xf7, (byte)0x17}, + {(byte)0x34, (byte)0x02, (byte)0xde, (byte)0x2d, (byte)0x53, (byte)0xf2, (byte)0x84, (byte)0x98, (byte)0xcf, (byte)0x02, (byte)0x9d, (byte)0x60, (byte)0x9f, (byte)0x02, (byte)0x91, (byte)0x14}, + {(byte)0x0e, (byte)0xd6, (byte)0xea, (byte)0xe6, (byte)0x2e, (byte)0x7b, (byte)0x4f, (byte)0x08, (byte)0xbb, (byte)0xf3, (byte)0xbc, (byte)0xaf, (byte)0xfd, (byte)0x5b, (byte)0x4f, (byte)0x79}, + {(byte)0xcb, (byte)0xcf, (byte)0xb0, (byte)0xcb, (byte)0x48, (byte)0x72, (byte)0x44, (byte)0x8b, (byte)0x79, (byte)0xee, (byte)0xcd, (byte)0x1c, (byte)0xbe, (byte)0x39, (byte)0x70, (byte)0x44}, + {(byte)0x7e, (byte)0xea, (byte)0xcd, (byte)0xee, (byte)0x6e, (byte)0x90, (byte)0x32, (byte)0xb7, (byte)0x8d, (byte)0x53, (byte)0x35, (byte)0xed, (byte)0x2b, (byte)0x8a, (byte)0x05, (byte)0x7b}, + {(byte)0x67, (byte)0xc2, (byte)0x8f, (byte)0x43, (byte)0x5e, (byte)0x2e, (byte)0x7c, (byte)0xd0, (byte)0xe2, (byte)0x41, (byte)0x27, (byte)0x61, (byte)0xda, (byte)0x4f, (byte)0xef, (byte)0x1b}, + {(byte)0x29, (byte)0x24, (byte)0xd9, (byte)0xb0, (byte)0xaf, (byte)0xca, (byte)0xcc, (byte)0x07, (byte)0x67, (byte)0x5f, (byte)0xfd, (byte)0xe2, (byte)0x1f, (byte)0xc7, (byte)0x0b, (byte)0x3b}, + {(byte)0xab, (byte)0x4d, (byte)0x63, (byte)0xf1, (byte)0xe6, (byte)0x86, (byte)0x7f, (byte)0xe9, (byte)0xec, (byte)0xdb, (byte)0x8f, (byte)0xca, (byte)0xb9, (byte)0xd4, (byte)0x65, (byte)0xee}, + {(byte)0x1c, (byte)0x30, (byte)0xbf, (byte)0x84, (byte)0xd4, (byte)0xb7, (byte)0xcd, (byte)0x64, (byte)0x5b, (byte)0x2a, (byte)0x40, (byte)0x4f, (byte)0xad, (byte)0x03, (byte)0x7e, (byte)0x33}, + {(byte)0xb2, (byte)0xcc, (byte)0x0b, (byte)0xb9, (byte)0x94, (byte)0x17, (byte)0x23, (byte)0xbf, (byte)0x69, (byte)0x02, (byte)0x8b, (byte)0x2e, (byte)0x8d, (byte)0xf6, (byte)0x98, (byte)0x00}, + {(byte)0xfa, (byte)0x04, (byte)0x78, (byte)0xa6, (byte)0xde, (byte)0x6f, (byte)0x55, (byte)0x72, (byte)0x4a, (byte)0xaa, (byte)0x9e, (byte)0xc8, (byte)0x5c, (byte)0x9d, (byte)0x2d, (byte)0x8a}, + {(byte)0xdf, (byte)0xb4, (byte)0x9f, (byte)0x2b, (byte)0x6b, (byte)0x77, (byte)0x2a, (byte)0x12, (byte)0x0e, (byte)0xfa, (byte)0x4f, (byte)0x2e, (byte)0x29, (byte)0x12, (byte)0x9f, (byte)0xd4}, + {(byte)0x1e, (byte)0xa1, (byte)0x03, (byte)0x44, (byte)0xf4, (byte)0x49, (byte)0xa2, (byte)0x36, (byte)0x32, (byte)0xd6, (byte)0x11, (byte)0xae, (byte)0xbb, (byte)0x6a, (byte)0x12, (byte)0xee}, + {(byte)0xaf, (byte)0x04, (byte)0x49, (byte)0x88, (byte)0x4b, (byte)0x05, (byte)0x00, (byte)0x84, (byte)0x5f, (byte)0x96, (byte)0x00, (byte)0xc9, (byte)0x9c, (byte)0xa8, (byte)0xec, (byte)0xa6}, + {(byte)0x21, (byte)0x02, (byte)0x5e, (byte)0xd8, (byte)0x9d, (byte)0x19, (byte)0x9c, (byte)0x4f, (byte)0x78, (byte)0xa2, (byte)0xc7, (byte)0xe3, (byte)0x27, (byte)0xe5, (byte)0x93, (byte)0xec}, + {(byte)0xbf, (byte)0x3a, (byte)0xaa, (byte)0xf8, (byte)0xa7, (byte)0x59, (byte)0xc9, (byte)0xb7, (byte)0xb9, (byte)0x28, (byte)0x2e, (byte)0xcd, (byte)0x82, (byte)0xd4, (byte)0x01, (byte)0x73}, + {(byte)0x62, (byte)0x60, (byte)0x70, (byte)0x0d, (byte)0x61, (byte)0x86, (byte)0xb0, (byte)0x17, (byte)0x37, (byte)0xf2, (byte)0xef, (byte)0xd9, (byte)0x10, (byte)0x30, (byte)0x7d, (byte)0x6b}, + {(byte)0x5a, (byte)0xca, (byte)0x45, (byte)0xc2, (byte)0x21, (byte)0x30, (byte)0x04, (byte)0x43, (byte)0x81, (byte)0xc2, (byte)0x91, (byte)0x53, (byte)0xf6, (byte)0xfc, (byte)0x9a, (byte)0xc6}, + {(byte)0x92, (byte)0x23, (byte)0x97, (byte)0x3c, (byte)0x22, (byte)0x6b, (byte)0x68, (byte)0xbb, (byte)0x2c, (byte)0xaf, (byte)0x92, (byte)0xe8, (byte)0x36, (byte)0xd1, (byte)0x94, (byte)0x3a}, + {(byte)0xd3, (byte)0xbf, (byte)0x92, (byte)0x38, (byte)0x22, (byte)0x58, (byte)0x86, (byte)0xeb, (byte)0x6c, (byte)0xba, (byte)0xb9, (byte)0x58, (byte)0xe5, (byte)0x10, (byte)0x71, (byte)0xb4}, + {(byte)0xdb, (byte)0x86, (byte)0x3c, (byte)0xe5, (byte)0xae, (byte)0xf0, (byte)0xc6, (byte)0x77, (byte)0x93, (byte)0x3d, (byte)0xfd, (byte)0xdd, (byte)0x24, (byte)0xe1, (byte)0x12, (byte)0x8d}, + {(byte)0xbb, (byte)0x60, (byte)0x62, (byte)0x68, (byte)0xff, (byte)0xeb, (byte)0xa0, (byte)0x9c, (byte)0x83, (byte)0xe4, (byte)0x8d, (byte)0xe3, (byte)0xcb, (byte)0x22, (byte)0x12, (byte)0xb1}, + {(byte)0x73, (byte)0x4b, (byte)0xd3, (byte)0xdc, (byte)0xe2, (byte)0xe4, (byte)0xd1, (byte)0x9c, (byte)0x2d, (byte)0xb9, (byte)0x1a, (byte)0x4e, (byte)0xc7, (byte)0x2b, (byte)0xf7, (byte)0x7d}, + {(byte)0x43, (byte)0xbb, (byte)0x47, (byte)0xc3, (byte)0x61, (byte)0x30, (byte)0x1b, (byte)0x43, (byte)0x4b, (byte)0x14, (byte)0x15, (byte)0xc4, (byte)0x2c, (byte)0xb3, (byte)0x92, (byte)0x4e}, + {(byte)0xdb, (byte)0xa7, (byte)0x75, (byte)0xa8, (byte)0xe7, (byte)0x07, (byte)0xef, (byte)0xf6, (byte)0x03, (byte)0xb2, (byte)0x31, (byte)0xdd, (byte)0x16, (byte)0xeb, (byte)0x68, (byte)0x99}, + {(byte)0x6d, (byte)0xf3, (byte)0x61, (byte)0x4b, (byte)0x3c, (byte)0x75, (byte)0x59, (byte)0x77, (byte)0x8e, (byte)0x5e, (byte)0x23, (byte)0x02, (byte)0x7e, (byte)0xca, (byte)0x47, (byte)0x2c}, + {(byte)0xcd, (byte)0xa7, (byte)0x5a, (byte)0x17, (byte)0xd6, (byte)0xde, (byte)0x7d, (byte)0x77, (byte)0x6d, (byte)0x1b, (byte)0xe5, (byte)0xb9, (byte)0xb8, (byte)0x86, (byte)0x17, (byte)0xf9}, + {(byte)0xec, (byte)0x6b, (byte)0x43, (byte)0xf0, (byte)0x6b, (byte)0xa8, (byte)0xe9, (byte)0xaa, (byte)0x9d, (byte)0x6c, (byte)0x06, (byte)0x9d, (byte)0xa9, (byte)0x46, (byte)0xee, (byte)0x5d}, + {(byte)0xcb, (byte)0x1e, (byte)0x69, (byte)0x50, (byte)0xf9, (byte)0x57, (byte)0x33, (byte)0x2b, (byte)0xa2, (byte)0x53, (byte)0x11, (byte)0x59, (byte)0x3b, (byte)0xf3, (byte)0x27, (byte)0xc1}, + {(byte)0x2c, (byte)0xee, (byte)0x0c, (byte)0x75, (byte)0x00, (byte)0xda, (byte)0x61, (byte)0x9c, (byte)0xe4, (byte)0xed, (byte)0x03, (byte)0x53, (byte)0x60, (byte)0x0e, (byte)0xd0, (byte)0xd9}, + {(byte)0xf0, (byte)0xb1, (byte)0xa5, (byte)0xa1, (byte)0x96, (byte)0xe9, (byte)0x0c, (byte)0xab, (byte)0x80, (byte)0xbb, (byte)0xba, (byte)0xbc, (byte)0x63, (byte)0xa4, (byte)0xa3, (byte)0x50}, + {(byte)0xae, (byte)0x3d, (byte)0xb1, (byte)0x02, (byte)0x5e, (byte)0x96, (byte)0x29, (byte)0x88, (byte)0xab, (byte)0x0d, (byte)0xde, (byte)0x30, (byte)0x93, (byte)0x8d, (byte)0xca, (byte)0x39}, + {(byte)0x17, (byte)0xbb, (byte)0x8f, (byte)0x38, (byte)0xd5, (byte)0x54, (byte)0xa4, (byte)0x0b, (byte)0x88, (byte)0x14, (byte)0xf3, (byte)0xa8, (byte)0x2e, (byte)0x75, (byte)0xb4, (byte)0x42}, + {(byte)0x34, (byte)0xbb, (byte)0x8a, (byte)0x5b, (byte)0x5f, (byte)0x42, (byte)0x7f, (byte)0xd7, (byte)0xae, (byte)0xb6, (byte)0xb7, (byte)0x79, (byte)0x36, (byte)0x0a, (byte)0x16, (byte)0xf6}, + {(byte)0x26, (byte)0xf6, (byte)0x52, (byte)0x41, (byte)0xcb, (byte)0xe5, (byte)0x54, (byte)0x38, (byte)0x43, (byte)0xce, (byte)0x59, (byte)0x18, (byte)0xff, (byte)0xba, (byte)0xaf, (byte)0xde}, + {(byte)0x4c, (byte)0xe9, (byte)0x9a, (byte)0x54, (byte)0xb9, (byte)0xf3, (byte)0x02, (byte)0x6a, (byte)0xa2, (byte)0xca, (byte)0x9c, (byte)0xf7, (byte)0x83, (byte)0x9e, (byte)0xc9, (byte)0x78}, + {(byte)0xae, (byte)0x51, (byte)0xa5, (byte)0x1a, (byte)0x1b, (byte)0xdf, (byte)0xf7, (byte)0xbe, (byte)0x40, (byte)0xc0, (byte)0x6e, (byte)0x28, (byte)0x22, (byte)0x90, (byte)0x12, (byte)0x35}, + {(byte)0xa0, (byte)0xc1, (byte)0x61, (byte)0x3c, (byte)0xba, (byte)0x7e, (byte)0xd2, (byte)0x2b, (byte)0xc1, (byte)0x73, (byte)0xbc, (byte)0x0f, (byte)0x48, (byte)0xa6, (byte)0x59, (byte)0xcf}, + {(byte)0x75, (byte)0x6a, (byte)0xcc, (byte)0x03, (byte)0x02, (byte)0x28, (byte)0x82, (byte)0x88, (byte)0x4a, (byte)0xd6, (byte)0xbd, (byte)0xfd, (byte)0xe9, (byte)0xc5, (byte)0x9d, (byte)0xa1} + }; + + private final byte[] buffer; + private int off; + + public Haraka512Digest() + { + this.buffer = new byte[64]; + } + + public Haraka512Digest(Haraka512Digest digest) + { + this.buffer = Arrays.clone(digest.buffer); + this.off = digest.off; + } + + private void mix512(byte[][] s1, byte[][] s2) + { + System.arraycopy(s1[0], 12, s2[0], 0, 4); + System.arraycopy(s1[2], 12, s2[0], 4, 4); + System.arraycopy(s1[1], 12, s2[0], 8, 4); + System.arraycopy(s1[3], 12, s2[0], 12, 4); + + System.arraycopy(s1[2], 0, s2[1], 0, 4); + System.arraycopy(s1[0], 0, s2[1], 4, 4); + System.arraycopy(s1[3], 0, s2[1], 8, 4); + System.arraycopy(s1[1], 0, s2[1], 12, 4); + + System.arraycopy(s1[2], 4, s2[2], 0, 4); + System.arraycopy(s1[0], 4, s2[2], 4, 4); + System.arraycopy(s1[3], 4, s2[2], 8, 4); + System.arraycopy(s1[1], 4, s2[2], 12, 4); + + System.arraycopy(s1[0], 8, s2[3], 0, 4); + System.arraycopy(s1[2], 8, s2[3], 4, 4); + System.arraycopy(s1[1], 8, s2[3], 8, 4); + System.arraycopy(s1[3], 8, s2[3], 12, 4); + } + + private int haraka512256(byte[] msg, byte[] out, int outOff) + { + byte[][] s1 = new byte[4][16]; + byte[][] s2 = new byte[4][16]; + + //-- Unrolled version of above. + + System.arraycopy(msg, 0, s1[0], 0, 16); + System.arraycopy(msg, 16, s1[1], 0, 16); + System.arraycopy(msg, 32, s1[2], 0, 16); + System.arraycopy(msg, 48, s1[3], 0, 16); + + s1[0] = aesEnc(s1[0], RC[0]); + s1[1] = aesEnc(s1[1], RC[1]); + s1[2] = aesEnc(s1[2], RC[2]); + s1[3] = aesEnc(s1[3], RC[3]); + s1[0] = aesEnc(s1[0], RC[4]); + s1[1] = aesEnc(s1[1], RC[5]); + s1[2] = aesEnc(s1[2], RC[6]); + s1[3] = aesEnc(s1[3], RC[7]); + mix512(s1, s2); + + s1[0] = aesEnc(s2[0], RC[8]); + s1[1] = aesEnc(s2[1], RC[9]); + s1[2] = aesEnc(s2[2], RC[10]); + s1[3] = aesEnc(s2[3], RC[11]); + s1[0] = aesEnc(s1[0], RC[12]); + s1[1] = aesEnc(s1[1], RC[13]); + s1[2] = aesEnc(s1[2], RC[14]); + s1[3] = aesEnc(s1[3], RC[15]); + mix512(s1, s2); + + s1[0] = aesEnc(s2[0], RC[16]); + s1[1] = aesEnc(s2[1], RC[17]); + s1[2] = aesEnc(s2[2], RC[18]); + s1[3] = aesEnc(s2[3], RC[19]); + s1[0] = aesEnc(s1[0], RC[20]); + s1[1] = aesEnc(s1[1], RC[21]); + s1[2] = aesEnc(s1[2], RC[22]); + s1[3] = aesEnc(s1[3], RC[23]); + mix512(s1, s2); + + s1[0] = aesEnc(s2[0], RC[24]); + s1[1] = aesEnc(s2[1], RC[25]); + s1[2] = aesEnc(s2[2], RC[26]); + s1[3] = aesEnc(s2[3], RC[27]); + s1[0] = aesEnc(s1[0], RC[28]); + s1[1] = aesEnc(s1[1], RC[29]); + s1[2] = aesEnc(s1[2], RC[30]); + s1[3] = aesEnc(s1[3], RC[31]); + mix512(s1, s2); + + s1[0] = aesEnc(s2[0], RC[32]); + s1[1] = aesEnc(s2[1], RC[33]); + s1[2] = aesEnc(s2[2], RC[34]); + s1[3] = aesEnc(s2[3], RC[35]); + s1[0] = aesEnc(s1[0], RC[36]); + s1[1] = aesEnc(s1[1], RC[37]); + s1[2] = aesEnc(s1[2], RC[38]); + s1[3] = aesEnc(s1[3], RC[39]); + mix512(s1, s2); + + s1[0] = xor(s2[0], msg, 0); + s1[1] = xor(s2[1], msg, 16); + s1[2] = xor(s2[2], msg, 32); + s1[3] = xor(s2[3], msg, 48); + + System.arraycopy(s1[0], 8, out, outOff, 8); + System.arraycopy(s1[1], 8, out, outOff + 8, 8); + System.arraycopy(s1[2], 0, out, outOff + 16, 8); + System.arraycopy(s1[3], 0, out, outOff + 24, 8); + + return DIGEST_SIZE; + } + + public String getAlgorithmName() + { + return "Haraka-512"; + } + + public void update(byte in) + { + if (off + 1 > 64) + { + throw new IllegalArgumentException("total input cannot be more than 64 bytes"); + } + + buffer[off++] = in; + } + + public void update(byte[] in, int inOff, int len) + { + if (off + len > 64) + { + throw new IllegalArgumentException("total input cannot be more than 64 bytes"); + } + + System.arraycopy(in, inOff, buffer, off, len); + off += len; + } + + public int doFinal(byte[] out, int outOff) + { + if (off != 64) + { + throw new IllegalStateException("input must be exactly 64 bytes"); + } + + if (out.length - outOff < 32) + { + throw new IllegalArgumentException("output too short to receive digest"); + } + + int rv = haraka512256(buffer, out, outOff); + + reset(); + + return rv; + } + + public void reset() + { + off = 0; + Arrays.clear(buffer); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/HarakaBase.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/HarakaBase.java new file mode 100644 index 000000000..8617792a3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/HarakaBase.java @@ -0,0 +1,141 @@ +package com.fr.third.org.bouncycastle.crypto.digests; + +import com.fr.third.org.bouncycastle.crypto.Digest; + +/** + * Base class for Haraka v2, https://eprint.iacr.org/2016/098.pdf + */ +public abstract class HarakaBase + implements Digest +{ + protected static final int DIGEST_SIZE = 32; + + private static final byte[][] S = new byte[][]{ + {(byte)0x63, (byte)0x7c, (byte)0x77, (byte)0x7b, (byte)0xf2, (byte)0x6b, (byte)0x6f, (byte)0xc5, (byte)0x30, (byte)0x01, (byte)0x67, (byte)0x2b, (byte)0xfe, (byte)0xd7, (byte)0xab, (byte)0x76}, + {(byte)0xca, (byte)0x82, (byte)0xc9, (byte)0x7d, (byte)0xfa, (byte)0x59, (byte)0x47, (byte)0xf0, (byte)0xad, (byte)0xd4, (byte)0xa2, (byte)0xaf, (byte)0x9c, (byte)0xa4, (byte)0x72, (byte)0xc0}, + {(byte)0xb7, (byte)0xfd, (byte)0x93, (byte)0x26, (byte)0x36, (byte)0x3f, (byte)0xf7, (byte)0xcc, (byte)0x34, (byte)0xa5, (byte)0xe5, (byte)0xf1, (byte)0x71, (byte)0xd8, (byte)0x31, (byte)0x15}, + {(byte)0x04, (byte)0xc7, (byte)0x23, (byte)0xc3, (byte)0x18, (byte)0x96, (byte)0x05, (byte)0x9a, (byte)0x07, (byte)0x12, (byte)0x80, (byte)0xe2, (byte)0xeb, (byte)0x27, (byte)0xb2, (byte)0x75}, + {(byte)0x09, (byte)0x83, (byte)0x2c, (byte)0x1a, (byte)0x1b, (byte)0x6e, (byte)0x5a, (byte)0xa0, (byte)0x52, (byte)0x3b, (byte)0xd6, (byte)0xb3, (byte)0x29, (byte)0xe3, (byte)0x2f, (byte)0x84}, + {(byte)0x53, (byte)0xd1, (byte)0x00, (byte)0xed, (byte)0x20, (byte)0xfc, (byte)0xb1, (byte)0x5b, (byte)0x6a, (byte)0xcb, (byte)0xbe, (byte)0x39, (byte)0x4a, (byte)0x4c, (byte)0x58, (byte)0xcf}, + {(byte)0xd0, (byte)0xef, (byte)0xaa, (byte)0xfb, (byte)0x43, (byte)0x4d, (byte)0x33, (byte)0x85, (byte)0x45, (byte)0xf9, (byte)0x02, (byte)0x7f, (byte)0x50, (byte)0x3c, (byte)0x9f, (byte)0xa8}, + {(byte)0x51, (byte)0xa3, (byte)0x40, (byte)0x8f, (byte)0x92, (byte)0x9d, (byte)0x38, (byte)0xf5, (byte)0xbc, (byte)0xb6, (byte)0xda, (byte)0x21, (byte)0x10, (byte)0xff, (byte)0xf3, (byte)0xd2}, + {(byte)0xcd, (byte)0x0c, (byte)0x13, (byte)0xec, (byte)0x5f, (byte)0x97, (byte)0x44, (byte)0x17, (byte)0xc4, (byte)0xa7, (byte)0x7e, (byte)0x3d, (byte)0x64, (byte)0x5d, (byte)0x19, (byte)0x73}, + {(byte)0x60, (byte)0x81, (byte)0x4f, (byte)0xdc, (byte)0x22, (byte)0x2a, (byte)0x90, (byte)0x88, (byte)0x46, (byte)0xee, (byte)0xb8, (byte)0x14, (byte)0xde, (byte)0x5e, (byte)0x0b, (byte)0xdb}, + {(byte)0xe0, (byte)0x32, (byte)0x3a, (byte)0x0a, (byte)0x49, (byte)0x06, (byte)0x24, (byte)0x5c, (byte)0xc2, (byte)0xd3, (byte)0xac, (byte)0x62, (byte)0x91, (byte)0x95, (byte)0xe4, (byte)0x79}, + {(byte)0xe7, (byte)0xc8, (byte)0x37, (byte)0x6d, (byte)0x8d, (byte)0xd5, (byte)0x4e, (byte)0xa9, (byte)0x6c, (byte)0x56, (byte)0xf4, (byte)0xea, (byte)0x65, (byte)0x7a, (byte)0xae, (byte)0x08}, + {(byte)0xba, (byte)0x78, (byte)0x25, (byte)0x2e, (byte)0x1c, (byte)0xa6, (byte)0xb4, (byte)0xc6, (byte)0xe8, (byte)0xdd, (byte)0x74, (byte)0x1f, (byte)0x4b, (byte)0xbd, (byte)0x8b, (byte)0x8a}, + {(byte)0x70, (byte)0x3e, (byte)0xb5, (byte)0x66, (byte)0x48, (byte)0x03, (byte)0xf6, (byte)0x0e, (byte)0x61, (byte)0x35, (byte)0x57, (byte)0xb9, (byte)0x86, (byte)0xc1, (byte)0x1d, (byte)0x9e}, + {(byte)0xe1, (byte)0xf8, (byte)0x98, (byte)0x11, (byte)0x69, (byte)0xd9, (byte)0x8e, (byte)0x94, (byte)0x9b, (byte)0x1e, (byte)0x87, (byte)0xe9, (byte)0xce, (byte)0x55, (byte)0x28, (byte)0xdf}, + {(byte)0x8c, (byte)0xa1, (byte)0x89, (byte)0x0d, (byte)0xbf, (byte)0xe6, (byte)0x42, (byte)0x68, (byte)0x41, (byte)0x99, (byte)0x2d, (byte)0x0f, (byte)0xb0, (byte)0x54, (byte)0xbb, (byte)0x16}}; + + static byte sBox(byte x) + { + return S[(((x & 0xFF) >>> 4))][x & 0xF]; + } + + static byte[] subBytes(byte[] s) + { + byte[] out = new byte[s.length]; + out[0] = sBox(s[0]); + out[1] = sBox(s[1]); + out[2] = sBox(s[2]); + out[3] = sBox(s[3]); + out[4] = sBox(s[4]); + out[5] = sBox(s[5]); + out[6] = sBox(s[6]); + out[7] = sBox(s[7]); + out[8] = sBox(s[8]); + out[9] = sBox(s[9]); + out[10] = sBox(s[10]); + out[11] = sBox(s[11]); + out[12] = sBox(s[12]); + out[13] = sBox(s[13]); + out[14] = sBox(s[14]); + out[15] = sBox(s[15]); + return out; + } + + static byte[] shiftRows(byte[] s) + { + return new byte[]{ + s[0], s[5], s[10], s[15], + s[4], s[9], s[14], s[3], + s[8], s[13], s[2], s[7], + s[12], s[1], s[6], s[11] + }; + } + + static byte[] aesEnc(byte[] s, byte[] rk) + { + s = subBytes(s); + s = shiftRows(s); + s = mixColumns(s); + xorReverse(s, rk); + return s; + } + + static byte xTime(byte x) + { + if ((x >>> 7) > 0) + { + return (byte)(((x << 1) ^ 0x1b) & 0xff); + } + else + { + return (byte)((x << 1) & 0xff); + } + } + + + static void xorReverse(byte[] x, byte[] y) + { + x[0] = (byte)(x[0] ^ y[15]); + x[1] = (byte)(x[1] ^ y[14]); + x[2] = (byte)(x[2] ^ y[13]); + x[3] = (byte)(x[3] ^ y[12]); + x[4] = (byte)(x[4] ^ y[11]); + x[5] = (byte)(x[5] ^ y[10]); + x[6] = (byte)(x[6] ^ y[9]); + x[7] = (byte)(x[7] ^ y[8]); + x[8] = (byte)(x[8] ^ y[7]); + x[9] = (byte)(x[9] ^ y[6]); + x[10] = (byte)(x[10] ^ y[5]); + x[11] = (byte)(x[11] ^ y[4]); + x[12] = (byte)(x[12] ^ y[3]); + x[13] = (byte)(x[13] ^ y[2]); + x[14] = (byte)(x[14] ^ y[1]); + x[15] = (byte)(x[15] ^ y[0]); + } + + + static byte[] xor(byte[] x, byte[] y, int yStart) + { + byte[] out = new byte[16]; + for (int i = 0; i < out.length; i++) + { + out[i] = (byte)(x[i] ^ y[yStart++]); + } + return out; + } + + + static private byte[] mixColumns(byte[] s) + { + byte[] out = new byte[s.length]; + int j = 0; + for (int i = 0; i < 4; i++) + { + out[j++] = (byte)(xTime(s[4 * i]) ^ xTime(s[4 * i + 1]) ^ s[4 * i + 1] ^ s[4 * i + 2] ^ s[4 * i + 3]); + out[j++] = (byte)(s[4 * i] ^ xTime(s[4 * i + 1]) ^ xTime(s[4 * i + 2]) ^ s[4 * i + 2] ^ s[4 * i + 3]); + out[j++] = (byte)(s[4 * i] ^ s[4 * i + 1] ^ xTime(s[4 * i + 2]) ^ xTime(s[4 * i + 3]) ^ s[4 * i + 3]); + out[j++] = (byte)(xTime(s[4 * i]) ^ s[4 * i] ^ s[4 * i + 1] ^ s[4 * i + 2] ^ xTime(s[4 * i + 3])); + } + + return out; + } + + public int getDigestSize() + { + return DIGEST_SIZE; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/NullDigest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/NullDigest.java index a4ae1c448..1fe716ced 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/NullDigest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/NullDigest.java @@ -3,12 +3,13 @@ package com.fr.third.org.bouncycastle.crypto.digests; import java.io.ByteArrayOutputStream; import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.util.Arrays; public class NullDigest implements Digest { - private ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + private OpenByteArrayOutputStream bOut = new OpenByteArrayOutputStream(); public String getAlgorithmName() { @@ -32,17 +33,33 @@ public class NullDigest public int doFinal(byte[] out, int outOff) { - byte[] res = bOut.toByteArray(); + int size = bOut.size(); - System.arraycopy(res, 0, out, outOff, res.length); + bOut.copy(out, outOff); reset(); - return res.length; + return size; } public void reset() { bOut.reset(); } + + private static class OpenByteArrayOutputStream + extends ByteArrayOutputStream + { + public void reset() + { + super.reset(); + + Arrays.clear(buf); + } + + void copy(byte[] out, int outOff) + { + System.arraycopy(buf, 0, out, outOff, this.size()); + } + } } \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/SHA256Digest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/SHA256Digest.java index 4db7e178a..fb75f3774 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/SHA256Digest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/SHA256Digest.java @@ -271,42 +271,34 @@ public class SHA256Digest } /* SHA-256 functions */ - private int Ch( - int x, - int y, - int z) + private static int Ch(int x, int y, int z) { return (x & y) ^ ((~x) & z); +// return z ^ (x & (y ^ z)); } - private int Maj( - int x, - int y, - int z) + private static int Maj(int x, int y, int z) { - return (x & y) ^ (x & z) ^ (y & z); +// return (x & y) ^ (x & z) ^ (y & z); + return (x & y) | (z & (x ^ y)); } - private int Sum0( - int x) + private static int Sum0(int x) { return ((x >>> 2) | (x << 30)) ^ ((x >>> 13) | (x << 19)) ^ ((x >>> 22) | (x << 10)); } - private int Sum1( - int x) + private static int Sum1(int x) { return ((x >>> 6) | (x << 26)) ^ ((x >>> 11) | (x << 21)) ^ ((x >>> 25) | (x << 7)); } - private int Theta0( - int x) + private static int Theta0(int x) { return ((x >>> 7) | (x << 25)) ^ ((x >>> 18) | (x << 14)) ^ (x >>> 3); } - private int Theta1( - int x) + private static int Theta1(int x) { return ((x >>> 17) | (x << 15)) ^ ((x >>> 19) | (x << 13)) ^ (x >>> 10); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/SkeinEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/SkeinEngine.java index 219c9c3ff..15ffc4786 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/SkeinEngine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/digests/SkeinEngine.java @@ -9,6 +9,7 @@ import com.fr.third.org.bouncycastle.crypto.engines.ThreefishEngine; import com.fr.third.org.bouncycastle.crypto.macs.SkeinMac; import com.fr.third.org.bouncycastle.crypto.params.SkeinParameters; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Integers; import com.fr.third.org.bouncycastle.util.Memoable; /** @@ -221,7 +222,7 @@ public class SkeinEngine private static Integer variantIdentifier(int blockSizeBytes, int outputSizeBytes) { - return new Integer((outputSizeBytes << 16) | blockSizeBytes); + return Integers.valueOf((outputSizeBytes << 16) | blockSizeBytes); } private static class UbiTweak diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/CustomNamedCurves.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/CustomNamedCurves.java index 2ad41a418..dc4bf24ac 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/CustomNamedCurves.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/CustomNamedCurves.java @@ -6,12 +6,14 @@ import java.util.Hashtable; import java.util.Vector; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.cryptlib.CryptlibObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.gm.GMObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.sec.SECObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParametersHolder; import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.WNafUtil; import com.fr.third.org.bouncycastle.math.ec.custom.djb.Curve25519; import com.fr.third.org.bouncycastle.math.ec.custom.gm.SM2P256V1Curve; import com.fr.third.org.bouncycastle.math.ec.custom.sec.SecP128R1Curve; @@ -46,11 +48,19 @@ import com.fr.third.org.bouncycastle.math.ec.custom.sec.SecT571K1Curve; import com.fr.third.org.bouncycastle.math.ec.custom.sec.SecT571R1Curve; import com.fr.third.org.bouncycastle.math.ec.endo.GLVTypeBEndomorphism; import com.fr.third.org.bouncycastle.math.ec.endo.GLVTypeBParameters; +import com.fr.third.org.bouncycastle.math.ec.endo.ScalarSplitParameters; import com.fr.third.org.bouncycastle.util.Strings; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class CustomNamedCurves { + private static X9ECPoint configureBasepoint(ECCurve curve, String encoding) + { + X9ECPoint G = new X9ECPoint(curve, Hex.decodeStrict(encoding)); + WNafUtil.configureBasepoint(G.getPoint()); + return G; + } + private static ECCurve configureCurve(ECCurve curve) { return curve; @@ -80,9 +90,8 @@ public class CustomNamedCurves * * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14) */ - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A" - + "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9")); + X9ECPoint G = configureBasepoint(curve, + "042AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } @@ -95,11 +104,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("000E0D4D696E6768756151750CC03A4473D03679"); + byte[] S = Hex.decodeStrict("000E0D4D696E6768756151750CC03A4473D03679"); ECCurve curve = configureCurve(new SecP128R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "161FF7528B899B2D0C28607CA52C5B86" - + "CF5AC8395BAFEB13C02DA292DDED7A83")); + X9ECPoint G = configureBasepoint(curve, + "04161FF7528B899B2D0C28607CA52C5B86CF5AC8395BAFEB13C02DA292DDED7A83"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -115,19 +123,19 @@ public class CustomNamedCurves GLVTypeBParameters glv = new GLVTypeBParameters( new BigInteger("9ba48cba5ebcb9b6bd33b92830b2a2e0e192f10a", 16), new BigInteger("c39c6c3b3a36d7701b9c71a1f5804ae5d0003f4", 16), - new BigInteger[]{ - new BigInteger("9162fbe73984472a0a9e", 16), - new BigInteger("-96341f1138933bc2f505", 16) }, - new BigInteger[]{ - new BigInteger("127971af8721782ecffa3", 16), - new BigInteger("9162fbe73984472a0a9e", 16) }, - new BigInteger("9162fbe73984472a0a9d0590", 16), - new BigInteger("96341f1138933bc2f503fd44", 16), - 176); + new ScalarSplitParameters( + new BigInteger[]{ + new BigInteger("9162fbe73984472a0a9e", 16), + new BigInteger("-96341f1138933bc2f505", 16) }, + new BigInteger[]{ + new BigInteger("127971af8721782ecffa3", 16), + new BigInteger("9162fbe73984472a0a9e", 16) }, + new BigInteger("9162fbe73984472a0a9d0590", 16), + new BigInteger("96341f1138933bc2f503fd44", 16), + 176)); ECCurve curve = configureCurveGLV(new SecP160K1Curve(), glv); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB" - + "938CF935318FDCED6BC28286531733C3F03C4FEE")); + X9ECPoint G = configureBasepoint(curve, + "043B4C382CE37AA192A4019E763036F4F5DD4D7EBB938CF935318FDCED6BC28286531733C3F03C4FEE"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -139,11 +147,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("1053CDE42C14D696E67687561517533BF3F83345"); + byte[] S = Hex.decodeStrict("1053CDE42C14D696E67687561517533BF3F83345"); ECCurve curve = configureCurve(new SecP160R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "4A96B5688EF573284664698968C38BB913CBFC82" - + "23A628553168947D59DCC912042351377AC5FB32")); + X9ECPoint G = configureBasepoint(curve, + "044A96B5688EF573284664698968C38BB913CBFC8223A628553168947D59DCC912042351377AC5FB32"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -155,11 +162,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("B99B99B099B323E02709A4D696E6768756151751"); + byte[] S = Hex.decodeStrict("B99B99B099B323E02709A4D696E6768756151751"); ECCurve curve = configureCurve(new SecP160R2Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "52DCB034293A117E1F4FF11B30F7199D3144CE6D" - + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E")); + X9ECPoint G = configureBasepoint(curve, + "0452DCB034293A117E1F4FF11B30F7199D3144CE6DFEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -175,19 +181,19 @@ public class CustomNamedCurves GLVTypeBParameters glv = new GLVTypeBParameters( new BigInteger("bb85691939b869c1d087f601554b96b80cb4f55b35f433c2", 16), new BigInteger("3d84f26c12238d7b4f3d516613c1759033b1a5800175d0b1", 16), - new BigInteger[]{ - new BigInteger("71169be7330b3038edb025f1", 16), - new BigInteger("-b3fb3400dec5c4adceb8655c", 16) }, - new BigInteger[]{ - new BigInteger("12511cfe811d0f4e6bc688b4d", 16), - new BigInteger("71169be7330b3038edb025f1", 16) }, - new BigInteger("71169be7330b3038edb025f1d0f9", 16), - new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16), - 208); + new ScalarSplitParameters( + new BigInteger[]{ + new BigInteger("71169be7330b3038edb025f1", 16), + new BigInteger("-b3fb3400dec5c4adceb8655c", 16) }, + new BigInteger[]{ + new BigInteger("12511cfe811d0f4e6bc688b4d", 16), + new BigInteger("71169be7330b3038edb025f1", 16) }, + new BigInteger("71169be7330b3038edb025f1d0f9", 16), + new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16), + 208)); ECCurve curve = configureCurveGLV(new SecP192K1Curve(), glv); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D" - + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D")); + X9ECPoint G = configureBasepoint(curve, + "04DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -199,11 +205,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("3045AE6FC8422F64ED579528D38120EAE12196D5"); + byte[] S = Hex.decodeStrict("3045AE6FC8422F64ED579528D38120EAE12196D5"); ECCurve curve = configureCurve(new SecP192R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012" - + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811")); + X9ECPoint G = configureBasepoint(curve, + "04188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF101207192B95FFC8DA78631011ED6B24CDD573F977A11E794811"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -219,19 +224,19 @@ public class CustomNamedCurves GLVTypeBParameters glv = new GLVTypeBParameters( new BigInteger("fe0e87005b4e83761908c5131d552a850b3f58b749c37cf5b84d6768", 16), new BigInteger("60dcd2104c4cbc0be6eeefc2bdd610739ec34e317f9b33046c9e4788", 16), - new BigInteger[]{ - new BigInteger("6b8cf07d4ca75c88957d9d670591", 16), - new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) }, - new BigInteger[]{ - new BigInteger("1243ae1b4d71613bc9f780a03690e", 16), - new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) }, - new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16), - new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16), - 240); + new ScalarSplitParameters( + new BigInteger[]{ + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16), + new BigInteger("-b8adf1378a6eb73409fa6c9c637d", 16) }, + new BigInteger[]{ + new BigInteger("1243ae1b4d71613bc9f780a03690e", 16), + new BigInteger("6b8cf07d4ca75c88957d9d670591", 16) }, + new BigInteger("6b8cf07d4ca75c88957d9d67059037a4", 16), + new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16), + 240)); ECCurve curve = configureCurveGLV(new SecP224K1Curve(), glv); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C" - + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5")); + X9ECPoint G = configureBasepoint(curve, + "04A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -243,11 +248,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5"); + byte[] S = Hex.decodeStrict("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5"); ECCurve curve = configureCurve(new SecP224R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21" - + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34")); + X9ECPoint G = configureBasepoint(curve, + "04B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -263,19 +267,19 @@ public class CustomNamedCurves GLVTypeBParameters glv = new GLVTypeBParameters( new BigInteger("7ae96a2b657c07106e64479eac3434e99cf0497512f58995c1396c28719501ee", 16), new BigInteger("5363ad4cc05c30e0a5261c028812645a122e22ea20816678df02967c1b23bd72", 16), - new BigInteger[]{ - new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16), - new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) }, - new BigInteger[]{ - new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16), - new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) }, - new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16), - new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16), - 272); + new ScalarSplitParameters( + new BigInteger[]{ + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16), + new BigInteger("-e4437ed6010e88286f547fa90abfe4c3", 16) }, + new BigInteger[]{ + new BigInteger("114ca50f7a8e2f3f657c1108d9d44cfd8", 16), + new BigInteger("3086d221a7d46bcde86c90e49284eb15", 16) }, + new BigInteger("3086d221a7d46bcde86c90e49284eb153dab", 16), + new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16), + 272)); ECCurve curve = configureCurveGLV(new SecP256K1Curve(), glv); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798" - + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8")); + X9ECPoint G = configureBasepoint(curve, + "0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -287,11 +291,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("C49D360886E704936A6678E1139D26B7819F7E90"); + byte[] S = Hex.decodeStrict("C49D360886E704936A6678E1139D26B7819F7E90"); ECCurve curve = configureCurve(new SecP256R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296" - + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5")); + X9ECPoint G = configureBasepoint(curve, + "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -303,11 +306,11 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("A335926AA319A27A1D00896A6773A4827ACDAC73"); + byte[] S = Hex.decodeStrict("A335926AA319A27A1D00896A6773A4827ACDAC73"); ECCurve curve = configureCurve(new SecP384R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + X9ECPoint G = configureBasepoint(curve, "04" + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7" - + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F")); + + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -319,11 +322,11 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("D09E8800291CB85396CC6717393284AAA0DA64BA"); + byte[] S = Hex.decodeStrict("D09E8800291CB85396CC6717393284AAA0DA64BA"); ECCurve curve = configureCurve(new SecP521R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + X9ECPoint G = configureBasepoint(curve, "04" + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66" - + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650")); + + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -335,11 +338,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("10E723AB14D696E6768756151756FEBF8FCB49A9"); + byte[] S = Hex.decodeStrict("10E723AB14D696E6768756151756FEBF8FCB49A9"); ECCurve curve = configureCurve(new SecT113R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "009D73616F35F4AB1407D73562C10F" - + "00A52830277958EE84D1315ED31886")); + X9ECPoint G = configureBasepoint(curve, + "04009D73616F35F4AB1407D73562C10F00A52830277958EE84D1315ED31886"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -351,11 +353,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("10C0FB15760860DEF1EEF4D696E676875615175D"); + byte[] S = Hex.decodeStrict("10C0FB15760860DEF1EEF4D696E676875615175D"); ECCurve curve = configureCurve(new SecT113R2Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "01A57A6A7B26CA5EF52FCDB8164797" - + "00B3ADC94ED1FE674C06E695BABA1D")); + X9ECPoint G = configureBasepoint(curve, + "0401A57A6A7B26CA5EF52FCDB816479700B3ADC94ED1FE674C06E695BABA1D"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -367,11 +368,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("4D696E676875615175985BD3ADBADA21B43A97E2"); + byte[] S = Hex.decodeStrict("4D696E676875615175985BD3ADBADA21B43A97E2"); ECCurve curve = configureCurve(new SecT131R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "0081BAF91FDF9833C40F9C181343638399" - + "078C6E7EA38C001F73C8134B1B4EF9E150")); + X9ECPoint G = configureBasepoint(curve, + "040081BAF91FDF9833C40F9C181343638399078C6E7EA38C001F73C8134B1B4EF9E150"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -383,11 +383,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("985BD3ADBAD4D696E676875615175A21B43A97E3"); + byte[] S = Hex.decodeStrict("985BD3ADBAD4D696E676875615175A21B43A97E3"); ECCurve curve = configureCurve(new SecT131R2Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "0356DCD8F2F95031AD652D23951BB366A8" - + "0648F06D867940A5366D9E265DE9EB240F")); + X9ECPoint G = configureBasepoint(curve, + "040356DCD8F2F95031AD652D23951BB366A80648F06D867940A5366D9E265DE9EB240F"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -401,9 +400,8 @@ public class CustomNamedCurves { byte[] S = null; ECCurve curve = configureCurve(new SecT163K1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8" - + "0289070FB05D38FF58321F2E800536D538CCDAA3D9")); + X9ECPoint G = configureBasepoint(curve, + "0402FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE80289070FB05D38FF58321F2E800536D538CCDAA3D9"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -415,11 +413,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("24B7B137C8A14D696E6768756151756FD0DA2E5C"); + byte[] S = Hex.decodeStrict("24B7B137C8A14D696E6768756151756FD0DA2E5C"); ECCurve curve = configureCurve(new SecT163R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "0369979697AB43897789566789567F787A7876A654" - + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883")); + X9ECPoint G = configureBasepoint(curve, + "040369979697AB43897789566789567F787A7876A65400435EDB42EFAFB2989D51FEFCE3C80988F41FF883"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -431,11 +428,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("85E25BFE5C86226CDB12016F7553F9D0E693A268"); + byte[] S = Hex.decodeStrict("85E25BFE5C86226CDB12016F7553F9D0E693A268"); ECCurve curve = configureCurve(new SecT163R2Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "03F0EBA16286A2D57EA0991168D4994637E8343E36" - + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1")); + X9ECPoint G = configureBasepoint(curve, + "0403F0EBA16286A2D57EA0991168D4994637E8343E3600D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -447,11 +443,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("103FAEC74D696E676875615175777FC5B191EF30"); + byte[] S = Hex.decodeStrict("103FAEC74D696E676875615175777FC5B191EF30"); ECCurve curve = configureCurve(new SecT193R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1" - + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05")); + X9ECPoint G = configureBasepoint(curve, + "0401F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E10025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -463,11 +458,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("10B7B4D696E676875615175137C8A16FD0DA2211"); + byte[] S = Hex.decodeStrict("10B7B4D696E676875615175137C8A16FD0DA2211"); ECCurve curve = configureCurve(new SecT193R2Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F" - + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C")); + X9ECPoint G = configureBasepoint(curve, + "0400D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -481,9 +475,8 @@ public class CustomNamedCurves { byte[] S = null; ECCurve curve = configureCurve(new SecT233K1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126" - + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3")); + X9ECPoint G = configureBasepoint(curve, + "04017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD612601DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -495,11 +488,10 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3"); + byte[] S = Hex.decodeStrict("74D59FF07F6B413D0EA14B344B20A2DB049B50C3"); ECCurve curve = configureCurve(new SecT233R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B" - + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052")); + X9ECPoint G = configureBasepoint(curve, + "0400FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -513,9 +505,8 @@ public class CustomNamedCurves { byte[] S = null; ECCurve curve = configureCurve(new SecT239K1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC" - + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA")); + X9ECPoint G = configureBasepoint(curve, + "0429A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -529,9 +520,9 @@ public class CustomNamedCurves { byte[] S = null; ECCurve curve = configureCurve(new SecT283K1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + X9ECPoint G = configureBasepoint(curve, "04" + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836" - + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259")); + + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -543,11 +534,11 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE"); + byte[] S = Hex.decodeStrict("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE"); ECCurve curve = configureCurve(new SecT283R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + X9ECPoint G = configureBasepoint(curve, "04" + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053" - + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4")); + + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -561,9 +552,9 @@ public class CustomNamedCurves { byte[] S = null; ECCurve curve = configureCurve(new SecT409K1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + X9ECPoint G = configureBasepoint(curve, "04" + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746" - + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B")); + + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -575,11 +566,11 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("4099B5A457F9D69F79213D094C4BCD4D4262210B"); + byte[] S = Hex.decodeStrict("4099B5A457F9D69F79213D094C4BCD4D4262210B"); ECCurve curve = configureCurve(new SecT409R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + X9ECPoint G = configureBasepoint(curve, "04" + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7" - + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706")); + + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -593,9 +584,9 @@ public class CustomNamedCurves { byte[] S = null; ECCurve curve = configureCurve(new SecT571K1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + X9ECPoint G = configureBasepoint(curve, "04" + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972" - + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3")); + + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -607,11 +598,11 @@ public class CustomNamedCurves { protected X9ECParameters createParameters() { - byte[] S = Hex.decode("2AA058F73A0E33AB486B0F610410C53A7F132310"); + byte[] S = Hex.decodeStrict("2AA058F73A0E33AB486B0F610410C53A7F132310"); ECCurve curve = configureCurve(new SecT571R1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" + X9ECPoint G = configureBasepoint(curve, "04" + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19" - + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B")); + + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; @@ -625,13 +616,13 @@ public class CustomNamedCurves { byte[] S = null; ECCurve curve = configureCurve(new SM2P256V1Curve()); - X9ECPoint G = new X9ECPoint(curve, Hex.decode("04" - + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" - + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0")); + X9ECPoint G = configureBasepoint(curve, + "0432C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0"); return new X9ECParameters(curve, G, curve.getOrder(), curve.getCofactor(), S); } }; + static final Hashtable nameToCurve = new Hashtable(); static final Hashtable nameToOID = new Hashtable(); static final Hashtable oidToCurve = new Hashtable(); @@ -670,7 +661,7 @@ public class CustomNamedCurves static { - defineCurve("curve25519", curve25519); + defineCurveWithOID("curve25519", CryptlibObjectIdentifiers.curvey25519, curve25519); // defineCurveWithOID("secp112r1", SECObjectIdentifiers.secp112r1, secp112r1); // defineCurveWithOID("secp112r2", SECObjectIdentifiers.secp112r2, secp112r2); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/ECUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/ECUtil.java index 77b438f54..160c835e8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/ECUtil.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/ECUtil.java @@ -4,6 +4,7 @@ import java.math.BigInteger; import java.security.SecureRandom; import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.util.BigIntegers; class ECUtil { @@ -13,7 +14,7 @@ class ECUtil BigInteger k; do { - k = new BigInteger(nBitLength, random); + k = BigIntegers.createRandomBigInteger(nBitLength, random); } while (k.equals(ECConstants.ZERO) || (k.compareTo(n) >= 0)); return k; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/test/ECElGamalTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/test/ECElGamalTest.java new file mode 100644 index 000000000..04d7e3a7a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/test/ECElGamalTest.java @@ -0,0 +1,88 @@ +package com.fr.third.org.bouncycastle.crypto.ec.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.ec.ECDecryptor; +import com.fr.third.org.bouncycastle.crypto.ec.ECElGamalDecryptor; +import com.fr.third.org.bouncycastle.crypto.ec.ECElGamalEncryptor; +import com.fr.third.org.bouncycastle.crypto.ec.ECEncryptor; +import com.fr.third.org.bouncycastle.crypto.ec.ECPair; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ECElGamalTest + extends SimpleTest +{ + public String getName() + { + return "ECElGamal"; + } + + public void performTest() + throws Exception + { + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ParametersWithRandom pRandom = new ParametersWithRandom(pubKey, new SecureRandom()); + + doTest(priKey, pRandom, BigInteger.valueOf(20)); + + BigInteger rand = new BigInteger(pubKey.getParameters().getN().bitLength() - 1, new SecureRandom()); + + doTest(priKey, pRandom, rand); + } + + private void doTest(ECPrivateKeyParameters priKey, ParametersWithRandom pRandom, BigInteger value) + { + ECPoint data = priKey.getParameters().getG().multiply(value); + + ECEncryptor encryptor = new ECElGamalEncryptor(); + + encryptor.init(pRandom); + + ECPair pair = encryptor.encrypt(data); + + ECDecryptor decryptor = new ECElGamalDecryptor(); + + decryptor.init(priKey); + + ECPoint result = decryptor.decrypt(pair); + + if (!data.equals(result)) + { + fail("point pair failed to decrypt back to original"); + } + } + + public static void main(String[] args) + { + runTest(new ECElGamalTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/test/ECTransformationTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/test/ECTransformationTest.java new file mode 100644 index 000000000..41d5ca573 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/ec/test/ECTransformationTest.java @@ -0,0 +1,149 @@ +package com.fr.third.org.bouncycastle.crypto.ec.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.ec.ECDecryptor; +import com.fr.third.org.bouncycastle.crypto.ec.ECElGamalDecryptor; +import com.fr.third.org.bouncycastle.crypto.ec.ECElGamalEncryptor; +import com.fr.third.org.bouncycastle.crypto.ec.ECEncryptor; +import com.fr.third.org.bouncycastle.crypto.ec.ECNewPublicKeyTransform; +import com.fr.third.org.bouncycastle.crypto.ec.ECNewRandomnessTransform; +import com.fr.third.org.bouncycastle.crypto.ec.ECPair; +import com.fr.third.org.bouncycastle.crypto.ec.ECPairTransform; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ECTransformationTest + extends SimpleTest +{ + public String getName() + { + return "ECTransformationTest"; + } + + public void performTest() + throws Exception + { + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + + ParametersWithRandom pRandom = new ParametersWithRandom(pubKey, new SecureRandom()); + + doTest(priKey, pRandom, BigInteger.valueOf(20)); + + BigInteger rand = new BigInteger(pubKey.getParameters().getN().bitLength() - 1, new SecureRandom()); + + doTest(priKey, pRandom, rand); + doSameKeyTest(priKey, pRandom, rand); + } + + private void doTest(ECPrivateKeyParameters priKey, ParametersWithRandom pRandom, BigInteger value) + { + ECPoint data = priKey.getParameters().getG().multiply(value); + + ECEncryptor encryptor = new ECElGamalEncryptor(); + + encryptor.init(pRandom); + + ECPair pair = encryptor.encrypt(data); + + ECKeyPairGenerator ecGen = new ECKeyPairGenerator(); + + ecGen.init(new ECKeyGenerationParameters(priKey.getParameters(), new SecureRandom())); + + AsymmetricCipherKeyPair reEncKP = ecGen.generateKeyPair(); + + ECPairTransform ecr = new ECNewPublicKeyTransform(); + + ecr.init(reEncKP.getPublic()); + + ECPair srcPair = pair; + + // re-encrypt the message portion + pair = ecr.transform(srcPair); + + ECDecryptor decryptor = new ECElGamalDecryptor(); + + decryptor.init(priKey); + + // decrypt out the original private key + ECPoint p = decryptor.decrypt(new ECPair(srcPair.getX(), pair.getY())); + + decryptor.init(reEncKP.getPrivate()); + + // decrypt the fully transformed point. + ECPoint result = decryptor.decrypt(new ECPair(pair.getX(), p)); + + if (!data.equals(result)) + { + fail("point pair failed to decrypt back to original"); + } + } + + private void doSameKeyTest(ECPrivateKeyParameters priKey, ParametersWithRandom pRandom, BigInteger value) + { + ECPoint data = priKey.getParameters().getG().multiply(value); + + ECEncryptor encryptor = new ECElGamalEncryptor(); + + encryptor.init(pRandom); + + ECPair pair = encryptor.encrypt(data); + + ECPairTransform ecr = new ECNewRandomnessTransform(); + + ecr.init(pRandom); + + ECPair srcPair = pair; + + // re-encrypt the message portion + pair = ecr.transform(srcPair); + + ECDecryptor decryptor = new ECElGamalDecryptor(); + + decryptor.init(priKey); + + // decrypt the fully transformed point. + ECPoint result = decryptor.decrypt(pair); + + if (!data.equals(result)) + { + fail("point pair failed to decrypt back to original"); + } + } + + public static void main(String[] args) + { + runTest(new ECTransformationTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/encodings/OAEPEncoding.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/encodings/OAEPEncoding.java index b4792e1e5..6f7c9ddef 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/encodings/OAEPEncoding.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/encodings/OAEPEncoding.java @@ -221,10 +221,17 @@ public class OAEPEncoding // on encryption, we need to make sure our decrypted block comes back // the same size. // + boolean wrongData = (block.length < (2 * defHash.length) + 1); - System.arraycopy(data, 0, block, block.length - data.length, data.length); - - boolean shortData = (block.length < (2 * defHash.length) + 1); + if (data.length <= block.length) + { + System.arraycopy(data, 0, block, block.length - data.length, data.length); + } + else + { + System.arraycopy(data, 0, block, 0, block.length); + wrongData = true; + } // // unmask the seed. @@ -278,7 +285,7 @@ public class OAEPEncoding start++; - if (defHashWrong | shortData | dataStartWrong) + if (defHashWrong | wrongData | dataStartWrong) { Arrays.fill(block, (byte)0); throw new InvalidCipherTextException("data wrong"); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ARIAEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ARIAEngine.java index 304183696..aee415f7c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ARIAEngine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ARIAEngine.java @@ -15,8 +15,8 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class ARIAEngine implements BlockCipher { - private static final byte[][] C = { Hex.decode("517cc1b727220a94fe13abe8fa9a6ee0"), - Hex.decode("6db14acc9e21c820ff28b1d5ef5de2b0"), Hex.decode("db92371d2126e9700324977504e8c90e") }; + private static final byte[][] C = { Hex.decodeStrict("517cc1b727220a94fe13abe8fa9a6ee0"), + Hex.decodeStrict("6db14acc9e21c820ff28b1d5ef5de2b0"), Hex.decodeStrict("db92371d2126e9700324977504e8c90e") }; private static final byte[] SB1_sbox = { (byte)0x63, (byte)0x7c, (byte)0x77, (byte)0x7b, (byte)0xf2, (byte)0x6b, (byte)0x6f, (byte)0xc5, (byte)0x30, (byte)0x01, (byte)0x67, (byte)0x2b, (byte)0xfe, (byte)0xd7, (byte)0xab, diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/CAST5Engine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/CAST5Engine.java index 3b2ba32f5..fcf215851 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/CAST5Engine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/CAST5Engine.java @@ -20,9 +20,7 @@ import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; public class CAST5Engine implements BlockCipher { - protected final static int M32 = 0xffffffff; - - protected final static int[] + private final static int[] S1 = { 0x30fb40d4, 0x9fa0ff0b, 0x6beccd2f, 0x3f258c7a, 0x1e213f2f, 0x9c004dd3, 0x6003e540, 0xcf9fc949, 0xbfd4af27, 0x88bbbdb5, 0xe2034090, 0x98d09675, 0x6e63a0e0, 0x15c361d2, 0xc2e7661d, 0x22d4ff8e, diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ChaCha7539Engine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ChaCha7539Engine.java index 502f154c1..24a146289 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ChaCha7539Engine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ChaCha7539Engine.java @@ -17,7 +17,7 @@ public class ChaCha7539Engine extends Salsa20Engine public String getAlgorithmName() { - return "ChaCha7539-" + rounds; + return "ChaCha7539"; } protected int getNonceSize() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/CramerShoupCoreEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/CramerShoupCoreEngine.java index 5dc51ae16..fdc819e07 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/CramerShoupCoreEngine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/CramerShoupCoreEngine.java @@ -12,6 +12,7 @@ import com.fr.third.org.bouncycastle.crypto.params.CramerShoupPrivateKeyParamete import com.fr.third.org.bouncycastle.crypto.params.CramerShoupPublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Strings; /** * Essentially the Cramer-Shoup encryption / decryption algorithms according to @@ -19,13 +20,12 @@ import com.fr.third.org.bouncycastle.util.BigIntegers; */ public class CramerShoupCoreEngine { - private static final BigInteger ONE = BigInteger.valueOf(1); private CramerShoupKeyParameters key; private SecureRandom random; private boolean forEncryption; - private String label = null; + private byte[] label = null; /** * initialise the CramerShoup engine. @@ -38,7 +38,7 @@ public class CramerShoupCoreEngine { init(forEncryption, param); - this.label = label; + this.label = Strings.toUTF8ByteArray(label); } /** @@ -217,7 +217,7 @@ public class CramerShoupCoreEngine digest.update(eBytes, 0, eBytes.length); if (this.label != null) { - byte[] lBytes = this.label.getBytes(); + byte[] lBytes = this.label; digest.update(lBytes, 0, lBytes.length); } byte[] out = new byte[digest.getDigestSize()]; @@ -252,7 +252,7 @@ public class CramerShoupCoreEngine digest.update(eBytes, 0, eBytes.length); if (this.label != null) { - byte[] lBytes = this.label.getBytes(); + byte[] lBytes = this.label; digest.update(lBytes, 0, lBytes.length); } byte[] out = new byte[digest.getDigestSize()]; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ElGamalEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ElGamalEngine.java index 60e99f04b..54f7393b2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ElGamalEngine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/ElGamalEngine.java @@ -179,11 +179,11 @@ public class ElGamalEngine ElGamalPublicKeyParameters pub = (ElGamalPublicKeyParameters)key; int pBitLength = p.bitLength(); - BigInteger k = new BigInteger(pBitLength, random); + BigInteger k = BigIntegers.createRandomBigInteger(pBitLength, random); while (k.equals(ZERO) || (k.compareTo(p.subtract(TWO)) > 0)) { - k = new BigInteger(pBitLength, random); + k = BigIntegers.createRandomBigInteger(pBitLength, random); } BigInteger g = key.getParameters().getG(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/EthereumIESEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/EthereumIESEngine.java new file mode 100644 index 000000000..aa3f19b46 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/EthereumIESEngine.java @@ -0,0 +1,619 @@ +package com.fr.third.org.bouncycastle.crypto.engines; + + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.crypto.BasicAgreement; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.DerivationFunction; +import com.fr.third.org.bouncycastle.crypto.DerivationParameters; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.DigestDerivationFunction; +import com.fr.third.org.bouncycastle.crypto.EphemeralKeyPair; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.KeyParser; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.OutputLengthException; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.IESParameters; +import com.fr.third.org.bouncycastle.crypto.params.IESWithCipherParameters; +import com.fr.third.org.bouncycastle.crypto.params.ISO18033KDFParameters; +import com.fr.third.org.bouncycastle.crypto.params.KDFParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Pack; + +/** + * Support class for constructing integrated encryption ciphers for doing basic message exchanges on top of key + * agreement ciphers. Follows the description given in IEEE Std 1363a. + *

+ * Some tweaks added to IESEngine to conform to the Ethereum encryption approach. + */ +public class EthereumIESEngine +{ + BasicAgreement agree; + DerivationFunction kdf; + Mac mac; + BufferedBlockCipher cipher; + byte[] macBuf; + // Ethereum addition: commonMac added when performing the MAC encryption. + byte[] commonMac; + + boolean forEncryption; + CipherParameters privParam, pubParam; + IESParameters param; + + byte[] V; + private EphemeralKeyPairGenerator keyPairGenerator; + private KeyParser keyParser; + private byte[] IV; + + /** + * Set up for use with stream mode, where the key derivation function is used to provide a stream of bytes to xor with + * the message. + * + * @param agree the key agreement used as the basis for the encryption + * @param kdf the key derivation function used for byte generation + * @param mac the message authentication code generator for the message + * @param commonMac the common MAC bytes to append to the mac + */ + public EthereumIESEngine(BasicAgreement agree, DerivationFunction kdf, Mac mac, byte[] commonMac) + { + this.agree = agree; + this.kdf = kdf; + this.mac = mac; + this.macBuf = new byte[mac.getMacSize()]; + this.commonMac = commonMac; + this.cipher = null; + } + + /** + * Set up for use in conjunction with a block cipher to handle the message. It is strongly recommended that the + * cipher is not in ECB mode. + * + * @param agree the key agreement used as the basis for the encryption + * @param kdf the key derivation function used for byte generation + * @param mac the message authentication code generator for the message + * @param commonMac the common MAC bytes to append to the mac + * @param cipher the cipher to used for encrypting the message + */ + public EthereumIESEngine(BasicAgreement agree, DerivationFunction kdf, Mac mac, byte[] commonMac, BufferedBlockCipher cipher) + { + this.agree = agree; + this.kdf = kdf; + this.mac = mac; + this.macBuf = new byte[mac.getMacSize()]; + this.commonMac = commonMac; + this.cipher = cipher; + } + + /** + * Initialise the encryptor. + * + * @param forEncryption whether or not this is encryption/decryption. + * @param privParam our private key parameters + * @param pubParam the recipient's/sender's public key parameters + * @param params encoding and derivation parameters, may be wrapped to include an IV for an underlying block cipher. + */ + public void init( + boolean forEncryption, + CipherParameters privParam, + CipherParameters pubParam, + CipherParameters params) + { + this.forEncryption = forEncryption; + this.privParam = privParam; + this.pubParam = pubParam; + this.V = new byte[0]; + + extractParams(params); + } + + /** + * Initialise the decryptor. + * + * @param publicKey the recipient's/sender's public key parameters + * @param params encoding and derivation parameters, may be wrapped to include an IV for an underlying block cipher. + * @param ephemeralKeyPairGenerator the ephemeral key pair generator to use. + */ + public void init( + AsymmetricKeyParameter publicKey, + CipherParameters params, + EphemeralKeyPairGenerator ephemeralKeyPairGenerator) + { + this.forEncryption = true; + this.pubParam = publicKey; + this.keyPairGenerator = ephemeralKeyPairGenerator; + + extractParams(params); + } + + /** + * Initialise the encryptor. + * + * @param privateKey the recipient's private key. + * @param params encoding and derivation parameters, may be wrapped to include an IV for an underlying block cipher. + * @param publicKeyParser the parser for reading the ephemeral public key. + */ + public void init(AsymmetricKeyParameter privateKey, CipherParameters params, KeyParser publicKeyParser) + { + this.forEncryption = false; + this.privParam = privateKey; + this.keyParser = publicKeyParser; + + extractParams(params); + } + + private void extractParams(CipherParameters params) + { + if (params instanceof ParametersWithIV) + { + this.IV = ((ParametersWithIV)params).getIV(); + this.param = (IESParameters)((ParametersWithIV)params).getParameters(); + } + else + { + this.IV = null; + this.param = (IESParameters)params; + } + } + + public BufferedBlockCipher getCipher() + { + return cipher; + } + + public Mac getMac() + { + return mac; + } + + private byte[] encryptBlock(byte[] in, int inOff, int inLen) + throws InvalidCipherTextException + { + byte[] C = null, K = null, K1 = null, K2 = null; + int len; + + if (cipher == null) + { + // Streaming mode. + K1 = new byte[inLen]; + K2 = new byte[param.getMacKeySize() / 8]; + K = new byte[K1.length + K2.length]; + + kdf.generateBytes(K, 0, K.length); + + if (V.length != 0) + { + System.arraycopy(K, 0, K2, 0, K2.length); + System.arraycopy(K, K2.length, K1, 0, K1.length); + } + else + { + System.arraycopy(K, 0, K1, 0, K1.length); + System.arraycopy(K, inLen, K2, 0, K2.length); + } + + C = new byte[inLen]; + + for (int i = 0; i != inLen; i++) + { + C[i] = (byte)(in[inOff + i] ^ K1[i]); + } + len = inLen; + } + else + { + // Block cipher mode. + K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8]; + K2 = new byte[param.getMacKeySize() / 8]; + K = new byte[K1.length + K2.length]; + + kdf.generateBytes(K, 0, K.length); + System.arraycopy(K, 0, K1, 0, K1.length); + System.arraycopy(K, K1.length, K2, 0, K2.length); + + // If iv provided use it to initialise the cipher + if (IV != null) + { + cipher.init(true, new ParametersWithIV(new KeyParameter(K1), IV)); + } + else + { + cipher.init(true, new KeyParameter(K1)); + } + + C = new byte[cipher.getOutputSize(inLen)]; + len = cipher.processBytes(in, inOff, inLen, C, 0); + len += cipher.doFinal(C, len); + } + + + // Convert the length of the encoding vector into a byte array. + byte[] P2 = param.getEncodingV(); + byte[] L2 = null; + if (V.length != 0) + { + L2 = getLengthTag(P2); + } + + + // Apply the MAC. + byte[] T = new byte[mac.getMacSize()]; + // Ethereum change: + // Instead of initializing the mac with the bytes, we initialize with the hash of the bytes. + // Old code: mac.init(new KeyParameter(K2)); + Digest hash = new SHA256Digest(); + byte[] K2hash = new byte[hash.getDigestSize()]; + hash.reset(); + hash.update(K2, 0, K2.length); + hash.doFinal(K2hash, 0); + + mac.init(new KeyParameter(K2hash)); + // we also update the mac with the IV: + mac.update(IV, 0, IV.length); + // end of Ethereum change. + mac.update(C, 0, C.length); + if (P2 != null) + { + mac.update(P2, 0, P2.length); + } + if (V.length != 0) + { + mac.update(L2, 0, L2.length); + } + // Ethereum change + mac.update(commonMac, 0, commonMac.length); + mac.doFinal(T, 0); + + + // Output the triple (V,C,T). + byte[] Output = new byte[V.length + len + T.length]; + System.arraycopy(V, 0, Output, 0, V.length); + System.arraycopy(C, 0, Output, V.length, len); + System.arraycopy(T, 0, Output, V.length + len, T.length); + return Output; + } + + private byte[] decryptBlock(byte[] in_enc, int inOff, int inLen) + throws InvalidCipherTextException + { + byte[] M, K, K1, K2; + int len = 0; + + // Ensure that the length of the input is greater than the MAC in bytes + if (inLen < V.length + mac.getMacSize()) + { + throw new InvalidCipherTextException("length of input must be greater than the MAC and V combined"); + } + + // note order is important: set up keys, do simple encryptions, check mac, do final encryption. + if (cipher == null) + { + // Streaming mode. + K1 = new byte[inLen - V.length - mac.getMacSize()]; + K2 = new byte[param.getMacKeySize() / 8]; + K = new byte[K1.length + K2.length]; + + kdf.generateBytes(K, 0, K.length); + + if (V.length != 0) + { + System.arraycopy(K, 0, K2, 0, K2.length); + System.arraycopy(K, K2.length, K1, 0, K1.length); + } + else + { + System.arraycopy(K, 0, K1, 0, K1.length); + System.arraycopy(K, K1.length, K2, 0, K2.length); + } + + // process the message + M = new byte[K1.length]; + + for (int i = 0; i != K1.length; i++) + { + M[i] = (byte)(in_enc[inOff + V.length + i] ^ K1[i]); + } + } + else + { + // Block cipher mode. + K1 = new byte[((IESWithCipherParameters)param).getCipherKeySize() / 8]; + K2 = new byte[param.getMacKeySize() / 8]; + K = new byte[K1.length + K2.length]; + + kdf.generateBytes(K, 0, K.length); + System.arraycopy(K, 0, K1, 0, K1.length); + System.arraycopy(K, K1.length, K2, 0, K2.length); + + CipherParameters cp = new KeyParameter(K1); + + // If IV provide use it to initialize the cipher + if (IV != null) + { + cp = new ParametersWithIV(cp, IV); + } + + cipher.init(false, cp); + + M = new byte[cipher.getOutputSize(inLen - V.length - mac.getMacSize())]; + + // do initial processing + len = cipher.processBytes(in_enc, inOff + V.length, inLen - V.length - mac.getMacSize(), M, 0); + } + + // Convert the length of the encoding vector into a byte array. + byte[] P2 = param.getEncodingV(); + byte[] L2 = null; + if (V.length != 0) + { + L2 = getLengthTag(P2); + } + + // Verify the MAC. + int end = inOff + inLen; + byte[] T1 = Arrays.copyOfRange(in_enc, end - mac.getMacSize(), end); + + byte[] T2 = new byte[T1.length]; + // Ethereum change: + // Instead of initializing the mac with the bytes, we initialize with the hash of the bytes. + // Old code: mac.init(new KeyParameter(K2)); + Digest hash = new SHA256Digest(); + byte[] K2hash = new byte[hash.getDigestSize()]; + hash.reset(); + hash.update(K2, 0, K2.length); + hash.doFinal(K2hash, 0); + mac.init(new KeyParameter(K2hash)); + // we also update the mac with the IV: + mac.update(IV, 0, IV.length); + // end of Ethereum change. + + mac.update(in_enc, inOff + V.length, inLen - V.length - T2.length); + + if (P2 != null) + { + mac.update(P2, 0, P2.length); + } + if (V.length != 0) + { + mac.update(L2, 0, L2.length); + } + // Ethereum change + mac.update(commonMac, 0, commonMac.length); + mac.doFinal(T2, 0); + + if (!Arrays.constantTimeAreEqual(T1, T2)) + { + throw new InvalidCipherTextException("invalid MAC"); + } + + if (cipher == null) + { + return M; + } + else + { + len += cipher.doFinal(M, len); + + return Arrays.copyOfRange(M, 0, len); + } + } + + + public byte[] processBlock(byte[] in, int inOff, int inLen) + throws InvalidCipherTextException + { + if (forEncryption) + { + if (keyPairGenerator != null) + { + EphemeralKeyPair ephKeyPair = keyPairGenerator.generate(); + + this.privParam = ephKeyPair.getKeyPair().getPrivate(); + this.V = ephKeyPair.getEncodedPublicKey(); + } + } + else + { + if (keyParser != null) + { + ByteArrayInputStream bIn = new ByteArrayInputStream(in, inOff, inLen); + + try + { + this.pubParam = keyParser.readKey(bIn); + } + catch (IOException e) + { + throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e); + } + catch (IllegalArgumentException e) + { + throw new InvalidCipherTextException("unable to recover ephemeral public key: " + e.getMessage(), e); + } + + int encLength = (inLen - bIn.available()); + this.V = Arrays.copyOfRange(in, inOff, inOff + encLength); + } + } + + // Compute the common value and convert to byte array. + agree.init(privParam); + BigInteger z = agree.calculateAgreement(pubParam); + byte[] Z = BigIntegers.asUnsignedByteArray(agree.getFieldSize(), z); + + // Create input to KDF. + if (V.length != 0) + { + byte[] VZ = Arrays.concatenate(V, Z); + Arrays.fill(Z, (byte)0); + Z = VZ; + } + + try + { + // Initialise the KDF. + KDFParameters kdfParam = new KDFParameters(Z, param.getDerivationV()); + kdf.init(kdfParam); + + return forEncryption ? encryptBlock(in, inOff, inLen) : decryptBlock(in, inOff, inLen); + } + finally + { + Arrays.fill(Z, (byte)0); + } + } + + // as described in Shroup's paper and P1363a + protected byte[] getLengthTag(byte[] p2) + { + byte[] L2 = new byte[8]; + if (p2 != null) + { + Pack.longToBigEndian(p2.length * 8L, L2, 0); + } + return L2; + } + + /** + * Basic KDF generator for derived keys and ivs as defined by IEEE P1363a/ISO 18033
+ * This implementation is based on ISO 18033/P1363a. + *

+ * This class has been adapted from the BaseKDFBytesGenerator implementation of Bouncy Castle. Only one + * change is present specifically for Ethereum. + */ + public static class HandshakeKDFFunction + implements DigestDerivationFunction + { + private int counterStart; + private Digest digest; + private byte[] shared; + private byte[] iv; + + /** + * Construct a KDF Parameters generator. + *

+ * + * @param counterStart value of counter. + * @param digest the digest to be used as the source of derived keys. + */ + public HandshakeKDFFunction(int counterStart, Digest digest) + { + this.counterStart = counterStart; + this.digest = digest; + } + + public void init(DerivationParameters param) + { + if (param instanceof KDFParameters) + { + KDFParameters p = (KDFParameters)param; + + shared = p.getSharedSecret(); + iv = p.getIV(); + } + else if (param instanceof ISO18033KDFParameters) + { + ISO18033KDFParameters p = (ISO18033KDFParameters)param; + + shared = p.getSeed(); + iv = null; + } + else + { + throw new IllegalArgumentException("KDF parameters required for generator"); + } + } + + /** + * return the underlying digest. + */ + public Digest getDigest() + { + return digest; + } + + /** + * fill len bytes of the output buffer with bytes generated from the derivation function. + * + * @throws IllegalArgumentException if the size of the request will cause an overflow. + * @throws DataLengthException if the out buffer is too small. + */ + public int generateBytes(byte[] out, int outOff, int len) + throws DataLengthException, IllegalArgumentException + { + if ((out.length - len) < outOff) + { + throw new OutputLengthException("output buffer too small"); + } + + long oBytes = len; + int outLen = digest.getDigestSize(); + + // + // this is at odds with the standard implementation, the + // maximum value should be hBits * (2^32 - 1) where hBits + // is the digest output size in bits. We can't have an + // array with a long index at the moment... + // + if (oBytes > ((2L << 32) - 1)) + { + throw new IllegalArgumentException("output length too large"); + } + + int cThreshold = (int)((oBytes + outLen - 1) / outLen); + + byte[] dig = new byte[digest.getDigestSize()]; + + byte[] C = new byte[4]; + Pack.intToBigEndian(counterStart, C, 0); + + int counterBase = counterStart & ~0xFF; + + for (int i = 0; i < cThreshold; i++) + { + // only change for Ethereum: invert those 2 lines. + digest.update(C, 0, C.length); + digest.update(shared, 0, shared.length); + // End of change for Ethereum. + + if (iv != null) + { + digest.update(iv, 0, iv.length); + } + + digest.doFinal(dig, 0); + + if (len > outLen) + { + System.arraycopy(dig, 0, out, outOff, outLen); + outOff += outLen; + len -= outLen; + } + else + { + System.arraycopy(dig, 0, out, outOff, len); + } + + if (++C[3] == 0) + { + counterBase += 0x100; + Pack.intToBigEndian(counterBase, C, 0); + } + } + + digest.reset(); + + return (int)oBytes; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/GOST28147WrapEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/GOST28147WrapEngine.java index c9d826b97..61e77267b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/GOST28147WrapEngine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/GOST28147WrapEngine.java @@ -4,10 +4,8 @@ import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; import com.fr.third.org.bouncycastle.crypto.Wrapper; import com.fr.third.org.bouncycastle.crypto.macs.GOST28147Mac; -import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; -import com.fr.third.org.bouncycastle.crypto.params.ParametersWithSBox; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithUKM; import com.fr.third.org.bouncycastle.util.Arrays; @@ -29,19 +27,7 @@ public class GOST28147WrapEngine cipher.init(forWrapping, pU.getParameters()); - KeyParameter kParam; - - if (pU.getParameters() instanceof ParametersWithSBox) - { - kParam = (KeyParameter)((ParametersWithSBox)pU.getParameters()).getParameters(); - } - else - { - kParam = (KeyParameter)pU.getParameters(); - } - - - mac.init(new ParametersWithIV(kParam, pU.getUKM())); + mac.init(new ParametersWithIV(pU.getParameters(), pU.getUKM())); } public String getAlgorithmName() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RFC3211WrapEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RFC3211WrapEngine.java index 9ec0de6ce..e9e4c139d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RFC3211WrapEngine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RFC3211WrapEngine.java @@ -10,6 +10,7 @@ import com.fr.third.org.bouncycastle.crypto.Wrapper; import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.util.Arrays; /** * an implementation of the RFC 3211 Key Wrap @@ -39,6 +40,12 @@ public class RFC3211WrapEngine ParametersWithRandom p = (ParametersWithRandom)param; rand = p.getRandom(); + + if (!(p.getParameters() instanceof ParametersWithIV)) + { + throw new IllegalArgumentException("RFC3211Wrap requires an IV"); + } + this.param = (ParametersWithIV)p.getParameters(); } else @@ -48,6 +55,11 @@ public class RFC3211WrapEngine rand = CryptoServicesRegistrar.getSecureRandom(); } + if (!(param instanceof ParametersWithIV)) + { + throw new IllegalArgumentException("RFC3211Wrap requires an IV"); + } + this.param = (ParametersWithIV)param; } } @@ -67,6 +79,11 @@ public class RFC3211WrapEngine throw new IllegalStateException("not set for wrapping"); } + if (inLen > 255 || inLen < 0) + { + throw new IllegalArgumentException("input must be from 0 to 255 bytes"); + } + engine.init(true, param); int blockSize = engine.getBlockSize(); @@ -82,9 +99,6 @@ public class RFC3211WrapEngine } cekBlock[0] = (byte)inLen; - cekBlock[1] = (byte)~in[inOff]; - cekBlock[2] = (byte)~in[inOff + 1]; - cekBlock[3] = (byte)~in[inOff + 2]; System.arraycopy(in, inOff, cekBlock, 4, inLen); @@ -93,6 +107,10 @@ public class RFC3211WrapEngine rand.nextBytes(pad); System.arraycopy(pad, 0, cekBlock, inLen + 4, pad.length); + cekBlock[1] = (byte)~cekBlock[4]; + cekBlock[2] = (byte)~cekBlock[4 + 1]; + cekBlock[3] = (byte)~cekBlock[4 + 2]; + for (int i = 0; i < cekBlock.length; i += blockSize) { engine.processBlock(cekBlock, i, cekBlock, i); @@ -150,25 +168,33 @@ public class RFC3211WrapEngine engine.processBlock(cekBlock, i, cekBlock, i); } - if ((cekBlock[0] & 0xff) > cekBlock.length - 4) + boolean invalidLength = ((cekBlock[0] & 0xff) > cekBlock.length - 4); + + byte[] key; + if (invalidLength) { - throw new InvalidCipherTextException("wrapped key corrupted"); + key = new byte[cekBlock.length - 4]; + } + else + { + key = new byte[cekBlock[0] & 0xff]; } - byte[] key = new byte[cekBlock[0] & 0xff]; - - System.arraycopy(cekBlock, 4, key, 0, cekBlock[0]); - + System.arraycopy(cekBlock, 4, key, 0, key.length); + // Note: Using constant time comparison int nonEqual = 0; for (int i = 0; i != 3; i++) { byte check = (byte)~cekBlock[1 + i]; - nonEqual |= (check ^ key[i]); + nonEqual |= (check ^ cekBlock[4 + i]); } - if (nonEqual != 0) + + Arrays.clear(cekBlock); + + if (nonEqual != 0 | invalidLength) { - throw new InvalidCipherTextException("wrapped key fails checksum"); + throw new InvalidCipherTextException("wrapped key corrupted"); } return key; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RSABlindedEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RSABlindedEngine.java index 8cc39bcb7..380c3e7a2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RSABlindedEngine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RSABlindedEngine.java @@ -38,15 +38,31 @@ public class RSABlindedEngine if (param instanceof ParametersWithRandom) { - ParametersWithRandom rParam = (ParametersWithRandom)param; + ParametersWithRandom rParam = (ParametersWithRandom)param; - key = (RSAKeyParameters)rParam.getParameters(); - random = rParam.getRandom(); + this.key = (RSAKeyParameters)rParam.getParameters(); + + if (key instanceof RSAPrivateCrtKeyParameters) + { + this.random = rParam.getRandom(); + } + else + { + this.random = null; + } } else { - key = (RSAKeyParameters)param; - random = CryptoServicesRegistrar.getSecureRandom(); + this.key = (RSAKeyParameters)param; + + if (key instanceof RSAPrivateCrtKeyParameters) + { + this.random = CryptoServicesRegistrar.getSecureRandom(); + } + else + { + this.random = null; + } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RSACoreEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RSACoreEngine.java index ccb299891..dc9576965 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RSACoreEngine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/RSACoreEngine.java @@ -1,12 +1,13 @@ package com.fr.third.org.bouncycastle.crypto.engines; +import java.math.BigInteger; + import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.DataLengthException; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; - -import java.math.BigInteger; +import com.fr.third.org.bouncycastle.util.Arrays; /** * this does your basic RSA algorithm. @@ -142,20 +143,29 @@ class RSACoreEngine return tmp; } + + return output; } else { + byte[] rv; if (output[0] == 0) // have ended up with an extra zero byte, copy down. { - byte[] tmp = new byte[output.length - 1]; + rv = new byte[output.length - 1]; - System.arraycopy(output, 1, tmp, 0, tmp.length); + System.arraycopy(output, 1, rv, 0, rv.length); + } + else // maintain decryption time + { + rv = new byte[output.length]; - return tmp; + System.arraycopy(output, 0, rv, 0, rv.length); } - } - return output; + Arrays.fill(output, (byte)0); + + return rv; + } } public BigInteger processBlock(BigInteger input) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/SM2Engine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/SM2Engine.java index d81efcd04..69867657a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/SM2Engine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/SM2Engine.java @@ -12,7 +12,6 @@ import com.fr.third.org.bouncycastle.crypto.params.ECKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; -import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECMultiplier; import com.fr.third.org.bouncycastle.math.ec.ECPoint; @@ -27,7 +26,13 @@ import com.fr.third.org.bouncycastle.util.Pack; */ public class SM2Engine { + public enum Mode + { + C1C2C3, C1C3C2; + } + private final Digest digest; + private final Mode mode; private boolean forEncryption; private ECKeyParameters ecKey; @@ -40,9 +45,24 @@ public class SM2Engine this(new SM3Digest()); } + public SM2Engine(Mode mode) + { + this(new SM3Digest(), mode); + } + public SM2Engine(Digest digest) { + this(digest, Mode.C1C2C3); + } + + public SM2Engine(Digest digest, Mode mode) + { + if (mode == null) + { + throw new IllegalArgumentException("mode cannot be NULL"); + } this.digest = digest; + this.mode = mode; } public void init(boolean forEncryption, CipherParameters param) @@ -89,6 +109,11 @@ public class SM2Engine } } + public int getOutputSize(int inputLen) + { + return (1 + 2 * curveLength) + inputLen + digest.getDigestSize(); + } + protected ECMultiplier createBasePointMultiplier() { return new FixedPointCombMultiplier(); @@ -126,8 +151,14 @@ public class SM2Engine addFieldElement(digest, kPB.getAffineYCoord()); digest.doFinal(c3, 0); - - return Arrays.concatenate(c1, c2, c3); + + switch (mode) + { + case C1C3C2: + return Arrays.concatenate(c1, c3, c2); + default: + return Arrays.concatenate(c1, c2, c3); + } } private byte[] decrypt(byte[] in, int inOff, int inLen) @@ -147,9 +178,17 @@ public class SM2Engine c1P = c1P.multiply(((ECPrivateKeyParameters)ecKey).getD()).normalize(); - byte[] c2 = new byte[inLen - c1.length - digest.getDigestSize()]; + int digestSize = this.digest.getDigestSize(); + byte[] c2 = new byte[inLen - c1.length - digestSize]; - System.arraycopy(in, inOff + c1.length, c2, 0, c2.length); + if (mode == Mode.C1C3C2) + { + System.arraycopy(in, inOff + c1.length + digestSize, c2, 0, c2.length); + } + else + { + System.arraycopy(in, inOff + c1.length, c2, 0, c2.length); + } kdf(digest, c1P, c2); @@ -162,9 +201,19 @@ public class SM2Engine digest.doFinal(c3, 0); int check = 0; - for (int i = 0; i != c3.length; i++) + if (mode == Mode.C1C3C2) { - check |= c3[i] ^ in[inOff + c1.length + c2.length + i]; + for (int i = 0; i != c3.length; i++) + { + check |= c3[i] ^ in[inOff + c1.length + i]; + } + } + else + { + for (int i = 0; i != c3.length; i++) + { + check |= c3[i] ^ in[inOff + c1.length + c2.length + i]; + } } Arrays.fill(c1, (byte)0); @@ -183,7 +232,7 @@ public class SM2Engine { for (int i = 0; i != encData.length; i++) { - if (encData[i] != in[inOff]) + if (encData[i] != in[inOff + i]) { return false; } @@ -248,9 +297,9 @@ public class SM2Engine BigInteger k; do { - k = new BigInteger(qBitLength, random); + k = BigIntegers.createRandomBigInteger(qBitLength, random); } - while (k.equals(ECConstants.ZERO) || k.compareTo(ecParams.getN()) >= 0); + while (k.equals(BigIntegers.ZERO) || k.compareTo(ecParams.getN()) >= 0); return k; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/SM4Engine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/SM4Engine.java index 85094eb44..382ba209c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/SM4Engine.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/SM4Engine.java @@ -20,41 +20,41 @@ public class SM4Engine private static final int BLOCK_SIZE = 16; private final static byte[] Sbox = - { - (byte)0xd6, (byte)0x90, (byte)0xe9, (byte)0xfe, (byte)0xcc, (byte)0xe1, (byte)0x3d, (byte)0xb7, (byte)0x16, (byte)0xb6, (byte)0x14, (byte)0xc2, (byte)0x28, (byte)0xfb, (byte)0x2c, (byte)0x05, - (byte)0x2b, (byte)0x67, (byte)0x9a, (byte)0x76, (byte)0x2a, (byte)0xbe, (byte)0x04, (byte)0xc3, (byte)0xaa, (byte)0x44, (byte)0x13, (byte)0x26, (byte)0x49, (byte)0x86, (byte)0x06, (byte)0x99, - (byte)0x9c, (byte)0x42, (byte)0x50, (byte)0xf4, (byte)0x91, (byte)0xef, (byte)0x98, (byte)0x7a, (byte)0x33, (byte)0x54, (byte)0x0b, (byte)0x43, (byte)0xed, (byte)0xcf, (byte)0xac, (byte)0x62, - (byte)0xe4, (byte)0xb3, (byte)0x1c, (byte)0xa9, (byte)0xc9, (byte)0x08, (byte)0xe8, (byte)0x95, (byte)0x80, (byte)0xdf, (byte)0x94, (byte)0xfa, (byte)0x75, (byte)0x8f, (byte)0x3f, (byte)0xa6, - (byte)0x47, (byte)0x07, (byte)0xa7, (byte)0xfc, (byte)0xf3, (byte)0x73, (byte)0x17, (byte)0xba, (byte)0x83, (byte)0x59, (byte)0x3c, (byte)0x19, (byte)0xe6, (byte)0x85, (byte)0x4f, (byte)0xa8, - (byte)0x68, (byte)0x6b, (byte)0x81, (byte)0xb2, (byte)0x71, (byte)0x64, (byte)0xda, (byte)0x8b, (byte)0xf8, (byte)0xeb, (byte)0x0f, (byte)0x4b, (byte)0x70, (byte)0x56, (byte)0x9d, (byte)0x35, - (byte)0x1e, (byte)0x24, (byte)0x0e, (byte)0x5e, (byte)0x63, (byte)0x58, (byte)0xd1, (byte)0xa2, (byte)0x25, (byte)0x22, (byte)0x7c, (byte)0x3b, (byte)0x01, (byte)0x21, (byte)0x78, (byte)0x87, - (byte)0xd4, (byte)0x00, (byte)0x46, (byte)0x57, (byte)0x9f, (byte)0xd3, (byte)0x27, (byte)0x52, (byte)0x4c, (byte)0x36, (byte)0x02, (byte)0xe7, (byte)0xa0, (byte)0xc4, (byte)0xc8, (byte)0x9e, - (byte)0xea, (byte)0xbf, (byte)0x8a, (byte)0xd2, (byte)0x40, (byte)0xc7, (byte)0x38, (byte)0xb5, (byte)0xa3, (byte)0xf7, (byte)0xf2, (byte)0xce, (byte)0xf9, (byte)0x61, (byte)0x15, (byte)0xa1, - (byte)0xe0, (byte)0xae, (byte)0x5d, (byte)0xa4, (byte)0x9b, (byte)0x34, (byte)0x1a, (byte)0x55, (byte)0xad, (byte)0x93, (byte)0x32, (byte)0x30, (byte)0xf5, (byte)0x8c, (byte)0xb1, (byte)0xe3, - (byte)0x1d, (byte)0xf6, (byte)0xe2, (byte)0x2e, (byte)0x82, (byte)0x66, (byte)0xca, (byte)0x60, (byte)0xc0, (byte)0x29, (byte)0x23, (byte)0xab, (byte)0x0d, (byte)0x53, (byte)0x4e, (byte)0x6f, - (byte)0xd5, (byte)0xdb, (byte)0x37, (byte)0x45, (byte)0xde, (byte)0xfd, (byte)0x8e, (byte)0x2f, (byte)0x03, (byte)0xff, (byte)0x6a, (byte)0x72, (byte)0x6d, (byte)0x6c, (byte)0x5b, (byte)0x51, - (byte)0x8d, (byte)0x1b, (byte)0xaf, (byte)0x92, (byte)0xbb, (byte)0xdd, (byte)0xbc, (byte)0x7f, (byte)0x11, (byte)0xd9, (byte)0x5c, (byte)0x41, (byte)0x1f, (byte)0x10, (byte)0x5a, (byte)0xd8, - (byte)0x0a, (byte)0xc1, (byte)0x31, (byte)0x88, (byte)0xa5, (byte)0xcd, (byte)0x7b, (byte)0xbd, (byte)0x2d, (byte)0x74, (byte)0xd0, (byte)0x12, (byte)0xb8, (byte)0xe5, (byte)0xb4, (byte)0xb0, - (byte)0x89, (byte)0x69, (byte)0x97, (byte)0x4a, (byte)0x0c, (byte)0x96, (byte)0x77, (byte)0x7e, (byte)0x65, (byte)0xb9, (byte)0xf1, (byte)0x09, (byte)0xc5, (byte)0x6e, (byte)0xc6, (byte)0x84, - (byte)0x18, (byte)0xf0, (byte)0x7d, (byte)0xec, (byte)0x3a, (byte)0xdc, (byte)0x4d, (byte)0x20, (byte)0x79, (byte)0xee, (byte)0x5f, (byte)0x3e, (byte)0xd7, (byte)0xcb, (byte)0x39, (byte)0x48 - }; + { + (byte)0xd6, (byte)0x90, (byte)0xe9, (byte)0xfe, (byte)0xcc, (byte)0xe1, (byte)0x3d, (byte)0xb7, (byte)0x16, (byte)0xb6, (byte)0x14, (byte)0xc2, (byte)0x28, (byte)0xfb, (byte)0x2c, (byte)0x05, + (byte)0x2b, (byte)0x67, (byte)0x9a, (byte)0x76, (byte)0x2a, (byte)0xbe, (byte)0x04, (byte)0xc3, (byte)0xaa, (byte)0x44, (byte)0x13, (byte)0x26, (byte)0x49, (byte)0x86, (byte)0x06, (byte)0x99, + (byte)0x9c, (byte)0x42, (byte)0x50, (byte)0xf4, (byte)0x91, (byte)0xef, (byte)0x98, (byte)0x7a, (byte)0x33, (byte)0x54, (byte)0x0b, (byte)0x43, (byte)0xed, (byte)0xcf, (byte)0xac, (byte)0x62, + (byte)0xe4, (byte)0xb3, (byte)0x1c, (byte)0xa9, (byte)0xc9, (byte)0x08, (byte)0xe8, (byte)0x95, (byte)0x80, (byte)0xdf, (byte)0x94, (byte)0xfa, (byte)0x75, (byte)0x8f, (byte)0x3f, (byte)0xa6, + (byte)0x47, (byte)0x07, (byte)0xa7, (byte)0xfc, (byte)0xf3, (byte)0x73, (byte)0x17, (byte)0xba, (byte)0x83, (byte)0x59, (byte)0x3c, (byte)0x19, (byte)0xe6, (byte)0x85, (byte)0x4f, (byte)0xa8, + (byte)0x68, (byte)0x6b, (byte)0x81, (byte)0xb2, (byte)0x71, (byte)0x64, (byte)0xda, (byte)0x8b, (byte)0xf8, (byte)0xeb, (byte)0x0f, (byte)0x4b, (byte)0x70, (byte)0x56, (byte)0x9d, (byte)0x35, + (byte)0x1e, (byte)0x24, (byte)0x0e, (byte)0x5e, (byte)0x63, (byte)0x58, (byte)0xd1, (byte)0xa2, (byte)0x25, (byte)0x22, (byte)0x7c, (byte)0x3b, (byte)0x01, (byte)0x21, (byte)0x78, (byte)0x87, + (byte)0xd4, (byte)0x00, (byte)0x46, (byte)0x57, (byte)0x9f, (byte)0xd3, (byte)0x27, (byte)0x52, (byte)0x4c, (byte)0x36, (byte)0x02, (byte)0xe7, (byte)0xa0, (byte)0xc4, (byte)0xc8, (byte)0x9e, + (byte)0xea, (byte)0xbf, (byte)0x8a, (byte)0xd2, (byte)0x40, (byte)0xc7, (byte)0x38, (byte)0xb5, (byte)0xa3, (byte)0xf7, (byte)0xf2, (byte)0xce, (byte)0xf9, (byte)0x61, (byte)0x15, (byte)0xa1, + (byte)0xe0, (byte)0xae, (byte)0x5d, (byte)0xa4, (byte)0x9b, (byte)0x34, (byte)0x1a, (byte)0x55, (byte)0xad, (byte)0x93, (byte)0x32, (byte)0x30, (byte)0xf5, (byte)0x8c, (byte)0xb1, (byte)0xe3, + (byte)0x1d, (byte)0xf6, (byte)0xe2, (byte)0x2e, (byte)0x82, (byte)0x66, (byte)0xca, (byte)0x60, (byte)0xc0, (byte)0x29, (byte)0x23, (byte)0xab, (byte)0x0d, (byte)0x53, (byte)0x4e, (byte)0x6f, + (byte)0xd5, (byte)0xdb, (byte)0x37, (byte)0x45, (byte)0xde, (byte)0xfd, (byte)0x8e, (byte)0x2f, (byte)0x03, (byte)0xff, (byte)0x6a, (byte)0x72, (byte)0x6d, (byte)0x6c, (byte)0x5b, (byte)0x51, + (byte)0x8d, (byte)0x1b, (byte)0xaf, (byte)0x92, (byte)0xbb, (byte)0xdd, (byte)0xbc, (byte)0x7f, (byte)0x11, (byte)0xd9, (byte)0x5c, (byte)0x41, (byte)0x1f, (byte)0x10, (byte)0x5a, (byte)0xd8, + (byte)0x0a, (byte)0xc1, (byte)0x31, (byte)0x88, (byte)0xa5, (byte)0xcd, (byte)0x7b, (byte)0xbd, (byte)0x2d, (byte)0x74, (byte)0xd0, (byte)0x12, (byte)0xb8, (byte)0xe5, (byte)0xb4, (byte)0xb0, + (byte)0x89, (byte)0x69, (byte)0x97, (byte)0x4a, (byte)0x0c, (byte)0x96, (byte)0x77, (byte)0x7e, (byte)0x65, (byte)0xb9, (byte)0xf1, (byte)0x09, (byte)0xc5, (byte)0x6e, (byte)0xc6, (byte)0x84, + (byte)0x18, (byte)0xf0, (byte)0x7d, (byte)0xec, (byte)0x3a, (byte)0xdc, (byte)0x4d, (byte)0x20, (byte)0x79, (byte)0xee, (byte)0x5f, (byte)0x3e, (byte)0xd7, (byte)0xcb, (byte)0x39, (byte)0x48 + }; private final static int[] CK = - { - 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, - 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, - 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, - 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, - 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, - 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, - 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, - 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 - }; + { + 0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, + 0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9, + 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249, + 0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, + 0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229, + 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299, + 0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, + 0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279 + }; private final static int[] FK = - { - 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc - }; + { + 0xa3b1bac6, 0x56aa3350, 0x677d9197, 0xb27022dc + }; private final int[] X = new int[4]; @@ -151,22 +151,6 @@ public class SM4Engine return L(tau(Z)); } - // reverse substitution - private void R(int[] A, int off) - { - int off0 = off; - int off1 = off + 1; - int off2 = off + 2; - int off3 = off + 3; - - A[off0] = A[off0] ^ A[off3]; - A[off3] = A[off0] ^ A[off3]; - A[off0] = A[off0] ^ A[off3]; - A[off1] = A[off1] ^ A[off2]; - A[off2] = A[off1] ^ A[off2]; - A[off1] = A[off1] ^ A[off2]; - } - // The round functions private int F0(int[] X, int rk) { @@ -250,18 +234,16 @@ public class SM4Engine X[2] = F2(X, rk[i + 2]); X[3] = F3(X, rk[i + 3]); } - R(X, 0); - Pack.intToBigEndian(X[0], out, outOff); - Pack.intToBigEndian(X[1], out, outOff + 4); - Pack.intToBigEndian(X[2], out, outOff + 8); - Pack.intToBigEndian(X[3], out, outOff + 12); + Pack.intToBigEndian(X[3], out, outOff); + Pack.intToBigEndian(X[2], out, outOff + 4); + Pack.intToBigEndian(X[1], out, outOff + 8); + Pack.intToBigEndian(X[0], out, outOff + 12); - return 16; + return BLOCK_SIZE; } public void reset() { - } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc128CoreEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc128CoreEngine.java new file mode 100644 index 000000000..df56d7550 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc128CoreEngine.java @@ -0,0 +1,570 @@ +package com.fr.third.org.bouncycastle.crypto.engines; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.OutputLengthException; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Memoable; + +/** + * Zuc128Engine implementation. + * Based on https://www.gsma.com/aboutus/wp-content/uploads/2014/12/eea3eia3zucv16.pdf + */ +public class Zuc128CoreEngine + implements StreamCipher, Memoable +{ + /* the s-boxes */ + private static final byte[] S0 = new byte[]{ + (byte)0x3e, (byte)0x72, (byte)0x5b, (byte)0x47, (byte)0xca, (byte)0xe0, (byte)0x00, (byte)0x33, (byte)0x04, (byte)0xd1, (byte)0x54, (byte)0x98, (byte)0x09, (byte)0xb9, (byte)0x6d, (byte)0xcb, + (byte)0x7b, (byte)0x1b, (byte)0xf9, (byte)0x32, (byte)0xaf, (byte)0x9d, (byte)0x6a, (byte)0xa5, (byte)0xb8, (byte)0x2d, (byte)0xfc, (byte)0x1d, (byte)0x08, (byte)0x53, (byte)0x03, (byte)0x90, + (byte)0x4d, (byte)0x4e, (byte)0x84, (byte)0x99, (byte)0xe4, (byte)0xce, (byte)0xd9, (byte)0x91, (byte)0xdd, (byte)0xb6, (byte)0x85, (byte)0x48, (byte)0x8b, (byte)0x29, (byte)0x6e, (byte)0xac, + (byte)0xcd, (byte)0xc1, (byte)0xf8, (byte)0x1e, (byte)0x73, (byte)0x43, (byte)0x69, (byte)0xc6, (byte)0xb5, (byte)0xbd, (byte)0xfd, (byte)0x39, (byte)0x63, (byte)0x20, (byte)0xd4, (byte)0x38, + (byte)0x76, (byte)0x7d, (byte)0xb2, (byte)0xa7, (byte)0xcf, (byte)0xed, (byte)0x57, (byte)0xc5, (byte)0xf3, (byte)0x2c, (byte)0xbb, (byte)0x14, (byte)0x21, (byte)0x06, (byte)0x55, (byte)0x9b, + (byte)0xe3, (byte)0xef, (byte)0x5e, (byte)0x31, (byte)0x4f, (byte)0x7f, (byte)0x5a, (byte)0xa4, (byte)0x0d, (byte)0x82, (byte)0x51, (byte)0x49, (byte)0x5f, (byte)0xba, (byte)0x58, (byte)0x1c, + (byte)0x4a, (byte)0x16, (byte)0xd5, (byte)0x17, (byte)0xa8, (byte)0x92, (byte)0x24, (byte)0x1f, (byte)0x8c, (byte)0xff, (byte)0xd8, (byte)0xae, (byte)0x2e, (byte)0x01, (byte)0xd3, (byte)0xad, + (byte)0x3b, (byte)0x4b, (byte)0xda, (byte)0x46, (byte)0xeb, (byte)0xc9, (byte)0xde, (byte)0x9a, (byte)0x8f, (byte)0x87, (byte)0xd7, (byte)0x3a, (byte)0x80, (byte)0x6f, (byte)0x2f, (byte)0xc8, + (byte)0xb1, (byte)0xb4, (byte)0x37, (byte)0xf7, (byte)0x0a, (byte)0x22, (byte)0x13, (byte)0x28, (byte)0x7c, (byte)0xcc, (byte)0x3c, (byte)0x89, (byte)0xc7, (byte)0xc3, (byte)0x96, (byte)0x56, + (byte)0x07, (byte)0xbf, (byte)0x7e, (byte)0xf0, (byte)0x0b, (byte)0x2b, (byte)0x97, (byte)0x52, (byte)0x35, (byte)0x41, (byte)0x79, (byte)0x61, (byte)0xa6, (byte)0x4c, (byte)0x10, (byte)0xfe, + (byte)0xbc, (byte)0x26, (byte)0x95, (byte)0x88, (byte)0x8a, (byte)0xb0, (byte)0xa3, (byte)0xfb, (byte)0xc0, (byte)0x18, (byte)0x94, (byte)0xf2, (byte)0xe1, (byte)0xe5, (byte)0xe9, (byte)0x5d, + (byte)0xd0, (byte)0xdc, (byte)0x11, (byte)0x66, (byte)0x64, (byte)0x5c, (byte)0xec, (byte)0x59, (byte)0x42, (byte)0x75, (byte)0x12, (byte)0xf5, (byte)0x74, (byte)0x9c, (byte)0xaa, (byte)0x23, + (byte)0x0e, (byte)0x86, (byte)0xab, (byte)0xbe, (byte)0x2a, (byte)0x02, (byte)0xe7, (byte)0x67, (byte)0xe6, (byte)0x44, (byte)0xa2, (byte)0x6c, (byte)0xc2, (byte)0x93, (byte)0x9f, (byte)0xf1, + (byte)0xf6, (byte)0xfa, (byte)0x36, (byte)0xd2, (byte)0x50, (byte)0x68, (byte)0x9e, (byte)0x62, (byte)0x71, (byte)0x15, (byte)0x3d, (byte)0xd6, (byte)0x40, (byte)0xc4, (byte)0xe2, (byte)0x0f, + (byte)0x8e, (byte)0x83, (byte)0x77, (byte)0x6b, (byte)0x25, (byte)0x05, (byte)0x3f, (byte)0x0c, (byte)0x30, (byte)0xea, (byte)0x70, (byte)0xb7, (byte)0xa1, (byte)0xe8, (byte)0xa9, (byte)0x65, + (byte)0x8d, (byte)0x27, (byte)0x1a, (byte)0xdb, (byte)0x81, (byte)0xb3, (byte)0xa0, (byte)0xf4, (byte)0x45, (byte)0x7a, (byte)0x19, (byte)0xdf, (byte)0xee, (byte)0x78, (byte)0x34, (byte)0x60 + }; + + private static final byte[] S1 = new byte[]{ + (byte)0x55, (byte)0xc2, (byte)0x63, (byte)0x71, (byte)0x3b, (byte)0xc8, (byte)0x47, (byte)0x86, (byte)0x9f, (byte)0x3c, (byte)0xda, (byte)0x5b, (byte)0x29, (byte)0xaa, (byte)0xfd, (byte)0x77, + (byte)0x8c, (byte)0xc5, (byte)0x94, (byte)0x0c, (byte)0xa6, (byte)0x1a, (byte)0x13, (byte)0x00, (byte)0xe3, (byte)0xa8, (byte)0x16, (byte)0x72, (byte)0x40, (byte)0xf9, (byte)0xf8, (byte)0x42, + (byte)0x44, (byte)0x26, (byte)0x68, (byte)0x96, (byte)0x81, (byte)0xd9, (byte)0x45, (byte)0x3e, (byte)0x10, (byte)0x76, (byte)0xc6, (byte)0xa7, (byte)0x8b, (byte)0x39, (byte)0x43, (byte)0xe1, + (byte)0x3a, (byte)0xb5, (byte)0x56, (byte)0x2a, (byte)0xc0, (byte)0x6d, (byte)0xb3, (byte)0x05, (byte)0x22, (byte)0x66, (byte)0xbf, (byte)0xdc, (byte)0x0b, (byte)0xfa, (byte)0x62, (byte)0x48, + (byte)0xdd, (byte)0x20, (byte)0x11, (byte)0x06, (byte)0x36, (byte)0xc9, (byte)0xc1, (byte)0xcf, (byte)0xf6, (byte)0x27, (byte)0x52, (byte)0xbb, (byte)0x69, (byte)0xf5, (byte)0xd4, (byte)0x87, + (byte)0x7f, (byte)0x84, (byte)0x4c, (byte)0xd2, (byte)0x9c, (byte)0x57, (byte)0xa4, (byte)0xbc, (byte)0x4f, (byte)0x9a, (byte)0xdf, (byte)0xfe, (byte)0xd6, (byte)0x8d, (byte)0x7a, (byte)0xeb, + (byte)0x2b, (byte)0x53, (byte)0xd8, (byte)0x5c, (byte)0xa1, (byte)0x14, (byte)0x17, (byte)0xfb, (byte)0x23, (byte)0xd5, (byte)0x7d, (byte)0x30, (byte)0x67, (byte)0x73, (byte)0x08, (byte)0x09, + (byte)0xee, (byte)0xb7, (byte)0x70, (byte)0x3f, (byte)0x61, (byte)0xb2, (byte)0x19, (byte)0x8e, (byte)0x4e, (byte)0xe5, (byte)0x4b, (byte)0x93, (byte)0x8f, (byte)0x5d, (byte)0xdb, (byte)0xa9, + (byte)0xad, (byte)0xf1, (byte)0xae, (byte)0x2e, (byte)0xcb, (byte)0x0d, (byte)0xfc, (byte)0xf4, (byte)0x2d, (byte)0x46, (byte)0x6e, (byte)0x1d, (byte)0x97, (byte)0xe8, (byte)0xd1, (byte)0xe9, + (byte)0x4d, (byte)0x37, (byte)0xa5, (byte)0x75, (byte)0x5e, (byte)0x83, (byte)0x9e, (byte)0xab, (byte)0x82, (byte)0x9d, (byte)0xb9, (byte)0x1c, (byte)0xe0, (byte)0xcd, (byte)0x49, (byte)0x89, + (byte)0x01, (byte)0xb6, (byte)0xbd, (byte)0x58, (byte)0x24, (byte)0xa2, (byte)0x5f, (byte)0x38, (byte)0x78, (byte)0x99, (byte)0x15, (byte)0x90, (byte)0x50, (byte)0xb8, (byte)0x95, (byte)0xe4, + (byte)0xd0, (byte)0x91, (byte)0xc7, (byte)0xce, (byte)0xed, (byte)0x0f, (byte)0xb4, (byte)0x6f, (byte)0xa0, (byte)0xcc, (byte)0xf0, (byte)0x02, (byte)0x4a, (byte)0x79, (byte)0xc3, (byte)0xde, + (byte)0xa3, (byte)0xef, (byte)0xea, (byte)0x51, (byte)0xe6, (byte)0x6b, (byte)0x18, (byte)0xec, (byte)0x1b, (byte)0x2c, (byte)0x80, (byte)0xf7, (byte)0x74, (byte)0xe7, (byte)0xff, (byte)0x21, + (byte)0x5a, (byte)0x6a, (byte)0x54, (byte)0x1e, (byte)0x41, (byte)0x31, (byte)0x92, (byte)0x35, (byte)0xc4, (byte)0x33, (byte)0x07, (byte)0x0a, (byte)0xba, (byte)0x7e, (byte)0x0e, (byte)0x34, + (byte)0x88, (byte)0xb1, (byte)0x98, (byte)0x7c, (byte)0xf3, (byte)0x3d, (byte)0x60, (byte)0x6c, (byte)0x7b, (byte)0xca, (byte)0xd3, (byte)0x1f, (byte)0x32, (byte)0x65, (byte)0x04, (byte)0x28, + (byte)0x64, (byte)0xbe, (byte)0x85, (byte)0x9b, (byte)0x2f, (byte)0x59, (byte)0x8a, (byte)0xd7, (byte)0xb0, (byte)0x25, (byte)0xac, (byte)0xaf, (byte)0x12, (byte)0x03, (byte)0xe2, (byte)0xf2 + }; + + /* the constants D */ + private static final short[] EK_d = new short[]{ + 0x44D7, 0x26BC, 0x626B, 0x135E, 0x5789, 0x35E2, 0x7135, 0x09AF, + 0x4D78, 0x2F13, 0x6BC4, 0x1AF1, 0x5E26, 0x3C4D, 0x789A, 0x47AC + }; + + /** + * State. + */ + private final int[] LFSR = new int[16]; + private final int[] F = new int[2]; + private final int[] BRC = new int[4]; + + /** + * index of next byte in keyStream. + */ + private int theIndex; + + /** + * Advanced stream. + */ + private final byte[] keyStream = new byte[4]; // Integer.BYTES + + /** + * The iterations. + */ + private int theIterations; + + /** + * Reset state. + */ + private Zuc128CoreEngine theResetState; + + /** + * Constructor. + */ + protected Zuc128CoreEngine() + { + } + + /** + * Constructor. + * + * @param pSource the source engine + */ + protected Zuc128CoreEngine(final Zuc128CoreEngine pSource) + { + reset(pSource); + } + + /** + * initialise a Snow3G cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @throws IllegalArgumentException if the params argument is inappropriate. + */ + public void init(final boolean forEncryption, + final CipherParameters params) + { + /* + * encryption and decryption is completely symmetrical, so the 'forEncryption' is + * irrelevant. (Like 90% of stream ciphers) + */ + + /* Determine parameters */ + CipherParameters myParams = params; + byte[] newKey = null; + byte[] newIV = null; + if ((myParams instanceof ParametersWithIV)) + { + final ParametersWithIV ivParams = (ParametersWithIV)myParams; + newIV = ivParams.getIV(); + myParams = ivParams.getParameters(); + } + if (myParams instanceof KeyParameter) + { + final KeyParameter keyParam = (KeyParameter)myParams; + newKey = keyParam.getKey(); + } + + /* Initialise engine and mark as initialised */ + theIndex = 0; + theIterations = 0; + setKeyAndIV(newKey, newIV); + + /* Save reset state */ + theResetState = (Zuc128CoreEngine)copy(); + } + + /** + * Obtain Max iterations. + * + * @return the maximum iterations + */ + protected int getMaxIterations() + { + return 2047; + } + + /** + * Obtain Algorithm Name. + * + * @return the name + */ + public String getAlgorithmName() + { + return "Zuc-128"; + } + + /** + * Process bytes. + * + * @param in the input buffer + * @param inOff the starting offset in the input buffer + * @param len the length of data in the input buffer + * @param out the output buffer + * @param outOff the starting offset in the output buffer + * @return the number of bytes returned in the output buffer + */ + public int processBytes(final byte[] in, + final int inOff, + final int len, + final byte[] out, + final int outOff) + { + /* Check for errors */ + if (theResetState == null) + { + throw new IllegalStateException(getAlgorithmName() + " not initialised"); + } + if ((inOff + len) > in.length) + { + throw new DataLengthException("input buffer too short"); + } + if ((outOff + len) > out.length) + { + throw new OutputLengthException("output buffer too short"); + } + + /* Loop through the input bytes */ + for (int i = 0; i < len; i++) + { + out[i + outOff] = returnByte(in[i + inOff]); + } + return len; + } + + /** + * Reset the engine. + */ + public void reset() + { + if (theResetState != null) + { + reset(theResetState); + } + } + + /** + * Process single byte. + * + * @param in the input byte + * @return the output byte + */ + public byte returnByte(final byte in) + { + /* Make the keyStream if required */ + if (theIndex == 0) + { + makeKeyStream(); + } + + /* Map the next byte and adjust index */ + final byte out = (byte)(keyStream[theIndex] ^ in); + theIndex = (theIndex + 1) % 4; // Integer.BYTES + + /* Return the mapped character */ + return out; + } + + /** + * Encode a 32-bit value into a buffer (little-endian). + * + * @param val the value to encode + * @param buf the output buffer + * @param off the output offset + */ + public static void encode32be(int val, byte[] buf, int off) + { + buf[off] = (byte)(val >> 24); + buf[off + 1] = (byte)(val >> 16); + buf[off + 2] = (byte)(val >> 8); + buf[off + 3] = (byte)val; + } + + /* ����������������������- */ + + /** + * Modular add c = a + b mod (2^31 � 1). + * + * @param a value A + * @param b value B + * @return the result + */ + private int AddM(final int a, final int b) + { + final int c = a + b; + return (c & 0x7FFFFFFF) + (c >>> 31); + } + + /** + * Multiply by power of two. + * + * @param x input value + * @param k the power of two + * @return the result + */ + private static int MulByPow2(final int x, final int k) + { + return ((((x) << k) | ((x) >>> (31 - k))) & 0x7FFFFFFF); + } + + /** + * LFSR with initialisation mode. + * + * @param u + */ + private void LFSRWithInitialisationMode(final int u) + { + int f = LFSR[0]; + int v = MulByPow2(LFSR[0], 8); + f = AddM(f, v); + v = MulByPow2(LFSR[4], 20); + f = AddM(f, v); + v = MulByPow2(LFSR[10], 21); + f = AddM(f, v); + v = MulByPow2(LFSR[13], 17); + f = AddM(f, v); + v = MulByPow2(LFSR[15], 15); + f = AddM(f, v); + f = AddM(f, u); + + /* update the state */ + LFSR[0] = LFSR[1]; + LFSR[1] = LFSR[2]; + LFSR[2] = LFSR[3]; + LFSR[3] = LFSR[4]; + LFSR[4] = LFSR[5]; + LFSR[5] = LFSR[6]; + LFSR[6] = LFSR[7]; + LFSR[7] = LFSR[8]; + LFSR[8] = LFSR[9]; + LFSR[9] = LFSR[10]; + LFSR[10] = LFSR[11]; + LFSR[11] = LFSR[12]; + LFSR[12] = LFSR[13]; + LFSR[13] = LFSR[14]; + LFSR[14] = LFSR[15]; + LFSR[15] = f; + } + + /** + * LFSR with work mode. + */ + private void LFSRWithWorkMode() + { + int f, v; + f = LFSR[0]; + v = MulByPow2(LFSR[0], 8); + f = AddM(f, v); + v = MulByPow2(LFSR[4], 20); + f = AddM(f, v); + v = MulByPow2(LFSR[10], 21); + f = AddM(f, v); + v = MulByPow2(LFSR[13], 17); + f = AddM(f, v); + v = MulByPow2(LFSR[15], 15); + f = AddM(f, v); + + /* update the state */ + LFSR[0] = LFSR[1]; + LFSR[1] = LFSR[2]; + LFSR[2] = LFSR[3]; + LFSR[3] = LFSR[4]; + LFSR[4] = LFSR[5]; + LFSR[5] = LFSR[6]; + LFSR[6] = LFSR[7]; + LFSR[7] = LFSR[8]; + LFSR[8] = LFSR[9]; + LFSR[9] = LFSR[10]; + LFSR[10] = LFSR[11]; + LFSR[11] = LFSR[12]; + LFSR[12] = LFSR[13]; + LFSR[13] = LFSR[14]; + LFSR[14] = LFSR[15]; + LFSR[15] = f; + } + + /** + * BitReorganization. + */ + private void BitReorganization() + { + BRC[0] = ((LFSR[15] & 0x7FFF8000) << 1) | (LFSR[14] & 0xFFFF); + BRC[1] = ((LFSR[11] & 0xFFFF) << 16) | (LFSR[9] >>> 15); + BRC[2] = ((LFSR[7] & 0xFFFF) << 16) | (LFSR[5] >>> 15); + BRC[3] = ((LFSR[2] & 0xFFFF) << 16) | (LFSR[0] >>> 15); + } + + /** + * Rotate integer. + * + * @param a the integer + * @param k the shift + * @return the result + */ + static int ROT(int a, int k) + { + return (((a) << k) | ((a) >>> (32 - k))); + } + + /** + * L1. + * + * @param X the input integer. + * @return the result + */ + private static int L1(final int X) + { + return (X ^ ROT(X, 2) ^ ROT(X, 10) ^ ROT(X, 18) ^ ROT(X, 24)); + } + + /** + * L2. + * + * @param X the input integer. + * @return the result + */ + private static int L2(final int X) + { + return (X ^ ROT(X, 8) ^ ROT(X, 14) ^ ROT(X, 22) ^ ROT(X, 30)); + } + + /** + * Build a 32-bit integer from constituent parts. + * + * @param a part A + * @param b part B + * @param c part C + * @param d part D + * @return the built integer + */ + private static int MAKEU32(final byte a, + final byte b, + final byte c, + final byte d) + { + return (((a & 0xFF) << 24) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | ((d & 0xFF))); + } + + /** + * F. + */ + int F() + { + int W, W1, W2, u, v; + W = (BRC[0] ^ F[0]) + F[1]; + W1 = F[0] + BRC[1]; + W2 = F[1] ^ BRC[2]; + u = L1((W1 << 16) | (W2 >>> 16)); + v = L2((W2 << 16) | (W1 >>> 16)); + F[0] = MAKEU32(S0[u >>> 24], S1[(u >>> 16) & 0xFF], + S0[(u >>> 8) & 0xFF], S1[u & 0xFF]); + F[1] = MAKEU32(S0[v >>> 24], S1[(v >>> 16) & 0xFF], + S0[(v >>> 8) & 0xFF], S1[v & 0xFF]); + return W; + } + + /** + * Build a 31-bit integer from constituent parts. + * + * @param a part A + * @param b part B + * @param c part C + * @return the built integer + */ + private static int MAKEU31(final byte a, + final short b, + final byte c) + { + return (((a & 0xFF) << 23) | ((b & 0xFFFF) << 8) | (c & 0xFF)); + } + + /** + * Process key and IV into LFSR. + * + * @param pLFSR the LFSR + * @param k the key + * @param iv the iv + */ + protected void setKeyAndIV(final int[] pLFSR, + final byte[] k, + final byte[] iv) + { + /* Check lengths */ + if (k == null || k.length != 16) + { + throw new IllegalArgumentException("A key of 16 bytes is needed"); + } + if (iv == null || iv.length != 16) + { + throw new IllegalArgumentException("An IV of 16 bytes is needed"); + } + + /* expand key */ + LFSR[0] = MAKEU31(k[0], EK_d[0], iv[0]); + LFSR[1] = MAKEU31(k[1], EK_d[1], iv[1]); + LFSR[2] = MAKEU31(k[2], EK_d[2], iv[2]); + LFSR[3] = MAKEU31(k[3], EK_d[3], iv[3]); + LFSR[4] = MAKEU31(k[4], EK_d[4], iv[4]); + LFSR[5] = MAKEU31(k[5], EK_d[5], iv[5]); + LFSR[6] = MAKEU31(k[6], EK_d[6], iv[6]); + LFSR[7] = MAKEU31(k[7], EK_d[7], iv[7]); + LFSR[8] = MAKEU31(k[8], EK_d[8], iv[8]); + LFSR[9] = MAKEU31(k[9], EK_d[9], iv[9]); + LFSR[10] = MAKEU31(k[10], EK_d[10], iv[10]); + LFSR[11] = MAKEU31(k[11], EK_d[11], iv[11]); + LFSR[12] = MAKEU31(k[12], EK_d[12], iv[12]); + LFSR[13] = MAKEU31(k[13], EK_d[13], iv[13]); + LFSR[14] = MAKEU31(k[14], EK_d[14], iv[14]); + LFSR[15] = MAKEU31(k[15], EK_d[15], iv[15]); + } + + /** + * Process key and IV. + * + * @param k the key + * @param iv the IV + */ + private void setKeyAndIV(final byte[] k, + final byte[] iv) + { + /* Initialise LFSR */ + setKeyAndIV(LFSR, k, iv); + + /* set F_R1 and F_R2 to zero */ + F[0] = 0; + F[1] = 0; + int nCount = 32; + while (nCount > 0) + { + BitReorganization(); + final int w = F(); + LFSRWithInitialisationMode(w >>> 1); + nCount--; + } + BitReorganization(); + F(); /* discard the output of F */ + LFSRWithWorkMode(); + } + + /** + * Create the next byte keyStream. + */ + private void makeKeyStream() + { + encode32be(makeKeyStreamWord(), keyStream, 0); + } + + /** + * Create the next keyStream word. + * + * @return the next word + */ + protected int makeKeyStreamWord() + { + if (theIterations++ >= getMaxIterations()) + { + throw new IllegalStateException("Too much data processed by singleKey/IV"); + } + BitReorganization(); + final int result = F() ^ BRC[3]; + LFSRWithWorkMode(); + return result; + } + + /** + * Create a copy of the engine. + * + * @return the copy + */ + public Memoable copy() + { + return new Zuc128CoreEngine(this); + } + + /** + * Reset from saved engine state. + * + * @param pState the state to restore + */ + public void reset(final Memoable pState) + { + final Zuc128CoreEngine e = (Zuc128CoreEngine)pState; + System.arraycopy(e.LFSR, 0, LFSR, 0, LFSR.length); + System.arraycopy(e.F, 0, F, 0, F.length); + System.arraycopy(e.BRC, 0, BRC, 0, BRC.length); + System.arraycopy(e.keyStream, 0, keyStream, 0, keyStream.length); + theIndex = e.theIndex; + theIterations = e.theIterations; + theResetState = e; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc128Engine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc128Engine.java new file mode 100644 index 000000000..a59b4b1ce --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc128Engine.java @@ -0,0 +1,39 @@ +package com.fr.third.org.bouncycastle.crypto.engines; + +import com.fr.third.org.bouncycastle.util.Memoable; + +/** + * Zuc256 implementation. + * Based on http://www.is.cas.cn/ztzl2016/zouchongzhi/201801/W020180126529970733243.pdf + */ +public final class Zuc128Engine + extends Zuc128CoreEngine +{ + /** + * Constructor for streamCipher. + */ + public Zuc128Engine() + { + super(); + } + + /** + * Constructor for Memoable. + * + * @param pSource the source engine + */ + private Zuc128Engine(final Zuc128Engine pSource) + { + super(pSource); + } + + /** + * Create a copy of the engine. + * + * @return the copy + */ + public Memoable copy() + { + return new Zuc128Engine(this); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc256CoreEngine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc256CoreEngine.java new file mode 100644 index 000000000..21c932b87 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc256CoreEngine.java @@ -0,0 +1,181 @@ +package com.fr.third.org.bouncycastle.crypto.engines; + +import com.fr.third.org.bouncycastle.util.Memoable; + +/** + * Zuc256 implementation. + * Based on http://www.is.cas.cn/ztzl2016/zouchongzhi/201801/W020180126529970733243.pdf + */ +public class Zuc256CoreEngine + extends Zuc128CoreEngine +{ + /* the constants D */ + private static final byte[] EK_d = new byte[]{ + 0x22, 0x2f, 0x24, 0x2a, 0x6d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x52, 0x10, 0x30 +// 0b0100010, 0b0101111, 0b0100100, 0b0101010, 0b1101101, 0b1000000, 0b1000000, 0b1000000, +// 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1010010, 0b0010000, 0b0110000 + }; + + /* the constants D for 32 bit Mac*/ + private static final byte[] EK_d32 = new byte[]{ + 0x22, 0x2f, 0x25, 0x2a, 0x6d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x52, 0x10, 0x30 +// 0b0100010, 0b0101111, 0b0100101, 0b0101010, 0b1101101, 0b1000000, 0b1000000, 0b1000000, +// 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1010010, 0b0010000, 0b0110000 + }; + + /* the constants D for 64 bit Mac */ + private static final byte[] EK_d64 = new byte[]{ + 0x23, 0x2f, 0x24, 0x2a, 0x6d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x52, 0x10, 0x30 +// 0b0100011, 0b0101111, 0b0100100, 0b0101010, 0b1101101, 0b1000000, 0b1000000, 0b1000000, +// 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1010010, 0b0010000, 0b0110000 + }; + + /* the constants D for 128 bit Mac */ + private static final byte[] EK_d128 = new byte[]{ + 0x23, 0x2f, 0x25, 0x2a, 0x6d, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x52, 0x10, 0x30 +// 0b0100011, 0b0101111, 0b0100101, 0b0101010, 0b1101101, 0b1000000, 0b1000000, 0b1000000, +// 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1000000, 0b1010010, 0b0010000, 0b0110000 + }; + + /** + * The selected D constants. + */ + private byte[] theD; + + /** + * Constructor for streamCipher. + */ + protected Zuc256CoreEngine() + { + theD = EK_d; + } + + /** + * Constructor for Mac. + * + * @param pLength the Mac length + */ + protected Zuc256CoreEngine(final int pLength) + { + switch (pLength) + { + case 32: + theD = EK_d32; + break; + case 64: + theD = EK_d64; + break; + case 128: + theD = EK_d128; + break; + default: + throw new IllegalArgumentException("Unsupported length: " + pLength); + } + } + + /** + * Constructor for Memoable. + * + * @param pSource the source engine + */ + protected Zuc256CoreEngine(final Zuc256CoreEngine pSource) + { + super(pSource); + } + + /** + * Obtain Max iterations. + * + * @return the maximum iterations + */ + protected int getMaxIterations() + { + return 625; + } + + /** + * Obtain Algorithm Name. + * + * @return the name + */ + public String getAlgorithmName() + { + return "Zuc-256"; + } + + /** + * Build a 31-bit integer from constituent parts. + * + * @param a part A + * @param b part B + * @param c part C + * @param d part D + * @return the built integer + */ + private static int MAKEU31(byte a, byte b, byte c, byte d) + { + return (((a & 0xFF) << 23) | ((b & 0xFF) << 16) | ((c & 0xFF) << 8) | (d & 0xFF)); + } + + /** + * Process key and IV into LFSR. + * + * @param pLFSR the LFSR + * @param k the key + * @param iv the iv + */ + protected void setKeyAndIV(final int[] pLFSR, + final byte[] k, + final byte[] iv) + { + /* Check lengths */ + if (k == null || k.length != 32) + { + throw new IllegalArgumentException("A key of 32 bytes is needed"); + } + if (iv == null || iv.length != 25) + { + throw new IllegalArgumentException("An IV of 25 bytes is needed"); + } + + /* expand key and IV */ + pLFSR[0] = MAKEU31(k[0], theD[0], k[21], k[16]); + pLFSR[1] = MAKEU31(k[1], theD[1], k[22], k[17]); + pLFSR[2] = MAKEU31(k[2], theD[2], k[23], k[18]); + pLFSR[3] = MAKEU31(k[3], theD[3], k[24], k[19]); + pLFSR[4] = MAKEU31(k[4], theD[4], k[25], k[20]); + pLFSR[5] = MAKEU31(iv[0], (byte)(theD[5] | (iv[17] & 0x3F)), k[5], k[26]); + pLFSR[6] = MAKEU31(iv[1], (byte)(theD[6] | (iv[18] & 0x3F)), k[6], k[27]); + pLFSR[7] = MAKEU31(iv[10], (byte)(theD[7] | (iv[19] & 0x3F)), k[7], iv[2]); + pLFSR[8] = MAKEU31(k[8], (byte)(theD[8] | (iv[20] & 0x3F)), iv[3], iv[11]); + pLFSR[9] = MAKEU31(k[9], (byte)(theD[9] | (iv[21] & 0x3F)), iv[12], iv[4]); + pLFSR[10] = MAKEU31(iv[5], (byte)(theD[10] | (iv[22] & 0x3F)), k[10], k[28]); + pLFSR[11] = MAKEU31(k[11], (byte)(theD[11] | (iv[23] & 0x3F)), iv[6], iv[13]); + pLFSR[12] = MAKEU31(k[12], (byte)(theD[12] | (iv[24] & 0x3F)), iv[7], iv[14]); + pLFSR[13] = MAKEU31(k[13], theD[13], iv[15], iv[8]); + pLFSR[14] = MAKEU31(k[14], (byte)(theD[14] | ((k[31] >>> 4) & 0xF)), iv[16], iv[9]); + pLFSR[15] = MAKEU31(k[15], (byte)(theD[15] | (k[31] & 0xF)), k[30], k[29]); + } + + /** + * Create a copy of the engine. + * + * @return the copy + */ + public Memoable copy() + { + return new Zuc256CoreEngine(this); + } + + /** + * Reset from saved engine state. + * + * @param pState the state to restore + */ + public void reset(final Memoable pState) + { + final Zuc256CoreEngine e = (Zuc256CoreEngine)pState; + super.reset(pState); + theD = e.theD; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc256Engine.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc256Engine.java new file mode 100644 index 000000000..c48c4e7f8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/engines/Zuc256Engine.java @@ -0,0 +1,49 @@ +package com.fr.third.org.bouncycastle.crypto.engines; + +import com.fr.third.org.bouncycastle.util.Memoable; + +/** + * Zuc256 implementation. + * Based on http://www.is.cas.cn/ztzl2016/zouchongzhi/201801/W020180126529970733243.pdf + */ +public final class Zuc256Engine + extends Zuc256CoreEngine +{ + /** + * Constructor for streamCipher. + */ + public Zuc256Engine() + { + super(); + } + + /** + * Constructor for Mac. + * + * @param pLength the Mac length + */ + public Zuc256Engine(final int pLength) + { + super(pLength); + } + + /** + * Constructor for Memoable. + * + * @param pSource the source engine + */ + private Zuc256Engine(final Zuc256Engine pSource) + { + super(pSource); + } + + /** + * Create a copy of the engine. + * + * @return the copy + */ + public Memoable copy() + { + return new Zuc256Engine(this); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/Argon2BytesGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/Argon2BytesGenerator.java new file mode 100644 index 000000000..1913b6706 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/Argon2BytesGenerator.java @@ -0,0 +1,756 @@ +package com.fr.third.org.bouncycastle.crypto.generators; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.Blake2bDigest; +import com.fr.third.org.bouncycastle.crypto.params.Argon2Parameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Pack; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + + +/** + * Argon2 PBKDF - Based on the results of https://password-hashing.net/ and https://www.ietf.org/archive/id/draft-irtf-cfrg-argon2-03.txt + */ +public class Argon2BytesGenerator +{ + + private static final int ARGON2_BLOCK_SIZE = 1024; + private static final int ARGON2_QWORDS_IN_BLOCK = ARGON2_BLOCK_SIZE / 8; + + private static final int ARGON2_ADDRESSES_IN_BLOCK = 128; + + private static final int ARGON2_PREHASH_DIGEST_LENGTH = 64; + private static final int ARGON2_PREHASH_SEED_LENGTH = 72; + + private static final int ARGON2_SYNC_POINTS = 4; + + /* Minimum and maximum number of lanes (degree of parallelism) */ + private static final int MIN_PARALLELISM = 1; + private static final int MAX_PARALLELISM = 16777216; + + /* Minimum and maximum digest size in bytes */ + private static final int MIN_OUTLEN = 4; + + /* Minimum and maximum number of passes */ + private static final int MIN_ITERATIONS = 1; + + private Block[] memory; + + + private int segmentLength; + private int laneLength; + + + private Argon2Parameters parameters; + + private byte[] result; + + public Argon2BytesGenerator() + { + + } + + /** + * Initialise the Argon2BytesGenerator from the parameters. + * + * @param parameters Argon2 configuration. + */ + public void init(Argon2Parameters parameters) + { + this.parameters = parameters; + + + if (parameters.getLanes() < Argon2BytesGenerator.MIN_PARALLELISM) + { + throw new IllegalStateException("lanes must be greater than " + Argon2BytesGenerator.MIN_PARALLELISM); + } + else if (parameters.getLanes() > Argon2BytesGenerator.MAX_PARALLELISM) + { + throw new IllegalStateException("lanes must be less than " + Argon2BytesGenerator.MAX_PARALLELISM); + } + else if (parameters.getMemory() < 2 * parameters.getLanes()) + { + throw new IllegalStateException("memory is less than: " + (2 * parameters.getLanes()) + " expected " + (2 * parameters.getLanes())); + } + else if (parameters.getIterations() < Argon2BytesGenerator.MIN_ITERATIONS) + { + throw new IllegalStateException("iterations is less than: " + Argon2BytesGenerator.MIN_ITERATIONS); + } + + doInit(parameters); + } + + public int generateBytes(char[] password, byte[] out) + { + return generateBytes(parameters.getCharToByteConverter().convert(password), out); + } + + public int generateBytes(char[] password, byte[] out, int outOff, int outLen) + { + return generateBytes(parameters.getCharToByteConverter().convert(password), out, outOff, outLen); + } + + public int generateBytes(byte[] password, byte[] out) + { + return generateBytes(password, out, 0, out.length); + } + + public int generateBytes(byte[] password, byte[] out, int outOff, int outLen) + { + if (outLen < Argon2BytesGenerator.MIN_OUTLEN) + { + throw new IllegalStateException("output length less than " + Argon2BytesGenerator.MIN_OUTLEN); + } + + initialize(password, outLen); + fillMemoryBlocks(); + digest(outLen); + + System.arraycopy(result, 0, out, outOff, outLen); + + reset(); + + return outLen; + } + + // Clear memory. + private void reset() + { + // Reset memory. + for (int i = 0; i < memory.length; i++) + { + Block b = memory[i]; + + b.clear(); + } + memory = null; + Arrays.fill(result, (byte)0); + } + + private void doInit(Argon2Parameters parameters) + { + /* 2. Align memory size */ + /* Minimum memoryBlocks = 8L blocks, where L is the number of lanes */ + int memoryBlocks = parameters.getMemory(); + + if (memoryBlocks < 2 * Argon2BytesGenerator.ARGON2_SYNC_POINTS * parameters.getLanes()) + { + memoryBlocks = 2 * Argon2BytesGenerator.ARGON2_SYNC_POINTS * parameters.getLanes(); + } + + this.segmentLength = memoryBlocks / (parameters.getLanes() * Argon2BytesGenerator.ARGON2_SYNC_POINTS); + this.laneLength = segmentLength * Argon2BytesGenerator.ARGON2_SYNC_POINTS; + + /* Ensure that all segments have equal length */ + memoryBlocks = segmentLength * (parameters.getLanes() * Argon2BytesGenerator.ARGON2_SYNC_POINTS); + + initMemory(memoryBlocks); + } + + + private void initMemory(int memoryBlocks) + { + this.memory = new Block[memoryBlocks]; + + for (int i = 0; i < memory.length; i++) + { + memory[i] = new Block(); + } + } + + private void fillMemoryBlocks() + { + FillBlock filler = new FillBlock(); + Position position = new Position(); + for (int i = 0; i < parameters.getIterations(); i++) + { + for (int j = 0; j < ARGON2_SYNC_POINTS; j++) + { + for (int k = 0; k < parameters.getLanes(); k++) + { + position.update(i, k, j, 0); + fillSegment(filler, position); + } + } + } + } + + private void fillSegment(FillBlock filler, Position position) + { + + Block addressBlock = null, inputBlock = null, zeroBlock = null; + + boolean dataIndependentAddressing = isDataIndependentAddressing(position); + int startingIndex = getStartingIndex(position); + int currentOffset = position.lane * laneLength + position.slice * segmentLength + startingIndex; + int prevOffset = getPrevOffset(currentOffset); + + if (dataIndependentAddressing) + { + addressBlock = filler.addressBlock.clear(); + zeroBlock = filler.zeroBlock.clear(); + inputBlock = filler.inputBlock.clear(); + + initAddressBlocks(filler, position, zeroBlock, inputBlock, addressBlock); + } + + for (position.index = startingIndex; position.index < segmentLength; position.index++, currentOffset++, prevOffset++) + { + prevOffset = rotatePrevOffset(currentOffset, prevOffset); + + long pseudoRandom = getPseudoRandom(filler, position, addressBlock, inputBlock, zeroBlock, prevOffset, dataIndependentAddressing); + int refLane = getRefLane(position, pseudoRandom); + int refColumn = getRefColumn(position, pseudoRandom, refLane == position.lane); + + /* 2 Creating a new block */ + Block prevBlock = memory[prevOffset]; + Block refBlock = memory[((laneLength) * refLane + refColumn)]; + Block currentBlock = memory[currentOffset]; + + if (isWithXor(position)) + { + filler.fillBlockWithXor(prevBlock, refBlock, currentBlock); + } + else + { + filler.fillBlock(prevBlock, refBlock, currentBlock); + } + } + } + + private boolean isDataIndependentAddressing(Position position) + { + return (parameters.getType() == Argon2Parameters.ARGON2_i) || + (parameters.getType() == Argon2Parameters.ARGON2_id + && (position.pass == 0) + && (position.slice < ARGON2_SYNC_POINTS / 2) + ); + } + + private void initAddressBlocks(FillBlock filler, Position position, Block zeroBlock, Block inputBlock, Block addressBlock) + { + inputBlock.v[0] = intToLong(position.pass); + inputBlock.v[1] = intToLong(position.lane); + inputBlock.v[2] = intToLong(position.slice); + inputBlock.v[3] = intToLong(memory.length); + inputBlock.v[4] = intToLong(parameters.getIterations()); + inputBlock.v[5] = intToLong(parameters.getType()); + + if ((position.pass == 0) && (position.slice == 0)) + { + /* Don't forget to generate the first block of addresses: */ + nextAddresses(filler, zeroBlock, inputBlock, addressBlock); + } + } + + private boolean isWithXor(Position position) + { + return !(position.pass == 0 || parameters.getVersion() == Argon2Parameters.ARGON2_VERSION_10); + } + + private int getPrevOffset(int currentOffset) + { + if (currentOffset % laneLength == 0) + { + /* Last block in this lane */ + return currentOffset + laneLength - 1; + } + else + { + /* Previous block */ + return currentOffset - 1; + } + } + + private int rotatePrevOffset(int currentOffset, int prevOffset) + { + if (currentOffset % laneLength == 1) + { + prevOffset = currentOffset - 1; + } + return prevOffset; + } + + private static int getStartingIndex(Position position) + { + if ((position.pass == 0) && (position.slice == 0)) + { + return 2; /* we have already generated the first two blocks */ + } + else + { + return 0; + } + } + + private void nextAddresses(FillBlock filler, Block zeroBlock, Block inputBlock, Block addressBlock) + { + inputBlock.v[6]++; + filler.fillBlock(zeroBlock, inputBlock, addressBlock); + filler.fillBlock(zeroBlock, addressBlock, addressBlock); + } + + /* 1.2 Computing the index of the reference block */ + /* 1.2.1 Taking pseudo-random value from the previous block */ + private long getPseudoRandom(FillBlock filler, Position position, Block addressBlock, Block inputBlock, Block zeroBlock, int prevOffset, boolean dataIndependentAddressing) + { + if (dataIndependentAddressing) + { + if (position.index % ARGON2_ADDRESSES_IN_BLOCK == 0) + { + nextAddresses(filler, zeroBlock, inputBlock, addressBlock); + } + return addressBlock.v[position.index % ARGON2_ADDRESSES_IN_BLOCK]; + } + else + { + return memory[prevOffset].v[0]; + } + } + + private int getRefLane(Position position, long pseudoRandom) + { + int refLane = (int)(((pseudoRandom >>> 32)) % parameters.getLanes()); + + if ((position.pass == 0) && (position.slice == 0)) + { + /* Can not reference other lanes yet */ + refLane = position.lane; + } + return refLane; + } + + private int getRefColumn(Position position, long pseudoRandom, + boolean sameLane) + { + + int referenceAreaSize; + int startPosition; + + if (position.pass == 0) + { + startPosition = 0; + + if (sameLane) + { + /* The same lane => add current segment */ + referenceAreaSize = position.slice * segmentLength + position.index - 1; + } + else + { + /* pass == 0 && !sameLane => position.slice > 0*/ + referenceAreaSize = position.slice * segmentLength + ((position.index == 0) ? (-1) : 0); + } + + } + else + { + startPosition = ((position.slice + 1) * segmentLength) % laneLength; + + if (sameLane) + { + referenceAreaSize = laneLength - segmentLength + position.index - 1; + } + else + { + referenceAreaSize = laneLength - segmentLength + ((position.index == 0) ? (-1) : 0); + } + } + + long relativePosition = pseudoRandom & 0xFFFFFFFFL; +// long relativePosition = pseudoRandom << 32 >>> 32; + relativePosition = (relativePosition * relativePosition) >>> 32; + relativePosition = referenceAreaSize - 1 - ((referenceAreaSize * relativePosition) >>> 32); + + return (int)(startPosition + relativePosition) % laneLength; + } + + private void digest(int outputLength) + { + Block finalBlock = memory[laneLength - 1]; + + /* XOR the last blocks */ + for (int i = 1; i < parameters.getLanes(); i++) + { + int lastBlockInLane = i * laneLength + (laneLength - 1); + finalBlock.xorWith(memory[lastBlockInLane]); + } + + byte[] finalBlockBytes = finalBlock.toBytes(); + + result = hash(finalBlockBytes, outputLength); + } + + /** + * H0 = H64(p, τ, m, t, v, y, |P|, P, |S|, S, |L|, K, |X|, X) + * -> 64 byte (ARGON2_PREHASH_DIGEST_LENGTH) + */ + private byte[] initialHash(Argon2Parameters parameters, int outputLength, byte[] password) + { + Blake2bDigest blake = new Blake2bDigest(ARGON2_PREHASH_DIGEST_LENGTH * 8); + + addIntToLittleEndian(blake, parameters.getLanes()); + addIntToLittleEndian(blake, outputLength); + addIntToLittleEndian(blake, parameters.getMemory()); + addIntToLittleEndian(blake, parameters.getIterations()); + addIntToLittleEndian(blake, parameters.getVersion()); + addIntToLittleEndian(blake, parameters.getType()); + + addByteString(blake, password); + addByteString(blake, parameters.getSalt()); + addByteString(blake, parameters.getSecret()); + addByteString(blake, parameters.getAdditional()); + + byte[] blake2hash = new byte[blake.getDigestSize()]; + blake.doFinal(blake2hash, 0); + + return blake2hash; + } + + /** + * H' - hash - variable length hash function + */ + private byte[] hash(byte[] input, int outputLength) + { + byte[] result = new byte[outputLength]; + byte[] outlenBytes = Pack.intToLittleEndian(outputLength); + + int blake2bLength = 64; + + if (outputLength <= blake2bLength) + { + Blake2bDigest blake = new Blake2bDigest(outputLength * 8); + + blake.update(outlenBytes, 0, outlenBytes.length); + blake.update(input, 0, input.length); + blake.doFinal(result, 0); + } + else + { + Blake2bDigest digest = new Blake2bDigest(blake2bLength * 8); + byte[] outBuffer = new byte[blake2bLength]; + + /* V1 */ + digest.update(outlenBytes, 0, outlenBytes.length); + digest.update(input, 0, input.length); + digest.doFinal(outBuffer, 0); + + System.arraycopy(outBuffer, 0, result, 0, blake2bLength / 2); + + int r = ((outputLength + 31) / 32) - 2; + + int position = blake2bLength / 2; + + for (int i = 2; i <= r; i++, position += blake2bLength / 2) + { + /* V2 to Vr */ + digest.update(outBuffer, 0, outBuffer.length); + digest.doFinal(outBuffer, 0); + + System.arraycopy(outBuffer, 0, result, position, blake2bLength / 2); + } + + int lastLength = outputLength - 32 * r; + + /* Vr+1 */ + digest = new Blake2bDigest(lastLength * 8); + + digest.update(outBuffer, 0, outBuffer.length); + digest.doFinal(result, position); + } + + return result; + } + + private static void roundFunction(Block block, + int v0, int v1, int v2, int v3, + int v4, int v5, int v6, int v7, + int v8, int v9, int v10, int v11, + int v12, int v13, int v14, int v15) + { + + F(block, v0, v4, v8, v12); + F(block, v1, v5, v9, v13); + F(block, v2, v6, v10, v14); + F(block, v3, v7, v11, v15); + + F(block, v0, v5, v10, v15); + F(block, v1, v6, v11, v12); + F(block, v2, v7, v8, v13); + F(block, v3, v4, v9, v14); + } + + private static void F(Block block, int a, int b, int c, int d) + { + fBlaMka(block, a, b); + rotr64(block, d, a, 32); + + fBlaMka(block, c, d); + rotr64(block, b, c, 24); + + fBlaMka(block, a, b); + rotr64(block, d, a, 16); + + fBlaMka(block, c, d); + rotr64(block, b, c, 63); + } + + /*designed by the Lyra PHC team */ + /* a <- a + b + 2*aL*bL + * + == addition modulo 2^64 + * aL = least 32 bit */ + private static void fBlaMka(Block block, int x, int y) + { + final long m = 0xFFFFFFFFL; + final long xy = (block.v[x] & m) * (block.v[y] & m); + + block.v[x] = block.v[x] + block.v[y] + 2 * xy; + } + + private static void rotr64(Block block, int v, int w, long c) + { + final long temp = block.v[v] ^ block.v[w]; + block.v[v] = (temp >>> c) | (temp << (64 - c)); + } + + private void initialize(byte[] password, int outputLength) + { + byte[] initialHash = initialHash(parameters, outputLength, password); + + fillFirstBlocks(initialHash); + } + + private static void addIntToLittleEndian(Digest digest, int n) + { + digest.update((byte)(n)); + digest.update((byte)(n >>> 8)); + digest.update((byte)(n >>> 16)); + digest.update((byte)(n >>> 24)); + } + + private static void addByteString(Digest digest, byte[] octets) + { + if (octets != null) + { + addIntToLittleEndian(digest, octets.length); + digest.update(octets, 0, octets.length); + } + else + { + addIntToLittleEndian(digest, 0); + } + } + + /** + * (H0 || 0 || i) 72 byte -> 1024 byte + * (H0 || 1 || i) 72 byte -> 1024 byte + */ + private void fillFirstBlocks(byte[] initialHash) + { + final byte[] zeroBytes = {0, 0, 0, 0}; + final byte[] oneBytes = {1, 0, 0, 0}; + + byte[] initialHashWithZeros = getInitialHashLong(initialHash, zeroBytes); + byte[] initialHashWithOnes = getInitialHashLong(initialHash, oneBytes); + + for (int i = 0; i < parameters.getLanes(); i++) + { + Pack.intToLittleEndian(i, initialHashWithZeros, ARGON2_PREHASH_DIGEST_LENGTH + 4); + Pack.intToLittleEndian(i, initialHashWithOnes, ARGON2_PREHASH_DIGEST_LENGTH + 4); + + byte[] blockhashBytes = hash(initialHashWithZeros, ARGON2_BLOCK_SIZE); + memory[i * laneLength + 0].fromBytes(blockhashBytes); + + blockhashBytes = hash(initialHashWithOnes, ARGON2_BLOCK_SIZE); + memory[i * laneLength + 1].fromBytes(blockhashBytes); + } + } + + private byte[] getInitialHashLong(byte[] initialHash, byte[] appendix) + { + byte[] initialHashLong = new byte[ARGON2_PREHASH_SEED_LENGTH]; + + System.arraycopy(initialHash, 0, initialHashLong, 0, ARGON2_PREHASH_DIGEST_LENGTH); + System.arraycopy(appendix, 0, initialHashLong, ARGON2_PREHASH_DIGEST_LENGTH, 4); + + return initialHashLong; + } + + private long intToLong(int x) + { + return (long)(x & 0xffffffffL); + } + + private static class FillBlock + { + Block R = new Block(); + Block Z = new Block(); + + Block addressBlock = new Block(); + Block zeroBlock = new Block(); + Block inputBlock = new Block(); + + private void applyBlake() + { + /* Apply Blake2 on columns of 64-bit words: (0,1,...,15) , then + (16,17,..31)... finally (112,113,...127) */ + for (int i = 0; i < 8; i++) + { + + int i16 = 16 * i; + roundFunction(Z, + i16, i16 + 1, i16 + 2, + i16 + 3, i16 + 4, i16 + 5, + i16 + 6, i16 + 7, i16 + 8, + i16 + 9, i16 + 10, i16 + 11, + i16 + 12, i16 + 13, i16 + 14, + i16 + 15 + ); + } + + /* Apply Blake2 on rows of 64-bit words: (0,1,16,17,...112,113), then + (2,3,18,19,...,114,115).. finally (14,15,30,31,...,126,127) */ + for (int i = 0; i < 8; i++) + { + + int i2 = 2 * i; + roundFunction(Z, + i2, i2 + 1, i2 + 16, + i2 + 17, i2 + 32, i2 + 33, + i2 + 48, i2 + 49, i2 + 64, + i2 + 65, i2 + 80, i2 + 81, + i2 + 96, i2 + 97, i2 + 112, + i2 + 113 + ); + } + } + + private void fillBlock(Block X, Block Y, Block currentBlock) + { + if (X == zeroBlock) + { + R.copyBlock(Y); + } + else + { + R.xor(X, Y); + } + Z.copyBlock(R); + applyBlake(); + currentBlock.xor(R, Z); + } + + private void fillBlockWithXor(Block X, Block Y, Block currentBlock) + { + R.xor(X, Y); + Z.copyBlock(R); + applyBlake(); + currentBlock.xor(R, Z, currentBlock); + } + } + + private static class Block + { + private static final int SIZE = ARGON2_QWORDS_IN_BLOCK; + + /* 128 * 8 Byte QWords */ + private final long[] v; + + private Block() + { + v = new long[SIZE]; + } + + void fromBytes(byte[] input) + { + if (input.length != ARGON2_BLOCK_SIZE) + { + throw new IllegalArgumentException("input shorter than blocksize"); + } + + for (int i = 0; i < SIZE; i++) + { + v[i] = Pack.littleEndianToLong(input, i * 8); + } + } + + byte[] toBytes() + { + byte[] result = new byte[ARGON2_BLOCK_SIZE]; + + for (int i = 0; i < SIZE; i++) + { + Pack.longToLittleEndian(v[i], result, i * 8); + } + + return result; + } + + private void copyBlock(Block other) + { + System.arraycopy(other.v, 0, v, 0, SIZE); + } + + private void xor(Block b1, Block b2) + { + for (int i = 0; i < SIZE; i++) + { + v[i] = b1.v[i] ^ b2.v[i]; + } + } + + public void xor(Block b1, Block b2, Block b3) + { + for (int i = 0; i < SIZE; i++) + { + v[i] = b1.v[i] ^ b2.v[i] ^ b3.v[i]; + } + } + + private void xorWith(Block other) + { + for (int i = 0; i < v.length; i++) + { + v[i] = v[i] ^ other.v[i]; + } + } + + public String toString() + { + StringBuffer result = new StringBuffer(); + for (int i = 0; i < SIZE; i++) + { + result.append(Hex.toHexString(Pack.longToLittleEndian(v[i]))); + } + + return result.toString(); + } + + public Block clear() + { + Arrays.fill(v, 0); + return this; + } + } + + private static class Position + { + int pass; + int lane; + int slice; + int index; + + Position() + { + + } + + void update(int pass, int lane, int slice, int index) + { + this.pass = pass; + this.lane = lane; + this.slice = slice; + this.index = index; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/CramerShoupParametersGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/CramerShoupParametersGenerator.java index 03453d870..7d2fd8633 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/CramerShoupParametersGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/CramerShoupParametersGenerator.java @@ -91,7 +91,7 @@ public class CramerShoupParametersGenerator for (; ; ) { - q = new BigInteger(qLength, 2, random); + q = BigIntegers.createRandomPrime(qLength, 2, random); p = q.shiftLeft(1).add(ONE); if (p.isProbablePrime(certainty) && (certainty <= 2 || q.isProbablePrime(certainty))) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java index aa407372b..fae5544b6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DHKeyGeneratorHelper.java @@ -27,7 +27,7 @@ class DHKeyGeneratorHelper int minWeight = limit >>> 2; for (;;) { - BigInteger x = new BigInteger(limit, random).setBit(limit - 1); + BigInteger x = BigIntegers.createRandomBigInteger(limit, random).setBit(limit - 1); if (WNafUtil.getNafWeight(x) >= minWeight) { return x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DHParametersHelper.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DHParametersHelper.java index e7bbc9b0f..0b15c3bf1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DHParametersHelper.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DHParametersHelper.java @@ -24,7 +24,7 @@ class DHParametersHelper for (;;) { - q = new BigInteger(qLength, 2, random); + q = BigIntegers.createRandomPrime(qLength, 2, random); // p <- 2q + 1 p = q.shiftLeft(1).add(ONE); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DSAParametersGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DSAParametersGenerator.java index e561b1bcd..b188f0814 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DSAParametersGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/DSAParametersGenerator.java @@ -352,7 +352,7 @@ public class DSAParametersGenerator { // A.2.3 Verifiable Canonical Generation of the Generator g BigInteger e = p.subtract(ONE).divide(q); - byte[] ggen = Hex.decode("6767656E"); + byte[] ggen = Hex.decodeStrict("6767656E"); // 7. U = domain_parameter_seed || "ggen" || index || count. byte[] U = new byte[seed.length + ggen.length + 1 + 2]; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java index dac2de4df..0acace5b5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/ECKeyPairGenerator.java @@ -16,6 +16,7 @@ import com.fr.third.org.bouncycastle.math.ec.ECMultiplier; import com.fr.third.org.bouncycastle.math.ec.ECPoint; import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; import com.fr.third.org.bouncycastle.math.ec.WNafUtil; +import com.fr.third.org.bouncycastle.util.BigIntegers; public class ECKeyPairGenerator implements AsymmetricCipherKeyPairGenerator, ECConstants @@ -50,9 +51,9 @@ public class ECKeyPairGenerator BigInteger d; for (;;) { - d = new BigInteger(nBitLength, random); + d = BigIntegers.createRandomBigInteger(nBitLength, random); - if (d.compareTo(TWO) < 0 || (d.compareTo(n) >= 0)) + if (d.compareTo(ONE) < 0 || (d.compareTo(n) >= 0)) { continue; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/Ed25519KeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/Ed25519KeyPairGenerator.java new file mode 100644 index 000000000..0d18ebcbb --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/Ed25519KeyPairGenerator.java @@ -0,0 +1,27 @@ +package com.fr.third.org.bouncycastle.crypto.generators; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; + +public class Ed25519KeyPairGenerator + implements AsymmetricCipherKeyPairGenerator +{ + private SecureRandom random; + + public void init(KeyGenerationParameters parameters) + { + this.random = parameters.getRandom(); + } + + public AsymmetricCipherKeyPair generateKeyPair() + { + Ed25519PrivateKeyParameters privateKey = new Ed25519PrivateKeyParameters(random); + Ed25519PublicKeyParameters publicKey = privateKey.generatePublicKey(); + return new AsymmetricCipherKeyPair(publicKey, privateKey); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/Ed448KeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/Ed448KeyPairGenerator.java new file mode 100644 index 000000000..625af9fdb --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/Ed448KeyPairGenerator.java @@ -0,0 +1,27 @@ +package com.fr.third.org.bouncycastle.crypto.generators; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PublicKeyParameters; + +public class Ed448KeyPairGenerator + implements AsymmetricCipherKeyPairGenerator +{ + private SecureRandom random; + + public void init(KeyGenerationParameters parameters) + { + this.random = parameters.getRandom(); + } + + public AsymmetricCipherKeyPair generateKeyPair() + { + Ed448PrivateKeyParameters privateKey = new Ed448PrivateKeyParameters(random); + Ed448PublicKeyParameters publicKey = privateKey.generatePublicKey(); + return new AsymmetricCipherKeyPair(publicKey, privateKey); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/GOST3410KeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/GOST3410KeyPairGenerator.java index 307b8d717..04660c62d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/GOST3410KeyPairGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/GOST3410KeyPairGenerator.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.generators; +import java.math.BigInteger; +import java.security.SecureRandom; + import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; @@ -8,9 +11,7 @@ import com.fr.third.org.bouncycastle.crypto.params.GOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.GOST3410PrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.GOST3410PublicKeyParameters; import com.fr.third.org.bouncycastle.math.ec.WNafUtil; - -import java.math.BigInteger; -import java.security.SecureRandom; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * a GOST3410 key pair generator. @@ -41,7 +42,7 @@ public class GOST3410KeyPairGenerator int minWeight = 64; for (;;) { - x = new BigInteger(256, random); + x = BigIntegers.createRandomBigInteger(256, random); if (x.signum() < 1 || x.compareTo(q) >= 0) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/GOST3410ParametersGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/GOST3410ParametersGenerator.java index 92ad96ee6..e27f8e2d1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/GOST3410ParametersGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/GOST3410ParametersGenerator.java @@ -5,6 +5,7 @@ import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.params.GOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.GOST3410ValidationParameters; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * generate suitable parameters for GOST3410. @@ -466,7 +467,7 @@ public class GOST3410ParametersGenerator for(;;) { - BigInteger d = new BigInteger(length, init_random); + BigInteger d = BigIntegers.createRandomBigInteger(length, init_random); // 1 < d < p-1 if (d.compareTo(ONE) > 0 && d.compareTo(pSub1) < 0) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/NaccacheSternKeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/NaccacheSternKeyPairGenerator.java index 7076090ea..b41b61770 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/NaccacheSternKeyPairGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/NaccacheSternKeyPairGenerator.java @@ -1,15 +1,16 @@ package com.fr.third.org.bouncycastle.crypto.generators; +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Vector; + import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; import com.fr.third.org.bouncycastle.crypto.params.NaccacheSternKeyGenerationParameters; import com.fr.third.org.bouncycastle.crypto.params.NaccacheSternKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.NaccacheSternPrivateKeyParameters; - -import java.math.BigInteger; -import java.security.SecureRandom; -import java.util.Vector; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * Key generation parameters for NaccacheStern cipher. For details on this cipher, please see @@ -176,7 +177,7 @@ public class NaccacheSternKeyPairGenerator for (;;) { tries++; - g = new BigInteger(strength, certainty, rand); + g = BigIntegers.createRandomPrime(strength, certainty, rand); if (g.modPow(e, n).equals(ONE)) { continue; @@ -284,10 +285,10 @@ public class NaccacheSternKeyPairGenerator int certainty, SecureRandom rand) { - BigInteger p_ = new BigInteger(bitLength, certainty, rand); + BigInteger p_ = BigIntegers.createRandomPrime(bitLength, certainty, rand); while (p_.bitLength() != bitLength) { - p_ = new BigInteger(bitLength, certainty, rand); + p_ = BigIntegers.createRandomPrime(bitLength, certainty, rand); } return p_; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java index dd9460656..fce1aec3d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/PKCS5S2ParametersGenerator.java @@ -8,7 +8,6 @@ import com.fr.third.org.bouncycastle.crypto.macs.HMac; import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; import com.fr.third.org.bouncycastle.crypto.util.DigestFactory; -import com.fr.third.org.bouncycastle.util.Arrays; /** * Generator for PBE derived keys and ivs as defined by PKCS 5 V2.0 Scheme 2. @@ -113,7 +112,7 @@ public class PKCS5S2ParametersGenerator { keySize = keySize / 8; - byte[] dKey = Arrays.copyOfRange(generateDerivedKey(keySize), 0, keySize); + byte[] dKey = generateDerivedKey(keySize); return new KeyParameter(dKey, 0, keySize); } @@ -134,7 +133,7 @@ public class PKCS5S2ParametersGenerator keySize = keySize / 8; ivSize = ivSize / 8; - byte[] dKey = generateDerivedKey(keySize + ivSize); + byte[] dKey = generateDerivedKey(keySize + ivSize); return new ParametersWithIV(new KeyParameter(dKey, 0, keySize), dKey, keySize, ivSize); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/RSABlindingFactorGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/RSABlindingFactorGenerator.java index b4d53ea14..982bc02c9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/RSABlindingFactorGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/RSABlindingFactorGenerator.java @@ -8,6 +8,7 @@ import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * Generate a random factor suitable for use with RSA blind signatures @@ -68,7 +69,7 @@ public class RSABlindingFactorGenerator do { - factor = new BigInteger(length, random); + factor = BigIntegers.createRandomBigInteger(length, random); gcd = factor.gcd(m); } while (factor.equals(ZERO) || factor.equals(ONE) || !gcd.equals(ONE)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java index ca9d45246..eef20b112 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/RSAKeyPairGenerator.java @@ -10,6 +10,7 @@ import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import com.fr.third.org.bouncycastle.math.Primes; import com.fr.third.org.bouncycastle.math.ec.WNafUtil; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * an RSA key pair generator. @@ -159,7 +160,7 @@ public class RSAKeyPairGenerator { for (int i = 0; i != 5 * bitlength; i++) { - BigInteger p = new BigInteger(bitlength, 1, param.getRandom()); + BigInteger p = BigIntegers.createRandomPrime(bitlength, 1, param.getRandom()); if (p.mod(e).equals(ONE)) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/SCrypt.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/SCrypt.java index dc07c7ec1..8b23c8dcd 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/SCrypt.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/SCrypt.java @@ -118,31 +118,37 @@ public class SCrypt int[] blockY = new int[BCount]; int[] X = new int[BCount]; - int[][] V = new int[N][]; + int[] V = new int[N * BCount]; try { System.arraycopy(B, BOff, X, 0, BCount); - for (int i = 0; i < N; ++i) + int off = 0; + for (int i = 0; i < N; i += 2) { - V[i] = Arrays.clone(X); + System.arraycopy(X, 0, V, off, BCount); + off += BCount; BlockMix(X, blockX1, blockX2, blockY, r); + System.arraycopy(blockY, 0, V, off, BCount); + off += BCount; + BlockMix(blockY, blockX1, blockX2, X, r); } int mask = N - 1; for (int i = 0; i < N; ++i) { int j = X[BCount - 16] & mask; - Xor(X, V[j], 0, X); - BlockMix(X, blockX1, blockX2, blockY, r); + System.arraycopy(V, j * BCount, blockY, 0, BCount); + Xor(blockY, X, 0, blockY); + BlockMix(blockY, blockX1, blockX2, X, r); } System.arraycopy(X, 0, B, BOff, BCount); } finally { - ClearAll(V); + Clear(V); ClearAll(new int[][]{X, blockX1, blockX2, blockY}); } } @@ -163,8 +169,6 @@ public class SCrypt YOff = halfLen + BOff - YOff; BOff += 16; } - - System.arraycopy(Y, 0, B, 0, Y.length); } private static void Xor(int[] a, int[] b, int bOff, int[] output) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/X25519KeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/X25519KeyPairGenerator.java new file mode 100644 index 000000000..b1232f518 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/X25519KeyPairGenerator.java @@ -0,0 +1,27 @@ +package com.fr.third.org.bouncycastle.crypto.generators; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.X25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X25519PublicKeyParameters; + +public class X25519KeyPairGenerator + implements AsymmetricCipherKeyPairGenerator +{ + private SecureRandom random; + + public void init(KeyGenerationParameters parameters) + { + this.random = parameters.getRandom(); + } + + public AsymmetricCipherKeyPair generateKeyPair() + { + X25519PrivateKeyParameters privateKey = new X25519PrivateKeyParameters(random); + X25519PublicKeyParameters publicKey = privateKey.generatePublicKey(); + return new AsymmetricCipherKeyPair(publicKey, privateKey); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/X448KeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/X448KeyPairGenerator.java new file mode 100644 index 000000000..c434e2687 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/generators/X448KeyPairGenerator.java @@ -0,0 +1,27 @@ +package com.fr.third.org.bouncycastle.crypto.generators; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448PublicKeyParameters; + +public class X448KeyPairGenerator + implements AsymmetricCipherKeyPairGenerator +{ + private SecureRandom random; + + public void init(KeyGenerationParameters parameters) + { + this.random = parameters.getRandom(); + } + + public AsymmetricCipherKeyPair generateKeyPair() + { + X448PrivateKeyParameters privateKey = new X448PrivateKeyParameters(random); + X448PublicKeyParameters publicKey = privateKey.generatePublicKey(); + return new AsymmetricCipherKeyPair(publicKey, privateKey); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java index f8b9fdc4b..40923aec2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/kems/ECIESKeyEncapsulation.java @@ -73,7 +73,15 @@ public class ECIESKeyEncapsulation // If both cofactorMode and oldCofactorMode are set to true // then the implementation will use the new cofactor ECDH this.CofactorMode = cofactorMode; - this.OldCofactorMode = oldCofactorMode; + // https://www.shoup.net/iso/std4.pdf, Page 34. + if (cofactorMode) + { + this.OldCofactorMode = false; + } + else + { + this.OldCofactorMode = oldCofactorMode; + } this.SingleHashMode = singleHashMode; } @@ -121,7 +129,7 @@ public class ECIESKeyEncapsulation BigInteger r = BigIntegers.createRandomInRange(ONE, n, rnd); // Compute the static-ephemeral key agreement - BigInteger rPrime = CofactorMode ? r.multiply(h).mod(n) : r; + BigInteger rPrime = OldCofactorMode ? r.multiply(h).mod(n) : r; ECMultiplier basePointMultiplier = createBasePointMultiplier(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/DSTU7564Mac.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/DSTU7564Mac.java index cee3f4feb..8f157214e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/DSTU7564Mac.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/DSTU7564Mac.java @@ -38,6 +38,9 @@ public class DSTU7564Mac public void init(CipherParameters params) throws IllegalArgumentException { + paddedKey = null; + reset(); + if (params instanceof KeyParameter) { byte[] key = ((KeyParameter)params).getKey(); @@ -111,7 +114,11 @@ public class DSTU7564Mac inputLength = 0; - return engine.doFinal(out, outOff); + int res = engine.doFinal(out, outOff); + + reset(); + + return res; } public void reset() @@ -145,13 +152,13 @@ public class DSTU7564Mac private byte[] padKey(byte[] in) { int paddedLen = ((in.length + engine.getByteLength() - 1) / engine.getByteLength()) * engine.getByteLength(); - - int extra = engine.getByteLength() - (int)(in.length % engine.getByteLength()); + + int extra = paddedLen - in.length; if (extra < 13) // terminator byte + 96 bits of length { paddedLen += engine.getByteLength(); } - + byte[] padded = new byte[paddedLen]; System.arraycopy(in, 0, padded, 0, in.length); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/DSTU7624Mac.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/DSTU7624Mac.java index 27afdf521..da18b6ea5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/DSTU7624Mac.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/DSTU7624Mac.java @@ -25,6 +25,8 @@ public class DSTU7624Mac private byte[] c, cTemp, kDelta; + private boolean initCalled = false; + public DSTU7624Mac(int blockBitLength, int q) { this.engine = new DSTU7624Engine(blockBitLength); @@ -42,7 +44,8 @@ public class DSTU7624Mac if (params instanceof KeyParameter) { engine.init(true, params); - engine.processBlock(kDelta, 0, kDelta, 0); + initCalled = true; + reset(); } else { @@ -133,6 +136,8 @@ public class DSTU7624Mac System.arraycopy(c, 0, out, outOff, macSize); + reset(); + return macSize; } @@ -143,7 +148,12 @@ public class DSTU7624Mac Arrays.fill(kDelta, (byte)0x00); Arrays.fill(buf, (byte)0x00); engine.reset(); - engine.processBlock(kDelta, 0, kDelta, 0); + + if (initCalled) + { + engine.processBlock(kDelta, 0, kDelta, 0); + } + bufOff = 0; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/GOST28147Mac.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/GOST28147Mac.java index 254e2e814..f0633f57f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/GOST28147Mac.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/GOST28147Mac.java @@ -67,6 +67,19 @@ public class GOST28147Mac reset(); buf = new byte[blockSize]; macIV = null; + + recursiveInit(params); + } + + private void recursiveInit( + CipherParameters params) + throws IllegalArgumentException + { + if (params == null) { + return; + } + + CipherParameters child = null; if (params instanceof ParametersWithSBox) { ParametersWithSBox param = (ParametersWithSBox)params; @@ -76,13 +89,7 @@ public class GOST28147Mac // System.arraycopy(param.getSBox(), 0, this.S, 0, param.getSBox().length); - // - // set key if there is one - // - if (param.getParameters() != null) - { - workingKey = generateWorkingKey(((KeyParameter)param.getParameters()).getKey()); - } + child = param.getParameters(); } else if (params instanceof KeyParameter) { @@ -92,14 +99,15 @@ public class GOST28147Mac { ParametersWithIV p = (ParametersWithIV)params; - workingKey = generateWorkingKey(((KeyParameter)p.getParameters()).getKey()); System.arraycopy(p.getIV(), 0, mac, 0, mac.length); macIV = p.getIV(); // don't skip the initial CM5Func + child = p.getParameters(); } else { - throw new IllegalArgumentException("invalid parameter passed to GOST28147 init - " + params.getClass().getName()); + throw new IllegalArgumentException("invalid parameter passed to GOST28147 init - " + params.getClass().getName()); } + recursiveInit(child); } public String getAlgorithmName() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/Zuc128Mac.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/Zuc128Mac.java new file mode 100644 index 000000000..df1698749 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/Zuc128Mac.java @@ -0,0 +1,245 @@ +package com.fr.third.org.bouncycastle.crypto.macs; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.engines.Zuc128CoreEngine; + +/** + * Zuc128 Mac implementation. + * Based on http://www.qtc.jp/3GPP/Specs/eea3eia3specificationv16.pdf + */ +public final class Zuc128Mac + implements Mac +{ + /** + * The Maximum Bit Mask. + */ + private static final int TOPBIT = 0x80; + + /** + * The Zuc128 Engine. + */ + private final InternalZuc128Engine theEngine; + + /** + * The calculated Mac in words. + */ + private int theMac; + + /** + * The active keyStream. + */ + private final int[] theKeyStream; + + /** + * The initialised state. + */ + private Zuc128CoreEngine theState; + + /** + * The current word index. + */ + private int theWordIndex; + + /** + * The current byte index. + */ + private int theByteIndex; + + /** + * Constructor. + */ + public Zuc128Mac() + { + theEngine = new InternalZuc128Engine(); + theKeyStream = new int[2]; + } + + /** + * Obtain Algorithm Name. + * + * @return the name + */ + public String getAlgorithmName() + { + return "Zuc128Mac"; + } + + /** + * Obtain Mac Size. + * + * @return the size in Bytes + */ + public int getMacSize() + { + return 4; // Integer.Bytes + } + + /** + * Initialise the Mac. + * + * @param pParams the parameters + */ + public void init(final CipherParameters pParams) + { + /* Initialise the engine */ + theEngine.init(true, pParams); + theState = (Zuc128CoreEngine)theEngine.copy(); + initKeyStream(); + } + + /** + * Initialise the keyStream. + */ + private void initKeyStream() + { + /* Initialise the Mac */ + theMac = 0; + + /* Initialise the KeyStream */ + for (int i = 0; i < theKeyStream.length - 1; i++) + { + theKeyStream[i] = theEngine.createKeyStreamWord(); + } + theWordIndex = theKeyStream.length - 1; + theByteIndex = 3; //Integer.BYTES - 1; + } + + /** + * Update the mac with a single byte. + * + * @param in the byte to update with + */ + public void update(final byte in) + { + /* shift for next byte */ + shift4NextByte(); + + /* Loop through the bits */ + final int bitBase = theByteIndex * 8; //Byte.SIZE; + for (int bitMask = TOPBIT, bitNo = 0; bitMask > 0; bitMask >>= 1, bitNo++) + { + /* If the bit is set */ + if ((in & bitMask) != 0) + { + /* update theMac */ + updateMac(bitBase + bitNo); + } + } + } + + /** + * Shift for next byte. + */ + private void shift4NextByte() + { + /* Adjust the byte index */ + theByteIndex = (theByteIndex + 1) % 4; //Integer.BYTES; + + /* Adjust keyStream if required */ + if (theByteIndex == 0) + { + theKeyStream[theWordIndex] = theEngine.createKeyStreamWord(); + theWordIndex = (theWordIndex + 1) % theKeyStream.length; + } + } + + /** + * Update the Mac. + * + * @param bitNo the bit number + */ + private void updateMac(final int bitNo) + { + /* Update the Mac */ + theMac ^= getKeyStreamWord(bitNo); + } + + /** + * Obtain the keyStreamWord. + * + * @param bitNo the bitNumber + * @return the word + */ + private int getKeyStreamWord(final int bitNo) + { + /* Access the first word and return it if this is bit 0 */ + final int myFirst = theKeyStream[theWordIndex]; + if (bitNo == 0) + { + return myFirst; + } + + /* Access the second word */ + final int mySecond = theKeyStream[(theWordIndex + 1) % theKeyStream.length]; + return (myFirst << bitNo) | (mySecond >>> (32 - bitNo)); // Integer.SIZE - bitNo + } + + /** + * Update the mac. + * + * @param in the input buffer + * @param inOff the starting offset in the input buffer + * @param len the length of data to process + */ + public void update(final byte[] in, final int inOff, final int len) + { + for (int byteNo = 0; byteNo < len; byteNo++) + { + update(in[inOff + byteNo]); + } + } + + /** + * Obtain the final word. + * + * @return the final word + */ + private int getFinalWord() + { + if (theByteIndex != 0) + { + return theEngine.createKeyStreamWord(); + } + theWordIndex = (theWordIndex + 1) % theKeyStream.length; + return theKeyStream[theWordIndex]; + } + + /** + * Finalize the mac. + * + * @param out the output buffer + * @param outOff the starting offset in the input buffer + * @return the size of the mac + */ + public int doFinal(final byte[] out, final int outOff) + { + /* Finish the Mac and output it */ + shift4NextByte(); + theMac ^= getKeyStreamWord(theByteIndex * 8); //Byte.SIZE + theMac ^= getFinalWord(); + Zuc128CoreEngine.encode32be(theMac, out, outOff); + + /* Reset the Mac */ + reset(); + return getMacSize(); + } + + public void reset() + { + if (theState != null) + { + theEngine.reset(theState); + } + initKeyStream(); + } + + private static class InternalZuc128Engine + extends Zuc128CoreEngine + { + int createKeyStreamWord() + { + return super.makeKeyStreamWord(); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/Zuc256Mac.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/Zuc256Mac.java new file mode 100644 index 000000000..114c8433d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/macs/Zuc256Mac.java @@ -0,0 +1,274 @@ +package com.fr.third.org.bouncycastle.crypto.macs; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.engines.Zuc256CoreEngine; + +/** + * Zuc256 Mac implementation. + * Based on http://www.is.cas.cn/ztzl2016/zouchongzhi/201801/W020180126529970733243.pdf + */ +public final class Zuc256Mac + implements Mac +{ + /** + * The Maximum Bit Mask. + */ + private static final int TOPBIT = 0x80; + + /** + * The Zuc256 Engine. + */ + private final InternalZuc256Engine theEngine; + + /** + * The mac length. + */ + private final int theMacLength; + + /** + * The calculated Mac in words. + */ + private final int[] theMac; + + /** + * The active keyStream. + */ + private final int[] theKeyStream; + + /** + * The initialised state. + */ + private Zuc256CoreEngine theState; + + /** + * The current word index. + */ + private int theWordIndex; + + /** + * The current byte index. + */ + private int theByteIndex; + + /** + * Constructor. + * + * @param pLength the bit length of the Mac + */ + public Zuc256Mac(final int pLength) + { + theEngine = new InternalZuc256Engine(pLength); + theMacLength = pLength; + final int numWords = pLength / 32; // Integer.SIZE + theMac = new int[numWords]; + theKeyStream = new int[numWords + 1]; + } + + /** + * Obtain Algorithm Name. + * + * @return the name + */ + public String getAlgorithmName() + { + return "Zuc256Mac-" + theMacLength; + } + + /** + * Obtain Mac Size. + * + * @return the size in Bytes + */ + public int getMacSize() + { + return theMacLength / 8; //Byte.SIZE + } + + /** + * Initialise the Mac. + * + * @param pParams the parameters + */ + public void init(final CipherParameters pParams) + { + /* Initialise the engine */ + theEngine.init(true, pParams); + theState = (Zuc256CoreEngine)theEngine.copy(); + initKeyStream(); + } + + /** + * Initialise the keyStream. + */ + private void initKeyStream() + { + /* Initialise the Mac */ + for (int i = 0; i < theMac.length; i++) + { + theMac[i] = theEngine.createKeyStreamWord(); + } + + /* Initialise the KeyStream */ + for (int i = 0; i < theKeyStream.length - 1; i++) + { + theKeyStream[i] = theEngine.createKeyStreamWord(); + } + theWordIndex = theKeyStream.length - 1; + theByteIndex = 4 - 1; // Integer.SIZE + } + + /** + * Update the mac with a single byte. + * + * @param in the byte to update with + */ + public void update(final byte in) + { + /* shift for next byte */ + shift4NextByte(); + + /* Loop through the bits */ + final int bitBase = theByteIndex * 8; //Byte.SIZE; + for (int bitMask = TOPBIT, bitNo = 0; bitMask > 0; bitMask >>= 1, bitNo++) + { + /* If the bit is set */ + if ((in & bitMask) != 0) + { + /* update theMac */ + updateMac(bitBase + bitNo); + } + } + } + + /** + * Shift for next byte. + */ + private void shift4NextByte() + { + /* Adjust the byte index */ + theByteIndex = (theByteIndex + 1) % 4; //Integer.BYTES + + /* Adjust keyStream if required */ + if (theByteIndex == 0) + { + theKeyStream[theWordIndex] = theEngine.createKeyStreamWord(); + theWordIndex = (theWordIndex + 1) % theKeyStream.length; + } + } + + /** + * Shift for final update. + */ + private void shift4Final() + { + /* Adjust the byte index */ + theByteIndex = (theByteIndex + 1) % 4; //Integer.BYTES + + /* No need to read another word to the keyStream */ + if (theByteIndex == 0) + { + theWordIndex = (theWordIndex + 1) % theKeyStream.length; + } + } + + /** + * Update the Mac. + * + * @param bitNo the bit number + */ + private void updateMac(final int bitNo) + { + /* Loop through the Mac */ + for (int wordNo = 0; wordNo < theMac.length; wordNo++) + { + theMac[wordNo] ^= getKeyStreamWord(wordNo, bitNo); + } + } + + /** + * Obtain the keyStreamWord. + * + * @param wordNo the wordNumber + * @param bitNo the bitNumber + * @return the word + */ + private int getKeyStreamWord(final int wordNo, final int bitNo) + { + /* Access the first word and return it if this is bit 0 */ + final int myFirst = theKeyStream[(theWordIndex + wordNo) % theKeyStream.length]; + if (bitNo == 0) + { + return myFirst; + } + + /* Access the second word */ + final int mySecond = theKeyStream[(theWordIndex + wordNo + 1) % theKeyStream.length]; + return (myFirst << bitNo) | (mySecond >>> (32 - bitNo)); //Integer.SIZE - bitNo + } + + /** + * Update the mac. + * + * @param in the input buffer + * @param inOff the starting offset in the input buffer + * @param len the length of data to process + */ + public void update(final byte[] in, final int inOff, final int len) + { + for (int byteNo = 0; byteNo < len; byteNo++) + { + update(in[inOff + byteNo]); + } + } + + /** + * Finalize the mac. + * + * @param out the output buffer + * @param outOff the starting offset in the output buffer + * @return the size of the mac + */ + public int doFinal(final byte[] out, final int outOff) + { + /* shift for final update */ + shift4Final(); + + /* Finish the Mac and output it */ + updateMac(theByteIndex * 8); //Byte.SIZE) + for (int i = 0; i < theMac.length; i++) + { + Zuc256CoreEngine.encode32be(theMac[i], out, outOff + i * 4); //Integer.BYTES) + } + + /* Reset the Mac */ + reset(); + return getMacSize(); + } + + /** + * Reset the Mac. + */ + public void reset() + { + if (theState != null) + { + theEngine.reset(theState); + } + initKeyStream(); + } + + private static class InternalZuc256Engine + extends Zuc256CoreEngine + { + public InternalZuc256Engine(int pLength) + { + super(pLength); + } + + int createKeyStreamWord() + { + return super.makeKeyStreamWord(); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/AEADBlockCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/AEADBlockCipher.java index a2b78c1f9..cb3172e77 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/AEADBlockCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/AEADBlockCipher.java @@ -1,146 +1,17 @@ package com.fr.third.org.bouncycastle.crypto.modes; import com.fr.third.org.bouncycastle.crypto.BlockCipher; -import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.crypto.DataLengthException; -import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; /** - * A block cipher mode that includes authenticated encryption with a streaming mode and optional associated data. - *

- * Implementations of this interface may operate in a packet mode (where all input data is buffered and - * processed dugin the call to {@link #doFinal(byte[], int)}), or in a streaming mode (where output data is - * incrementally produced with each call to {@link #processByte(byte, byte[], int)} or - * {@link #processBytes(byte[], int, int, byte[], int)}. - *

- * This is important to consider during decryption: in a streaming mode, unauthenticated plaintext data - * may be output prior to the call to {@link #doFinal(byte[], int)} that results in an authentication - * failure. The higher level protocol utilising this cipher must ensure the plaintext data is handled - * appropriately until the end of data is reached and the entire ciphertext is authenticated. - * @see com.fr.third.org.bouncycastle.crypto.params.AEADParameters + * An {@link AEADCipher} based on a {@link BlockCipher}. */ public interface AEADBlockCipher + extends AEADCipher { /** - * initialise the underlying cipher. Parameter can either be an AEADParameters or a ParametersWithIV object. + * return the {@link BlockCipher} this object wraps. * - * @param forEncryption true if we are setting up for encryption, false otherwise. - * @param params the necessary parameters for the underlying cipher to be initialised. - * @exception IllegalArgumentException if the params argument is inappropriate. - */ - public void init(boolean forEncryption, CipherParameters params) - throws IllegalArgumentException; - - /** - * Return the name of the algorithm. - * - * @return the algorithm name. - */ - public String getAlgorithmName(); - - /** - * return the cipher this object wraps. - * - * @return the cipher this object wraps. + * @return the {@link BlockCipher} this object wraps. */ public BlockCipher getUnderlyingCipher(); - - /** - * Add a single byte to the associated data check. - *
If the implementation supports it, this will be an online operation and will not retain the associated data. - * - * @param in the byte to be processed. - */ - public void processAADByte(byte in); - - /** - * Add a sequence of bytes to the associated data check. - *
If the implementation supports it, this will be an online operation and will not retain the associated data. - * - * @param in the input byte array. - * @param inOff the offset into the in array where the data to be processed starts. - * @param len the number of bytes to be processed. - */ - public void processAADBytes(byte[] in, int inOff, int len); - - /** - * encrypt/decrypt a single byte. - * - * @param in the byte to be processed. - * @param out the output buffer the processed byte goes into. - * @param outOff the offset into the output byte array the processed data starts at. - * @return the number of bytes written to out. - * @exception DataLengthException if the output buffer is too small. - */ - public int processByte(byte in, byte[] out, int outOff) - throws DataLengthException; - - /** - * process a block of bytes from in putting the result into out. - * - * @param in the input byte array. - * @param inOff the offset into the in array where the data to be processed starts. - * @param len the number of bytes to be processed. - * @param out the output buffer the processed bytes go into. - * @param outOff the offset into the output byte array the processed data starts at. - * @return the number of bytes written to out. - * @exception DataLengthException if the output buffer is too small. - */ - public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) - throws DataLengthException; - - /** - * Finish the operation either appending or verifying the MAC at the end of the data. - * - * @param out space for any resulting output data. - * @param outOff offset into out to start copying the data at. - * @return number of bytes written into out. - * @throws IllegalStateException if the cipher is in an inappropriate state. - * @throws com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException if the MAC fails to match. - */ - public int doFinal(byte[] out, int outOff) - throws IllegalStateException, InvalidCipherTextException; - - /** - * Return the value of the MAC associated with the last stream processed. - * - * @return MAC for plaintext data. - */ - public byte[] getMac(); - - /** - * return the size of the output buffer required for a processBytes - * an input of len bytes. - *

- * The returned size may be dependent on the initialisation of this cipher - * and may not be accurate once subsequent input data is processed - this method - * should be invoked immediately prior to input data being processed. - *

- * - * @param len the length of the input. - * @return the space required to accommodate a call to processBytes - * with len bytes of input. - */ - public int getUpdateOutputSize(int len); - - /** - * return the size of the output buffer required for a processBytes plus a - * doFinal with an input of len bytes. - *

- * The returned size may be dependent on the initialisation of this cipher - * and may not be accurate once subsequent input data is processed - this method - * should be invoked immediately prior to a call to final processing of input data - * and a call to {@link #doFinal(byte[], int)}. - *

- * @param len the length of the input. - * @return the space required to accommodate a call to processBytes and doFinal - * with len bytes of input. - */ - public int getOutputSize(int len); - - /** - * Reset the cipher. After resetting the cipher is in the same state - * as it was after the last init (if there was one). - */ - public void reset(); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/AEADCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/AEADCipher.java new file mode 100644 index 000000000..aca677426 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/AEADCipher.java @@ -0,0 +1,138 @@ +package com.fr.third.org.bouncycastle.crypto.modes; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; + +/** + * A cipher mode that includes authenticated encryption with a streaming mode and optional associated data. + *

+ * Implementations of this interface may operate in a packet mode (where all input data is buffered and + * processed during the call to {@link #doFinal(byte[], int)}), or in a streaming mode (where output data is + * incrementally produced with each call to {@link #processByte(byte, byte[], int)} or + * {@link #processBytes(byte[], int, int, byte[], int)}. + *

+ * This is important to consider during decryption: in a streaming mode, unauthenticated plaintext data + * may be output prior to the call to {@link #doFinal(byte[], int)} that results in an authentication + * failure. The higher level protocol utilising this cipher must ensure the plaintext data is handled + * appropriately until the end of data is reached and the entire ciphertext is authenticated. + * @see com.fr.third.org.bouncycastle.crypto.params.AEADParameters + */ +public interface AEADCipher +{ + /** + * initialise the underlying cipher. Parameter can either be an AEADParameters or a ParametersWithIV object. + * + * @param forEncryption true if we are setting up for encryption, false otherwise. + * @param params the necessary parameters for the underlying cipher to be initialised. + * @exception IllegalArgumentException if the params argument is inappropriate. + */ + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException; + + /** + * Return the name of the algorithm. + * + * @return the algorithm name. + */ + public String getAlgorithmName(); + + /** + * Add a single byte to the associated data check. + *
If the implementation supports it, this will be an online operation and will not retain the associated data. + * + * @param in the byte to be processed. + */ + public void processAADByte(byte in); + + /** + * Add a sequence of bytes to the associated data check. + *
If the implementation supports it, this will be an online operation and will not retain the associated data. + * + * @param in the input byte array. + * @param inOff the offset into the in array where the data to be processed starts. + * @param len the number of bytes to be processed. + */ + public void processAADBytes(byte[] in, int inOff, int len); + + /** + * encrypt/decrypt a single byte. + * + * @param in the byte to be processed. + * @param out the output buffer the processed byte goes into. + * @param outOff the offset into the output byte array the processed data starts at. + * @return the number of bytes written to out. + * @exception DataLengthException if the output buffer is too small. + */ + public int processByte(byte in, byte[] out, int outOff) + throws DataLengthException; + + /** + * process a block of bytes from in putting the result into out. + * + * @param in the input byte array. + * @param inOff the offset into the in array where the data to be processed starts. + * @param len the number of bytes to be processed. + * @param out the output buffer the processed bytes go into. + * @param outOff the offset into the output byte array the processed data starts at. + * @return the number of bytes written to out. + * @exception DataLengthException if the output buffer is too small. + */ + public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) + throws DataLengthException; + + /** + * Finish the operation either appending or verifying the MAC at the end of the data. + * + * @param out space for any resulting output data. + * @param outOff offset into out to start copying the data at. + * @return number of bytes written into out. + * @throws IllegalStateException if the cipher is in an inappropriate state. + * @throws com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException if the MAC fails to match. + */ + public int doFinal(byte[] out, int outOff) + throws IllegalStateException, InvalidCipherTextException; + + /** + * Return the value of the MAC associated with the last stream processed. + * + * @return MAC for plaintext data. + */ + public byte[] getMac(); + + /** + * return the size of the output buffer required for a processBytes + * an input of len bytes. + *

+ * The returned size may be dependent on the initialisation of this cipher + * and may not be accurate once subsequent input data is processed - this method + * should be invoked immediately prior to input data being processed. + *

+ * + * @param len the length of the input. + * @return the space required to accommodate a call to processBytes + * with len bytes of input. + */ + public int getUpdateOutputSize(int len); + + /** + * return the size of the output buffer required for a processBytes plus a + * doFinal with an input of len bytes. + *

+ * The returned size may be dependent on the initialisation of this cipher + * and may not be accurate once subsequent input data is processed - this method + * should be invoked immediately prior to a call to final processing of input data + * and a call to {@link #doFinal(byte[], int)}. + *

+ * @param len the length of the input. + * @return the space required to accommodate a call to processBytes and doFinal + * with len bytes of input. + */ + public int getOutputSize(int len); + + /** + * Reset the cipher. After resetting the cipher is in the same state + * as it was after the last init (if there was one). + */ + public void reset(); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/CCMBlockCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/CCMBlockCipher.java index d2c3fc0c9..3c9d0bfc9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/CCMBlockCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/CCMBlockCipher.java @@ -73,7 +73,7 @@ public class CCMBlockCipher nonce = param.getNonce(); initialAssociatedText = param.getAssociatedText(); - macSize = param.getMacSize() / 8; + macSize = getMacSize(forEncryption, param.getMacSize()); cipherParameters = param.getKey(); } else if (params instanceof ParametersWithIV) @@ -82,7 +82,7 @@ public class CCMBlockCipher nonce = param.getIV(); initialAssociatedText = null; - macSize = macBlock.length / 2; + macSize = getMacSize(forEncryption, 64); cipherParameters = param.getParameters(); } else @@ -434,6 +434,16 @@ public class CCMBlockCipher return cMac.doFinal(macBlock, 0); } + private int getMacSize(boolean forEncryption, int requestedMacBits) + { + if (forEncryption && (requestedMacBits < 32 || requestedMacBits > 128 || 0 != (requestedMacBits & 15))) + { + throw new IllegalArgumentException("tag length in octets must be one of {4,6,8,10,12,14,16}"); + } + + return requestedMacBits >>> 3; + } + private int getAssociatedTextLength() { return associatedText.size() + ((initialAssociatedText == null) ? 0 : initialAssociatedText.length); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/ChaCha20Poly1305.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/ChaCha20Poly1305.java new file mode 100644 index 000000000..c6a0b51e7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/ChaCha20Poly1305.java @@ -0,0 +1,608 @@ +package com.fr.third.org.bouncycastle.crypto.modes; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.OutputLengthException; +import com.fr.third.org.bouncycastle.crypto.engines.ChaCha7539Engine; +import com.fr.third.org.bouncycastle.crypto.macs.Poly1305; +import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Pack; + +public class ChaCha20Poly1305 + implements AEADCipher +{ + private static final class State + { + static final int UNINITIALIZED = 0; + static final int ENC_INIT = 1; + static final int ENC_AAD = 2; + static final int ENC_DATA = 3; + static final int ENC_FINAL = 4; + static final int DEC_INIT = 5; + static final int DEC_AAD = 6; + static final int DEC_DATA = 7; + static final int DEC_FINAL = 8; + } + + private static final int BUF_SIZE = 64; + private static final int KEY_SIZE = 32; + private static final int NONCE_SIZE = 12; + private static final int MAC_SIZE = 16; + private static final byte[] ZEROES = new byte[MAC_SIZE - 1]; + + private static final long AAD_LIMIT = Long.MAX_VALUE - Long.MIN_VALUE; + private static final long DATA_LIMIT = ((1L << 32) - 1) * 64; + + private final ChaCha7539Engine chacha20; + private final Mac poly1305; + + private final byte[] key = new byte[KEY_SIZE]; + private final byte[] nonce = new byte[NONCE_SIZE]; + private final byte[] buf = new byte[BUF_SIZE + MAC_SIZE]; + private final byte[] mac = new byte[MAC_SIZE]; + + private byte[] initialAAD; + + private long aadCount; + private long dataCount; + private int state = State.UNINITIALIZED; + private int bufPos; + + public ChaCha20Poly1305() + { + this(new Poly1305()); + } + + public ChaCha20Poly1305(Mac poly1305) + { + if (null == poly1305) + { + throw new NullPointerException("'poly1305' cannot be null"); + } + if (MAC_SIZE != poly1305.getMacSize()) + { + throw new IllegalArgumentException("'poly1305' must be a 128-bit MAC"); + } + + this.chacha20 = new ChaCha7539Engine(); + this.poly1305 = poly1305; + } + + public String getAlgorithmName() + { + return "ChaCha20Poly1305"; + } + + public void init(boolean forEncryption, CipherParameters params) throws IllegalArgumentException + { + KeyParameter initKeyParam; + byte[] initNonce; + CipherParameters chacha20Params; + + if (params instanceof AEADParameters) + { + AEADParameters aeadParams = (AEADParameters)params; + + int macSizeBits = aeadParams.getMacSize(); + if ((MAC_SIZE * 8) != macSizeBits) + { + throw new IllegalArgumentException("Invalid value for MAC size: " + macSizeBits); + } + + initKeyParam = aeadParams.getKey(); + initNonce = aeadParams.getNonce(); + chacha20Params = new ParametersWithIV(initKeyParam, initNonce); + + this.initialAAD = aeadParams.getAssociatedText(); + } + else if (params instanceof ParametersWithIV) + { + ParametersWithIV ivParams = (ParametersWithIV)params; + + initKeyParam = (KeyParameter)ivParams.getParameters(); + initNonce = ivParams.getIV(); + chacha20Params = ivParams; + + this.initialAAD = null; + } + else + { + throw new IllegalArgumentException("invalid parameters passed to ChaCha20Poly1305"); + } + + // Validate key + if (null == initKeyParam) + { + if (State.UNINITIALIZED == state) + { + throw new IllegalArgumentException("Key must be specified in initial init"); + } + } + else + { + if (KEY_SIZE != initKeyParam.getKey().length) + { + throw new IllegalArgumentException("Key must be 256 bits"); + } + } + + // Validate nonce + if (null == initNonce || NONCE_SIZE != initNonce.length) + { + throw new IllegalArgumentException("Nonce must be 96 bits"); + } + + // Check for encryption with reused nonce + if (State.UNINITIALIZED != state && forEncryption && Arrays.areEqual(nonce, initNonce)) + { + if (null == initKeyParam || Arrays.areEqual(key, initKeyParam.getKey())) + { + throw new IllegalArgumentException("cannot reuse nonce for ChaCha20Poly1305 encryption"); + } + } + + if (null != initKeyParam) + { + System.arraycopy(initKeyParam.getKey(), 0, key, 0, KEY_SIZE); + } + + System.arraycopy(initNonce, 0, nonce, 0, NONCE_SIZE); + + chacha20.init(true, chacha20Params); + + this.state = forEncryption ? State.ENC_INIT : State.DEC_INIT; + + reset(true, false); + } + + public int getOutputSize(int len) + { + int total = Math.max(0, len) + bufPos; + + switch (state) + { + case State.DEC_INIT: + case State.DEC_AAD: + case State.DEC_DATA: + return Math.max(0, total - MAC_SIZE); + case State.ENC_INIT: + case State.ENC_AAD: + case State.ENC_DATA: + return total + MAC_SIZE; + default: + throw new IllegalStateException("state="+state); + } + } + + public int getUpdateOutputSize(int len) + { + int total = Math.max(0, len) + bufPos; + + switch (state) + { + case State.DEC_INIT: + case State.DEC_AAD: + case State.DEC_DATA: + total = Math.max(0, total - MAC_SIZE); + break; + case State.ENC_INIT: + case State.ENC_AAD: + case State.ENC_DATA: + break; + default: + throw new IllegalStateException(); + } + + return total - (total % BUF_SIZE); + } + + public void processAADByte(byte in) + { + checkAAD(); + + this.aadCount = incrementCount(aadCount, 1, AAD_LIMIT); + poly1305.update(in); + } + + public void processAADBytes(byte[] in, int inOff, int len) + { + if (null == in) + { + throw new NullPointerException("'in' cannot be null"); + } + if (inOff < 0) + { + throw new IllegalArgumentException("'inOff' cannot be negative"); + } + if (len < 0) + { + throw new IllegalArgumentException("'len' cannot be negative"); + } + if (inOff > (in.length - len)) + { + throw new DataLengthException("Input buffer too short"); + } + + checkAAD(); + + if (len > 0) + { + this.aadCount = incrementCount(aadCount, len, AAD_LIMIT); + poly1305.update(in, inOff, len); + } + } + + public int processByte(byte in, byte[] out, int outOff) throws DataLengthException + { + checkData(); + + switch (state) + { + case State.DEC_DATA: + { + buf[bufPos] = in; + if (++bufPos == buf.length) + { + poly1305.update(buf, 0, BUF_SIZE); + processData(buf, 0, BUF_SIZE, out, outOff); + System.arraycopy(buf, BUF_SIZE, buf, 0, MAC_SIZE); + this.bufPos = MAC_SIZE; + return BUF_SIZE; + } + + return 0; + } + case State.ENC_DATA: + { + buf[bufPos] = in; + if (++bufPos == BUF_SIZE) + { + processData(buf, 0, BUF_SIZE, out, outOff); + poly1305.update(out, outOff, BUF_SIZE); + this.bufPos = 0; + return BUF_SIZE; + } + + return 0; + } + default: + throw new IllegalStateException(); + } + } + + public int processBytes(byte[] in, int inOff, int len, byte[] out, int outOff) throws DataLengthException + { + if (null == in) + { + throw new NullPointerException("'in' cannot be null"); + } + if (null == out) + { + throw new NullPointerException("'out' cannot be null"); + } + if (inOff < 0) + { + throw new IllegalArgumentException("'inOff' cannot be negative"); + } + if (len < 0) + { + throw new IllegalArgumentException("'len' cannot be negative"); + } + if (inOff > (in.length - len)) + { + throw new DataLengthException("Input buffer too short"); + } + if (outOff < 0) + { + throw new IllegalArgumentException("'outOff' cannot be negative"); + } + + checkData(); + + int resultLen = 0; + + switch (state) + { + case State.DEC_DATA: + { + for (int i = 0; i < len; ++i) + { + buf[bufPos] = in[inOff + i]; + if (++bufPos == buf.length) + { + poly1305.update(buf, 0, BUF_SIZE); + processData(buf, 0, BUF_SIZE, out, outOff + resultLen); + System.arraycopy(buf, BUF_SIZE, buf, 0, MAC_SIZE); + this.bufPos = MAC_SIZE; + resultLen += BUF_SIZE; + } + } + break; + } + case State.ENC_DATA: + { + if (bufPos != 0) + { + while (len > 0) + { + --len; + buf[bufPos] = in[inOff++]; + if (++bufPos == BUF_SIZE) + { + processData(buf, 0, BUF_SIZE, out, outOff); + poly1305.update(out, outOff, BUF_SIZE); + this.bufPos = 0; + resultLen = BUF_SIZE; + break; + } + } + } + + while (len >= BUF_SIZE) + { + processData(in, inOff, BUF_SIZE, out, outOff + resultLen); + poly1305.update(out, outOff + resultLen, BUF_SIZE); + inOff += BUF_SIZE; + len -= BUF_SIZE; + resultLen += BUF_SIZE; + } + + if (len > 0) + { + System.arraycopy(in, inOff, buf, 0, len); + this.bufPos = len; + } + break; + } + default: + throw new IllegalStateException(); + } + + return resultLen; + } + + public int doFinal(byte[] out, int outOff) throws IllegalStateException, InvalidCipherTextException + { + if (null == out) + { + throw new NullPointerException("'out' cannot be null"); + } + if (outOff < 0) + { + throw new IllegalArgumentException("'outOff' cannot be negative"); + } + + checkData(); + + Arrays.clear(mac); + + int resultLen = 0; + + switch (state) + { + case State.DEC_DATA: + { + if (bufPos < MAC_SIZE) + { + throw new InvalidCipherTextException("data too short"); + } + + resultLen = bufPos - MAC_SIZE; + + if (outOff > (out.length - resultLen)) + { + throw new OutputLengthException("Output buffer too short"); + } + + if (resultLen > 0) + { + poly1305.update(buf, 0, resultLen); + processData(buf, 0, resultLen, out, outOff); + } + + finishData(State.DEC_FINAL); + + if (!Arrays.constantTimeAreEqual(MAC_SIZE, mac, 0, buf, resultLen)) + { + throw new InvalidCipherTextException("mac check in ChaCha20Poly1305 failed"); + } + + break; + } + case State.ENC_DATA: + { + resultLen = bufPos + MAC_SIZE; + + if (outOff > (out.length - resultLen)) + { + throw new OutputLengthException("Output buffer too short"); + } + + if (bufPos > 0) + { + processData(buf, 0, bufPos, out, outOff); + poly1305.update(out, outOff, bufPos); + } + + finishData(State.ENC_FINAL); + + System.arraycopy(mac, 0, out, outOff + bufPos, MAC_SIZE); + break; + } + default: + throw new IllegalStateException(); + } + + reset(false, true); + + return resultLen; + } + + public byte[] getMac() + { + return Arrays.clone(mac); + } + + public void reset() + { + reset(true, true); + } + + private void checkAAD() + { + switch (state) + { + case State.DEC_INIT: + this.state = State.DEC_AAD; + break; + case State.ENC_INIT: + this.state = State.ENC_AAD; + break; + case State.DEC_AAD: + case State.ENC_AAD: + break; + case State.ENC_FINAL: + throw new IllegalStateException("ChaCha20Poly1305 cannot be reused for encryption"); + default: + throw new IllegalStateException(); + } + } + + private void checkData() + { + switch (state) + { + case State.DEC_INIT: + case State.DEC_AAD: + finishAAD(State.DEC_DATA); + break; + case State.ENC_INIT: + case State.ENC_AAD: + finishAAD(State.ENC_DATA); + break; + case State.DEC_DATA: + case State.ENC_DATA: + break; + case State.ENC_FINAL: + throw new IllegalStateException("ChaCha20Poly1305 cannot be reused for encryption"); + default: + throw new IllegalStateException(); + } + } + + private void finishAAD(int nextState) + { + padMAC(aadCount); + + this.state = nextState; + } + + private void finishData(int nextState) + { + padMAC(dataCount); + + byte[] lengths = new byte[16]; + Pack.longToLittleEndian(aadCount, lengths, 0); + Pack.longToLittleEndian(dataCount, lengths, 8); + poly1305.update(lengths, 0, 16); + + poly1305.doFinal(mac, 0); + + this.state = nextState; + } + + private long incrementCount(long count, int increment, long limit) + { + if (count + Long.MIN_VALUE > (limit - increment) + Long.MIN_VALUE) + { + throw new IllegalStateException("Limit exceeded"); + } + + return count + increment; + } + + private void initMAC() + { + byte[] firstBlock = new byte[64]; + try + { + chacha20.processBytes(firstBlock, 0, 64, firstBlock, 0); + poly1305.init(new KeyParameter(firstBlock, 0, 32)); + } + finally + { + Arrays.clear(firstBlock); + } + } + + private void padMAC(long count) + { + int partial = (int)count % MAC_SIZE; + if (0 != partial) + { + poly1305.update(ZEROES, 0, MAC_SIZE - partial); + } + } + + private void processData(byte[] in, int inOff, int inLen, byte[] out, int outOff) + { + if (outOff > (out.length - inLen)) + { + throw new OutputLengthException("Output buffer too short"); + } + + chacha20.processBytes(in, inOff, inLen, out, outOff); + + this.dataCount = incrementCount(dataCount, inLen, DATA_LIMIT); + } + + private void reset(boolean clearMac, boolean resetCipher) + { + Arrays.clear(buf); + + if (clearMac) + { + Arrays.clear(mac); + } + + this.aadCount = 0L; + this.dataCount = 0L; + this.bufPos = 0; + + switch (state) + { + case State.DEC_INIT: + case State.ENC_INIT: + break; + case State.DEC_AAD: + case State.DEC_DATA: + case State.DEC_FINAL: + this.state = State.DEC_INIT; + break; + case State.ENC_AAD: + case State.ENC_DATA: + case State.ENC_FINAL: + this.state = State.ENC_FINAL; + return; + default: + throw new IllegalStateException(); + } + + if (resetCipher) + { + chacha20.reset(); + } + + initMAC(); + + if (null != initialAAD) + { + processAADBytes(initialAAD, 0, initialAAD.length); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/PaddedBlockCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/PaddedBlockCipher.java index 591217e29..bdd6abc29 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/PaddedBlockCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/modes/PaddedBlockCipher.java @@ -237,7 +237,7 @@ public class PaddedBlockCipher // int count = buf[blockSize - 1] & 0xff; - if ((count < 0) || (count > blockSize)) + if (count > blockSize) { throw new InvalidCipherTextException("pad block corrupted"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/AEADParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/AEADParameters.java index 1ab08c5ff..5d3ee9bbe 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/AEADParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/AEADParameters.java @@ -1,6 +1,7 @@ package com.fr.third.org.bouncycastle.crypto.params; import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.util.Arrays; public class AEADParameters implements CipherParameters @@ -33,9 +34,9 @@ public class AEADParameters public AEADParameters(KeyParameter key, int macSize, byte[] nonce, byte[] associatedText) { this.key = key; - this.nonce = nonce; + this.nonce = Arrays.clone(nonce); this.macSize = macSize; - this.associatedText = associatedText; + this.associatedText = Arrays.clone(associatedText); } public KeyParameter getKey() @@ -50,11 +51,11 @@ public class AEADParameters public byte[] getAssociatedText() { - return associatedText; + return Arrays.clone(associatedText); } public byte[] getNonce() { - return nonce; + return Arrays.clone(nonce); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Argon2Parameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Argon2Parameters.java new file mode 100644 index 000000000..b5b1e4ca1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Argon2Parameters.java @@ -0,0 +1,206 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import com.fr.third.org.bouncycastle.crypto.CharToByteConverter; +import com.fr.third.org.bouncycastle.crypto.PasswordConverter; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class Argon2Parameters +{ + public static final int ARGON2_d = 0x00; + public static final int ARGON2_i = 0x01; + public static final int ARGON2_id = 0x02; + + public static final int ARGON2_VERSION_10 = 0x10; + public static final int ARGON2_VERSION_13 = 0x13; + + private static final int DEFAULT_ITERATIONS = 3; + private static final int DEFAULT_MEMORY_COST = 12; + private static final int DEFAULT_LANES = 1; + private static final int DEFAULT_TYPE = ARGON2_i; + private static final int DEFAULT_VERSION = ARGON2_VERSION_13; + + public static class Builder + { + private byte[] salt; + private byte[] secret; + private byte[] additional; + + private int iterations; + private int memory; + private int lanes; + + private int version; + private final int type; + + private CharToByteConverter converter = PasswordConverter.UTF8; + + public Builder() + { + this(DEFAULT_TYPE); + } + + public Builder(int type) + { + this.type = type; + this.lanes = DEFAULT_LANES; + this.memory = 1 << DEFAULT_MEMORY_COST; + this.iterations = DEFAULT_ITERATIONS; + this.version = DEFAULT_VERSION; + } + + public Builder withParallelism(int parallelism) + { + this.lanes = parallelism; + return this; + } + + public Builder withSalt(byte[] salt) + { + this.salt = Arrays.clone(salt); + return this; + } + + public Builder withSecret(byte[] secret) + { + this.secret = Arrays.clone(secret); + return this; + } + + public Builder withAdditional(byte[] additional) + { + this.additional = Arrays.clone(additional); + return this; + } + + public Builder withIterations(int iterations) + { + this.iterations = iterations; + return this; + } + + + public Builder withMemoryAsKB(int memory) + { + this.memory = memory; + return this; + } + + + public Builder withMemoryPowOfTwo(int memory) + { + this.memory = 1 << memory; + return this; + } + + public Builder withVersion(int version) + { + this.version = version; + return this; + } + + public Builder withCharToByteConverter(CharToByteConverter converter) + { + this.converter = converter; + return this; + } + + public Argon2Parameters build() + { + return new Argon2Parameters(type, salt, secret, additional, iterations, memory, lanes, version, converter); + } + + public void clear() + { + Arrays.clear(salt); + Arrays.clear(secret); + Arrays.clear(additional); + } + } + + private final byte[] salt; + private final byte[] secret; + private final byte[] additional; + + private final int iterations; + private final int memory; + private final int lanes; + + private final int version; + private final int type; + private final CharToByteConverter converter; + + private Argon2Parameters( + int type, + byte[] salt, + byte[] secret, + byte[] additional, + int iterations, + int memory, + int lanes, + int version, + CharToByteConverter converter) + { + + this.salt = Arrays.clone(salt); + this.secret = Arrays.clone(secret); + this.additional = Arrays.clone(additional); + this.iterations = iterations; + this.memory = memory; + this.lanes = lanes; + this.version = version; + this.type = type; + this.converter = converter; + } + + public byte[] getSalt() + { + return Arrays.clone(salt); + } + + public byte[] getSecret() + { + return Arrays.clone(secret); + } + + public byte[] getAdditional() + { + return Arrays.clone(additional); + } + + public int getIterations() + { + return iterations; + } + + public int getMemory() + { + return memory; + } + + public int getLanes() + { + return lanes; + } + + public int getVersion() + { + return version; + } + + public int getType() + { + return type; + } + + public CharToByteConverter getCharToByteConverter() + { + return converter; + } + + public void clear() + { + Arrays.clear(salt); + Arrays.clear(secret); + Arrays.clear(additional); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/CramerShoupParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/CramerShoupParameters.java index b1b11a62a..7ea4c6c98 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/CramerShoupParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/CramerShoupParameters.java @@ -4,50 +4,61 @@ import java.math.BigInteger; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.util.Memoable; + +public class CramerShoupParameters + implements CipherParameters +{ + + private BigInteger p; // prime order of G + private BigInteger g1, g2; // generate G + + private Digest H; // hash function + + public CramerShoupParameters(BigInteger p, BigInteger g1, BigInteger g2, Digest H) + { + this.p = p; + this.g1 = g1; + this.g2 = g2; + this.H = (Digest)((Memoable)H).copy(); + this.H.reset(); + } + + public boolean equals(Object obj) + { + if (!(obj instanceof CramerShoupParameters)) + { + return false; + } + + CramerShoupParameters pm = (CramerShoupParameters)obj; + + return (pm.getP().equals(p) && pm.getG1().equals(g1) && pm.getG2().equals(g2)); + } + + public int hashCode() + { + return getP().hashCode() ^ getG1().hashCode() ^ getG2().hashCode(); + } + + public BigInteger getG1() + { + return g1; + } + + public BigInteger getG2() + { + return g2; + } + + public BigInteger getP() + { + return p; + } + + public Digest getH() + { + return (Digest)((Memoable)H).copy(); + } -public class CramerShoupParameters implements CipherParameters { - - private BigInteger p; // prime order of G - private BigInteger g1, g2; // generate G - - private Digest H; // hash function - - public CramerShoupParameters(BigInteger p, BigInteger g1, BigInteger g2, Digest H) { - this.p = p; - this.g1 = g1; - this.g2 = g2; - this.H = H; - } - - public boolean equals(Object obj) { - if (!(obj instanceof DSAParameters)) { - return false; - } - - CramerShoupParameters pm = (CramerShoupParameters) obj; - - return (pm.getP().equals(p) && pm.getG1().equals(g1) && pm.getG2().equals(g2)); - } - - public int hashCode() { - return getP().hashCode() ^ getG1().hashCode() ^ getG2().hashCode(); - } - - public BigInteger getG1() { - return g1; - } - - public BigInteger getG2() { - return g2; - } - - public BigInteger getP() { - return p; - } - - public Digest getH() { - H.reset(); - return H; - } - } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DHParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DHParameters.java index d5bf77742..4bb8892c5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DHParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DHParameters.java @@ -3,6 +3,7 @@ package com.fr.third.org.bouncycastle.crypto.params; import java.math.BigInteger; import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.util.Properties; public class DHParameters implements CipherParameters @@ -94,7 +95,7 @@ public class DHParameters } } - if (m > p.bitLength()) + if (m > p.bitLength() && !Properties.isOverrideSet("com.fr.third.org.bouncycastle.dh.allow_unsafe_p_value")) { throw new IllegalArgumentException("unsafe p value so small specific l required"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DHValidationParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DHValidationParameters.java index 1490be267..af226a8be 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DHValidationParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DHValidationParameters.java @@ -11,7 +11,7 @@ public class DHValidationParameters byte[] seed, int counter) { - this.seed = seed; + this.seed = Arrays.clone(seed); this.counter = counter; } @@ -22,7 +22,7 @@ public class DHValidationParameters public byte[] getSeed() { - return seed; + return Arrays.clone(seed); } public boolean equals( diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DSAValidationParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DSAValidationParameters.java index 7aa312de1..f9721a296 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DSAValidationParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DSAValidationParameters.java @@ -20,7 +20,7 @@ public class DSAValidationParameters int counter, int usageIndex) { - this.seed = seed; + this.seed = Arrays.clone(seed); this.counter = counter; this.usageIndex = usageIndex; } @@ -32,7 +32,7 @@ public class DSAValidationParameters public byte[] getSeed() { - return seed; + return Arrays.clone(seed); } public int getUsageIndex() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DSTU4145Parameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DSTU4145Parameters.java new file mode 100644 index 000000000..80feb64a0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/DSTU4145Parameters.java @@ -0,0 +1,21 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import com.fr.third.org.bouncycastle.util.Arrays; + +public class DSTU4145Parameters + extends ECDomainParameters +{ + private final byte[] dke; + + public DSTU4145Parameters(ECDomainParameters ecParameters, byte[] dke) + { + super(ecParameters.getCurve(), ecParameters.getG(), ecParameters.getN(), ecParameters.getH(), ecParameters.getSeed()); + + this.dke = Arrays.clone(dke); + } + + public byte[] getDKE() + { + return Arrays.clone(dke); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECDHUPrivateParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECDHUPrivateParameters.java index 2be81a343..f40357ad5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECDHUPrivateParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECDHUPrivateParameters.java @@ -1,6 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.params; import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; /** * Parameters holder for private unified static/ephemeral agreement as described in NIST SP 800-56A. @@ -41,9 +43,9 @@ public class ECDHUPrivateParameters if (ephemeralPublicKey == null) { - ephemeralPublicKey = new ECPublicKeyParameters( - parameters.getG().multiply(ephemeralPrivateKey.getD()), - parameters); + ECPoint q = new FixedPointCombMultiplier().multiply(parameters.getG(), ephemeralPrivateKey.getD()); + + ephemeralPublicKey = new ECPublicKeyParameters(q, parameters); } else if (!parameters.equals(ephemeralPublicKey.getParameters())) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECDomainParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECDomainParameters.java index b1b143871..73d396086 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECDomainParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECDomainParameters.java @@ -11,11 +11,12 @@ import com.fr.third.org.bouncycastle.util.Arrays; public class ECDomainParameters implements ECConstants { - private ECCurve curve; - private byte[] seed; - private ECPoint G; - private BigInteger n; - private BigInteger h; + private final ECCurve curve; + private final byte[] seed; + private final ECPoint G; + private final BigInteger n; + private final BigInteger h; + private BigInteger hInv = null; public ECDomainParameters( @@ -53,10 +54,10 @@ public class ECDomainParameters // we can't check for h == null here as h is optional in X9.62 as it is not required for ECDSA this.curve = curve; - this.G = validate(curve, G); + this.G = validatePublicPoint(curve, G); this.n = n; this.h = h; - this.seed = seed; + this.seed = Arrays.clone(seed); } public ECCurve getCurve() @@ -101,47 +102,70 @@ public class ECDomainParameters return true; } - if ((obj instanceof ECDomainParameters)) + if (!(obj instanceof ECDomainParameters)) { - ECDomainParameters other = (ECDomainParameters)obj; - - return this.curve.equals(other.curve) && this.G.equals(other.G) && this.n.equals(other.n) && this.h.equals(other.h); + return false; } - return false; + ECDomainParameters other = (ECDomainParameters)obj; + + return this.curve.equals(other.curve) + && this.G.equals(other.G) + && this.n.equals(other.n); } public int hashCode() { - int hc = curve.hashCode(); - hc *= 37; +// return Arrays.hashCode(new Object[]{ curve, G, n }); + int hc = 4; + hc *= 257; + hc ^= curve.hashCode(); + hc *= 257; hc ^= G.hashCode(); - hc *= 37; + hc *= 257; hc ^= n.hashCode(); - hc *= 37; - hc ^= h.hashCode(); return hc; } - static ECPoint validate(ECCurve c, ECPoint q) + public BigInteger validatePrivateScalar(BigInteger d) { - if (q == null) + if (null == d) { - throw new IllegalArgumentException("point has null value"); + throw new NullPointerException("Scalar cannot be null"); } - if (q.isInfinity()) + if (d.compareTo(ECConstants.ONE) < 0 || (d.compareTo(getN()) >= 0)) { - throw new IllegalArgumentException("point at infinity"); + throw new IllegalArgumentException("Scalar is not in the interval [1, n - 1]"); } - q = q.normalize(); + return d; + } + + public ECPoint validatePublicPoint(ECPoint q) + { + return validatePublicPoint(getCurve(), q); + } + + static ECPoint validatePublicPoint(ECCurve c, ECPoint q) + { + if (null == q) + { + throw new NullPointerException("Point cannot be null"); + } + + q = ECAlgorithms.importPoint(c, q).normalize(); + + if (q.isInfinity()) + { + throw new IllegalArgumentException("Point at infinity"); + } if (!q.isValid()) { - throw new IllegalArgumentException("point not on curve"); + throw new IllegalArgumentException("Point not on curve"); } - return ECAlgorithms.importPoint(c, q); + return q; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECGOST3410Parameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECGOST3410Parameters.java new file mode 100644 index 000000000..515326705 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECGOST3410Parameters.java @@ -0,0 +1,47 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; + +public class ECGOST3410Parameters + extends ECNamedDomainParameters +{ + private final ASN1ObjectIdentifier publicKeyParamSet; + private final ASN1ObjectIdentifier digestParamSet; + private final ASN1ObjectIdentifier encryptionParamSet; + + public ECGOST3410Parameters(ECDomainParameters ecParameters, ASN1ObjectIdentifier publicKeyParamSet, ASN1ObjectIdentifier digestParamSet) + { + this(ecParameters, publicKeyParamSet, digestParamSet, null); + } + + public ECGOST3410Parameters(ECDomainParameters ecParameters, ASN1ObjectIdentifier publicKeyParamSet, ASN1ObjectIdentifier digestParamSet, ASN1ObjectIdentifier encryptionParamSet) + { + super(publicKeyParamSet, ecParameters.getCurve(), ecParameters.getG(), ecParameters.getN(), ecParameters.getH(), ecParameters.getSeed()); + + if (ecParameters instanceof ECNamedDomainParameters) + { + if (!publicKeyParamSet.equals(((ECNamedDomainParameters)ecParameters).getName())) + { + throw new IllegalArgumentException("named parameters do not match publicKeyParamSet value"); + } + } + this.publicKeyParamSet = publicKeyParamSet; + this.digestParamSet = digestParamSet; + this.encryptionParamSet = encryptionParamSet; + } + + public ASN1ObjectIdentifier getPublicKeyParamSet() + { + return publicKeyParamSet; + } + + public ASN1ObjectIdentifier getDigestParamSet() + { + return digestParamSet; + } + + public ASN1ObjectIdentifier getEncryptionParamSet() + { + return encryptionParamSet; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECKeyParameters.java index 96ac055ff..1fed14cf2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECKeyParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECKeyParameters.java @@ -3,19 +3,24 @@ package com.fr.third.org.bouncycastle.crypto.params; public class ECKeyParameters extends AsymmetricKeyParameter { - ECDomainParameters params; + private final ECDomainParameters parameters; protected ECKeyParameters( boolean isPrivate, - ECDomainParameters params) + ECDomainParameters parameters) { super(isPrivate); - this.params = params; + if (null == parameters) + { + throw new NullPointerException("'parameters' cannot be null"); + } + + this.parameters = parameters; } public ECDomainParameters getParameters() { - return params; + return parameters; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECNamedDomainParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECNamedDomainParameters.java index c6527720f..07c659553 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECNamedDomainParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECNamedDomainParameters.java @@ -29,6 +29,12 @@ public class ECNamedDomainParameters this.name = name; } + public ECNamedDomainParameters(ASN1ObjectIdentifier name, ECDomainParameters domainParameters) + { + super(domainParameters.getCurve(), domainParameters.getG(), domainParameters.getN(), domainParameters.getH(), domainParameters.getSeed()); + this.name = name; + } + public ASN1ObjectIdentifier getName() { return name; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java index 3964deec5..2eb8af3bf 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECPrivateKeyParameters.java @@ -5,14 +5,15 @@ import java.math.BigInteger; public class ECPrivateKeyParameters extends ECKeyParameters { - BigInteger d; + private final BigInteger d; public ECPrivateKeyParameters( BigInteger d, - ECDomainParameters params) + ECDomainParameters parameters) { - super(true, params); - this.d = d; + super(true, parameters); + + this.d = parameters.validatePrivateScalar(d); } public BigInteger getD() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECPublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECPublicKeyParameters.java index 09849c9fb..f42b12615 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECPublicKeyParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/ECPublicKeyParameters.java @@ -5,19 +5,19 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint; public class ECPublicKeyParameters extends ECKeyParameters { - private final ECPoint Q; + private final ECPoint q; public ECPublicKeyParameters( - ECPoint Q, - ECDomainParameters params) + ECPoint q, + ECDomainParameters parameters) { - super(false, params); + super(false, parameters); - this.Q = ECDomainParameters.validate(params.getCurve(), Q); + this.q = parameters.validatePublicPoint(q); } public ECPoint getQ() { - return Q; + return q; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed25519KeyGenerationParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed25519KeyGenerationParameters.java new file mode 100644 index 000000000..d4cd31a3a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed25519KeyGenerationParameters.java @@ -0,0 +1,14 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; + +public class Ed25519KeyGenerationParameters + extends KeyGenerationParameters +{ + public Ed25519KeyGenerationParameters(SecureRandom random) + { + super(random, 256); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed25519PrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed25519PrivateKeyParameters.java new file mode 100644 index 000000000..92c12b5f2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed25519PrivateKeyParameters.java @@ -0,0 +1,106 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed25519; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.io.Streams; + +public final class Ed25519PrivateKeyParameters + extends AsymmetricKeyParameter +{ + public static final int KEY_SIZE = Ed25519.SECRET_KEY_SIZE; + public static final int SIGNATURE_SIZE = Ed25519.SIGNATURE_SIZE; + + private final byte[] data = new byte[KEY_SIZE]; + + public Ed25519PrivateKeyParameters(SecureRandom random) + { + super(true); + + Ed25519.generatePrivateKey(random, data); + } + + public Ed25519PrivateKeyParameters(byte[] buf, int off) + { + super(true); + + System.arraycopy(buf, off, data, 0, KEY_SIZE); + } + + public Ed25519PrivateKeyParameters(InputStream input) throws IOException + { + super(true); + + if (KEY_SIZE != Streams.readFully(input, data)) + { + throw new EOFException("EOF encountered in middle of Ed25519 private key"); + } + } + + public void encode(byte[] buf, int off) + { + System.arraycopy(data, 0, buf, off, KEY_SIZE); + } + + public byte[] getEncoded() + { + return Arrays.clone(data); + } + + public Ed25519PublicKeyParameters generatePublicKey() + { + byte[] publicKey = new byte[Ed25519.PUBLIC_KEY_SIZE]; + Ed25519.generatePublicKey(data, 0, publicKey, 0); + return new Ed25519PublicKeyParameters(publicKey, 0); + } + + public void sign(int algorithm, Ed25519PublicKeyParameters publicKey, byte[] ctx, byte[] msg, int msgOff, int msgLen, byte[] sig, int sigOff) + { + byte[] pk = new byte[Ed25519.PUBLIC_KEY_SIZE]; + if (null == publicKey) + { + Ed25519.generatePublicKey(data, 0, pk, 0); + } + else + { + publicKey.encode(pk, 0); + } + + switch (algorithm) + { + case Ed25519.Algorithm.Ed25519: + { + if (null != ctx) + { + throw new IllegalArgumentException("ctx"); + } + + Ed25519.sign(data, 0, pk, 0, msg, msgOff, msgLen, sig, sigOff); + break; + } + case Ed25519.Algorithm.Ed25519ctx: + { + Ed25519.sign(data, 0, pk, 0, ctx, msg, msgOff, msgLen, sig, sigOff); + break; + } + case Ed25519.Algorithm.Ed25519ph: + { + if (Ed25519.PREHASH_SIZE != msgLen) + { + throw new IllegalArgumentException("msgLen"); + } + + Ed25519.signPrehash(data, 0, pk, 0, ctx, msg, msgOff, sig, sigOff); + break; + } + default: + { + throw new IllegalArgumentException("algorithm"); + } + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed25519PublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed25519PublicKeyParameters.java new file mode 100644 index 000000000..718fdbccc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed25519PublicKeyParameters.java @@ -0,0 +1,44 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed25519; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.io.Streams; + +public final class Ed25519PublicKeyParameters + extends AsymmetricKeyParameter +{ + public static final int KEY_SIZE = Ed25519.PUBLIC_KEY_SIZE; + + private final byte[] data = new byte[KEY_SIZE]; + + public Ed25519PublicKeyParameters(byte[] buf, int off) + { + super(false); + + System.arraycopy(buf, off, data, 0, KEY_SIZE); + } + + public Ed25519PublicKeyParameters(InputStream input) throws IOException + { + super(false); + + if (KEY_SIZE != Streams.readFully(input, data)) + { + throw new EOFException("EOF encountered in middle of Ed25519 public key"); + } + } + + public void encode(byte[] buf, int off) + { + System.arraycopy(data, 0, buf, off, KEY_SIZE); + } + + public byte[] getEncoded() + { + return Arrays.clone(data); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed448KeyGenerationParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed448KeyGenerationParameters.java new file mode 100644 index 000000000..b010e27dc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed448KeyGenerationParameters.java @@ -0,0 +1,14 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; + +public class Ed448KeyGenerationParameters + extends KeyGenerationParameters +{ + public Ed448KeyGenerationParameters(SecureRandom random) + { + super(random, 448); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed448PrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed448PrivateKeyParameters.java new file mode 100644 index 000000000..16cf444e9 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed448PrivateKeyParameters.java @@ -0,0 +1,96 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed448; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.io.Streams; + +public final class Ed448PrivateKeyParameters + extends AsymmetricKeyParameter +{ + public static final int KEY_SIZE = Ed448.SECRET_KEY_SIZE; + public static final int SIGNATURE_SIZE = Ed448.SIGNATURE_SIZE; + + private final byte[] data = new byte[KEY_SIZE]; + + public Ed448PrivateKeyParameters(SecureRandom random) + { + super(true); + + Ed448.generatePrivateKey(random, data); + } + + public Ed448PrivateKeyParameters(byte[] buf, int off) + { + super(true); + + System.arraycopy(buf, off, data, 0, KEY_SIZE); + } + + public Ed448PrivateKeyParameters(InputStream input) throws IOException + { + super(true); + + if (KEY_SIZE != Streams.readFully(input, data)) + { + throw new EOFException("EOF encountered in middle of Ed448 private key"); + } + } + + public void encode(byte[] buf, int off) + { + System.arraycopy(data, 0, buf, off, KEY_SIZE); + } + + public byte[] getEncoded() + { + return Arrays.clone(data); + } + + public Ed448PublicKeyParameters generatePublicKey() + { + byte[] publicKey = new byte[Ed448.PUBLIC_KEY_SIZE]; + Ed448.generatePublicKey(data, 0, publicKey, 0); + return new Ed448PublicKeyParameters(publicKey, 0); + } + + public void sign(int algorithm, Ed448PublicKeyParameters publicKey, byte[] ctx, byte[] msg, int msgOff, int msgLen, byte[] sig, int sigOff) + { + byte[] pk = new byte[Ed448.PUBLIC_KEY_SIZE]; + if (null == publicKey) + { + Ed448.generatePublicKey(data, 0, pk, 0); + } + else + { + publicKey.encode(pk, 0); + } + + switch (algorithm) + { + case Ed448.Algorithm.Ed448: + { + Ed448.sign(data, 0, pk, 0, ctx, msg, msgOff, msgLen, sig, sigOff); + break; + } + case Ed448.Algorithm.Ed448ph: + { + if (Ed448.PREHASH_SIZE != msgLen) + { + throw new IllegalArgumentException("msgLen"); + } + + Ed448.signPrehash(data, 0, pk, 0, ctx, msg, msgOff, sig, sigOff); + break; + } + default: + { + throw new IllegalArgumentException("algorithm"); + } + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed448PublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed448PublicKeyParameters.java new file mode 100644 index 000000000..53e728a3c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/Ed448PublicKeyParameters.java @@ -0,0 +1,44 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed448; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.io.Streams; + +public final class Ed448PublicKeyParameters + extends AsymmetricKeyParameter +{ + public static final int KEY_SIZE = Ed448.PUBLIC_KEY_SIZE; + + private final byte[] data = new byte[KEY_SIZE]; + + public Ed448PublicKeyParameters(byte[] buf, int off) + { + super(false); + + System.arraycopy(buf, off, data, 0, KEY_SIZE); + } + + public Ed448PublicKeyParameters(InputStream input) throws IOException + { + super(false); + + if (KEY_SIZE != Streams.readFully(input, data)) + { + throw new EOFException("EOF encountered in middle of Ed448 public key"); + } + } + + public void encode(byte[] buf, int off) + { + System.arraycopy(data, 0, buf, off, KEY_SIZE); + } + + public byte[] getEncoded() + { + return Arrays.clone(data); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/IESParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/IESParameters.java index 6de054df0..b48b4b4ca 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/IESParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/IESParameters.java @@ -1,6 +1,7 @@ package com.fr.third.org.bouncycastle.crypto.params; import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.util.Arrays; /** * parameters for using an integrated cipher in stream mode. @@ -22,19 +23,19 @@ public class IESParameters byte[] encoding, int macKeySize) { - this.derivation = derivation; - this.encoding = encoding; + this.derivation = Arrays.clone(derivation); + this.encoding = Arrays.clone(encoding); this.macKeySize = macKeySize; } public byte[] getDerivationV() { - return derivation; + return Arrays.clone(derivation); } public byte[] getEncodingV() { - return encoding; + return Arrays.clone(encoding); } public int getMacKeySize() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/MQVPrivateParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/MQVPrivateParameters.java index 7829f08a3..8dfc15ad5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/MQVPrivateParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/MQVPrivateParameters.java @@ -1,6 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.params; import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; public class MQVPrivateParameters implements CipherParameters @@ -38,9 +40,9 @@ public class MQVPrivateParameters if (ephemeralPublicKey == null) { - ephemeralPublicKey = new ECPublicKeyParameters( - parameters.getG().multiply(ephemeralPrivateKey.getD()), - parameters); + ECPoint q = new FixedPointCombMultiplier().multiply(parameters.getG(), ephemeralPrivateKey.getD()); + + ephemeralPublicKey = new ECPublicKeyParameters(q, parameters); } else if (!parameters.equals(ephemeralPublicKey.getParameters())) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/RSAKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/RSAKeyParameters.java index 3c5531f3d..b794fc227 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/RSAKeyParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/RSAKeyParameters.java @@ -2,9 +2,19 @@ package com.fr.third.org.bouncycastle.crypto.params; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.util.Properties; + public class RSAKeyParameters extends AsymmetricKeyParameter { + // Hexadecimal value of the product of the 131 smallest odd primes from 3 to 743 + private static final BigInteger SMALL_PRIMES_PRODUCT = new BigInteger( + "8138e8a0fcf3a4e84a771d40fd305d7f4aa59306d7251de54d98af8fe95729a1f" + + "73d893fa424cd2edc8636a6c3285e022b0e3866a565ae8108eed8591cd4fe8d2" + + "ce86165a978d719ebf647f362d33fca29cd179fb42401cbaf3df0c614056f9c8" + + "f3cfd51e474afb6bc6974f78db8aba8e9e517fded658591ab7502bd41849462f", + 16); + private static final BigInteger ONE = BigInteger.valueOf(1); private BigInteger modulus; @@ -36,12 +46,14 @@ public class RSAKeyParameters throw new IllegalArgumentException("RSA modulus is even"); } - // the value is the product of the 132 smallest primes from 3 to 751 - if (!modulus.gcd(new BigInteger("145188775577763990151158743208307020242261438098488931355057091965" + - "931517706595657435907891265414916764399268423699130577757433083166" + - "651158914570105971074227669275788291575622090199821297575654322355" + - "049043101306108213104080801056529374892690144291505781966373045481" + - "8359472391642885328171302299245556663073719855")).equals(ONE)) + // If you need to set this you need to have a serious word to whoever is generating + // your keys. + if (Properties.isOverrideSet("com.fr.third.org.bouncycastle.rsa.allow_unsafe_mod")) + { + return modulus; + } + + if (!modulus.gcd(SMALL_PRIMES_PRODUCT).equals(ONE)) { throw new IllegalArgumentException("RSA modulus has a small prime factor"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/SM2KeyExchangePrivateParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/SM2KeyExchangePrivateParameters.java index 87190534f..59b47ca25 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/SM2KeyExchangePrivateParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/SM2KeyExchangePrivateParameters.java @@ -1,7 +1,9 @@ package com.fr.third.org.bouncycastle.crypto.params; import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.math.ec.ECMultiplier; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; /** * Private parameters for an SM2 key exchange. The ephemeralPrivateKey is used to calculate the random point used in the algorithm. @@ -35,11 +37,13 @@ public class SM2KeyExchangePrivateParameters throw new IllegalArgumentException("Static and ephemeral private keys have different domain parameters"); } + ECMultiplier m = new FixedPointCombMultiplier(); + this.initiator = initiator; this.staticPrivateKey = staticPrivateKey; - this.staticPublicPoint = parameters.getG().multiply(staticPrivateKey.getD()).normalize(); + this.staticPublicPoint = m.multiply(parameters.getG(), staticPrivateKey.getD()).normalize(); this.ephemeralPrivateKey = ephemeralPrivateKey; - this.ephemeralPublicPoint = parameters.getG().multiply(ephemeralPrivateKey.getD()).normalize(); + this.ephemeralPublicPoint = m.multiply(parameters.getG(), ephemeralPrivateKey.getD()).normalize(); } public boolean isInitiator() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/SkeinParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/SkeinParameters.java index 68857b07d..26372c529 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/SkeinParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/SkeinParameters.java @@ -196,7 +196,7 @@ public class SkeinParameters throw new IllegalArgumentException("Parameter value must not be null."); } if ((type != PARAM_TYPE_KEY) - && (type <= PARAM_TYPE_CONFIG || type >= PARAM_TYPE_OUTPUT || type == PARAM_TYPE_MESSAGE)) + && (type < PARAM_TYPE_CONFIG || type >= PARAM_TYPE_OUTPUT || type == PARAM_TYPE_MESSAGE)) { throw new IllegalArgumentException("Parameter types must be in the range 0,5..47,49..62."); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X25519KeyGenerationParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X25519KeyGenerationParameters.java new file mode 100644 index 000000000..3d49c5cb1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X25519KeyGenerationParameters.java @@ -0,0 +1,14 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; + +public class X25519KeyGenerationParameters + extends KeyGenerationParameters +{ + public X25519KeyGenerationParameters(SecureRandom random) + { + super(random, 255); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X25519PrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X25519PrivateKeyParameters.java new file mode 100644 index 000000000..6886e3ac1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X25519PrivateKeyParameters.java @@ -0,0 +1,70 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.math.ec.rfc7748.X25519; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.io.Streams; + +public final class X25519PrivateKeyParameters + extends AsymmetricKeyParameter +{ + public static final int KEY_SIZE = X25519.SCALAR_SIZE; + public static final int SECRET_SIZE = X25519.POINT_SIZE; + + private final byte[] data = new byte[KEY_SIZE]; + + public X25519PrivateKeyParameters(SecureRandom random) + { + super(true); + + X25519.generatePrivateKey(random, data); + } + + public X25519PrivateKeyParameters(byte[] buf, int off) + { + super(true); + + System.arraycopy(buf, off, data, 0, KEY_SIZE); + } + + public X25519PrivateKeyParameters(InputStream input) throws IOException + { + super(true); + + if (KEY_SIZE != Streams.readFully(input, data)) + { + throw new EOFException("EOF encountered in middle of X25519 private key"); + } + } + + public void encode(byte[] buf, int off) + { + System.arraycopy(data, 0, buf, off, KEY_SIZE); + } + + public byte[] getEncoded() + { + return Arrays.clone(data); + } + + public X25519PublicKeyParameters generatePublicKey() + { + byte[] publicKey = new byte[X25519.POINT_SIZE]; + X25519.generatePublicKey(data, 0, publicKey, 0); + return new X25519PublicKeyParameters(publicKey, 0); + } + + public void generateSecret(X25519PublicKeyParameters publicKey, byte[] buf, int off) + { + byte[] encoded = new byte[X25519.POINT_SIZE]; + publicKey.encode(encoded, 0); + if (!X25519.calculateAgreement(data, 0, encoded, 0, buf, off)) + { + throw new IllegalStateException("X25519 agreement failed"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X25519PublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X25519PublicKeyParameters.java new file mode 100644 index 000000000..2a0fa18e0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X25519PublicKeyParameters.java @@ -0,0 +1,44 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import com.fr.third.org.bouncycastle.math.ec.rfc7748.X25519; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.io.Streams; + +public final class X25519PublicKeyParameters + extends AsymmetricKeyParameter +{ + public static final int KEY_SIZE = X25519.POINT_SIZE; + + private final byte[] data = new byte[KEY_SIZE]; + + public X25519PublicKeyParameters(byte[] buf, int off) + { + super(false); + + System.arraycopy(buf, off, data, 0, KEY_SIZE); + } + + public X25519PublicKeyParameters(InputStream input) throws IOException + { + super(false); + + if (KEY_SIZE != Streams.readFully(input, data)) + { + throw new EOFException("EOF encountered in middle of X25519 public key"); + } + } + + public void encode(byte[] buf, int off) + { + System.arraycopy(data, 0, buf, off, KEY_SIZE); + } + + public byte[] getEncoded() + { + return Arrays.clone(data); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X448KeyGenerationParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X448KeyGenerationParameters.java new file mode 100644 index 000000000..84859bcc8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X448KeyGenerationParameters.java @@ -0,0 +1,14 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; + +public class X448KeyGenerationParameters + extends KeyGenerationParameters +{ + public X448KeyGenerationParameters(SecureRandom random) + { + super(random, 448); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X448PrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X448PrivateKeyParameters.java new file mode 100644 index 000000000..9376dc33e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X448PrivateKeyParameters.java @@ -0,0 +1,70 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.math.ec.rfc7748.X448; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.io.Streams; + +public final class X448PrivateKeyParameters + extends AsymmetricKeyParameter +{ + public static final int KEY_SIZE = X448.SCALAR_SIZE; + public static final int SECRET_SIZE = X448.POINT_SIZE; + + private final byte[] data = new byte[KEY_SIZE]; + + public X448PrivateKeyParameters(SecureRandom random) + { + super(true); + + X448.generatePrivateKey(random, data); + } + + public X448PrivateKeyParameters(byte[] buf, int off) + { + super(true); + + System.arraycopy(buf, off, data, 0, KEY_SIZE); + } + + public X448PrivateKeyParameters(InputStream input) throws IOException + { + super(true); + + if (KEY_SIZE != Streams.readFully(input, data)) + { + throw new EOFException("EOF encountered in middle of X448 private key"); + } + } + + public void encode(byte[] buf, int off) + { + System.arraycopy(data, 0, buf, off, KEY_SIZE); + } + + public byte[] getEncoded() + { + return Arrays.clone(data); + } + + public X448PublicKeyParameters generatePublicKey() + { + byte[] publicKey = new byte[X448.POINT_SIZE]; + X448.generatePublicKey(data, 0, publicKey, 0); + return new X448PublicKeyParameters(publicKey, 0); + } + + public void generateSecret(X448PublicKeyParameters publicKey, byte[] buf, int off) + { + byte[] encoded = new byte[X448.POINT_SIZE]; + publicKey.encode(encoded, 0); + if (!X448.calculateAgreement(data, 0, encoded, 0, buf, off)) + { + throw new IllegalStateException("X448 agreement failed"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X448PublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X448PublicKeyParameters.java new file mode 100644 index 000000000..45124d693 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/X448PublicKeyParameters.java @@ -0,0 +1,44 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +import com.fr.third.org.bouncycastle.math.ec.rfc7748.X448; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.io.Streams; + +public final class X448PublicKeyParameters + extends AsymmetricKeyParameter +{ + public static final int KEY_SIZE = X448.POINT_SIZE; + + private final byte[] data = new byte[KEY_SIZE]; + + public X448PublicKeyParameters(byte[] buf, int off) + { + super(false); + + System.arraycopy(buf, off, data, 0, KEY_SIZE); + } + + public X448PublicKeyParameters(InputStream input) throws IOException + { + super(false); + + if (KEY_SIZE != Streams.readFully(input, data)) + { + throw new EOFException("EOF encountered in middle of X448 public key"); + } + } + + public void encode(byte[] buf, int off) + { + System.arraycopy(data, 0, buf, off, KEY_SIZE); + } + + public byte[] getEncoded() + { + return Arrays.clone(data); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/XDHUPrivateParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/XDHUPrivateParameters.java new file mode 100644 index 000000000..dfd7d05bd --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/XDHUPrivateParameters.java @@ -0,0 +1,87 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; + +/** + * Parameters holder for private unified static/ephemeral agreement using Edwards Curves. + */ +public class XDHUPrivateParameters + implements CipherParameters +{ + private AsymmetricKeyParameter staticPrivateKey; + private AsymmetricKeyParameter ephemeralPrivateKey; + private AsymmetricKeyParameter ephemeralPublicKey; + + public XDHUPrivateParameters( + AsymmetricKeyParameter staticPrivateKey, + AsymmetricKeyParameter ephemeralPrivateKey) + { + this(staticPrivateKey, ephemeralPrivateKey, null); + } + + public XDHUPrivateParameters( + AsymmetricKeyParameter staticPrivateKey, + AsymmetricKeyParameter ephemeralPrivateKey, + AsymmetricKeyParameter ephemeralPublicKey) + { + if (staticPrivateKey == null) + { + throw new NullPointerException("staticPrivateKey cannot be null"); + } + if (!(staticPrivateKey instanceof X448PrivateKeyParameters || staticPrivateKey instanceof X25519PrivateKeyParameters)) + { + throw new IllegalArgumentException("only X25519 and X448 paramaters can be used"); + } + if (ephemeralPrivateKey == null) + { + throw new NullPointerException("ephemeralPrivateKey cannot be null"); + } + + if (!staticPrivateKey.getClass().isAssignableFrom(ephemeralPrivateKey.getClass())) + { + throw new IllegalArgumentException("static and ephemeral private keys have different domain parameters"); + } + + if (ephemeralPublicKey == null) + { + if (ephemeralPrivateKey instanceof X448PrivateKeyParameters) + { + ephemeralPublicKey = ((X448PrivateKeyParameters)ephemeralPrivateKey).generatePublicKey(); + } + else + { + ephemeralPublicKey = ((X25519PrivateKeyParameters)ephemeralPrivateKey).generatePublicKey(); + } + } + else + { + if (ephemeralPublicKey instanceof X448PublicKeyParameters && !(staticPrivateKey instanceof X448PrivateKeyParameters)) + { + throw new IllegalArgumentException("ephemeral public key has different domain parameters"); + } + if (ephemeralPublicKey instanceof X25519PublicKeyParameters && !(staticPrivateKey instanceof X25519PrivateKeyParameters)) + { + throw new IllegalArgumentException("ephemeral public key has different domain parameters"); + } + } + + this.staticPrivateKey = staticPrivateKey; + this.ephemeralPrivateKey = ephemeralPrivateKey; + this.ephemeralPublicKey = ephemeralPublicKey; + } + + public AsymmetricKeyParameter getStaticPrivateKey() + { + return staticPrivateKey; + } + + public AsymmetricKeyParameter getEphemeralPrivateKey() + { + return ephemeralPrivateKey; + } + + public AsymmetricKeyParameter getEphemeralPublicKey() + { + return ephemeralPublicKey; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/XDHUPublicParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/XDHUPublicParameters.java new file mode 100644 index 000000000..35cb61466 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/params/XDHUPublicParameters.java @@ -0,0 +1,48 @@ +package com.fr.third.org.bouncycastle.crypto.params; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; + +/** + * Parameters holder for public unified static/ephemeral agreement using Edwards Curves. + */ +public class XDHUPublicParameters + implements CipherParameters +{ + private AsymmetricKeyParameter staticPublicKey; + private AsymmetricKeyParameter ephemeralPublicKey; + + public XDHUPublicParameters( + AsymmetricKeyParameter staticPublicKey, + AsymmetricKeyParameter ephemeralPublicKey) + { + if (staticPublicKey == null) + { + throw new NullPointerException("staticPublicKey cannot be null"); + } + if (!(staticPublicKey instanceof X448PublicKeyParameters || staticPublicKey instanceof X25519PublicKeyParameters)) + { + throw new IllegalArgumentException("only X25519 and X448 paramaters can be used"); + } + if (ephemeralPublicKey == null) + { + throw new NullPointerException("ephemeralPublicKey cannot be null"); + } + if (!staticPublicKey.getClass().isAssignableFrom(ephemeralPublicKey.getClass())) + { + throw new IllegalArgumentException("static and ephemeral public keys have different domain parameters"); + } + + this.staticPublicKey = staticPublicKey; + this.ephemeralPublicKey = ephemeralPublicKey; + } + + public AsymmetricKeyParameter getStaticPublicKey() + { + return staticPublicKey; + } + + public AsymmetricKeyParameter getEphemeralPublicKey() + { + return ephemeralPublicKey; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java index 88bc8eab1..02eb02118 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/SP800SecureRandomBuilder.java @@ -10,6 +10,7 @@ import com.fr.third.org.bouncycastle.crypto.prng.drbg.CTRSP800DRBG; import com.fr.third.org.bouncycastle.crypto.prng.drbg.HMacSP800DRBG; import com.fr.third.org.bouncycastle.crypto.prng.drbg.HashSP800DRBG; import com.fr.third.org.bouncycastle.crypto.prng.drbg.SP80090DRBG; +import com.fr.third.org.bouncycastle.util.Arrays; /** * Builder class for making SecureRandom objects based on SP 800-90A Deterministic Random Bit Generators (DRBG). @@ -72,7 +73,7 @@ public class SP800SecureRandomBuilder */ public SP800SecureRandomBuilder setPersonalizationString(byte[] personalizationString) { - this.personalizationString = personalizationString; + this.personalizationString = Arrays.clone(personalizationString); return this; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/X931SecureRandomBuilder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/X931SecureRandomBuilder.java index e64647473..9185d1435 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/X931SecureRandomBuilder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/X931SecureRandomBuilder.java @@ -5,6 +5,7 @@ import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.BlockCipher; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.Pack; public class X931SecureRandomBuilder @@ -58,7 +59,7 @@ public class X931SecureRandomBuilder public X931SecureRandomBuilder setDateTimeVector(byte[] dateTimeVector) { - this.dateTimeVector = dateTimeVector; + this.dateTimeVector = Arrays.clone(dateTimeVector); return this; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java index 9e9b9fa7f..3b9127a21 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/drbg/CTRSP800DRBG.java @@ -157,7 +157,7 @@ public class CTRSP800DRBG // -- Internal state migration --- - private static final byte[] K_BITS = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + private static final byte[] K_BITS = Hex.decodeStrict("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); // 1. If (number_of_bits_to_return > max_number_of_bits), then return an // ERROR_FLAG. diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/CTRDRBGTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/CTRDRBGTest.java new file mode 100644 index 000000000..7c8ba19a7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/CTRDRBGTest.java @@ -0,0 +1,528 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.AESFastEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.params.DESedeParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.prng.drbg.CTRSP800DRBG; +import com.fr.third.org.bouncycastle.crypto.prng.drbg.SP80090DRBG; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * CTR DRBG Test + */ +public class CTRDRBGTest + extends SimpleTest +{ + public String getName() + { + return "CTRDRBGTest"; + } + + public static void main(String[] args) + { + runTest(new CTRDRBGTest()); + } + + private DRBGTestVector[] createTestVectorData() + { + return new DRBGTestVector[] + { + new DRBGTestVector( + new DESedeEngine(), 168, + new Bit232EntropyProvider().get(232), + false, + "20212223242526", + 112, + new String[] + { + "ABC88224514D0316EA3D48AEE3C9A2B4", + "D3D3F372E43E7ABDC4FA293743EED076" + } + ), + new DRBGTestVector( + new DESedeEngine(), 168, + new Bit232EntropyProvider().get(232), + false, + "20212223242526", + 112, + new String[] + { + "D4564EE072ACA5BD279536E14F94CB12", + "1CCD9AFEF15A9679BA75E35225585DEA" + } + ) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"), + new DRBGTestVector( + new DESedeEngine(), 168, + new Bit232EntropyProvider().get(232), + false, + "20212223242526", + 112, + new String[] + { + "760BED7D92B083B10AF31CF0656081EB", + "FD1AC41482384D823CF3FD6F0E6C88B3" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C"), + new DRBGTestVector( + new DESedeEngine(), 168, + new Bit232EntropyProvider().get(232), + false, + "20212223242526", + 112, + new String[] + { + "7A4C1D7ADC8A67FDB50100ED23583A2C", + "43044D311C0E07541CA5C8B0916976B2" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C") + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"), + new DRBGTestVector( + new DESedeEngine(), 168, + new Bit232EntropyProvider().get(232), + true, + "20212223242526", + 112, + new String[] + { + "8FB78ABCA75C9F284E974E36141866BC", + "9D9745FF31C42A4488CBB771B13B5D86" + } + ), + new DRBGTestVector( + new DESedeEngine(), 168, + new Bit232EntropyProvider().get(232), + true, + "20212223242526", + 112, + new String[] + { + "0E389920A09B485AA4ABD0CA7E60D89C", + "F4478EC6659A0D3577625B0C73A211DD" + } + ) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"), + new DRBGTestVector( + new DESedeEngine(), 168, + new Bit232EntropyProvider().get(232), + true, + "20212223242526", + 112, + new String[] + { + "64983055D014550B39DE699E43130B64", + "035FDDA8582A2214EC722C410A8D95D3" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C"), + new DRBGTestVector( + new DESedeEngine(), 168, + new Bit232EntropyProvider().get(232), + true, + "20212223242526", + 112, + new String[] + { + "A29C1A8C42FBC562D7D1DBA7DC541FFE", + "0BDA66B049429061C013E4228C2F44C6" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C") + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"), + new DRBGTestVector( + new AESFastEngine(), 128, + new Bit256EntropyProvider().get(256), + false, + "2021222324252627", + 128, + new String[] + { + "8CF59C8CF6888B96EB1C1E3E79D82387AF08A9E5FF75E23F1FBCD4559B6B997E", + "69CDEF912C692D61B1DA4C05146B52EB7B8849BD87937835328254EC25A9180E" + } + ), + new DRBGTestVector( + new AESFastEngine(), 128, + new Bit256EntropyProvider().get(256), + false, + "2021222324252627", + 128, + new String[] + { + "E8C74A4B7BFFB53BEB80E78CA86BB6DF70E2032AEB473E0DD54D2339CEFCE9D0", + "26B3F823B4DBAFC23B141375E10B3AEB7A0B5DEF1C7D760B6F827D01ECD17AC7" + } + ) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"), + new DRBGTestVector( + new AESFastEngine(), 128, + new Bit256EntropyProvider().get(256), + false, + "2021222324252627", + 128, + new String[] + { + "18FDEFBDC43D7A36D5D6D862205765D1D701C9F237007030DF1B8E70EE4EEE29", + "9888F1D38BB1CCE31B363AA1BD9B39616876C30DEE1FF0B7BD8C4C441715C833" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"), + new DRBGTestVector( + new AESFastEngine(), 128, + new Bit256EntropyProvider().get(256), + true, + "2021222324252627", + 128, + new String[] + { + "BFF4B85D68C84529F24F69F9ACF1756E29BA648DDEB825C225FA32BA490EF4A9", + "9BD2635137A52AF7D0FCBEFEFB97EA93A0F4C438BD98956C0DACB04F15EE25B3" + } + ), + new DRBGTestVector( + new AESFastEngine(), 128, + new Bit256EntropyProvider().get(256), + true, + "2021222324252627", + 128, + new String[] + { + "4573AC8BBB33D7CC4DBEF3EEDF6EAE748B536C3A1082CEE4948CDB51C83A7F9C", + "99C628CDD87BD8C2F1FE443AA7F761DA16886436326323354DA6311FFF5BC678" + } + ) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"), + new DRBGTestVector( + new AESFastEngine(), 128, + new Bit256EntropyProvider().get(256), + true, + "2021222324252627", + 128, + new String[] + { + "F324104E2FA14F79D8AA60DF06B93B3BC157324958F0A7EE1E193677A70E0250", + "78F4C840134F40DC001BFAD3A90B5EF4DEBDBFAC3CFDF0CD69A89DC4FD34713F" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"), + new DRBGTestVector( + new AESFastEngine(), 192, + new Bit320EntropyProvider().get(320), + false, + "202122232425262728292A2B", + 192, + new String[] + { + "E231244B3235B085C81604424357E85201E3828B5C45568679A5555F867AAC8C", + "DDD0F7BCCADADAA31A67652259CE569A271DD85CF66C3D6A7E9FAED61F38D219" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061626364656667"), + new DRBGTestVector( + new AESFastEngine(), 192, + new Bit320EntropyProvider().get(320), + true, + "202122232425262728292A2B", + 192, + new String[] + { + "F780D4A2C25CF8EE7407D948EC0B724A4235D8B20E65081392755CA7912AD7C0", + "BA14617F915BA964CB79276BDADC840C14B631BBD1A59097054FA6DFF863B238" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F6061626364656667"), + new DRBGTestVector( + new AESFastEngine(), 256, + new Bit384EntropyProvider().get(384), + false, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "47111E146562E9AA2FB2A1B095D37A8165AF8FC7CA611D632BE7D4C145C83900", + "98A28E3B1BA363C9DAF0F6887A1CF52B833D3354D77A7C10837DD63DD2E645F8" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F") + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"), + new DRBGTestVector( + new AESFastEngine(), 256, + new Bit384EntropyProvider().get(384), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "71BB3F9C9CEAF4E6C92A83EB4C7225010EE150AC75E23F5F77AD5073EF24D88A", + "386DEBBBF091BBF0502957B0329938FB836B82E594A2F5FDD5EB28D4E35528F4" + } + ) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"), + new DRBGTestVector( + new AESFastEngine(), 256, + new Bit384EntropyProvider().get(384), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "1A2E3FEE9056E98D375525FDC2B63B95B47CE51FCF594D804BD5A17F2E01139B", + "601F95384F0D85946301D1EACE8F645A825CE38F1E2565B0C0C439448E9CA8AC" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F"), + new DRBGTestVector( + new AESFastEngine(), 256, + new Bit384EntropyProvider().get(384), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "EAE6BCE781807E524D26605EA198077932D01EEB445B9AC6C5D99C101D29F46E", + "738E99C95AF59519AAD37FF3D5180986ADEBAB6E95836725097E50A8D1D0BD28" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F") + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"), + new DRBGTestVector( + new AESFastEngine(), 256, + new Bit384EntropyProvider().get(384), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "eae6bce781807e524d26605ea198077932d01eeb445b9ac6c5d99c101d29f46e30b27377", + "ec51b55b49904c3ff9e13939f1cf27398993e1b3acb2b0be0be8761261428f0aa8ba2657" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F") + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECF") + }; + } + + public void performTest() + throws Exception + { + DRBGTestVector[] tests = createTestVectorData(); + + for (int i = 0; i != tests.length; i++) + { + DRBGTestVector tv = tests[i]; + + byte[] nonce = tv.nonce(); + byte[] personalisationString = tv.personalizationString(); + + SP80090DRBG d = new CTRSP800DRBG(tv.getCipher(), tv.keySizeInBits(), tv.securityStrength(), tv.entropySource(), personalisationString, nonce); + + byte[] output = new byte[tv.expectedValue(0).length]; + + d.generate(output, tv.additionalInput(0), tv.predictionResistance()); + + byte[] expected = tv.expectedValue(0); + + if (!areEqual(expected, output)) + { + fail("Test #" + (i + 1) + ".1 failed, expected " + new String(Hex.encode(tv.expectedValue(0))) + " got " + new String(Hex.encode(output))); + } + + output = new byte[tv.expectedValue(0).length]; + + d.generate(output, tv.additionalInput(1), tv.predictionResistance()); + + expected = tv.expectedValue(1); + if (!areEqual(expected, output)) + { + fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output))); + } + } + + // DESede/TDEA key parity test + DRBGTestVector tv = tests[0]; + + SP80090DRBG drbg = new CTRSP800DRBG(new KeyParityCipher(tv.getCipher()), tv.keySizeInBits(), tv.securityStrength(), tv.entropySource(), tv.personalizationString(), tv.nonce()); + + byte[] output = new byte[tv.expectedValue(0).length]; + + drbg.generate(output, tv.additionalInput(0), tv.predictionResistance()); + + // Exception tests + SP80090DRBG d; + try + { + d = new CTRSP800DRBG(new AESEngine(), 256, 256, new Bit232EntropyProvider().get(128), null, null); + fail("no exception thrown"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("Not enough entropy for security strength required")) + { + fail("Wrong exception", e); + } + } + + try + { + d = new CTRSP800DRBG(new DESedeEngine(), 256, 256, new Bit232EntropyProvider().get(232), null, null); + fail("no exception thrown"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("Requested security strength is not supported by block cipher and key size")) + { + fail("Wrong exception", e); + } + } + + try + { + d = new CTRSP800DRBG(new DESedeEngine(), 168, 256, new Bit232EntropyProvider().get(232), null, null); + fail("no exception thrown"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("Requested security strength is not supported by block cipher and key size")) + { + fail("Wrong exception", e); + } + } + + try + { + d = new CTRSP800DRBG(new AESEngine(), 192, 256, new Bit232EntropyProvider().get(232), null, null); + fail("no exception thrown"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("Requested security strength is not supported by block cipher and key size")) + { + fail("Wrong exception", e); + } + } + } + + private class Bit232EntropyProvider + extends TestEntropySourceProvider + { + Bit232EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C" + + "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDC"), true); + } + } + + private class Bit256EntropyProvider + extends TestEntropySourceProvider + { + Bit256EntropyProvider() + { + super(Hex.decode( + "0001020304050607"+ + "08090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"+ + "8081828384858687"+ + "88898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F"+ + "C0C1C2C3C4C5C6C7"+ + "C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"), true); + } + } + + private class Bit320EntropyProvider + extends TestEntropySourceProvider + { + Bit320EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F"+ + "101112131415161718191A1B1C1D1E1F2021222324252627"+ + "808182838485868788898A8B8C8D8E8F"+ + "909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7"+ + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"+ + "D0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7"), true); + } + } + + private class Bit384EntropyProvider + extends TestEntropySourceProvider + { + Bit384EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F1011121314151617" + + "18191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F" + + "808182838485868788898A8B8C8D8E8F9091929394959697" + + "98999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAF" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7" + + "D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF"), true); + } + } + + private class KeyParityCipher + implements BlockCipher + { + private BlockCipher cipher; + + KeyParityCipher(BlockCipher cipher) + { + this.cipher = cipher; + } + + public void init(boolean forEncryption, CipherParameters params) + throws IllegalArgumentException + { + byte[] k = Arrays.clone(((KeyParameter)params).getKey()); + + DESedeParameters.setOddParity(k); + + if (!Arrays.areEqual(((KeyParameter)params).getKey(), k)) + { + fail("key not odd parity"); + } + + cipher.init(forEncryption, params); + } + + public String getAlgorithmName() + { + return cipher.getAlgorithmName(); + } + + public int getBlockSize() + { + return cipher.getBlockSize(); + } + + public int processBlock(byte[] in, int inOff, byte[] out, int outOff) + throws DataLengthException, IllegalStateException + { + return cipher.processBlock(in, inOff, out, outOff); + } + + public void reset() + { + cipher.reset(); + } + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/DRBGTestVector.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/DRBGTestVector.java new file mode 100644 index 000000000..c8b401123 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/DRBGTestVector.java @@ -0,0 +1,131 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import java.util.ArrayList; +import java.util.List; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.prng.EntropySource; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +public class DRBGTestVector +{ + private Digest _digest; + private BlockCipher _cipher; + private int _keySizeInBits; + private EntropySource _eSource; + private boolean _pr; + private String _nonce; + private String _personalisation; + private int _ss; + private String[] _ev; + private List _ai = new ArrayList(); + + public DRBGTestVector(Digest digest, EntropySource eSource, boolean predictionResistance, String nonce, int securityStrength, String[] expected) + { + _digest = digest; + _eSource = eSource; + _pr = predictionResistance; + _nonce = nonce; + _ss = securityStrength; + _ev = expected; + _personalisation = null; + } + + public DRBGTestVector(BlockCipher cipher, int keySizeInBits, EntropySource eSource, boolean predictionResistance, String nonce, int securityStrength, String[] expected) + { + _cipher = cipher; + _keySizeInBits = keySizeInBits; + _eSource = eSource; + _pr = predictionResistance; + _nonce = nonce; + _ss = securityStrength; + _ev = expected; + _personalisation = null; + } + + public Digest getDigest() + { + return _digest; + } + + public BlockCipher getCipher() + { + return _cipher; + } + + public int keySizeInBits() + { + return _keySizeInBits; + } + + public DRBGTestVector addAdditionalInput(String input) + { + _ai.add(input); + + return this; + } + + public DRBGTestVector setPersonalizationString(String p) + { + _personalisation = p; + + return this; + } + + public EntropySource entropySource() + { + return _eSource; + } + + public boolean predictionResistance() + { + return _pr; + } + + public byte[] nonce() + { + if (_nonce == null) + { + return null; + } + + return Hex.decode(_nonce); + } + + public byte[] personalizationString() + { + if (_personalisation == null) + { + return null; + } + + return Hex.decode(_personalisation); + } + + public int securityStrength() + { + return _ss; + } + + public byte[] expectedValue(int index) + { + return Hex.decode(_ev[index]); + } + + public byte[] additionalInput(int position) + { + int len = _ai.size(); + byte[] rv; + if (position >= len) + { + rv = null; + } + else + { + rv = Hex.decode((String)(_ai.get(position))); + } + return rv; + } + + } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/DualECDRBGTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/DualECDRBGTest.java new file mode 100644 index 000000000..e2c6b348d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/DualECDRBGTest.java @@ -0,0 +1,415 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA384Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.prng.drbg.DualECSP800DRBG; +import com.fr.third.org.bouncycastle.crypto.prng.drbg.SP80090DRBG; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Dual EC SP800-90 DRBG test + */ +public class DualECDRBGTest + extends SimpleTest +{ + public String getName() + { + return "DualECDRBG"; + } + + public static void main(String[] args) + { + runTest(new DualECDRBGTest()); + } + + private DRBGTestVector[] createTestVectorData() + { + return new DRBGTestVector[] + { + new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(128), + false, + "2021222324252627", + 128, + new String[] + { + "FF5163C388F791E96F1052D5C8F0BD6FBF7144839C4890FF85487C5C12702E4C9849AF518AE68DEB14D3A62702BBDE4B98AB211765FD87ACA12FC2A6", + "9A0A11F2DFB88F7260559DD8DA6134EB2B34CC0415FA8FD0474DB6B85E1A08385F41B435DF81296B1B4EDF66E0107C0844E3D28A89B05046B89177F2" + }), + new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(128), + false, + "2021222324252627", + 128, + new String[] + { + "C08E954FCD486D0B0934A0236692AC705A835D1A3C94D2ACD4684AB26E978D7D42E73CC06D6EC1472C63E51BED7F71518395836E2052BBD73A20CABB", + "1D76DEE36FCC5F9478C112EAFA1C4CCD0635435A6F3A247A3BA3849790B5245070E95C1A67BE7A39BFB213F2C0EFCC171A3253DA6D54DA4362EA2099" + }) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"), + new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(128), + false, + "2021222324252627", + 128, + new String[] + { + "3AB095CC493A8730D70DE923108B2E4710799044FFC27D0A1156250DDF97E8B05ACE055E49F3E3F5B928CCD18317A3E68FCB0B6F0459ADF9ECF79C87", + "7B902FC35B0AF50F57F8822936D08A96E41B16967C6B1AA0BC05032F0D53919DC587B664C883E2FE8F3948002FCD8BCBFC4706BCAA2075EF6BF41167" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F"), + new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(128), + false, + "2021222324252627", + 128, + new String[] + { + "3B68A1D95ED0312150AC1991189780F37EC50E75249F915CD806BBA0C44F9E3A919B2390805E1E90C1D2D1C823B17B96DB44535B72E0CFB62723529D", + "250B933475E3BD4FC85D97FD797834B599DEDEDF8B6F15474E1F31B4AF215CFA7A8C0A0296A2E374B3886BB0CC7E49DBB19324564B451E64F12864F9" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F") + .addAdditionalInput("606162636465666768696A6B6C6D6E6F") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"), + new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(128), + true, + "2021222324252627", + 128, + new String[] + { + "8C77288EDBEA9A742464F78D55E33593C1BF5F9D8CD8609D6D53BAC4E4B42252A227A99BAD0F2358B05955CD35723B549401C71C9C1F32F8A2018E24", + "56ECA61C64F69C1C232E992623C71418BD0B96D783118FAAD94A09E3A9DB74D15E805BA7F14625995CA77612B2EF7A05863699ECBABF70D3D422C014" + }), + new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(128), + true, + "2021222324252627", + 128, + new String[] + { + "A5C397DFEB540E86F0470E9625D5C5AC2D50016FB201E8DF574F2201DFBB42A799FEB9E238AAD301A493382250EEE60D2E2927E500E848E57535ABD1", + "BF9894630BEBAF0A0EDFE726285EB055FD2ED678B76673803DD327F49DBEDE87D3E447A6EB73B5D5C52A40078132677F412E9E7DE32B9B1CB32421B9" + }) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAF"), + new DRBGTestVector( + new SHA384Digest(), + new SHA384EntropyProvider().get(192), + false, + "202122232425262728292A2B", + 192, + new String[] + { + "1F858858B65357D6360E1ED8F8475767B08DAB30718CCA01C6FAE77A4BDCE2702C76D0FB4758EA1ED6AA587CFD26B9011DC8A75D0B4154193BB2C1798FFA52BCAB208310" + + "3CD2AAD44BEED56D042FC2B8915D7D9BED6437EFEB1582EE", + "6E4AAB63938212C870F24BB067A32CA9E7FC2343" + + "5D411729268C8BA6F90E87074D04888CE2CC5A916B7AC93F" + + "EDE85E2995645DFCC4CE44B9FB41F1BFCC5E9F59EE3A8E1B" + + "8F85247F741B7C480521EE6BF8BA319B59048E65F08FAA76" + }), + new DRBGTestVector( + new SHA384Digest(), + new SHA384EntropyProvider().get(192), + false, + "202122232425262728292A2B", + 192, + new String[] + { + "E6A30AB0C9AFCBA673E4F1C94B3DB1F0C7D78B3D" + + "87B967281BE1E7B3CAF5200AED502C26B84FC169FE8336BD" + + "23271CB299812F2CF1955AA63FC362044ABA246EF1610F9E" + + "DC613924A84A00F8DB3FC65C13373F3171EB20848FA9A70E", + "8585764DF1C86EA12ACCB882525BF6217B447486" + + "5EBFDA367B8657FA80471139BAC626172B9F219DF2CE9099" + + "F65833E07CD1A8DD80468779EA3C26620A2C9C9F5C7EFCDD" + + "C036E6F6C8BF70316D3C37FC246A4CC79B3F1DB971D72ED0" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F5051525354555657"), + new DRBGTestVector( + new SHA384Digest(), + new SHA384EntropyProvider().get(192), + false, + "202122232425262728292A2B", + 192, + new String[] + { + "13F6EA9BBA7BABDC2A52A3B9FD73D65ECAA638A0" + + "4C74BCCA2ACDE6FD29FEA4B5D884E095E87D1B7C0DEB9D37" + + "7AD81FBFEEA2D5EF82C0F6F52B9FCC359E769AC9DF2A876C" + + "58BAF21657814F3E66D1680B1D4EBD65581E42534F85197D", + "FC0A36F4D20F8F83BE3430AA3C36A49191821A82" + + "072BBC3D5AFF8D7EC39484D646277CE87599B6FE8CCA9862" + + "559703A10F4DE1066BFD30B80C325E774B512525BC6D3734" + + "4C93906368243D31F89E99C4D2A6E9BEB24D5F7267360DCA" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F5051525354555657") + .addAdditionalInput("606162636465666768696A6B6C6D6E6F7071727374757677") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7"), + new DRBGTestVector( + new SHA384Digest(), + new SHA384EntropyProvider().get(192), + true, + "202122232425262728292A2B", + 192, + new String[] + { + "FE55601BF734493013705CCEB76E44AAD48373F7" + + "42E72B83D4701FA6549255F1CDE6217953522FF973BA4F6E" + + "C96D2BDCF14A76BE7DEB61781E34B99335BD714F17C91739" + + "B4E2AB57E36E9C3116E215D3D94FCFAD532636874875CAC7", + "F5E59D0ABADE81F62FFAB9D4A6A26FF200016608" + + "A7215E389858FFED83FBC75CFD33DBA6688C89AA32AD22E4" + + "80EA3D04EADFB35567B67564207E64B77844E8E4A87502D5" + + "02DBBB6D8277F1CACDB7CF8D293D09DB7DD59A950821507A" + }) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F7071727374757677") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7"), + new DRBGTestVector( + new SHA384Digest(), + new SHA384EntropyProvider().get(192), + true, + "202122232425262728292A2B", + 192, + new String[] + { + "CC788F70FB08F256D9604333630D85936D400F45" + + "718DC3F939A8B9F6F75D3E4EC17D68FBB924AEACB7021295" + + "48FA63CE9BCB82176639B64DE890A47025B5582312FE934E" + + "F0D0A12697C0F05D2DA108CCADB511BA0EB62F4051BB2354", + "2C922EA620D76E4137B315EBC29E518F80951B3F" + + "0E6173FA2BFD94A230EE513EE2E4EB330D802F620DD24911" + + "534EC0F95A1F1D44A2125F5D57476A666FC372092B55D0D6" + + "8B49738F5BC466EC206AB3CF6A972B38BCFAE5FCD53C7E21 " + }), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(256), + false, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "7A8313798EE1" + + "D1898712683F2D0B0DEE5804146ABA64FDA8DB4E539CC8D1" + + "E59C74EE5AA48E73E958C8EC85DD529D42E68B4F7E02FFAF" + + "3E3EF8312AEA68BC08A414885E60A7DF0B55F9D90210B319" + + "E9B8FD23E078A4153636F29AA3CAC8198CB1D5D846151653" + + "ECE275A591089261238014E5058410065AB8229EB9115E8E", + "918B5D79E646" + + "64966D954BC5E2946BF48F061BF0C2701C3C2D1F75EA821E" + + "1DA05D5B3C2C4EEA246E806B53BF6BDB3F3D53A3AE756C2A" + + "45C72603973A3DE1BC367C283CA124A5589CEAB30E5D2D74" + + "8A40DD874FF15B032CF4F4B2AAD590B0DB91A0D38FCE93C5" + + "AAD4E55AC482F86FF06FAE66B7C7CCA7E45557E1A5A3B85D" + }), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(256), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "C7ED88A2C690" + + "1C04802BA2BB04262921B19664835A4A3C002CB9F13E35E3" + + "DEB3698A436BF1C85B070E9E6977CA78A5130905AA0C01A9" + + "4130F5133DF904A4ACF59A7DD01227E8FCA1C8D51F093839" + + "46ECD950113104760D7E216CAF581FE9D3AACE6FC4CDDC4C" + + "CD736D26A60BE8BE2A6A78CD752D1EC7CCC802638B177307", + "83B78B206785" + + "4412EEB24AEA86064D510C68FD96DBF94EAC1BC2022752D7" + + "558AEB9F97B9CBC1B9648FE4D88E2C82A6F530675E1DB92D" + + "396D6D85BDAD2A23CBD10AD808ECCCFBFC811EB68AE835E4" + + "912E011DD10A4399C8DE2D9D88F81B6168B05D282B9DAC1E" + + "65E0A45F61043E1FA047870DD582295E6C50DD1185B13594 " + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F") + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(256), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "CC7035C73040" + + "5CF5DF7137ED9E10744B75B540AFFC68EB564B71C0F737E8" + + "F656B6171940497FA90D8F383EFB6FC6717BA14AAA164EF5" + + "6641C0F513312551DCD21D0A5B0DBDCD97F627E968DFD752" + + "56C11CF2BCCA5822EAACE796A34CB7D2F8CD8CC6DBE76274" + + "498289BBC4C2F1CADA6185D82605CF992EC285BC4945EE9E", + "0E6C329AD1BE" + + "681EB1E6F5E03A89E3D80153D6CCDD5A3ECF865003EE4A2D" + + "E5A23B7F43681361CFAFC3A3FEF17777E75CF9D6685573C8" + + "87A3962CB955076D45D6F1E45EE4B8CB31A4731CDA031FA2" + + "815B6D34E29F2603526CE186576F4CCA3FEDF7F8ACDB37C9" + + "9D762706ABE4967D44739C8CFCFCC76C58B1ED243AC394C0" + }), + // From http://csrc.nist.gov/groups/STM/cavp/documents/drbg/drbgtestvectors.zip + // modified to test partial block processing. + new DRBGTestVector( + new SHA256Digest(), + new TestEntropySourceProvider(Hex.decode("a826f1cd3fa24b9e71c316e5bf2bafff"), false).get(128), + false, + "82bc3bf050614b34", + 128, + new String[] + { + "14949b876e30f832331f59f2e687350bea9ba22b78549521a70748ca916c74ebff0b638266aa" + + "d81e089545eb60bfe332f7d134d91ed3c104f975fae0f71391add71e3380a725251ed5552a84" + + "650637eddfc88b5ab26311277cbc429aa152b2cfac61c67846512d7564114177a622f25e870a" + + "acec37c0977d", + "7050bf74a887809673ecd295071f7a457d1e2e227f68ef4b4445e34f3904b95d4833180ee522" + + "104bfc996234063e2c76173937b883c66b0e64a56643877228cad5212cddbf839270ef80889b" + + "c83424c141c2419f2231004c8860f8fd95435e2c9f8ac7409fcbfb6a74851fadc7d99bf5d68b" + + "591892f0e3a1" + }), + new DRBGTestVector( + new SHA256Digest(), + new TestEntropySourceProvider(Hex.decode("a826f1cd3fa24b9e71c316e5bf2bafff"), false).get(128), + false, + "82bc3bf050614b34", + 128, + new String[] + { + "14949b876e30f832331f59f2e687350bea9ba22b78549521a70748ca916c74ebff0b638266aa" + + "d81e089545eb60bfe332f7d134d91ed3c104f975fae0f71391add71e3380a725251ed5552a84" + + "650637eddfc88b5ab26311277cbc429aa152b2cfac61c67846512d7564114177a622f25e870a" + + "acec37c0977d", + "7050bf74a887809673ecd295071f7a457d1e2e227f68ef4b4445e34f3904b95d4833180ee522" + + "104bfc996234063e2c76173937b883c66b0e64a56643877228cad5212cddbf839270ef80889b" + + "c83424c141c2419f2231004c8860f8fd95435e2c9f8ac7409fcbfb6a74851fadc7d99bf5d68b" + + "591892f0e3" + }) + }; + } + + public void performTest() + throws Exception + { + DRBGTestVector[] tests = createTestVectorData(); + + for (int i = 0; i != tests.length; i++) + { + DRBGTestVector tv = tests[i]; + + byte[] nonce = tv.nonce(); + byte[] personalisationString = tv.personalizationString(); + + SP80090DRBG d = new DualECSP800DRBG(tv.getDigest(), tv.securityStrength(), tv.entropySource(), personalisationString, nonce); + + byte[] output = new byte[tv.expectedValue(0).length]; + + d.generate(output, tv.additionalInput(0), tv.predictionResistance()); + + byte[] expected = tv.expectedValue(0); + + if (!areEqual(expected, output)) + { + fail("Test #" + (i + 1) + ".1 failed, expected " + new String(Hex.encode(tv.expectedValue(0))) + " got " + new String(Hex.encode(output))); + } + + output = new byte[tv.expectedValue(1).length]; + + d.generate(output, tv.additionalInput(1), tv.predictionResistance()); + + expected = tv.expectedValue(1); + if (!areEqual(expected, output)) + { + fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output))); + } + } + + // Exception tests + // + SP80090DRBG d; + + try + { + d = new DualECSP800DRBG(new SHA256Digest(), 256, new SHA256EntropyProvider().get(128), null, null); + fail("no exception thrown"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("EntropySource must provide between 256 and 4096 bits")) + { + fail("Wrong exception", e); + } + } + + try + { + d = new DualECSP800DRBG(new SHA256Digest(), 256, new SHA256EntropyProvider().get(1 << (13 - 1) + 1), null, null); + fail("no exception thrown"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("EntropySource must provide between 256 and 4096 bits")) + { + fail("Wrong exception", e); + } + } + + try + { + d = new DualECSP800DRBG(new SHA1Digest(), 256, new SHA256EntropyProvider().get(256), null, null); + fail("no exception thrown"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("Requested security strength is not supported by digest")) + { + fail("Wrong exception", e); + } + } + } + + private class SHA256EntropyProvider + extends TestEntropySourceProvider + { + SHA256EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F " + + "808182838485868788898A8B8C8D8E8F" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"), true); + } + } + + private class SHA384EntropyProvider + extends TestEntropySourceProvider + { + SHA384EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F1011121314151617" + + "808182838485868788898A8B8C8D8E8F9091929394959697" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7"), true); + } + } + + private class SHA512EntropyProvider + extends TestEntropySourceProvider + { + SHA512EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F" + + "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDF"), true); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/FixedSecureRandomTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/FixedSecureRandomTest.java new file mode 100644 index 000000000..a60896188 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/FixedSecureRandomTest.java @@ -0,0 +1,68 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import com.fr.third.org.bouncycastle.crypto.prng.FixedSecureRandom; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class FixedSecureRandomTest + extends SimpleTest +{ + byte[] base = Hex.decode("deadbeefdeadbeef"); + byte[] r1 = Hex.decode("cafebabecafebabe"); + byte[] r2 = Hex.decode("ffffffffcafebabedeadbeef"); + + public String getName() + { + return "FixedSecureRandom"; + } + + public void performTest() + throws Exception + { + FixedSecureRandom fixed = new FixedSecureRandom(base); + byte[] buf = new byte[8]; + + fixed.nextBytes(buf); + + if (!Arrays.areEqual(buf, base)) + { + fail("wrong data returned"); + } + + fixed = new FixedSecureRandom(base); + + byte[] seed = fixed.generateSeed(8); + + if (!Arrays.areEqual(seed, base)) + { + fail("wrong seed data returned"); + } + + if (!fixed.isExhausted()) + { + fail("not exhausted"); + } + + fixed = new FixedSecureRandom(new byte[][] { r1, r2 }); + + seed = fixed.generateSeed(12); + + if (!Arrays.areEqual(seed, Hex.decode("cafebabecafebabeffffffff"))) + { + fail("wrong seed data returned - composite"); + } + + fixed.nextBytes(buf); + + if (!Arrays.areEqual(buf, Hex.decode("cafebabedeadbeef"))) + { + fail("wrong data returned"); + } + } + + public static void main(String[] args) + { + runTest(new FixedSecureRandomTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/HMacDRBGTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/HMacDRBGTest.java new file mode 100644 index 000000000..ac40e7c71 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/HMacDRBGTest.java @@ -0,0 +1,508 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA384Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.prng.drbg.HMacSP800DRBG; +import com.fr.third.org.bouncycastle.crypto.prng.drbg.SP80090DRBG; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * HMAC SP800-90 DRBG + */ +public class HMacDRBGTest + extends SimpleTest +{ + public String getName() + { + return "HMacDRBG"; + } + + public static void main(String[] args) + { + runTest(new HMacDRBGTest()); + } + + private DRBGTestVector[] createTestVectorData() + { + return new DRBGTestVector[] + { + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + false, + "2021222324", + 80, + new String[] + { + "5A7D3B449F481CB38DF79AD2B1FCC01E57F8135E8C0B22CD0630BFB0127FB5408C8EFC17A929896E", + "82cf772ec3e84b00fc74f5df104efbfb2428554e9ce367d03aeade37827fa8e9cb6a08196115d948" + }), + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + false, + "2021222324", + 80, + new String[] + { + "B3BD05246CBA12A64735A4E3FDE599BC1BE30F439BD060208EEA7D71F9D123DF47B3CE069D98EDE6", + "B5DADA380E2872DF935BCA55B882C8C9376902AB639765472B71ACEBE2EA8B1B6B49629CB67317E0" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"), + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + false, + "2021222324", + 80, + new String[] + { + "C7AAAC583C6EF6300714C2CC5D06C148CFFB40449AD0BB26FAC0497B5C57E161E36681BCC930CE80", + "6EBD2B7B5E0A2AD7A24B1BF9A1DBA47D43271719B9C37B7FE81BA94045A14A7CB514B446666EA5A7" + }) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90919293949596") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6"), + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + true, + "2021222324", + 80, + new String[] + { + "FEC4597F06A3A8CC8529D59557B9E661053809C0BC0EFC282ABD87605CC90CBA9B8633DCB1DAE02E", + "84ADD5E2D2041C01723A4DE4335B13EFDF16B0E51A0AD39BD15E862E644F31E4A2D7D843E57C5968" + }), + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + true, + "2021222324", + 80, + new String[] + { + "6C37FDD729AA40F80BC6AB08CA7CC649794F6998B57081E4220F22C5C283E2C91B8E305AB869C625", + "CAF57DCFEA393B9236BF691FA456FEA7FDF1DF8361482CA54D5FA723F4C88B4FA504BF03277FA783" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"), + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + true, + "2021222324", + 80, + new String[] + { + "A1BA8FA58BB5013F43F7B6ED52B4539FA16DC77957AEE815B9C07004C7E992EB8C7E591964AFEEA2", + "84264A73A818C95C2F424B37D3CC990B046FB50C2DC64A164211889A010F2471A0912FFEA1BF0195" + }) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90919293949596") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6"), + new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(440), + false, + "2021222324252627", + 128, + new String[] + { + "D67B8C1734F46FA3F763CF57C6F9F4F2" + + "DC1089BD8BC1F6F023950BFC5617635208C8501238AD7A44" + + "00DEFEE46C640B61AF77C2D1A3BFAA90EDE5D207406E5403", + "8FDAEC20F8B421407059E3588920DA7E" + + "DA9DCE3CF8274DFA1C59C108C1D0AA9B0FA38DA5C792037C" + + "4D33CD070CA7CD0C5608DBA8B885654639DE2187B74CB263" + }), + new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(440), + true, + "2021222324252627", + 128, + new String[] + { + "FABD0AE25C69DC2EFDEFB7F20C5A31B5" + + "7AC938AB771AA19BF8F5F1468F665C938C9A1A5DF0628A56" + + "90F15A1AD8A613F31BBD65EEAD5457D5D26947F29FE91AA7", + "6BD925B0E1C232EFD67CCD84F722E927" + + "ECB46AB2B740014777AF14BA0BBF53A45BDBB62B3F7D0B9C" + + "8EEAD057C0EC754EF8B53E60A1F434F05946A8B686AFBC7A" + }), + new DRBGTestVector( + new SHA384Digest(), + new SHA384EntropyProvider().get(888), + false, + "202122232425262728292A2B", + 192, + new String[]{ + "03AB8BCE4D1DBBB636C5C5B7E1C58499FEB1C619CDD11D35" + + "CD6CF6BB8F20EF27B6F5F9054FF900DB9EBF7BF30ED4DCBB" + + "BC8D5B51C965EA226FFEE2CA5AB2EFD00754DC32F357BF7A" + + "E42275E0F7704DC44E50A5220AD05AB698A22640AC634829", + "B907E77144FD55A54E9BA1A6A0EED0AAC780020C41A15DD8" + + "9A6C163830BA1D094E6A17100FF71EE30A96E1EE04D2A966" + + "03832A4E404F1966C2B5F4CB61B9927E8D12AC1E1A24CF23" + + "88C14E8EC96C35181EAEE32AAA46330DEAAFE5E7CE783C74"}) + .setPersonalizationString( + "404142434445464748494A4B4C4D4E" + + "4F505152535455565758595A5B5C5D5E5F60616263646566" + + "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" + + "7F808182838485868788898A8B8C8D8E8F90919293949596" + + "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"), + new DRBGTestVector( + new SHA384Digest(), + new SHA384EntropyProvider().get(888), + true, + "202122232425262728292A2B", + 192, + new String[]{ + "804A3AD720F4FCE8738D0632514FEF16430CB7D63A8DF1A5" + + "F02A3CE3BD7ED6A668B69E63E2BB93F096EE753D6194A0F1" + + "A32711063653009636337D22167CC4402D019AC216FA574F" + + "091CF6EA283568D737A77BE38E8F09382C69E76B142ABC3A", + "73B8E55C753202176A17B9B9754A9FE6F23B01861FCD4059" + + "6AEAA301AF1AEF8AF0EAF22FBF34541EFFAB1431666ACACC" + + "759338C7E28672819D53CFEF10A3E19DAFBD53295F1980A9" + + "F491504A2725506784B7AC826D92C838A8668171CAAA86E7"}) + .setPersonalizationString( + "404142434445464748494A4B4C4D4E" + + "4F505152535455565758595A5B5C5D5E5F60616263646566" + + "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" + + "7F808182838485868788898A8B8C8D8E8F90919293949596" + + "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + false, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[]{ + "2A5FF6520C20F66E" + + "D5EA431BD4AEAC58F975EEC9A015137D5C94B73AA09CB8B5" + + "9D611DDEECEB34A52BB999424009EB9EAC5353F92A6699D2" + + "0A02164EEBBC6492941E10426323898465DFD731C7E04730" + + "60A5AA8973841FDF3446FB6E72A58DA8BDA2A57A36F3DD98" + + "6DF85C8A5C6FF31CDE660BF8A841B21DD6AA9D3AC356B87B", + "0EDC8D7D7CEEC7FE" + + "36333FB30C0A9A4B27AA0BECBF075568B006C1C3693B1C29" + + "0F84769C213F98EB5880909EDF068FDA6BFC43503987BBBD" + + "4FC23AFBE982FE4B4B007910CC4874EEC217405421C8D8A1" + + "BA87EC684D0AF9A6101D9DB787AE82C3A6A25ED478DF1B12" + + "212CEC325466F3AC7C48A56166DD0B119C8673A1A9D54F67"}) + .setPersonalizationString( + "404142434445464748494A4B4C4D4E" + + "4F505152535455565758595A5B5C5D5E5F60616263646566" + + "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" + + "7F808182838485868788898A8B8C8D8E8F90919293949596" + + "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[]{ + "AAE4DC3C9ECC74D9" + + "061DD527117EF3D29E1E52B26853C539D6CA797E8DA3D0BB" + + "171D8E30B8B194D8C28F7F6BE3B986B88506DC6A01B294A7" + + "165DD1C3470F7BE7B396AA0DB7D50C4051E7C7E1C8A7D21A" + + "2B5878C0BCB163CAA79366E7A1162FDC88429616CD3E6977" + + "8D327520A6BBBF71D8AA2E03EC4A9DAA0E77CF93E1EE30D2 ", + "129FF6D31A23FFBC" + + "870632B35EE477C2280DDD2ECDABEDB900C78418BE2D243B" + + "B9D8E5093ECE7B6BF48638D8F704D134ADDEB7F4E9D5C142" + + "CD05683E72B516486AF24AEC15D61E81E270DD4EBED91B62" + + "12EB8896A6250D5C8BC3A4A12F7E3068FBDF856F47EB23D3" + + "79F82C1EBCD1585FB260B9C0C42625FBCEE68CAD773CD5B1"}) + .setPersonalizationString( + "404142434445464748494A4B4C4D4E" + + "4F505152535455565758595A5B5C5D5E5F60616263646566" + + "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" + + "7F808182838485868788898A8B8C8D8E8F90919293949596" + + "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + false, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[]{ + "7AE31A2DEC31075F" + + "E5972660C16D22ECC0D415C5693001BE5A468B590BC1AE2C" + + "43F647F8D681AEEA0D87B79B0B4E5D089CA2C9D327534234" + + "0254E6B04690D77A71A294DA9568479EEF8BB2A2110F18B6" + + "22F60F35235DE0E8F9D7E98105D84AA24AF0757AF005DFD5" + + "2FA51DE3F44FCE0C5F3A27FCE8B0F6E4A3F7C7B53CE34A3D", + "D83A8084630F286D" + + "A4DB49B9F6F608C8993F7F1397EA0D6F4A72CF3EF2733A11" + + "AB823C29F2EBDEC3EDE962F93D920A1DB59C84E1E879C29F" + + "5F9995FC3A6A3AF9B587CA7C13EA197D423E81E1D6469942" + + "B6E2CA83A97E91F6B298266AC148A1809776C26AF5E239A5" + + "5A2BEB9E752203A694E1F3FE2B3E6A0C9C314421CDB55FBD "}) + .setPersonalizationString( + "404142434445464748494A4B4C4D4E" + + "4F505152535455565758595A5B5C5D5E5F60616263646566" + + "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" + + "7F808182838485868788898A8B8C8D8E8F90919293949596" + + "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE") + .addAdditionalInput( + "606162636465666768696A6B6C6D6E" + + "6F707172737475767778797A7B7C7D7E7F80818283848586" + + "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" + + "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE") + .addAdditionalInput( + "A0A1A2A3A4A5A6A7A8A9AAABACADAE" + + "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" + + "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" + + "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" + + "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E"), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[]{ + "28FD6060C4F35F4D" + + "317AB2060EE32019E0DAA330F3F5650BBCA57CB67EE6AF1C" + + "6F25D1B01F3601EDA85DC2ED29A9B2BA4C85CF491CE7185F" + + "1A2BD9378AE3C655BD1CEC2EE108AE7FC382989F6D4FEA8A" + + "B01499697C2F07945CE02C5ED617D04287FEAF3BA638A4CE" + + "F3BB6B827E40AF16279580FCF1FDAD830930F7FDE341E2AF", + "C0B1601AFE39338B" + + "58DC2BE7C256AEBE3C21C5A939BEEC7E97B3528AC420F0C6" + + "341847187666E0FF578A8EB0A37809F877365A28DF2FA0F0" + + "6354A6F02496747369375B9A9D6B756FDC4A8FB308E08256" + + "9D79A85BB960F747256626389A3B45B0ABE7ECBC39D5CD7B" + + "2C18DF2E5FDE8C9B8D43474C54B6F9839468445929B438C7"}), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[]{ + "72691D2103FB567C" + + "CD30370715B36666F63430087B1C688281CA0974DB456BDB" + + "A7EB5C48CFF62EA05F9508F3B530CE995A272B11EC079C13" + + "923EEF8E011A93C19B58CC6716BC7CB8BD886CAA60C14D85" + + "C023348BD77738C475D6C7E1D9BFF4B12C43D8CC73F838DC" + + "4F8BD476CF8328EEB71B3D873D6B7B859C9B21065638FF95", + "8570DA3D47E1E160" + + "5CF3E44B8D328B995EFC64107B6292D1B1036B5F88CE3160" + + "2F12BEB71D801C0942E7C0864B3DB67A9356DB203490D881" + + "24FE86BCE38AC2269B4FDA6ABAA884039DF80A0336A24D79" + + "1EB3067C8F5F0CF0F18DD73B66A7B316FB19E02835CC6293" + + "65FCD1D3BE640178ED9093B91B36E1D68135F2785BFF505C"}) + .addAdditionalInput( + "606162636465666768696A6B6C6D6E" + + "6F707172737475767778797A7B7C7D7E7F80818283848586" + + "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" + + "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE") + .addAdditionalInput( + "A0A1A2A3A4A5A6A7A8A9AAABACADAE" + + "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" + + "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" + + "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" + + "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E"), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[]{ + "AAE4DC3C9ECC74D9" + + "061DD527117EF3D29E1E52B26853C539D6CA797E8DA3D0BB" + + "171D8E30B8B194D8C28F7F6BE3B986B88506DC6A01B294A7" + + "165DD1C3470F7BE7B396AA0DB7D50C4051E7C7E1C8A7D21A" + + "2B5878C0BCB163CAA79366E7A1162FDC88429616CD3E6977" + + "8D327520A6BBBF71D8AA2E03EC4A9DAA0E77CF93E1EE30D2 ", + "129FF6D31A23FFBC" + + "870632B35EE477C2280DDD2ECDABEDB900C78418BE2D243B" + + "B9D8E5093ECE7B6BF48638D8F704D134ADDEB7F4E9D5C142" + + "CD05683E72B516486AF24AEC15D61E81E270DD4EBED91B62" + + "12EB8896A6250D5C8BC3A4A12F7E3068FBDF856F47EB23D3" + + "79F82C1EBCD1585FB260B9C0C42625FBCEE68CAD773CD5B1"}) + .setPersonalizationString( + "404142434445464748494A4B4C4D4E" + + "4F505152535455565758595A5B5C5D5E5F60616263646566" + + "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" + + "7F808182838485868788898A8B8C8D8E8F90919293949596" + + "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[]{ + "B8E827652175E6E0" + + "6E513C7BE94B5810C14ED94AD903647940CAEB7EE014C848" + + "8DCBBE6D4D6616D06656A3DC707CDAC4F02EE6D8408C065F" + + "CB068C0760DA47C5D60E5D70D09DC3929B6979615D117F7B" + + "EDCC661A98514B3A1F55B2CBABDCA59F11823E4838065F1F" + + "8431CBF28A577738234AF3F188C7190CC19739E72E9BBFFF", + "7ED41B9CFDC8C256" + + "83BBB4C553CC2DC61F690E62ABC9F038A16B8C519690CABE" + + "BD1B5C196C57CF759BB9871BE0C163A57315EA96F615136D" + + "064572F09F26D659D24211F9610FFCDFFDA8CE23FFA96735" + + "7595182660877766035EED800B05364CE324A75EB63FD9B3" + + "EED956D147480B1D0A42DF8AA990BB628666F6F61D60CBE2"}) + .setPersonalizationString( + "404142434445464748494A4B4C4D4E" + + "4F505152535455565758595A5B5C5D5E5F60616263646566" + + "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" + + "7F808182838485868788898A8B8C8D8E8F90919293949596" + + "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE") + .addAdditionalInput( + "606162636465666768696A6B6C6D6E" + + "6F707172737475767778797A7B7C7D7E7F80818283848586" + + "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" + + "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE") + .addAdditionalInput( + "A0A1A2A3A4A5A6A7A8A9AAABACADAE" + + "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" + + "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" + + "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" + + "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E") + }; + } + + public void performTest() + throws Exception + { + DRBGTestVector[] tests = createTestVectorData(); + + for (int i = 0; i != tests.length; i++) + { + DRBGTestVector tv = tests[i]; + + byte[] nonce = tv.nonce(); + byte[] personalisationString = tv.personalizationString(); + + SP80090DRBG d = new HMacSP800DRBG(new HMac(tv.getDigest()), tv.securityStrength(), tv.entropySource(), personalisationString, nonce); + + byte[] output = new byte[tv.expectedValue(0).length]; + + d.generate(output, tv.additionalInput(0), tv.predictionResistance()); + + byte[] expected = tv.expectedValue(0); + + if (!areEqual(expected, output)) + { + fail("Test #" + (i + 1) + ".1 failed, expected " + new String(Hex.encode(tv.expectedValue(0))) + " got " + new String(Hex.encode(output))); + } + + output = new byte[tv.expectedValue(0).length]; + + d.generate(output, tv.additionalInput(1), tv.predictionResistance()); + + expected = tv.expectedValue(1); + if (!areEqual(expected, output)) + { + fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output))); + } + } + + // Exception tests + // + SP80090DRBG d; + try + { + d = new HMacSP800DRBG(new HMac(new SHA256Digest()), 256, new SHA256EntropyProvider().get(128), null, null); + fail("no exception thrown"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("Not enough entropy for security strength required")) + { + fail("Wrong exception", e); + } + } + } + + private class SHA1EntropyProvider + extends TestEntropySourceProvider + { + SHA1EntropyProvider() + { + super( + Hex.decode( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F30313233343536" + + "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6"), true); + } + } + + private class SHA256EntropyProvider + extends TestEntropySourceProvider + { + SHA256EntropyProvider() + { + super(Hex.decode( + "00010203040506" + + "0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E" + + "1F202122232425262728292A2B2C2D2E2F30313233343536" + + "80818283848586" + + "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" + + "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "C0C1C2C3C4C5C6" + + "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" + + "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6"), true); + } + } + + private class SHA384EntropyProvider + extends TestEntropySourceProvider + { + SHA384EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223242526" + + "2728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556" + + "5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E" + + "808182838485868788898A8B8C8D8E" + + "8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6" + + "A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBE" + + "BFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6" + + "D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCE" + + "CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6" + + "E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFE" + + "FF000102030405060708090A0B0C0D0E0F10111213141516" + + "1718191A1B1C1D1E1F202122232425262728292A2B2C2D2E"), true); + } + } + + private class SHA512EntropyProvider + extends TestEntropySourceProvider + { + SHA512EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E" + + "0F101112131415161718191A1B1C1D1E1F20212223242526" + + "2728292A2B2C2D2E2F303132333435363738393A3B3C3D3E" + + "3F404142434445464748494A4B4C4D4E4F50515253545556" + + "5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E" + + "808182838485868788898A8B8C8D8E" + + "8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6" + + "A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBE" + + "BFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6" + + "D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCE" + + "CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6" + + "E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFE" + + "FF000102030405060708090A0B0C0D0E0F10111213141516" + + "1718191A1B1C1D1E1F202122232425262728292A2B2C2D2E"), true); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/HashDRBGTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/HashDRBGTest.java new file mode 100644 index 000000000..e416e7b86 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/HashDRBGTest.java @@ -0,0 +1,481 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA384Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.prng.drbg.HashSP800DRBG; +import com.fr.third.org.bouncycastle.crypto.prng.drbg.SP80090DRBG; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * DRBG Test + */ +public class HashDRBGTest + extends SimpleTest +{ + public String getName() + { + return "HashDRBG"; + } + + public static void main(String[] args) + { + runTest(new HashDRBGTest()); + } + + private DRBGTestVector[] createTestVectorData() + { + return new DRBGTestVector[] + { + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + false, + "2021222324", + 80, + new String[] + { + "9F7CFF1ECA23E750F66326969F11800F12088BA68E441D15D888B3FE12BF66FE057494F4546DE2F1", + "B77AA5C0CD55BBCEED7574AF223AFD988C7EEC8EFF4A94E5E89D26A04F58FA79F5E0D3702D7A9A6A" + } + ), + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + false, + "2021222324", + 80, + new String[] + { + "AB438BD3B01A0AF85CFEE29F7D7B71621C4908B909124D430E7B406FB1086EA994C582E0D656D989", + "29D9098F987E7005314A0F51B3DD2B8122F4AED706735DE6AD5DDBF223177C1E5F3AEBC52FAB90B9" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"), + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + false, + "2021222324", + 80, + new String[] + { + "E76B4EDD5C865BC8AFD809A59B69B429AC7F4352A579BCF3F75E56249A3491F87C3CA6848B0FAB25", + "6577B6B4F87A93240B199FE51A3B335313683103DECE171E3256FB7E803586CA4E45DD242EB01F70" + }) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90919293949596") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6"), + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + true, + "2021222324", + 80, + new String[] + { + "56EF4913373994D5539F4D7D17AFE7448CDF5E72416CC6A71A340059FA0D5AE526B23250C46C0944", + "575B37A2739814F966C63B60A2C4F149CA9ACC84FC4B25493289B085C67B2E30F5F0B99A2C349E2A" + }), + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + true, + "2021222324", + 80, + new String[] + { + "532CA1165DCFF21C55592687639884AF4BC4B057DF8F41DE653AB44E2ADEC7C9303E75ABE277EDBF", + "73C2C67C696D686D0C4DBCEB5C2AF7DDF6F020B6874FAE4390F102117ECAAFF54418529A367005A0" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"), + new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + true, + "2021222324", + 80, + new String[] + { + "183C242A1430E46C4ED70B4DBE1BF9AB0AB8721CDCA2A2D1820AD6F6C956858543B2AA191D8D1287", + "F196F9BD021C745CBD5AC7BFCE48EAAF0D0E7C091FBF436940E63A198EE770D9A4F0718669AF2BC9" + }) + .addAdditionalInput("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90919293949596") + .addAdditionalInput("A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6"), + new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(440), + false, + "2021222324252627", + 128, + new String[] + { + "77E05A0E7DC78AB5D8934D5E93E82C06" + + "A07C04CEE6C9C53045EEB485872777CF3B3E35C474F976B8" + + "94BF301A86FA651F463970E89D4A0534B2ECAD29EC044E7E", + "5FF4BA493C40CFFF3B01E472C575668C" + + "CE3880B9290B05BFEDE5EC96ED5E9B2898508B09BC800EEE" + + "099A3C90602ABD4B1D4F343D497C6055C87BB956D53BF351" + } + ), + new DRBGTestVector( + new SHA256Digest(), + new SHA256EntropyProvider().get(440), + true, + "2021222324252627", + 128, + new String[] + { + "92275523C70E567BCF9B35EC50B933F8" + + "12616DF586B7F72EE1BC7735A5C2654373CBBC72316DFF84" + + "20A33BF02B97AC8D1952583F270ACD7005CC027F4CF1187E", + "681A46B2AA8694A0FE4DEEA720927A84" + + "EAAA985E59C19F8BE0984D8CBEF8C69B754167641946E040" + + "EE2043E1CCB29DCF063C0A50830E428E6DCA262ECD77C542" + }), + new DRBGTestVector( + new SHA384Digest(), + new SHA384EntropyProvider().get(888), + false, + "202122232425262728292A2B", + 192, + new String[] + { + "04FF23AD15E78790ADD36B438BBC097C7A11747CC2CCEEDE" + + "2C978B23B3DC63B732C953061D7764990ABFEFC47A581B92" + + "1BC0428C4F12212460E406A0F0651E7F0CB9A90ABFDB07B5" + + "25565C74F0AA085082F6CF213AAFAD0C0646895078F1E1FE", + "4F35B85F95DEE3E873054905CFD02341653E18F529930CBE" + + "14D909F37FEAF2C790D22FAE7516B4590BE35D53E2FE1A35" + + "AFE4B6607CB358589C3B4D094A1D81FE0717F1DF5BDDEB3E" + + "114F130BB781E66C22B5B770E8AE115FF39F8ADAF66DEEDF" + } + ), + new DRBGTestVector( + new SHA384Digest(), + new SHA384EntropyProvider().get(888), + true, + "202122232425262728292A2B", + 192, + new String[] + { + "97993B78F7C31C0E876DC92EB7D6C408E09D608AD6B99D0E" + + "A2229B05A578C426334FCC8A1C7E676ED2D89A5B4CDF5B3F" + + "4ADF11936BF14F4E10909DBA9C24F4FDFFDE72351DA8E2CC" + + "3B135A395373899E5F1A5955B880CA9B9E9DD4C9CA7FA4D4", + "F5983946320E36C64EF283CA1F65D197CF81624EC6778E77" + + "0E78949D84EF21A45CDD62D1DB76920D4C2836FC6AE5299F" + + "AF1357D9701FAD10FBD88D1E2832239436D76EB271BDC3CA" + + "04425EC88BC0E89A4D5C37FFCE7C6C3ABDE9C413AE6D3FEA" + } + ), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + false, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "DA126CF95C6BF97E" + + "2F731F2137A907ACC70FD7AC9EBACD1C6E31C74029B052E3" + + "AABC48F3B00993F2B2381F7650A55322A968C86E05DE88E6" + + "367F6EF89A601DB4342E9086C7AC13B5E56C32E9E668040B" + + "73847893C5BFD38A1CF44F348B4EEE4CD68ADB7E7B8C837F" + + "19BC4F902761F7CFF24AB1D704FD11C4E929D8553753B55D", + "400B977CE8A2BB6A" + + "84C6FD1CF901459685ABF5408CFF4588CEDF52E2D2DC300A" + + "A9B4FAED8CD0161C2172B1FD269253195883D6EBF21020F2" + + "C20E5F2C81AE60C8595B834A229B1F5B726C1125717E6207" + + "8886EF38E61E32707AD5F8116C6393DFB6E7C7AE0E8E92BB" + + "D7E0C3D04BBA02F5169F2F569A58158915FEE4C9D28D45DB" + } + ) + .setPersonalizationString( + "404142434445464748494A4B4C4D4E" + + "4F505152535455565758595A5B5C5D5E5F60616263646566" + + "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" + + "7F808182838485868788898A8B8C8D8E8F90919293949596" + + "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE") + .addAdditionalInput( + "606162636465666768696A6B6C6D6E" + + "6F707172737475767778797A7B7C7D7E7F80818283848586" + + "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" + + "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE") + .addAdditionalInput( + "A0A1A2A3A4A5A6A7A8A9AAABACADAE" + + "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" + + "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" + + "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" + + "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E"), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "F93CA6855590A77F" + + "07354097E90E026648B6115DF008FFEDBD9D9811F54E8286" + + "EF00FDD6BA1E58DF2535E3FBDD9A9BA3754A97F36EE83322" + + "1582060A1F37FCE4EE8826636B28EAD589593F4CA8B64738" + + "8F24EB3F0A34796968D21BDEE6F81FD5DF93536F935937B8" + + "025EC8CBF57DDB0C61F2E41463CC1516D657DA2829C6BF90", + "4817618F48C60FB1" + + "CE5BFBDA0CAF4591882A31F6EE3FE0F78779992A06EC60F3" + + "7FB9A8D6108C231F0A927754B0599FA4FA27A4E25E065EF0" + + "3085B892979DC0E7A1080883CAEBFDFD3665A8F2D061C521" + + "F7D6E3DA2AF8B97B6B43B6EC831AF515070A83BBB9AC95ED" + + "4EF49B756A2377A5F0833D847E27A88DDB0C2CE4AD782E7B " + } + ), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "0455DD4AD7DBACB2" + + "410BE58DF7248D765A4547ABAEE1743B0BCAD37EBD06DA7C" + + "F7CE5E2216E525327E9E2005EBEF2CE53BD733B18128627D" + + "3FD6153089373AF2606A1584646A0EA488BFEF45228699A0" + + "89CEA8AEC44502D86D9591F3552C688B7F7B45FCB0C3C2B9" + + "43C1CD8A6FC63DF4D81C3DA543C9CF2843855EA84E4F959C", + "C047D46D7F614E4E" + + "4A7952C79A451F8F7ACA379967E2977C401C626A2ED70D74" + + "A63660579A354115BC8C8C8CC3AEA3050686A0CFCDB6FA9C" + + "F78D4C2165BAF851C6F9B1CD16A2E14C15C6DAAC56C16E75" + + "FC84A14D58B41622E88B0F1B1995587FD8BAA999CBA98025" + + "4C8AB9A9691DF7B84D88B639A9A3106DEABEB63748B99C09" + } + ) + .addAdditionalInput( + "606162636465666768696A6B6C6D6E" + + "6F707172737475767778797A7B7C7D7E7F80818283848586" + + "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" + + "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE") + .addAdditionalInput( + "A0A1A2A3A4A5A6A7A8A9AAABACADAE" + + "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" + + "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" + + "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" + + "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E"), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "22EB93A67911DA73" + + "85D9180C78127DE1A04FF713114C07C9C615F7CC5EF72744" + + "A2DDCD7C3CB85E65DED8EF5F240FBDCBEBBDE2BAAC8ECF7D" + + "CBC8AC333E54607AD41DC495D83DF72A05EF55B127C1441C" + + "9A0EFFDA2C7954DB6C2D04342EB812E5E0B11D6C395F41ED" + + "A2702ECE5BA479E2DFA18F953097492636C12FE30CE5C968", + "E66698CFBF1B3F2E" + + "919C03036E584EAA81CF1C6666240AF05F70637043733954" + + "D8A1E5A66A04C53C6900FDC145D4A3A80A31F5868ACE9AC9" + + "4E14E2051F624A05EEA1F8B684AA5410BCE315E76EA07C71" + + "5D6F34731320FF0DCF78D795E6EFA2DF92B98BE636CDFBA2" + + "9008DD392112AEC202F2E481CB9D83F987FEA69CD1B368BB" + } + ) + .setPersonalizationString( + "404142434445464748494A4B4C4D4E" + + "4F505152535455565758595A5B5C5D5E5F60616263646566" + + "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" + + "7F808182838485868788898A8B8C8D8E8F90919293949596" + + "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE"), + new DRBGTestVector( + new SHA512Digest(), + new SHA512EntropyProvider().get(888), + true, + "202122232425262728292A2B2C2D2E2F", + 256, + new String[] + { + "7596A76372308BD5" + + "A5613439934678B35521A94D81ABFE63A21ACF61ABB88B61" + + "E86A12C37F308F2BBBE32BE4B38D03AE808386494D70EF52" + + "E9E1365DD18B7784CAB826F31D47579E4D57F69D8BF3152B" + + "95741946CEBE58571DF58ED39980D9AF44E69F01E8989759" + + "8E40171101A0E3302838E0AD9E849C01988993CF9F6E5263", + "DBE5EE36FCD85301" + + "303E1C3617C1AC5E23C08885D0BEFAAD0C85A0D89F85B9F1" + + "6ECE3D88A24EB96504F2F13EFA7049621782F5DE2C416A0D" + + "294CCFE53545C4E309C48E1E285A2B829A574B72B3C2FBE1" + + "34D01E3706B486F2401B9820E17298A342666918E15B8462" + + "87F8C5AF2D96B20FAF3D0BB392E15F4A06CDB0DECD1B6AD7" + } + ) + .setPersonalizationString( + "404142434445464748494A4B4C4D4E" + + "4F505152535455565758595A5B5C5D5E5F60616263646566" + + "6768696A6B6C6D6E6F707172737475767778797A7B7C7D7E" + + "7F808182838485868788898A8B8C8D8E8F90919293949596" + + "9798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAE") + .addAdditionalInput( + "606162636465666768696A6B6C6D6E" + + "6F707172737475767778797A7B7C7D7E7F80818283848586" + + "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" + + "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE") + .addAdditionalInput( + "A0A1A2A3A4A5A6A7A8A9AAABACADAE" + + "AFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6" + + "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" + + "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6" + + "F7F8F9FAFBFCFDFEFF000102030405060708090A0B0C0D0E") + }; + } + + public void performTest() + throws Exception + { + DRBGTestVector[] tests = createTestVectorData(); + + for (int i = 0; i != tests.length; i++) + { + DRBGTestVector tv = tests[i]; + + byte[] nonce = tv.nonce(); + byte[] personalisationString = tv.personalizationString(); + + SP80090DRBG d = new HashSP800DRBG(tv.getDigest(), tv.securityStrength(), tv.entropySource(), personalisationString, nonce); + + byte[] output = new byte[tv.expectedValue(0).length]; + + d.generate(output, tv.additionalInput(0), tv.predictionResistance()); + + byte[] expected = tv.expectedValue(0); + + if (!areEqual(expected, output)) + { + fail("Test #" + (i + 1) + ".1 failed, expected " + new String(Hex.encode(tv.expectedValue(0))) + " got " + new String(Hex.encode(output))); + } + + output = new byte[tv.expectedValue(0).length]; + + d.generate(output, tv.additionalInput(1), tv.predictionResistance()); + + expected = tv.expectedValue(1); + if (!areEqual(expected, output)) + { + fail("Test #" + (i + 1) + ".2 failed, expected " + new String(Hex.encode(tv.expectedValue(1))) + " got " + new String(Hex.encode(output))); + } + } + + // Exception tests + // + SP80090DRBG d; + try + { + d = new HashSP800DRBG(new SHA256Digest(), 256, new SHA256EntropyProvider().get(128), null, null); + fail("no exception thrown"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("Not enough entropy for security strength required")) + { + fail("Wrong exception", e); + } + } + + try + { + d = new HashSP800DRBG(new SHA1Digest(), 256, new SHA256EntropyProvider().get(256), null, null); + fail("no exception thrown"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("Requested security strength is not supported by the derivation function")) + { + fail("Wrong exception", e); + } + } + } + + private class SHA1EntropyProvider + extends TestEntropySourceProvider + { + SHA1EntropyProvider() + { + super( + Hex.decode( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F30313233343536" + + "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6"), true); + } + } + + private class SHA256EntropyProvider + extends TestEntropySourceProvider + { + SHA256EntropyProvider() + { + super(Hex.decode( + "00010203040506" + + "0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E" + + "1F202122232425262728292A2B2C2D2E2F30313233343536" + + "80818283848586" + + "8788898A8B8C8D8E8F909192939495969798999A9B9C9D9E" + + "9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "C0C1C2C3C4C5C6" + + "C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDE" + + "DFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6"), true); + } + } + + private class SHA384EntropyProvider + extends TestEntropySourceProvider + { + SHA384EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20212223242526" + + "2728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556" + + "5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E" + + "808182838485868788898A8B8C8D8E" + + "8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6" + + "A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBE" + + "BFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6" + + "D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCE" + + "CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6" + + "E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFE" + + "FF000102030405060708090A0B0C0D0E0F10111213141516" + + "1718191A1B1C1D1E1F202122232425262728292A2B2C2D2E"), true); + } + } + + private class SHA512EntropyProvider + extends TestEntropySourceProvider + { + SHA512EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E" + + "0F101112131415161718191A1B1C1D1E1F20212223242526" + + "2728292A2B2C2D2E2F303132333435363738393A3B3C3D3E" + + "3F404142434445464748494A4B4C4D4E4F50515253545556" + + "5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E" + + "808182838485868788898A8B8C8D8E" + + "8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6" + + "A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBE" + + "BFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6" + + "D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEE" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCE" + + "CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6" + + "E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFE" + + "FF000102030405060708090A0B0C0D0E0F10111213141516" + + "1718191A1B1C1D1E1F202122232425262728292A2B2C2D2E"), true); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/RegressionTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/RegressionTest.java new file mode 100644 index 000000000..7628a41a5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/RegressionTest.java @@ -0,0 +1,22 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.Test; + +public class RegressionTest +{ + public static Test[] tests = { + new CTRDRBGTest(), + new DualECDRBGTest(), + new HashDRBGTest(), + new HMacDRBGTest(), + new SP800RandomTest(), + new X931Test(), + new FixedSecureRandomTest() + }; + + public static void main(String[] args) + { + SimpleTest.runTests(tests); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/SP800RandomTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/SP800RandomTest.java new file mode 100644 index 000000000..2eeb83029 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/SP800RandomTest.java @@ -0,0 +1,288 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.prng.BasicEntropySourceProvider; +import com.fr.third.org.bouncycastle.crypto.prng.SP800SecureRandomBuilder; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SP800RandomTest + extends SimpleTest +{ + + public String getName() + { + return "SP800RandomTest"; + } + + private void testHashRandom() + { + DRBGTestVector tv = new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + true, + "2021222324", + 80, + new String[] + { + "532CA1165DCFF21C55592687639884AF4BC4B057DF8F41DE653AB44E2ADEC7C9303E75ABE277EDBF", + "73C2C67C696D686D0C4DBCEB5C2AF7DDF6F020B6874FAE4390F102117ECAAFF54418529A367005A0" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"); + + doHashTest(0, tv); + + tv = new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + false, + "2021222324", + 80, + new String[] + { + "AB438BD3B01A0AF85CFEE29F7D7B71621C4908B909124D430E7B406FB1086EA994C582E0D656D989", + "29D9098F987E7005314A0F51B3DD2B8122F4AED706735DE6AD5DDBF223177C1E5F3AEBC52FAB90B9" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"); + + doHashTest(1, tv); + } + + private void doHashTest(int index, DRBGTestVector tv) + { + SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(new SHA1EntropyProvider()); + + rBuild.setPersonalizationString(tv.personalizationString()); + rBuild.setSecurityStrength(tv.securityStrength()); + rBuild.setEntropyBitsRequired(tv.entropySource().getEntropy().length * 8); + + SecureRandom random = rBuild.buildHash(tv.getDigest(), tv.nonce(), tv.predictionResistance()); + + byte[] expected = tv.expectedValue(0); + byte[] produced = new byte[expected.length]; + + random.nextBytes(produced); + + if (!Arrays.areEqual(expected, produced)) + { + fail(index + " SP800 Hash SecureRandom produced incorrect result (1)"); + } + + random.nextBytes(produced); + expected = tv.expectedValue(1); + + if (!Arrays.areEqual(expected, produced)) + { + fail(index + " SP800 Hash SecureRandom produced incorrect result (2)"); + } + } + + private void testHMACRandom() + { + DRBGTestVector tv = new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + true, + "2021222324", + 80, + new String[] + { + "6C37FDD729AA40F80BC6AB08CA7CC649794F6998B57081E4220F22C5C283E2C91B8E305AB869C625", + "CAF57DCFEA393B9236BF691FA456FEA7FDF1DF8361482CA54D5FA723F4C88B4FA504BF03277FA783" + }) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F70717273747576"); + + doHMACTest(tv); + + tv = new DRBGTestVector( + new SHA1Digest(), + new SHA1EntropyProvider().get(440), + false, + "2021222324", + 80, + new String[] + { + "5A7D3B449F481CB38DF79AD2B1FCC01E57F8135E8C0B22CD0630BFB0127FB5408C8EFC17A929896E", + "82cf772ec3e84b00fc74f5df104efbfb2428554e9ce367d03aeade37827fa8e9cb6a08196115d948" + }); + + doHMACTest(tv); + } + + private void doHMACTest(DRBGTestVector tv) + { + SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(new SHA1EntropyProvider()); + + rBuild.setPersonalizationString(tv.personalizationString()); + rBuild.setSecurityStrength(tv.securityStrength()); + rBuild.setEntropyBitsRequired(tv.entropySource().getEntropy().length * 8); + + SecureRandom random = rBuild.buildHMAC(new HMac(tv.getDigest()), tv.nonce(), tv.predictionResistance()); + + byte[] expected = tv.expectedValue(0); + byte[] produced = new byte[expected.length]; + + random.nextBytes(produced); + if (!Arrays.areEqual(expected, produced)) + { + fail("SP800 HMAC SecureRandom produced incorrect result (1)"); + } + + random.nextBytes(produced); + expected = tv.expectedValue(1); + + if (!Arrays.areEqual(expected, produced)) + { + fail("SP800 HMAC SecureRandom produced incorrect result (2)"); + } + } + + private void testCTRRandom() + { + DRBGTestVector tv = new DRBGTestVector( + new DESedeEngine(), 168, + new Bit232EntropyProvider().get(232), + false, + "20212223242526", + 112, + new String[] + { + "ABC88224514D0316EA3D48AEE3C9A2B4", + "D3D3F372E43E7ABDC4FA293743EED076" + } + ); + + doCTRTest(tv); + + tv = new DRBGTestVector( + new DESedeEngine(), 168, + new Bit232EntropyProvider().get(232), + true, + "20212223242526", + 112, + new String[] + { + "64983055D014550B39DE699E43130B64", + "035FDDA8582A2214EC722C410A8D95D3" + } + ) + .setPersonalizationString("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C"); + + doCTRTest(tv); + } + + private void doCTRTest(DRBGTestVector tv) + { + SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(new Bit232EntropyProvider()); + + rBuild.setPersonalizationString(tv.personalizationString()); + rBuild.setSecurityStrength(tv.securityStrength()); + rBuild.setEntropyBitsRequired(tv.entropySource().getEntropy().length * 8); + + SecureRandom random = rBuild.buildCTR(tv.getCipher(), tv.keySizeInBits(), tv.nonce(), tv.predictionResistance()); + + byte[] expected = tv.expectedValue(0); + byte[] produced = new byte[expected.length]; + + random.nextBytes(produced); + if (!Arrays.areEqual(expected, produced)) + { + fail("SP800 CTR SecureRandom produced incorrect result (1)"); + } + + random.nextBytes(produced); + expected = tv.expectedValue(1); + + if (!Arrays.areEqual(expected, produced)) + { + fail("SP800 CTR SecureRandom produced incorrect result (2)"); + } + } + + private void testGenerateSeed() + { + SP800SecureRandomBuilder rBuild = new SP800SecureRandomBuilder(new Bit232EntropyProvider()); + + rBuild.setPersonalizationString(Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C")); + rBuild.setSecurityStrength(112); + rBuild.setEntropyBitsRequired(232); + + SecureRandom random = rBuild.buildCTR(new DESedeEngine(), 168, Hex.decode("20212223242526"), false); + + rBuild = new SP800SecureRandomBuilder(new BasicEntropySourceProvider(random, false)); + + rBuild.setPersonalizationString(Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C")); + rBuild.setSecurityStrength(112); + rBuild.setEntropyBitsRequired(232); + + random = rBuild.buildCTR(new DESedeEngine(), 168, Hex.decode("20212223242526"), false); + + byte[] expected = Hex.decode("760bed7d92b083b10af31cf0656081eb51d241f0"); + + byte[] produced = random.generateSeed(20); + + if (!Arrays.areEqual(expected, produced)) + { + fail("SP800 CTR SecureRandom.generateSeed() produced incorrect result (1)"); + } + } + + public void performTest() + throws Exception + { + testHashRandom(); + testHMACRandom(); + testCTRRandom(); + testGenerateSeed(); + } + + public static void main(String[] args) + { + runTest(new SP800RandomTest()); + } + + // for HMAC/Hash + private class SHA1EntropyProvider + extends TestEntropySourceProvider + { + SHA1EntropyProvider() + { + super( + Hex.decode( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F30313233343536" + + "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6"), true); + } + } + + // for Dual EC + private class SHA256EntropyProvider + extends TestEntropySourceProvider + { + SHA256EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F " + + "808182838485868788898A8B8C8D8E8F" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECF"), true); + } + } + + private class Bit232EntropyProvider + extends TestEntropySourceProvider + { + Bit232EntropyProvider() + { + super(Hex.decode( + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C" + + "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C" + + "C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDC"), true); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/TestEntropySourceProvider.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/TestEntropySourceProvider.java new file mode 100644 index 000000000..04f9095b8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/TestEntropySourceProvider.java @@ -0,0 +1,46 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import com.fr.third.org.bouncycastle.crypto.prng.EntropySource; +import com.fr.third.org.bouncycastle.crypto.prng.EntropySourceProvider; + +public class TestEntropySourceProvider + implements EntropySourceProvider +{ + private final byte[] data; + private final boolean isPredictionResistant; + + protected TestEntropySourceProvider(byte[] data, boolean isPredictionResistant) + { + this.data = data; + this.isPredictionResistant = isPredictionResistant; + } + + public EntropySource get(final int bitsRequired) + { + return new EntropySource() + { + int index = 0; + + public boolean isPredictionResistant() + { + return isPredictionResistant; + } + + public byte[] getEntropy() + { + byte[] rv = new byte[bitsRequired / 8]; + + System.arraycopy(data, index, rv, 0, rv.length); + + index += bitsRequired / 8; + + return rv; + } + + public int entropySize() + { + return bitsRequired; + } + }; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/X931Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/X931Test.java new file mode 100644 index 000000000..6086e1b10 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/X931Test.java @@ -0,0 +1,124 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.prng.X931SecureRandomBuilder; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * HMAC SP800-90 DRBG + */ +public class X931Test + extends SimpleTest +{ + public String getName() + { + return "X931"; + } + + public static void main(String[] args) + { + runTest(new X931Test()); + } + + private X931TestVector[] createTestVectorData() + { + return new X931TestVector[] + { + new X931TestVector( + new AESEngine(), + new AES128EntropyProvider(), + "f7d36762b9915f1ed585eb8e91700eb2", + "259e67249288597a4d61e7c0e690afae", + false, + new String[] { + "15f013af5a8e9df9a8e37500edaeac43", + "a9d74bb1c90a222adc398546d64879cf", + "0379e404042d58180764fb9e6c5d94bb", + "3c74603e036d28c79947ffb56fee4e51", + "e872101a4df81ebbe1e632fc87195d52", + "26a6b3d33b8e7e68b75d9630ec036314" }), + new X931TestVector( + new DESedeEngine(), + new TDESEntropyProvider(), + "ef16ec643e5db5892cbc6eabba310b3410e6f8759e3e382c", + "55df103deaf68dc4", + false, + new String[] { + "9c960bb9662ce6de", + "d9d0e527fd0931da", + "3e2db9994e9e6995", + "0e3868aef8218cf7", + "7b0b0ca137f8fd81", + "f657df270ad12265" }) + }; + } + + public void performTest() + throws Exception + { + X931TestVector[] vectors = createTestVectorData(); + + for (int i = 0; i != vectors.length; i++) + { + X931TestVector tv = vectors[i]; + X931SecureRandomBuilder bld = new X931SecureRandomBuilder(tv.getEntropyProvider()); + + bld.setDateTimeVector(Hex.decode(tv.getDateTimeVector())); + + SecureRandom rand = bld.build(tv.getEngine(), new KeyParameter(Hex.decode(tv.getKey())), tv.isPredictionResistant()); + + for (int j = 0; j != tv.getExpected().length - 1; j++) + { + byte[] expected = Hex.decode(tv.getExpected()[j]); + byte[] res = new byte[expected.length]; + + rand.nextBytes(res); + + if (!Arrays.areEqual(expected, res)) + { + fail("expected output wrong [" + j + "] got : " + Strings.fromByteArray(Hex.encode(res))); + } + } + + byte[] expected = Hex.decode(tv.getExpected()[tv.getExpected().length - 1]); + byte[] res = new byte[expected.length]; + + for (int j = tv.getExpected().length - 1; j != 10000; j++) + { + rand.nextBytes(res); + } + + if (!Arrays.areEqual(expected, res)) + { + fail("expected output wrong [" + 10000 + "] got : " + Strings.fromByteArray(Hex.encode(res))); + } + } + } + + private class AES128EntropyProvider + extends TestEntropySourceProvider + { + AES128EntropyProvider() + { + super(Hex.decode( + "35cc0ea481fc8a4f5f05c7d4667233b2"), true); + } + } + + private class TDESEntropyProvider + extends TestEntropySourceProvider + { + TDESEntropyProvider() + { + super(Hex.decode( + "96d872b9122c5e74"), true); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/X931TestVector.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/X931TestVector.java new file mode 100644 index 000000000..8adfef282 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/prng/test/X931TestVector.java @@ -0,0 +1,56 @@ +package com.fr.third.org.bouncycastle.crypto.prng.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.prng.EntropySourceProvider; + +public class X931TestVector +{ + private final BlockCipher engine; + private final EntropySourceProvider entropyProvider; + private final String key; + private final String dateTimeVector; + private final boolean predictionResistant; + private final String[] expected; + + public X931TestVector(BlockCipher engine, EntropySourceProvider entropyProvider, String key, String dateTimeVector, boolean predictionResistant, String[] expected) + { + this.engine = engine; + this.entropyProvider = entropyProvider; + this.key = key; + + + this.dateTimeVector = dateTimeVector; + this.predictionResistant = predictionResistant; + this.expected = expected; + } + + public String getDateTimeVector() + { + return dateTimeVector; + } + + public BlockCipher getEngine() + { + return engine; + } + + public EntropySourceProvider getEntropyProvider() + { + return entropyProvider; + } + + public String[] getExpected() + { + return expected; + } + + public String getKey() + { + return key; + } + + public boolean isPredictionResistant() + { + return predictionResistant; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSADigestSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSADigestSigner.java index 88fb08a0f..4097df950 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSADigestSigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSADigestSigner.java @@ -1,16 +1,10 @@ package com.fr.third.org.bouncycastle.crypto.signers; -import java.io.IOException; import java.math.BigInteger; -import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; -import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; -import com.fr.third.org.bouncycastle.asn1.ASN1Integer; -import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; -import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; -import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.Signer; import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; @@ -19,16 +13,28 @@ import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; public class DSADigestSigner implements Signer { + private final DSA dsa; private final Digest digest; - private final DSA dsaSigner; + private final DSAEncoding encoding; private boolean forSigning; public DSADigestSigner( - DSA signer, - Digest digest) + DSA dsa, + Digest digest) { + this.dsa = dsa; this.digest = digest; - this.dsaSigner = signer; + this.encoding = StandardDSAEncoding.INSTANCE; + } + + public DSADigestSigner( + DSAExt dsa, + Digest digest, + DSAEncoding encoding) + { + this.dsa = dsa; + this.digest = digest; + this.encoding = encoding; } public void init( @@ -60,7 +66,7 @@ public class DSADigestSigner reset(); - dsaSigner.init(forSigning, parameters); + dsa.init(forSigning, parameters); } /** @@ -97,13 +103,13 @@ public class DSADigestSigner byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); - BigInteger[] sig = dsaSigner.generateSignature(hash); + BigInteger[] sig = dsa.generateSignature(hash); try { - return derEncode(sig[0], sig[1]); + return encoding.encode(getOrder(), sig[0], sig[1]); } - catch (IOException e) + catch (Exception e) { throw new IllegalStateException("unable to encode signature"); } @@ -122,10 +128,11 @@ public class DSADigestSigner try { - BigInteger[] sig = derDecode(signature); - return dsaSigner.verifySignature(hash, sig[0], sig[1]); + BigInteger[] sig = encoding.decode(getOrder(), signature); + + return dsa.verifySignature(hash, sig[0], sig[1]); } - catch (IOException e) + catch (Exception e) { return false; } @@ -136,28 +143,8 @@ public class DSADigestSigner digest.reset(); } - private byte[] derEncode( - BigInteger r, - BigInteger s) - throws IOException + protected BigInteger getOrder() { - ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1Integer(r)); - v.add(new ASN1Integer(s)); - - return new DERSequence(v).getEncoded(ASN1Encoding.DER); - } - - private BigInteger[] derDecode( - byte[] encoding) - throws IOException - { - ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); - - return new BigInteger[] - { - ((ASN1Integer)s.getObjectAt(0)).getValue(), - ((ASN1Integer)s.getObjectAt(1)).getValue() - }; + return dsa instanceof DSAExt ? ((DSAExt)dsa).getOrder() : null; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSAEncoding.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSAEncoding.java new file mode 100644 index 000000000..c9676c373 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSAEncoding.java @@ -0,0 +1,31 @@ +package com.fr.third.org.bouncycastle.crypto.signers; + +import java.io.IOException; +import java.math.BigInteger; + +/** + * An interface for different encoding formats for DSA signatures. + */ +public interface DSAEncoding +{ + /** + * Decode the (r, s) pair of a DSA signature. + * + * @param n the order of the group that r, s belong to. + * @param encoding an encoding of the (r, s) pair of a DSA signature. + * @return the (r, s) of a DSA signature, stored in an array of exactly two elements, r followed by s. + * @throws IOException + */ + BigInteger[] decode(BigInteger n, byte[] encoding) throws IOException; + + /** + * Encode the (r, s) pair of a DSA signature. + * + * @param n the order of the group that r, s belong to. + * @param r the r value of a DSA signature. + * @param s the s value of a DSA signature. + * @return an encoding of the DSA signature given by the provided (r, s) pair. + * @throws IOException + */ + byte[] encode(BigInteger n, BigInteger r, BigInteger s) throws IOException; +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSASigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSASigner.java index 480d0dc32..cb54db236 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSASigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSASigner.java @@ -5,19 +5,20 @@ import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.params.DSAKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; import com.fr.third.org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.DSAPublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * The Digital Signature Algorithm - as described in "Handbook of Applied * Cryptography", pages 452 - 453. */ public class DSASigner - implements DSA + implements DSAExt { private final DSAKCalculator kCalculator; @@ -70,6 +71,11 @@ public class DSASigner this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom); } + public BigInteger getOrder() + { + return key.getParameters().getQ(); + } + /** * generate a signature for the given message using the key we were * initialised with. For conventional DSA the message should be a SHA-1 @@ -171,6 +177,6 @@ public class DSASigner // Calculate a random multiple of q to add to k. Note that g^q = 1 (mod p), so adding multiple of q to k does not change r. int randomBits = 7; - return new BigInteger(randomBits, provided != null ? provided : CryptoServicesRegistrar.getSecureRandom()).add(BigInteger.valueOf(128)).multiply(q); + return BigIntegers.createRandomBigInteger(randomBits, provided != null ? provided : CryptoServicesRegistrar.getSecureRandom()).add(BigInteger.valueOf(128)).multiply(q); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSTU4145Signer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSTU4145Signer.java index 1ab58af71..b747a005b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSTU4145Signer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/DSTU4145Signer.java @@ -5,7 +5,7 @@ import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; @@ -18,6 +18,7 @@ import com.fr.third.org.bouncycastle.math.ec.ECMultiplier; import com.fr.third.org.bouncycastle.math.ec.ECPoint; import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * DSTU 4145-2002 @@ -26,7 +27,7 @@ import com.fr.third.org.bouncycastle.util.Arrays; *

*/ public class DSTU4145Signer - implements DSA + implements DSAExt { private static final BigInteger ONE = BigInteger.valueOf(1); @@ -58,6 +59,11 @@ public class DSTU4145Signer } + public BigInteger getOrder() + { + return key.getParameters().getN(); + } + public BigInteger[] generateSignature(byte[] message) { ECDomainParameters ec = key.getParameters(); @@ -146,7 +152,7 @@ public class DSTU4145Signer */ private static BigInteger generateRandomInteger(BigInteger n, SecureRandom random) { - return new BigInteger(n.bitLength() - 1, random); + return BigIntegers.createRandomBigInteger(n.bitLength() - 1, random); } private static ECFieldElement hash2FieldElement(ECCurve curve, byte[] hash) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECDSASigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECDSASigner.java index db204487e..1a3a59dd5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECDSASigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECDSASigner.java @@ -5,7 +5,7 @@ import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; @@ -23,7 +23,7 @@ import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; * EC-DSA as described in X9.62 */ public class ECDSASigner - implements ECConstants, DSA + implements ECConstants, DSAExt { private final DSAKCalculator kCalculator; @@ -76,6 +76,11 @@ public class ECDSASigner this.random = initSecureRandom(forSigning && !kCalculator.isDeterministic(), providedRandom); } + public BigInteger getOrder() + { + return key.getParameters().getN(); + } + // 5.3 pg 28 /** * generate a signature for the given message using the key we were diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECGOST3410Signer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECGOST3410Signer.java index f64d16ac2..c660a9c92 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECGOST3410Signer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECGOST3410Signer.java @@ -5,7 +5,7 @@ import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; @@ -16,12 +16,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECMultiplier; import com.fr.third.org.bouncycastle.math.ec.ECPoint; import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * GOST R 34.10-2001 Signature Algorithm */ public class ECGOST3410Signer - implements DSA + implements DSAExt { ECKeyParameters key; @@ -52,6 +54,11 @@ public class ECGOST3410Signer } } + public BigInteger getOrder() + { + return key.getParameters().getN(); + } + /** * generate a signature for the given message using the key we were * initialised with. For conventional GOST3410 the message should be a GOST3411 @@ -62,12 +69,7 @@ public class ECGOST3410Signer public BigInteger[] generateSignature( byte[] message) { - byte[] mRev = new byte[message.length]; // conversion is little-endian - for (int i = 0; i != mRev.length; i++) - { - mRev[i] = message[mRev.length - 1 - i]; - } - + byte[] mRev = Arrays.reverse(message); // conversion is little-endian BigInteger e = new BigInteger(1, mRev); ECDomainParameters ec = key.getParameters(); @@ -85,7 +87,7 @@ public class ECGOST3410Signer { do { - k = new BigInteger(n.bitLength(), random); + k = BigIntegers.createRandomBigInteger(n.bitLength(), random); } while (k.equals(ECConstants.ZERO)); @@ -112,12 +114,7 @@ public class ECGOST3410Signer BigInteger r, BigInteger s) { - byte[] mRev = new byte[message.length]; // conversion is little-endian - for (int i = 0; i != mRev.length; i++) - { - mRev[i] = message[mRev.length - 1 - i]; - } - + byte[] mRev = Arrays.reverse(message); // conversion is little-endian BigInteger e = new BigInteger(1, mRev); BigInteger n = key.getParameters().getN(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECGOST3410_2012Signer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECGOST3410_2012Signer.java index 6d97e9204..995fd6f70 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECGOST3410_2012Signer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECGOST3410_2012Signer.java @@ -5,7 +5,7 @@ import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; @@ -16,12 +16,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECMultiplier; import com.fr.third.org.bouncycastle.math.ec.ECPoint; import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * GOST R 34.10-2012 Signature Algorithm */ public class ECGOST3410_2012Signer - implements DSA + implements DSAExt { ECKeyParameters key; @@ -52,6 +54,11 @@ public class ECGOST3410_2012Signer } } + public BigInteger getOrder() + { + return key.getParameters().getN(); + } + /** * generate a signature for the given message using the key we were * initialised with. For conventional GOST3410 2012 the message should be a GOST3411 2012 @@ -62,12 +69,7 @@ public class ECGOST3410_2012Signer public BigInteger[] generateSignature( byte[] message) { - - byte[] mRev = new byte[message.length]; // conversion is little-endian - for (int i = 0; i != mRev.length; i++) - { - mRev[i] = message[mRev.length - 1 - i]; - } + byte[] mRev = Arrays.reverse(message); // conversion is little-endian BigInteger e = new BigInteger(1, mRev); ECDomainParameters ec = key.getParameters(); @@ -85,7 +87,7 @@ public class ECGOST3410_2012Signer { do { - k = new BigInteger(n.bitLength(), random); + k = BigIntegers.createRandomBigInteger(n.bitLength(), random); } while (k.equals(ECConstants.ZERO)); @@ -112,13 +114,7 @@ public class ECGOST3410_2012Signer BigInteger r, BigInteger s) { - - - byte[] mRev = new byte[message.length]; // conversion is little-endian - for (int i = 0; i != mRev.length; i++) - { - mRev[i] = message[mRev.length - 1 - i]; - } + byte[] mRev = Arrays.reverse(message); // conversion is little-endian BigInteger e = new BigInteger(1, mRev); BigInteger n = key.getParameters().getN(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECNRSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECNRSigner.java index c5e5af1a7..59b18ed2d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECNRSigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/ECNRSigner.java @@ -6,7 +6,7 @@ import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.DataLengthException; import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; @@ -17,17 +17,26 @@ import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; import com.fr.third.org.bouncycastle.math.ec.ECAlgorithms; import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** - * EC-NR as described in IEEE 1363-2000 + * EC-NR as described in IEEE 1363-2000 - a signature algorithm for Elliptic Curve which + * also offers message recovery. */ public class ECNRSigner - implements DSA + implements DSAExt { private boolean forSigning; private ECKeyParameters key; private SecureRandom random; + /** + * Initialise the signer. + * + * @param forSigning true if we are generating a signature, false + * for verification or if we want to use the signer for message recovery. + * @param param key parameters for signature generation. + */ public void init( boolean forSigning, CipherParameters param) @@ -55,6 +64,11 @@ public class ECNRSigner } } + public BigInteger getOrder() + { + return key.getParameters().getN(); + } + // Section 7.2.5 ECSP-NR, pg 34 /** * generate a signature for the given message using the key we were @@ -68,22 +82,20 @@ public class ECNRSigner public BigInteger[] generateSignature( byte[] digest) { - if (! this.forSigning) + if (!this.forSigning) { throw new IllegalStateException("not initialised for signing"); } - BigInteger n = ((ECPrivateKeyParameters)this.key).getParameters().getN(); - int nBitLength = n.bitLength(); + BigInteger n = getOrder(); BigInteger e = new BigInteger(1, digest); - int eBitLength = e.bitLength(); - + ECPrivateKeyParameters privKey = (ECPrivateKeyParameters)key; - - if (eBitLength > nBitLength) + + if (e.compareTo(n) >= 0) { - throw new DataLengthException("input too large for ECNR key."); + throw new DataLengthException("input too large for ECNR key"); } BigInteger r = null; @@ -155,17 +167,49 @@ public class ECNRSigner { throw new DataLengthException("input too large for ECNR key."); } - + + BigInteger t = extractT(pubKey, r, s); + + return t != null && t.equals(e.mod(n)); + } + + /** + * Returns the data used for the signature generation, assuming the public key passed + * to init() is correct. + * + * @return null if r and s are not valid. + */ + public byte[] getRecoveredMessage(BigInteger r, BigInteger s) + { + if (this.forSigning) + { + throw new IllegalStateException("not initialised for verifying/recovery"); + } + + BigInteger t = extractT((ECPublicKeyParameters)key, r, s); + + if (t != null) + { + return BigIntegers.asUnsignedByteArray(t); + } + + return null; + } + + private BigInteger extractT(ECPublicKeyParameters pubKey, BigInteger r, BigInteger s) + { + BigInteger n = pubKey.getParameters().getN(); + // r in the range [1,n-1] - if (r.compareTo(ECConstants.ONE) < 0 || r.compareTo(n) >= 0) + if (r.compareTo(ECConstants.ONE) < 0 || r.compareTo(n) >= 0) { - return false; + return null; } // s in the range [0,n-1] NB: ECNR spec says 0 - if (s.compareTo(ECConstants.ZERO) < 0 || s.compareTo(n) >= 0) + if (s.compareTo(ECConstants.ZERO) < 0 || s.compareTo(n) >= 0) { - return false; + return null; } // compute P = sG + rW @@ -178,12 +222,11 @@ public class ECNRSigner // components must be bogus. if (P.isInfinity()) { - return false; + return null; } BigInteger x = P.getAffineXCoord().toBigInteger(); - BigInteger t = r.subtract(x).mod(n); - return t.equals(e); + return r.subtract(x).mod(n); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed25519Signer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed25519Signer.java new file mode 100644 index 000000000..7effd5480 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed25519Signer.java @@ -0,0 +1,109 @@ +package com.fr.third.org.bouncycastle.crypto.signers; + +import java.io.ByteArrayOutputStream; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.Signer; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed25519; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class Ed25519Signer + implements Signer +{ + private final Buffer buffer = new Buffer(); + + private boolean forSigning; + private Ed25519PrivateKeyParameters privateKey; + private Ed25519PublicKeyParameters publicKey; + + public Ed25519Signer() + { + } + + public void init(boolean forSigning, CipherParameters parameters) + { + this.forSigning = forSigning; + + if (forSigning) + { + // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters? + + this.privateKey = (Ed25519PrivateKeyParameters)parameters; + this.publicKey = privateKey.generatePublicKey(); + } + else + { + this.privateKey = null; + this.publicKey = (Ed25519PublicKeyParameters)parameters; + } + + reset(); + } + + public void update(byte b) + { + buffer.write(b); + } + + public void update(byte[] buf, int off, int len) + { + buffer.write(buf, off, len); + } + + public byte[] generateSignature() + { + if (!forSigning || null == privateKey) + { + throw new IllegalStateException("Ed25519Signer not initialised for signature generation."); + } + + return buffer.generateSignature(privateKey, publicKey); + } + + public boolean verifySignature(byte[] signature) + { + if (forSigning || null == publicKey) + { + throw new IllegalStateException("Ed25519Signer not initialised for verification"); + } + + return buffer.verifySignature(publicKey, signature); + } + + public void reset() + { + buffer.reset(); + } + + private static class Buffer extends ByteArrayOutputStream + { + synchronized byte[] generateSignature(Ed25519PrivateKeyParameters privateKey, Ed25519PublicKeyParameters publicKey) + { + byte[] signature = new byte[Ed25519PrivateKeyParameters.SIGNATURE_SIZE]; + privateKey.sign(Ed25519.Algorithm.Ed25519, publicKey, null, buf, 0, count, signature, 0); + reset(); + return signature; + } + + synchronized boolean verifySignature(Ed25519PublicKeyParameters publicKey, byte[] signature) + { + if (Ed25519.SIGNATURE_SIZE != signature.length) + { + return false; + } + + byte[] pk = publicKey.getEncoded(); + boolean result = Ed25519.verify(signature, 0, pk, 0, buf, 0, count); + reset(); + return result; + } + + public synchronized void reset() + { + Arrays.fill(buf, 0, count, (byte)0); + this.count = 0; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed25519ctxSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed25519ctxSigner.java new file mode 100644 index 000000000..57621a434 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed25519ctxSigner.java @@ -0,0 +1,111 @@ +package com.fr.third.org.bouncycastle.crypto.signers; + +import java.io.ByteArrayOutputStream; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.Signer; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed25519; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class Ed25519ctxSigner + implements Signer +{ + private final Buffer buffer = new Buffer(); + private final byte[] context; + + private boolean forSigning; + private Ed25519PrivateKeyParameters privateKey; + private Ed25519PublicKeyParameters publicKey; + + public Ed25519ctxSigner(byte[] context) + { + this.context = Arrays.clone(context); + } + + public void init(boolean forSigning, CipherParameters parameters) + { + this.forSigning = forSigning; + + if (forSigning) + { + // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters? + + this.privateKey = (Ed25519PrivateKeyParameters)parameters; + this.publicKey = privateKey.generatePublicKey(); + } + else + { + this.privateKey = null; + this.publicKey = (Ed25519PublicKeyParameters)parameters; + } + + reset(); + } + + public void update(byte b) + { + buffer.write(b); + } + + public void update(byte[] buf, int off, int len) + { + buffer.write(buf, off, len); + } + + public byte[] generateSignature() + { + if (!forSigning || null == privateKey) + { + throw new IllegalStateException("Ed25519ctxSigner not initialised for signature generation."); + } + + return buffer.generateSignature(privateKey, publicKey, context); + } + + public boolean verifySignature(byte[] signature) + { + if (forSigning || null == publicKey) + { + throw new IllegalStateException("Ed25519ctxSigner not initialised for verification"); + } + + return buffer.verifySignature(publicKey, context, signature); + } + + public void reset() + { + buffer.reset(); + } + + private static class Buffer extends ByteArrayOutputStream + { + synchronized byte[] generateSignature(Ed25519PrivateKeyParameters privateKey, Ed25519PublicKeyParameters publicKey, byte[] ctx) + { + byte[] signature = new byte[Ed25519PrivateKeyParameters.SIGNATURE_SIZE]; + privateKey.sign(Ed25519.Algorithm.Ed25519ctx, publicKey, ctx, buf, 0, count, signature, 0); + reset(); + return signature; + } + + synchronized boolean verifySignature(Ed25519PublicKeyParameters publicKey, byte[] ctx, byte[] signature) + { + if (Ed25519.SIGNATURE_SIZE != signature.length) + { + return false; + } + + byte[] pk = publicKey.getEncoded(); + boolean result = Ed25519.verify(signature, 0, pk, 0, ctx, buf, 0, count); + reset(); + return result; + } + + public synchronized void reset() + { + Arrays.fill(buf, 0, count, (byte)0); + this.count = 0; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed25519phSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed25519phSigner.java new file mode 100644 index 000000000..6ffaa9d38 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed25519phSigner.java @@ -0,0 +1,93 @@ +package com.fr.third.org.bouncycastle.crypto.signers; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.Signer; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed25519; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class Ed25519phSigner + implements Signer +{ + private final Digest prehash = Ed25519.createPrehash(); + private final byte[] context; + + private boolean forSigning; + private Ed25519PrivateKeyParameters privateKey; + private Ed25519PublicKeyParameters publicKey; + + public Ed25519phSigner(byte[] context) + { + this.context = Arrays.clone(context); + } + + public void init(boolean forSigning, CipherParameters parameters) + { + this.forSigning = forSigning; + + if (forSigning) + { + // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters? + + this.privateKey = (Ed25519PrivateKeyParameters)parameters; + this.publicKey = privateKey.generatePublicKey(); + } + else + { + this.privateKey = null; + this.publicKey = (Ed25519PublicKeyParameters)parameters; + } + + reset(); + } + + public void update(byte b) + { + prehash.update(b); + } + + public void update(byte[] buf, int off, int len) + { + prehash.update(buf, off, len); + } + + public byte[] generateSignature() + { + if (!forSigning || null == privateKey) + { + throw new IllegalStateException("Ed25519phSigner not initialised for signature generation."); + } + + byte[] msg = new byte[Ed25519.PREHASH_SIZE]; + if (Ed25519.PREHASH_SIZE != prehash.doFinal(msg, 0)) + { + throw new IllegalStateException("Prehash digest failed"); + } + + byte[] signature = new byte[Ed25519PrivateKeyParameters.SIGNATURE_SIZE]; + privateKey.sign(Ed25519.Algorithm.Ed25519ph, publicKey, context, msg, 0, Ed25519.PREHASH_SIZE, signature, 0); + return signature; + } + + public boolean verifySignature(byte[] signature) + { + if (forSigning || null == publicKey) + { + throw new IllegalStateException("Ed25519phSigner not initialised for verification"); + } + if (Ed25519.SIGNATURE_SIZE != signature.length) + { + return false; + } + + byte[] pk = publicKey.getEncoded(); + return Ed25519.verifyPrehash(signature, 0, pk, 0, context, prehash); + } + + public void reset() + { + prehash.reset(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed448Signer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed448Signer.java new file mode 100644 index 000000000..1f48d9d66 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed448Signer.java @@ -0,0 +1,112 @@ +package com.fr.third.org.bouncycastle.crypto.signers; + +import java.io.ByteArrayOutputStream; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.Signer; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PublicKeyParameters; +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed448; +import com.fr.third.org.bouncycastle.util.Arrays; + + +public class Ed448Signer + implements Signer +{ + private final Buffer buffer = new Buffer(); + private final byte[] context; + + private boolean forSigning; + private Ed448PrivateKeyParameters privateKey; + private Ed448PublicKeyParameters publicKey; + + public Ed448Signer(byte[] context) + { + this.context = Arrays.clone(context); + } + + public void init(boolean forSigning, CipherParameters parameters) + { + this.forSigning = forSigning; + + if (forSigning) + { + // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters? + + this.privateKey = (Ed448PrivateKeyParameters)parameters; + this.publicKey = privateKey.generatePublicKey(); + } + else + { + this.privateKey = null; + this.publicKey = (Ed448PublicKeyParameters)parameters; + } + + reset(); + } + + public void update(byte b) + { + buffer.write(b); + } + + public void update(byte[] buf, int off, int len) + { + buffer.write(buf, off, len); + } + + public byte[] generateSignature() + { + if (!forSigning || null == privateKey) + { + throw new IllegalStateException("Ed448Signer not initialised for signature generation."); + } + + return buffer.generateSignature(privateKey, publicKey, context); + } + + public boolean verifySignature(byte[] signature) + { + if (forSigning || null == publicKey) + { + throw new IllegalStateException("Ed448Signer not initialised for verification"); + } + + return buffer.verifySignature(publicKey, context, signature); + } + + public void reset() + { + buffer.reset(); + } + + private static class Buffer extends ByteArrayOutputStream + { + synchronized byte[] generateSignature(Ed448PrivateKeyParameters privateKey, Ed448PublicKeyParameters publicKey, byte[] ctx) + { + byte[] signature = new byte[Ed448PrivateKeyParameters.SIGNATURE_SIZE]; + privateKey.sign(Ed448.Algorithm.Ed448, publicKey, ctx, buf, 0, count, signature, 0); + reset(); + return signature; + } + + synchronized boolean verifySignature(Ed448PublicKeyParameters publicKey, byte[] ctx, byte[] signature) + { + if (Ed448.SIGNATURE_SIZE != signature.length) + { + return false; + } + + byte[] pk = publicKey.getEncoded(); + boolean result = Ed448.verify(signature, 0, pk, 0, ctx, buf, 0, count); + reset(); + return result; + } + + public synchronized void reset() + { + Arrays.fill(buf, 0, count, (byte)0); + this.count = 0; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed448phSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed448phSigner.java new file mode 100644 index 000000000..9d6ea193f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/Ed448phSigner.java @@ -0,0 +1,93 @@ +package com.fr.third.org.bouncycastle.crypto.signers; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.Signer; +import com.fr.third.org.bouncycastle.crypto.Xof; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PublicKeyParameters; +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed448; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class Ed448phSigner + implements Signer +{ + private final Xof prehash = Ed448.createPrehash(); + private final byte[] context; + + private boolean forSigning; + private Ed448PrivateKeyParameters privateKey; + private Ed448PublicKeyParameters publicKey; + + public Ed448phSigner(byte[] context) + { + this.context = Arrays.clone(context); + } + + public void init(boolean forSigning, CipherParameters parameters) + { + this.forSigning = forSigning; + + if (forSigning) + { + // TODO Allow AsymmetricCipherKeyPair to be a CipherParameters? + + this.privateKey = (Ed448PrivateKeyParameters)parameters; + this.publicKey = privateKey.generatePublicKey(); + } + else + { + this.privateKey = null; + this.publicKey = (Ed448PublicKeyParameters)parameters; + } + + reset(); + } + + public void update(byte b) + { + prehash.update(b); + } + + public void update(byte[] buf, int off, int len) + { + prehash.update(buf, off, len); + } + + public byte[] generateSignature() + { + if (!forSigning || null == privateKey) + { + throw new IllegalStateException("Ed448phSigner not initialised for signature generation."); + } + + byte[] msg = new byte[Ed448.PREHASH_SIZE]; + if (Ed448.PREHASH_SIZE != prehash.doFinal(msg, 0, Ed448.PREHASH_SIZE)) + { + throw new IllegalStateException("Prehash digest failed"); + } + + byte[] signature = new byte[Ed448PrivateKeyParameters.SIGNATURE_SIZE]; + privateKey.sign(Ed448.Algorithm.Ed448ph, publicKey, context, msg, 0, Ed448.PREHASH_SIZE, signature, 0); + return signature; + } + + public boolean verifySignature(byte[] signature) + { + if (forSigning || null == publicKey) + { + throw new IllegalStateException("Ed448phSigner not initialised for verification"); + } + if (Ed448.SIGNATURE_SIZE != signature.length) + { + return false; + } + + byte[] pk = publicKey.getEncoded(); + return Ed448.verifyPrehash(signature, 0, pk, 0, context, prehash); + } + + public void reset() + { + prehash.reset(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/GOST3410Signer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/GOST3410Signer.java index 892fb9e7e..37b1f5eb8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/GOST3410Signer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/GOST3410Signer.java @@ -5,18 +5,20 @@ import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.params.GOST3410KeyParameters; import com.fr.third.org.bouncycastle.crypto.params.GOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.GOST3410PrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.GOST3410PublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * GOST R 34.10-94 Signature Algorithm */ public class GOST3410Signer - implements DSA + implements DSAExt { GOST3410KeyParameters key; @@ -47,6 +49,11 @@ public class GOST3410Signer } } + public BigInteger getOrder() + { + return key.getParameters().getQ(); + } + /** * generate a signature for the given message using the key we were * initialised with. For conventional GOST3410 the message should be a GOST3411 @@ -57,19 +64,14 @@ public class GOST3410Signer public BigInteger[] generateSignature( byte[] message) { - byte[] mRev = new byte[message.length]; // conversion is little-endian - for (int i = 0; i != mRev.length; i++) - { - mRev[i] = message[mRev.length - 1 - i]; - } - + byte[] mRev = Arrays.reverse(message); // conversion is little-endian BigInteger m = new BigInteger(1, mRev); GOST3410Parameters params = key.getParameters(); BigInteger k; do { - k = new BigInteger(params.getQ().bitLength(), random); + k = BigIntegers.createRandomBigInteger(params.getQ().bitLength(), random); } while (k.compareTo(params.getQ()) >= 0); @@ -97,12 +99,7 @@ public class GOST3410Signer BigInteger r, BigInteger s) { - byte[] mRev = new byte[message.length]; // conversion is little-endian - for (int i = 0; i != mRev.length; i++) - { - mRev[i] = message[mRev.length - 1 - i]; - } - + byte[] mRev = Arrays.reverse(message); // conversion is little-endian BigInteger m = new BigInteger(1, mRev); GOST3410Parameters params = key.getParameters(); BigInteger zero = BigInteger.valueOf(0); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/HMacDSAKCalculator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/HMacDSAKCalculator.java index 47a675d65..41bcc64f6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/HMacDSAKCalculator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/HMacDSAKCalculator.java @@ -52,12 +52,13 @@ public class HMacDSAKCalculator Arrays.fill(V, (byte)0x01); Arrays.fill(K, (byte)0); - byte[] x = new byte[(n.bitLength() + 7) / 8]; + int size = BigIntegers.getUnsignedByteLength(n); + byte[] x = new byte[size]; byte[] dVal = BigIntegers.asUnsignedByteArray(d); System.arraycopy(dVal, 0, x, x.length - dVal.length, dVal.length); - byte[] m = new byte[(n.bitLength() + 7) / 8]; + byte[] m = new byte[size]; BigInteger mInt = bitsToInt(message); @@ -101,7 +102,7 @@ public class HMacDSAKCalculator public BigInteger nextK() { - byte[] t = new byte[((n.bitLength() + 7) / 8)]; + byte[] t = new byte[BigIntegers.getUnsignedByteLength(n)]; for (;;) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/PSSSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/PSSSigner.java index 0f98ff9c2..3c9f89118 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/PSSSigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/PSSSigner.java @@ -12,6 +12,7 @@ import com.fr.third.org.bouncycastle.crypto.Signer; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; import com.fr.third.org.bouncycastle.crypto.params.RSABlindingParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.util.Arrays; /** * RSA-PSS as described in PKCS# 1 v 2.1. @@ -250,10 +251,11 @@ public class PSSSigner block[i] ^= dbMask[i]; } - block[0] &= (0xff >> ((block.length * 8) - emBits)); - System.arraycopy(h, 0, block, block.length - hLen - 1, hLen); + int firstByteMask = 0xff >>> ((block.length * 8) - emBits); + + block[0] &= firstByteMask; block[block.length - 1] = trailer; byte[] b = cipher.processBlock(block, 0, block.length); @@ -275,6 +277,7 @@ public class PSSSigner try { byte[] b = cipher.processBlock(signature, 0, signature.length); + Arrays.fill(block, 0, block.length - b.length, (byte)0); System.arraycopy(b, 0, block, block.length - b.length, b.length); } catch (Exception e) @@ -282,7 +285,10 @@ public class PSSSigner return false; } - if (block[block.length - 1] != trailer) + int firstByteMask = 0xff >>> ((block.length * 8) - emBits); + + if ((block[0] & 0xff) != (block[0] & firstByteMask) + || block[block.length - 1] != trailer) { clearBlock(block); return false; @@ -295,7 +301,7 @@ public class PSSSigner block[i] ^= dbMask[i]; } - block[0] &= (0xff >> ((block.length * 8) - emBits)); + block[0] &= firstByteMask; for (int i = 0; i != block.length - hLen - sLen - 2; i++) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/PlainDSAEncoding.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/PlainDSAEncoding.java new file mode 100644 index 000000000..001b83f3c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/PlainDSAEncoding.java @@ -0,0 +1,62 @@ +package com.fr.third.org.bouncycastle.crypto.signers; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; + +public class PlainDSAEncoding + implements DSAEncoding +{ + public static final PlainDSAEncoding INSTANCE = new PlainDSAEncoding(); + + public byte[] encode(BigInteger n, BigInteger r, BigInteger s) + { + int valueLength = BigIntegers.getUnsignedByteLength(n); + byte[] result = new byte[valueLength * 2]; + encodeValue(n, r, result, 0, valueLength); + encodeValue(n, s, result, valueLength, valueLength); + return result; + } + + public BigInteger[] decode(BigInteger n, byte[] encoding) + { + int valueLength = BigIntegers.getUnsignedByteLength(n); + if (encoding.length != valueLength * 2) + { + throw new IllegalArgumentException("Encoding has incorrect length"); + } + + return new BigInteger[] { + decodeValue(n, encoding, 0, valueLength), + decodeValue(n, encoding, valueLength, valueLength), + }; + } + + protected BigInteger checkValue(BigInteger n, BigInteger x) + { + if (x.signum() < 0 || x.compareTo(n) >= 0) + { + throw new IllegalArgumentException("Value out of range"); + } + + return x; + } + + protected BigInteger decodeValue(BigInteger n, byte[] buf, int off, int len) + { + byte[] bs = Arrays.copyOfRange(buf, off, off + len); + return checkValue(n, new BigInteger(1, bs)); + } + + private void encodeValue(BigInteger n, BigInteger x, byte[] buf, int off, int len) + { + byte[] bs = checkValue(n, x).toByteArray(); + int bsOff = Math.max(0, bs.length - len); + int bsLen = bs.length - bsOff; + + int pos = len - bsLen; + Arrays.fill(buf, off, off + pos, (byte)0); + System.arraycopy(bs, bsOff, buf, off + pos, bsLen); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/RSADigestSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/RSADigestSigner.java index 61f4092d3..755940a60 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/RSADigestSigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/RSADigestSigner.java @@ -39,6 +39,8 @@ public class RSADigestSigner */ static { + // Null-digester is intentionally NOT on this mapping. + oidMap.put("RIPEMD128", TeleTrusTObjectIdentifiers.ripemd128); oidMap.put("RIPEMD160", TeleTrusTObjectIdentifiers.ripemd160); oidMap.put("RIPEMD256", TeleTrusTObjectIdentifiers.ripemd256); @@ -72,7 +74,15 @@ public class RSADigestSigner ASN1ObjectIdentifier digestOid) { this.digest = digest; - this.algId = new AlgorithmIdentifier(digestOid, DERNull.INSTANCE); + if (digestOid != null) + { + this.algId = new AlgorithmIdentifier(digestOid, DERNull.INSTANCE); + } + else + { + // NULL digester, match behaviour with DigestSignatureSpi + this.algId = null; + } } /** @@ -84,7 +94,7 @@ public class RSADigestSigner } /** - * initialise the signer for signing or verification. + * Initialize the signer for signing or verification. * * @param forSigning * true if for signing, false otherwise @@ -240,6 +250,20 @@ public class RSADigestSigner byte[] hash) throws IOException { + if (algId == null) + { + try + { + // check hash is at least right format + DigestInfo.getInstance(hash); + return hash; + } + catch (IllegalArgumentException e) + { + throw new IOException("malformed DigestInfo for NONEwithRSA hash: " + e.getMessage()); + } + } + DigestInfo dInfo = new DigestInfo(algId, hash); return dInfo.getEncoded(ASN1Encoding.DER); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java index e6e8b115d..cf4faa429 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/RandomDSAKCalculator.java @@ -3,6 +3,8 @@ package com.fr.third.org.bouncycastle.crypto.signers; import java.math.BigInteger; import java.security.SecureRandom; +import com.fr.third.org.bouncycastle.util.BigIntegers; + public class RandomDSAKCalculator implements DSAKCalculator { @@ -34,7 +36,7 @@ public class RandomDSAKCalculator BigInteger k; do { - k = new BigInteger(qBitLength, random); + k = BigIntegers.createRandomBigInteger(qBitLength, random); } while (k.equals(ZERO) || k.compareTo(q) >= 0); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/SM2Signer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/SM2Signer.java index 00e232a38..6e21c2136 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/SM2Signer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/SM2Signer.java @@ -1,14 +1,7 @@ package com.fr.third.org.bouncycastle.crypto.signers; -import java.io.IOException; import java.math.BigInteger; -import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; -import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; -import com.fr.third.org.bouncycastle.asn1.ASN1Integer; -import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; -import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; -import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.CryptoException; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; @@ -27,7 +20,6 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECMultiplier; import com.fr.third.org.bouncycastle.math.ec.ECPoint; import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; -import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.encoders.Hex; /** @@ -37,13 +29,36 @@ public class SM2Signer implements Signer, ECConstants { private final DSAKCalculator kCalculator = new RandomDSAKCalculator(); - private final SM3Digest digest = new SM3Digest(); + private final Digest digest; + private final DSAEncoding encoding; private ECDomainParameters ecParams; private ECPoint pubPoint; private ECKeyParameters ecKey; private byte[] z; + public SM2Signer() + { + this(StandardDSAEncoding.INSTANCE, new SM3Digest()); + } + + public SM2Signer(Digest digest) + { + this(StandardDSAEncoding.INSTANCE, digest); + } + + public SM2Signer(DSAEncoding encoding) + { + this.encoding = encoding; + this.digest = new SM3Digest(); + } + + public SM2Signer(DSAEncoding encoding, Digest digest) + { + this.encoding = encoding; + this.digest = digest; + } + public void init(boolean forSigning, CipherParameters param) { CipherParameters baseParam; @@ -53,11 +68,17 @@ public class SM2Signer { baseParam = ((ParametersWithID)param).getParameters(); userID = ((ParametersWithID)param).getID(); + + if (userID.length >= 8192) + { + throw new IllegalArgumentException("SM2 user ID must be less than 2^16 bits long"); + } } else { baseParam = param; - userID = Hex.decode("31323334353637383132333435363738"); // the default value + // the default value, string value is "1234567812345678" + userID = Hex.decodeStrict("31323334353637383132333435363738"); } if (forSigning) @@ -104,13 +125,11 @@ public class SM2Signer { try { - BigInteger[] rs = derDecode(signature); - if (rs != null) - { - return verifySignature(rs[0], rs[1]); - } + BigInteger[] rs = encoding.decode(ecParams.getN(), signature); + + return verifySignature(rs[0], rs[1]); } - catch (IOException e) + catch (Exception e) { } @@ -133,7 +152,7 @@ public class SM2Signer byte[] eHash = digestDoFinal(); BigInteger n = ecParams.getN(); - BigInteger e = calculateE(eHash); + BigInteger e = calculateE(n, eHash); BigInteger d = ((ECPrivateKeyParameters)ecKey).getD(); BigInteger r, s; @@ -168,9 +187,9 @@ public class SM2Signer // A7 try { - return derEncode(r, s); + return encoding.encode(ecParams.getN(), r, s); } - catch (IOException ex) + catch (Exception ex) { throw new CryptoException("unable to encode signature: " + ex.getMessage(), ex); } @@ -197,7 +216,7 @@ public class SM2Signer byte[] eHash = digestDoFinal(); // B4 - BigInteger e = calculateE(eHash); + BigInteger e = calculateE(n, eHash); // B5 BigInteger t = r.add(s).mod(n); @@ -269,39 +288,9 @@ public class SM2Signer return new FixedPointCombMultiplier(); } - protected BigInteger calculateE(byte[] message) + protected BigInteger calculateE(BigInteger n, byte[] message) { + // TODO Should hashes larger than the order be truncated as with ECDSA? return new BigInteger(1, message); } - - protected BigInteger[] derDecode(byte[] encoding) - throws IOException - { - ASN1Sequence seq = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(encoding)); - if (seq.size() != 2) - { - return null; - } - - BigInteger r = ASN1Integer.getInstance(seq.getObjectAt(0)).getValue(); - BigInteger s = ASN1Integer.getInstance(seq.getObjectAt(1)).getValue(); - - byte[] expectedEncoding = derEncode(r, s); - if (!Arrays.constantTimeAreEqual(expectedEncoding, encoding)) - { - return null; - } - - return new BigInteger[]{ r, s }; - } - - protected byte[] derEncode(BigInteger r, BigInteger s) - throws IOException - { - - ASN1EncodableVector v = new ASN1EncodableVector(); - v.add(new ASN1Integer(r)); - v.add(new ASN1Integer(s)); - return new DERSequence(v).getEncoded(ASN1Encoding.DER); - } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/StandardDSAEncoding.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/StandardDSAEncoding.java new file mode 100644 index 000000000..fe355c13b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/StandardDSAEncoding.java @@ -0,0 +1,64 @@ +package com.fr.third.org.bouncycastle.crypto.signers; + +import java.io.IOException; +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class StandardDSAEncoding + implements DSAEncoding +{ + public static final StandardDSAEncoding INSTANCE = new StandardDSAEncoding(); + + public byte[] encode(BigInteger n, BigInteger r, BigInteger s) throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + encodeValue(n, v, r); + encodeValue(n, v, s); + return new DERSequence(v).getEncoded(ASN1Encoding.DER); + } + + public BigInteger[] decode(BigInteger n, byte[] encoding) throws IOException + { + ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); + if (seq.size() == 2) + { + BigInteger r = decodeValue(n, seq, 0); + BigInteger s = decodeValue(n, seq, 1); + + byte[] expectedEncoding = encode(n, r, s); + if (Arrays.areEqual(expectedEncoding, encoding)) + { + return new BigInteger[]{ r, s }; + } + } + + throw new IllegalArgumentException("Malformed signature"); + } + + protected BigInteger checkValue(BigInteger n, BigInteger x) + { + if (x.signum() < 0 || (null != n && x.compareTo(n) >= 0)) + { + throw new IllegalArgumentException("Value out of range"); + } + + return x; + } + + protected BigInteger decodeValue(BigInteger n, ASN1Sequence s, int pos) + { + return checkValue(n, ((ASN1Integer)s.getObjectAt(pos)).getValue()); + } + + protected void encodeValue(BigInteger n, ASN1EncodableVector v, BigInteger x) + { + v.add(new ASN1Integer(checkValue(n, x))); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/X931Signer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/X931Signer.java index 756a5452b..cc6c23462 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/X931Signer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/signers/X931Signer.java @@ -166,7 +166,8 @@ public class X931Signer t = t.min(kParam.getModulus().subtract(t)); - return BigIntegers.asUnsignedByteArray((kParam.getModulus().bitLength() + 7) / 8, t); + int size = BigIntegers.getUnsignedByteLength(kParam.getModulus()); + return BigIntegers.asUnsignedByteArray(size, t); } private void createSignatureBlock(int trailer) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AEADTestUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AEADTestUtil.java new file mode 100644 index 000000000..4a031da12 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AEADTestUtil.java @@ -0,0 +1,475 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.OutputLengthException; +import com.fr.third.org.bouncycastle.crypto.modes.AEADBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.AEADCipher; +import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +public class AEADTestUtil +{ + public static void testTampering(Test test, AEADCipher cipher, CipherParameters params) + throws InvalidCipherTextException + { + byte[] plaintext = new byte[1000]; + for (int i = 0; i < plaintext.length; i++) + { + plaintext[i] = (byte)i; + } + cipher.init(true, params); + + byte[] ciphertext = new byte[cipher.getOutputSize(plaintext.length)]; + int len = cipher.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); + cipher.doFinal(ciphertext, len); + + int macLength = cipher.getMac().length; + + // Test tampering with a single byte + cipher.init(false, params); + byte[] tampered = new byte[ciphertext.length]; + byte[] output = new byte[plaintext.length]; + System.arraycopy(ciphertext, 0, tampered, 0, tampered.length); + tampered[0] += 1; + + cipher.processBytes(tampered, 0, tampered.length, output, 0); + try + { + cipher.doFinal(output, 0); + throw new TestFailedException( + new SimpleTestResult(false, test + " : tampering of ciphertext not detected.")); + } + catch (InvalidCipherTextException e) + { + // Expected + } + + // Test truncation of ciphertext to < tag length + cipher.init(false, params); + byte[] truncated = new byte[macLength - 1]; + System.arraycopy(ciphertext, 0, truncated, 0, truncated.length); + + cipher.processBytes(truncated, 0, truncated.length, output, 0); + try + { + cipher.doFinal(output, 0); + fail(test, "tampering of ciphertext not detected."); + } + catch (InvalidCipherTextException e) + { + // Expected + } + } + + private static void fail(Test test, String message) + { + throw new TestFailedException(SimpleTestResult.failed(test, message)); + } + + private static void fail(Test test, String message, String expected, String result) + { + throw new TestFailedException(SimpleTestResult.failed(test, message, expected, result)); + } + + public static void testReset(Test test, AEADCipher cipher1, AEADBlockCipher cipher2, CipherParameters params) + throws InvalidCipherTextException + { + cipher1.init(true, params); + + byte[] plaintext = new byte[1000]; + byte[] ciphertext = new byte[cipher1.getOutputSize(plaintext.length)]; + + // Establish baseline answer + crypt(cipher1, plaintext, ciphertext); + + // Test encryption resets + checkReset(test, cipher1, params, true, plaintext, ciphertext); + + // Test decryption resets with fresh instance + cipher2.init(false, params); + checkReset(test, cipher2, params, false, ciphertext, plaintext); + } + + private static void checkReset(Test test, + AEADCipher cipher, + CipherParameters params, + boolean encrypt, + byte[] pretext, + byte[] posttext) + throws InvalidCipherTextException + { + // Do initial run + byte[] output = new byte[posttext.length]; + crypt(cipher, pretext, output); + + // Check encrypt resets cipher + crypt(cipher, pretext, output); + if (!Arrays.areEqual(output, posttext)) + { + fail(test, (encrypt ? "Encrypt" : "Decrypt") + " did not reset cipher."); + } + + // Check init resets data + cipher.processBytes(pretext, 0, 100, output, 0); + cipher.init(encrypt, params); + + try + { + crypt(cipher, pretext, output); + } + catch (DataLengthException e) + { + fail(test, "Init did not reset data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test, "Init did not reset data.", new String(Hex.encode(posttext)), new String(Hex.encode(output))); + } + + // Check init resets AD + cipher.processAADBytes(pretext, 0, 100); + cipher.init(encrypt, params); + + try + { + crypt(cipher, pretext, output); + } + catch (DataLengthException e) + { + fail(test, "Init did not reset additional data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test, "Init did not reset additional data."); + } + + // Check reset resets data + cipher.processBytes(pretext, 0, 100, output, 0); + cipher.reset(); + + try + { + crypt(cipher, pretext, output); + } + catch (DataLengthException e) + { + fail(test, "Init did not reset data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test, "Reset did not reset data."); + } + + // Check reset resets AD + cipher.processAADBytes(pretext, 0, 100); + cipher.reset(); + + try + { + crypt(cipher, pretext, output); + } + catch (DataLengthException e) + { + fail(test, "Init did not reset data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test, "Reset did not reset additional data."); + } + } + + private static void crypt(AEADCipher cipher, byte[] plaintext, byte[] output) + throws InvalidCipherTextException + { + int len = cipher.processBytes(plaintext, 0, plaintext.length, output, 0); + cipher.doFinal(output, len); + } + + public static void testOutputSizes(Test test, AEADBlockCipher cipher, AEADParameters params) + throws IllegalStateException, + InvalidCipherTextException + { + int maxPlaintext = cipher.getUnderlyingCipher().getBlockSize() * 10; + byte[] plaintext = new byte[maxPlaintext]; + byte[] ciphertext = new byte[maxPlaintext * 2]; + + // Check output size calculations for truncated ciphertext lengths + cipher.init(true, params); + cipher.doFinal(ciphertext, 0); + int macLength = cipher.getMac().length; + + cipher.init(false, params); + for (int i = 0; i < macLength; i++) + { + cipher.reset(); + if (cipher.getUpdateOutputSize(i) != 0) + { + fail(test, "AE cipher should not produce update output with ciphertext length <= macSize"); + } + if (cipher.getOutputSize(i) != 0) + { + fail(test, "AE cipher should not produce output with ciphertext length <= macSize"); + } + } + + for (int i = 0; i < plaintext.length; i++) + { + cipher.init(true, params); + int expectedCTUpdateSize = cipher.getUpdateOutputSize(i); + int expectedCTOutputSize = cipher.getOutputSize(i); + + if (expectedCTUpdateSize < 0) + { + fail(test, "Encryption update output size should not be < 0 for size " + i); + } + + if (expectedCTOutputSize < 0) + { + fail(test, "Encryption update output size should not be < 0 for size " + i); + } + + int actualCTSize = cipher.processBytes(plaintext, 0, i, ciphertext, 0); + + if (expectedCTUpdateSize != actualCTSize) + { + fail(test, "Encryption update output size did not match calculated for plaintext length " + i, + String.valueOf(expectedCTUpdateSize), String.valueOf(actualCTSize)); + } + + actualCTSize += cipher.doFinal(ciphertext, actualCTSize); + + if (expectedCTOutputSize != actualCTSize) + { + fail(test, "Encryption actual final output size did not match calculated for plaintext length " + i, + String.valueOf(expectedCTOutputSize), String.valueOf(actualCTSize)); + } + + cipher.init(false, params); + int expectedPTUpdateSize = cipher.getUpdateOutputSize(actualCTSize); + int expectedPTOutputSize = cipher.getOutputSize(actualCTSize); + + if (expectedPTOutputSize != i) + { + fail(test, "Decryption update output size did not original plaintext length " + i, + String.valueOf(expectedPTUpdateSize), String.valueOf(i)); + } + + int actualPTSize = cipher.processBytes(ciphertext, 0, actualCTSize, plaintext, 0); + + if (expectedPTUpdateSize != actualPTSize) + { + fail(test, "Decryption update output size did not match calculated for plaintext length " + i, + String.valueOf(expectedPTUpdateSize), String.valueOf(actualPTSize)); + } + + actualPTSize += cipher.doFinal(plaintext, actualPTSize); + + if (expectedPTOutputSize != actualPTSize) + { + fail(test, "Decryption update output size did not match calculated for plaintext length " + i, + String.valueOf(expectedPTOutputSize), String.valueOf(actualPTSize)); + } + + } + } + + public static void testBufferSizeChecks(Test test, AEADBlockCipher cipher, AEADParameters params) + throws IllegalStateException, + InvalidCipherTextException + { + int blockSize = cipher.getUnderlyingCipher().getBlockSize(); + int maxPlaintext = (blockSize * 10); + byte[] plaintext = new byte[maxPlaintext]; + + + cipher.init(true, params); + + int expectedUpdateOutputSize = cipher.getUpdateOutputSize(plaintext.length); + byte[] ciphertext = new byte[cipher.getOutputSize(plaintext.length)]; + + try + { + cipher.processBytes(new byte[maxPlaintext - 1], 0, maxPlaintext, new byte[expectedUpdateOutputSize], 0); + fail(test, "processBytes should validate input buffer length"); + } + catch (DataLengthException e) + { + // Expected + } + cipher.reset(); + + if (expectedUpdateOutputSize > 0) + { + int outputTrigger = 0; + // Process bytes until output would be produced + for(int i = 0; i < plaintext.length; i++) { + if (cipher.getUpdateOutputSize(1) != 0) + { + outputTrigger = i + 1; + break; + } + cipher.processByte(plaintext[i], ciphertext, 0); + } + if (outputTrigger == 0) + { + fail(test, "Failed to find output trigger size"); + } + try + { + cipher.processByte(plaintext[0], new byte[cipher.getUpdateOutputSize(1) - 1], 0); + fail(test, "Encrypt processByte should validate output buffer length"); + } + catch (OutputLengthException e) + { + // Expected + } + cipher.reset(); + + // Repeat checking with entire input at once + try + { + cipher.processBytes(plaintext, 0, outputTrigger, + new byte[cipher.getUpdateOutputSize(outputTrigger) - 1], 0); + fail(test, "Encrypt processBytes should validate output buffer length"); + } + catch (OutputLengthException e) + { + // Expected + } + cipher.reset(); + + } + + // Remember the actual ciphertext for later + int actualOutputSize = cipher.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); + actualOutputSize += cipher.doFinal(ciphertext, actualOutputSize); + int macSize = cipher.getMac().length; + + cipher.reset(); + try + { + cipher.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); + cipher.doFinal(new byte[cipher.getOutputSize(0) - 1], 0); + fail(test, "Encrypt doFinal should validate output buffer length"); + } + catch (OutputLengthException e) + { + // Expected + } + + // Decryption tests + + cipher.init(false, params); + expectedUpdateOutputSize = cipher.getUpdateOutputSize(actualOutputSize); + + if (expectedUpdateOutputSize > 0) + { + // Process bytes until output would be produced + int outputTrigger = 0; + for (int i = 0; i < plaintext.length; i++) + { + if (cipher.getUpdateOutputSize(1) != 0) + { + outputTrigger = i + 1; + break; + } + cipher.processByte(ciphertext[i], plaintext, 0); + } + if (outputTrigger == 0) + { + fail(test, "Failed to find output trigger size"); + } + + try + { + cipher.processByte(ciphertext[0], new byte[cipher.getUpdateOutputSize(1) - 1], 0); + fail(test, "Decrypt processByte should validate output buffer length"); + } + catch (OutputLengthException e) + { + // Expected + } + cipher.reset(); + + // Repeat test with processBytes + try + { + cipher.processBytes(ciphertext, 0, outputTrigger, + new byte[cipher.getUpdateOutputSize(outputTrigger) - 1], 0); + fail(test, "Decrypt processBytes should validate output buffer length"); + } + catch (OutputLengthException e) + { + // Expected + } + } + + cipher.reset(); + // Data less than mac length should fail before output length check + try + { + // Assumes AE cipher on decrypt can't return any data until macSize bytes are received + if (cipher.processBytes(ciphertext, 0, macSize - 1, plaintext, 0) != 0) + { + fail(test, "AE cipher unexpectedly produced output"); + } + cipher.doFinal(new byte[0], 0); + fail(test, "Decrypt doFinal should check ciphertext length"); + } + catch (InvalidCipherTextException e) + { + // Expected + } + + try + { + // Search through plaintext lengths until one is found that creates >= 1 buffered byte + // during decryption of ciphertext for doFinal to handle + for (int i = 2; i < plaintext.length; i++) + { + cipher.init(true, params); + int encrypted = cipher.processBytes(plaintext, 0, i, ciphertext, 0); + encrypted += cipher.doFinal(ciphertext, encrypted); + + cipher.init(false, params); + cipher.processBytes(ciphertext, 0, encrypted - 1, plaintext, 0); + if (cipher.processByte(ciphertext[encrypted - 1], plaintext, 0) == 0) + { + cipher.doFinal(new byte[cipher.getOutputSize(0) - 1], 0); + fail(test, "Decrypt doFinal should check output length"); + cipher.reset(); + + // Truncated Mac should be reported in preference to inability to output + // buffered plaintext byte + try + { + cipher.processBytes(ciphertext, 0, actualOutputSize - 1, plaintext, 0); + cipher.doFinal(new byte[cipher.getOutputSize(0) - 1], 0); + fail(test, "Decrypt doFinal should check ciphertext length"); + } + catch (InvalidCipherTextException e) + { + // Expected + } + cipher.reset(); + } + } + fail(test, "Decrypt doFinal test couldn't find a ciphertext length that buffered for doFinal"); + } + catch (OutputLengthException e) + { + // Expected + } + } + + static AEADParameters reuseKey(AEADParameters p) + { + return new AEADParameters(null, p.getMacSize(), p.getNonce(), p.getAssociatedText()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESFastTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESFastTest.java new file mode 100644 index 000000000..b9dca693e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESFastTest.java @@ -0,0 +1,150 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.engines.AESFastEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test vectors from the NIST standard tests and Brian Gladman's vector set + * + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + */ +public class AESFastTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new AESFastEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(1, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(2, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(3, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(4, new AESFastEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(5, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(6, new AESFastEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(7, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(8, new AESFastEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(9, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(10, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(11, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(12, new AESFastEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(13, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(14, new AESFastEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(15, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(16, new AESFastEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(17, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(18, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(19, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(20, new AESFastEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(21, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(22, new AESFastEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(23, 10000, new AESFastEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168") + }; + + private BlockCipher _engine = new AESFastEngine(); + + AESFastTest() + { + super(tests, new AESFastEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "AESFast"; + } + + public void performTest() + throws Exception + { + super.performTest(); + + byte[] keyBytes = new byte[16]; + + _engine.init(true, new KeyParameter(keyBytes)); + + // + // init tests + // + try + { + byte[] dudKey = new byte[6]; + + _engine.init(true, new KeyParameter(dudKey)); + + fail("failed key length check"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + byte[] iv = new byte[16]; + + _engine.init(true, new ParametersWithIV(null, iv)); + + fail("failed parameter check"); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + public static void main( + String[] args) + { + runTest(new AESFastTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESLightTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESLightTest.java new file mode 100644 index 000000000..1c2fe6146 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESLightTest.java @@ -0,0 +1,150 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.engines.AESLightEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test vectors from the NIST standard tests and Brian Gladman's vector set + * + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + */ +public class AESLightTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new AESLightEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(1, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(2, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(3, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(4, new AESLightEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(5, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(6, new AESLightEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(7, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(8, new AESLightEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(9, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(10, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(11, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(12, new AESLightEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(13, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(14, new AESLightEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(15, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(16, new AESLightEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(17, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(18, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(19, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(20, new AESLightEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(21, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(22, new AESLightEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(23, 10000, new AESLightEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168") + }; + + private BlockCipher _engine = new AESLightEngine(); + + AESLightTest() + { + super(tests, new AESLightEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "AESLight"; + } + + public void performTest() + throws Exception + { + super.performTest(); + + byte[] keyBytes = new byte[16]; + + _engine.init(true, new KeyParameter(keyBytes)); + + // + // init tests + // + try + { + byte[] dudKey = new byte[6]; + + _engine.init(true, new KeyParameter(dudKey)); + + fail("failed key length check"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + byte[] iv = new byte[16]; + + _engine.init(true, new ParametersWithIV(null, iv)); + + fail("failed parameter check"); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + public static void main( + String[] args) + { + runTest(new AESLightTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESTest.java new file mode 100644 index 000000000..2c25f1f29 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESTest.java @@ -0,0 +1,478 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.OFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.SICBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test vectors from the NIST standard tests and Brian Gladman's vector set + * + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + */ +public class AESTest + extends CipherTest +{ + private static final byte[] tData = Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114F3F6752AE8D7831138F041560631B1145A01020304050607"); + private static final byte[] outCBC1 = Hex.decode("a444a9a4d46eb30cb7ed34d62873a89f8fdf2bf8a54e1aeadd06fd85c9cb46f021ee7cd4f418fa0bb72e9d07c70d5d20"); + private static final byte[] outCBC2 = Hex.decode("585681354f0e01a86b32f94ebb6a675045d923cf201263c2aaecca2b4de82da0edd74ca5efd654c688f8a58e61955b11"); + private static final byte[] outSIC1 = Hex.decode("82a1744e8ebbd053ca72362d5e570326e0b6fdaf824ab673fbf029042886b23c75129a015852913790f81f94447475a0"); + private static final byte[] outSIC2 = Hex.decode("146cbb581d9e12c3333dd9c736fbb93043c92019f78580da48f81f80b3f551d58ea836fed480fc6912fefa9c5c89cc24"); + private static final byte[] outCFB1 = Hex.decode("82a1744e8ebbd053ca72362d5e5703264b4182de3208c374b8ac4fa36af9c5e5f4f87d1e3b67963d06acf5eb13914c90"); + private static final byte[] outCFB2 = Hex.decode("146cbb581d9e12c3333dd9c736fbb9303c8a3eb5185e2809e9d3c28e25cc2d2b6f5c11ee28d6530f72c412b1438a816a"); + private static final byte[] outOFB1 = Hex.decode("82a1744e8ebbd053ca72362d5e5703261ebf1fdbec05e57b3465b583132f84b43bf95b2c89040ad1677b22d42db69a7a"); + private static final byte[] outOFB2 = Hex.decode("146cbb581d9e12c3333dd9c736fbb9309ea4c2a7696c84959a2dada49f2f1c5905db1f0cec3a31acbc4701e74ab05e1f"); + + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new AESEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(1, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(2, 10000, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(3, 10000, new AESEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(4, new AESEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(5, 10000, new AESEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(6, new AESEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(7, 10000, new AESEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(8, new AESEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(9, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(10, 10000, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(11, 10000, new AESEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(12, new AESEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(13, 10000, new AESEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(14, new AESEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(15, 10000, new AESEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(16, new AESEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(17, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(18, 10000, new AESEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(19, 10000, new AESEngine(), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(20, new AESEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(21, 10000, new AESEngine(), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(22, new AESEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(23, 10000, new AESEngine(), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168") + }; + + private BlockCipher _engine = new AESEngine(); + + public AESTest() + { + super(tests, new AESEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "AES"; + } + + private void testNullSIC() + throws InvalidCipherTextException + { + BufferedBlockCipher b = new BufferedBlockCipher(new SICBlockCipher(new AESEngine())); + KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")); + + b.init(true, new ParametersWithIV(kp, new byte[16])); + + byte[] out = new byte[b.getOutputSize(tData.length)]; + + int len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outSIC1, out)) + { + fail("no match on first nullSIC check"); + } + + b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f"))); + + len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outSIC2, out)) + { + fail("no match on second nullSIC check"); + } + } + + private void testNullCBC() + throws InvalidCipherTextException + { + BufferedBlockCipher b = new BufferedBlockCipher(new CBCBlockCipher(new AESEngine())); + KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")); + + b.init(true, new ParametersWithIV(kp, new byte[16])); + + byte[] out = new byte[b.getOutputSize(tData.length)]; + + int len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outCBC1, out)) + { + fail("no match on first nullCBC check"); + } + + b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f"))); + + len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outCBC2, out)) + { + fail("no match on second nullCBC check"); + } + } + + private void testNullOFB() + throws InvalidCipherTextException + { + BufferedBlockCipher b = new BufferedBlockCipher(new OFBBlockCipher(new AESEngine(), 128)); + KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")); + + b.init(true, new ParametersWithIV(kp, new byte[16])); + + byte[] out = new byte[b.getOutputSize(tData.length)]; + + int len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outOFB1, out)) + { + fail("no match on first nullOFB check"); + } + + b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f"))); + + len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outOFB2, out)) + { + fail("no match on second nullOFB check"); + } + } + + private void testNullCFB() + throws InvalidCipherTextException + { + BufferedBlockCipher b = new BufferedBlockCipher(new CFBBlockCipher(new AESEngine(), 128)); + KeyParameter kp = new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")); + + b.init(true, new ParametersWithIV(kp, new byte[16])); + + byte[] out = new byte[b.getOutputSize(tData.length)]; + + int len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outCFB1, out)) + { + fail("no match on first nullCFB check"); + } + + b.init(true, new ParametersWithIV(null, Hex.decode("000102030405060708090a0b0c0d0e0f"))); + + len = b.processBytes(tData, 0, tData.length, out, 0); + + len += b.doFinal(out, len); + + if (!areEqual(outCFB2, out)) + { + fail("no match on second nullCFB check"); + } + } + + private boolean areEqual(byte[] a, int aOff, byte[] b, int bOff) + { + for (int i = bOff; i != b.length; i++) + { + if (a[aOff + i - bOff] != b[i]) + { + return false; + } + } + + return true; + } + + private void skipTest() + { + CipherParameters params = new ParametersWithIV(new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), Hex.decode("00000000000000000000000000000000")); + SICBlockCipher engine = new SICBlockCipher(new AESEngine()); + + engine.init(true, params); + + SecureRandom rand = new SecureRandom(); + byte[] plain = new byte[50000]; + byte[] cipher = new byte[50000]; + + rand.nextBytes(plain); + engine.processBytes(plain, 0, plain.length, cipher, 0); + + byte[] fragment = new byte[20]; + + engine.init(true, params); + + engine.skip(10); + + if (engine.getPosition() != 10) + { + fail("skip position incorrect - 10 got " + engine.getPosition()); + } + + engine.processBytes(plain, 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 10, fragment, 0)) + { + fail("skip forward 10 failed"); + } + + engine.skip(1000); + + if (engine.getPosition() != 1010 + fragment.length) + { + fail("skip position incorrect - " + (1010 + fragment.length) + " got " + engine.getPosition()); + } + + engine.processBytes(plain, 1010 + fragment.length, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + fragment.length, fragment, 0)) + { + fail("skip forward 1000 failed"); + } + + engine.skip(-10); + + if (engine.getPosition() != 1010 + 2 * fragment.length - 10) + { + fail("skip position incorrect - " + (1010 + 2 * fragment.length - 10) + " got " + engine.getPosition()); + } + + engine.processBytes(plain, 1010 + 2 * fragment.length - 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + 2 * fragment.length - 10, fragment, 0)) + { + fail("skip back 10 failed"); + } + + engine.skip(-1000); + + if (engine.getPosition() != 60) + { + fail("skip position incorrect - " + 60 + " got " + engine.getPosition()); + } + + engine.processBytes(plain, 60, fragment.length, fragment, 0); + + if (!areEqual(cipher, 60, fragment, 0)) + { + fail("skip back 1000 failed"); + } + + long pos = engine.seekTo(1010); + + if (pos != 1010) + { + fail("position incorrect - " + 1010 + " got " + pos); + } + + engine.processBytes(plain, 1010, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010, fragment, 0)) + { + fail("seek to 1010 failed"); + } + + engine.reset(); + + for (int i = 0; i != 5000; i++) + { + engine.skip(i); + + if (engine.getPosition() != i) + { + fail("skip forward at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip forward i failed: " + i); + } + + if (engine.getPosition() != i + fragment.length) + { + fail("cipher at wrong position: " + engine.getPosition() + " [" + i + "]"); + } + + engine.skip(-fragment.length); + + if (engine.getPosition() != i) + { + fail("skip back at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip back i failed: " + i); + } + + engine.reset(); + } + } + + private void ctrCounterTest() + { + CipherParameters params = new ParametersWithIV(new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), Hex.decode("000000000000000000000000000000")); + SICBlockCipher engine = new SICBlockCipher(new AESEngine()); + + engine.init(true, params); + + SecureRandom rand = new SecureRandom(); + byte[] cipher = new byte[256 * 16]; + byte[] plain = new byte[255 * 16]; + + rand.nextBytes(plain); + engine.processBytes(plain, 0, plain.length, cipher, 0); + + engine.init(true, params); + + byte[] fragment = new byte[20]; + + plain = new byte[256 * 16]; + engine.init(true, params); + + try + { + engine.processBytes(plain, 0, plain.length, cipher, 0); + fail("out of range data not caught"); + } + catch (IllegalStateException e) + { + if (!"Counter in CTR/SIC mode out of range.".equals(e.getMessage())) + { + fail("wrong exception"); + } + } + } + + public void performTest() + throws Exception + { + super.performTest(); + + byte[] keyBytes = new byte[16]; + + _engine.init(true, new KeyParameter(keyBytes)); + + // + // init tests + // + try + { + byte[] dudKey = new byte[6]; + + _engine.init(true, new KeyParameter(dudKey)); + + fail("failed key length check"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + byte[] iv = new byte[16]; + + _engine.init(true, new ParametersWithIV(null, iv)); + + fail("failed parameter check"); + } + catch (IllegalArgumentException e) + { + // expected + } + + testNullCBC(); + testNullSIC(); + testNullOFB(); + testNullCFB(); + + skipTest(); + ctrCounterTest(); + } + + public static void main( + String[] args) + { + runTest(new AESTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESVectorFileTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESVectorFileTest.java new file mode 100644 index 000000000..fa0a6aae7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESVectorFileTest.java @@ -0,0 +1,258 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.AESFastEngine; +import com.fr.third.org.bouncycastle.crypto.engines.AESLightEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * Test vectors from the NIST standard tests and Brian Gladman's vector set + * + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + */ +public class AESVectorFileTest + implements Test +{ + + private int countOfTests = 0; + private int testNum = 0; + + protected BlockCipher createNewEngineForTest() + { + return new AESEngine(); + } + + private Test[] readTestVectors(InputStream inStream) + { + // initialize key, plaintext, ciphertext = null + // read until find BLOCKSIZE= + // return if not 128 + // read KEYSIZE= or ignore + // loop + // read a line + // if starts with BLOCKSIZE= + // parse the rest. return if not 128 + // if starts with KEY= + // parse the rest and set KEY + // if starts with PT= + // parse the rest and set plaintext + // if starts with CT= + // parse the rest and set ciphertext + // if starts with TEST= or end of file + // if key, plaintext, ciphertext are all not null + // save away their values as the next test + // until end of file + List tests = new ArrayList(); + String key = null; + String plaintext = null; + String ciphertext = null; + + BufferedReader in = new BufferedReader(new InputStreamReader(inStream)); + + try + { + String line = in.readLine(); + + while (line != null) + { + line = line.trim().toLowerCase(); + if (line.startsWith("blocksize=")) + { + int i = 0; + try + { + i = Integer.parseInt(line.substring(10).trim()); + } + catch (Exception e) + { + } + if (i != 128) + { + return null; + } + } + else if (line.startsWith("keysize=")) + { + int i = 0; + try + { + i = Integer.parseInt(line.substring(10).trim()); + } + catch (Exception e) + { + } + if ((i != 128) && (i != 192) && (i != 256)) + { + return null; + } + } + else if (line.startsWith("key=")) + { + key = line.substring(4).trim(); + } + else if (line.startsWith("pt=")) + { + plaintext = line.substring(3).trim(); + } + else if (line.startsWith("ct=")) + { + ciphertext = line.substring(3).trim(); + } + else if (line.startsWith("test=")) + { + if ((key != null) && (plaintext != null) + && (ciphertext != null)) + { + tests.add(new BlockCipherVectorTest(testNum++, + createNewEngineForTest(), new KeyParameter(Hex + .decode(key)), plaintext, ciphertext)); + } + } + + line = in.readLine(); + } + try + { + in.close(); + } + catch (IOException e) + { + } + } + catch (IOException e) + { + } + if ((key != null) && (plaintext != null) && (ciphertext != null)) + { + tests.add(new BlockCipherVectorTest(testNum++, + createNewEngineForTest(), + new KeyParameter(Hex.decode(key)), plaintext, ciphertext)); + } + return (Test[])(tests.toArray(new Test[tests.size()])); + } + + public String getName() + { + return "AES"; + } + + private TestResult performTestsFromZipFile(File zfile) + { + try + { + ZipFile inZip = new ZipFile(zfile); + for (Enumeration files = inZip.entries(); files.hasMoreElements();) + { + Test[] tests = null; + try + { + tests = readTestVectors(inZip + .getInputStream((ZipEntry)(files.nextElement()))); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": threw " + + e); + } + if (tests != null) + { + for (int i = 0; i != tests.length; i++) + { + TestResult res = tests[i].perform(); + countOfTests++; + + if (!res.isSuccessful()) + { + return res; + } + } + } + } + inZip.close(); + return new SimpleTestResult(true, getName() + ": Okay"); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": threw " + e); + } + } + + private static final String[] zipFileNames = { "rijn.tv.ecbnk.zip", + "rijn.tv.ecbnt.zip", "rijn.tv.ecbvk.zip", "rijn.tv.ecbvt.zip" }; + + public TestResult perform() + { + countOfTests = 0; + for (int i = 0; i < zipFileNames.length; i++) + { + File inf = new File(zipFileNames[i]); + TestResult res = performTestsFromZipFile(inf); + if (!res.isSuccessful()) + { + return res; + } + } + return new SimpleTestResult(true, getName() + ": " + countOfTests + + " performed Okay"); + } + + public static void main(String[] args) + { + AESVectorFileTest test = new AESVectorFileTest(); + TestResult result = test.perform(); + System.out.println(result); + + test = new AESLightVectorFileTest(); + result = test.perform(); + System.out.println(result); + + test = new AESFastVectorFileTest(); + result = test.perform(); + System.out.println(result); + + } + + private static class AESLightVectorFileTest extends AESVectorFileTest + { + protected BlockCipher createNewEngineForTest() + { + return new AESLightEngine(); + } + + public String getName() + { + return "AESLight"; + } + + } + + private static class AESFastVectorFileTest extends AESVectorFileTest + { + protected BlockCipher createNewEngineForTest() + { + return new AESFastEngine(); + } + + public String getName() + { + return "AESFast"; + } + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESWrapPadTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESWrapPadTest.java new file mode 100644 index 000000000..f5f883d28 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESWrapPadTest.java @@ -0,0 +1,173 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.Wrapper; +import com.fr.third.org.bouncycastle.crypto.engines.AESWrapPadEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * This is a test harness I use because I cannot modify the BC test harness without + * invalidating the signature on their signed provider library. The code here is not + * high quality but it does test the RFC vectors as well as randomly generated values. + * The RFC test vectors are tested by making sure both the ciphertext and decrypted + * values match the expected values whereas the random values are just checked to make + * sure that: + *

unwrap(wrap(random_value, random_kek), random_kek) == random_value.

+ */ + +public class AESWrapPadTest + extends SimpleTest +{ + + private final int numOfRandomIterations = 100; + + public AESWrapPadTest() + { + + } + + private void wrapAndUnwrap(byte[] kek, byte[] key, byte[] expected) + throws Exception + { + Wrapper wrapper = new AESWrapPadEngine(); + + wrapper.init(true, new KeyParameter(kek)); + + byte[] cipherText = wrapper.wrap(key, 0, key.length); + if (!areEqual(cipherText, expected)) + { + fail("Wrapped value does not match expected."); + } + wrapper.init(false, new KeyParameter(kek)); + byte[] plainText = wrapper.unwrap(cipherText, 0, cipherText.length); + + if (!areEqual(key, plainText)) + { + fail("Unwrapped value does not match original."); + } + } + + private void wrapAndUnwrap(byte[] kek, byte[] key) + throws Exception + { + Wrapper wrapper = new AESWrapPadEngine(); + + wrapper.init(true, new KeyParameter(kek)); + + byte[] cipherText = wrapper.wrap(key, 0, key.length); + + wrapper.init(false, new KeyParameter(kek)); + byte[] plainText = wrapper.unwrap(cipherText, 0, cipherText.length); + + if (!areEqual(key, plainText)) + { + fail("Unwrapped value does not match original."); + } + } + + private void wrapWithIVTest() + throws Exception + { + byte[] kek = Hex.decode("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); + byte[] key = Hex.decode("c37b7e6492584340bed12207808941155068f738"); + byte[] expected = Hex.decode("5cbdb3fb71351d0e628b85dbcba1a1890d4db26d1335e11d1aabea11124caad0"); + + Wrapper wrapper = new AESWrapPadEngine(); + + wrapper.init(true, new ParametersWithIV(new KeyParameter(kek), Hex.decode("33333333"))); + + byte[] cipherText = wrapper.wrap(key, 0, key.length); + if (!areEqual(cipherText, expected)) + { + fail("Wrapped value does not match expected."); + } + wrapper.init(false, new ParametersWithIV(new KeyParameter(kek), Hex.decode("33333333"))); + byte[] plainText = wrapper.unwrap(cipherText, 0, cipherText.length); + + if (!areEqual(key, plainText)) + { + fail("Unwrapped value does not match original."); + } + } + + public String getName() + { + return "AESWrapPad"; + } + + public void performTest() + throws Exception + { + // test RFC 5649 test vectors + byte[] kek = Hex.decode("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); + byte[] key = Hex.decode("c37b7e6492584340bed12207808941155068f738"); + byte[] wrap = Hex.decode("138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a"); + + wrapAndUnwrap(kek, key, wrap); + + wrap = Hex.decode("afbeb0f07dfbf5419200f2ccb50bb24f"); + key = Hex.decode("466f7250617369"); + wrapAndUnwrap(kek, key, wrap); + + wrapWithIVTest(); + + // + // offset test + // + Wrapper wrapper = new AESWrapPadEngine(); + + byte[] pText = new byte[5 + key.length]; + byte[] cText; + + System.arraycopy(key, 0, pText, 5, key.length); + + wrapper.init(true, new KeyParameter(kek)); + + cText = wrapper.wrap(pText, 5, key.length); + if (!Arrays.areEqual(cText, wrap)) + { + fail("failed offset wrap test expected " + new String(Hex.encode(wrap)) + " got " + new String(Hex.encode(cText))); + } + + wrapper.init(false, new KeyParameter(kek)); + + cText = new byte[6 + wrap.length]; + System.arraycopy(wrap, 0, cText, 6, wrap.length); + + pText = wrapper.unwrap(cText, 6, wrap.length); + if (!Arrays.areEqual(pText, key)) + { + fail("failed offset unwrap test expected " + new String(Hex.encode(key)) + " got " + new String(Hex.encode(pText))); + } + + // test random values + SecureRandom rnd = new SecureRandom(); + for (int i = 0; i < numOfRandomIterations; i++) + { + int kekLength = 128; + boolean shouldIncrease = (rnd.nextInt() & 0x01) != 0; + if (shouldIncrease) + { + kekLength = 256; + } + kek = new byte[kekLength / 8]; + rnd.nextBytes(kek); + int keyToWrapSize = RNGUtils.nextInt(rnd, 256 / 8 - 8) + 8; + byte[] keyToWrap = new byte[keyToWrapSize]; + rnd.nextBytes(keyToWrap); + wrapAndUnwrap(kek, keyToWrap); + } + } + + public static void main( + String[] args) + { + runTest(new AESWrapPadTest()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESWrapTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESWrapTest.java new file mode 100644 index 000000000..09d08b6e3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/AESWrapTest.java @@ -0,0 +1,260 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.Wrapper; +import com.fr.third.org.bouncycastle.crypto.engines.AESWrapEngine; +import com.fr.third.org.bouncycastle.crypto.engines.AESWrapPadEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * Wrap Test + */ +public class AESWrapTest + extends SimpleTest +{ + public String getName() + { + return "AESWrap"; + } + + private void wrapTest( + int id, + byte[] kek, + byte[] in, + byte[] out) + { + wrapTest(id, kek, in, out, false); + } + + private void wrapTest( + int id, + byte[] kek, + byte[] in, + byte[] out, + boolean useReverseDirection) + { + Wrapper wrapper = new AESWrapEngine(useReverseDirection); + + wrapper.init(true, new KeyParameter(kek)); + + try + { + byte[] cText = wrapper.wrap(in, 0, in.length); + if (!Arrays.areEqual(cText, out)) + { + fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail("failed wrap test exception " + e.toString()); + } + + wrapper.init(false, new KeyParameter(kek)); + + try + { + byte[] pText = wrapper.unwrap(out, 0, out.length); + if (!Arrays.areEqual(pText, in)) + { + fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); + } + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail("failed unwrap test exception.", e); + } + + // + // offset test + // + byte[] pText = new byte[5 + in.length]; + byte[] cText; + + System.arraycopy(in, 0, pText, 5, in.length); + + wrapper.init(true, new KeyParameter(kek)); + + try + { + cText = wrapper.wrap(pText, 5, in.length); + if (!Arrays.areEqual(cText, out)) + { + fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + } + catch (Exception e) + { + fail("failed wrap test exception " + e.toString()); + } + + wrapper.init(false, new KeyParameter(kek)); + + cText = new byte[6 + out.length]; + System.arraycopy(out, 0, cText, 6, out.length); + + try + { + pText = wrapper.unwrap(cText, 6, out.length); + if (!Arrays.areEqual(pText, in)) + { + fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); + } + } + catch (Exception e) + { + fail("failed unwrap test exception.", e); + } + } + + private void heapIssueTest() + { + byte[] key = Hex.decode("d305ef52a6b9e72c810b821261d2d678"); + byte[] ciphertext = Hex.decode("d2b2906d209a46261d8f6794eca3179d"); + + Wrapper aes = new AESWrapPadEngine(); + aes.init(false, new KeyParameter(key)); + try + { + byte[] result = aes.unwrap(ciphertext, 0, ciphertext.length); + + fail("incorrect pad not detected"); + } + catch (InvalidCipherTextException e) + { + // ignore + } + } + + public void performTest() + throws Exception + { + byte[] kek1 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] in1 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out1 = Hex.decode("1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5"); + + wrapTest(1, kek1, in1, out1); + + byte[] kek2 = Hex.decode("000102030405060708090a0b0c0d0e0f1011121314151617"); + byte[] in2 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out2 = Hex.decode("96778b25ae6ca435f92b5b97c050aed2468ab8a17ad84e5d"); + + wrapTest(2, kek2, in2, out2); + + byte[] kek3 = Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + byte[] in3 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out3 = Hex.decode("64e8c3f9ce0f5ba263e9777905818a2a93c8191e7d6e8ae7"); + + wrapTest(3, kek3, in3, out3); + + byte[] kek4 = Hex.decode("000102030405060708090a0b0c0d0e0f1011121314151617"); + byte[] in4 = Hex.decode("00112233445566778899aabbccddeeff0001020304050607"); + byte[] out4 = Hex.decode("031d33264e15d33268f24ec260743edce1c6c7ddee725a936ba814915c6762d2"); + wrapTest(4, kek4, in4, out4); + + byte[] kek5 = Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + byte[] in5 = Hex.decode("00112233445566778899aabbccddeeff0001020304050607"); + byte[] out5 = Hex.decode("a8f9bc1612c68b3ff6e6f4fbe30e71e4769c8b80a32cb8958cd5d17d6b254da1"); + wrapTest(5, kek5, in5, out5); + + byte[] kek6 = Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + byte[] in6 = Hex.decode("00112233445566778899aabbccddeeff000102030405060708090a0b0c0d0e0f"); + byte[] out6 = Hex.decode("28c9f404c4b810f4cbccb35cfb87f8263f5786e2d80ed326cbc7f0e71a99f43bfb988b9b7a02dd21"); + wrapTest(6, kek6, in6, out6); + + byte[] kek7 = Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); + byte[] in7 = Hex.decode("00112233445566778899aabbccddeeff000102030405060708090a0b0c0d0e0f"); + byte[] out7 = Hex.decode("cba01acbdb4c7c39fa59babb383c485f318837208731a81c735b5be6ba710375a1159e26a9b57228"); + wrapTest(7, kek7, in7, out7, true); + + Wrapper wrapper = new AESWrapEngine(); + KeyParameter key = new KeyParameter(new byte[16]); + byte[] buf = new byte[16]; + + try + { + wrapper.init(true, key); + + wrapper.unwrap(buf, 0, buf.length); + + fail("failed unwrap state test."); + } + catch (IllegalStateException e) + { + // expected + } + catch (InvalidCipherTextException e) + { + fail("unexpected exception: " + e, e); + } + + try + { + wrapper.init(false, key); + + wrapper.wrap(buf, 0, buf.length); + + fail("failed unwrap state test."); + } + catch (IllegalStateException e) + { + // expected + } + + // + // short test + // + try + { + wrapper.init(false, key); + + wrapper.unwrap(buf, 0, buf.length / 2); + + fail("failed unwrap short test."); + } + catch (InvalidCipherTextException e) + { + // expected + } + + try + { + wrapper.init(true, key); + + wrapper.wrap(buf, 0, 15); + + fail("ailed wrap length test."); + } + catch (DataLengthException e) + { + // expected + } + + heapIssueTest(); + } + + public static void main( + String[] args) + { + AESWrapTest test = new AESWrapTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ARIATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ARIATest.java new file mode 100644 index 000000000..2e9344568 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ARIATest.java @@ -0,0 +1,167 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.engines.ARIAEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ARIATest + extends SimpleTest +{ + private static SecureRandom R = new SecureRandom(); + + private static final String[][] TEST_VECTORS_RFC5794 = { + { + "128-Bit Key", + "000102030405060708090a0b0c0d0e0f", + "00112233445566778899aabbccddeeff", + "d718fbd6ab644c739da95f3be6451778" + }, + { + "192-Bit Key", + "000102030405060708090a0b0c0d0e0f1011121314151617", + "00112233445566778899aabbccddeeff", + "26449c1805dbe7aa25a468ce263a9e79" + }, + { + "256-Bit Key", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "00112233445566778899aabbccddeeff", + "f92bd7c79fb72e2f2b8f80c1972d24fc" + }, + }; + + public String getName() + { + return "ARIA"; + } + + public void performTest() throws Exception + { + checkTestVectors_RFC5794(); + + for (int i = 0; i < 100; ++i) + { + checkRandomRoundtrips(); + } + + new MyARIAEngine().checkImplementation(); + } + + private void checkRandomRoundtrips() + { + ARIAEngine ce = new ARIAEngine(); + ARIAEngine cd = new ARIAEngine(); + + byte[] txt = new byte[ce.getBlockSize()]; + byte[] enc = new byte[ce.getBlockSize()]; + byte[] dec = new byte[ce.getBlockSize()]; + + for (int keyLen = 16; keyLen <= 32; keyLen += 8) + { + byte[] K = new byte[keyLen]; + + R.nextBytes(K); + + KeyParameter key = new KeyParameter(K); + ce.init(true, key); + cd.init(false, key); + + R.nextBytes(txt); + + for (int i = 0; i < 100; ++i) + { + ce.processBlock(txt, 0, enc, 0); + cd.processBlock(enc, 0, dec, 0); + + isTrue(Arrays.areEqual(txt, dec)); + + System.arraycopy(enc, 0, txt, 0, enc.length); + } + } + } + + private void checkTestVector_RFC5794(String[] tv) + { + String name = "'" + tv[0] + "'"; + + BlockCipher c = new ARIAEngine(); + int blockSize = c.getBlockSize(); + isTrue("Wrong block size returned from getBlockSize() for " + name, 16 == blockSize); + + KeyParameter key = new KeyParameter(Hex.decode(tv[1])); + byte[] plaintext = Hex.decode(tv[2]); + byte[] ciphertext = Hex.decode(tv[3]); + + isTrue("Unexpected plaintext length for " + name, blockSize == plaintext.length); + isTrue("Unexpected ciphertext length for " + name, blockSize == ciphertext.length); + + c.init(true, key); + + byte[] actual = new byte[blockSize]; + int num = c.processBlock(plaintext, 0, actual, 0); + + isTrue("Wrong length returned from processBlock() (encryption) for " + name, blockSize == num); + isTrue("Incorrect ciphertext computed for " + name, Arrays.areEqual(ciphertext, actual)); + + c.init(false, key); + num = c.processBlock(ciphertext, 0, actual, 0); + + isTrue("Wrong length returned from processBlock() (decryption) for " + name, blockSize == num); + isTrue("Incorrect plaintext computed for " + name, Arrays.areEqual(plaintext, actual)); + } + + private void checkTestVectors_RFC5794() + { + for (int i = 0; i < TEST_VECTORS_RFC5794.length; ++i) + { + checkTestVector_RFC5794(TEST_VECTORS_RFC5794[i]); + } + } + + public static void main(String[] args) + { + runTest(new ARIATest()); + } + + private class MyARIAEngine extends ARIAEngine + { + public void checkImplementation() + { + checkInvolution(); + checkSBoxes(); + } + + private void checkInvolution() + { + byte[] x = new byte[16], y = new byte[16]; + + for (int i = 0; i < 100; ++i) + { + R.nextBytes(x); + System.arraycopy(x, 0, y, 0, 16); + A(y); + A(y); + ARIATest.this.isTrue(Arrays.areEqual(x, y)); + } + } + + private void checkSBoxes() + { + for (int i = 0; i < 256; ++i) + { + byte x = (byte)i; + + ARIATest.this.isTrue(x == SB1(SB3(x))); + ARIATest.this.isTrue(x == SB3(SB1(x))); + + ARIATest.this.isTrue(x == SB2(SB4(x))); + ARIATest.this.isTrue(x == SB4(SB2(x))); + } + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Argon2Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Argon2Test.java new file mode 100644 index 000000000..65aa16a62 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Argon2Test.java @@ -0,0 +1,225 @@ +package com.fr.third.org.bouncycastle.crypto.test; + + +import com.fr.third.org.bouncycastle.crypto.generators.Argon2BytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.Argon2Parameters; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Tests from https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03 + * + */ +public class Argon2Test + extends SimpleTest +{ + private static final int DEFAULT_OUTPUTLEN = 32; + + public String getName() + { + return "ArgonTest"; + } + + public void performTest() + throws Exception + { + if (getJvmVersion() < 7) + { + return; + } + + testVectorsFromInternetDraft(); + + int version = Argon2Parameters.ARGON2_VERSION_10; + + + /* Multiple test cases for various input values */ + hashTest(version, 2, 16, 1, "password", "somesalt", + "f6c4db4a54e2a370627aff3db6176b94a2a209a62c8e36152711802f7b30c694", DEFAULT_OUTPUTLEN); + + hashTest(version, 2, 20, 1, "password", "somesalt", + "9690ec55d28d3ed32562f2e73ea62b02b018757643a2ae6e79528459de8106e9", + DEFAULT_OUTPUTLEN); + + hashTest(version, 2, 18, 1, "password", "somesalt", + "3e689aaa3d28a77cf2bc72a51ac53166761751182f1ee292e3f677a7da4c2467", + DEFAULT_OUTPUTLEN); + + hashTest(version, 2, 8, 1, "password", "somesalt", + "fd4dd83d762c49bdeaf57c47bdcd0c2f1babf863fdeb490df63ede9975fccf06", + DEFAULT_OUTPUTLEN); + hashTest(version, 2, 8, 2, "password", "somesalt", + "b6c11560a6a9d61eac706b79a2f97d68b4463aa3ad87e00c07e2b01e90c564fb", DEFAULT_OUTPUTLEN); + hashTest(version, 1, 16, 1, "password", "somesalt", + "81630552b8f3b1f48cdb1992c4c678643d490b2b5eb4ff6c4b3438b5621724b2", DEFAULT_OUTPUTLEN); + hashTest(version, 4, 16, 1, "password", "somesalt", + "f212f01615e6eb5d74734dc3ef40ade2d51d052468d8c69440a3a1f2c1c2847b", DEFAULT_OUTPUTLEN); + hashTest(version, 2, 16, 1, "differentpassword", "somesalt", + "e9c902074b6754531a3a0be519e5baf404b30ce69b3f01ac3bf21229960109a3", DEFAULT_OUTPUTLEN); + hashTest(version, 2, 16, 1, "password", "diffsalt", + "79a103b90fe8aef8570cb31fc8b22259778916f8336b7bdac3892569d4f1c497", DEFAULT_OUTPUTLEN); + + hashTest(version, 2, 16, 1, "password", "diffsalt", + "1a097a5d1c80e579583f6e19c7e4763ccb7c522ca85b7d58143738e12ca39f8e6e42734c950ff2463675b97c37ba" + + "39feba4a9cd9cc5b4c798f2aaf70eb4bd044c8d148decb569870dbd923430b82a083f284beae777812cce18cdac68ee8ccef" + + "c6ec9789f30a6b5a034591f51af830f4", + 112); + + + version = Argon2Parameters.ARGON2_VERSION_13; + + + /* Multiple test cases for various input values */ + hashTest(version, 2, 16, 1, "password", "somesalt", + "c1628832147d9720c5bd1cfd61367078729f6dfb6f8fea9ff98158e0d7816ed0", + DEFAULT_OUTPUTLEN); + + hashTest(version, 2, 20, 1, "password", "somesalt", + "d1587aca0922c3b5d6a83edab31bee3c4ebaef342ed6127a55d19b2351ad1f41", DEFAULT_OUTPUTLEN); + + hashTest(version, 2, 18, 1, "password", "somesalt", + "296dbae80b807cdceaad44ae741b506f14db0959267b183b118f9b24229bc7cb", DEFAULT_OUTPUTLEN); + + hashTest(version, 2, 8, 1, "password", "somesalt", + "89e9029f4637b295beb027056a7336c414fadd43f6b208645281cb214a56452f", DEFAULT_OUTPUTLEN); + + hashTest(version, 2, 8, 2, "password", "somesalt", + "4ff5ce2769a1d7f4c8a491df09d41a9fbe90e5eb02155a13e4c01e20cd4eab61", DEFAULT_OUTPUTLEN); + hashTest(version, 1, 16, 1, "password", "somesalt", + "d168075c4d985e13ebeae560cf8b94c3b5d8a16c51916b6f4ac2da3ac11bbecf", DEFAULT_OUTPUTLEN); + hashTest(version, 4, 16, 1, "password", "somesalt", + "aaa953d58af3706ce3df1aefd4a64a84e31d7f54175231f1285259f88174ce5b", DEFAULT_OUTPUTLEN); + hashTest(version, 2, 16, 1, "differentpassword", "somesalt", + "14ae8da01afea8700c2358dcef7c5358d9021282bd88663a4562f59fb74d22ee", DEFAULT_OUTPUTLEN); + hashTest(version, 2, 16, 1, "password", "diffsalt", + "b0357cccfbef91f3860b0dba447b2348cbefecadaf990abfe9cc40726c521271", DEFAULT_OUTPUTLEN); + + } + + + private void hashTest(int version, int iterations, int memory, int parallelism, + String password, String salt, String passwordRef, int outputLength) + { + Argon2Parameters.Builder builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_i) + .withVersion(version) + .withIterations(iterations) + .withMemoryPowOfTwo(memory) + .withParallelism(parallelism) + .withSalt(Strings.toByteArray(salt)); + + // + // Set the password. + // + Argon2BytesGenerator gen = new Argon2BytesGenerator(); + + gen.init(builder.build()); + + byte[] result = new byte[outputLength]; + gen.generateBytes(password.toCharArray(), result, 0, result.length); + + + isTrue(passwordRef + " Failed", areEqual(result, Hex.decode(passwordRef))); + } + + + /** + * Tests from https://tools.ietf.org/html/draft-irtf-cfrg-argon2-03 + * + * @throws Exception + */ + private void testVectorsFromInternetDraft() + { + byte[] ad = Hex.decode("040404040404040404040404"); + byte[] secret = Hex.decode("0303030303030303"); + byte[] salt = Hex.decode("02020202020202020202020202020202"); + byte[] password = Hex.decode("0101010101010101010101010101010101010101010101010101010101010101"); + + Argon2Parameters.Builder builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_d) + .withVersion(Argon2Parameters.ARGON2_VERSION_13) // 19 + .withIterations(3) + .withMemoryAsKB(32) + .withParallelism(4) + .withAdditional(ad) + .withSecret(secret) + .withSalt(salt); + + Argon2BytesGenerator dig = new Argon2BytesGenerator(); + + dig.init(builder.build()); + + byte[] result = new byte[32]; + dig.generateBytes(password, result); + isTrue("Argon 2d Failed", areEqual(result, Hex.decode("512b391b6f1162975371d30919734294f" + + "868e3be3984f3c1a13a4db9fabe4acb"))); + + + builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_i) + .withVersion(Argon2Parameters.ARGON2_VERSION_13) // 19 + .withIterations(3) + .withMemoryAsKB(32) + .withParallelism(4) + .withAdditional(ad) + .withSecret(secret) + .withSalt(salt); + + dig = new Argon2BytesGenerator(); + + dig.init(builder.build()); + + result = new byte[32]; + dig.generateBytes(password, result); + isTrue("Argon 2i Failed", areEqual(result, Hex.decode("c814d9d1dc7f37aa13f0d77f2494bda1c8de6b016" + + "dd388d29952a4c4672b6ce8"))); + + + builder = new Argon2Parameters.Builder(Argon2Parameters.ARGON2_id) + .withVersion(Argon2Parameters.ARGON2_VERSION_13) // 19 + .withIterations(3) + .withMemoryAsKB(32) + .withParallelism(4) + .withAdditional(ad) + .withSecret(secret) + .withSalt(salt); + + dig = new Argon2BytesGenerator(); + + dig.init(builder.build()); + + result = new byte[32]; + dig.generateBytes(password, result); + isTrue("Argon 2id Failed", areEqual(result, Hex.decode("0d640df58d78766c08c037a34a8b53c9d01ef0452" + + "d75b65eb52520e96b01e659"))); + + } + + private static int getJvmVersion() + { + String version = System.getProperty("java.version"); + + if (version.startsWith("1.7")) + { + return 7; + } + if (version.startsWith("1.8")) + { + return 8; + } + if (version.startsWith("1.9")) + { + return 9; + } + if (version.startsWith("1.1")) + { + return 10; + } + + return -1; + } + + public static void main(String[] args) + { + runTest(new Argon2Test()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BCryptTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BCryptTest.java new file mode 100644 index 000000000..bb88d4aa7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BCryptTest.java @@ -0,0 +1,153 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.generators.BCrypt; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Integers; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/* + * bcrypt test vectors + */ +public class BCryptTest + extends SimpleTest +{ + // Raw test vectors based on crypt style test vectors + // Cross checked with JBCrypt + private static final Object[][] testVectors = { + {"", "144b3d691a7b4ecf39cf735c7fa7a79c", Integers.valueOf(6), "557e94f34bf286e8719a26be94ac1e16d95ef9f819dee092"}, + {"00", "144b3d691a7b4ecf39cf735c7fa7a79c", Integers.valueOf(6), "557e94f34bf286e8719a26be94ac1e16d95ef9f819dee092"}, + {"00", "26c63033c04f8bcba2fe24b574db6274", Integers.valueOf(8), "56701b26164d8f1bc15225f46234ac8ac79bf5bc16bf48ba"}, + {"00", "9b7c9d2ada0fd07091c915d1517701d6", Integers.valueOf(10), "7b2e03106a43c9753821db688b5cc7590b18fdf9ba544632"}, + {"6100", "a3612d8c9a37dac2f99d94da03bd4521", Integers.valueOf(6), "e6d53831f82060dc08a2e8489ce850ce48fbf976978738f3"}, + {"6100", "7a17b15dfe1c4be10ec6a3ab47818386", Integers.valueOf(8), "a9f3469a61cbff0a0f1a1445dfe023587f38b2c9c40570e1"}, + {"6100", "9bef4d04e1f8f92f3de57323f8179190", Integers.valueOf(10), "5169fd39606d630524285147734b4c981def0ee512c3ace1"}, + {"61626300", "2a1f1dc70a3d147956a46febe3016017", Integers.valueOf(6), "d9a275b493bcbe1024b0ff80d330253cfdca34687d8f69e5"}, + {"61626300", "4ead845a142c9bc79918c8797f470ef5", Integers.valueOf(8), "8d4131a723bfbbac8a67f2e035cae08cc33b69f37331ea91"}, + {"61626300", "631c554493327c32f9c26d9be7d18e4c", Integers.valueOf(10), "8cd0b863c3ff0860e31a2b42427974e0283b3af7142969a6"}, + {"6162636465666768696a6b6c6d6e6f707172737475767778797a00", "02d1176d74158ee29cffdac6150cf123", Integers.valueOf(6), "4d38b523ce9dc6f2f6ff9fb3c2cd71dfe7f96eb4a3baf19f"}, + {"6162636465666768696a6b6c6d6e6f707172737475767778797a00", "715b96caed2ac92c354ed16c1e19e38a", Integers.valueOf(8), "98bf9ffc1f5be485f959e8b1d526392fbd4ed2d5719f506b"}, + {"6162636465666768696a6b6c6d6e6f707172737475767778797a00", "85727e838f9049397fbec90566ede0df", Integers.valueOf(10), "cebba53f67bd28af5a44c6707383c231ac4ef244a6f5fb2b"}, + {"7e21402324255e262a28292020202020207e21402324255e262a2829504e4246524400", "8512ae0d0fac4ec9a5978f79b6171028", Integers.valueOf(6), "26f517fe5345ad575ba7dfb8144f01bfdb15f3d47c1e146a"}, + {"7e21402324255e262a28292020202020207e21402324255e262a2829504e4246524400", "1ace2de8807df18c79fced54678f388f", Integers.valueOf(8), "d51d7cdf839b91a25758b80141e42c9f896ae80fd6cd561f"}, + {"7e21402324255e262a28292020202020207e21402324255e262a2829504e4246524400", "36285a6267751b14ba2dc989f6d43126", Integers.valueOf(10), "db4fab24c1ff41c1e2c966f8b3d6381c76e86f52da9e15a9"}, + {"c2a300", "144b3d691a7b4ecf39cf735c7fa7a79c", Integers.valueOf(6), "5a6c4fedb23980a7da9217e0442565ac6145b687c7313339"}, + }; + + public String getName() + { + return "BCrypt"; + } + + public void performTest() + throws Exception + { + testParameters(); + testShortKeys(); + testVectors(); + } + + private void testShortKeys() + { + byte[] salt = new byte[16]; + + // Check BCrypt with empty key pads to zero byte key + byte[] hashEmpty = BCrypt.generate(new byte[0], salt, 4); + byte[] hashZero1 = BCrypt.generate(new byte[1], salt, 4); + + if (!Arrays.areEqual(hashEmpty, hashZero1)) + { + fail("Hash for empty password should equal zeroed key", new String(Hex.encode(hashEmpty)), + new String(Hex.encode(hashZero1))); + } + + // Check zeroed byte key of min Blowfish length is equivalent + byte[] hashZero4 = BCrypt.generate(new byte[4], salt, 4); + if (!Arrays.areEqual(hashEmpty, hashZero4)) + { + fail("Hash for empty password should equal zeroed key[4]", new String(Hex.encode(hashEmpty)), new String( + Hex.encode(hashZero4))); + } + + // Check BCrypt isn't padding too small (32 bit) keys + byte[] hashA = BCrypt.generate(new byte[]{(byte)'a'}, salt, 4); + byte[] hashA0 = BCrypt.generate(new byte[]{(byte)'a', (byte)0}, salt, 4); + if (Arrays.areEqual(hashA, hashA0)) + { + fail("Small keys should not be 0 padded."); + } + } + + public void testParameters() + { + checkOK("Empty key", new byte[0], new byte[16], 4); + checkOK("Minimal values", new byte[1], new byte[16], 4); + // checkOK("Max cost", new byte[1], new byte[16], 31); + checkOK("Max passcode", new byte[72], new byte[16], 4); + checkIllegal("Null password", null, new byte[16], 4); + checkIllegal("Null salt", new byte[1], null, 4); + checkIllegal("Salt too small", new byte[1], new byte[15], 4); + checkIllegal("Salt too big", new byte[1], new byte[17], 4); + checkIllegal("Cost too low", new byte[16], new byte[16], 3); + checkIllegal("Cost too high", new byte[16], new byte[16], 32); + checkIllegal("Passcode too long", new byte[73], new byte[16], 32); + } + + private void checkOK(String msg, byte[] pass, byte[] salt, int cost) + { + try + { + BCrypt.generate(pass, salt, cost); + } + catch (IllegalArgumentException e) + { + e.printStackTrace(); + fail(msg); + } + } + + private void checkIllegal(String msg, byte[] pass, byte[] salt, int cost) + { + try + { + BCrypt.generate(pass, salt, cost); + fail(msg); + } + catch (IllegalArgumentException e) + { + // e.printStackTrace(); + } + } + + public void testVectors() + throws Exception + { + for (int i = 0; i < testVectors.length; i++) + { + byte[] password = Hex.decode((String)testVectors[i][0]); + byte[] salt = Hex.decode((String)testVectors[i][1]); + int cost = ((Integer)testVectors[i][2]).intValue(); + byte[] expected = Hex.decode((String)testVectors[i][3]); + + test(password, salt, cost, expected); + } + + isTrue(areEqual(BCrypt.generate(BCrypt.passwordToByteArray("12341234".toCharArray()), Hex.decode("01020304050607080102030405060708"), 5), Hex.decode("cdd19088721c50e5cb49a7b743d93b5a6e67bef0f700cd78"))); + isTrue(areEqual(BCrypt.generate(BCrypt.passwordToByteArray("1234".toCharArray()), Hex.decode("01020304050607080102030405060708"), 5), Hex.decode("02a3269aca2732484057b40c614204814cbfc2becd8e093e"))); + } + + private void test(byte[] password, byte[] salt, int cost, byte[] expected) + { + byte[] hash = BCrypt.generate(password, salt, cost); + if (!Arrays.areEqual(hash, expected)) + { + fail("Hash for " + new String(Hex.encode(password)), new String(Hex.encode(expected)), + new String(Hex.encode(hash))); + } + } + + public static void main(String[] args) + { + runTest(new BCryptTest()); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BigIntegersTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BigIntegersTest.java new file mode 100644 index 000000000..e7dc6fe51 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BigIntegersTest.java @@ -0,0 +1,34 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomData; + +public class BigIntegersTest + extends SimpleTest +{ + public String getName() + { + return "BigIntegers"; + } + + public void performTest() + throws Exception + { + BigInteger min = BigInteger.valueOf(5); + isTrue(min.equals(BigIntegers.createRandomPrime(min.bitLength(), 1, + new TestRandomData(BigIntegers.asUnsignedByteArray(min))))); + + BigInteger max = BigInteger.valueOf(743); + isTrue(max.equals(BigIntegers.createRandomPrime(max.bitLength(), 1, + new TestRandomData(BigIntegers.asUnsignedByteArray(max))))); + } + + public static void main(String[] args) + throws Exception + { + runTest(new BigIntegersTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Blake2bDigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Blake2bDigestTest.java new file mode 100644 index 000000000..5550a7b1f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Blake2bDigestTest.java @@ -0,0 +1,328 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.UnsupportedEncodingException; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.Blake2bDigest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Blake2bDigestTest + extends SimpleTest +{ + + private static final String[][] keyedTestVectors = + { // input/message, key, hash + + // Vectors from BLAKE2 web site: https://blake2.net/blake2b-test.txt + { + "", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "10ebb67700b1868efb4417987acf4690ae9d972fb7a590c2f02871799aaa4786b5e996e8f0f4eb981fc214b005f42d2ff4233499391653df7aefcbc13fc51568"}, + + { + "00", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "961f6dd1e4dd30f63901690c512e78e4b45e4742ed197c3c5e45c549fd25f2e4187b0bc9fe30492b16b0d0bc4ef9b0f34c7003fac09a5ef1532e69430234cebd"}, + + { + "0001", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "da2cfbe2d8409a0f38026113884f84b50156371ae304c4430173d08a99d9fb1b983164a3770706d537f49e0c916d9f32b95cc37a95b99d857436f0232c88a965"}, + + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "f1aa2b044f8f0c638a3f362e677b5d891d6fd2ab0765f6ee1e4987de057ead357883d9b405b9d609eea1b869d97fb16d9b51017c553f3b93c0a1e0f1296fedcd"}, + + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "c230f0802679cb33822ef8b3b21bf7a9a28942092901d7dac3760300831026cf354c9232df3e084d9903130c601f63c1f4a4a4b8106e468cd443bbe5a734f45f"}, + + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + "142709d62e28fcccd0af97fad0f8465b971e82201dc51070faa0372aa43e92484be1c1e73ba10906d5d1853db6a4106e0a7bf9800d373d6dee2d46d62ef2a461"}}; + + private final static String[][] unkeyedTestVectors = + { // from: http://fossies.org/linux/john/src/rawBLAKE2_512_fmt_plug.c + // hash, input/message + // digests without leading $BLAKE2$ + { + "4245af08b46fbb290222ab8a68613621d92ce78577152d712467742417ebc1153668f1c9e1ec1e152a32a9c242dc686d175e087906377f0c483c5be2cb68953e", + "blake2"}, + { + "021ced8799296ceca557832ab941a50b4a11f83478cf141f51f933f653ab9fbcc05a037cddbed06e309bf334942c4e58cdf1a46e237911ccd7fcf9787cbc7fd0", + "hello world"}, + { + "1f7d9b7c9a90f7bfc66e52b69f3b6c3befbd6aee11aac860e99347a495526f30c9e51f6b0db01c24825092a09dd1a15740f0ade8def87e60c15da487571bcef7", + "verystrongandlongpassword"}, + { + "a8add4bdddfd93e4877d2746e62817b116364a1fa7bc148d95090bc7333b3673f82401cf7aa2e4cb1ecd90296e3f14cb5413f8ed77be73045b13914cdcd6a918", + "The quick brown fox jumps over the lazy dog"}, + { + "786a02f742015903c6c6fd852552d272912f4740e15847618a86e217f71f5419d25e1031afee585313896444934eb04b903a685b1448b755d56f701afe9be2ce", + ""}, + { + "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923", + "abc"}, + }; + + public String getName() + { + return "BLAKE2b"; + } + + private void offsetTest( + Digest digest, + byte[] input, + byte[] expected) + { + byte[] resBuf = new byte[expected.length + 11]; + + digest.update(input, 0, input.length); + + digest.doFinal(resBuf, 11); + + if (!areEqual(Arrays.copyOfRange(resBuf, 11, resBuf.length), expected)) + { + fail("Offset failed got " + new String(Hex.encode(resBuf))); + } + } + + public void performTest() + throws Exception + { + // test keyed test vectors: + + Blake2bDigest blake2bkeyed = new Blake2bDigest(Hex.decode(keyedTestVectors[0][1])); + for (int tv = 0; tv < keyedTestVectors.length; tv++) + { + + byte[] input = Hex.decode(keyedTestVectors[tv][0]); + blake2bkeyed.reset(); + + blake2bkeyed.update(input, 0, input.length); + byte[] keyedHash = new byte[64]; + blake2bkeyed.doFinal(keyedHash, 0); + + if (!Arrays.areEqual(Hex.decode(keyedTestVectors[tv][2]), keyedHash)) + { + fail("BLAKE2b mismatch on test vector ", + keyedTestVectors[tv][2], + new String(Hex.encode(keyedHash))); + } + + offsetTest(blake2bkeyed, input, keyedHash); + } + + Blake2bDigest blake2bunkeyed = new Blake2bDigest(); + // test unkeyed test vectors: + for (int i = 0; i < unkeyedTestVectors.length; i++) + { + + try + { + // blake2bunkeyed.update( + // unkeyedTestVectors[i][1].getBytes("UTF-8")); + // test update(byte b) + byte[] unkeyedInput = unkeyedTestVectors[i][1] + .getBytes("UTF-8"); + for (int j = 0; j < unkeyedInput.length; j++) + { + blake2bunkeyed.update(unkeyedInput[j]); + } + } + catch (UnsupportedEncodingException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + byte[] unkeyedHash = new byte[64]; + blake2bunkeyed.doFinal(unkeyedHash, 0); + blake2bunkeyed.reset(); + + if (!Arrays.areEqual(Hex.decode(unkeyedTestVectors[i][0]), + unkeyedHash)) + { + fail("BLAKE2b mismatch on test vector ", + unkeyedTestVectors[i][0], + new String(Hex.encode(unkeyedHash))); + } + } + + cloneTest(); + resetTest(); + testNullKeyVsUnkeyed(); + testLengthConstruction(); + } + + private void cloneTest() + { + Blake2bDigest blake2bCloneSource = new Blake2bDigest(Hex.decode(keyedTestVectors[3][1]), 16, Hex.decode("000102030405060708090a0b0c0d0e0f"), Hex.decode("101112131415161718191a1b1c1d1e1f")); + byte[] expected = Hex.decode("b6d48ed5771b17414c4e08bd8d8a3bc4"); + + checkClone(blake2bCloneSource, expected); + + // just digest size + blake2bCloneSource = new Blake2bDigest(160); + expected = Hex.decode("64202454e538279b21cea0f5a7688be656f8f484"); + checkClone(blake2bCloneSource, expected); + + // null salt and personalisation + blake2bCloneSource = new Blake2bDigest(Hex.decode(keyedTestVectors[3][1]), 16, null, null); + expected = Hex.decode("2b4a081fae2d7b488f5eed7e83e42a20"); + checkClone(blake2bCloneSource, expected); + + // null personalisation + blake2bCloneSource = new Blake2bDigest(Hex.decode(keyedTestVectors[3][1]), 16, Hex.decode("000102030405060708090a0b0c0d0e0f"), null); + expected = Hex.decode("00c3a2a02fcb9f389857626e19d706f6"); + checkClone(blake2bCloneSource, expected); + + // null salt + blake2bCloneSource = new Blake2bDigest(Hex.decode(keyedTestVectors[3][1]), 16, null, Hex.decode("101112131415161718191a1b1c1d1e1f")); + expected = Hex.decode("f445ec9c062a3c724f8fdef824417abb"); + checkClone(blake2bCloneSource, expected); + } + + private void checkClone(Blake2bDigest blake2bCloneSource, byte[] expected) + { + byte[] message = Hex.decode(keyedTestVectors[3][0]); + + blake2bCloneSource.update(message, 0, message.length); + + byte[] hash = new byte[blake2bCloneSource.getDigestSize()]; + + Blake2bDigest digClone = new Blake2bDigest(blake2bCloneSource); + + blake2bCloneSource.doFinal(hash, 0); + if (!areEqual(expected, hash)) + { + fail("clone source not correct"); + } + + digClone.doFinal(hash, 0); + if (!areEqual(expected, hash)) + { + fail("clone not correct"); + } + } + + private void testLengthConstruction() + { + try + { + new Blake2bDigest(-1); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("BLAKE2b digest bit length must be a multiple of 8 and not greater than 512", e.getMessage()); + } + + try + { + new Blake2bDigest(9); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("BLAKE2b digest bit length must be a multiple of 8 and not greater than 512", e.getMessage()); + } + + try + { + new Blake2bDigest(520); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("BLAKE2b digest bit length must be a multiple of 8 and not greater than 512", e.getMessage()); + } + + try + { + new Blake2bDigest(null, -1, null, null); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("Invalid digest length (required: 1 - 64)", e.getMessage()); + } + + try + { + new Blake2bDigest(null, 65, null, null); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("Invalid digest length (required: 1 - 64)", e.getMessage()); + } + } + + private void testNullKeyVsUnkeyed() + { + byte[] abc = Strings.toByteArray("abc"); + + for (int i = 1; i != 64; i++) + { + Blake2bDigest dig1 = new Blake2bDigest(i * 8); + Blake2bDigest dig2 = new Blake2bDigest(null, i, null, null); + + byte[] out1 = new byte[i]; + byte[] out2 = new byte[i]; + + dig1.update(abc, 0, abc.length); + dig2.update(abc, 0, abc.length); + + dig1.doFinal(out1, 0); + dig2.doFinal(out2, 0); + + isTrue(Arrays.areEqual(out1, out2)); + } + } + + private void resetTest() + { + // Generate a non-zero key + byte[] key = new byte[32]; + for (byte i = 0; i < key.length; i++) + { + key[i] = i; + } + // Generate some non-zero input longer than the key + byte[] input = new byte[key.length + 1]; + for (byte i = 0; i < input.length; i++) + { + input[i] = i; + } + // Hash the input + Blake2bDigest digest = new Blake2bDigest(key); + digest.update(input, 0, input.length); + byte[] hash = new byte[digest.getDigestSize()]; + digest.doFinal(hash, 0); + // Using a second instance, hash the input without calling doFinal() + Blake2bDigest digest1 = new Blake2bDigest(key); + digest1.update(input, 0, input.length); + // Reset the second instance and hash the input again + digest1.reset(); + digest1.update(input, 0, input.length); + byte[] hash1 = new byte[digest.getDigestSize()]; + digest1.doFinal(hash1, 0); + // The hashes should be identical + if (!Arrays.areEqual(hash, hash1)) + { + fail("state was not reset"); + } + } + + public static void main(String[] args) + throws Exception + { + runTest(new Blake2bDigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Blake2sDigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Blake2sDigestTest.java new file mode 100644 index 000000000..e5e1a9dba --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Blake2sDigestTest.java @@ -0,0 +1,311 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.util.Random; + +import com.fr.third.org.bouncycastle.crypto.digests.Blake2sDigest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Blake2sDigestTest + extends SimpleTest +{ + + // Vectors from BLAKE2 web site: https://blake2.net/blake2s-test.txt + private static final String[][] keyedTestVectors = { + // input/message, key, hash + { + "", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "48a8997da407876b3d79c0d92325ad3b89cbb754d86ab71aee047ad345fd2c49", + }, + { + "00", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "40d15fee7c328830166ac3f918650f807e7e01e177258cdc0a39b11f598066f1", + }, + { + "0001", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "6bb71300644cd3991b26ccd4d274acd1adeab8b1d7914546c1198bbe9fc9d803", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "172ffc67153d12e0ca76a8b6cd5d4731885b39ce0cac93a8972a18006c8b8baf", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "4f8ce1e51d2fe7f24043a904d898ebfc91975418753413aa099b795ecb35cedb", + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfe", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3fb735061abc519dfe979e54c1ee5bfad0a9d858b3315bad34bde999efd724dd", + }, + }; + + public String getName() + { + return "BLAKE2s"; + } + + public void testDigestWithKeyedTestVectors() + { + Blake2sDigest digest = new Blake2sDigest(Hex.decode( + keyedTestVectors[0][1])); + for (int i = 0; i != keyedTestVectors.length; i++) + { + String[] keyedTestVector = keyedTestVectors[i]; + byte[] input = Hex.decode(keyedTestVector[0]); + digest.reset(); + + digest.update(input, 0, input.length); + byte[] hash = new byte[32]; + digest.doFinal(hash, 0); + + if (!areEqual(Hex.decode(keyedTestVector[2]), hash)) + { + fail("BLAKE2s mismatch on test vector ", + keyedTestVector[2], + new String(Hex.encode(hash))); + } + } + } + + public void testDigestWithKeyedTestVectorsAndRandomUpdate() + { + Blake2sDigest digest = new Blake2sDigest(Hex.decode( + keyedTestVectors[0][1])); + Random random = new Random(); + for (int i = 0; i < 100; i++) + { + for (int j = 0; j != keyedTestVectors.length; j++) + { + String[] keyedTestVector = keyedTestVectors[j]; + byte[] input = Hex.decode(keyedTestVector[0]); + if (input.length < 3) + { + continue; + } + digest.reset(); + + int pos = (random.nextInt() & 0xffff) % input.length; + if (pos > 0) + { + digest.update(input, 0, pos); + } + digest.update(input[pos]); + if (pos < (input.length - 1)) + { + digest.update(input, pos + 1, input.length - (pos + 1)); + } + + byte[] hash = new byte[32]; + digest.doFinal(hash, 0); + + if (!areEqual(Hex.decode(keyedTestVector[2]), hash)) + { + fail("BLAKE2s mismatch on test vector ", + keyedTestVector[2], + new String(Hex.encode(hash))); + } + } + } + } + + private void testLengthConstruction() + { + try + { + new Blake2sDigest(-1); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("BLAKE2s digest bit length must be a multiple of 8 and not greater than 256", e.getMessage()); + } + + try + { + new Blake2sDigest(9); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("BLAKE2s digest bit length must be a multiple of 8 and not greater than 256", e.getMessage()); + } + + try + { + new Blake2sDigest(512); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("BLAKE2s digest bit length must be a multiple of 8 and not greater than 256", e.getMessage()); + } + + try + { + new Blake2sDigest(null, -1, null, null); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("Invalid digest length (required: 1 - 32)", e.getMessage()); + } + + try + { + new Blake2sDigest(null, 33, null, null); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("Invalid digest length (required: 1 - 32)", e.getMessage()); + } + } + + private void testNullKeyVsUnkeyed() + { + byte[] abc = Strings.toByteArray("abc"); + + for (int i = 1; i != 32; i++) + { + Blake2sDigest dig1 = new Blake2sDigest(i * 8); + Blake2sDigest dig2 = new Blake2sDigest(null, i, null, null); + + byte[] out1 = new byte[i]; + byte[] out2 = new byte[i]; + + dig1.update(abc, 0, abc.length); + dig2.update(abc, 0, abc.length); + + dig1.doFinal(out1, 0); + dig2.doFinal(out2, 0); + + isTrue(Arrays.areEqual(out1, out2)); + } + } + + public void testReset() + { + // Generate a non-zero key + byte[] key = new byte[32]; + for (byte i = 0; i < key.length; i++) + { + key[i] = i; + } + // Generate some non-zero input longer than the key + byte[] input = new byte[key.length + 1]; + for (byte i = 0; i < input.length; i++) + { + input[i] = i; + } + // Hash the input + Blake2sDigest digest = new Blake2sDigest(key); + digest.update(input, 0, input.length); + byte[] hash = new byte[digest.getDigestSize()]; + digest.doFinal(hash, 0); + // Create a second instance, hash the input without calling doFinal() + Blake2sDigest digest1 = new Blake2sDigest(key); + digest1.update(input, 0, input.length); + // Reset the second instance and hash the input again + digest1.reset(); + digest1.update(input, 0, input.length); + byte[] hash1 = new byte[digest.getDigestSize()]; + digest1.doFinal(hash1, 0); + // The hashes should be identical + if (!areEqual(hash, hash1)) + { + fail("BLAKE2s mismatch on test vector ", + new String(Hex.encode(hash)), + new String(Hex.encode(hash1))); + } + } + + // Self-test routine from https://tools.ietf.org/html/rfc7693#appendix-E + private static final String SELF_TEST_RESULT = + "6A411F08CE25ADCDFB02ABA641451CEC53C598B24F4FC787FBDC88797F4C1DFE"; + private static final int[] SELF_TEST_DIGEST_LEN = {16, 20, 28, 32}; + private static final int[] SELF_TEST_INPUT_LEN = {0, 3, 64, 65, 255, 1024}; + + private static byte[] selfTestSequence(int len, int seed) + { + int a = 0xDEAD4BAD * seed; + int b = 1; + int t; + byte[] out = new byte[len]; + + for (int i = 0; i < len; i++) + { + t = a + b; + a = b; + b = t; + out[i] = (byte)((t >> 24) & 0xFF); + } + + return out; + } + + public void runSelfTest() + { + Blake2sDigest testDigest = new Blake2sDigest(); + byte[] md = new byte[32]; + + for (int i = 0; i < 4; i++) + { + int outlen = SELF_TEST_DIGEST_LEN[i]; + for (int j = 0; j < 6; j++) + { + int inlen = SELF_TEST_INPUT_LEN[j]; + + // unkeyed hash + byte[] in = selfTestSequence(inlen, inlen); + Blake2sDigest unkeyedDigest = new Blake2sDigest(outlen * 8); + unkeyedDigest.update(in, 0, inlen); + unkeyedDigest.doFinal(md, 0); + // hash the hash + testDigest.update(md, 0, outlen); + + // keyed hash + byte[] key = selfTestSequence(outlen, outlen); + Blake2sDigest keyedDigest = new Blake2sDigest(key, outlen, null, + null); + keyedDigest.update(in, 0, inlen); + keyedDigest.doFinal(md, 0); + // hash the hash + testDigest.update(md, 0, outlen); + } + } + + byte[] hash = new byte[32]; + testDigest.doFinal(hash, 0); + if (!areEqual(Hex.decode(SELF_TEST_RESULT), hash)) + { + fail("BLAKE2s mismatch on test vector ", + SELF_TEST_RESULT, + new String(Hex.encode(hash))); + } + } + + public void performTest() + throws Exception + { + testDigestWithKeyedTestVectors(); + testDigestWithKeyedTestVectorsAndRandomUpdate(); + testReset(); + runSelfTest(); + testNullKeyVsUnkeyed(); + testLengthConstruction(); + } + + public static void main(String[] args) + throws Exception + { + runTest(new Blake2sDigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Blake2xsDigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Blake2xsDigestTest.java new file mode 100644 index 000000000..163fbb169 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Blake2xsDigestTest.java @@ -0,0 +1,2690 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.Blake2xsDigest; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Blake2xsDigestTest + extends SimpleTest +{ + + // https://github.com/BLAKE2/BLAKE2/blob/master/testvectors/blake2-kat.json + private static final String[][] xofTestVectors = { + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "99" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "57d5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "72d07f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "bdf28396" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "20e81fc0f3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "53d87da652c6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "dea6abdba2b385" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e8ef785d84bed985" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8564786ae17558a034" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8fe7cf0bedfc5c8a25c4" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "ced64dbdb850b8d9238544" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "a61e711081c80de67b0f5cd3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "ca84913682c32af70a5a762e96" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "b3051e87aeb0e2f29d4197ea1001" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "f1db5e2f2bde30d08125a67d718b3a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "541e57a4988909ea2f81953f6ca1cb75" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "58910f890077e12ec101610597195ddc0e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "42a2b79173ee4f554baafe870efdd11d0bef" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "ab2133a08e937af16b521a09a83c5b25fe39fb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "839d21a3030d13c2f59fea3634d8394cfa97c7d4" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "0a0eb5cddef7a827d7d3ba947e55c04d5d74ae4780" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "5fbfa41a06fabac5349e39701e79be5ee7d74195ac94" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "58ff07c4812f286cfb69bae047742a1fe519c5a886f3a5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "653a88f2458217a42ebb0cff862076dfff08ebdcef917bd2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "4f64ff718d4a02663a64d61ef7a3a0b8a9e0d201c310931f32" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "5980b25c906286f0850b2349b0ab1b6fdff051aac85814648c64" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "89a4ae162416824f35ef116369d155b2d941df8a3d3f6dbba2279e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e72beb4a6524fdfe06fb519edd634e62bfac05dc26e73d7da4e6b105" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "34fdfab2a60eb77a4b30e0a14d1b90c4d3fed0284b6ca4503d1e87729d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "f0fe72dcc5a7aa3cd3ba068e14395b1998db37f922593dd6f340b3831ce3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "ca46fb7d84d726f5011c00c379ef2fb625151c0a1f416e62c9da2aa14c33cb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "91cab802b466092897c7639a02acf529ca61864e5e8c8e422b3a9381a95154d1" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "0253f5487d927a5d35d0089ad9cab2d7515b65d332e870c78d1229d1c584bec3d5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "38524415a7ecc9d09128cbd0999bb76847fc812148b5a432548e4e500720b356c803" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "4607a9e4ac70b3b61c47c44f9e5d05450bc356f2a323a9d2d213525ef2ad2905f82f79" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c8ab4ac86f91ab339c79bec70920cdf382f7cffa279a80687a5c27cf691cc92777120c3e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "de63da44e818a837a9ccb7d339ae9e68bb4632eb34ad5dcc2223de7b8c1dca50a3739ff8ea" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "ad5a3ff34c717f1ea06334e074e30b4c57053501566d4889beb32933bc6dabd01f74d17fd3ec" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "845a8fcb16cc5459868f5200a811f511c84caf7fd7f6de2010c162c1eaeca1f3f135b14c4de356" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "5ee53a681ccf1bb9d65359e2dd5daa377ce9f54096678a67390c2c9db5e797eabe13fc0ca5d4037c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "ed2230ff3817d2ba55e65dc137a3ea9865e436355ac542ca0ee71bfb70e0f48f61f5a0099dbb6df616" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "29be3322662c65b7cceecbdaf27e6f65f93cf41bf27fe5dc8c29891297892bdf1adc948026ef20b6c29c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "82c496d4ed8b6cca197c25bd2fc6924c35ae9a23fd555cf12456cb24850124b1b8dce9a1badf1983f16cc5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c80125ad9d202db1fcbd9a4c7ec3857eb5578b20ef54cf71197954a45df5b5d246bbcfac43f19ae3aaf7b212" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "6d25dcdaba3b133747de6c4fae478a6feee65c70b6ca904768796aba08a056071d2853b8375cad2911fdfff20e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "ce14b4f4f327941684be16178f86c3cc1382c326909d3577748c672d6a80253c7a563ff36c409d647997cf1039a6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "62c256d6561b46b0cc6567b188ce615aadeb4b51880e16f2a268cbe3eb37b97d1136089d892b5dda8f65d1e418eda9" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "02a06f6949c942ddcd8a659faa3492a12f22ed44cfd58de5e4312ad33b1af337655d2b292f9e4802b5ea1ad0f2f9a2be" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c9eb45d0a7430548d96f1033a0e0c62e150c0a105b53de8b7288ec74349ed6d329b60abeb64053cbd13c97404f0b1a8a9b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "253d1710e74d36ee28918880220468da1be23678579bee544a671094dd05cdc658752585bdcb8d943c5dd008531ada11a813" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8ac3361542a33bd1ddbaa83ceb37113e391803b46824e91a81862f8867420b78dcadc8967ca6645084db367f811001471c17c0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "cdc6b82553314ed27d442d6445a97667ec94337ee913d7a6f6f83ac197286e93ad455be6e5346a3369ed7a5c03152f4e452b1773" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "74d8b9c28a80e3d2f9add23c1700a0a8677c6833c969f8337375411d0f2514757bb6dddbcb1ace7e0046fe3668f941860c9f624811" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1a801c80e2e74bcccd583037b6b2228c8bca8444a3ce7d3c47aac3647842c204c1f3997e2f0f8b2b3d63b27a9f845e392bb273497dbf" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "4641d3f104a6d384d04c7a92712c02a7c1df543cddd80ad88252113c155b344530fe1602f50f0325f61669daa4b7dbb6ed5e1e3229ff37" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "b79a894d9e95b0d71b78810f7ad18fbeb4bd3d84843b585195e3cdee4021a9ba3f0e6e1b960356afcf607fe3b5eab448dcf512fc5b0929fb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "3e89fd9a7daf87bc75088c756067afb8da003e746553603338e0ef5aadf804267448c74e8ad014cde658708e5707976e8311881bbdd2fd3415" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "d74c6b60df37362d218396f411d1ee7d7e34cb502ea637e9c9c10523f8f687c13a9b32d704fd49045f22c1c4b9d0576b3eb51f5f2b2e234703a0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "5e428a29f184b93022812c39485c770cde5c3b4596c0d4e714054187a4bab511193458f7b618d64e2debbd8d5b5680b602326ed760cc5d48c5fc84" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "04147c14a73752961ae870b0ab6c3704e29c8534be4b3063adbf1430eee5f144a57bd003afce1fc1fbf6f926a34c504203ecd113ca3f2de3744238a2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8f54504e449e743a4308fb215d250a08f0541d376f8bec5f4d7afb609326795416a168084f62c187eac40f036603e8426d306a05df36b5e91a1733813a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "76c564a9a5960016b9e588d4fcad94a4b9afe77172edeff7cfbc25b2d08277225fd50250a05a3281f677adfdd96777351bd895fd289137dffd8588907deb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "25981b7d6af3c87840639621acd46ce4bce8612fe7f081cca25b72a569c81c498606deaf781f89b07534625336563e19c6b2c467033bd04b55561251f8521a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "57aa5c761e7cfa573c48785109ad76445441de0ee0f9fe9dd4abb920b7cb5f608fc9a029f85ec478a130f194372b6112f5f2d10408e0d23f696cc9e313b7f1d3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "150a3e311efb3299d0b9ca333526bdb96a0584f00b52f4e723407cc332a9d5f0f64f426fec8717ae03eaebf1b52401956595bd6e56543a53517be104be99745e51" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "6add9e23840ca283a12f0b695a39631e5e068c27abb35edf351b19e542ec30d956b3a978df34155941e11b8182f71a57f3f4edad8dc8913b3e3830989ebdcaaf3952" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "9878a842d17d75bae411967da45e1e23c395a714192d424a4a082c5ffd8745c5d872a841d827865fd4586c668798117d65b293ed2950427610cb9c908bb961699a9585" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "65f1a8874e3563170d4f8c81a52fe1b27d5137056e95ff03ccc97a1c658f29fedf0f3debaa39452f14821b2ce06d349f89f6aec7340e79727dfe4609b7d08c1b5f3b591e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "0d1d71883a5d82addb706c677a054c03be97972392fce88b9dfc676fe83662c2d8a310f1ea00acc7bf1303b324bccc7bd7c9b8ec0f0d3e33d6e31311ad96357b144078b0bb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "b85aeb30fd301c182b980ec09dc99caf533e7ec86f35580004b6741aec28d4ca416d13eaaf1c87758f1eb3a70525932129f65528a790983b012a7620db68d7858b48f9e999d6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "bc3c10e1a08de16ce26134f363843f9243caf3bd1dcf445cfca839ee55cb5ca5f8994acd13509609578dd39d6b3c89901bf129a5bff17ffa1bb506ad7f63d0c18a570b8953a488" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "d37cb91bdca013430f38c914d1ef18b68dc38e5c6013cf8e357048df2c86261a0f3301bbe436362bd81059c1f315cff45a9091f1e1d84141f63ff92f2c56a6ba11fe3db17cff3377" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "52704d061557de8f2debc6cfb71616bd6ea10eef41523670f87e8f8acc673fd3100b063b95f8bca943b3eb98984f908142d6da9e040aaf93cd711191d00ac48fa56e4669d2e7e5b548" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "2c0981b3580aed2add3f7c0167f04221b376819ff5406034a41c261ec5969ff248b7a0ce2a6c9f01f1ec80b7d98c148a3a9f842c626354576c9e6cd0588aa129cc9360e9aaa8d4c58bf4" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1b9b51a0e20a02922fabb2a99f11c9ab0111ceda3e20433b25caf010190aba37789c996947cff081d0c6332bf2a780d90c1ccaaa05ebe9a2f186e30b210f9859ace8bc9fe84bb5aa512e8e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8489919afae8ad867c55bddcb43868a089cdb5ed7b8fe0a3dadddbd12cf6ac1d608741d76881c085b4542fb5e82959860b4d617fcff1e627cc89910a8d7cf848dd6b0b70c9870005b8be5ea7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "2b820effcb8312b6c05f1013d61327f84c1f11c5b8834a7e59820bbb8ccf77990d0190fe70f62bed946605d82e66ed4c68236c9aa39d9a88fe668331dacc607a3dc4a30365e9a185bf294e94ce" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "481f56240d0aab02b669e7e595041ea59851a8372b375bd1131e39cbdcd76e73734dd5838ae8ae655c2ef513af9bce364b103911defd332da64a1fe9a11011195e4a71c11e8eb57d82d0457b0346" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "b57d1fa9332b7a22fd6cb3348733c2883f4a99f4a6fe22239dea9320a458f062a391e240044d19105b81f3c08dc9ecc5a9f86bc884cc1bad649b9cd5ce12a1f0a73bcfb5c1c32dbcbd75a74f5df617" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "f59fdea0a8b6b99202c455194f5bb65e56fb45d34500c37a7e73470bd1175714969b608cb7507e8fa1b9e39dc82b1582b3cd4b193e1f518f016a7251b6f52ff4b1d217758715b739eee27b1c9a2aed11" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "56fe4e7c41e9ff59c48b6200d17e6f9eb30b6d4d18154bab7db9aaf206b667e937cd3d4ae23916dfb9f1485ef68c1aef8fe7a661c6a5fb9cb8034364821641b6ee9d76bd4cc378a454435a98c71e47ef8f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c7233615cf8b9d6871fdd7c0024f5ef629e00b2e0c0a19abdcc7b789ff1493d187ebad63b651eca605f8295b29f01364422527a15176754c332f3cf566fd2fbcccfee0bb33d9305e7b8660f81f3e8f6d42ca" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c1bca6f43d40a287f596e4730e27fcf56ab9b841aef9e4daa4e244846f2036689cb319520b93a43aac9e9238ffc256f26e7e5860873cb3404417099eb8147a5e12a094c3d9a758ac989c0c2baeb1e719c2a432" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e3b82e4cceec32977767241c1b1e8504ba76018162de5cea14a19c5f06875a32fff9e53a047e68416b8dc6bcb9e991487b81b76e58428cb33f92f637965f9ee00ec57923019e702c7ba3a8b3c1b7049f3bccdeba" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1489fc59f0b16c2f6bf4a78b6cb71a4c12e0a9e02567edb6a14ec2dfc512687113a709d7e4457a8d03c9d3b1a6cd77a0d50ec5aaab94d48d366e976e7f3dec356ea32ec0561bea07ce8a4204911619ebe54152c73b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "7cb2babff9c15db475ee00db87804d984fdc3be81272a60f8286b7ccfc4294841908c56c7268e80356b566582ba457614e392f58613c4059b184e085b0caf4e81aef8ab67a2220c068151ae100c9a323792d7f49e477" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "508f70ce1e4450291f690e2172944e5008dc6bfc494f891a8c79c012351ff160357b39c69027859bd0d6ca7d329ef4c5779e8f3cfd5921ce9c7170038821e4ff03f5279a01156299cc5227eb8a81cae310d4c7ca52e7cb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e534d9fd2632c0d64a3df145048bc674ea0f01af879a26f252a4b0cf406d8bc4c2f134a86443228b667ec1c0c1babb2b04775b064a3994965cd6080913036ed387483fc9295930fe9ebb1da87adcccbca8318fd2b1d14e29" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "deed43ef976409050873e966a722922bd2b61bf11cff0064b5458b9eaaf9bac20846b7f20606d84b0429bc1a0c00df5b742cec643d44659b3243cf42217e6abc84d01cd326139120f96c92f625a08dcdf193639bc5756e29f9" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "00b322e73e6eae7de84425961f11b9736806bafaddf0495274552328c6b1dbc9c88227de05e8348c04b9fdd9e9898fe69065cad8f884e4bf1a2eb821ad0a3eb4b49cee2ef299a0051976b28af1d3d16777233b75db6b9004cdbc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "9d3a5ca80e99eefe49eee987132c73bb973260869149ecf8b167a7a4424939f48c5acfce848232f49372aff6ff09908f943768a5b87bc30594ad6272f63b5ec2fb46e742700767d4663f82a1ac88e060ee87dd30ecc27115f52df1" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e068a4c054cf8b757ac81d216c961f221276e1753148fc9202f83f258bd2877d192e324784fabe600a2dcb53996d67aee8ee9964b9020e2bf458daa4e9494a193f3446daf087899d71c52688a14c05f5ebb6811ca0fad85003aaefe2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "0d4ea1a13a2cb5e403caf018e5c529dcf0fb8b1fa625e150fa46383c45fc25e51725e946f09b93877ae2058de3577e996637817a3332c46842089ceef2dc9a4f52f14edd2f10fe56d11477a4eb06e559d4636c4f06019be3911426d1b3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8de5e14a26cf4c758fd43b30b71fab2a77480ee98faccc95488849a49fb983362f883e5c75d6e6515063c15194f3fe9fada18b91b8ccf0b3ced07c410d8eda5f0956a1fe9340b5a3dacc10c2f1b5f4a9c751a65361f21273a11e571829cc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "bfec8b58ee2e2e32008eb9d7d304914ea756ecb31879eb2318e066c182b0e77e6a518e366f345692e29f497515f799895983200f0d7dafa65c83a7506c03e8e5eee387cffdb27a0e6f5f3e9cb0ccbcfba827984586f608769f08f6b1a84872" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "291a233932dca80d3a4ff11f06c056b8c7e9de2a99c4c28c666965ef6c075b8d90017608ac7074b7e4831536f5811ccf97f47ec39660ee1de01e31161cbfaeb575a45413df6a9a69767763a4578c23d1d697d7b8673d2b2dabb05dbd506c7c62" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "967c76e3814a1a2fe4ab811b8e0ec56b54dd67f37947bc3554adcd143d8ff17f0f11b5736d512dd8966bad9c4e4c2aae5835ef5d0baff5c6a034e58e3eafacaaa0d0ba4489dd78f06449754b25688fd9e50a191bab8ca6dea5e59c08aa07f2947b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "4ea13e136028596e6e0ffbcd2aa8f177d2e40abb7a5efc95a66b0113eab8eb48c7e0af7a7499eeb6e04b341a229f24fb5b9c6ab444288d32a9489e9c9abc6bbad1fcf406adeff9b14e29bc60dc0307094ad8e6b1b6151d7dc185c2a6b2f2c0465798" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "61aa1f4d4e2cdf23bd547f425b52cdac799ff437ea49adbd5a81f0801f640881a09569fbc8b6c91ea2c5538f518e054b5ea75dd074a8285b5869b109646408621b64f6a902ae061192f0dc25a172361508c945e218d1e42182abc21eab8d2b00c8e308" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "5e3f0046de3d99d5de3d01ef2947b812714e09af342d9ea03311565a748ac0842540e0504aa8a54d4c7563bd8948d36177d88cc7b14777b2c7930252d4ec1c1a0fa0e21ff2889f41615c9b828b179c4778f314751cc58fbe386bb6cc48b1a729cafd9f2f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "37238968e530a2c072632186f8c54f271d15f43d2bb2a5541914a9d771a7d22a2e718992f74534da17f126e1616c39788bb4a8196e49da93ff4c6300b0d873de6b1effa0af995f534ff4c5c079324e66b18d3c2a87b632541a39c1353a6e2c0cf5b594d4e0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "88623f66c92f3993a309c6ecdafd29815c8b9ac1757290ca3a5f5694932e57acf70fdd83c595858b3331afae7de0884859ecf11b28f84ec8794fb16a136ae0cc9a4360f64a9dc6e8cc5160e8f11e2d2243e927e1479bae5afb82d192b44e59971357a5cb14ab" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e8b11e720b0870db776a8f682b85c865144ffae5a7ab7849bbd0cd9077e5f64d4ee4aec0b25d06ff5d2ad528b1248df90a3dc8cc189cec026b22910d57d756b12153362001920c3f82d102f910eafdd34b1a50e9b99b019107e764b5b8eeda5b465c755d684489" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "690501ac0b21e40128f36be64fd19919dbfb4e0edcf01df9a4d946f1660d3c81b896e77fdb74ef601e44b4af6e1a0f6aead0fca6328542dc7c99d230ca97b905bcbf2dbe0bbc6a73f062d555fe2579cd3e658ddb9a6959467f64fc02344e42cecbfe1c10740f3b6e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "672a69beeb960495361d80ce9bdc3c348b8a747ae83399cb648a720ab7596a8c2db14f924c0960355988189d6aa437e87c3ef3cf3a716d49a045a4fa8dcc7731925f1d5e66f8c0e644d9b4746f5f27d2361269c1313f8badcb38d74ece67d4de7dae120dd9f8291393" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "739c7ea259cebc61598b9630de10c1217eb32a1107933b8929ffbe71e664c266f5733b94843a57f92f57af363ff73ba91022d92183ea368ed26a7bb27162b66651ccb4c3fd417b0ed195d2b7f1323396c49d82f5fd17c60962f795705c3f8262cacff82a587d49c25b37" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "fc80be54afb6a6dbfa21744fa588249e6532572e70236ccc6170f5abfee2e7806104f2ec507782d93efbe7b9f7b098588bfc2f62879df7b05929523015cd5720ef452c244ec212bd21ecc3e1a15932858dc6a55b6888947c067865f0c34f7e8b78b76c8f18c28e1a0b81d0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "7dfa64ccdeec6811f6f67a899511d693b999cfafe705a9cdf0458273ad314d2580e01d6975a476beb67e9cffd48da875aa9faabc555968ce2f3ad0b1d9526c986b78fd86b8abc36e281de1e4258ba5521240ac7734990de7299e51063344d9bf9fc1a47d8a9b0c4b9243e7b8" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c4d84255d5a7ebb77d632d59f998decbac3d031464653146adf5e78475910cc049fc0101fabed376bd8440bfdffd83d80c27081d531b9fcc3e732248dca2c3bf6007da725c0787ba07269b05034a953a2df682c962e1441c96024966ee6663853f8c3ac88e80bc6117b7f68483" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "9003bcbe5e928e28827eeb435f311730e8ab0e7d1f2bb615f4258e591c625d28301ea72520079c40455a9464e4811599ceeedb913071f5c9c8b4486079108e0916282668799441c4901b72d5a57da1f72b65a1512a23c4c0c88857ada847d75c39f3e925100ef0bdde49f5127083" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1c1ce518a470f751be5abc5c95e797809b40c83f5002c69c3e34b2eb52e9eabd4202539d821e98e8510733e26dad712527ff04e17d37f9172c58e4af94524fdf0bdd55126cce429c7ec91293d073a4e3d33b33a8bb198b2bac7113799cac70df1d860db405b78a0bac420976a6f6d6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "23e5ac8c6331d772e7b2bdd3f0b6fe57df95bee52645013072f076835a3393547d454d67f3f228d1cc2d1e969a80879c241f68273477ae65a6cf6e5194e5ad6cdb2881b74fc0a3e31263669bf5f1fb70890c681c5e1d12eee43b44141e9b95d0180c11aa95c0e513a96861bc3944cc31" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "51f3254390ba613dad1b4288b6b40f8615e047e1ae85b7eca3d1e8fddddb5ef0555c1db8683fd889fc304c62c70eef2ea4c21c2192f6097a996d421b8b6f730cf829ac14f82b45c64c299831e8015039a10314896517297c4c48a91d0914a6da1eb7951e29d0ec63f3fde0c98e24bf7ab5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "75168cde1904184c2cc845ecdef73f69fa67a709cda969853fe8644c44cf8674f13c3a399509f1671568edeb936ef60a450c282aef04086bded69d0696df84b00c3d3477ad51d5483cdade2eddf8093de0aef19761f7af4f6182bf48e848b422088a22ab38eb331c8908a2ad28956e4824b2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "d8f6542eaa90aebbc9d24c28e29c229ea4cc6a775aa8146e98cf6929160d90786fd1168e5e81aa91246e4175b06a383f3cf61a6d832b91c13ca2ebfd88f659e351da333fb25ded1fc44df314cb42897cb56ed6544fe556d4e6a658fead6154b3a1cae3e50be2c81f2f86a326515078fb8cc910" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "2be8d7128e0200e78ccd7cf6e61a8786b62809b2a17fc3b333387b2205794fef2b6836b19eb9600b8de93aed934191b3e2c291954244d46e87774c465f96b46ff46093d66d6ca1ac4176e9e59c6ea649ea174ac197043f6b2b39ab3397218e78bc2bd79071bb4ab3532d304bac5c5e47730dec36" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "835a085c2f477b537c8d5ff4dd439f2794f8cb3bc1d787fe30b3ff9c590c3d3df6f4b903238c482c63e24b448fcb347b73821089496fd7587f4b9f23ef73c615060c9282fd67f8f012869ffebc12521cb745dc318b07b48dc02aa8b5a512aed4e346919b3ee4836cbdaffef1b3dabdb01bcc7eb636" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "6c626640d1496181b0c161e28ccf741598e521d9187e8ac1a648bf7128dafea2562a6e9010f2dd8fbe561f158a0d1eed7c7f1ac2cd208b7cfa2c352939227a12da50018c54cc44a7146ac79d5d847897a69cd64e22f252abbb506d141d3a8393b38a3a3cd99096a3d10037de1feb6404b6c5072c3d98" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "295ccefe2bd4e68d533fe402c8e6477ad00a3cba55aa1c99b7a9bf31f0d021d761607d27312fb099784a456efbaad30fbddd354df45c328838c423f169888c3e7ac7dd9f9052ea356aa46171156ddc645dd2d9801aa23ca832c8a19c5c2fbef040b66fcc579bd73e92e0a1052519452392c94b50176012" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e635d9a82e5fa5af49561bae9abf31ce5c2fb85c1d3ed819f2aec39019bd637d66595ed7be4d1eec75d2f97ee0bf41b441624667e0e7a727e4aedb3c306c6903aba306b88074d2c9ae6787c14003fb76408efb90b0827538f5099ea35baf2a1d7c874ab38804efe51a925aa852a9b4e776e21fe913518afb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "92e056584b2767dc7a5f4f4d0837c034d962eb36e97a590fa3386b106a58e238842923b8e688d6034e7c1466cb26f2b09a5378117a8fbf3fc08398070fcb4ab8d0ca0b4ef197a4252ecb5eccca097d32cb036c8ece264a45f9f7d4b0ab945fd95286ed3714b9979b0575226fc52c979fc26cfa8d3d23e6b327" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "d826daae45241b3e5b24e9049a4f86c454b50c5de06e2dc70605acc8da4712f9391ba7a8ea90449c368590881ddcdb2d37775004ca032aa8861453704c9afc42a77553d24f664db7798b25667e9b5e3d04287a35fd6e604feb70a2f8d03de083a364e7711687eddca8c3b73e0134b940b0a42f9631a74f39cf1f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8cf01578e2d2cf15680485db397ee230e4d04171c45fd8d0c65555128f6a13b8dd28cfd7d90807ff4f71ab9ef5384bc8160c49a23b19a541658d7b8f8c43aa98f09af0fc0668da332b1b8f9590a5a5b46fe9058bacf25157892705130d8004dde4eeab3255214776a2d9b2368755b20574b37524f15e300e0aa093" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "16ce0a26a1985633c5f9c653bf4da9853b301b08c321165e20ab38762efc7952352556f91d109779485cab6100294f3d59269b99082037fd5e48a125523c95d5ec4e8339d3eaccc67d9bf37c7e82c0962d72532b0448a4497d312524ee2f92b44a6763de12996164821f0f11db66031b1247cb4cc1dcfbc366b93c88" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "b145e964233d8c74eded80b6c625de7efe274142c26ae9140a762bfbd31bf543eb8e52c65fe0c96dec46a02c08a8fac0aa564f0abdfe6ce629d5e191ea159165f351982d51f0d64ea434a1e7e789ffef38ecb8756485cbc2614de9b80e1172fd2c4be05ae5b7dc76182f8d9ba29106e5ed4f8d610c7708fc97eccade92" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c96773d31fb8c6f02fbf2a9f4f4ff74234e26808d7162678d25c931309209c3b568fc2c69b5d97a00ae7378702b344644fe9c4b0f9e44fe01ee219a3471866ee1fafa8b00265a10dccd1b3f676562ffe2fe43bee82c4f7b5ff5e04dfd4e23de75b6ee35dfaf01c716c0db1c848a781d04978bba749d347b6e85c5334b74a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "87776d4b3be82f3eef9a88f8135a005e4c8efb34d51d182efc358af1b4287b46c8c16a6307fc57dbdd7af3af57c3f3670a310e65c69ff7c91b2a75bfe622dc860cb6384459eafa243d0d6cc768add9bf5145e6ad393777d745f285ef4e96f2238da3f7416b049958cd55019850982843315038cb97f788be3aadbf283ef956" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "4d1f33edc0d969128edb16e0756c5b1ef45caa7c23a2f3724dab70c8d068cfbfc4ee15ca2fa799b1eb286c2298036faec73d3cac41b950083e17ef20ddff9d55aa8b4d0365c6dd38d5ddea19ebfa2cb009dd5961320c547af20f96044f7a82a0919126466bad6f88f49b0342fd40f5c7b85206e77d26256c8b7ff4fedf36119b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "9339bc4d2c29865f64d1b93b1e29314bc26b78d53b69873ef54205b3891155683f2d8199eb9c8bb37becb7ec02d126b730cc4310c9c70785fb819551beb509ec14f2f7cef1deb83a8c9fae4511f94d48ed38f8a444b73630cd433ed8e6022211286a2df8193dbaa1f57b38ff84d6ac2945a575dfd4804b538cbd33800f488f254a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c4018d36d2f84fe2e1f726181caf1952f3501b4b4ababe525c76d8436c9e79d18094a3f7726f3bdced6781f1626e90ee3b230bb4862e5497129bb58b40d6717c7f25ca7d96f80b1f37273105acc9dbd30f15fc0c5b81f465e2f596948a00aefb9d976eef60669e1770cdb6beabd2ba112622734c8659eb87f0aa08c034d462a0267d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "03a44e84603f79ebdeef6680447ded2bdd5a640549f4ed6cc493ddec1006d0535481417bb8ce221e1b3b2535cd0223630e2f96a8e47f44da8a998c2766be89b2e245033a1bf1fc15f506825964e6c6a9c6c5eebf06b1fec66b8322d1425755aabe7391ca9f5c59cfe0c14095036b141f864c01a5dff04b8fdfb7de2b88d6c31f8c684f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "181870851c94b7b02629c99ed1bdf55a20412534c5101918cdb36525364b1e7d0f7eb2b4f549be88bfec9eabe45be9e4bc3d8495258b83c6107c995c85e1f5ec84bbb8bd43f58ae98d13854ea7de75e51a5f73e24bff4e6dd850878b3b7f8948ff99924b9706bec23fa613634abe2191023d01d463ea7f6f4019f1eb4af6e74832008e69" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "9b8d7205ace31b13e544de5f65ec17fa2ce350c8bd32e68aea7b22cfdba9e0181b8db8dc961a279f3441e2f86543e0ef8de65b89d28eeac748fb65a2b5c13466ca94fd45c425f8146c4fa12c6705e6230b0a0ea060fafeeb43907087682d26a465fcf7f21ac52f1351f73b45d75ece0680d27db1be924af3a92adc38a9efec2963b6882b8b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "60ddbc9c10494d540b04627b30dbceefa1331bfed86ea30407c99fb18a50f5afe58a7f73544f6c70b3034825111fdd139dfc3e0c3c00ee2f1960fee71284332f727efa6187a4d131d4271e23948a2c2092b24fc0b366ecb11ab464bc85e2c779fd3d9f2b68e62ee59d9b86debfdd96cac33b2628a5a966c26b0602e242ed4053737a3db0e83d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "27e3bca4fccfae88c9a7a7f43c0b72a302b626cdf32eb70122e9cdbc100be2d29d945098f5d74354b4f90a66e938ed6eea3ed9cadc24a1b08d12e731150b327f0f53ad43fdaa9ba76785c03fcb9b2995cc2ea67009a0ce10e92f9ed9fab54c09b3f90b0fb9db2545edb9088f93a547333fff31dec6000120914baf6b6ad7feba9ceee614beed11" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "71028d445c4d77fa30c5c58057b4d233ad2e12ee640d484177e20c635fd1ebc150d1a3e4d855b7910623492a6828c215d5d1a9f39a4ff3f4e6c98c98068fb1f3b4ce319658fdc764854b95928bf0315a81a0f0a022b3d2bd285f22b16b1613b52590399f1b993589ff2f8997c4d9eabda69c9f3b8a925ac9b4942b380c6fe0ccc95f1b4e3d8cf336" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8533108fe06b8ffadb5b8618d03486db657bc32221488b7b629d6ea2e24c1e1de3755edb971c1db135bb38e0cc943bc2b3aae2369b3019b98b5a92dbe122b35dfbef0620685d5a808f21c31704e7296f207dfda914fad3a903d8142c623a83a0f55dbd0313bbca2c2831c8e4f02b10bef62ef321644836b3b5224a0eb68e84f25742450b10f9c59bed" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "45a62940d954283daa40a17b89a8d89f383ecd3a888d009b31d96f48bb5a656e4d6870062b41ff33d0b7dc7893b3a480f2d2c4c909b18d50365451e7e56c6305d26e357cf51665bda819c1f64b59dfe87123755523ff969934f5900d2f5e69da3189c118ac2bc1c0438f14b1a37d2227801ac6895a3c54dbab0faf77e9b1b8eea879c9dcbfbb7dbcfaef" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "03f992e29cff3059d46ae559186581b67954e6efa73d7a8aa26ed3e453828c3e8ca5031a988dbd680648f5775b0484a09d0ec953c49c3f44bbeeafec5d7c0820e6c04cabab144d66e2076f1dc8ffda96fdd292edad65a671c440a2810bd0c86e9608173ebde1d193f2fc738e1482cabea306208b9eae348113be4855d5aa322ea604597cc0793488b65cea" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "f3a30064a77618fcb495df57dd45d498e7fc9edf91e6c41fb76ab296201f6b9eecff62f5a3aa6309e38d02bff0548238dc7a54bb1c51f89500c8cd07bb8da92a7659cfb12b175f6417eff25d811c930b029c543c4cd0f849e77cacf476f3bc690a169e1dbc5a60c407cf206074980d265a44231a9afe10aa679b542f63397019011e6fdc0316f658dd10a4d6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "ab3cfed6234f8bba8918664f83d266b3876ad57575032b3260c3cbba740ef1530db08f0f5e9f1718d5bf1f177922407ed746455736f21016994e0b447258234921f0f373974ba0e17f04f0aabdf7e7a33d180e474fb259191450ba590e225e9d7fcdd7fa5d4b3eea4f836444e31ecea28727d215709ba33bf6f2fe31305689600a314dffc81f99afdc1f63010f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "fcc8d836915a460569d081121755425439a95a85f635b8b1087b55abf43c1ae3af7350de02a0d11443315e5b46cd2dc135c5a2522801ced212bbe05c7c595ce3cf30b9bca9a34082b270b42c02b12e3c570524a9f7724ff0adfb2a134cfc70b6da98c375f197cd1a0f56c792695a88272ab3c30fbc3d46cd391303812e3db840e594f59b25e21007fbb7e259ad2c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "7664b3954ecad281dc23e0dac62536a4512076afd536addfc74d2ccf9742e80abd6a45dbdecccbb951e41b5f9dc4b5c10fa2734a0ff4b247f237950367a3e2f1ee00f75813eb6c3d6da4383ab908333fc123d5570a43319587d9625516122104e5691a7c6e9244ab7785846e13da5bd0e15568eea2d491cf202a0253a25209389b27c817c22c5ff3da99520cd71290" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "ed5ee508aab550984e5c58cbdefab0b5161a4455f2d4eb0cfb633dc2fe88144504e294af91dc830604a0c6be4583b97d054fd2d11c431292e52e559206bac1a447b4267a93740c7fc50973a6569772589286593164262056ddd60e6cde4fcd7798cfcbe4761ceed93c68f9075c6f1d5ded991974c2c75a8057eeeb73eeb07de5dfdfde32af4f69fa1476209f38003cdc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "5a1c93e287f1e01a6e832e7c0c23522db04758c67faf12f8900cbfdf48cd62fdd0e5f1c1de85c921104164e35ff970ae0f047ec1ffdc84934cb869d4f944cbe010061b6e1f04fcc67eb1fe73a267c9e2cc784937b70ccc9bc210ce12c52c1a4c6e944d212d8a7789f7fb28e0633f299bfbb69bc967a464cf18610c695029f14a9049fafd3d876b68c9e3abdb4f829ee2cb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "70de86a6b3d9cd1d9b61084e7008b948afa2beda8e6171618260533d5f55bde09d454add55d6c6419467a57e48fa5ff16ffe852d5d650659310e3d56da10d0bea2d3ca1ed3557ea2ee5cd9a1067f3415a628aa0c174234ae0636e662b51bf5d1d0d066f5900e7464ab741bc69d3fec621dc610748271a672862aaf3c553fe4ca2ed9ba4f57f1e27953e3167fd1d9c3e4c30e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "2bb9490c3f07c77e4cc4db3b10e57e6606920d0ae01bf3a7b68a3d29b327ba9f5d7389fb0636d1494c3cb95d27122cfbcd9ae960fa0fadcbb123927f93599a24be52a01be80f5763597b8c52268ae553f5f6a90894573cd0a8876ee1035a65ff5a739c8abd8f115cab980d369d68b266b7a34d75f9c18b2efe3742e3e398ab6c70448f670354a8b486fa916bbff492fc98daab" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "deaf859404fc6e48c66cff9bc437eed861b45dabdbe625af4a82353f426a040050ed9235c0798a40930714df30bb796b64e9ad0df4350e196390aba4b0a10a6cae34007414a5880c5c2ce672c2b36a0e7d2622d677b74348ce07eb3cbb1c5a9c568063d8da555a64a0ba4b126a0e9d9f9ccde4cfca6d206f54c022f7518b8dda9d26d31a7dc9a2afcc3abf70ee5b0fcef9bf669f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "f875ef68c13c5a982637b84eb21a11e6f57ffab07bbc11e5326fea005326cb27c6f70e99347d5bf3b303639c260193c1b7d15de51da7e661e2ee4d08d5022d918d0bf1f3a4572d8003a8a4afb821f6dd03c2bc189391f25b2e425b743282f1371d209b61cce95092a2aedfabcc842fcfdef7a0b33473992e13fe0d6da31b41976597aebd26657407ede2d7c51ab1dfad8d44e66b86" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "9f46e27edb697d90398d02620b06ac8d49a3f66f0cfb02b9c628e70bfa0bda51eb024376fbcec59d8517f1e896557349d22ec78038b66a9a16460b8941005336bff96caa32e195abded0d31de0f4c8ab234d994979dc2b53476460abf5136b6b7fe6489793c14c48daab353208e150c43f7b1c7d659d6f8b5bf2fc3663335495e9aa47537afa5b5173aebde200f26705b6f1f3efc4be" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "35a3235938ed1312e8d79120615daa622cb5d24bb84efaa84dfd8daad79311ce6ebd52af7c8ea8dfc3ab72f49ede51d5b62f538e6cc84127a0eefa20c558961c644ea09c913cfc8550173109deb8554e0a418351073d5bda8f13cecdc71f32efa4e8c96ff5b30f663c7a4112f4b6b6afd6ab8daba9e2c7ac604a7e4b00cb52cce8ed10bca0cd6a6d1842b59867ca9e7f36ad678d28ec5a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "b3a70cd849fb5978199d363881831cc9df46c940d405360faa294e36e8ebcbbfdd8a672dca3b3195eb86b1a0817e537f853ee599ef3058692bcf5dcccd37118fdd42d50c524bc96ba7c6d2deedfe062a32b7ac93a20a8bd3ef20fb7a1766db25313390838e6a08e01cc932dc8b4410efdbb02aa4d53cd88d1b5fa0ba564b6e764aa417833f52e0a3ac46b42f4da1ddce5a35e070e0e02343" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "090c351eadfa98ea2843c39c0f1f6c6bc1800cf17359ae22e7a8a24960ddf137666e1cb45eaa675bd01175e81110f54c775ba952e3de3784987c96b92bd9fd349c7f120de13553366f621e7437a08e374612dae5f9f2cf9081c6761bf287c7a3af39963f06a345f1a8f7a8b04d360836f172bcc2f4b3aa2c6754a60b1bd49d42747561b3fef35501581f606777e6530c446daa462a4f7ccf83" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "01cba0c30285c6963c3bd9455713eb330bb887289c2a71ef7755e64cc0067810f120a1becf6a0dd45eb8c31ddb2befae75bbe7b4fa7dca9417455b92b6adb7118a36bed55b379f66d9bf4423ec928f14ff644019a6b9bbef69cc013f717b9a385ada55c87c06dd6b3474020edeef23188d0ccbc5d758e61eb00a20f9f52f309f2a8ba45f49db93170e61c239eb8bbc3c89b0b925c1c87a099aad" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e13f2c5aff51c441fc9aaf48aa45bfa2afc7c517104b6b7d50a9c4fa40ddd0595bb06541ec709c685aaea4c77ac37afb266f3510ac0c8c8891b4904a065ff9f7dd11de4bb758f6f2f5b16370a3ebc5890ec75b69a2c014bc9c67598c7e094c8820858e34c0d2150996dbd1c3de69f53dbfae0283412d27680428437ec1d5dfa444c5a553851bde66ef3377019c06f93d36e9b7e540e09ed223c948" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "84d5ae7fab040456d5b60a49db84184c6522c671eae6d715432d5b92da30fa8d17ca6fd8e10f00dc0a06fd7bc0fd3c1b00e6308b0c2615b20aa1a65d8ac905238c0520774181ffbdf4767eb2971813de6ecb07baad256ae3dbcb1b73d90afd0f5de22ee1e4be79541bcf4eb887ce1f904c3f32a868b289a76e43214ec171bc1639b51132a1f6b0db60c835761b6106115d81aecbc385114d56372891" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "5fe779f861e709fe51ba04ef56aeab3865b758ddd56caec49d268eb04ccf2cfbd83075286011ba7af59b8c50f81d978b029b541a5a5023c86533e1d25c4db5ec4f9b4ccadade8f4332fb62dd5f41cc0756adb4662c4b9063c7bca3dac7719082080e07de40956a4f3922b0271d6227115eb634639383608693bde9942fbeb4c0a76c1efa407946ad440556f489800d92eca6a7c73beacdac79e7fc551a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "be6ba46b695d0b8a24d4886e3a49caa510bed696d342a842bc51c0d015b9b737f299516ec27d3082a8c87fcc92bd50efa4a3aae7ca140bff820e5a849fa02b421fc0647a09f5a0f01bcc31c966fefab1e136b0c6d1fe1bfdb24a436f7a84d3905a88dbe18ceda4ea4923ad4b2b42ecf1923678f3d0bcca46c20c4a8edaed8f76e27ebeeff5d3fb3831de0b0de469e73968f94adb172c50eed38cb058ea62" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "a00bc425de55c2d030ac39dcce74083b56f809c1f1f8e3398fd68f4139a083ea7261f872378aafcfa6bb45b720101c9be64eef0eb2097a1c4f66ce4b56df65b144ba74267ace2c0dc80076d5d3e6e8a9acd70f21e7e743422acfc148be0088db05ef5575f9eaf5a1bcfaa468142b8f2c4a62ab3247571dc2481254ff030ca298dee37a4500845ee322378324ae2f635f4891e2d46f1f9c71ca307e5243d056" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "5f57318fca8c3a3b590e0205a5f5d314c15fd2ae751ba7befb91c4f898205f3f2701651e23f941c274b9228a39b598b33405f4a75e9d6600f1192e4f06f81edeb7f619ecc4e82b161f0cf9c8d37e68c7139ca9d653ee34a43419205caa61d14ab51f28b7c8e393dca8d6fdfdbd796d7f84ec0f3f33ebadeec67dbf7afe134c37f2bfc24a8ec47e0536361a87c8ac238e42c0baa9eebb9d576548c847f78f3f78" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "61237c1ea7a82566fc6f76a1d3d78eec3b3181de76065da39f4bd1da971e40e3011334c225e66ef4d4ff50e49b331ac39b00c91f985aec227d43f7e0eeee40c2668328201bc663039851fcf757e1c757f27f831a983b1050ac1e669c6a1f4cb42fd76c40f76cf0f4bb889ea36c02890f0d2adaa009d47169a9a8b4d1bdfb2e107c7b3b2bc907c368c59ab37ef54f84c4488ab75901995ac8430c27be15934f0de6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "24c443acf04ee19b20fae2268582993fbd142d22ad75a777647201116bd8c123334f6e0e847b3030af1482f7cd2cd2ccf5425683172094cda8e73e33cdc9991ca69e3285b9387beabf00c370ceb47db606aeae4b958636dd0937ce857cbdedbe31cb67a33eedcf2c51dccf620e20d8dd9f35718dbd208d865f1459e4cf3946e0a9b4e60ad0c450ba81d73d892b0cd595a52f4e07b6f740bb957e7768a9f32bc154ab" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "7ba4f3ed6000a2117982962ffd84e932de959aee244a8096778264fdbec4d04ddacda8a73c5728b04f0571ce5b9ec482a9ecf50b21133418f644262d9794601e7f2398629122b5b888d6af02ecb42d2e41238e0082fb2d47636f2aaa6cdb7d3be5eacdd4d4912f1b307e49572f1d657038ca83d1a9c456bc3bb6faf851687e5cdf4977984a44050413b5fd2c4272c2a3448fcda152e2c306a98d738ba1f8a21fcbf57a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "9b16ea160c255452b6baf3c4e5caf627c1f4e8663da9c9036f048860d31f0918075e3eda569254422b0295ff3afa152e4df0f99de21bac416e028e2a32e52896179f18bce7be2c5ecce28625222dcfaf2cc503ac4768df7bf04cd38d6dfcf1f1c4233051ae9843de7ac552203cbe0afcdee913ced89103a986af7fec428f9f93167a4218d5745cdcf57c6de15bcac08ce8a8de8b03ad9ebde73978a6486f7e1b90d1123e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1dc2f82fc83a973eba60ee0ca1ad7a50fc50e9db3fc530378865b9abd4101198d6017a40777839dbc6313ecf35b7b727e0311226fa865d73a43cd28a400d8b35408d789b2249b7a8e5df452d50c6a3c28fcaadb58b222261be49aeee3667e0ba7c5f2726e31cd5bffd125231116baee18bdf7727ce3bcc0c31e1cf600635623881a944d14d514e1becd9bd0d823b41a93ae969396db22411172efdcb73593fc8cf80071f2c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e8c00940d825a6117d59d922221e01e2dfc2fcb47bcba06a72f09e8f5969bf988aee8a4035fc97d4ba4a0d4629c06912c908b90611c1cf4c580f8bd3345fd8b155c64dd747a9c21017146d620913979ece6df5a610d12ebb9ef30724586655ea7a11e45ed51a58f7705db538dd075a6a5ff70239e88a8d8da0817da0318aa57f637b522c50418da50d0710ece7e3b36331eb1147094ea8321659e6cfbfb90e92f10e90c3a73c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8e9c1aee76744af025ba3f5bf630c13af132ab7c55230c8adbd20b214f204494f08035d9cf1beaa30a3f8522eabb88d02d5558e7f43c27b58c56dec5bf67812055a99bfca881e86f0024ef84501eb63bd5af849a134de4dabccb087a6cafe0426ff0d03de8cdcea2af83746f94b33eba2dcf4de7775d6a4db8d0ccb0d789e11b9bc3586e82e31a265cb26f82ef705139a5464118072af13f494f1b9a07bbbdb19dd596fdcac414" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "44753f6011c68059b5fdbaf6156e158221b5f1a544225844b33f3d4509efe0d4185a670627c3652b4f6427b583ebc5d941da2a801111a12d8d46ab1c0fde95c91e538be2e86954be14d3e7ae33d04029102e4267f3e2f099fb76f6801ff19f26b5ba07c29ab74cf1e3f3e3bdff363699dcfa7a32e3ffda3419bd22691cc64167f66a3c999714144e1079e6ff0472dc218d11274c061d92d97ee5ac1e02c104d1313a1ce3272326d3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "f6a4be7b99c42b72c4e03cef4ac7420b445fb0720804df5f58d284e16cf27ae905dcd5e53f2ac1cc19d62c762fc9906cd45a0a5720dce51692285118f80dcd0cfa4008730a49c69aa259cf9221f2a992c21617e5fb361b03cffe6bdc283866d4f4823abbf43f02dd4d9351f1e37cbabe3eba1438dce281d6b87fcdcc88f4d6c2473d479467e13a5a1e94d1fcc32b9932c5f28ada66615d1f8c7e6e9170b06ff1c1041eaa4ca838edf7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "894491aeccd8edcceb6a6cb3c7722b2959cc591f8443b1efbc19a459d84c77183b2439e594e644b5b66091059fe372cc41c98ee01e2b83242ed2379dc97cb7f9d75fa146b36dfa9f923f2e5093b19fa4beb18d844af8926338f458d458f7452075bd0882e70570fc9b74cb61fa4fc2d50f8aeba4ee7d1dfaa4cdd44134c751ef6dd04d06f4892256472a09b9cf68919769c3b1ccd75c3b89b7f122d9b5c37d8745caaab703a32113afe7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "0ba47fc6ad5364ed20dba3638480fd26ab35fcc2da8220e971f3849235d6e706f291e08736bd2edb5de04299bf2fbb97d9fea02456244540821a7ecd0f3b87a7819e054fb14130c92245b72b8b8b4e5a0d3a0cbf513a75aeb398e2c5842553c947297603cc733021608451a615cde713099a4b4d1ab26b6a322932d1fd6a99c0285b7c44103c7ee80499db0716160382db8fea1b5caea9aeaaf1d940dedf185b903dfc2764bae972005fe0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "9f80b7abc0af99d288971d6a3bd35dc802e7975eeb854bc16dc0d7a2b4c41607fca9d2628d042d65d7a2bdabde5912ab36b293932c12f02f8c97d2623fd4b660a559de3ebfe58ef90f5cb5dd9515f5d21157825803f32aeaf2c1700ff8d084c0b7bcc70ac7f29090ad8c218375624d58f2ce789ab0b345da99ad17a47279d3e8a001f337e5fa7278c26554c673a7bac334efb258471c4156974cd1b54749a49000cc7459fb3983b4258e1f0a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c254b38aaed704cce241ac2308490d469aa01403a44fa44987e3a33a94f51a9b762d02ea54967a8ba351812a6662463e82fcc4ee07af0862113e01c3f6d513b292dd02ae0e3afcc8584b559b930a27f877443d9443afa119db7cee8c632e18f186df0b907e8e3f3267f48a5a44232b720cc9330720e93a31cfbdab14718453cd5eac89beac73c996b6175bae2e91eda40e47625b286d42993fcac967e8320d7cb013a84427df4e30d23abe9cfe" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "abc8df1ef3606c517f5a2d8623e5cd0325504ebfc670da56ca01a570cf3840416b24f21091a68a536e162cc7ed7922869b7ab30283e57f5eeb60b778a06a8c5d6c6d10c91fe5cd37ce47669b785b11a3e1ae824eb9dbc4857a3ecfe0d1aeedeb103688daa07c4e01eb3e12507fcbdf1522fc5a186afbd858cfe8a453278c78285271c303a82417afa3d1893e09b4d2d1146c715cd226292af1ef2ad968ac7e491c127129d106677336767f25597c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "dcb3db73e478b5957276b1c6b16b1cb26d6679d4ce009ee6e5f4dff8ac135296f3ceeb80426d5bffac0324e927d7f77e31d011737e7460cb1f19b8c8aed25a786ebd8b521524c5faddfa009c6799778b48c50075d43db1dbdb891715f038595c597380a8d02baa3f06c58bf3d610148ef84c7bfc610455b63c1a8acc9e834cc079bdc9452bf5a1964c75776f33ce648d71b99a3a97f776938fd76314296a892973f1ac73cfd778eb130bb7aacab4b1" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "b390160aab430ba9fd39956bc2cffbb81e85f83323840c665cb3c8534dcbba46769ace43b21a0e0f6808b22cbe2e64075c5ee4aeb9f6588cf377a7f10f824aa48e9c3ff93c2ab1ee3bf2149ec9d51783af44d50d49f5801f5e30183b4a18ee99496357201602cfb7cdc6c68ea95bdb858dcef3f4333e304183f139811c853ce1397deadea3875036c72d4e018f8443763e5679bbf177b6d6f9295a9f0079dd6f3d33d523481b44d5abf432fb5cc372dc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "eb380ddac0f8e07171d05759fac1dc71a22448e1453ff2430f82944743457b56a6c5228f6d14408d703cdb89305c5d67efd1c8cc9b0b145e51784edab2beab0021dce4a93fd4113cbdd7c7a33a6a77028228eb6b2a6750dfd2f842769da9692b8f1da6f9ce58ed56a63a666be97912f464ff57d3214889b7d66394b759caa18e57266b63bef3002a8a32d1138ff033e8f078d88b2f01b800e3f1181acb82460b8352b6736b3f122f02f416fd4aa40ec98c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "b480f56a66f51cb1385dec327ce586e81d3d9143a7301dce4bc593035080d6c2e1f0cb256bfaa082f68edd8542c0e0166464021dd2a5d721e9f6ce79d05208c348d9c892beecda78200ff67d61a96d7d2df1eb5426d41d5cca0ae3b25e896a914360db473c96899b923fd850a03770923473fded07c0b82cfa2e8c6f9aeca4f266829ebd10a07c1662d2ab1f2986eb9ebc33559958db46a89d46c7dee617caf1740f5e3022458d5cb0b8476381ed6ec8abc7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "a91a2d8ecb6485fa780adb7dab9679ac17f2b269306589e1eff3bd7842c2e004795ba3367ab5e6bad584159a6e6c063d64c0338cdb19f89eba55059992b02258f27fbbe1b5b748810a6d00cb365e08a493b98159a169616b8ff88f7e67e7ddb6502e03481a2c601852ed0b6651fb8963af760fdac36edd4fdcce1529b2c3800af3e63ab6bb013864b49950f04a3c784f0e84db4a1f58aa8b4a437b86673d124caa8534afff3fc5be3f5d5f16ba6f862ab5b9e7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "214b8e934e70e2e9ed6ca65e198bca56c84f498fc642b5add5b709b62544171a4d57f82d70d1fbb5cd4359379aadd8dbf274da265ea78302d66f130aa5593ab968a64f596e5f72093ccc3e5473e2de5cb4378823e6282e93d52fbdc4217cb1f942da7e5fdbae8c5ccd44c59fde24128bbcc3436bb6e43fa6d7bacb7a8714f693f1348dedbb024a8c22e164e0e7804a51bfb316569c3fde1b771fb2af9a648d949cd701cbab36a5bcd87c6923428301f3d64f5231" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "a2efa708dda81f8ef989f37cb10cf344a8a91548cffbab474041b59c5ebcebf34355e38de9e3b853201b3a4547762b9d10bfbdb52d8230c057fe84177b7790f488204d401fb8dc35fda836cbd549d504c47487ca1ed4fe80f327acd84a43e228c43c811070d74b788a3ea7b39b4a908bf9a17098fe36723f994b0d4cf2390ad430b979a5a48b89e1b7069656f806d53ded32cd256e3d3ad0ec09738b822aba507c16d15f2f4b748fd050b7984654e597d9b30c63eb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1c8e20f3bb00f4d30a8b6d53458ff0b13032bdae6bbf1c99389d32069284dba2e82e068205583bf493de4cbf873ddb0018d866d4543e480b7f3040be117f526e99dc60a60bd84c3ebca8331dc2c126304369420c5c98d00f55d753cf7a993d58962093fae8460f2af2e495908bbe8276c50c11d15dd7ce09dfa35a49bdb6c1b0679f4abc2645034d9b61e07f29af79239dc2a47bd04157ccb5e77011f8dda9f75ed06e1fcb6b87b18a0d02a2648d91f6800ddd041a85" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "34a6209350420b4fe7eb859cbc21e7323f73921819f03529de3051d248f5ba3d73694eac76ef6e3281c51755ca6d625f6f840b181e18ef1f227669603e7f65875891639111d996314dc4b6e5a2dd18a8fa2da32ee3fc1514a44b3b105d291f3d49990d2a1c904921685b9f713c484fa1787608c735bccaeb4ceccd3e799960354444cdce5d9880a3100ca285560d2b9d3842391f60ef89126a58a0af453b1dd0d8ee44d253a99fbcc9f5b0ccd7b80cd2488a57bb4b23d8" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "85aecb151295bb3b7c992aa4c2534701e6ec0c9893d9bc8b95716262497411d9592b4f061357e7de7d03b0bf213c0c371c513e12fdf5d0fcaddf8b4b801a261082731dd269ab64e436dbade46152669a945bc51b9fb583cf287c76af8f236b2b44c85649066d2f46ad699435c3c3e954a9e85503537d70f34c06c5aa7c5e0cff11d2cf37c9ce6e883c837d7873a0b152470b26e21c82fb36c300a5e0bb62c81d09444d0967f0e8e8533d69660686f2c7fe2cc6f28478e231" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e7eaea666eda1ad214069ebe8acc8c01e7fcaea21ac8bc4922c686f8f256741f6b29c00fba4e9556b056e3c1ee55d75f06d946d77450c5398e17844ded4f7276693bbe9109bfe9507f42bced1971b3b03f3d70f25f0f99e29d82969bcf1bb663e4c4ae2a04882e05baa2f9c34c029b700c745705581cc5dcef33472cf2319aad0d1d37d92add19e20c88168475463969ca10c5e37cdee346482edbd9133636ad18690070fa7313fa39a7b8656b3e67340d386bd91eb2069262" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e0d3cae4de4bb434d22e779d992c671825b2af5209a236d0d82fe8103d21bf4519401ce2cd4c2852a8aa63f4aa29c8533ac9cb280bf39c92e5813208f563e7b3b88393f611175e99bdf22abc75e2cb175e5bcc9e0f614766e8c9f61b675899e701fad79ddc1f84c18649e50795305667bd22f1bc5dabf914ef207770c99ce3d802ff9afb36c829e5eb34c3218aa3ac47381da335d6dd1757c92af01f51b45d1f7b08a2ce50586474171acaa36927b10752268bc727b057f7c14d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "3d237d5b4e1fd29c6677c0fe437bc6624165b3a6e3ca157258dede30d0a59346a57b49ae0cb049324d5c6f289e91de76ffb29395a79e4937a74fdaefa65ea2513a487b8b50675954b72c9d551b0de89ef39c5596e678bae4b5b1cbeebf86e6818555fe886c624fa37f645120973fc92f4f83b263fe6d3e6eb4896d3bbdb8840c01a5f96d9213ac0400cb39e045ebbdbae00179afb31b77823a1ca3fae079d2cc4b09fb0525aec2ea5421e2c4b5ff9e2c881a29b49f9868d15a5dc4" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "89a8c115681b38ec1fef2137fe0dc1c76d53d042820536455233743830fb08a9d601fd1f3d796a08472687e457cad3166dd4781fa3ec0ade3ba31ba38a528932f0c6a1727d012631f649e50c76b983873217fc3c397c39ad8661c0f818222c55b35d0679b8ff13ff66235ad5bbb64c2eaa2891e400d443c687ddba429c2ec038c080785510cf999e0d2bf4e3918b27ec209145e0176dd533ff69876e4ac57438ec45ff3574a8e03afddf802e946385a158505526c1f6f6d816db2d3b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "f3f8196eeb035d4d2d9a0312f962190af5451a245a04ca77d2f7201c57a34f81332822730fb68bbe9c7876fe5b2dfbd56734110a9cc550419643ad094dda17171fcb06437e69e76c6614f4b90acfa3767093ad1eaeb5ddd3ea30769efdae090545eb74c482559c9c08e78231b0f235402a339eaf72c1c3f202a456d9a954e3187325bdaec1cee4a436e65a7ba401596a88c8b116470cadf8143f1cf0206eb7fea09fbe13178e30c7522218d80cb5146550f94c0f7085011bbea616c82a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "17790b069543cc3116bf84983c6fda6b6782d48bea79f4359f194a0a91f071fc9dff793af64302ff581d60905ca0e0ec07e16bb1af54d30bbe2ad2f522611d6d164ca85274041ab0a041f78a066480f19cb44ef88980febb1108513654b06480350fb68923b64b3c06c749d9da05430a0b4440105c44653e808a8557f59ac721c99aea7edf76b3bb3f1abebb4a7e55babf42cdc03c91135b48ff1554e57a96f07ed9bab8e6f529c93c6ccfa6961a591d8d05d7a9ef4d333b7722d2b29b08" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "86e0a5f8f3e995dae42d2e73d87438cf139f4bc42bdffe97dbf8fc26939f1454a254fdcd56882b3f552fa30b25ca62d0315fa49f1d5d42020b68bfc7bdb20fd4957ed50a533b2be720a8af438e68f174cbfee6817f3f0b3be2bfa365ab51942dab2b321def065c20cda6c7b1a7aa6fc3a1f1d6b4185880491601507ae2a0fa9686b40aaf0524705b760e15d9db822bbca58fba45f6c2d1b33fe49381120dec862d3940a3b145106125e3e99068beda1b073e5f03d38f6973e5969a4bab896e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "0459375f9886f055105cb34a109eb44de838bd5e14812f0719a40593aa1bd3c76c8339b7ad90d934d23f1b2aef5aca6f795c4e0132fb1e2d0702fb044f4724fb33e75c5a5d5af60501bec7c873349b1b8bb756ff7a816088ed08fd1a1e79830396d3f73f4656da870a5c1c0aa238c024ed490ec93e0e410c9312b96b5a64313e3d404c6236c655c9d9ad5df6b64e2149bc62f0173f33df60840f44386f4726ce15ee50fbaa0aedf1c384225413889f68571e578412bc6f6897081848fb7df0cc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1cc2c138b0cec83dddb572024356c6a05b456b889f69a8dd2cd8007fe7a23715b567fd6f646c0282b5c5d5360c0e1dc04fa45f69010eaaff42385ba85fd8d343bd1f6d2ac4556fc35ef57394473652f468bc28a0911eeca4234cf0f5e15d5b61a5c8e6340e974835aa8d5e36c63cfafb67bc1388d94e2a57f37056ff1925401f3ea9b497ce7750af79d45a8bbfe9cffd0597a0ad17cbffaa0f90451ac25ed14e807e4ec68e0100373a9d951d094c43308ebc195aae1c68067e1308bbc6144d0464" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "464d0ed294396d610f6b6ce100a876c0ef5b6d3193b746e2152cf437c422a2ab89abca1af36d2d585ddca437e43f9b045c129147820b0ec937d75f5051bb70c528ad9d419a38c9062d665a111e738e44ee9ec9c0f06e566c7267b05f8bb824854d4441c4cd3ba152002c4425e42e9e67926ee8f152f4b76f8bedf50855bfffb23780f02897765571a66b22c3b91fb115ecbd8f6b60b47761cb89d776d8376fd7a7ec9f267e4a27c0339d05812fb98e332100c3540d26a13d1122c09ab64acd30092f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8b18cb31351dc0e00052722e236ab7c57c35c6ffff24a1dc28a56854f48ededdb067315234f6b25308a45c8fd9cd8130ecb24cb5ab0b1719796681fcbb4fd007f92c7d946545a0ac340f7e641cf3647756e08a96d4bd3396b691c9701b149c0c3859fcc922c76d2e827b5717198f015644301acfd2629840a0196e00e9f50477fc561dc69c8df6322d05e922212f2a5d5436701bc3256cad9d868cbd3ca4616938c8cb0e6dca03d2acec7709aa0dbb82b558b912f7e18283fcf13b7e32a992b222f341" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "f9962f0b9c6d5628577fcbc108d5708c2ecdc65c157ebabadfc68350cd0734d8ce6277544f39b16438f3b29b8265bfe421eec22f854e7ce8c0d165ddb38ecc523d895704764dfe263303a72db9aec08b1aaf5edba746b585fad6af8b7c61c7753cf9f1fa6121959842bcf74566cbd18bb8471bcf438cc3080feaca7891d326e627de7fb0f104851f1afcd832c3031366406953581540eddb0834dc79964facab1e7b8a45a3c64c6726e3057f82c22c674cc09f41bac59aaf3f7c727f4cee52306f91fe4f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "fd7af4e31d0f692bd74c4089e0af8890a933800b04521d59bb8c24bacc43e96193fea4475bd67419153362b83e54d235d7c7816d4027197e73ec1474dd2d7d003c1297eaf6ea80586d748cc52f1719b73f66cd6174c09c12524f960cd4d4bc26d066020d2ead9af8210bb78eebcb7e480604a1eeb15cb5e3df95f8d701b2d3ebb0b5b06822e157f09fd5a12fbf6af1762ff5cc9a7bb780237fe572eeb9fc4f52ea8b3494b1690fa5809819af4680070d25081dc00bf531710a13d8b661fbeef104ce7bce72" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "7a366aa68ea6dd5eaf6820ad9ac4a4863a3e67dd54d1d54b13f4bc88043398a5bac0c735750e5d3d65c157f97cd981aa1ea489f58d6ddd187fd18b8c65bcc3f36e22f564c64786254f319e25bdfd3edfd9d9cb744e7d36115788ca119b892ab4bffba4b467eeb7be8bfaaa09d902143765622351126e1d9707929350701875d512a762d28ec4d9e506d946078be66c6f57b9f5f21d8121bb339e9688b52a7ec1af7c4d0755026a531b73cb940c512d28d3421a302d83acd915ff2fc3c2a45ad5ebd91db7168b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e29fdaf8cae1f2aceb376d53f550170e5d18c44b3083c835340ed6079f312c7d1776824a4604d7967efda33b3824f106abfaf08f359555a24b78dc8ed6787186b8650a19adf64a8a7bd3d8598d9fb4699d3c8df6007086b03141a78aed1fab1ba46d4ad57d6b165dd2a405a6725e50d7bf0114728d1f81eb542abc72ebf499bf795f58f8bd0805b15fabd16de34bc646a7199e2df0e80064a9aef599c9d60884a6503fb9cc50efbc6e46d6dc1c8992978b9cd67b6d61b779c99e98d01c4c84a258a3318e57672a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "da61658788de4b16bc6eae4d9999785448e4055e730629275d1dadd048ac007440ec203f593c4e790cf9bdeba07ac926ab4310c5d6c196fa62dd239b22074bffa535fa1e9616bf7ceed9ecd56b7b6ec1d1d6f88c8672fc4087db0488cb0313642599682a5cbfdb7b79cbff91b4bcf76ad8f779d9fc2fa8fb95c4123775c7c0ffaea19dc28f310aa40cf734b8de7aea233c18b40ce01a851d0e208017e4a8f36c74d344a41dce80b6b180699021bbb13670c2c6025681b730c5f2ea581923f900c9e42baa2d5e0a38" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "31f1b58b087a656bd501b6b89b95e87ec36db90469b3ca02e8bc2b2f2493ccaa9dee81e8877f41a846b717ab550bf3ddc60438d747520f28ce4c30db9ed6be0e5062e5bd4aeeda7c42b94792247b383423cc24dc84613b1c8c892fd3c926267a1f6b290619be07126a34a442b860980967844138155bdf8fc4869115fc65fecd28b16bba47b4651e8bb586c1189dbb7d557124e04943ef79754beffdfe63ef9151610abbfd7b9696b98a6af7f5af088a6ce6ab23ec7533b7ce2942ec61bf9baedab3f3768205ebc85b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "77b6b031b61fa2a66115ba10bdbce0922cc3a5fa29a1410dd5e7021182389319800c3c2e3587af3629ae821366ccd5fa498960786814c3a2263a7b912d2ee866a35a51fdce1df8c7b9c6a86659bd6d2a05d665fb0b6f39582f26d648420abdc1f0404739b0502f85ce9b0d034d51a3eeabc562a8900ecee65dec28e111befc3c62ef8f928e707cdd2ec76068f3d347eeb0f062f6abd23e7c0cbd50061fd462dbf07bec30ef13ced3e5c65d2d8913495680a71a80275c0ca20d7a693a3b25f8c96beb78dabfdc55b8ab57" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "5169d680a74be335c0bbfa5f28985595b9d23b4a7101f92d11332ed5938b578900c18b6c2cd6676bf3bdf93121b6537d3aa97b3856b2fda9dabcb1a01f7eec7bdb8239dc8e6aed00f08bce422ad6b834670c847684669c84739ee2e26baca9703db038b92b943bd9ce0f8fb2711e79f8722115e6d7b8eb9b5cbc2b7e318fdae83edf3dc24b400b1907c8b8450c6b31bc975ed4303c9bcaf84b4003077f7c39514244434f7ed1b691ec9bf4c01005e14f40e1818ec376cac21d60f3986dba064f48655a5ca9a9f6045957db" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1681227674cf4bc7124559c7c3409caa4eaec0f895a35693d454e44d79166bd93d29fafb5750c4235609d8a6545b19685a3049466c1e9a01e79221ff4d045390d3493186d116eef714a26e79dbc38a84d2b44b5909524d123ee2a1db6c5fb8d97f6d9776acd3a77210107c2853780225d49b8aebd00486eca5f469d0fb4ede6a7bb72ff92d778357b25053307db21b4f394c120c42712d52fb2ab3f803b276d5d81619a94560bfa0dbbad76a88f6527e453ee3eae3cd0dad3e9be3bbda9277a167d4de833f2a0876f13032a0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1ff6e40a736e0aab47957a8f9631e7b7740645cc10e00ad4f1e95837bd45dc95f44d63139c28351c80432d195e8970222544d7b9f31b29cfde5bda467b814ff381b0af02ddfca8199f18aceb656eaf34df471918b5280c0c5e08ad17dafbbd22627febdf9e62ab1fc0beea3f3732ea166b4715733ec2c68262c09103ee96b062a0d112af1e800cff59b970101626bf3af5ec665d9de91467101e8a261dc733fef971639ada5b8c7679efc6a83cd6195fe5ee933efac81e8f83d0fcc4147f6dd7ddb35c1d0a17395f3309c4328e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "b44f695a21679104c2ee1662abff4f654712c990c2b8a89141481e5f33757484a2b921e822c5f37e5703cdbca480df2813163bab64fe5f7ee2958c6e08d2296908cd2aec4b66055f4d64d39967fed56f1074365d1d0e973cf10cb6b8b872ce0debe7658d75d73a4295d858b316559f9ddd9c4adae98143d990880dcac0b8f2c803a6162f0627bc18e8b43c0ccc1475fd03c51b39a64d93e7d60bc63de383598833fc248b5daf8c124ecbe9c39e1be8cd9c0e5c453936b1370177720f2d0b76078088ae483018ae6d5432b4324aa2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "dde2dbfa04b50b16c03e7134981e2a947f49fd05ca06c25d3dce5203bdb17a281af45a291f9e0c3a463468f90415322bb4e61ef0016f47f169e0cdbd4dd88b352f6f27c12ddb9705a1269529eae07f3d34f6ec9fd5ac8eaaf3f20fb1961c188a771163c50778dcf452ea52b17723399d3f8a02967b0e27cfa61ac1c90adb585d6fa504f646e3d08c9abd695405563ea08b0163c6a4f91c88f7b0321e4393e234a355e3fc83a5245ca46cc6236e6f053d854360a7bf379f521acee6b6f54deda7b2fe233208d75ae77db9d1d827afe0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "fd0e4876256b31547b3bc1a2c2def5c417a5d3fb2c3771946784705528611d0bd60b1b5bedf3ee074875b6c8f38f57eac0323d85842dc3980c133f785379ae98fc732cdf733e7600b0cdd895b15ef0a280a01171fc7be87995047e70f8f4a1556e4cd7f0cbe0afd63fea4e51d5b8ee613ce38241e6f6e9e25c577cc8ad7dc914c0f26314a6a629cfd85d364ee73db9e888036fcad410478b563590aa10324d0b7d95618d36210fe8d086808b09fe52939f629d0e083ef6b03c1bc46b7e57779649f5f2b5f9f2e7f99d4017d1c20de6ce" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "6cfb70ed1c1ba261bb608217a062828357f228007518657378d4c633b5f15a54946cdf4a25f3466860339b42ad84b2a13553a8c7e49999716d7c8bace66ba68bb499d7840c622fa93245bf144b0bad70bdc16a27ec9bfafa92a1a58e846c3565d1309a29a371fcc2105e50b769f4fb620d839f042fde48e72a01e5889154f0572e31b7d6caa4326f393cba00100404c38ba6150465cb181aa29d4031d3e2ec3f09310caf4dd0bea9bc5527aa0161e41ddd923c4c0885dfcfc08ff92e85c703901dfe0ab233066a3d2d41a282d77fb767bc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8cd5d164a2b79c9e78b6235e49e62a174b7318c8c5b9a1e56e344951ee03daceab43c7ad9240e6ace541a052a1f500145b4dbd6590bba86f094f0b0696650c64be3ed6d041acd8ea6b0a32082eaf396faadcf0ef1880eb8ac2fbfd82b41f4755f02e970061328a7c8d93de8043d6d8df00e0e3527ae796738be6a76513e12af27807e981d152aa64892a1290c5d28636b4f7917cd0b7c4cb84fc00f4b9687e195cf77a52cc14bc1f5881a02f2a118d2296f7a254ac1a6d566ce4c04e91e42c398ae305e406db300dc3a9d450a390958fc62a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "a7a88b8862ac6d4895b627d2b4ca88f144781d69f64da7ff294b92b1f398c8740f94664c8262d5f1a47ec35cb2442fd91f5a0e74317782c2dbd861022945447313d7e5d17f930ab9f7e546dbc02e5df9f07629baf206fac4c3a5bd8de1d4172fb99bd2423b67c9e6c16d5648d3a95554996fd9d8ffb8a0dea44cf70e9f3976c53187e3f54810bafc49ea8164f77e8f0e6b1207445940b82f7a2ba783d9bfa1bd19cf847d7d6a5eb5989433c7aee0356a021b0701ffce133cf2242560b451abfc240d23ab2584de14bc727537a7b5fd582c4322" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "a3dead87fa53514025d8523b2ebcd89c7136c51788a8828c4ab62cf129e39a13f0ebaa2c990e621511bb6e8c1f948c4ea4775ae68263f368d7a7d52346a2fb45fb098d7009d46ea17078b8a0ae8a6cdc2368e6df793f5362bda3ec1d88959ae4aaf665d6d755902c908bba2ee95a38f59a5bfa9564103b95789f31f293c8766c51d8f41fb598581dc1503a8904b6efb74071c9fc7f5d6028a609bd4780f283867eb71e5754d1459d70f5393a5da9a2e0f90492bba2264b3db26cb4294082a8d98cabeba6733e5081a8d026f8a490858d8855d239" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "cbed99581a74de8d52bd80a970cec4fad1deba42a37496c7a584dfe75f1f883e1810b2efe18d59b6d92d800d1a0290b956fb35f8f8c9ba0878e0e5d477fa1d4d3fa0d7a835a25cdf9282ad93dafdfd90a28d7314d42b4724cfa495a599eeeb501a719168e38dc82200a593ae3f34920eca33a0224f511247a733f03ffaf1ebf476ad3645c3f1807bfc01619dfaf8731405d5efa106df774c0f3f018f8a545def065578651b01c33dfa5643d4a1b03dc9953bc943ea097f1a616002400e1cc4241084f63acb935561e0d3ba0ed5e487ffb3cded6a5b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "cebc668bc2e2f5089abfd20f1e15167f923a3d8514839eba2d6321f91f4cc7045ccb9d07f77bcb4872e42984e54b78f2e1c5fa66882c34d0369342b78d05443001b6eb97943f80d90689f140343b7b8b7e0eb2b5aa41d270c6cca1062c11b3cc6e0801e62213cece8860aace2a94176702f5e5f3ee31cb09e8c5b18d5d1e99a66492b115f11eb951e78b268e19009ff509605c66cc319d38ac0402c20d384c3ae4772b8d3aa4ad03dd19a639d5dd4a7e88307d68cb7bc13d768f1bfd7724cb2da50812e77a516ed36a1666b23ad3c5d8c80f4a94b9f2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1241811d00320b1ba7c370bfef2e3f423caa0680c22d17674db382617ec02be7c360bfadf95329ddae76919208bfe6f138b45885a5cc54e9fa46096707625c8b6a9b2be1e29428a98177a8c7d703969fc6f34c7b4cbcd316b7515b23502d0eedff8dad2d918b2673089160ce5bfbf1a03fa43bded3b7c006fe23af584a577b6518238706cc1ba6d0f462bc3f62e68948dd2332fe3ab624df9662cde869cdff1b8785a08af7f14aaee0217ca2e29b3e1679acdd25ff50958aaef05c13797bbe4992ba77c3091320c5e1b237decb7131a1eab79dfd636260" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "f175fe4bb81904142c7bbf271a3133444b8fde748d151672c471392458238dfd84cb643715705e2f21d7193ba52e06b81f6644a8733eaf71aaa9b24be772e6491b68717d6755b4af4e45f43cf88f874fca71a01e559d4a5a1f60c321d3e0ea0a8854b8d51ce7f8febebfade0edcf04a74f3c21814061cc7e9e5a48a40c49778a803a0eae7449f73512016f272784e32a4cc78c8d0f30ce3832b7e2d324bdd7b0c3d09ca49c654348760d261c55b56cb7767535ea925af2f0159780bdc8906c57abcc6319f2a5e9f16bf6729bc6e919311e5948aaffd84e89" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "8923aa7bc888549a47f405f61f09cfd235a9126250566506b7576d1c65a7e49dc76553f1921a4d1e1458c35bb032d4d804e421d8e19d9ee0dc80fe4de1f06d183c3ce60709df1726450532ad082275bd2552233bce9b15324dd1211d939c0ade85a16b5618754c6bfbba9dc15e79c2e69d375918a5301d8fca2fc5fb0dd02d71490575192497f769967c5c5a15a3552109d862c5ea21170db9a660418dafc942982d56a46181ec290c6fe9322738f00ccd0dab2bb825e557e39d61662409609b5d06676e9801ee7826076a665dbc9a0b65c17fc48d6223cfda" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "4dd761fd488c41c89c1998a95dcfae35c7907221195c6747aaada8e37b900d6c2f1a69e874a088dc2a7f01c31c64d877fe0a970716446135af511380276a51b067ef6a4ab914765a36444add895d4586a941bd1ba8db907487159a968bb8cf2f4457585b331cdaed2dd327b972c5aa71eca959add6dde4ad0b97f82bee9dd5ce457b0bb3b6da042068f6ff2bb8c20d8459d44172dcfd6139215a42aca13ebeec835357d3e7e01b1a684a4089c1e502cb655331acda4cd2f1c748ec2d86c8841f7606cb13271710ae816d62c3e7e4e35c968cd608f54bad127074" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "af5d2912543cf85417cc243ce775ca86d09a3463a6f6caa554834cab060d88dd18678dc22c46c99529709afa2499e37d58e345a72d40dec191ac1035b9eb6cdb85c41e6d5935574b9600e3b6acbf9292d237b410827e3e4ba40023141e19372bce972e16561983a0a2d06b5659224a8cfb4fdc253311a7c7c3b08d34db27c5118f5423ebc5d0503dba6ffc8653b5d0be4e82e3b0d3cac1f5b2a5efac448849c42d775fb659b041dbc793c0b64a58e884410d6aaf69e3d7bcd7bf500e61ef66f16f77ad1b4c3f009206577196be081b7aee014f4d62cebfb6d058e8" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1317d1f48092dff2f78bacd0ca292e7a36839ed52d7bf1e0e729ff800372456a544ece4e740443652b67dc697e316009b3dcecbf9cc471193dfac3935c81f928744770a8b250159f44de9461f068d024927d5d8a4aebd2061fe015927ae67658aa48209aadd2115de5d02fb55fc5b4c274c7c9f2dbe218116fdc235e37d07a9fc5747da978c4fbee1244e5210ddbda05984f0e3dbc5b63359d2c928051a4d5ce6cd3857b6864ad1dec588ceb6306328f925f195a05aacf53d9340427f5fd433289fa0320f073417e68f356e4e6e5fb6b8a2a467af8fd51f4092afc10" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "3dc8e8ad7119b010d186e1238acb4bbaf33a2d93852ba91f733611e981df6597a87226f6c6d41edac6981d12e7642daa82c0490fd150b8d57f790630716b188af8285925fc0ff8457b4aa93963adfbdebacb8ba89fc4281bc56e4562a632e030f47093a7a44ec563c23dd6556cdedf899a2d3c1298f63e7959716981f82743b3f4d8cca371c7881550fb30bde8b7feba2e80d0ed5ec63e166d0ef17ddf8db2cf8cfe983d88eb40b0b10e0c9a9eeb38b220f7e013bb952c86b5ad11fc570f525c0125e01302a28ed8b1a97cc79edb87846a8e596c4d28f5018f2387a1ef" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "3a2f35477d7056e9ffd101691d80926ae1595c6fc618be62d6b24eed1922c1fdf10dc62d019a29b87440f3f3311dd90d0155e726eb96c3a49d985e9bf719e1480ecb4f4460d16cac29aa64b77e58d9a414160ed5f90ef0811c161c4e860a2ac705c988ac3567b1e63de780781b61ca6e8f16087a89e5304ceb7a68506ffa692194130eb82d1a458cf0057cb4a08346ace3076c72728c4e7abab4bf0add26d33eec3709a7644bc2c7cc355a10887f245f92fc049d733dfd1a87d2b67c9ee12ea4545cb84df60f3d8ffe209b7ac2fb3aada065acd7138d3680e36802f671f0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "b8d04609ff91f7dd457592d183d5482fe26f2862069011c5255d4c265c7906b55c72d2befd472309430fed0664b39cb67d16fcc622ada4976e2ff23c39910f85566473ab6bf0f5a8e1315310a2789ceddda80cae84f48f7a2d6c75df0277b5424d2c54c20209a9cf298f94d43b7769ada163ad1b4c2497e6a2406d41af3cbf11d233b882a46ee9195ad7f511b3de6369fc65e34ed54715681bbf8afefb337fc2f26adadecb429fda383b56a2529cfc7aec86b6377dbc17d03557d61f5410c106672d3a553c36e2a3722663f47d75c4c45595a9e7579d058aea1b35a5caa836" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "7d2f8d13222f1aafc0a47689010713d019feede3b1fdfad25def42550cbe918f5f4829787413a3606f854e0d431c6b2761d53f92786e969965d06700a39945adbdc17972b0ce501ddc5c6dd4b489944611ccbb9e62134d98fea9ef5bb6b5f7a684d971bc09e21fe6b40828199864516bc0b00323767a6d9506c8e3aa47c7676feaa60c820d70d0d8bfb7c3b7abb8d47eadf3beca782c79f6cb469c7c8c3340c14896b3489cb950fd23c4439a72f5c8a9589efcefb85bc786ee32124030a1c6d346011ef105cddbb398a6fef999cd19b04fcbbc6427cc385e8399d2611f0f3e65" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "723898ccebd8d2746ce9e3796d429462fe9e34cec7fd6c863e3d90c4f51eced7e241365ff428161a6762544675b6c805e6cc04c625f4d727e6e2e596c501ca5d9baab86c7b4d04fe4da505acd3e2d34b477ece7339b2064ae9f8d991d4f21de6273fb32fdd789df450b3d10e8961a5061290af31ea4f240a512da433fcead2c0908f9a020a0167fa45b7575e65f4febdd63ae251953afc407de50c5ed5da15384a16b5bbd86ff3514cd1f7cf2902cb7192dadd848987929121b051da8de022239c01e8b8f40379c0970e31ba98859bc5349637fcae05c8a50ea7c00fa3300b1af6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "6433591eaca79f1bb52aef15dbaea5e19f2b29312e594ac58702c3f96c297d87ca6ee2bffa2f961f41814c410b763125ec7a412e0621f32fd4b0fe2e17ac262c75780bd43877c56c413c2a6bd8c119ea73baf2cb821d46b7684f81101d3ed0429b6a94ad91742f7bd51b11bf4c12e5547c30e870f8e407bb5ffbdb96b10f901430eaf3e650b69b7802e93ec2c75d05183fb905f21d590e79617e4d08838a1ca126cb47d7e80a55253444682b49543b97146e71a96ddab190821a3007b28b55785442259bb2ade35e0cfe11e994f3894b7f3f5fceb341734e6b52d7e22b22f678f283" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "7d7e6bca9da076e7e833dd86bcb7d86fa305755e46e252eb201982fa3a3bd7fbd5d04d9077908a694de27a236361ea68a1f04adc231cc3856de97941ac8936152c51fe55e02be1673f315281cec9ae3b3f10f1668a84c1a96ee3f0a889c22cfeb7d6175b3bc23052971ae2e88b9be6fd5454b6256b8d62bdf617ad6cb22ad93fa02a20f1a3c29cee6447dff6806bcc7169f0b94b016c6a68f0b5a581a58d41a0cab986d4660cedcf1cc6113df7423bd486ef4e4b8f7fe33f3d82afccb9c86eea598156aedc90bdbccb75fd55c254975a193e1a6937e7a5ea0aefa94de7a9667565826c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "ac91aa5434938c1293186c76b7ae28a8437e621ac79c93b4b8145de9951f1948fd4cac58b781c3593a444b51751297db4dfd6bca2aa3452156f6bc412010da90270b09b6c5d0e4d8d836dadc2bdc35152ec6fdec7d1faedcb33868c81717100dca6bea92e08408ca6d1bbc7b68e7f71ae48f2fb2117697b9fdc4b46cccdf2d81bd6dc8c76c225ac71a49548b2f3788e47d56127a703e6705b08f4949738415b3392a701025775359ac29940a12161e554e50e6a6d5c0229039b25326ae1a61c93035f68c389ab2e88e8dce09b2f55d9291e6e640d411a543f5e97fa50eee2c10aedaf5fb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "0502fd59c54a710da5a6c4060d3573de3ad4c9a5a570722f95ccef846e5c7a574c8bb772816a6e7dd5c56331af86139fe7fbf3d7a3fb1c44c9d8579094c622b061060ef1f3dcd77163932ee6fe66af70d854e31ecfc086979416cf3e193c5dcd19ec1a9933aac0c04964981e4f76169a937bf9a454d9ca413d6a1097dee798a5f60a20b0643acb48c7514f026a9219a8d7aee6087584ac33a8c52af289699e604f2659bd7fbb45342cc3be9e7fe7564fa0332e5c2233daa9472f59d59f38369c1d153cee628fd5ba511c0f5df6deface8ad81a2864d403273175db913047b80556da8ef76e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "3d7eb388c75f23aa5a413c1aea1fcb3ba1d76123bc1834b5b973b385aa12eb0041ab55f571c7432287786ddae33539ca8777250f7f1960c973d7afbf561c274104f3c4cc033cab139247e43d98a5c814076482fe829e2eee0e302b3265676fdc82cf921935d19161ae814394cda9818f8e7c2bb4c56565790fffefa9ba86ab35816daa9bcb35f11e72637e7a6b127d084057906035914ff0ae08f71b601d755371171d249c7f87586e53cef8e175fb6312e8771ff5ead9a2f68050b8bf1add0aea7a3cd2f6d18eea57c6a7a13918cf7ebeb21113d09ce9c7a641a34b8ac22c9c164e9729ffda" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "a2a3b9a7c7f17ed8c51f8437c92e8918d0102f320227682192479a094a0cd6401d689a24f0f1f0ec7ccd7d5343391a7ef7590db47c83da0b43c133c673a679b49dacce5386a92c50880ff2803489a1ab8edf6212a155dfe8e3cdeff98cb145ddc1a9a1260385ffafb175e954d67eb5816c4da009df5a21b96a5cba8e77050220abd4f0b21f87fd44bf0354b9ea270cb8e428bd2d1822c8ae57256a413016b67894a3c38ef74bda287c2ee7aac2efbf244bea3dd1e9e94b0e1a5b18295f538253d7362e0bf0b5c090ca4b537e692bdb993e1225b23565cb281372f4d3a0ce247b96b1af1db06da1" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "42563ee8adfb99ea56890d94074a727c47d0aef5756145a92b1a41ae4cfeaa91351c88668afc1c4a715f35d265a36ffc103c5820098b13f0bb4ec0b761066aeb521a3b40dd40bacb45f58908cb2742e453c671754e85cfc43b12ac385dc1c72883260196658ae345ca16d16a08548fc8197709e3d026b7130bf6a0a74375dbfe619e64d35c2577f8e2d53eca56ae60d11551208ce41f95d19f789d909b4d9fcb52d289ed8862d5f1bfe5542b9fc68dd49d20f673b53a06e2ad6d74725e1180228a2dabf7f2089f4a974a22e91f3f413c2a4c18d7f5da95152a0338c3f406b71d760a9b2c32a5328b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "d699a03480c769b114056f7b8c1c2f4ea6013f785216a91ab9cf02df1a72625162c74979bfdbb938f76e0248f7a18c20dca243104aacefd8e8d2c9eba6ac0123f38fdc6ed1dadab1ed473097276f6c1a50d1d6fab39f2dfa8e78cc965d5875f73c703785c77e346c4ca551aa4ac0c25fd74567555209aa5bc7b7455a71f3d6cdc94a81297d1aa2901d2be9423f91e4d2c6977355910b0bb0dfad851e87bfca350e1406225dec1c514cfd2325411425c71dbfcacd4e21338980af552e5f833e4743a96130e71988005a26ecaeeac6abca9fe7aab0c8ff320ff135195532bde17cc5cc398476fa935597" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "cbc516abdb43cc8aa4d6e8c0dd28c4f8a1286d510a9ee9db7815814b635c6f17dbee4d4d18442d03faa7b21bc9756e7ab276f855d8780e2c35e0fdc4e6e1d2c7bdba75b3236e761289731461427e89ae9c36b815727740004c7aa565b9c8e52796a67a5be792c01365e6005d7bdaf71eeb26cbb67a2c503e978cc1469cf90cc5c67a0277eb78227c66c999fda6d87f6e2c8d69ca614f5335fb77333ad53bd64a904b9a588e99d5362b965fa509829bc88c5163f09ba40147e61834dab7316ff537eedbd207ab34c103c014048a33861e85d1e5384145a002b0d21cc0dcbb55ef3ebe8c595dcb910ec06e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "e63a2558d900ebbee7ecf56cfd1a20b7ed133c1476f9504fa814917cbd3057c729e38284cacdf8c6e65387be06664ffbd5dba5523186a05231c377b26ad453b8ffba3439d44ea10e4a12ab7038da3c734927d88769a00ec15d39dd2d7d2ac8bef814d06bcbf804889ef46d2ed58bfe2d0bc4a9bf10594f3c4244f7460f40eb1df72d80ef4c20ea18c2af5a059ade20d634e3d0f184a6d025ce40759ddb4de99746cbe4afe858893c2a5c2f51c19e47e2b2a36c7efef85ac7bbe63657253a2ebc0915f09f288d7c2030f24c923dfd0f29b66f8ebfdf3cfbb6f551ba7d83c068ba8144e566df37b64edbf111" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c12bc01a2001cca9b3b2f8aa048c86a70fb6f9c0f03ee16e0dff7154d5989c0f22e0d5db0c05a0a24f85e89e1bf1c1c49a7343158fa5827a3031fad7a3b62cf69a24f9d6541984c498b758a70a91576c0209be7f83ff47b3788de21ccb1f2c5dde0d654b92ce5d6c4da20f0904a453d2dbb2f84b43ff4d8ae84432d896bf07ee1047af1a942c5e2576917a279846451e1ab36843ff1c7fee1202e1ff7d4fb14788bf4ddd7bdc050048d73d2375440575b04c83127a5a4189b926f777f24d9abe76270c4f1c64a3f9da133180a8f6f88f423134ecf7b49df41c57b6c736bcb2c896f754dbc07f6b4fc807f047" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "df5437f55443ccd7676aa471db84da24295903a87f02dd95e23aa468f6fd60be2e96d1d4366e2bb831c0f396b9b92328baaf45641a1c19339b768021f6aa823c953fefc56e7dd15805f4a3c0f83f9a21b5b3a7f81591febc8f0b1614813cc4b09df3a67dc11cb3d0f4d0399101da60b7986c1b7af3d19afa3a245a6c457332caa28e4c87be2596b6662992631d6ea8361c44f7b5f0ae991951b18fa187de224966fd074e2add2cd4e442ab18118737b75751c32b5c14afaf06318c2011b08e62c5c2bb35e48ab946a59be2ba6dadb3dc0e94b69ed0de84f02d6b5c61ffd4bc42cbf393b51760583477946b5417" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "491baaaf3061239f157fb02dda59e76f995c710d6170179821aa556264dd237e2eeb3c1b51efb94623e5603a0f0d3f0cce2b5ace1108e5c1f1edb359f5e1d65de4c99f1f48cca747adc58786515b955f65177e36f4f5c7fc696146fd4e7f7b9cb38c81b215fe08b6f034710cf9076b29dad70f8795bdb89bf4688c020fd2362feb2b6876fbdc9cf0edd250709cc7d059870f080ba9899f977007110274ebac11373578d11c93b1ff5872253aa395b1bd0b4e9da71c273dfd8c98c46d65d692c688adbd656bbcadd4ad4a5531e5ea96728afd25da0ea6c3b472bd5924aaff2b0e26ec6e0f0496f1cdd8c3c8cb34b4" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "39d12b605a6241a2a239a9cfa9936556b2d6f8d961b6165425f0a9b8c63940db014e41ad93aa9a94e68517a7553a4979a58eb24238eef54baea5384836be636b9953893114830467065ecb7b5d8b53fe8d861001f3c16e616cc5cbe0650942b40b068dc6740ba40684f837685f0581d699ec34226967223228bb73f5449d933c2fd7577b4f5feb3c98c5cc890c86e56e666b135c9ac46ca67f0ef5f4f5516beb221006b38bb37c1e8df9b549a5ba128fe168b83752c588d0ff9ddf725d31431f0ae085b5dd9f251124e0d575f9f79b6d2c28ba8d5c79a7d106c2617f77863a95fce0ff9962e6a21c4c00647ba27e8f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c0ef3d806481d316ab62e4a75d42256f653138e6bfbfb42c398e88ee6f3d5ee2e85c5f6d407196718cda38c890111f2ca41a20238fe78903b1071591916b964e1cb15e1c357cd0f2c30aebf03a3662e14cbc1cd5bd4d58cf0054960edb9f091e3f4ed6c11a87fcdfdd84b8f5ca3ad8f1e4e5f06efd9594e1c5e5240ac9a8a373e140850d6b4eb4df20da33ce768b46a645fd73ec0fde5b799d548a12be5452492e46dba3da03fccce0cd3666ce88373ed07633024f29dc883c16245f8992b0b134e5461ad8def4922b4911e526f3e3c72b121fec0318369d1a40a4fadfa5078585494d3926b7ec6fc522fc85e3eec7aa" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "d9c78eb756dc9335fed007b1156ee7d89356291bd1808b025b7ac3bdaac8597c2a68f3d99890c04578ada7fad23125dc1fdee6e183f17c332882979913fd2610352e61f4f1b6e3c711907f4c6b5ecdd5ab5659b9788ab98e734455ba2a564215c7cd147a838e4ee02f4f35fdeb38706e64d23b8dfe3a58b0e1fa76c63038dc6aae308896bf52b9f851b76f3760f808b00e17442328f78287161dc283affb00862dd500140b86ca787bd58fd20f8425d2b5735467f723db7a0f9d1d08800ec395078a5470670056013ee95d7e59eee510fa23fe899a59594a3f823a1d62017a03bf464135c6b71f405e774c25563218b45f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "fb4504919408017da6d8a0622f6e95b9ed6b14db7841bd44f046eef98bf26bc834ecb3f4b7628ba3a53fc4d75075a25bfdc8536d014a185c0087fca9e011efe29e794b0e02719b617470fff50b02562a521e6c109a6cc183d74ab70b60ff1326255f8de02307cae03ff1bf49a771b5b311daa67cd4131004b2a1efaccd1d157c468637ea400caa891a531261b32f0fc61b241ff0fb8d1e8cf90703f80945a50dbf8edd650d43dd1c19dd4bcfdc202812f7dd5fe7d66dd39b3a9be37ecbfe1d0b3609c79cb19e49cafac783f02b9815912619cb3ccf8aaa47362bbb98f21fb48f61dfbe20d48b281fac8263b84b7c472b1719" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "0c317a9baf295d07e050e015a73f8827778973d924707c71aac3edf5e0f13bb51ad4f391b56d9b6dc204bbfc71d091d274fbb21e38317b7844a5e1cd58225279471401512a874ce6da69b364e2bad389069892057eba683f55b97ca4d18febda810eced644b6475fb00b64a4d86e81ba344a41b8b120eb63b047a45c9251c396448b07afa0315e062f40c430cae51448eaed7946cc58c7ff05917b564e6e4f99d1522be04d235659b3dc1e3f7ab0e65a5bb1cc3d26c1589e8532cb361f6bf2ef0b6b27e57569030db4e543a684c17db3dfc6bdb984834d842fd3642412ff88453d78dbd0cfd3b0771b6c0fb7ee38261cd1d103" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "3edf5d417a0d1a38a3a57e5265eb8df1542e25d90cd64292ab63713cb4a75b9c94850978fe2bd2f96f160b61c51d62eb2092d19b70c4448c2900f57f861f34425e2af6fd060c94f237fd4cccb745bee2bc47d0b4d5d8a57bd612af6109f5bb9a964bb4a6360371bec3bf851c269aad8d0f191eb7a9b77a1e98bc096a9b5586252526508a1c25cc1f6b0c1333f97c86a8799ad2ef8aa123400aa8741fe6277a2b92a6c4d4edaadc7fcae7953fbdf5ef1b499f871f66809b0d72c9b03e9b49cd5b8a91dc1c749fada0d9a4595d085f4b3e7643e239689c87a73455b31c9c5a6e0b899934408edc0dab175ce25c659c238b69e9ebbe" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "80f4ea817d4649de3f998374e11c9b41c3db5a5ac86b53031abab352171f46b893592ac5650a5218f7e54964b962b297079751c1d82bfbb9333fac445067a04473d26cf96a71c0c8092a8571d91f4413bfef40807206584d04928a5243f5ecec60e42aa3e0c83a28c8df71075d9a52ffd3519d5e40a0b20d4f4d1b21c695a249b5509a540cc0360d2906d6fddb6fa327beb9b087b1ad4d40ad435a2d589406369e7655dbd6d4f6ea340e35301b4bc02ac03ca85e55c8e50dff67718a9c1aedb6a0334bdc99f6c8b4dd52996bfd8dfca840c10aa92f6cf9d84c3994f5719fbc8d6a9592ffdada572d32aef67a9d7f9c897e08a197cb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "32d5d8e29fe1b68a49a30ef65787bf1ce003534891700ca2efe6dc4ce4b8770857130cad694451c148ed276c6843cc92597b3cd0129a043cd2d0803d82dda405b4151c5b4121bc276540c1723f4ce0f490d5ba0a4bff3a92117898d6ec362cbabd34052b6f82633f059a9f7948b46ab11cbe78d23f5a4828dfff412acf333a21cca6aacf570348a12a44c2939d360099234c2a68aff2bfc7e6fa0af55fbecbcb7d5d581a133bc46af75437147bdc42bd2cc0769098953655b2a41b5fec382ce63820ff4a447c7f62c825e68628279b8da57071a0c0a187943cfe5ac99e8447c3cb565973642115bf78cab6884cacd202d5c086ff09a5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "2042c8097d147442b9e0787ad9efc72f0b351bcbc3e4037556a82e29a6f0015f0c8e162513c6529fcb5e1e790c789c0022e34ec0541128ee07f3597062ca54e4bc9ac6566861d0d3e93212c229a318b379f03e480776b0c57dc0053535d3c94ebe54887fd89212bc3f1814eccbe00918049f17b9db59aea0e5cba970ec6bae937cd059d0eacd3bffaa19dc1ebf5f5cd90681effe1eff986754b80c5817589abf4ca404bce5ccaa066c4753494b8620e0a796f7892c6ee8c62a44a9b40f7a098d344f09b45134583f860a3b59621aa31b96e094713406674a9974df69d206eb8efaffc9b7feda8ae5757406e5278873d68114e11dc57ee3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "32217f6690884421cd6b0cb94884511ed0047b3a317cd2ff899b2dc866ece06ae9473018019124ab7f91918b9410a67f411ec349182c7f9dea73fad0152716d8f9910496e83fd50c56c93d5b088548071d65eae370722ac87178e62126f3a702ad323bac48bd7c238d65033c76187baabd952d6008723ecc4f492ca401b85fade1b219b31c6ede814e0ae35e1977ffd7b3b8c3b3474a3465a860ea7f27ee4b92852b09e4343772272deb760621bac6beb48143013dbe1c7ff1b7ff51cf66d02bd59e76604ad8b3374c688a05843f8af5e66465d5b5b738712e809d87587468c970e6239594720f1200b084fdd0829f282912a86d1c6360dd" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "da4830165af94ace9b01248bf2c373911096ebd83129cf6f454128c41efce7fea91156ab30a74a521e533b3ddb21b4a48de883c0ba7028420a128b3ead0a0d15d42766ce4d0607413cce1f947fa25f4a5ba29573554e68e005978d3b14ac0216ada50e02964759625bb313926f5ee7369fb3d4f50ab7e20244d2930d7f0113a44dd4b3edee72c15d57224d24b9fe9d9c1df2ef77f7566b18b6fcbb1f550f7717d4cf50b6666da197bfe2f4c3c23fe7d1ff6f770711dcc54ef9231bfa6ff455f859fb4be342e33a623723f17976f7b014ff8f50bfd2a687622dccf55e724d17337c65a1ef721c9ae68aece4906387078f058809e2a139e9755d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "1017ee9edb76500379a9eb1011cdfdb02cba68c53e47dcb2a2e29075c1b275f6a60782257b69e23e92563e8e6ef00bd99b5eac94ec223279e18422af405b0708689e8e3ae56044286c80f4de21474b4d0f8a5e525ed4394dd285abc592fd52410893a4f5b695ec9015bb3e95d9b8905ee6357122020729177042dd1b1a36f3fb33f992d4abbee44753c0d911745a186db1dfbfada785e5cfdb119217107f51e33858ddc5cfc97bafb75d838baf5e7407176db5080dfd3f4417221f0d1673db79289f16cac33e1be977f75a699658a965bb4730118202eabe34486f35664eec62610260014755d2704339ce611e759eae087b9b9ffe237bb8e88d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "5fb36a00c95a45ec6e7526c2a35189980e231aa36c2c8d6a9ccf288abe52ff56f77f01a0303d267fbed331bde0c30555e0f5a298b148fece91d802e3c33c233b535e37caef41ce16ab5df52070fdc3bcff00aefc15a552b0760769011e81aa70fb5740a3a568a15b5f72bc70564630209c5356dee3e49b1e089d97d9137f33653d81758f0a38aa53913753b5703249b5bcdd0104c86998d815951d5d0ec94685dbcf98e7fdbeae10361e9522fe87ba60c49fa6290503016cfd85a478a91fc70e9d43075b167058f1589b194296c750c6693f9dc245e9b21a483975ada00217166189b99b6c56357886e9a8063da35e9d20db24002ed36edbbd1981" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "c6942d36146678f56f4f8cec34f97448aeaeab84424cc0ea957292227287ffa954d5186f3e133eddd0d460c741dfc104f0015165e5efb7ee33043b97e55b2995b7887c49a5df5546459f445819a55edee3fc39743352b5b197095787710dd55b11f88d1155b051b97918885916a59dc8d64dc31c2e1eebd3995bf144c86849b992a35be67fa30bbba18a565b1aae21ad2738236014cbde288ecfcb910a7edbf33d41bf59fd81675a8fc0f3dce569d0662d6d565e8bcccb8528328aa75bc98e09163be1ff113af4d7e4dd514ead744117754e54b4bc85c194c2f074d3d27033011c66beb70e984ef7b675b70a9eb73a3dc0c3d626bba33a87cde4dd68" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "55f5d8c7a4fb578ae7f02e9d627b5ec4e6279aaeb1791be6a030e00f3f715eff486affd8539d41fd7517588cb6a08dc77c0a3d2ad6be11492cc950d44137c3209177ca50e5a48073a85ecac000fee2cc97c81ea4c82f9ddaec4ec479219ceffa06052d6c0fd57044b7c69c07b6c361269aa6e2fd6dec3d93cef32cd8a698af82f676f211053787b69194552d03d3db7ddc508efb6336f17541d7c18b18e93854d24644ca999495e8b321303b8dfe9eb430d251ee9e265dc838b1d201f84018fb89cca117954c7c059927e5eb8ab54afe5caf720292edfc003959fd93f945dabae0c3d56edd430894c103f579a048ba0c097a17fb4954df8acaa46026b5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "7c4634ca8c596c5f3003986ef7a26bbae711327cc9ea020b546755ebe23e4997731fc1a9760de9e44529a8d671f99f567db7aba5d8b594ae35a61bb585cd2a950f6c216f3173614b1f96ac120085f79106732e7bb55edbfe1b525c23e4dbb117a23517ac4a89cd3d09a39b421ac1bf3f83ea763c272f3f653c3c3807130d6a998394359bc5f51047c46f77af1c738b363cd243c10d1c7a0d9db55d8e14c91bced77065d0a5c21061d181ef6fab35218aeb065b49630b9e3b29ca1d64fe21ddd2b906d9a9421eca770639084e97ca4b04cbd522a355f7e30465219a5ac869003f5c5d40401d5e049a9737081effda31c6ea9e6aaf4205c85470d5a2ca2d37" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "2953a3385e63c8bc7bf7f441756deedf21f7620528ded82100ee0639658c6b973ee4878b1ed8c7a9a755b2aefaf010855c64933c578cdf5d9b93f991ea044ff020662757901c1b6014f354f061f7274c2d912eae78601944be200be650a869219a9f67890f5d6a48ab799c3676b24009642690105b20e034c6632b36956e43d049b306b0a596d0ecc0e79cb1ff11824ea31e8d023bba757bf2597bc58e83076e1c45b2f0e9b72fa93f4423589401efa4916d2f9a82833f44e2866bcbb222ddec1b5a70ac5f78716e4389e566dff0e9c1b510eae7a3106c47eb60b8b5bab89acbe46c055a7554bb1cdfa485a891c3b548c7a5f1d38c03cdfefa5ead65031ea4" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "", + "d4a23a17b657fa3ddc2df61eefce362f048b9dd156809062997ab9d5b1fb26b8542b1a638f517fcbad72a6fb23de0754db7bb488b75c12ac826dcced9806d7873e6b31922097ef7b42506275ccc54caf86918f9d1c6cdb9bad2bacf123c0380b2e5dc3e98de83a159ee9e10a8444832c371e5b72039b31c38621261aa04d8271598b17dba0d28c20d1858d879038485ab069bdb58733b5495f934889658ae81b7536bcf601cfcc572060863c1ff2202d2ea84c800482dbe777335002204b7c1f70133e4d8a6b7516c66bb433ad31030a7a9a9a6b9ea69890aa40662d908a5acfe8328802595f0284c51a000ce274a985823de9ee74250063a879a3787fca23a6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "0e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "5196" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ad6bad" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "d8e4b32f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "8eb89056f3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "410497c2ed72" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f0de771b375c90" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "8662db8685033611" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "9ef9f1eed88a3f52ca" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "08225082df0d2b0a815e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "0f6e84a17439f1bc97c299" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "895ec39c78d3556cefdbfabc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "2b396b3fa90ab556079a79b44d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "abae26501c4c1d6123c0f2289111" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "bca098df9099b3f785a37ba40fce5f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "19b827f054b67a120f11efb0d690be70" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "b88d32a338fd60b58570fda228a121113b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3f30143af1cad33f9b794576e078cc79062e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ffddb58d9aa8d38086fcdae07e6653e8f31dfc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "abb99c2e74a74556919040ca0cd857c95ec985e9" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "71f13f89af55ba936f8a7188ee93d2e8fb0cf2a720" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "99734fdf0eef4838a7515426f4c59b800854e2fcdc1c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "579b1652aa1f5779d2b0e61868af856855020bdd44d7a7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1383d4ab4a6d8672b4075d421a159f69380ff47e4bb518d5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "d3fa1412712dbbab71d4c6265dc1585c8dcc73380cf807f76a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1d57868a71e7245667780455d9aaa9e0683baf08fbaf946091c2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ef80418fe7049c6251ed7960a6b0e9def0da2749781994b24593a0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ef91cb81e4bfb50231e89475e251e2ef2fde59357551cd227588b63f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "d7f398a5d21c3139cff0562a84f154b6953c7bc18a5f4b60491c196b6d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "0a2abc6d38f30aef253579a4088c5b9aec64391f37d576eb06a300c193a5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "02dd758fa23113a14fd94830e50e0f6b86faec4e551e808b0ca8d00fef2a15" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "a4fe2bd0f96a215fa7164ae1a405f4030a586c12b0c29806a099d7d7fdd8dd72" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "7dce710a20f42ab687ec6ea83b53faaa418229ce0d5a2ff2a5e66defb0b65c03c9" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "0320c40b5eea641d0bc25420b7545ac1d796b61563728a4dc451207f1addeedcf860" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "460539415f2baeb626fad748dee0eb3e9f27221661160e13edf39d1b5d476ee0672400" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "02de8ffa5b9c748164f99ed9d678b02e53f4ae88fb26c6d94a8cefc328725a692eae78c2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "348a61a0136436136910262ad67ef20644b32c15456d5fad6b1679386d0bea87cc1a2e2b5e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "24c32966c803434d48d2283482ee8f404f598cf7a17961748125d2ed1da987039b1ce00f2ba7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "bd07cb16121d3b47adf03b96c41c947beadc01e40548e0d0773e61780d48d33a0e2a675ca681a6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "a35844e34c20b4b9371b6c52fac412afe5d80a4c1e40aa3a0e5a729dc3d41c2c3719d096f616f0ba" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "6df1efbb4567747fe98d218935612f8835852dde2ce3dec767792d7f1d876cdae0056fef085245449d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "48d6094af78bd38d8f4b39c54279b80ef617bc6ad21def0b2c62113b656c5d6a55aea2e3fde94a254b92" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "cd6e684759d2f19083164712c2aca0038442efb5b646594396b1fccdbd21203290f44cfdecca0373b3801b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "155dfbf26103c8354362663677fa27d0e1ce3487a821a2a7171014c1bd5dd071f4974df272b1374765b8f2e1" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "15b11067f311efa4ee813dbca48d690dc92780656bc4d4c56510523190a240180867c829a8b8b9844175a8aa23" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "9bc27953a17fb84d5eabe95b4ea6bc03ea450274abccfb6f3938ded8560fb59662459a11a86b0e0f32fbea6bb1f8" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "03b78fb0b34fb8662accdf350a6be75ace9789653ee4375d351e871f6a98ac5e782ca4b4a717665d25e49a5ae25d81" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "687e9a6fda6e2ce0e40e4d30fef38c31e3513d2892bbe85c991fc3715947e42bc49bcd079a40ed061c2c3665efe555ab" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f3886027d2049a8909e26545bd202d6a6fa2a6f815d31c7d520f705a81fa606dd695369c37aee4fa77dc645e9b05813ceb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "e4a412ccd20b97797d91ccc286904fcd17c5afe8bed0618f1af333c052c473cd327637d951c32e4af047106036a3bc8c1c45" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "92f4b8c240a28b6238bc2eabadaf2ff3c4bfe0e6c61268ace6aebdeb0691450caea4287db8b329bde96af8cdb8a0fe2f57ef2d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "e506834b3445e1a9a9b7bae844e91e0834512a06c0dc75fa4604e3b903c4e23616f2e0c78b5cc496660b4a13064bb1138edef4ff" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "27031955a40d8dbd1591f26e3c26e367a3c68f8204a396c6a4ba34b89672896d11276966a42bd516716f35ed63e442e116dbcf35da" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "646b1635c68d2328dddd5ac26eb9877c24c28390a45753a65044c3136ae2fe4fb40d09bf555271646d3dceb1ab1b7c8d8e421f553f94" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f6171f8d833743bdee7cc8f8b29c38614e1d2d8d6a5fff68bec2c0f4dd463d7941ff5c368e2683d8f1dc97119bde2b73ca412718bc8cb1" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "45db1c478b040aa2e23fb4427017079810775c62abe737e82ec0ef8dcd0fc51f521f29fe6412fff7eac9beb7bcf75f483f3f8b971e42454b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "500dab14687db3ca3dde9304af5f54194b37bdf475628af46b07bfbf6bc2b64ecef284b17f9d1d9be41794699bc0e76c2878b3a55730f7142d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "31bba2efc7b3f415c3f031d4c06bb590ae40085ad157370af30238e03e25a359c9e133212ed34b7a006f839173b577e7015a87fdff2270fafddb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "0600b3fb4b5e1ed0c8b2698ac1d9905e67e027390764821f963ad8d2b33cbc378b9c25c3ee422992d22b760222ed5697be0576d73938ae9d634ed7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "4c0ca4f177d132594a4c613bad68da24c564efa3b4da0d0a903f26534a2e09f8d799d10e78f48ccdb0203954a36c5cf1bf24c076632c2b022b041200" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "97aacf2e1b013677b2e14084f097cb1e64d7b3fa36f097e189d86dc4a263bcc46817cd1ee6ff0c7ccd9acef63201cdc0e36254e19204a7388643bb571f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "71fd6846ce7adb0843d6063546a16b79b54ad6c0f018a479a45817624fa221f63525084860559d1a0679c8d89a80701c62743ec2da8419d503f8f0cd7946" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f73dfb046def3362d6de36077dae2cee2587fe95fe0800548bb7d99737897096ba59052e0dadcc1fb0ccb5535391875328637a0376a43a4d89366758dfe3e2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ec470d0aa932c78c5bcf86203ec0014314114765fa679c3daef214f883a17e1b4ca12f44433772a6e4ef685c904b2fc35586c6bd88f325b965968b06d808d73f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "cf601753ffa09fe48a8a84c37769991e96290e200bbaf1910c57760f989bd0c72e6128e294528ee861ad7eee70d589de3cf4a0c35f7197e1925a64d0133628d87d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f15413f7d6fc54bb55829f698da92ee42fcf58dde1aa1bd07d438ecdc32ad6bf2bcdbecc99f18ed43e81b33065af5a4ca29960ae50553e610c0bbf4153d580e73dbb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "84b1738adb9757fb9402ef7113581291136184d7ae35fe0b6a738da6acb0889d4d5bac7a957024e3709fa80c77d3859871ed1aa25cf488e438a2d24cfadce6008761dd" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "e02814bb81f250c1835a05108396b74c7878e737654bb83155e241774d04e639bbc571b413cd9349092f926c8a149a53cd33e9b63f370b6d460e504199d2e7d849db6cbe" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "aeee4a789956ec0913592c30ce4f9c544894da77ba447c84df3be2c869100e4df8f7e316445d844b31c3209abcc912f647735fd4a7136c2f35c6fda5b2e6708f5ca951b2b0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "8cfd11ca385de3c843de84c830d59278fe79b70fb5ddbfbfc1ddefeb22c329ef2f607d1d1abbd1cd0d0cc7c5d3ed922add76aadca0d2f57b66cb16c582b6f18f60aee2f7509b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "852e5ce2047d8d8b42b4c7e4987b95d23e8026a202d4567951bbbd23111e389fe33a736318546a914d2bddedfbf53846036ad9e35f29318b1f96e33eba08f071d6dc665149feb6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f225c23164979d0d13874a90ee291627e4f61a672a5578506fd3d65a12cb48a182f78350dc24c637b2f3950dc4882a5c1d5d5bad551c6f3e0093aa87e962bea51566af3791d52d65" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "5f33864d882455f8ef046aed64e2d1691e5c1555e333b0852750592e6f00d3b5ec941d0c00e99629612795d5870cf93c984b45e4464ba072a34903b400a42824ac13da28c7c1cb1959" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "7baaee7c3eb68c18c5ae1d45ba381803de34e36a52e2d7ccc9d48a297273c4d8644b473195bc23005f7a4f5ca790b1fa11f6a96e585e635513f11745dd97a69c1222204ab28d3c7735df" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "d0a2a3fc450ef9af7ae982041feb2842901026467d87839c33b4a9e081ea63d5be60ae99ca6e42393ded45255b8f42886f87ba0310572d9f0d8b5a07ff4b6bae1f30559a844983cc568560" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3aa4164462b3e7044c35b08b047b924790f6d5c520b1df4305b5d41f4717e81f0cd4bccb9a5a6594773832b8707443adde4047caaed2293f92234df257df54ed275a9658fab483d0576d33a9" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c8b4239fd7f1b893d978268f77f6505b5775d89090374322d40083b0f4c437423f670ca213f7fe05c61069725da2561646eefaea597ac48e293fbad44c2872046857e56d04a426a84008cefd71" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f94839a7024c0a16971271b6727c081770110c957b1f2e03be03d2200b565cf8240f2873b0426042aaea996a1784fadb2b27f23bc1a521b4f7320dfbed86cd38d75141365ba9b443defc0a3b4078" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "8af934fdc8b3376ca09bdd89f9057ed38b656bff96a8f8a3038d456a265689ca32036670cb01469cc6e958cc4a46f1e80d700ae56659828a65c0456b8e55f28f255bc86ce48e44377bf1f9970b617d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ada572989e42f0e38c1f7c22b46bb52a84df8f7b3b773c9f17a5823e59a9725248d703efb4cb011abc9474e8e711666ed3cfa60db48480a8160615dfabad761bc0eb843d2e46299c59b61a15b4422fdf" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "b11f1ea52a7e4bd2a5cf1e234b7c9eb909fb45860080f0a6bdb5517a37b5b7cd90f3a9e2297f995e96c293189b807a7bf6e7633bebbc36674544db5f18dd33020aeaf50ee832efe4d3d053873fd31ce3b9" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "e54b006cd96c43d19787c1ab1e08ea0f8922bdb7142e748212e7912a1f2c0a4fad1b9f5209c30960b8b83ef4960e929b155a8a48c8fb7ce4326915950cede6b98a96b6f1ecb12715b713985dacd1c1180413" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ee2c2f31a414ccd8f6a790f55e09155fd50aac2a878f9014f6c6035cae9186f90cdef0b7adf3e207c3d24ddfba8cd321b2e9228b02a1182b6973da6698071fce8cc0a23a7bf0d5aefd21ab1b8dc7818549bba3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "6d6810793bad6c7efe8fd56cac04a0fb8717a44c09cbfaebce196a80ac318c79ca5c2db54fee8191ee2d305b690a92bd9e2c947a3c29342a93ac05796484638787a184e4525e82aeb9afa2f9480caebb91014c51" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "91e4694366cff84854872667fd168d2d42eca9070cdc92fca9936e8361e7266931f418450d098a42686241d08024dd72f0024d22ba644bd414245e78608942321ff61860ba1245f83c88592dc7995c49c0c53aa8a9" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "608aa620a5cf145f4477694407ccd8faa3182465b29ae98d96a42f7409434c21e4671bcae079f6871a09d8f2965e4926a9b08277d32f9dd6a474e3a9fb232f27fc4235df9c02abf67f7e540ca9ddc270ee91b23a5b57" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c14f75e92f75f4356ab01c8792af13383e7fef2ffb3064de55e8da0a50511fea364ccd8140134872adccad197228319260a7b77b67a39677a0dcdcadfb750333ac8e032121e278bdcdbed5e452dae0416011186d9ebf29" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "03fcb9f6e1f058091b11351e775184ff2cd1f31ee846c6ea8efd49dd344f4af473f92eb44eba8a019776f77bb24e294aa9f962b39feecf7c59d46f1a606f89b1e81c2715ac9aa252e9ce941d091ffb99bb52404961794cf8" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "11e189b1d90fcfe8111c79c5351d826f5ec15a602af3b71d50bc7ed813f36c9a682520984ae911669d3c3036223a53176794c7e17929efab2b1c5b500f24f8c83d3db5d1029c5714c6fd34eb800a913985c218071677b9885c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "69f8f5db3ab0321a708ab2f4234645dade6bfda495851dbe7257f2b72e3e8378b9fa8120bc836b737a675271e519b4712d2b56b359e0f2234ba7552dd4828b939e0542e729878ac1f81b6ce14cb573e76af3a6aa227f95b2350e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "be734d78fae92cacb009cc400e023086bc3a3a10e8ca7cb4d553ea85314f51383660b8508e8477af60baf7e07c04cc9e094690ae12c73e5f089763201b4b48d664b94b4f5820bd1540f4a84100fdf8fce7f6466aa5d5c34fcbab45" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "d61b77032403f9b6ea5ad2b760eb0157545e37f1712ec44d7926ccf130e8fc0fe8e9b15570a6214c3899a074811486182b250dc97ebdd3b61403614d935cd0a61c0899f31b0e49b81c8a9a4fe8409822c470aacfde229d965dd62f51" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c31bd548e36d5fae95ed8fa6e807642711c897f0fcc3b0d00bd317ed2bca73412064618c6a84a61c71bce3e963333b0266a5656571dcc4ba8a8c9d84af4bdb445c34a7aef445b15d77698e0b13c436c928cc7fa7acd5f68867e8132993" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "9903b8adab803d085b634bfae2e109dd247a7d6249f203403216d9f7410c36142df8fa56fb4d6f78136eef5817bad5ea3608439bb19336628c37d42db16ab2df8018b773baedafb77278a50926370b48bd81710203c7abc7b4043f9a1751" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "4dadaf0d6a96022c8ce40d48f460526d9956da33260e1770315ead420da75b122c762762aa3ddc1aef9070ff2298b2304cf90443318b17183b60778f3859b141053e5827decfff27ff106a48cfdb0371d0ef614fc7400e860b676df3176d1a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "314dda800f2f494ca9c9678f178940d2284cb29c51cb01ca2019a9bede0cdc50f8ecf2a77e238b884867e78e691461a66100b38f374c4ccac80309641533a3217eca7e6b9a9af01c026201f0afaec5a61629a59eb530c3cb81934b0cb5b45eae" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "4658b7500951f75c84e4509d74047ca621009835c0152f03c9f96ca73beb29608c44390ba4473323e621284be872bdb72175628780113e470036265d11dfcb284ac04604e667f1e4c1d357a411d3100d4d9f84a14a6fabd1e3f4de0ac81af50179" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "491f877592837e7912f16b73ee1fb06f4633d854a5723e156978f48ec48fbd8b5e863c24d838ff95fa865155d07e5513df42c8bb7706f8e3806b705866475c0ac04bbe5aa4b91b7dc373e82153483b1b03304a1a791b058926c1becd069509cbf46e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "231034720c719ab31f7c146a702a971f5943b70086b80a2a3eb928fa9380b7a1ad8773bfd0739142d2ad6e19819765ca54f92db5f16c1df5fa4b445c266215a92527bd4ef50ed277b9a21aee3fb7a8128c14ce084f53eac878a7a660b7c011eb1a33c5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3366860c77804fe0b4f368b02bb5b0d150821d957e3ba37842da9fc8d336e9d702c8446ecafbd19d79b868702f32405853bc17695873a7306e0ce4573cd9ac0b7fc7dd35534d7635198d152a1802f7d8d6a4bb07600fcdaacfaa1c3f40a09bc02e974c99" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ccbbbe621f910a95835f5f8d74b21e13f8a4b03f72f91f37b5c7e995aa3cd5539508d5e234e77a4668a42c239b2d13ef0e55ecf85142055e3f8a7e46320e21324a6b88e6c823ac04b485125c2aa59b61476481208f92ea4dd330cb18777c1cf0df7cd07893" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "87faf0e49e7e5ab66ee3147921f8817867fe637d4ab694c33ee8009c759e7d707f44c69c1b9754e2b4f8f47b25f51cd01de7273f548f4952e8efc4d9044c6ea72d1d5857e0ffeb3f44b0c88cb67683401cfb2f1d17f0ca5696641bef28d7579f68d9d066d968" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "38c876a007ec727c92e2503990c4d9407cea2271026aee88cd7b16c4396f00cc4b760576adf2d683713a3f6063cc13ecd7e4f3b6148ad914ca89f34d1375aa4c8e2033f1315153189507bfd116b07fc4bc14f751bbbb0e752f621153ae8df4d68491a22430b309" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "87d636a33dbd9ad81ecd6f3569e418bf8a972f97c5644787b99c361195231a72455a121dd7b3254d6ff80101a0a1e2b1eb1ca4866bd23063fe007310c88c4a2ab3b49f14755cd0ee0e5ffa2fd0d2c0ea41d89e67a27a8f6c94b134ba8d361491b3c20bacac3d226b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "b021af793badbb857f9a353e320450c44c1030fce3885e6b271bcc02e6af65fdc5be4dc483ff44bd5d539ed1e7eb7efe3001252e92a87df8227ace601047e101c871d29302b3cb6c6f4639078afc81c4c0f4c2e04688612ecf3f7be1d58ea92894a5dab49b949f2089" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c5c1f2fbf2c8504a686b615278fc6221858d401b7fe790b75fb6bca6885cdd128e9142bf925471ee126f9e62d984de1c30c9c677eff5fdbd5eb0fa4ef3bff6a831056cea20fd61cf44d56ffc5bda0e8472ecdc67946d63c40db4ba882bc4dfa16d8ddac600570b9b6bf3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "88f8cc0daeaeaea7ab0520a311dff91b1fd9a7a3ec778c333422c9f3eb0bc183acc80dfefb17a5ac5f95c490693c45666ec69234919b83244003191bad837aa2a237daeb427e07b9e7aa6ca94b1db03d54ee8f4fe8d0802cb14a6599005eb6326eefe5008d9098d40aa851" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "2eb6b1a58e7fe39ff915ac84c2f21a22432c4f0d260380a3f993310af048b11647f95d23adf8a746500833ee4e467fb52ea9f1039519fa58bcb0f1d0151558147b3c92b83730aba0e20eeeea2b75f3ff3ad79f2f8a46cbbadb114a52e32f018342aeeaf827e03ad6d583bbce" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3ba7dcd16a98be1df6b904457709b906cbf8d39516ef107006c0bf363db79f91aaae033466624d30858e61c2c368599963e49f22446e4473aa0df06e9c734e183a941510d540536377072334910e9cef56bc66c12df310ecd4b9dc14207439c1da0ac08bdd9be9f2c840df207e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "a34a7926324ea96867dac6f0dba51d753268e497b1c4f272918c7eb0e34120be65b7b5ba044d583141ec3ea16fcedae6197116b16562fb0706a89dc8efd3ba173ccd0fd7d84d480e0a3dda3b580c326aa1caca623879b0fb91e7d173998889da704eda6495023b5ad4c9ad406298" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "5ef97d80b90d5c716322d9ba645a0e1b7a403968258a7d43d310320f60f96235f50e9f22cac0ad239636521fa0607d2f471051b505b371d88778c46fe6787d47a91a5bec4e3900fe6ed22918226fc9fbb3f70ee733c369420612b76b5f55988d757c891d7005d17ee55783fe506202" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "140d2c08dae0553f6a49585fd5c217796279152b2e100ebde6812d6e5f6b862b2a3a484aed4d6226197e511be2d7f05f55a916e32534ddcb81bdcf499c3f44f526eb515cc3b6fa4c4039ad251253241f541558bba7413ca29318a414179048a054104e433c674ca2d4b3a4c181878727" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "29fdfc1e859b001ee104d107216b5299a792d26b2418e823e0381fa390380d654e4a0a0720ba5ff59b2ff22d8c4e013284f980911dcfec7f0dca2f89867f311ced1ac8a14d669ef1114504a5b7626f67b22ecd86469800f1575543b72ab1d4c5c10ee08f06159a4a3e1ae09937f12aa173" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "52dfb643832a598a10786a430fc484d6370a05356ee61c80a101dbbcfac75847fba78e27e537cc4eb918eb5ab40b968d0fb23506fee2ad37e12fb7534fb55a9e50902b69ceb78d51db449cbe2d1fc0a8c0022d8a82e2182b0a059035e5f6c4f4cc90278518e178becfbea814f317f9e7c051" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "d32f69c6a8ee00ca83b82eaf82e312fbb00d9b2f6202412a1ffc6890b4509bbbeda4c4a90e8f7bca37e7fd82bd23307e2342d27aa10039a83da55e84ce273822740510e4ec239d73c52b0cbc245ad523af961994f19db225212bf4cc160f68a84760233952a8e09f2c963be9bb1d71ca4bb265" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "d1e603a46aa49ee1a9ded63918f80feca5fc22fb45f659fd837ff79be5ad7faf0bbd9c4ba91628ee293b478a7e6a7bd433fa265c20e5941b9ea7edc906055ce9799cbb06d0b33ae7ed7f4b918cc082c3d4a1ac317a4acec175a73cc3eeb7cb97d96d24133a29c19375c57f3a4105519846dd14d4" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "b45ac88fac2e8d8f5a4a90930cd7523730733369af9e39bf1ffb833c01108952198301f4619f04b9c399fef04c214bad3358999967c474b67a7c06457a1d61f9466489ed5c0c64c6cdc83027386d6263491d18e81ae8d68ca4e396a71207adaaa60997d0dca867065e68852e6dba9669b62dc7672b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "d5f2893edd67f8a4b5245a616039ffe459d50e3d103ad4675102028f2c497ea69bf52fa62cd9e84f30ae2ea40449302932bbb0a5e426a054f166fdbe92c744314cc0a0aa58bbc3a8739f7e099961219ec208a8d01c1ae8a2a2b06534bf822aaa00ca96218e430f0389c69c7f3fd195e128c38d484ff6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "37279a76e79f33f8b52f29358841db9ec2e03cc86d09a335f5a35c0a31a1db3e9c4eb7b1d1b978332f47f8c3e5409d4e443e1d15342a316f442e3bfa151f6a0d216df2443d80cbcf12c101c51f2946d81161583218584640f4f9c10de3bb3f4772bd3a0f4a365f444777456b913592719818afb26472b6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "a46d252a0addf504ad2541e7d992cbed58a22ea5679980fb0df072d37540a77dd0a1448bdb7f172da7da19d6e4180a29356ecb2a8b5199b59a24e7028bb4521f3281313d2c00da9e1d284972ab6527066e9d508d68094c6aa03537226ef19c28d47f91dddebfcc796ec4221642ddf9de5b80b3b90c22d9e7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "060c18d8b57b5e6572dee194c69e265c2743a48d4185a802eaa8d4dbd4c66c9ff725c93667f1fb816418f18c5f9be55e38b7718a9250bc06284bd834c7bd6dfcd11a97c14779ac539629bcd6e15b5fca3466d14fe60d8671af0fb8b080218703bc1c21563b8f640fde0304a3f4aeb9ec0482f880b5be0daa74" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "8f2f42bc01acca20d36054ec81272da60580a9a5414697e0bdb4e44a4ab18b8e690c8056d32f6eaaf9ee08f3448f1f23b9844cf33fb4a93cba5e8157b00b2179d18b6aa7215ae4e9dc9ad52484ad4bfb3688fc80565ddb246dd6db8f0937e01b0d2f2e2a64ad87e03c2a4ad74af5ab97976379445b96404f1d71" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ccb9e524051cca0578aa1cb437116a01c400338f371f9e57525214ad5143b9c3416897eae8e584ce79347297071f67041f921cbc381c2be0b310b8004d039c7cc08cb8ff30ef83c3db413f3fb9c799e31cd930f64da1592ec980cc19830b2a448594cb12a61fc7a229e9c59fe1d66179772865894afd068f0942e5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3eb5dc42172022ab7d0bc465a3c725b2d82ee8d9844b396913ceb8a885323dbbbf9ef4ed549724cc96d451ea1d1d44a8175a75f2a7d44bb8bfc2c2dffed00db0328cfde52bf9171f4025770abbe59b3aefd8151c480bafa09f613955fd571e5d8c0d4936c670d182cf119c068d420ded12af694d63cd5aef2f4f6f71" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "20ea77e58e41337ad63f149ed962a8210b6efa3747fe9bea317c4b48f9641f7145b7906ed020a7ae7d2ee59435392edc32aee7eff978a661375af723fbd440dd84e4a152f2e6ef66f4ab1046b22c77ac52717de721dfe39aa8ba8cd5da27baca00cc1fffe12c52382f0ee83ad1418f4c6a122effaf7471e1e125d7e7ba" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "95c662b835171fa23f948c3c3ed27bab9b3c367bbfe267fe65f8037a35b50cd7fc6030bfce4000425ef646c34793f0762635ae70487a0216ef7428da622be895d1b6040423246511c2370d6876a5c5d2df8bbd48fb14f787b632ad2c1f5a927fdf36bc493c1c8606accfa52de33258669f7d2d73c9c81119591c8ea2b0ef" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f708a230675d83299cc43167a771602d52fa37cbc068ef9128ef60d186e5d98efb8c98798da619d2011bf4673214f4a4c82e4b11156f6292f6e676d5b84dc1b81e7cc811b0d37310ac58da1bfcb339f6ba689d80dd876b82d131e03f450c6c9f15c3a3b3d4db43c273c94ed1d1bd6d369c4d30256ff80ea626bda56a6b94ea" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f8417766ce86b275f2b7fec49da832ab9bf9cb6fdfe1b916979ae5b69176d7e0293f8d34cb55cf2b4264a8d671370cb595c419c1a3ce5b8afa642208481333522005fbe48cdc700e47b29254b79f685e1e91e7e34121784f53bd6a7d9fb6369571bba992c54316a54e309bbc2d488e9f4233d51d72a0dd8845772377f2c0feb9" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3479e04efa2318afc441931a7d0134abc2f04227239fa5a6ae40f25189da1f1f313732026631969d3761aea0c478528b129808955be429136eeff003779dd0b8757e3b802bdff0f5f957e19278eabad72764aa74d469231e935f4c80040462ab56094e4a69a82346b3aeb075e73a8e30318e46fdaec0a42f17ccf5b592fb800613" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "03df0e061fa2ae63b42f94a1ba387661760deaab3ec8ffabcaff20eeed8d0717d8d09a0eafd9bde04e97b9501ac0c6f4255331f787d16054873f0673a3b42ce23b75a3b38c1ebcc04306d086c57a79d6095d8ce78e082a66c9efca7c2650c1046c6e0bbce0b2cba27c3824333e50e046e2a7703d3328ab3b82c9d6a51bc99b9516ff" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "76b488b801932932beefffdd8c19cf5b4632306e69e37e6a837e9a20c8e073bcadd5640549faa4972ebd7ee55cb2425b74cb041a52dd401b1a531beb6dfb23c4cfe74bc84f034156c8f55050ca93236eb73c4e2595d9fbf93dc49e1ec9a31705359732dda73f737ec4274e5c82626dc4ec929e5e2c7a2f5f5fb666181922bd8be575e3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ff17f6ef13abc0426b03d309dc6e8eeb822300f7b87eff4f9c44140a424098fd2aef860e5646066d22f5e8ed1e82a459c9b9ad7b9d5978c29718e17bff4eeefd1a80ba48108b551e62cd8be919e29edea8fbd5a96dfc97d01058d226105cfcdec0fba5d70769039c77be10bd182bd67f431e4b48b3345f534f08a4beb49628515d3e0b67" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "95b9d7b5b88431445ec80df511d4d106db2da75a2ba201484f90699157e5954d31a19f34d8f11524c1dabd88b9c3adcdba0520b2bdc8485def670409d1cd3707ff5f3e9dffe1bca56a23f254bf24770e2e636755f215814c8e897a062fd84c9f3f3fd62d16c6672a2578db26f65851b2c9f50e0f42685733a12dd9828cee198eb7c835b066" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "010e2192db21f3d49f96ba542b9977588025d823fc941c1c02d982eae87fb58c200b70b88d41bbe8ab0b0e8d6e0f14f7da03fde25e10148887d698289d2f686fa1408501422e1250af6b63e8bb30aac23dcdec4bba9c517361dff6dff5e6c6d9adcf42e1606e451b0004de10d90f0aed30dd853a7143e9e3f9256a1e638793713013ebee79d5" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "02aaf6b569e8e5b703ff5f28ccb6b89bf879b7311ea7f1a25edd372db62de8e000219afc1ad67e7909cc2f7c714c6fc63ba341062cebf24780980899950afc35cef38086ee88991e3002ae17c07fd8a16a49a8a90fc5540be0956dff95390c3d37629949de99920d93096eb35cf0427f75a6561cf68326e129dbeffb8772bfdce245d320f922ae" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "70752b3f18713e2f533246a2a46e38a83cc36dfccec07c1030b5204cba4432700735a8cee538b078d281a2d0262110381c5815a112bb84404f55af91652bd17502dd75e4910e062943d8a736ae3eecdfdd8e3f83e0a5e2ddeeff0ccbdadaddc95391310fc657a59724f7e6560c37dc1d5bb5db40170190f04a274c864ade9687c0f6a2a48283177a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "01f3c1333b44077c518cc594d0fb90c37651fb7b2442e71fc0a5611097f1cf7bcfaf11c8e0ac1b1cab54afba15bb9332df6bc64d8032368e3f686c8324b0114e0979dad78a5ccd3fff88bbe89eef89c4be586ca092addef552ed33224e85d8c2f4fba85ac7735f34b6aa5ae5299154f861a9fb83046b0e8fca4db32c1343e02676f283975f43c086cf" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "509283ebc99ff8d87902fa00e2d2a6fa239e335fb840dbd0fdbab6ed2d95e8275402523f7ce9a2fabd4b6c9b533288fbe914bde84365a204711d0977a7d698f4614385984dd4c137e4820035dd6737da364edff1bb62283e87a8c7ae8637314fe9b5777ec4ec21276dafedb2ad5ee1aa0ac99e34a6c01c055c8a239fd28681607f65143082cd4553c529" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c17e417e876db4e123c631f7136b8a85bfd6ce66a69180d0cd5ecfd6f037bb1c7bd7908d51f2c485bf9e92c0e1799ee5f6ab834ee481f5eb1a8020205adb4d0f90126d4e7c2c859c5a5f644bdfa9c649ff4f168e834de6f9769429732099d46d0af506ab86c6fd92175159bbc05c75db8e1fa867e6030d64250008d64c857c47caec3dc8b2ffb384d0193e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "950988fbe9d62a66f5f2c492bc8dc944a78eb3796ec37ba94b6a81a9d402ccad03cd8497fff74c5f4a03081c5fecec48574fecb21c1de261332c23108195d3f6a96ff8e433a1a30eda53dd5bb414973334f8cde5510ff759f7c17046cbb5acd8e8c4a6eecf2a9121ec3fc4b22c4daa72678194ce809024cd45c4ebb9ccdb6f854205cdb624f0787480d8034d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "552a212c403b473741da8e9c7b916d5e5e9bcc9949021ae1ca1ed46b7d4a98addbb604d9fff56175b7e0367db26c9635fa7813653dc8d610befdd09ec41e99b192a716106f4299eec8b940863e5a59cf26cdc2cd0c3017f9b4f215812bed15f69e77edf672178e13c55580982f01fcc2fa131ec3d736a55d56504c545f4be50fee83f1263e4d3f3c877cc6242c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "b00c4283dd3d9cd26e44bd97cede6c771cb14f2571b51cfdaae4309560ffd165da025a1bbd31096c3aa8286e2d6dcc3e681b8d01f2c5064ea26dfd0b5156b7a7f5d1e046c5bd1628f8fdae24b03bdf7cf7366900cc013a8cbed9d7f5937c914b08f8c27683b956e1279812d04288515333fc6aba3684dde2292951f0610649d90fe61606630fc6a4cd383649252c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f6e79457bb6d0884dd223be2cf5ae412a1ed425f1e4012f75951b096aea3b9f3581f9013bcae1aff2d3fc1e5c7e06f24af6d53c2c5c238b71c71cc670b05a7ee5204400026a5c4e5ddec3ad96771e49fae4b0f75ec58049ad9d972e5749a32d90f847f1ed2a1bab83db181e541cf5c8adb6b29ecc64dc25add491d408d3eb3ddcb013de7f5ffb6de9dd7ff300a5fc6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "fe1d71e1d5efa3f712d23216ee8ee9139e66bd648b83efc02cdb4d45a28cf36759ff190a84d14d9471477abefb5aea4111110336143dd80cf81e02f268120cc07d746538f968e9876bff8358d390f5b8e7eafa61ecd236cedaf276bd61865fdd3424988201dcdeda2e3e0c33c9e3b3670125dd1049106cc6df5695fb2dca443233ff440f265bbff055483bac1e859b83" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "4c80163562872a965dedd8725652906156ada6e9d999027d96f49289edb92f9ef043e9d7c3377e091b27f85275499454af32317535997fb4aaeaf93565ad481ff7d45d2abddd4df4b60f71a6923ec30496c6ae534dc5427107ab4c5e656a322c7ab058d4c13ec0ebafa76576560697ac98f84aa4a554f98ec87134c0d7dca9184cf70412a324aac91823c0aca02537d197" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "fdd58c5ffe88665beb7073c8f4c22472f4bc9390cdd27a42622ca55978b000ab7579f795d4de0dfcaf521b8268980ef1d20277b07567985c0fd5030784ad6c32541ac24e99ab706105a2255fc32935c0fce6fdad9bb224d94ae4eae2a3ff08836618a3adf193630647bce1952b69da4de360f59da303519278bfd39b733cf66820a5e9e971b702f45998b69a0889f4bec8ec" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ff38b15aba3794e2c81d88003e045ac6cbfc9f4833cdf896cefd8ac0c88674727ad9a9fcb9ef36574deea480e6f6e8691c8390ad73b8ea0eb3665c914b0d886546948e67d7987eea248b5feb52346ffdd965d5c835144c3bc63daf325e74b11267e32e58a914ae4521a668839d9445fececa49c5fba41f9e171698bbc7c6c97fa163a377a96456958d6e1d74f91ada56a30df8" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f048c19328d60b4e59ed76940415b2c84c23883198bba5699efb0a1774ad5da6d15390c7b55d77d66f37448fe08107f42a5336408d5322f4b630e3275865fc66dccab39f6e13fabc133e5a441fe352d81c7cd9a25f145a6e2e2417d3b0bbc79eafcd7ad688c02011fd268dd44ac3f4f87b37a84a46fd9e9975962fba92c9a3486deb0c45f6a2e044df4bb79f0feeea432c5008b0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1b3e5fe6f113cce28a6f8d6f7809d3cec398cabffe9ff2ff10a7fec29a4ee4b54186063fd5307a2be393c9ecd75a37620bdb94c9c18da69b658579676ec90351d10dc33a7cb3b75798b1234f9f684d4a73a0fab2df3d5d6fdb1c1b1514d0935c1f2dd21486f91c2595b2f8f8a500ff443b9305270fb6f3da7961d9316d4ed6a135a31c4a3611d40e6585bbb34f498cd5b9a5d92676" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "740db337baa12b16897f17a85fa5685acc85e48338867f8ac9c0198dd650f5dfa7c17725c1262c72207e365c8aa45ffaab6470a0e5afefbfc3bb702a9766064f28cc8b796878dfdd3ca9d0216c14941438fc541fb5be0a13d29a996c5c985db4f630df067a5626db5dcd8df3a2bff17dc446e46e4079b8815da4318cb228c7722684e2a795a0ca56f500ea51951a6a385385d886f678" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1465f2d578d167faa017fe8f763ce3cc8dc1e8371d774ed2a8803f12585296ee71a1f2253dd16b717a81f91f0f3641018a0111182b4e65d884b0a3d0292631ad807cdccc88bdeecb476e76f72b5246a630aff6e2401fa9570f85acb73ccb4e19ef04a932a03d7b7985dbe1e5bb410df517fe362321469e6f8b0e0cef6c31d7aa8ec06aa220620d66cc0e133fdee963589b12320fc9678e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "80c051952fa6f3ef6af0f1759ec3e83c8eb91abee1de360bfa09e74b05af2475a0dbf8f9135aa25892919bbe0515898cfb6f88abc9e1891f2b2180bb97370f578973d55c13c35edb22ed80647c2a7e2884d1ccb2dc2f92d7b6ec5843ade13a608a31190ce965bde97161c4d4af1d91ca9962053f9aa51865bdf04fc23fa35a6fc3c8e888941263a26ed66c2dd0b29b2325dfbd1227c5091c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "9c1e2a1aed6406052eed12b4495365f2f80e9c9645473f3549b607f20910bcd16dc3a4b173ac8d128129cdb7c76ebbc8e9a2a1ba0d822c66b367e790a69ac71f0a60ed4bff0e979148e3f3ee6607c76dbc572ee5ff17c27e4b52adebb4bedddff517f591a1977299c7cb01106f1453b098d29848ba3751c816215bb0d090c50f9e445b41b2c49d4eec83b92ce6c269ce835fd279e7cbbb5e47" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "466abda8944d0329d2975c0f2e2afc901f117887af301881f63b714f49a2f692fa63a8871fc0b301fe8573dc9b2689880cd8969e5072c57671e0633b041481dab25e65c9de404af033a11a8070c8ab70ca6d465318501afdd9940c7efbe1bb6d49581c222fad251dba4ee0a98efe22a3c4f74da05844523b30bbad6b080ac8df70a02da80bc9d477dfb869adb211e209a316d5dd1fd89a6b8f8e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "0e89a873e07799ba9372fc95d483193bd91a1ee6cc186374b51c8e4d1f40dd3d30e08f7feecfffbea5395d480ee588a294b96304b04f1ee7bbf6200cc8876395d1db3ac813e1019bb68d27204e514fe4a61ad2cbd1782dca0e38b5538c5390bca626c5895b745cfca5dac636fd4f37fed9014ab46ae1156c7789bbcbb956ff7ee5ce9effa560731d26783dc6ae8bddd53a5d28133614d0ddeddd9c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "fdde2b80bc7a577ef0a6c03e59512bd5b62c265d860b75416ef0ce374d544cbb4e3a5dbd31e3b43e82975090c28bc77d1bdec907aeceb5d1c8b71375b6d631b84a46153f5f1d195bfcb2af6f597a9cdc83782c5bbbb58c5188a87ebf375eee5212fa52523820a83106e8ecd52bedd60d95cd646159774389c07e1adcaa6b6f649408f33399ec6e507d61659696b3dd249996892d5986b654d94ff337" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f5d7d66929afcdff04de30e83f248e69e89604daea782e1d82d8032e91a95c1d6fb2f5578f79b51be4397e4cd7cbc608ce143fdddbc6fb6c43ffdd394a7df0124353b919aeeac025f3eb11ff246c3b9657c1a947fc534ce48e18feffada8797037c6bc7e2d9a9e2e019fe65627b3feb28e446473e3bd413047a2587f0be6a103403cb3c33fdc212dca14d8e386aa511c22308e632f5f9528dbabaf2deb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "332990a8dba55f977bc814436cf386ebbf10cb487a5f6ce83e13741bac670c6810284fbbe4e303547ef411e964fae82854e8c13cf56979b89ecfedd337aad78260060122d13dfbbf8497acb2066ed89e30a1d5c11008bd4d145b5ec353956310536304d8b8bba0793baec6d8f3ff49718a56e6694f8122078265cf5731d9ba61292c1219a1affb3679576d4998290aba3684a205c3469d40761a5c4e96b2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "efbdff285027610f03182009c89b953f19721cfcdb8accd74bab6ec4bdf3f555ab902cb0dd91284269d140638aaabd211748aa4da3b18cddc653b57e461b9ad8491807c535c08fe97d89eb587c6af19ca152e72479626ab764e8b62da89fefc8354c75a44851f985746d78715a5a92798dac1a4222be27897b3f0aa63d596aa7378545f49b259aa8518c3def8a2ec8f7aa956c43668c8717052035a7c36b47" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "0eea9bb83bdc324fd21b03669aa922fbebc448e7d25e210294c07862cfa6e061731dfb67b4810633f4dbe2130d90fa1c65843af436e74219d213c4458dcac1c48ec4541fc6e3b7918ab2bc621aedda53658050900c3865ca57cd5dfa1d28576827401956d2dd8b861fa90ab11bb0b544ded9bd3d62e3278ed484e17db8f2d5dc5ea4d19a0e15134ba6986714c2b22c59c2f0e517b74eb92ce40d2f5b89e6d79f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "25da9f90d2d3f81b420ea5b03be69df8ccf05f91cc46d9ace62c7f56ead9de4af576fbeee747b906aad69e59104523fe03e1a0a4d5d902352df18d18dc8225855c46fefeec9bd09c508c916995ed4161ee633f6e6291cb16e8cac7edcce213417d34a2c1edea84a0e613278b1e853e25fb4d66ff4c7ee4584e7f9b681c319c874d43502534e8c16a57b1ae7cc0723783807738a55b661e617ee285bdb8b845607f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "a76b6f81372df09322098868d469fb3fb9beafc5edb32c674974ca7032966aaca5b5c9bffef87bfe626bd8e33d1c5f054f7d5acd3b91ff95324d1ae39eb905b9f2694fe5cb03486cee86d2f661a751b0e6c716a61d1d405494c2d4e32bf803803dc02dba2c06eecf6f97fb1f6c5fd10cfc4215c06d627c46b6a16da0854e4c7c873d50aa1bd396b35961b5fa31ac962575230c07c369f8fbc1ff2256b47383a3df2a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f9db613812f2259972d91b1598ffb166031b339913925ee385f03b3b35dc4b2f1ae78a3c3d99c6ff6a07be129ce1f4b8d994d24988d7fbd31f20535d36ab6bd0592cfb4f8c1ed9244c7fa8a3c46e91272a1a40c6cfcf261c5658476c59793bf1a3775086e41a0492f88a31e2d9d1ce75cf1c6b4b928b3545d838d1de6b61b735d921bcf72e4e0615e9ff969ef76b4b947026cb016e2660ba39b0c4c953369a52c210de" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "e601c7e75f80b10a2d15b06c521618ddc1836fe9b024458385c53cbfcedd79f3b4239598cd7b9f72c42dec0b29dda9d4fa842173558ed16c2c0969f7117157317b57266990855b9acbf510e76310ebe4b96c0de47d7f6b00bb88d06fad2c2f01610b9a686079f3ed84613ba477922502bc2305681cd8dd465e70e357534503b7cbc68070ad16d9c51de96ccf0aae1599299331c5655b801fd1dd48dddf6902d0e9579f0c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ee5ff4ca16d1bde59ffaf2d064eac9141c1d8f120ea2bda942b7956ba3effc5f1e725a3b40b0b9223a14d7a50df1681d14ca0e0eda7bb09c428fa3b2701f83a7a3e139485a118f6287d266dbc7fe68c87b35becabc7782537c79cb8165bdc40cc103d7b6d4b627fafa0e4113f92341ab90ceab594bfae20dadbfafd401684584598941f1ffb8e23dc8a04ecd15376cda6d849fe0dfd177538c62413622d172d9d46e05c450" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1daca80db6ed9cb162ae24aae07c02f4126f07cd09ecee8e798fa1bc25c26c644333b63731b4ebc3f287f2318a820c32a3a55fc976576bc936f7384e2553d2891e3771ff24dd4c7f0256906460a8f12d30ed2b23583a0259cb00a9065a757d654d6e4603e7c7eb4a8426b527ae8a849d9350e9094b890367df3e8b23ad2df4d7dcce416bd8ea3badd037f53f7b07c02e5926515f196d62aeb9b8b14c863f067fc12c5dfc90db" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "27ff4e58a34ff1fcd66855d014ea17889a3cf0021a9fea3fabfd5b270ae770f40b5439e00c0d26bd9766f6fb0b4f23c5fcc195edf6d04bf708e5b0bced4f5c256e5ae47cc5651e51cd9fe9dc5d101439b9bc5cc24f76a8e8847c72686e2af1ce7098ad7bc104dad00c096a6d48b6453322e9cd6773fb91fb1eabd05dc5185a9aea07a2f64c6fea9897681b4428aaffe1fe5fd3e8ceb890b12169ec9d51eaabf0ca3d5ba415770d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "75e2fb56327983b04f640717be8cba6fef3655b4d8e5539587d6478356ec397efaed818b8425d052778eb30ef0dee656c52c2aeab079ed496ae4441a365f2130432c87ba757e25b4511656ad15e2eff84d342331fd2814d1f1d11af65d98a424c115ba183437c0d0aa55f5c44b8685028a47d89d0d36a0f20aed510c366ab338f074a941b404fb349caaec821e0850a627777cc8f5abce6b509290027a2a28ff1db62a5ed2f95fc6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c6ae8b6a060917cd498aa7874ad44baff73efc89a023d9f3e9d12c03d0b7f5bcb5e24e1bc2ab2f2c67b9a9d36ff8beb51b5affd4a3510361001c80642955b22ea4bf28b81a5affe5ecdbabd8d17960a6af3825a4522fe76b3d720b5d06e66bff5379d7a8de1f5cc3e7bb75163a854d77d9b3949bf904b6c4e568682f0dab7f217f80da7303cfdc9a53c17b6b51d8ddff0ce49541e0c7d7b2eed82a9d6be4aec73274c30895f5f0f5fa" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "606c9a15a89cd66a00f26122e33ab0a08c4f73f073d843e0f6a4c1618271cfd64e52a055327deaaea8841bdd5b778ebbbd46fbc5f43362326208fdb0d0f93153c57072e2e84cecfe3b45accae7cf9dd1b3eaf9d8250d8174b3dade2256ecc8c3acc77f79d1bf9795a53c46c0f04196d8b492608a9f2a0f0b80294e2abe012dc01e60af94323c467f44c536bf375cddbb068c78432843703dd00544f4fff3eaa1a5a1467afaae7815f80d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "88b383cb266937c4259fc65b9005a8c190ee6cc4b7d3575900e6f3f091d0a2cefa26e601259ffb3fd03083270eb63db1ffb8b4515ec454d12f0944f8f9f6869eedc2c5f1689766a748d74e79ad83ff6a1639aefdec6109342dead31e9cead50bcc00c5b2206e8aaa47fdd01397b141880490174141a1e6e19268378c1b54a84aba60ca711fd72f7df88e120dfea2caa140085a0cf73342f3c588b7edfb5b5e5ccabd68a32364746d92d536" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "dc0b293f1ba02a326743509f41efdfeeac1efc45137ac03e397a3273a1f586a0190cfb4ea96d6c13ca692a4de6de905c8338c3e29a04cbae76272f568b9d795cea5d758106b9d9cff6f80ef650d6b7c428ea3946c3acc594907fe4227ed68faf31f2f6775f1be5139dc0b4d73ed6308fa226b9077561c9e4c7a4df68cc6b819b0f463a11b9a09682ba99752c4db7aea9beac1d9279f2c2675d42b551d27aa2c1c34125e32f2f6f45c35bca45" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "5d801a7413311e1d1b19b3c321542b22e2a4ccbe340545d272abede9223741d9835a0fc80cc9da97a13f8bb4110eb4ad71093efba165b1edad0da01da89d86726e0d8e42ae003b4b50297d233c87da08406f0e7fc58ba6da5ee5ba3d2d7142cbe6632734eb2e7b7863c15cc82198ee8f9a0ae0b7f93bdbda1ed269b3824d5d3c8e78513815b17a4c0cc8c9706b9c77423a309ae3fd98e1e05cdbe9e2577834fd71f964301b10b66c316a2d8f2c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "2fd32a2bc15a9e96a100624404fd0a4e54ba9f8c0543d8ccf7c5c2e35f5e8c3c11dfd497320aa903900a4ca55a2b323b3ac4a7cfcd01bf0b448db8829072bee6b77c3d7bec2e1d8b414d907288d4a804d2379546ef2e2dc628269589164b13fceb32dba6fd5d48a956ce0b5c3eb28d894a95af58bf52f0d6d6cbe51317152744b4ccfc918ed17fa6856478d580b389016b772e1d02e57d2217a204e25361d91d4845a3fa20fefe2c5004f1f89ff7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f537b437662759bef8bd64368536b9c64fffbddc5e2cbdad465c3966b7f2c4bc5b96767ef40a1c144a4f1cd49edc4cc5b57e7eb30d9b90108f6fd3c0dc8a8808b9e0bd13aa3d661c4863637c5e4ba286553694a60bef18801299ae349df53a355051dcc46a7d003c4aa613808f430e9db8ca7dfe0b3f0a4c5ab6eb306aeb53e11a01f910064fbe6ca78b2a94fac34a2602f73de3f275953e13ff5c6bb5c39b82321ead17ec0f8ecc479e6afbc926e1" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1dd9fb7d5b5d5074971e69300720014deba6fbdb942bd29704cdfcd40fa5281d2a1b9f5b776183e03ff99c29587f10e8d325cb49c5c93e94f5132741b92c4086eec1374dea5c1e772cbb230c7b31f3e962eb572be810076bdb926b63732522cdf815c3ab99bbc164a1036aab103cac7b823dd21a911aec9bc794028f07b7f839bae0e68211286441f1c8d3a35b281fd321312577bbda04f643ecb2a74ec4527bb5148dbccbeba749f5ea19b6072366ba" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "5bd63737449de2d20ca63943953338ecf4cdd6cd0a726241adb04376385a809cc6ba0f3482a310746fbc2cd5eb214f03a14cdc548777fb0d048d659cd75a962e490c4fe47affc2430a34b10275e4c76752a115aae3a24d4fb4fad89ce4d79d65de10292f3490bfdaeabfae08ed51bda6ec8230e66cb07ddbeec26e3ef68dd71c852900659fcf0c963f4574ffe4626a33db9abf0873dde68b21138498b81e8cc44d354be4073615889a7ddff633b5447d38" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "a683ec8250506571f9c640fb1837e1ebb06f123e745f95e521e4ea7a0b2b08a514bbe5bdfd316903d1d6a05f5a143d94dab61d8a3a146ab40b2d6b72df2f0e945875a8aa7051ed115975f6f1567cfcbf04c5e11e3a7027b8e179ba00739181ba10b028e3df7259d0712f4a6cef96469ff737865b85fee2c2db02a6423e32505381e18a1e0b4ce3c7998b8d6b1b5e09c3a280b85486d0984c9e193b0ad2043c2bc4ad04f5b00a73956715937eebf6b3e27afc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "4df9d160b8e81c42930c48956fcb46b20b6656ee30e5a51dd6317876dc33e0160d31280fc185e58479f994991d575a917073b4439919c9ac49b6a7c3f985211d084c82c9d5c5b9a2d29c5699a22e79de3958d7b0e856b9aa97493cd4563aaa04fa3977a9bb89e0bc06a82296bdc76d20c8d393770176d648712454305fdfcf4e117d05acb5a5b006a9f8d0dc66dca708c4e4103ca825d2331750685c44ce3d9b3e753455580f4d6ac4533edeeb02cebec7cc84" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "67bb59c3ef5ee8bc79b89a673e331e581215076cc36b68f517ca0a74f74efafe9dcc240e6d8ca4b21019c27d6c9289f4419b4f218eeb39eb741c5ebebfe0ed2f6faeec5e8c477acf71907990e8e288f4d4049111779b0635c7bbec16b76493f1c22f645745fdac2b383679fee573e4f47af45ee08d84f63a5ace4ee1c06fa41e2e6e14b7bc392e38426813087a3a461efc62ed1941dc8f1728a2bdc04fde72a0b786558783c84abd4bd100e4926979a0a5e707b1" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "d341147169d2937ff2373bd0a9aefa77968ec8f0d993c6f9881eb174a1911e05cdc45993cb86d149a754bbe321ae38363f9518c50dd3faf087ffeeeb6a058b226ccab7858c00ba6de0e8f4d034b1d27508da5cc473f3a413189ee6fd912d7750486912944d4dc34405ce5ccc3885fb0aabcb922bcfa9081d0ab84c288022bd501235a835eb2e1124ed1d48fd4f8682da8e7919321031326502273375625c4e3a7282b9f53452195e53c6b4b57cd5c66f621bed1814" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "27e7872a54dfff359ea7f0fca256983f7600236e716e111be15a1fe72eb66923ea60038ca2953b0286447dfe4fe853ca13c4d1ddc7a578f1fc5fc8598b05809ad0c64a4363c0228f8d15e28280837a16a5c4dadab681e28968ae17934639fbc124bc59212138e494eecad48f6546c38366f1b7b2a0f56f579f41fb3aef75dc5a0958b25deaa50cb7fd1c69816aa9a51874a98e57911a33daf773c6e6166cecfeec7a0cf54df01ab4b931984f54424e92e08cd92d5e43" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "13dcc9c2783b3fbf6711d02505b924e72ec6736131159017b966dda90986b97522bf52fd15fc0560ecb91e2175322334aaaa0097e1f3777c0be6d5d3de18ed6fa3444133486068a777443a8d0fa212ca46994944555c87ad1fb3a367db711c7ebd8f7a7a6dbb3a0207de85851d1b0ad2f4149bdd5a5ba0e1a81ff742df95edee850c0de20e90dd01753137cb8f2c64e5e4638ceb893a3879ae2c049aa5bce44d56bf3f325b6c5029b2b8e1b2da8de7d4e48ca7d8f6fbdc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "9ca875115b109eab538d4ec7023600ad953cacdb49b5abe263e68b48eafac89a15e803e838d048d9625972f271cc8f36344bed7bab69abf0bf05979a4cfff273b82f9961626509765fcb4b4e7fa48212bcb3ab2b1f2dd5e2af768cba6300a813514dd13e4d269e3d36548af0cacdb18bb2439ec9459f6d847d39f5598304ec46a26d75de1f9f0c2a88db915bd26e45e1f1e68c5b5b50d1890e97a3803c36755f026863d14176b8b57f42e91d3ff37787f9b38e333e9f0433" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ec006ac11e6d62b6d9b32ebe2e18c002353a9ffd5dfbc5161ab887770ddd9b8c0e19e5321e5bc105add22e473050b71f0399327c7eba1ef809f8667c1f4e2c7172e10e753705e9a083f5bce88d77521225ecd9e89f1e1caed367fb0275dc28f620fbd67e6b176c9ae5d2659e6ec662116c9f2bbca3a93043233a4861e0688db6dc1800f752c5d58aa5033c250c891d9126e534ed921a9026eb333333fa8292059b8b446f336ca6a0cb4c7946b6aea3831653122f154a4ea1d7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "23deadc94481ce28188f3a0ca3e85431964cb31b60fabf381e6bd45ef0332bd4dde774b0281d317dc2e7d0c298fcf8625fa734126968df8b68ef8a35c325d84ba4fc53936ff3ffdd8838d2a8cabf8a9cac54aa444ed9875944e55994a22f7fa8538b1e983b57d9215fac5c0052029644044e790ce2f5044655608c1d7ad3bb862203ba3aba3b526606f273d342ed5721648e3f600942d3f7546f679161436389d879dd8094e1bd1b1e12cde15cd3cda4c30a40835665e4e5cf94" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "94701e06340114f9cf715a1fb659988d33db59e87bc4844b1500448960af757b5282f6d52967a6ae11aa4ecfc6818c962b084c811a57724f5d401191567f24ce917e4f8c3963474fdc9d2c8613c16f62446448b6da6eeae54d672825ed7606a90e4611d0e318ff00566862c955b636b5e81fec3362e8672ad2a6d222a515cf410482836deba092a51a4d464dfbbab35c50a33437ac16a88256e9e23ddd3c827cc58d3e5000ee90b12e4c5175c5733662d4848ae0d406c2f0a4f498" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "735b0758d5a331b2304f01081172eb95ae4115de651b1a6693c5b9543de33df25d9f421dbaeca033fc8bff57313b482778005aa9fdcbca65c643da2f3320e34197868eec3848ff3c70d7ac7d910fc332e9a359f892ae01641be253013b554a0d3f249b3586b1857e5a0f9482ebd91432a852b221f4287a6e81ed24e8064645d5b28ab9a13b26cc1420ce73dbc47b31acf8a871601022ce23bc443b1222ce9a037a2fe5226295feb4efd4fd671338f459ae146032697cf82fc55c8fbf" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c48d94f14549352790079fee69e3e72ebaa380510e3581a0824066413e7044a36ad08affbf9b52b21963d2f8e092ff0ac1c973c423ade3ece5d3bca852b894675e8173290529226939c24109f50b8b0d5c9f762ff10388833d99bea99c5ef3ebb2a9d19d2231e67ca6c9056d8834730605897426cd069cbeb6a46b9f5332be73ab45c03fcc35c2d91f22bf3861b2b2549f9ec8798aeff83ceaf707325c77e7389b388de8dab7c7c63a4110ec156c5145e42203c4a8e3d071a7cb83b4cd" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "553e9e0de274167ecdd7b5fc85f9c0e665be7c22c93ddc6ec840ce171cf5d1d1a476743eb7ea0c9492eac5a4c9837c62a91dd1a6ea9e6fff1f1470b22cc62359474a6ba0b0334b2739528454470f4e14b9c4eeb6fd2cdd7e7c6f97668eebd1000bef4388015630a8332de7b17c2004060ecb11e58029b3f9575040a5dd4e294e7c78e4fc99e4390c56534a4e933d9a45460f62ffaaba25da293f7765cd7a4ce78c28a85013b893a0099c1c128b01ee66a76f051dc1409bf4176e5afec90e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "dea8f97c66a3e375d0a3412105ed4f0784f3973ec8c57b4f553d3da40fd4cfd39761de563ec96a9178804641f7ebbee48caf9dec17a14bc8246618b22e683c0090259e3db19dc5b6175710df80cdc735a92a990a3cfb166461ae713adda7d9fa3c4cf9f409b1467f3cf85d2141ef3f119d1c53f23c0380b1ebd728d7e932c535965bca41a414b6ea5bf0f9a381e098d282a554a25ce41980d7c7be75ff5ce4b1e54cc61e683f1dd817b8e2c1a430d7f895e5e7af13912cc110f0bbb95372fb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "9dfda2e2f732867e60ed2b5fa99ab88eb82dc7a54334d02031258beef75fa4bd6962a1083b9c29e4eeb3e5ab8065f3e2fc732675b8d7705c16cfb4ef7305eb58120f1af5ddc55872a2cbde3a48661a0598f48f63e2e9aadc603545e2b6001748e3af9e86e1830af7b84ffd3e8f16679213d37cac91f07af0af02b37f5ed946ef5c955b60d488acc6ae736b10459ca7dabeacd7dabcfd656511ac913174f6d99327be59befe3e463a49afbb5235f0ce2840588c6edfbaaba00a4211c0764dd638" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ddcd23e8b9dc8889b8599c721e7f8ecc2cbdca03e5a8fd5105f7f2941daec4e2906c654210bdd478374ddee43ee749a920ee91872e057a1157d384dcd111266221b3c79774476b4862fe450704ff2c5353e9a936cac87c96515c28ed4c830335a55d084cb5873c5fd2dd907f3266d8eb7bf13b6dd7cd4966982a0949efd8e428dae13daee549e01cc3c226211d6307823f742c5ef2155601a4644c46eddd603d4abd959c6d242e427768df3b1e22d87971df58a1564b38311a897c85b497a72556" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "39016647acfbc63fe55a74598bc1956eaf4e0cb49d532c5d8323fc6a3f15a0231597f06eafd74ad245e672bf6b21e4da503cb5bf9d15e9038ef354b38807564d91f38b4258378ccd9b9420a1562d7136196822a1291c913d83c4cd99fd8d420990c72cdc47607124de21da8d9c7f472fdcc780379f186a04da93cd87628abf323c8dadcd7fb8fbade37d7d2b5c9f9fc524ff77494c98f42f2158a6f68c906105ca9e8bb2df463863cfc1e9008d8344f55c4e3203dde6699b59812d49ce1279fa1c86" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "02cff7567067cbca5911664c6bd7daaf484181edd2a771d0b64566c3ab08d382e83932cdd7b4dbf86c9cdd1a4c353a511e68afb6746a507a9cd385c198246f4543d606c6149a5384e4ff54c1b90d663dc7a4b91aeac3cf716db7ca6f9a1914e3a33efe82e7ccc4215999c0b012782402db4726db1d7d1c73571d45739aa6fcb5a20eeb54a84d5f99902a8d356cbf95f34c9c28c8f2badfbc08c69233514493c0c04963268c88bc54039ab2999c7b06cba405936dfc43b48cb53f62e18e7ff8ff3f6eb9" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "5764812ae6ab9491d8d295a0299228ec7146148ff373241a510faee7db7080706a8dada87938bf726c754e416c8c63c0ac617266a0a4863c2582412bf0f53b827e9a3465949a03dc2db3cb10b8c75e45cb9bf65410a0f6e6410b7f71f3a7e229e647cbbd5a54904bb96f8358adea1aaa0e845ac2838f6dd16936baa15a7c755af8029ef50aed3066d375d3265eaaa38822d11b173f4a1de39461d17d1629c8df7334d8da1b6401daaf7f34b2b48d6556ae99cd29ed1073926bcda867421832a4c36c7095" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "4df3043cf0f90462b37d9106e67366d112e4938c4f06abae97869531af89e9feebce0812dffe71a226de5dc36be652e26ef6a4be47d9b2db5cdd43809a565e4fc0988bfe82037c505dd276b757b785203249fd083fb474a25acccc9f38dc5164ff9097e05989aa6e280739a755231f93670e7226e22046914c155bf33d135b3f736ccca84cc47ae643215a054b54b7e13ffcd7ad73cced9279dc3210b80700fcc757acfb64c68e0bc4da05aac2b6a99d5582e79b303c88a7ac4dd8ed4289516bba0e243527" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "bf041a11622715426c3a755c637d5f478dd7da949e50f05377bf333f1c62c671ebdbf9467d37b780c25f7af9d453fc67fafb2f065a3f9f15d4c3561eeaa73fa6c813bf96dcf02430a2e6b65da8d174d2558110dc1208bdcb7898e2670894c0b9e2c894da3b130f57a90ec8ea1bffd27a37b4da4645c546b2b141db4e2c919154dac00e78dd3eb6e4445974e3bb07905982da35e4069ee8f8c5acd0efcfa5c981b4fd5d42da83c633e3e35ebdc959bd14c8bacb52212b4334f94aa64d2ee183861db35d2d8a94" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "a170ceda0613adc9c3a1e427f07beacf3b16ed69fb42b6bc09a38d803f632ad2929dba215b85683b74e2feb1d18fe17d0ea0db84d1be4e2e73476917a2a4cff51d6eca7c5e82232afde00dd2286a4c20eb09800b4d5d80e7ea35b6965b9792d99e399abda8cf32174ae2b7414b9bdb9d63e148f7357635a7310b130c939593cd3479164724011966c4232142df9966f09422f34f20b30af4b640a2c6d3dd985fe0ba3dfa9083cbb9b8dfe540ff9f6c608d18481213040768ef33300d773f9890c724ead320a1e7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "929477e9c2d0bbad3429a0e0de776695255013108261dc6404cb09828770e274d8bb650a50e490dfe917fc2047b0f8ee72e105927d9fa70523c727778cbf6ae876d641ad562938c870d12f2e047bb78920739dba0c3f8ce1fb77589623a5f1625f5d6ab81940c7dfc3dc3a641d82b2813629bab8282999317d6b93842334f123fb4693a9c2c9d8ba9bfc746642dfbd045cd2021b272eab7358aa954d453da53fc5392dfa7eb881f6f53809b692d27f3366595ff403289efcc691e118b4744a1147071d8909bef1e8" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3e98bb14fff5bdf7db38a3960dc55ca7d02333daed8712cca13dd5bffd114636559279db72554cc0a0ee1f7e15557d77cab0f2f1131f94fe698db81be38300a856a5eca85e5cf915fb7b6f38ccd2f27350e62cc30ce10ffe835118be3d435d2342ed3d06199b7e20c8e34d68902f0ab8745bd8b7d5b863d525c1f5906d2dca598db8a0f1e67736182cac15677579c58b8c670cae1be3e3c882153b2aa2988933e579ec2d6dbb00c671da64443dfc027dee6dfc3233c99758304570a982bf9b2eb59ccd70d0b54c4b54" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "aa12c7fa50ffdc2811c1872e4bee15f43e6909212385c872eb489f7e06dc1787043f56126f8373bdfa4b3f61405c73dd4dfd3f40aa5cd207e8520849c26f67716a46c0989a99efff42f24e0736e327af8e607c401a1bac77341e9a78c91e35d55b2457bdd5317a405a1fcf7a2a23de68ef92b65819e8aa3807c545361dfc9fe89125123492da958dc313cb5d03cb4b192c54ac6b27fcbc498652f5ed36b587bb74942b3ad453a8d79e5ddc06ebf806dad5046b73251064582ef5777dc530f8701701761884783fdf197f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "83e615cf6e17a29e63945710b548a6d9935850eec69830841e26cb6071e908bf72c87cf079ffb34c5eb1a390def72d004a9488224a18e189aa1092a0f1135712834d257a53dc1d0e2c6417d8f472ff13b181910f4c93a307420d44beec8875d5219a3160b8e921434ddf3f71d68db1c1d5c39d68edb7a604792f8b4e31ecda7895c99fc7031a5b98a22009c1da005ac8fd2da0b5d742743f5712d12fd76d11a18e487776ce21ca0d6e5ab9ca6d8c394c321b91c14e291399a642721361811a73b7392e8603a3004e7060bf" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ae1a8f7bfe4b1a0fa94708921dadb2c20b938239d7b9a2c7c598528f20f49764d322ebe85a5b2ea15563cf2f2304baf55d6607c52e2e1160859dcb7af6d7856899eada0e9128a180d3de6fed9334ba52b80c5c362d5591a0ec30f86d37a399927eb1c53076a12d26775522c511c83eb5b7abc2a00bd2dfd5627a8febba53d85f9b74c4b7f0c862ddb0d9298899b646b774d6cc23e4e23ab47174fccd34499253996d5e0917210e2f6daa1685f89f2f1fdfd5509ebc38191d539ecfb54ff0f5bbe6ef36ea35d425af6462f518" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1d033e06be253ab800c8176d3a9650ab2a5bcaa03e11ea95fb9ab3834b41eb0d1b2bcecfe219364c3104ef65a8d692bd77c798548b7d9a8faf7f5172db24ec7c93006d6e9839368291b8277a82c034a3731f1b2e298d6e0282ec8a7902e4f844d132f1d261d171375c646065e201849f2df73e3748d853a3122c2206aac92fea448500c5418ecfb3d80e0e6c0d51f85831ce74f6c659cc291f5348a1ef8b949f1b2a753633e382f40c1bd1b2f44748ea61127b6f568255ae25e1da9f52c8c53cd62cd482788ae430388a92694c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "104bc838b16a641749dcf73c57b207ea3bcc84381170e4ca362065a3d492e892b426a1f4fd82f69461d1ce1f3aaf8fc291ea30d6667e7e1aea4c44f7d52a5fa6d34709e6658483260ff5da76bfb74e7d194ad40dcac00daf0e45e74db4bc2248100a8b256b257278c3c98f1f2e3a80cdb812352aaf4155b3a4033999fb9fe7f506994fcf3a8db31e9e5ca8ef8c2e9c6326ca5b0803724ba641950eca877fe6ed6afc2e014651c56d0e6a61eaff7c5ed0b861d4bebe42904c0a568c26aa8abb2e97da2bfb40f14eafb6bf16cd208f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "5b92e4a175437d0a53eb10de2c56401720b11715a034459ebf506c3fd6534b5e817a0f09deac4bcfd353301d8d031b1331582ac09189b48e6ccea444655866c4bbd123d45ebabb774f877cf12d33b84cfca4a6a94f3f98869fcf2bbb6cc1b964c2438c2f348bcdf9001dce60a4706d20c169a040baa61cbeb0b8e58d505e6e3739ab03e110ae7efdf91347474033defbd1e86af322ec6456d3394699ca7ca6a29a70d9b10a38fe666eab2858bfe12dacb31568549c826c15af5b6fddf779954351be1872f04e53db7b3b5fbf61fd18" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "401cc7bd9f8227efaed70dad83fc8db3bd38efc166f0f11ab142c565c68ba9db680423a3d698b6f3476ef440051fd20b93f6a2ed045825567df5a65e3f62e4442ec396ad260a16a13a1dee46c7e8d88bdd7edf223ab76a9a787c1f4fe9925c051a4ca0e77a0e78baa29f36d193c862fd3a60653f544ea9e3f75f2f553891be8c1fb882f6a6aad118f576f3c2793efc67221b37a45ab6137434f6228cb002fc137b91fb8572c757f00736879453d64a8a868c131810ffdad9e9d028d132157ecb1da675d54047d19b27d3258c9b1bca0a" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c20cf0354982ca6a19d9a4dbf78f810934db2373941a12c263adefa61a5f385c859bc47028829c531dc25ccc0004c7510e707175a102ec3c4b4c933e3f52033e67476ff5f864c446c042a21e6037f7798363d20267891b965879fde80af6b59d77862e3a229af01b7ac78b578e94bd9f9b073c38a627c1864df0083aabb17024bdab6c3c0f0f73d31d59480523a2f23b78baa0385c15f290114305d7f98786b7dbc17a8c2aad97448e8ea389e68ef71091a6a9735ac12ca5497b9171da11a93c28d3273f58b74e2e46279d3ce9d0b20d19" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "e2365c2754073b511f16a1881ff8a537541ca7362ae7b84223d3c7d1d49d03a37d6d05dd2b819af9705c015dacc9dda83474eb14b7d5fce6e8a8f8c58e870149338d320e5ae476da6749af45e65ffed550d225a39dc74ffd93ba7da476985d6f44e90fc8e82454496260458431804d802fe804d825f611772f9710667377adfb1a11e4275bcecb42175c515f6a9439a359824f82cc9d480954364e6693099a821ace362e6c7ecbe68be8823bb5b49b4f23ad81b64139e3b63d9d4d298a842f013ef0d91ce7915ee8f816c70ba2aa3994216f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "9c43944676fe859327096f82049cf69e48b98715878400fdf2805e0d5ee642e6cc9c43739f418b701348a033c5cb96bf8702fcd2fac9be58262a843c1e4155ed8a1724b6ebf7cce659d88a95a0c54deb2d7d9574a45219b6419ee173d1d8fad3ace47c962b349abe1048565df85bbd0eb9b11698258c23598023a00fdd26573e41951452027125c6e894a97736ecd63fd15b29a55d8dd9dab7e2e18f541a2e341890a61b7c896e7dc67aa82f3479dacd4a8ec7558d40c34d9ae4060e13718d676c2450258d83de8a86e012813693098c165b4e" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1c707c29582d98a0e99639211102f3f041660ca03ad0939fe3855b8c1b22d6a9b8673c93e3eabc0ab231509b2b0d73c76a290a363943d12d2ff0ea30c6dd54eda753767effe04cabb4c3966388fa4c83a1906a0f48519a5fba9aeb585e0f8c45d6123a75ebe98fd1d0272f733a3925119481a321fe7509346c05128302851ba17a137f956f184e057a305e79a148727a5926de6854eb0314d5492fd735fa773d99ea34c95ca7546bd3a3aa8e66bcc6d860cec3d35d0e2165d5fbe8be99b6e7967df6693e5a6243e94c9c4a2528ae6305cbeca209" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "8f1e88103ffa378f062cade0ec509bec99a5c73fb273e79dbef24abf718ac26ac23dfd2b8932038ed3cb9637b71643c161142019f45b25b4fa4c52356737a27027e805ec635154327a66bfe64efc6285cca98c34edc7fb6c0766970a545342cf840aec0a5ba1dd3c6949be4fe97b0f8c8186de07536fd9074db34d09b2f08af9dcf9424d6edbf9cd044102c0e5dc35aff78c36d079dbd2c500e19c8c985ae2abaf6b2a20716bb719754a8840ce97632116c4d0b0e3c83ccca27f11c4204b76b5d6cfe6348a9615d8e4af53500dc4c2cabf12ec8c76" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "b9a0c28f1a6156992c103a84655fc6e654fa6e45e45819513afa797024717c00cc195994512fd53ecd1e12dac4d2448e0c40308382312084d2111f7db147b2e6589ce6d977f6115f629508167df8f45bac98abd49f6b272bcc4fd874dd5e29fb6daceb2d727a2a892194cfb9269eda00626ac89b4e74bd29b21e9f6ef18cb69889a02d4f0a06a2e5718899c1dc3b051c2cfa29653e782f87fefa478e6465bf5ff27f8b6abdb500077aac97100bd955ec535a587d66f23354be51cd8170289344bac9451f74e8aee3639f7c09981f4885e018912324d7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "456844a34ae1074246f8f71eeef2010ec8733265bed7c1cc60043d770edfa320cbd4284a94be2574337e16d27f125074ebd7e99031f7abb4547b9540a7b0b5148ef501b550dd929f3dfe39ac65519f563e9254424aaafa05b1d37c16c771882e9e25d4906ac58603da749adf686932cd73d81e2658134fe69294c7a521d257eaf2110c667fc9d6f09b52d24b93910e532184eeb96eae9d9c9750ac3c39e79367431ac1af7011172d0a8be46a31010219a0310a733068c589bfc4748f3626aa4ff8d355cc893d05111c287c9992e95ad47481a6c42d6eca" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c5c4b9900b9727bdc24baa544cad5faf8340be6b3759361f53889f71f5f4b224aa0090d875a00ea7116772117dbefc3a81c6950ca7ceeae71e4ba975c50d61fec82e6d9448d3a0dfd10bb087bdf0673e3e19fa2aaa7e97eebf71f11b86034fcf5a61240c71444ac3da15ef09b27b3523d37d309e8722380f835c1aee4a767bb027ec0674040853e5b53d6a31657f51acff6d2487860becd5ce695696cfe5937f4a0217b69e01cc6facc24dfe5f5230b8692a0b718e3b3c789d682db36101795a9a5f8bbb838c3679be72f7941a1db180135347d0a884ab7c" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1781df2fedd2c39137854737d054cd3ed16b0ade411e41d97888ac900fdb46d9ae26b3d2dd07e118fd57eabd0dfd03a55793c76420666444865371adffc9b2f35068a0d70f9cfda1ac27ccb4beff4ffa5b8bb8bddac843386675c38a181fd0d935d6d51b25d78e7ff4ecef27a9853c0f0d2879c395ed1c4883987d123890d04f851c3e042e1164c68c0d503de16816f4b0e554236e5f4c339ea11d01ce652f6208f78f457a2417a97c0a6a240f443262def4b6763abf53e597bf1a28f907dc7cbdc751a234ea7d75710ad5ab0c37e8e9805102a375abd44011" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "8963552ad1e729ead07750df599d734157aaa4bcdcac17e8eb19b4f99cdb162686ff433137aa4e8a0cc8df0053999196262115aec326cf37567d9ba4760e0ad21d5763977f1ab9b35c0fc667890fa87fc946ceb776a811b5adc69446bfb8f5d9908029dc5aa38db816e4a4e8f98e5a48cf0a01627031c5bd1ced8bc1940dcafe4ae2f1199b186468eafc07e96a89d95dc18ef0fed3eda5b58ce58f221a47ba5311313cc680367eeb058fafc7bcadce5f520b6371489d9e529278ae6ee2650a85aed82896879038bbd9aa8d685fc9528943ccf2235cdf69a86464" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "23ceae3008085134433f5de4b47bafe0f443d443491e6cd47b216dd2dcc3da65239515a6e6b9beb9a939ae9f1f1f5e11f88326475e0962f319d9bf75ddfb4a46e7cc3f799d7547f3c0b2e089018b75787b82ea1a7295e7411f4852f94c94170e98bb0647923b8eb7d184038e56560da46085540cbfef82b6b577c445d038f6c93fbfdfc96ab3a0191d20a57b8610efb4cc45cd95198198e6f80ac46b0601511885f650eb00992605be903bcb46cd53c360c6f86e476c4c9ca4ad052eb572bbf26eb81dd9c73bcbec137aea6ee27aa97dadf7bef733fa1555019dab" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c0fd31e82c996d7edef095cccfcf669accb85a483ea9c59f368cc980f73da7202a95c5156c34192ae4ebf773c1a683c079b17ac9d08b4265b4054fcddaf6666ca50f38f1a2ef2497459a68c06837363a526e850ecfbd223f55dba67db017eadb7a9139abb5bf3854834478b838aafa16c5ee90ea52fb2f7b8db2bcefb85b06fc455c2b6c27d0af9a49dbf2f313bf2599370637393e7972b31d8bf6759f3e6115c618e672831f84d76ba1879c754144e1df4d56b1e264b1797dcb8ab165040c8d20b931071081d7f74fbff590bdc8e888e71acc6a720270da8db7c821" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "936fdab91fba396e4a8754a97a04ba333daadc29885c9d0c8fea3387165278f4974e468fea57f2bfd8428c4d0f010833283db73735d39de0c0cb5898d0c06c0ecd05f61098935cb6130a8da60d1a6c2ecfe420f972263fff5a631b09e81c837183c5528bb1c740b36fc39cb082f3383c2b4afb25d04ad1d1f4af63dcf26a0bf5a647cd2e35a51cc119c4dc5031f5715b3bfa1f2b92de06bdac0d670fdd30980f32c51f3936b51e5db6b95a8d36279da5faa4c4e454f2b7e54e9f488071011c7f6f9b63da260a2e46d796d36c9a9dcae88085806a10a77bbb670d475778" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "a55fe162b287bd6eebd6cf7e7aeea8672322d924ae42c7404ff89aedb98943f3755d2889bca488cc7000e6e9b8e7a0ef289273cd29c44cc600e330d1775e3cb767f12150e1615dca8c3f67466463a3ca993a1b788cf67a7a35b95dfff954206eb5ea1e1bf7fb06482a551625b5c9fd9a86e8414c8cf79d3a14104a153cbe04aac5172aa4c4a89349f5856c4262dd1d7317a7544c9afbbed449e7dcc2b58d9df6c9c9ed3883e42e80f5c2433550f30e73c7bce0fccdd880adc19282a392dae26a0108e7faf168cfc15937aeb046d60712603286b8ddfb27916b79242d56f1" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "2bd6976592408cdbc4e41dcd3ecfbb786775ddedef914d9058e6753f839fdfe15b17d549dbc084aa6cdf3befa0158aa84c5d58c5876144fd7e6c41ab7d42419d0dd353732e0e6d3fafc4f5626c07433390a4fd467197e85b5de7e2cf1c26cc575356adedcc0740008523b503df12ff571387726c5ccb280376d19cbacb1d7ce7aab8b13292c6a8b8881e949cbf6d4610d16ebba1d46cdb8d0459596e0aa683d0307bd926e14de19b9bfeaefa29d91b82248604673a455520cbb64eef3f38cfad8e126a3b1cfa1aaba53a784c8ae0c50279c0ecdab54095d36f67ace9b8ebbb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "71913ae2b1c8729ed6da003c24a1d4f96e28d7faf55ca14ee0b2865282b9b61103ce6ee0b00b00aacf2081adedea5616f9dfd22c6d6d4f5907bcc02eb33edf92de0bd479794f51246d9b612b4543f6ff633c4fc83bfa6144c9d26721cdc690a3d5a8db54d8bc7873bfd32924eeb502810732b5ac2f1852bb021c401d26c39aa3b7eb09083093a9e89bf889b53383b5af61110aca1b9fdf38908c7d5a184fc5f46b3423a66a2749feb8de2c541c563987278dbd0513d99b732411012b5b75e385510de5f6839c3797dc094c9501d5f0504b06b43efb6e746f2129ca189c1da424" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "9d048a83294de08d3063d2ee4b4f3106641d9b340a3785c076233686dd3382d9064a349c9eaa78028d35652078b583e3f708e036eb2ced3f7f0e936c0fd98f5d0f8aa91b8d9badef298bd0c06843831279e7c0c67ca7e572f552cfdd984c12e924c08c13aeec6f7e13d161785546ebfd794b5d6a92a4744e52c4cab1d0df93b9468be6e264e8cfcc488f9c3c1817cbe501f4b9cc5999483b7433aea777226b25273a6ef2331b5f3b6db8091591e8e276015da3ef78bb2ee0526ffe23def2d8d193cbe594e8ced1f3d216fcedae2a1eb288da82e34cf98aebc28def658ee0849ae7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3251c96cbf82ee2e5264528c0b6cdfc23d20e1eb2d6441b5d62f0fd24c692a0d45a8bc8aac32884b7141ac0f4f113ec9fc7f6b4db3d696374177f9a42d602ca471275b928f639105a55b846da9ac7274cc37de8c38541f6895f94d72a81e117844b46601c201f7189b935a96e42505f2098ac985d92dfe86349a706ef6325b3c2e4060ced3c453e68ed09e043bcc75846b80118dc53530248da250fb57922d0afa53a7b2c89161aa4fa372a46b2a8e1307741cecedf585d2f998a9d496763800b6965c38a5d8aa566c709f13699c8185ab4fd8fdc8b824f4dd6d1c255b4788f50574" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "2de31dbc8a012254586f3229d3524fc529554e98850d30acdfc11406bba6a142029126ac165ee90b2de7509fc3571a8ee12e16b05054eb8baea879d135b39627f0d8331be3e66bc720c2096ce74e437daebf3bc53d8f2ccc228c3256d3edb6e9ae7c354a0c9350e6d663a9a30630bf9da3d96b96608a2a171ae28105714058b6c4b38a36c56561c4612c32aad25c65b7fb6faa4e4ecd44ebf9b2fad42ff9a807cda2581614fd30d41a7436069399b8d4f062a37a5bd4066a93d541fa5797a7d3e7dc9c4c40f0bbf5256f71613240f9ef128b3423eacaf428ada06b6a531f835281e4f3" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "07dadee629a08223dcd7ec441287b4c5e26347451d9c003e3a8496b4ea313b51126283a6720d7851e24423d9c9c818b4601247178f38a61f45fd4c8596d79529d416834226666a2c8552bbc901cc5cc3406a18fc88077fea52e1b620748553052ab7788c0d025b095b736fbe714cb3a968ec16b5917652eba2d7cf32ef3140d6c27b25d053e9786d24cd09a5306a0ef55e46201faa6196a91084267d7a7b5ca57c2efdeb2cb97d682d2a191b915553c8933f1d1b7faf0b4a1d83ef611f1e44438bc1c3d860fbfd12b5f26e5a6889a31ce26ae6a55c7a563b5816d113423ef3f25fa9befc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1d94166bb387526d519c4ce150221954da8930f66765fe6a5504e30a69962d595cfdd07a82c003843598864261f053bdb6f5086d516c261e089caa89990f0967605768ae9200bdfe4dcd7b77a93265cb33d9851a2a1036113c732bf3f37534530641300f0620de5c16101e16f4baf39d9fcbfcb01c52afce0992c329d8dbb438c314eee995c5020611d6f889e06b8a032785cba9a415580dbf752b5e510523c89f478cc6f047bd926f51e4a965c9749d1e76379c0e7e5b56803893bafaa4d2892b4c52f143b2fa777cd1035ea418684b8019df084f9a3f1f768753096621f342895c510d01" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "fc0073f199ed8a1d6edc8e7bdf182670003108d82b283aba82326e856f8de378987a03d0fe8d2041440fd29d51c63796aab44090d2b14ee00859b3a08cbe88f724badcd3c401226c5db8b307b8deea5be305412b080e9f99cf79d6d08d3646f347a7afebb62912e3e246e2e726f9aec5c101d916e47f984507b1d65d313697256c77da7eca3bc5811c87bee02a2826cefff0d92bae989609aaf95d70561b40d98474c37277c884aed887a1606d206b11e8a8a71d1f1d19319557b57351228ff0404be700a6cc56c0a30f3d4b7a0a046463fdaf19e7d5f59e155f378e35baa33db1e881f2207f" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f42a6a91278d6a076feba985b1cf4ce0af1fa9d6d039c136e8971e665ff088a10b6b9a379a6f5526fc5957773a0ccb8972a4a19be0745ac13937030a54b18dee4f4c5df47a58a33a7516b90e646e5da999166ab0e52f457f7c9b7e391836a687eaae37b377e59a4c995ab0c57162c307ab951a9ba6590f429cd27250e7010eb794ec1b1ec35f8aad189b2fd3e8aff24d93601d91a4884e6f84b02757ce7620a02901519fccfda52f68ad6df709d112a9c25d66bcbb9622806427ca8b8d346b6db05874bde800cde9cf17df4b05baab0f133febd1ebbb053b49c109a7f5b1f864a304d10288e2f0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "bbcefaf4a0739509f8a2f831c954071aac52e60cfa882a867b8b910dcf7edf92e1c0692bb027bc378c460a01cb6ecc8f2a012dd84ee5a678cd497b1457b6d393421fbee98ff544fc7eba24cbc3aae506254d9a2d74dde74437ce4c8a69010718506bf4c5943342a942e5e2d3406a3016280b6e37954c5d5e763346251afb0b746cad68cac757f9df765e092518729cfb9a5e76300c124e708ca33591a369767ffb63933cb72fba67beb2223d98984d0b75eb5d1a38615913747b520b3d613c715c0c77d2987bb88f3c419bcc5d38573cf4a8a4f550b2d876f05ca252d88c70a561d869a5018b32f7" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "dc2437010cb05d9cab2af5c275e1d2acd627ce19fb86355df91fb8d059e60d591663c8eb077d48388c9a321057a98136f49f0098348d9f29d808936f98bb1787c7ac75fb14f6076dfd2de5b59b1fa4848cabaa9a99a091dc24b561911c392ecdbe53f4adae82b852d830adea3a10490c908e337ce0a6d12354ce05a37ad3a06696b66820af8a1f67e6287533fd6f38a5f6ad1c6b078c08baf2c37d2683af01e6a5b33796c8ae48935a888f9bd265f4f11a4e27c433b8b1c9afd140bcd21a07e24378ad6badde8e47c57e3340f49e2406e8d49afadd65eaaa4c3d078c27d7e42118cb86cd248100a356" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "6c290db326dd3152e6fa9b9c0cd7d49e50a0221b96e32f5f34a8cb7d0c2edd3e937a7d025d6999b7b468add4d6894d8f7aceaabc18f4d9c171f1fe95ea1ae8570382a8450fbc595d95b1f51d24e1abc2970b0e1d20ca40aa21bdfb3656adf2f19882eda606f5ef1c03174e1d94c8d12f0fee8dce6852f42a364eeafa27a7971d4379405db8e46baac4d685b969238e5df06292a6c790bf1994a051b038e1d8db91e1bc4804f32443781c34a552ed2e8100cea374e77af56ba0e11c45990d3ba68df9087b1f4968cbcbb1c42f99b7267c76af926ff3134e093df28fab039cad420c6b70f2d9b5e678c155" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ac724a22ebabaedbbb052953e3c264a4b6440f313bad501cdc1484b64f33402a2230898776db5c818c28035ffae6ea24abd04b7159e42159833903a0c23a7c564f7645e49ddedb748fd9e51bd6cbf2eced98caaa35226970f003ce1fd260ac5795e096f1c04aebf8fd36e5e2adeea929b5e963a3cb71d6b55c85bb7d3a2b03a7e74b4416de8fa68950168d7c3ae8ed2e29bad1e8a182a7c5418e5d564373163778cd3c34e9d320eb1a60480a8f98b12e0026cbd7752e6079812e3767d9f55f3f10b8c214a6eceb2a58954091a06b33862af171a9b60bf2c6a44e8766e6c56e98092c56f2a8510f6d05c103" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "8c70114f7cffb375c2b9a06e27297a5c32418b2daf68af5bbedcc7106edbc070e764bf40c1f8eb15079e2ab77f898afff3490108ed9afb7ea9cb05df41d263be0e42d2321d3d2656622d7bd232bf68d37375fe7314b09cba66f19c8b59424198ee69e7a9f3de0ecce0685127807ce336fa479ccaf7aa1ebc4e406271ce6c4923ec36093516498cc227f9218869346c80ba5ae83e023aca0ae2bc86b5bf5d115a4616b6587cb869d92f8c780ab70d5766de07a204af5e1c8dbba622516d2e911b36c82e4687e4d258ea616c07f76ff0baa376c8d5975cffac0b25817f779ae3ce88b72eb47e378484ce999bf0" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "0733d59f041036398233fd47a84b93f6778ae5259ef5d62aa3b9faedec34c7edb570c18b2a5d2c4c55cf656d98a1ae396d45a3b746b7ad6f07312c3d05d1a50ffa90bcdcdba105e25b7b0c52664223f8c2476925d46dc6ea2406ded7d0b0b292f6656cebcc7616cfa4b82aec68b35d1da67f6ed2bf0171849d6bb65128d8a140ea5cf97f1003f8d7093bee077be78def4f7bd2caccbf0644f26b26285225142c40038484c3bb9ba9597744f4389e76dca3eb695c33ccc621cab1fb603cb3535a0ad318d220385d5e94f8674f3d55e97e097f8d5c049e911946afbfce783819951d65d6bff4567dc951390d1aaa" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "398ddbba3dcb5642c102efa841c1fcdaf067062e7eef8e2ee0cd73d7f77e57372d6ee1a9b7b6f86ad12d575001ae71f593449cb5a476c6bfeddaa2af0f9239c1d7effdedf66ceaf413707b5ab9661a7cc0ef8cfe4d1651579c4f0f64e2d12a52653c54f2dd60864e769eab8a627c89c56ee93365d031f0d2523cb95664b1575d51b122f33c9e94de75432a690658c977b68aa5b721a393f9b9b3b612c10e920a7d510c6d8460b35f8614c42f5d2c241a01b28105aa7c1b521ac63ebbedafac6d5a38c898e8590f918a1927bc53aecc2b1c8b18d7df9107c6997d9b3fa4b0bdb1c603da619d9e75670b97a5b40f06" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "ef07bbc7c4150dd47f8c69a7989948fe831dc798b0424dcd6551bfa8e88216095a7e5d720909bf3d23526b9ba464b66ff6b63a7337c31451ab9a15f04ead809a62bb52206237de77597a730106d02d227dd6099ea9ee2a92cdc446ac3b9d024e32255adb3e9b56b561c431e0b5a721f0336f19568a5335d0ebc6c73ed8ff2c15e219477d9e4b67f2928e251f8a61a2848857e037d010806c718ab062967fd8e85f3722252957923f5f9005aae47b4b1b3fa464e3ba9df573a56055f17e903126fbbcb6cb96de92fe617c97f84ef3ba0d8f2651dc4aa80c157f372ae1bc02e5067ad076f3fe48bb72c0f3c99273f82b" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "c7076986d2333f3a6752adf11f1a9e5c6bc4755f341073cc86a9c7519c8db029d5ae833fdf3fee826ff4692c57880c5074620ea97c00f1dde1e8a0f18501627984ded4d1b5c4af35be5cc1bcc868060a49a968dc0547acde490b4c68d79924a93a986aa0ad060c7de706e8a99ce8f84a4f8707b52a8ee122b763ba580d6b1f35f6af25094c69f49247da96c836991851ad36f60bf577863d7471608a012afa7a56656abeee7cd9b4f1f4d9d13a8526c0f33cd251caf7486639e787250390e7e488e9ec311fc3d847a7266cc59bcc2bc34192554aa57cf25db10ce04bdabef3fde6db85f55195ecc2ff892b2e268ebea6" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "01789f40d42d8d3e4a416fd9ae7de78c3a30507809eda200e1afaaf8d7020cd1fad18eba62d821946f220506cf105ff0e2069a771a2c233714afa6b2f695497e4b95c9693dbb93ec4c9a14720676aa87ee31dd34e4e081756477032b4a57b328285f2cdec1b269754c474936927e93acc26012aff1bb36f30c2402aca0a9b9ce9568f5000e2c934263933b436c94f8d6589c89db7edabc5d03a8fe795fe50c5166beab64ed7c22662b984ae2c66dbe4c090b0df603b27c759278f8d66859afea3f6a8f02c2c2a2202b9fc29132256f164b5050a803b43688dc4c9ba86374a3522afba5d1a19bb3820b883aebc267627095" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "2c61944bd6a50da00ebb951d2b67d79fc6b6fb5aca83b1de3dbd7690ab756bb1e1a21051ccf1e24136ac8ccb42a2ee10be94d2cb9289d5f52b6f90e9d07a3478f36a1eb7d08c3dec52ca154fd1427ba92a4ecbe73a71bceafbd26e9a39d50821e2876d3a0c0e6e373b9795dbf72ea29cc439ff42706be798c90d4617b39c90ec84bf9fb699dc8a9a34e25d81759d6c57df45efb1d0d68aa51278564b99633ed5dc464bb7d53c5c21f798f33bcd868657ecfe75a1ed8149d394b398969ef624831b30f1458465bfd2fdf3f284f2ffc54bf2817b5fab2e02056e864f78bb6fd870c64f3609dab218f25da8060f756e45121e79" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "942fa0c68cc72f69518a3a7aac0cde45bab0e928b5cb2bd24d049fc313f74b6afa87c4e34150484f3b5200163f8a6472d04777928ecc49319539fc17d71a38090f55a74f757fe45781a3c09f08dcd3dd4c73c8533a5e00cf8a86ebe77fe45be2848574f7c5d25e9a0632a60d2dd41febdbf987d2a0487e4a4ce6ed5f49f2d741a88ecac232b1498253fa4ee8147bbd0f600abdf295e81f7570015aac5fe6ca7bb4a99bb3fc54287106d7fc1132a574af49db82a7b9a5f33e193cde527ca2176c52cdab672165e0fe5720f71ada57ee90060aa069ae2a0bfe67c1b71b17c601c3c2224bf9891bc11ba216e3ebcb51fd95b8d7cb" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "0d68cfe9c087ec116fe7572042385159cc705960f842aabad1ed1387ec1697f4413a23c6090041328fedd4b626c6eeaac5b5a71acc1fd1bb8fbd228857ac5bd045c364be7a5a26338ff04c99c4c473cf445a891db6422d1bdef4533442df171643fc36a092fabb464298e4194c9e2950884de13d113ee24160a416404c16ddc5d2476cb3fb80da543e6ed9105f6003977acb34e1fdd2cbdf7a00d5ff84350b74ac231418c0d88269d02d824802791ff42a51cc835deb9869a6023f867f82ef6dc0bfb03e6dfa835646bb18a4074773486e308aa39e532aaea4e6fb35dcada7e060f8282c371ed26d22302323d4fd142a85534671" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "45e24b167a0bbef1bd8f79dd047763d0754f36a7b623f298059d177e8ac994945c37d2c4af06f01318960301595941124592f2995af1459d854339998d3ae17534df2d9793d6e203857d02c98a0cd88991e641b3e640090ba303f87b907dca8ca462fac19ad079b2c82ea5b521ab891b10138b083b3d9fa214a8fe60d1cb3599c5d199c61a2cfb7ee2f39e5a5abad5ac4998b707545f73e92128d21803420526d2598a53bb314adf29a0ef56b94bd2221601eb53ecb8540e8fffd38fba7bd827ef255e4ef55491475c0f383a241f81c72af4e1dbf2a65cd4d18a497615aa0de2791a3511a7977a8d4d41492bfa4085f2fd4e8f751d" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "1c1bb695ae90e6e33fc1e8b2a62ab98bf835ac7193440f2351c8cdd830472b637d2fd9c9013cb83caef506abc1c4f7567706db6046b1d184579c7a9223ab1b35e32898c70a3c27628123ffcfa518612f080a2c4a9f8e0a927a47dc98307d2b48de9d5dddcb5c82f0b0e4e610d44f1baa9bbbf7f5a727134680bb7d1327b73b52d8e5e36dbb53971e99e699d79f75a3fc01316bd7012947d119d6aeb7f75b8fbf0479c03002148553fa0da450fd59d4f1bebc252caa11ed9bec5b6ef54279b5f8382b61cffc67ec03f4baa7ea476c31364b86aa8ccad9fd0818717f0ced2dd49477874b4341c602d7a1beab860eb476c7e3ce597e6926" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "7a3cd9bb2277e2c7f1134fe7233f0f7883c2db9fba80aa5742b03041de0fe589d9e5ea84470dabf41bb66816f3e33ebf19a0ca5aba1004cf971249b258ff26a98dbd0c37ec6cd574854109433357720040bafed4531e0079186b1e853e0ced35d08d27f6d732ed6e2c6651b51cc15c420a24f2dc36c16ef4b3896df1bb03b3963f9aaeb02a48eac5772abd5948c2fd0db2bb74e3351e5eabd681c4f413655bd94dec96b1544c1d5d2d1df4bdc26020d25fe81d5238de824687a5505e1fbe08d11b3924b3ccc070fd225bf01eb79e3d21f7b62a836cd3bcc11c931669c37613470e356143df87c48848a829f5e018973a5db88eb6c60203" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "3f158afd0733fcc5dfe1efc2dd4eada732f942af734ee664955bb1ba613eafd0f349e7554a14d68200c62d8f2dca2ec8b81c8350735eaf437041f78b452598825b6899560963ade66a0fc74ad01f8343d1d19c7bb327a8dc14ffdb1c42fa72b2970d9155e2da6a2e6419d4117842d826ff38ffab9617307a0283d3ea28c8104ad9a6e087bb750ed1d10fd8f7100b1663682e979d80e43968c33d9eff66f4d1344e583ee521e78d0a2193c0577516b978339c143bfc689bc744bbc4a9163063de82c9706384b6b385e54666c86b34f23c1e25be293af06092ca31d857e11e5b2caf0d19dd3afbe85380878eda76d718b4bb869c67e044e242" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "a177af4387b9bfa3d59e97ee7b0ff5f4ae4a326fd9204c8d28831a67fcc385ee6c4828247b16d11aea9bb8cd9e6c4d2876c6b2fa6d5041ad39e1b04039071e29c4d86417e7eac4fc7d3823958a021823e2c880a757dfbcd0c8196371db5bbfac15e4d1a0596508b6d26f8c4a664924c95082d173f817995b44c4285d625d9b2f56c86632fe1295c5a8a7a3760028072bcb07bc245a705e7174d06b9d5c0c8ca495b9ac218f1921fa63f2db3fd148f07545366d008fb5aead7497d902b91fbaa39669929d4ae9d07df8557f1f0aed7b51252f10c6606e5ff3ede1327530ca356b4896ecf14bf7322d77fddfbe28d52f6de7f66eeb81704c87e2" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "01a15b9018e35cc342c926b01d03ad9db4993a6bf92e0555969fee90033f28f3ec234c1268b11b040dfa0770d4ceb39edfeb8ee6a589f4eebcc08d2d1b0a1a52953aa26eb44fdf4a2743c3dacb212a0c0f325572f645f53027b6f3c0c55abaeb1b0918c89bedcb5028f094d743ea354f8ff553c45f111a8fd5a14a4e5c835164747d302472e19a67da04b4c8e39756a9d248ce14d1ed43de75aca86850f2455eccd4639b2af035bb3f504cc9065d091c1c47e036083cb3fc50bf39292b11737c7ce0b49673ba93981de304dc65a671775b6ff927e3ff93850b214fffb5792105a4bdc81354d5b09e84afbdd1792b8fb4e9d0ae3dad2492b03282" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "24f07ae31279ceed18ec6d35990f21200934ad6b132c6c62e82fe92a40a0e60a5bed10720eff5a1f728971888682772b2d9060d4fee88f37d0824e7384dddcc549475f0e1a44eda4804778b62febe46e04657a20577ee70acb3425e334881eebd8ddf714ae8c527ea747e3367de384e595a43b299b6bb3f6b0a4716cf90038e0f75a47d5057d7fcc3c8a8f9224992c67f8ae0d3251ea09a24aed9ce57ab637f6b3cbb7083df62b6287f64d0877984c4249d113bdb2b07865082aa24cd7ec07061b17de320f51f29f25b82d7073d369cf2dbf96310c0c311997911b2cc02f606f9cd99663c57e78499192a2a78f9c9fa67013e0f9817287faa69b22" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "4aeb32bf9d050f10bea18d9f71b4afea7bd08550e574e7d50df234c7413668b297b6721d7a0f0bdcdcceb2f55adddea28cd59bd44be0c5ec067039e428706caae11f565d961ad6e7f4c51b0aed6d05cc5b8d826c4b9c39daefb6c7da46dce619a359dc9ce215a215218fa8d54ee0b4f301b6c201c7c2c5f7cb1c6e0cb76ba6c6e8f63ef7a5213d550b0d0857fa0ff9e3e38e497161617413ac066e2fa539520233193a5cb7baa0c2cb20b45e56bfed2c40a9544d1f230dd0cd6d4976e7cf51da8a13200c3957c0154c8237b2931ce19b824963ac576ea49b548cc6aa85c47796b470fb2c6308d88f390bb13607e294c84a838b2713b14ca6a5e8bcee" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "77e607478be5502432230c913d9ec82f967d87c0ee169a74076f989648853eca693277287f8a5b306bc94dfdbf64ca5cb5dfc0bc498589d51a691b8d57d4b0a9ee247d038fe1b5571183be3e75c37045bf1235863ff1b84b208c10e7f1a5ba54ff36af5b2870129867164d013e0a6d2cc067a3509bba2f46390302c80b651cf590ef69aad8effd94cab28a9b44be6a38b58cfc47c9c725d6fa467894163383b6873d10d263b1cbbad932ded59ab503920267ac026726f794a335a88f6ef564f8968c6fa6f5d3ea161eb6062ca349b9a0e4038273399cfa297a6b07ceda1ebaa99c9de2d935ee230a08c5a488ad46f3393243371d40916b8063cac9da63" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "50957c407519951bd32e45d21129d6b83436e520b0801ec8292d79a828106a41583a0d607f853dc4410e0a1427f7e873455a75df065cfc6eef970f7e49d123b346976460aadd91cf513c140c356442a84656904a8b1d708dc6089db371c36f4fe059c62302eaab3c06c0cb3b429961f899dcf99798464b8571a440cac7a52b495f32417af6bc8f58adc63647531f804b4e96273b29b42434c1236bde80ba3744fef7b1d11c2f9db332b35bc25123338ac9a0796aac213c9709b3c514ea7ecd80e22d3d8a74f28c8194418a6e1ff30714d0f5a61c068b73b2ba6cad14e05569b4a5a100da3f91429d6e3ffee10ceea057845ec6fc47a6c5125b22e598b2dc" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "f2273ec31e03cf42d9ca953f8b87e78c291cb538098e0f2436194b308ce30583f553fccb21ae6c2d58f3a5a2ca6037c1b8b7afb291009e4310a0c518e75314c5bb1e813bf521f56d0a4891d0772ad84f09a00634815029a3f9ad4e41eafb4a745e409ef3d4f0b1cf6232b70a5ce262b9432f096e834201a0992db5d09ffa5cbc5471460519a4bc7cdc33ae6dfe6ffc1e80ea5d29813136406499c3514186ced71854a340701519ef33b6c82ca67049ab58578ff49c4c4fbf7d97bfec2ecd8fbefec1b6d6467503fea9d26e134e8c35739a422647aaf4db29c9a32e3df36e5845791fdd75a70903e0ce808313a3327431b7772567f779bbaee2e134c109a387" + }, + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "5784e614d538f7f26c803191deb464a884817002988c36448dcbecfad1997fe51ab0b3853c51ed49ce9f4e477522fb3f32cc50515b753c18fb89a8d965afcf1ed5e099b22c4225732baeb986f5c5bc88e4582d27915e2a19126d3d4555fab4f6516a6a156dbfeed9e982fc589e33ce2b9e1ba2b416e11852ddeab93025974267ac82c84f071c3d07f215f47e3565fd1d962c76e0d635892ea71488273765887d31f250a26c4ddc377ed89b17326e259f6cc1de0e63158e83aebb7f5a7c08c63c767876c8203639958a407acca096d1f606c04b4f4b3fd771781a5901b1c3cee7c04c3b6870226eee309b74f51edbf70a3817cc8da87875301e04d0416a65dc5d" + } + }; + + public String getName() + { + return "BLAKE2xs"; + } + + private void testBlake2xsTestVectors() + { + for (int i = 0; i != Blake2xsDigestTest.xofTestVectors.length; i++) + { + String[] vector = Blake2xsDigestTest.xofTestVectors[i]; + byte[] input = Hex.decode(vector[0]); + byte[] key = Hex.decode(vector[1]); + + Blake2xsDigest h = new Blake2xsDigest(vector[2].length() / 2, key); + h.update(input, 0, input.length); + + byte[] out = new byte[vector[2].length() / 2]; + h.doFinal(out, 0); + if (!areEqual(out, Hex.decode(vector[2]))) + { + fail("BLAKE2xs mismatch on test vector ", vector[2], Hex.toHexString(out)); + } + + out = new byte[vector[2].length() / 2]; + h.update(input, 0, input.length); + Blake2xsDigest clone = new Blake2xsDigest(h); + + h.doOutput(out, 0, out.length); + if (!areEqual(out, Hex.decode(vector[2]))) + { + fail("BLAKE2xs mismatch on test vector after a reset", vector[2], Hex.toHexString(out)); + } + + byte[] outClone = new byte[out.length]; + clone.doFinal(outClone, 0, outClone.length); + if (!areEqual(out, outClone)) + { + fail("BLAKE2xs mismatch on test vector against a clone", + vector[2], Hex.toHexString(outClone)); + } + } + } + + private void testLengthConstruction() + { + try + { + new Blake2xsDigest(-1); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("BLAKE2xs digest length must be between 1 and 2^16-1", e.getMessage()); + } + } + + private void testOutputOverflow() + { + Blake2xsDigest h = new Blake2xsDigest(1); + byte[] out = new byte[2]; + + try + { + h.doFinal(out, 0, out.length); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("Output length is above the digest length", e.getMessage()); + } + + h.doFinal(out, 0, 1); + } + + private void testBlake2xsUnknownLength() + { + final long maxNumberOfBlocks = 1024 * 1024; + Blake2xsDigest h = new Blake2xsDigest() + { + public long getUnknownMaxLength() + { + return maxNumberOfBlocks * 32; + } + }; + + byte[] buf = new byte[32]; + for (int i = 0; i < maxNumberOfBlocks; i++) + { + h.doOutput(buf, 0, 32); + } + + try + { + h.doOutput(buf, 0, 32); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isEquals("Maximum length is 2^32 blocks of 32 bytes", e.getMessage()); + } + } + + public void performTest() + throws Exception + { + testBlake2xsTestVectors(); + testBlake2xsUnknownLength(); + testLengthConstruction(); + testOutputOverflow(); + } + + public static void main(String[] args) + { + runTest(new Blake2xsDigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlockCipherMonteCarloTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlockCipherMonteCarloTest.java new file mode 100644 index 000000000..fb99ed1c0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlockCipherMonteCarloTest.java @@ -0,0 +1,82 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * a basic test that takes a cipher, key parameter, and an input + * and output string. This test wraps the engine in a buffered block + * cipher with padding disabled. + */ +public class BlockCipherMonteCarloTest + extends SimpleTest +{ + int id; + int iterations; + BlockCipher engine; + CipherParameters param; + byte[] input; + byte[] output; + + public BlockCipherMonteCarloTest( + int id, + int iterations, + BlockCipher engine, + CipherParameters param, + String input, + String output) + { + this.id = id; + this.iterations = iterations; + this.engine = engine; + this.param = param; + this.input = Hex.decode(input); + this.output = Hex.decode(output); + } + + public String getName() + { + return engine.getAlgorithmName() + " Monte Carlo Test " + id; + } + + public void performTest() + throws Exception + { + BufferedBlockCipher cipher = new BufferedBlockCipher(engine); + + cipher.init(true, param); + + byte[] out = new byte[input.length]; + + System.arraycopy(input, 0, out, 0, out.length); + + for (int i = 0; i != iterations; i++) + { + int len1 = cipher.processBytes(out, 0, out.length, out, 0); + + cipher.doFinal(out, len1); + } + + if (!areEqual(out, output)) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + cipher.init(false, param); + + for (int i = 0; i != iterations; i++) + { + int len1 = cipher.processBytes(out, 0, out.length, out, 0); + + cipher.doFinal(out, len1); + } + + if (!areEqual(input, out)) + { + fail("failed reversal"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlockCipherResetTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlockCipherResetTest.java new file mode 100644 index 000000000..80788fed5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlockCipherResetTest.java @@ -0,0 +1,206 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.AESFastEngine; +import com.fr.third.org.bouncycastle.crypto.engines.AESLightEngine; +import com.fr.third.org.bouncycastle.crypto.engines.BlowfishEngine; +import com.fr.third.org.bouncycastle.crypto.engines.CAST5Engine; +import com.fr.third.org.bouncycastle.crypto.engines.CAST6Engine; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.engines.NoekeonEngine; +import com.fr.third.org.bouncycastle.crypto.engines.RC6Engine; +import com.fr.third.org.bouncycastle.crypto.engines.SEEDEngine; +import com.fr.third.org.bouncycastle.crypto.engines.SerpentEngine; +import com.fr.third.org.bouncycastle.crypto.engines.TEAEngine; +import com.fr.third.org.bouncycastle.crypto.engines.TwofishEngine; +import com.fr.third.org.bouncycastle.crypto.engines.XTEAEngine; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.GOFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.OFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.OpenPGPCFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.PGPCFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.SICBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test whether block ciphers implement reset contract on init, encrypt/decrypt and reset. + */ +public class BlockCipherResetTest + extends SimpleTest +{ + + public String getName() + { + return "Block Cipher Reset"; + } + + public void performTest() + throws Exception + { + // 128 bit block ciphers + testReset("AESFastEngine", new AESFastEngine(), new AESFastEngine(), new KeyParameter(new byte[16])); + testReset("AESEngine", new AESEngine(), new AESEngine(), new KeyParameter(new byte[16])); + testReset("AESLightEngine", new AESLightEngine(), new AESLightEngine(), new KeyParameter(new byte[16])); + testReset("Twofish", new TwofishEngine(), new TwofishEngine(), new KeyParameter(new byte[16])); + testReset("NoekeonEngine", new NoekeonEngine(), new NoekeonEngine(), new KeyParameter(new byte[16])); + testReset("SerpentEngine", new SerpentEngine(), new SerpentEngine(), new KeyParameter(new byte[16])); + testReset("SEEDEngine", new SEEDEngine(), new SEEDEngine(), new KeyParameter(new byte[16])); + testReset("CAST6Engine", new CAST6Engine(), new CAST6Engine(), new KeyParameter(new byte[16])); + testReset("RC6Engine", new RC6Engine(), new RC6Engine(), new KeyParameter(new byte[16])); + + // 64 bit block ciphers + testReset("DESEngine", new DESEngine(), new DESEngine(), new KeyParameter(new byte[8])); + testReset("BlowfishEngine", new BlowfishEngine(), new BlowfishEngine(), new KeyParameter(new byte[8])); + testReset("CAST5Engine", new CAST5Engine(), new CAST5Engine(), new KeyParameter(new byte[8])); + testReset("DESedeEngine", new DESedeEngine(), new DESedeEngine(), new KeyParameter(new byte[24])); + testReset("TEAEngine", new TEAEngine(), new TEAEngine(), new KeyParameter(new byte[16])); + testReset("XTEAEngine", new XTEAEngine(), new XTEAEngine(), new KeyParameter(new byte[16])); + + // primitive block cipher modes (don't reset on processBlock) + testModeReset("AES/CBC", new CBCBlockCipher(new AESEngine()), new CBCBlockCipher(new AESEngine()), + new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + testModeReset("AES/SIC", new SICBlockCipher(new AESEngine()), new SICBlockCipher(new AESEngine()), + new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + testModeReset("AES/CFB", new CFBBlockCipher(new AESEngine(), 128), new CFBBlockCipher(new AESEngine(), 128), + new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + testModeReset("AES/OFB", new OFBBlockCipher(new AESEngine(), 128), new OFBBlockCipher(new AESEngine(), 128), + new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + testModeReset("AES/GCTR", new GOFBBlockCipher(new DESEngine()), new GOFBBlockCipher(new DESEngine()), + new ParametersWithIV(new KeyParameter(new byte[8]), new byte[8])); + testModeReset("AES/OpenPGPCFB", new OpenPGPCFBBlockCipher(new AESEngine()), new OpenPGPCFBBlockCipher( + new AESEngine()), new KeyParameter(new byte[16])); + testModeReset("AES/PGPCFB", new PGPCFBBlockCipher(new AESEngine(), false), new PGPCFBBlockCipher( + new AESEngine(), false), new KeyParameter(new byte[16])); + + // PGPCFB with IV is broken (it's also not a PRP, so probably shouldn't be a BlockCipher) + // testModeReset("AES/PGPCFBwithIV", new PGPCFBBlockCipher(new AESEngine(), true), new + // PGPCFBBlockCipher( + // new AESEngine(), true), new ParametersWithIV(new KeyParameter(new byte[16]), new + // byte[16])); + // testModeReset("AES/PGPCFBwithIV_NoIV", new PGPCFBBlockCipher(new AESEngine(), true), new + // PGPCFBBlockCipher( + // new AESEngine(), true), new KeyParameter(new byte[16])); + + } + + private void testModeReset(String test, BlockCipher cipher1, BlockCipher cipher2, CipherParameters params) + throws InvalidCipherTextException + { + testReset(test, false, cipher1, cipher2, params); + } + + private void testReset(String test, BlockCipher cipher1, BlockCipher cipher2, CipherParameters params) + throws InvalidCipherTextException + { + testReset(test, true, cipher1, cipher2, params); + } + + private void testReset(String test, + boolean testCryptReset, + BlockCipher cipher1, + BlockCipher cipher2, + CipherParameters params) + throws InvalidCipherTextException + { + cipher1.init(true, params); + + byte[] plaintext = new byte[cipher1.getBlockSize()]; + byte[] ciphertext = new byte[(cipher1.getAlgorithmName().indexOf("PGPCFBwithIV")) > -1 ? 2 * cipher1.getBlockSize() + 2 + : cipher1.getBlockSize()]; + + // Establish baseline answer + crypt(cipher1, true, plaintext, ciphertext); + + // Test encryption resets + checkReset(test, testCryptReset, cipher1, params, true, plaintext, ciphertext); + + // Test decryption resets with fresh instance + cipher2.init(false, params); + checkReset(test, testCryptReset, cipher2, params, false, ciphertext, plaintext); + } + + private void checkReset(String test, + boolean testCryptReset, + BlockCipher cipher, + CipherParameters params, + boolean encrypt, + byte[] pretext, + byte[] posttext) + throws InvalidCipherTextException + { + // Do initial run + byte[] output = new byte[posttext.length]; + crypt(cipher, encrypt, pretext, output); + + // Check encrypt resets cipher + if (testCryptReset) + { + crypt(cipher, encrypt, pretext, output); + if (!Arrays.areEqual(output, posttext)) + { + fail(test + (encrypt ? " encrypt" : " decrypt") + " did not reset cipher."); + } + } + + // Check init resets data + cipher.processBlock(pretext, 0, output, 0); + cipher.init(encrypt, params); + + try + { + crypt(cipher, encrypt, pretext, output); + } + catch (DataLengthException e) + { + fail(test + " init did not reset data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test + " init did not reset data.", new String(Hex.encode(posttext)), new String(Hex.encode(output))); + } + + // Check reset resets data + cipher.processBlock(pretext, 0, output, 0); + cipher.reset(); + + try + { + crypt(cipher, encrypt, pretext, output); + } + catch (DataLengthException e) + { + fail(test + " reset did not reset data."); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(test + " reset did not reset data."); + } + } + + private static void crypt(BlockCipher cipher1, boolean encrypt, byte[] plaintext, byte[] output) + throws InvalidCipherTextException + { + cipher1.processBlock(plaintext, 0, output, 0); + if ((cipher1.getAlgorithmName().indexOf("PGPCFBwithIV") > -1) && !encrypt) + { + // Process past IV in first block + cipher1.processBlock(plaintext, cipher1.getBlockSize(), output, 0); + } + } + + public static void main(String[] args) + { + runTest(new BlockCipherResetTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlockCipherVectorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlockCipherVectorTest.java new file mode 100644 index 000000000..9d4719b6b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlockCipherVectorTest.java @@ -0,0 +1,73 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * a basic test that takes a cipher, key parameter, and an input + * and output string. This test wraps the engine in a buffered block + * cipher with padding disabled. + */ +public class BlockCipherVectorTest + extends SimpleTest +{ + int id; + BlockCipher engine; + CipherParameters param; + byte[] input; + byte[] output; + + public BlockCipherVectorTest( + int id, + BlockCipher engine, + CipherParameters param, + String input, + String output) + { + this.id = id; + this.engine = engine; + this.param = param; + this.input = Hex.decode(input); + this.output = Hex.decode(output); + } + + public String getName() + { + return engine.getAlgorithmName() + " Vector Test " + id; + } + + public void performTest() + throws Exception + { + BufferedBlockCipher cipher = new BufferedBlockCipher(engine); + + cipher.init(true, param); + + byte[] out = new byte[input.length]; + + int len1 = cipher.processBytes(input, 0, input.length, out, 0); + + cipher.doFinal(out, len1); + + if (!areEqual(out, output)) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + cipher.init(false, param); + + int len2 = cipher.processBytes(output, 0, output.length, out, 0); + + cipher.doFinal(out, len2); + + if (!areEqual(input, out)) + { + System.out.println(" got " + new String(Hex.encode(out))); + + fail("failed reversal - " + "expected " + new String(Hex.encode(input))); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlowfishTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlowfishTest.java new file mode 100644 index 000000000..d2918f324 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/BlowfishTest.java @@ -0,0 +1,57 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.BlowfishEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * blowfish tester - vectors from http://www.counterpane.com/vectors.txt + */ +public class BlowfishTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new BlowfishEngine(), + new KeyParameter(Hex.decode("0000000000000000")), + "0000000000000000", "4EF997456198DD78"), + new BlockCipherVectorTest(1, new BlowfishEngine(), + new KeyParameter(Hex.decode("FFFFFFFFFFFFFFFF")), + "FFFFFFFFFFFFFFFF", "51866FD5B85ECB8A"), + new BlockCipherVectorTest(2, new BlowfishEngine(), + new KeyParameter(Hex.decode("3000000000000000")), + "1000000000000001", "7D856F9A613063F2"), + new BlockCipherVectorTest(3, new BlowfishEngine(), + new KeyParameter(Hex.decode("1111111111111111")), + "1111111111111111", "2466DD878B963C9D"), + new BlockCipherVectorTest(4, new BlowfishEngine(), + new KeyParameter(Hex.decode("0123456789ABCDEF")), + "1111111111111111", "61F9C3802281B096"), + new BlockCipherVectorTest(5, new BlowfishEngine(), + new KeyParameter(Hex.decode("FEDCBA9876543210")), + "0123456789ABCDEF", "0ACEAB0FC6A0A28D"), + new BlockCipherVectorTest(6, new BlowfishEngine(), + new KeyParameter(Hex.decode("7CA110454A1A6E57")), + "01A1D6D039776742", "59C68245EB05282B"), + new BlockCipherVectorTest(7, new BlowfishEngine(), + new KeyParameter(Hex.decode("0131D9619DC1376E")), + "5CD54CA83DEF57DA", "B1B8CC0B250F09A0"), + }; + + BlowfishTest() + { + super(tests, new BlowfishEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "Blowfish"; + } + + public static void main( + String[] args) + { + runTest(new BlowfishTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CAST5Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CAST5Test.java new file mode 100644 index 000000000..a74ad9647 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CAST5Test.java @@ -0,0 +1,44 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.CAST5Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * cast tester - vectors from http://www.ietf.org/rfc/rfc2144.txt + */ +public class CAST5Test + extends CipherTest +{ + static SimpleTest[] tests = { + new BlockCipherVectorTest(0, new CAST5Engine(), + new KeyParameter(Hex.decode("0123456712345678234567893456789A")), + "0123456789ABCDEF", + "238B4FE5847E44B2"), + new BlockCipherVectorTest(0, new CAST5Engine(), + new KeyParameter(Hex.decode("01234567123456782345")), + "0123456789ABCDEF", + "EB6A711A2C02271B"), + new BlockCipherVectorTest(0, new CAST5Engine(), + new KeyParameter(Hex.decode("0123456712")), + "0123456789ABCDEF", + "7Ac816d16E9B302E"), + }; + + CAST5Test() + { + super(tests, new CAST5Engine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "CAST5"; + } + + public static void main( + String[] args) + { + runTest(new CAST5Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CAST6Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CAST6Test.java new file mode 100644 index 000000000..ccb541387 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CAST6Test.java @@ -0,0 +1,44 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.CAST6Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * cast6 tester - vectors from http://www.ietf.org/rfc/rfc2612.txt + */ +public class CAST6Test + extends CipherTest +{ + static SimpleTest[] tests = { + new BlockCipherVectorTest(0, new CAST6Engine(), + new KeyParameter(Hex.decode("2342bb9efa38542c0af75647f29f615d")), + "00000000000000000000000000000000", + "c842a08972b43d20836c91d1b7530f6b"), + new BlockCipherVectorTest(0, new CAST6Engine(), + new KeyParameter(Hex.decode("2342bb9efa38542cbed0ac83940ac298bac77a7717942863")), + "00000000000000000000000000000000", + "1b386c0210dcadcbdd0e41aa08a7a7e8"), + new BlockCipherVectorTest(0, new CAST6Engine(), + new KeyParameter(Hex.decode("2342bb9efa38542cbed0ac83940ac2988d7c47ce264908461cc1b5137ae6b604")), + "00000000000000000000000000000000", + "4f6a2038286897b9c9870136553317fa") + }; + + CAST6Test() + { + super(tests, new CAST6Engine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "CAST6"; + } + + public static void main( + String[] args) + { + runTest(new CAST6Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CCMTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CCMTest.java new file mode 100644 index 000000000..a5ae696ea --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CCMTest.java @@ -0,0 +1,305 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.modes.CCMBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * First four test vectors from + * NIST Special Publication 800-38C. + */ +public class CCMTest + extends SimpleTest +{ + private byte[] K1 = Hex.decode("404142434445464748494a4b4c4d4e4f"); + private byte[] N1 = Hex.decode("10111213141516"); + private byte[] A1 = Hex.decode("0001020304050607"); + private byte[] P1 = Hex.decode("20212223"); + private byte[] C1 = Hex.decode("7162015b4dac255d"); + private byte[] T1 = Hex.decode("6084341b"); + + private byte[] K2 = Hex.decode("404142434445464748494a4b4c4d4e4f"); + private byte[] N2 = Hex.decode("1011121314151617"); + private byte[] A2 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + private byte[] P2 = Hex.decode("202122232425262728292a2b2c2d2e2f"); + private byte[] C2 = Hex.decode("d2a1f0e051ea5f62081a7792073d593d1fc64fbfaccd"); + private byte[] T2 = Hex.decode("7f479ffca464"); + + private byte[] K3 = Hex.decode("404142434445464748494a4b4c4d4e4f"); + private byte[] N3 = Hex.decode("101112131415161718191a1b"); + private byte[] A3 = Hex.decode("000102030405060708090a0b0c0d0e0f10111213"); + private byte[] P3 = Hex.decode("202122232425262728292a2b2c2d2e2f3031323334353637"); + private byte[] C3 = Hex.decode("e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5484392fbc1b09951"); + private byte[] T3 = Hex.decode("67c99240c7d51048"); + + private byte[] K4 = Hex.decode("404142434445464748494a4b4c4d4e4f"); + private byte[] N4 = Hex.decode("101112131415161718191a1b1c"); + private byte[] A4 = Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); + private byte[] P4 = Hex.decode("202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"); + private byte[] C4 = Hex.decode("69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72b4ac6bec93e8598e7f0dadbcea5b"); + private byte[] T4 = Hex.decode("f4dd5d0ee404617225ffe34fce91"); + + // + // long data vector + // + private byte[] C5 = Hex.decode("49b17d8d3ea4e6174a48e2b65e6d8b417ac0dd3f8ee46ce4a4a2a509661cef52528c1cd9805333a5cfd482fa3f095a3c2fdd1cc47771c5e55fddd60b5c8d6d3fa5c8dd79d08b16242b6642106e7c0c28bd1064b31e6d7c9800c8397dbc3fa8071e6a38278b386c18d65d39c6ad1ef9501a5c8f68d38eb6474799f3cc898b4b9b97e87f9c95ce5c51bc9d758f17119586663a5684e0a0daf6520ec572b87473eb141d10471e4799ded9e607655402eca5176bbf792ef39dd135ac8d710da8e9e854fd3b95c681023f36b5ebe2fb213d0b62dd6e9e3cfe190b792ccb20c53423b2dca128f861a61d306910e1af418839467e466f0ec361d2539eedd99d4724f1b51c07beb40e875a87491ec8b27cd1"); + private byte[] T5 = Hex.decode("5c768856796b627b13ec8641581b"); + + public void performTest() + throws Exception + { + CCMBlockCipher ccm = new CCMBlockCipher(new AESEngine()); + + checkVectors(0, ccm, K1, 32, N1, A1, P1, T1, C1); + checkVectors(1, ccm, K2, 48, N2, A2, P2, T2, C2); + checkVectors(2, ccm, K3, 64, N3, A3, P3, T3, C3); + + ivParamTest(0, ccm, K1, N1); + + // + // 4 has a reduced associated text which needs to be replicated + // + byte[] a4 = new byte[65536]; // 524288 / 8 + + for (int i = 0; i < a4.length; i += A4.length) + { + System.arraycopy(A4, 0, a4, i, A4.length); + } + + checkVectors(3, ccm, K4, 112, N4, a4, P4, T4, C4); + + // + // long data test + // + checkVectors(4, ccm, K4, 112, N4, A4, A4, T5, C5); + + // decryption with output specified, non-zero offset. + ccm.init(false, new AEADParameters(new KeyParameter(K2), 48, N2, A2)); + + byte[] inBuf = new byte[C2.length + 10]; + byte[] outBuf = new byte[ccm.getOutputSize(C2.length) + 10]; + + System.arraycopy(C2, 0, inBuf, 10, C2.length); + + int len = ccm.processPacket(inBuf, 10, C2.length, outBuf, 10); + byte[] out = ccm.processPacket(C2, 0, C2.length); + + if (len != out.length || !isEqual(out, outBuf, 10)) + { + fail("decryption output incorrect"); + } + + // encryption with output specified, non-zero offset. + ccm.init(true, new AEADParameters(new KeyParameter(K2), 48, N2, A2)); + + int inLen = len; + inBuf = outBuf; + outBuf = new byte[ccm.getOutputSize(inLen) + 10]; + + len = ccm.processPacket(inBuf, 10, inLen, outBuf, 10); + out = ccm.processPacket(inBuf, 10, inLen); + + if (len != out.length || !isEqual(out, outBuf, 10)) + { + fail("encryption output incorrect"); + } + + // + // exception tests + // + + try + { + ccm.init(false, new AEADParameters(new KeyParameter(K1), 32, N2, A2)); + + ccm.processPacket(C2, 0, C2.length); + + fail("invalid cipher text not picked up"); + } + catch (InvalidCipherTextException e) + { + // expected + } + + try + { + ccm = new CCMBlockCipher(new DESEngine()); + + fail("incorrect block size not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + ccm.init(false, new KeyParameter(K1)); + + fail("illegal argument not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + AEADTestUtil.testReset(this, new CCMBlockCipher(new AESEngine()), new CCMBlockCipher(new AESEngine()), new AEADParameters(new KeyParameter(K1), 32, N2)); + AEADTestUtil.testTampering(this, ccm, new AEADParameters(new KeyParameter(K1), 32, N2)); + AEADTestUtil.testOutputSizes(this, new CCMBlockCipher(new AESEngine()), new AEADParameters( + new KeyParameter(K1), 32, N2)); + AEADTestUtil.testBufferSizeChecks(this, new CCMBlockCipher(new AESEngine()), new AEADParameters( + new KeyParameter(K1), 32, N2)); + } + + private boolean isEqual(byte[] exp, byte[] other, int off) + { + for (int i = 0; i != exp.length; i++) + { + if (exp[i] != other[off + i]) + { + return false; + } + } + + return true; + } + + private void checkVectors( + int count, + CCMBlockCipher ccm, + byte[] k, + int macSize, + byte[] n, + byte[] a, + byte[] p, + byte[] t, + byte[] c) + throws InvalidCipherTextException + { + byte[] fa = new byte[a.length / 2]; + byte[] la = new byte[a.length - (a.length / 2)]; + System.arraycopy(a, 0, fa, 0, fa.length); + System.arraycopy(a, fa.length, la, 0, la.length); + + checkVectors(count, ccm, "all initial associated data", k, macSize, n, a, null, p, t, c); + checkVectors(count, ccm, "subsequent associated data", k, macSize, n, null, a, p, t, c); + checkVectors(count, ccm, "split associated data", k, macSize, n, fa, la, p, t, c); + checkVectors(count, ccm, "reuse key", null, macSize, n, fa, la, p, t, c); + } + + private void checkVectors( + int count, + CCMBlockCipher ccm, + String additionalDataType, + byte[] k, + int macSize, + byte[] n, + byte[] a, + byte[] sa, + byte[] p, + byte[] t, + byte[] c) + throws InvalidCipherTextException + { + KeyParameter keyParam = (k == null) ? null : new KeyParameter(k); + + ccm.init(true, new AEADParameters(keyParam, macSize, n, a)); + + byte[] enc = new byte[c.length]; + + if (sa != null) + { + ccm.processAADBytes(sa, 0, sa.length); + } + + int len = ccm.processBytes(p, 0, p.length, enc, 0); + + len += ccm.doFinal(enc, len); + + if (!areEqual(c, enc)) + { + fail("encrypted stream fails to match in test " + count + " with " + additionalDataType); + } + + ccm.init(false, new AEADParameters(keyParam, macSize, n, a)); + + byte[] tmp = new byte[enc.length]; + + if (sa != null) + { + ccm.processAADBytes(sa, 0, sa.length); + } + + len = ccm.processBytes(enc, 0, enc.length, tmp, 0); + + len += ccm.doFinal(tmp, len); + + byte[] dec = new byte[len]; + + System.arraycopy(tmp, 0, dec, 0, len); + + if (!areEqual(p, dec)) + { + fail("decrypted stream fails to match in test " + count + " with " + additionalDataType, + new String(Hex.encode(p)), new String(Hex.encode(dec))); + } + + if (!areEqual(t, ccm.getMac())) + { + fail("MAC fails to match in test " + count + " with " + additionalDataType); + } + } + + private void ivParamTest( + int count, + CCMBlockCipher ccm, + byte[] k, + byte[] n) + throws InvalidCipherTextException + { + byte[] p = Strings.toByteArray("hello world!!"); + + ccm.init(true, new ParametersWithIV(new KeyParameter(k), n)); + + byte[] enc = new byte[p.length + 8]; + + int len = ccm.processBytes(p, 0, p.length, enc, 0); + + len += ccm.doFinal(enc, len); + + ccm.init(false, new ParametersWithIV(new KeyParameter(k), n)); + + byte[] tmp = new byte[enc.length]; + + len = ccm.processBytes(enc, 0, enc.length, tmp, 0); + + len += ccm.doFinal(tmp, len); + + byte[] dec = new byte[len]; + + System.arraycopy(tmp, 0, dec, 0, len); + + if (!areEqual(p, dec)) + { + fail("decrypted stream fails to match in test " + count); + } + } + + public String getName() + { + return "CCM"; + } + + public static void main( + String[] args) + { + runTest(new CCMTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CMacTest.java new file mode 100644 index 000000000..2410d7732 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CMacTest.java @@ -0,0 +1,365 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.AESFastEngine; +import com.fr.third.org.bouncycastle.crypto.engines.BlowfishEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.engines.RijndaelEngine; +import com.fr.third.org.bouncycastle.crypto.engines.Shacal2Engine; +import com.fr.third.org.bouncycastle.crypto.macs.CMac; +import com.fr.third.org.bouncycastle.crypto.macs.CMacWithIV; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * CMAC tester - Official Test Vectors. + */ +public class CMacTest + extends SimpleTest +{ + private static final byte[] keyBytes128 = Hex.decode("2b7e151628aed2a6abf7158809cf4f3c"); + private static final byte[] keyBytes192 = Hex.decode( + "8e73b0f7da0e6452c810f32b809079e5" + + "62f8ead2522c6b7b"); + private static final byte[] keyBytes256 = Hex.decode( + "603deb1015ca71be2b73aef0857d7781" + + "1f352c073b6108d72d9810a30914dff4"); + + private static final byte[] input0 = Hex.decode(""); + private static final byte[] input16 = Hex.decode("6bc1bee22e409f96e93d7e117393172a"); + private static final byte[] input40 = Hex.decode( + "6bc1bee22e409f96e93d7e117393172a" + + "ae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411"); + private static final byte[] input64 = Hex.decode( + "6bc1bee22e409f96e93d7e117393172a" + + "ae2d8a571e03ac9c9eb76fac45af8e51" + + "30c81c46a35ce411e5fbc1191a0a52ef" + + "f69f2445df4f9b17ad2b417be66c3710"); + + private static final byte[] output_k128_m0 = Hex.decode("bb1d6929e95937287fa37d129b756746"); + private static final byte[] output_k128_m16 = Hex.decode("070a16b46b4d4144f79bdd9dd04a287c"); + private static final byte[] output_k128_m40 = Hex.decode("dfa66747de9ae63030ca32611497c827"); + private static final byte[] output_k128_m64 = Hex.decode("51f0bebf7e3b9d92fc49741779363cfe"); + + private static final byte[] output_k192_m0 = Hex.decode("d17ddf46adaacde531cac483de7a9367"); + private static final byte[] output_k192_m16 = Hex.decode("9e99a7bf31e710900662f65e617c5184"); + private static final byte[] output_k192_m40 = Hex.decode("8a1de5be2eb31aad089a82e6ee908b0e"); + private static final byte[] output_k192_m64 = Hex.decode("a1d5df0eed790f794d77589659f39a11"); + + private static final byte[] output_k256_m0 = Hex.decode("028962f61b7bf89efc6b551f4667d983"); + private static final byte[] output_k256_m16 = Hex.decode("28a7023f452e8f82bd4bf28d8c37c35c"); + private static final byte[] output_k256_m40 = Hex.decode("aaf3d8f1de5640c232f5b169b9c911e6"); + private static final byte[] output_k256_m64 = Hex.decode("e1992190549f6ed5696a2c056c315410"); + + private static final byte[] output_des_ede = Hex.decode("1ca670dea381d37c"); + + private static final byte[] general_input = Strings.toByteArray("The quick brown fox jumps over the lazy dog."); + + public CMacTest() + { + } + + public void performTest() + { + BlockCipher cipher = new AESFastEngine(); + Mac mac = new CMac(cipher, 128); + + //128 bytes key + + KeyParameter key = new KeyParameter(keyBytes128); + + // 0 bytes message - 128 bytes key + mac.init(key); + + mac.update(input0, 0, input0.length); + + byte[] out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m0)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m0)) + + " got " + new String(Hex.encode(out))); + } + + // 16 bytes message - 128 bytes key + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m16)) + + " got " + new String(Hex.encode(out))); + } + + // 40 bytes message - 128 bytes key + mac.init(key); + + mac.update(input40, 0, input40.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m40)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m40)) + + " got " + new String(Hex.encode(out))); + } + + // 64 bytes message - 128 bytes key + mac.init(key); + + mac.update(input64, 0, input64.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m64)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m64)) + + " got " + new String(Hex.encode(out))); + } + + //192 bytes key + + key = new KeyParameter(keyBytes192); + + // 0 bytes message - 192 bytes key + mac.init(key); + + mac.update(input0, 0, input0.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m0)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m0)) + + " got " + new String(Hex.encode(out))); + } + + // 16 bytes message - 192 bytes key + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m16)) + + " got " + new String(Hex.encode(out))); + } + + // 40 bytes message - 192 bytes key + mac.init(key); + + mac.update(input40, 0, input40.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m40)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m40)) + + " got " + new String(Hex.encode(out))); + } + + // 64 bytes message - 192 bytes key + mac.init(key); + + mac.update(input64, 0, input64.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m64)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m64)) + + " got " + new String(Hex.encode(out))); + } + + //256 bytes key + + key = new KeyParameter(keyBytes256); + + // 0 bytes message - 256 bytes key + mac.init(key); + + mac.update(input0, 0, input0.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m0)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m0)) + + " got " + new String(Hex.encode(out))); + } + + // 16 bytes message - 256 bytes key + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m16)) + + " got " + new String(Hex.encode(out))); + } + + // 40 bytes message - 256 bytes key + mac.init(key); + + mac.update(input40, 0, input40.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m40)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m40)) + + " got " + new String(Hex.encode(out))); + } + + // 64 bytes message - 256 bytes key + mac.init(key); + + mac.update(input64, 0, input64.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m64)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m64)) + + " got " + new String(Hex.encode(out))); + } + + // CMAC with IV + // 16 bytes message - 256 bytes key + mac = new CMacWithIV(new AESFastEngine()); + + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m16)) + + " got " + new String(Hex.encode(out))); + } + + // CMAC with IV + // 16 bytes message - 256 bytes key + mac = new CMacWithIV(new AESFastEngine()); + + mac.init(new ParametersWithIV(key, Hex.decode("000102030405060708090a0b0c0d0e0f"))); + + mac.update(input16, 0, input16.length); + + out = new byte[16]; + + mac.doFinal(out, 0); + + if (areEqual(out, output_k256_m16)) + { + fail("Failed - got " + new String(Hex.encode(output_k256_m16))); + } + + if (!areEqual(out, Hex.decode("9347a60c64061b9ff2a92522ca8e08fc"))) + { + fail("Failed - expected " + "9347a60c64061b9ff2a92522ca8e08fc" + + " got " + new String(Hex.encode(out))); + } + + testCMac(new DESedeEngine(), keyBytes128, input0, output_des_ede); + + testCMac(new RijndaelEngine(), "2b7e151628aed2a6abf7158809cf4f3c", "682b9b57e769cc63231cf778c5c76646"); + testCMac(new RijndaelEngine(192), "2b7e151628aed2a6abf7158809cf4f3c", "2a11b6bdd1e4f8b6127c2960859ae73ede59c7200d77ff45"); + testCMac(new RijndaelEngine(256), "2b7e151628aed2a6abf7158809cf4f3c", "316d1df4084ada3e10b26266ae1fdae170a9d824ab37e981f06227c80c80fddd"); + testCMac(new BlowfishEngine(), "2b7e151628aed2a6abf7158809cf4f3c", "875d73b9bc3de78a"); + testCMac(new DESEngine(), "2b7e151628aed2a6", "3cc3a242585e49f9"); + testCMac(new Shacal2Engine(), "2b7e151628aed2a6abf7158809cf4f3c", "794b2766cd0d550877f1ded48ab74f9ddff20f32e6d69fae8a1ede4205e7d640"); + + testExceptions(); + } + + private void testCMac(BlockCipher cipher, String keyBytes, String expected) + { + testCMac(cipher, Hex.decode(keyBytes), general_input, Hex.decode(expected)); + } + + private void testCMac(BlockCipher cipher, byte[] keyBytes, byte[] input, byte[] expected) + { + Mac mac = new CMac(cipher, cipher.getBlockSize() * 8); + + KeyParameter key = new KeyParameter(keyBytes); + + mac.init(key); + + mac.update(input, 0, input.length); + + byte[] out = new byte[mac.getMacSize()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, expected)) + { + fail("Failed - expected " + Strings.fromByteArray(Hex.encode(expected)) + " got " + new String(Hex.encode(out))); + } + } + + private void testExceptions() + { + try + { + CMac mac = new CMac(new AESEngine()); + mac.init(new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + fail("CMac does not accept IV"); + } catch(IllegalArgumentException e) + { + // Expected + } + } + + public String getName() + { + return "CMac"; + } + + public static void main(String[] args) + { + runTest(new CMacTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CSHAKETest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CSHAKETest.java new file mode 100644 index 000000000..029190fb5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CSHAKETest.java @@ -0,0 +1,193 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.CSHAKEDigest; +import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * CSHAKE test vectors from: + * + * https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/cSHAKE_samples.pdf + */ +public class CSHAKETest + extends SimpleTest +{ + public String getName() + { + return "CSHAKE"; + } + + public void performTest() + throws Exception + { + CSHAKEDigest cshake = new CSHAKEDigest(128, new byte[0], Strings.toByteArray("Email Signature")); + + cshake.update(Hex.decode("00010203"), 0, 4); + + byte[] res = new byte[32]; + + cshake.doOutput(res, 0, res.length); + + isTrue("oops!", Arrays.areEqual(Hex.decode("c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5"), res)); + + cshake = new CSHAKEDigest(128, new byte[0], Strings.toByteArray("Email Signature")); + + cshake.update(Hex.decode( + "000102030405060708090A0B0C0D0E0F" + + "101112131415161718191A1B1C1D1E1F" + + "202122232425262728292A2B2C2D2E2F" + + "303132333435363738393A3B3C3D3E3F" + + "404142434445464748494A4B4C4D4E4F" + + "505152535455565758595A5B5C5D5E5F" + + "606162636465666768696A6B6C6D6E6F" + + "707172737475767778797A7B7C7D7E7F" + + "808182838485868788898A8B8C8D8E8F" + + "909192939495969798999A9B9C9D9E9F" + + "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF" + + "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" + + "C0C1C2C3C4C5C6C7"), 0, 1600 / 8); + + res = new byte[32]; + + cshake.doOutput(res, 0, res.length); + + isTrue(Arrays.areEqual(Hex.decode("C5221D50E4F822D96A2E8881A961420F294B7B24FE3D2094BAED2C6524CC166B "), res)); + + cshake = new CSHAKEDigest(256, new byte[0], Strings.toByteArray("Email Signature")); + + cshake.update(Hex.decode("00010203"), 0, 4); + + res = new byte[64]; + + cshake.doOutput(res, 0, res.length); + + isTrue(Arrays.areEqual(Hex.decode( + "D008828E2B80AC9D2218FFEE1D070C48"+ + "B8E4C87BFF32C9699D5B6896EEE0EDD1"+ + "64020E2BE0560858D9C00C037E34A969"+ + "37C561A74C412BB4C746469527281C8C"),res)); + + cshake = new CSHAKEDigest(256, new byte[0], Strings.toByteArray("Email Signature")); + + cshake.update(Hex.decode( + "000102030405060708090A0B0C0D0E0F" + + "101112131415161718191A1B1C1D1E1F" + + "202122232425262728292A2B2C2D2E2F" + + "303132333435363738393A3B3C3D3E3F" + + "404142434445464748494A4B4C4D4E4F" + + "505152535455565758595A5B5C5D5E5F" + + "606162636465666768696A6B6C6D6E6F" + + "707172737475767778797A7B7C7D7E7F" + + "808182838485868788898A8B8C8D8E8F" + + "909192939495969798999A9B9C9D9E9F" + + "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF" + + "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF" + + "C0C1C2C3C4C5C6C7"), 0, 1600 / 8); + + res = new byte[64]; + + cshake.doOutput(res, 0, res.length); + + isTrue(Arrays.areEqual(Hex.decode( + "07DC27B11E51FBAC75BC7B3C1D983E8B"+ + "4B85FB1DEFAF218912AC864302730917"+ + "27F42B17ED1DF63E8EC118F04B23633C"+ + "1DFB1574C8FB55CB45DA8E25AFB092BB"), res)); + + doFinalTest(); + longBlockTest(); + + checkSHAKE(128, new CSHAKEDigest(128, new byte[0], new byte[0]), Hex.decode("eeaabeef")); + checkSHAKE(256, new CSHAKEDigest(256, new byte[0], null), Hex.decode("eeaabeef")); + checkSHAKE(128, new CSHAKEDigest(128, null, new byte[0]), Hex.decode("eeaabeef")); + checkSHAKE(128, new CSHAKEDigest(128, null, null), Hex.decode("eeaabeef")); + checkSHAKE(256, new CSHAKEDigest(256, null, null), Hex.decode("eeaabeef")); + } + + private void doFinalTest() + { + CSHAKEDigest cshake = new CSHAKEDigest(128, new byte[0], Strings.toByteArray("Email Signature")); + + cshake.update(Hex.decode("00010203"), 0, 4); + + byte[] res = new byte[32]; + + cshake.doOutput(res, 0, res.length); + + isTrue(Arrays.areEqual(Hex.decode("c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5"), res)); + + cshake.doOutput(res, 0, res.length); + + isTrue(!Arrays.areEqual(Hex.decode("c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5"), res)); + + cshake.doFinal(res, 0, res.length); + + cshake.update(Hex.decode("00010203"), 0, 4); + + cshake.doFinal(res, 0, res.length); + + isTrue(Arrays.areEqual(Hex.decode("c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5"), res)); + + cshake.update(Hex.decode("00010203"), 0, 4); + + cshake.doOutput(res, 0, res.length); + + isTrue(Arrays.areEqual(Hex.decode("c1c36925b6409a04f1b504fcbca9d82b4017277cb5ed2b2065fc1d3814d5aaf5"), res)); + + cshake.doFinal(res, 0, res.length); + + isTrue(Arrays.areEqual(Hex.decode("9cbce830079c452abdeb875366a49ebfe75b89ef17396e34898e904830b0e136"), res)); + } + + private void longBlockTest() + { + byte[] data = new byte[16000]; + byte[] res = new byte[32]; + + for (int i = 0; i != data.length; i++) + { + data[i] = (byte)i; + } + + for (int i = 10000; i != data.length; i++) + { + CSHAKEDigest cshake = new CSHAKEDigest(128, new byte[0], Arrays.copyOfRange(data, 0, i)); + + cshake.update(Hex.decode("00010203"), 0, 4); + + cshake.doFinal(res, 0); + } + + CSHAKEDigest cshake = new CSHAKEDigest(256, new byte[0], new byte[200]); + + cshake.update(Arrays.copyOfRange(data, 0, 200), 0, 200); + + cshake.doFinal(res, 0); + + isTrue(Arrays.areEqual(Hex.decode("4a899b5be460d85a9789215bc17f88b8f8ac049bd3b519f561e7b5d3870dafa3"), res)); + } + + private void checkSHAKE(int bitSize, CSHAKEDigest cshake, byte[] msg) + { + SHAKEDigest ref = new SHAKEDigest(bitSize); + + ref.update(msg, 0, msg.length); + cshake.update(msg, 0, msg.length); + + byte[] res1 = new byte[32]; + byte[] res2 = new byte[32]; + + ref.doFinal(res1, 0, res1.length); + cshake.doFinal(res2, 0, res2.length); + + isTrue(Arrays.areEqual(res1, res2)); + } + public static void main( + String[] args) + { + runTest(new CSHAKETest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CTSTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CTSTest.java new file mode 100644 index 000000000..debd14668 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CTSTest.java @@ -0,0 +1,218 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.SkipjackEngine; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CTSBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.OldCTSBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.SICBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * CTS tester + */ +public class CTSTest + extends SimpleTest +{ + static byte[] in1 = Hex.decode("4e6f7720697320746865207420"); + static byte[] in2 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f0aaa"); + static byte[] out1 = Hex.decode("9952f131588465033fa40e8a98"); + static byte[] out2 = Hex.decode("358f84d01eb42988dc34efb994"); + static byte[] out3 = Hex.decode("170171cfad3f04530c509b0c1f0be0aefbd45a8e3755a873bff5ea198504b71683c6"); + + private void testCTS( + int id, + BlockCipher cipher, + CipherParameters params, + byte[] input, + byte[] output) + throws Exception + { + byte[] out = new byte[input.length]; + BufferedBlockCipher engine = new CTSBlockCipher(cipher); + + engine.init(true, params); + + int len = engine.processBytes(input, 0, input.length, out, 0); + + engine.doFinal(out, len); + + if (!areEqual(output, out)) + { + fail("failed encryption expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + engine.init(false, params); + + len = engine.processBytes(output, 0, output.length, out, 0); + + engine.doFinal(out, len); + + if (!areEqual(input, out)) + { + fail("failed decryption expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + } + + private void testOldCTS( + int id, + BlockCipher cipher, + CipherParameters params, + byte[] input, + byte[] output) + throws Exception + { + byte[] out = new byte[input.length]; + BufferedBlockCipher engine = new OldCTSBlockCipher(cipher); + + engine.init(true, params); + + int len = engine.processBytes(input, 0, input.length, out, 0); + + engine.doFinal(out, len); + + if (!areEqual(output, out)) + { + fail("failed encryption expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + engine.init(false, params); + + len = engine.processBytes(output, 0, output.length, out, 0); + + engine.doFinal(out, len); + + if (!areEqual(input, out)) + { + fail("failed decryption expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + } + + private void testExceptions() throws InvalidCipherTextException + { + BufferedBlockCipher engine = new CTSBlockCipher(new DESEngine()); + CipherParameters params = new KeyParameter(new byte[engine.getBlockSize()]); + engine.init(true, params); + + byte[] out = new byte[engine.getOutputSize(engine.getBlockSize())]; + + engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0); + try + { + engine.doFinal(out, 0); + fail("Expected CTS encrypt error on < 1 block input"); + } catch(DataLengthException e) + { + // Expected + } + + engine.init(true, params); + engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0); + try + { + engine.doFinal(out, 0); + } catch(DataLengthException e) + { + fail("Unexpected CTS encrypt error on == 1 block input"); + } + + engine.init(false, params); + engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0); + try + { + engine.doFinal(out, 0); + fail("Expected CTS decrypt error on < 1 block input"); + } catch(DataLengthException e) + { + // Expected + } + + engine.init(false, params); + engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0); + try + { + engine.doFinal(out, 0); + } catch(DataLengthException e) + { + fail("Unexpected CTS decrypt error on == 1 block input"); + } + + try + { + new CTSBlockCipher(new SICBlockCipher(new AESEngine())); + fail("Expected CTS construction error - only ECB/CBC supported."); + } catch(IllegalArgumentException e) + { + // Expected + } + + } + + public String getName() + { + return "CTS"; + } + + public void performTest() + throws Exception + { + byte[] key1 = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF }; + byte[] key2 = { (byte)0x01, (byte)0x23, (byte)0x45, (byte)0x67, (byte)0x89, (byte)0xAB, (byte)0xCD, (byte)0xEF, (byte)0xee, (byte)0xff }; + byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + testCTS(1, new DESEngine(), new KeyParameter(key1), in1, out1); + testCTS(2, new CBCBlockCipher(new DESEngine()), new ParametersWithIV(new KeyParameter(key1), iv), in1, out2); + testCTS(3, new CBCBlockCipher(new SkipjackEngine()), new ParametersWithIV(new KeyParameter(key2), iv), in2, out3); + + // + // test vectors from rfc3962 + // + byte[] aes128 = Hex.decode("636869636b656e207465726979616b69"); + byte[] aesIn1 = Hex.decode("4920776f756c64206c696b652074686520"); + byte[] aesOut1 = Hex.decode("c6353568f2bf8cb4d8a580362da7ff7f97"); + byte[] aesIn2 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c20476175277320"); + byte[] aesOut2 = Hex.decode("fc00783e0efdb2c1d445d4c8eff7ed2297687268d6ecccc0c07b25e25ecfe5"); + byte[] aesIn3 = Hex.decode("4920776f756c64206c696b65207468652047656e6572616c2047617527732043"); + byte[] aesOut3 = Hex.decode("39312523a78662d5be7fcbcc98ebf5a897687268d6ecccc0c07b25e25ecfe584"); + + testCTS(4, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn1, aesOut1); + testCTS(5, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn2, aesOut2); + testCTS(6, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn3, aesOut3); + + testOldCTS(4, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn1, aesOut1); + testOldCTS(5, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn2, aesOut2); + testOldCTS(6, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aesIn3, aesOut3); + + byte[] aes1Block = Hex.decode("4920776f756c64206c696b6520746865"); + byte[] preErrata = Hex.decode("e7664c13ff28c965b0d2a0e7ec353706"); // CTS style one block + byte[] pstErrata = Hex.decode("97687268d6ecccc0c07b25e25ecfe584"); // CBC style one block + byte[] pstErrataNonZeroIV = Hex.decode("571f5108c53fe95ab52df783df933fa3"); + + testCTS(7, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aes1Block, pstErrata); + testCTS(8, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), aes1Block), aes1Block, pstErrataNonZeroIV); + testOldCTS(9, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128), new byte[16]), aes1Block, preErrata); + + byte[] aes128b = Hex.decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f6"); + byte[] aesIn1b = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); + byte[] aesOut1b = Hex.decode("6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04"); + + testCTS(10, new CBCBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(aes128b), Hex.decode("aafd12f659cae63489b479e5076ddec2")), aesIn1b, aesOut1b); + + testExceptions(); + } + + public static void main( + String[] args) + { + runTest(new CTSTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CamelliaLightTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CamelliaLightTest.java new file mode 100644 index 000000000..1d748d603 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CamelliaLightTest.java @@ -0,0 +1,66 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.CamelliaLightEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Camellia tester - vectors from https://www.cosic.esat.kuleuven.be/nessie/testvectors/ and RFC 3713 + */ +public class CamelliaLightTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "80000000000000000000000000000000", "07923A39EB0A817D1C4D87BDB82D1F1C"), + new BlockCipherVectorTest(1, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "6C227F749319A3AA7DA235A9BBA05A2C"), + new BlockCipherVectorTest(2, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba9876543210")), + "0123456789abcdeffedcba9876543210", "67673138549669730857065648eabe43"), + // + // 192 bit + // + new BlockCipherVectorTest(3, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba98765432100011223344556677")), + "0123456789abcdeffedcba9876543210", "b4993401b3e996f84ee5cee7d79b09b9"), + new BlockCipherVectorTest(4, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "00040000000000000000000000000000", "9BCA6C88B928C1B0F57F99866583A9BC"), + new BlockCipherVectorTest(5, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("949494949494949494949494949494949494949494949494")), + "636EB22D84B006381235641BCF0308D2", "94949494949494949494949494949494"), + // + // 256 bit + // + new BlockCipherVectorTest(6, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff")), + "0123456789abcdeffedcba9876543210", "9acc237dff16d76c20ef7c919e3a7509"), + new BlockCipherVectorTest(7, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A")), + "057764FE3A500EDBD988C5C3B56CBA9A", "4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A"), + new BlockCipherVectorTest(8, new CamelliaLightEngine(), + new KeyParameter(Hex.decode("0303030303030303030303030303030303030303030303030303030303030303")), + "7968B08ABA92193F2295121EF8D75C8A", "03030303030303030303030303030303"), + }; + + CamelliaLightTest() + { + super(tests, new CamelliaLightEngine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "CamelliaLight"; + } + + public static void main( + String[] args) + { + runTest(new CamelliaLightTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CamelliaTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CamelliaTest.java new file mode 100644 index 000000000..5fa699e3b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CamelliaTest.java @@ -0,0 +1,70 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.CamelliaEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * Camellia tester - vectors from https://www.cosic.esat.kuleuven.be/nessie/testvectors/ and RFC 3713 + */ +public class CamelliaTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new CamelliaEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "80000000000000000000000000000000", "07923A39EB0A817D1C4D87BDB82D1F1C"), + new BlockCipherVectorTest(1, new CamelliaEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "6C227F749319A3AA7DA235A9BBA05A2C"), + new BlockCipherVectorTest(2, new CamelliaEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba9876543210")), + "0123456789abcdeffedcba9876543210", "67673138549669730857065648eabe43"), + // + // 192 bit + // + new BlockCipherVectorTest(3, new CamelliaEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba98765432100011223344556677")), + "0123456789abcdeffedcba9876543210", "b4993401b3e996f84ee5cee7d79b09b9"), + new BlockCipherVectorTest(4, new CamelliaEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "00040000000000000000000000000000", "9BCA6C88B928C1B0F57F99866583A9BC"), + new BlockCipherVectorTest(5, new CamelliaEngine(), + new KeyParameter(Hex.decode("949494949494949494949494949494949494949494949494")), + "636EB22D84B006381235641BCF0308D2", "94949494949494949494949494949494"), + // + // 256 bit + // + new BlockCipherVectorTest(6, new CamelliaEngine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff")), + "0123456789abcdeffedcba9876543210", "9acc237dff16d76c20ef7c919e3a7509"), + new BlockCipherVectorTest(7, new CamelliaEngine(), + new KeyParameter(Hex.decode("4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A")), + "057764FE3A500EDBD988C5C3B56CBA9A", "4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A"), + new BlockCipherVectorTest(8, new CamelliaEngine(), + new KeyParameter(Hex.decode("0303030303030303030303030303030303030303030303030303030303030303")), + "7968B08ABA92193F2295121EF8D75C8A", "03030303030303030303030303030303"), + }; + + CamelliaTest() + { + super(tests, new CamelliaEngine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "Camellia"; + } + + public static void main( + String[] args) + { + CamelliaTest test = new CamelliaTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ChaCha20Poly1305Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ChaCha20Poly1305Test.java new file mode 100644 index 000000000..a9eafd960 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ChaCha20Poly1305Test.java @@ -0,0 +1,433 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.macs.SipHash; +import com.fr.third.org.bouncycastle.crypto.modes.ChaCha20Poly1305; +import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.Times; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ChaCha20Poly1305Test + extends SimpleTest +{ + private static final String[][] TEST_VECTORS = new String[][] { + { + "Test Case 1", + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", + "4c616469657320616e642047656e746c" + + "656d656e206f662074686520636c6173" + + "73206f66202739393a20496620492063" + + "6f756c64206f6666657220796f75206f" + + "6e6c79206f6e652074697020666f7220" + + "746865206675747572652c2073756e73" + + "637265656e20776f756c642062652069" + + "742e", + "50515253c0c1c2c3c4c5c6c7", + "070000004041424344454647", + "d31a8d34648e60db7b86afbc53ef7ec2" + + "a4aded51296e08fea9e2b5a736ee62d6" + + "3dbea45e8ca9671282fafb69da92728b" + + "1a71de0a9e060b2905d6a5b67ecd3b36" + + "92ddbd7f2d778b8c9803aee328091b58" + + "fab324e4fad675945585808b4831d7bc" + + "3ff4def08e4b7a9de576d26586cec64b" + + "6116", + "1ae10b594f09e26a7e902ecbd0600691", + }, + }; + + public String getName() + { + return "ChaCha20Poly1305"; + } + + public void performTest() throws Exception + { + for (int i = 0; i < TEST_VECTORS.length; ++i) + { + runTestCase(TEST_VECTORS[i]); + } + + outputSizeTests(); + randomTests(); + testExceptions(); + } + + private void checkTestCase( + ChaCha20Poly1305 encCipher, + ChaCha20Poly1305 decCipher, + String testName, + byte[] SA, + byte[] P, + byte[] C, + byte[] T) + throws InvalidCipherTextException + { + byte[] enc = new byte[encCipher.getOutputSize(P.length)]; + if (SA != null) + { + encCipher.processAADBytes(SA, 0, SA.length); + } + int len = encCipher.processBytes(P, 0, P.length, enc, 0); + len += encCipher.doFinal(enc, len); + + if (enc.length != len) + { + fail("encryption reported incorrect length: " + testName); + } + + byte[] mac = encCipher.getMac(); + + byte[] data = new byte[P.length]; + System.arraycopy(enc, 0, data, 0, data.length); + byte[] tail = new byte[enc.length - P.length]; + System.arraycopy(enc, P.length, tail, 0, tail.length); + + if (!areEqual(C, data)) + { + fail("incorrect encrypt in: " + testName); + } + + if (!areEqual(T, mac)) + { + fail("getMac() returned wrong mac in: " + testName); + } + + if (!areEqual(T, tail)) + { + fail("stream contained wrong mac in: " + testName); + } + + byte[] dec = new byte[decCipher.getOutputSize(enc.length)]; + if (SA != null) + { + decCipher.processAADBytes(SA, 0, SA.length); + } + len = decCipher.processBytes(enc, 0, enc.length, dec, 0); + len += decCipher.doFinal(dec, len); + mac = decCipher.getMac(); + + data = new byte[C.length]; + System.arraycopy(dec, 0, data, 0, data.length); + + if (!areEqual(P, data)) + { + fail("incorrect decrypt in: " + testName); + } + } + + private ChaCha20Poly1305 initCipher(boolean forEncryption, AEADParameters parameters) + { + ChaCha20Poly1305 c = new ChaCha20Poly1305(); + c.init(forEncryption, parameters); + return c; + } + + private static int nextInt(SecureRandom rand, int n) + { + if ((n & -n) == n) // i.e., n is a power of 2 + { + return (int)((n * (long)(rand.nextInt() >>> 1)) >> 31); + } + + int bits, value; + do + { + bits = rand.nextInt() >>> 1; + value = bits % n; + } + while (bits - value + (n - 1) < 0); + + return value; + } + + private void outputSizeTests() + { + byte[] K = new byte[32]; + byte[] A = null; + byte[] N = new byte[12]; + + AEADParameters parameters = new AEADParameters(new KeyParameter(K), 16 * 8, N, A); + ChaCha20Poly1305 cipher = initCipher(true, parameters); + + if (cipher.getUpdateOutputSize(0) != 0) + { + fail("incorrect getUpdateOutputSize for initial 0 bytes encryption"); + } + + if (cipher.getOutputSize(0) != 16) + { + fail("incorrect getOutputSize for initial 0 bytes encryption"); + } + + cipher.init(false, parameters); + + if (cipher.getUpdateOutputSize(0) != 0) + { + fail("incorrect getUpdateOutputSize for initial 0 bytes decryption"); + } + + // NOTE: 0 bytes would be truncated data, but we want it to fail in the doFinal, not here + if (cipher.getOutputSize(0) != 0) + { + fail("fragile getOutputSize for initial 0 bytes decryption"); + } + + if (cipher.getOutputSize(16) != 0) + { + fail("incorrect getOutputSize for initial MAC-size bytes decryption"); + } + } + + private void randomTests() throws InvalidCipherTextException + { + SecureRandom random = new SecureRandom(); + random.setSeed(Times.nanoTime()); + + for (int i = 0; i < 10; ++i) + { + randomTest(random); + } + } + + private void randomTest(SecureRandom random) throws InvalidCipherTextException + { + int kLength = 32; + byte[] K = new byte[kLength]; + random.nextBytes(K); + + int pLength = random.nextInt() >>> 16; + byte[] P = new byte[pLength]; + random.nextBytes(P); + + int aLength = random.nextInt() >>> 24; + byte[] A = new byte[aLength]; + random.nextBytes(A); + + int saLength = random.nextInt() >>> 24; + byte[] SA = new byte[saLength]; + random.nextBytes(SA); + + int nonceLength = 12; + byte[] nonce = new byte[nonceLength]; + random.nextBytes(nonce); + + AEADParameters parameters = new AEADParameters(new KeyParameter(K), 16 * 8, nonce, A); + ChaCha20Poly1305 cipher = initCipher(true, parameters); + byte[] C = new byte[cipher.getOutputSize(P.length)]; + int predicted = cipher.getUpdateOutputSize(P.length); + + int split = nextInt(random, SA.length + 1); + cipher.processAADBytes(SA, 0, split); + cipher.processAADBytes(SA, split, SA.length - split); + + int len = cipher.processBytes(P, 0, P.length, C, 0); + if (predicted != len) + { + fail("encryption reported incorrect update length in randomised test"); + } + + len += cipher.doFinal(C, len); + if (C.length != len) + { + fail("encryption reported incorrect length in randomised test"); + } + + byte[] encT = cipher.getMac(); + byte[] tail = new byte[C.length - P.length]; + System.arraycopy(C, P.length, tail, 0, tail.length); + + if (!areEqual(encT, tail)) + { + fail("stream contained wrong mac in randomised test"); + } + + cipher.init(false, parameters); + byte[] decP = new byte[cipher.getOutputSize(C.length)]; + predicted = cipher.getUpdateOutputSize(C.length); + + split = nextInt(random, SA.length + 1); + cipher.processAADBytes(SA, 0, split); + cipher.processAADBytes(SA, split, SA.length - split); + + len = cipher.processBytes(C, 0, C.length, decP, 0); + if (predicted != len) + { + fail("decryption reported incorrect update length in randomised test"); + } + + len += cipher.doFinal(decP, len); + + if (!areEqual(P, decP)) + { + fail("incorrect decrypt in randomised test"); + } + + byte[] decT = cipher.getMac(); + if (!areEqual(encT, decT)) + { + fail("decryption produced different mac from encryption"); + } + + // + // key reuse test + // + cipher.init(false, AEADTestUtil.reuseKey(parameters)); + decP = new byte[cipher.getOutputSize(C.length)]; + + split = nextInt(random, SA.length + 1); + cipher.processAADBytes(SA, 0, split); + cipher.processAADBytes(SA, split, SA.length - split); + + len = cipher.processBytes(C, 0, C.length, decP, 0); + len += cipher.doFinal(decP, len); + + if (!areEqual(P, decP)) + { + fail("incorrect decrypt in randomised test"); + } + + decT = cipher.getMac(); + if (!areEqual(encT, decT)) + { + fail("decryption produced different mac from encryption"); + } + } + + private void runTestCase(String[] testVector) + throws InvalidCipherTextException + { + int pos = 0; + String testName = testVector[pos++]; + byte[] K = Hex.decode(testVector[pos++]); + byte[] P = Hex.decode(testVector[pos++]); + byte[] A = Hex.decode(testVector[pos++]); + byte[] N = Hex.decode(testVector[pos++]); + byte[] C = Hex.decode(testVector[pos++]); + byte[] T = Hex.decode(testVector[pos++]); + + runTestCase(testName, K, N, A, P, C, T); + } + + private void runTestCase( + String testName, + byte[] K, + byte[] N, + byte[] A, + byte[] P, + byte[] C, + byte[] T) + throws InvalidCipherTextException + { + byte[] fa = new byte[A.length / 2]; + byte[] la = new byte[A.length - (A.length / 2)]; + System.arraycopy(A, 0, fa, 0, fa.length); + System.arraycopy(A, fa.length, la, 0, la.length); + + runTestCase(testName + " all initial associated data", K, N, A, null, P, C, T); + runTestCase(testName + " all subsequent associated data", K, N, null, A, P, C, T); + runTestCase(testName + " split associated data", K, N, fa, la, P, C, T); + } + + private void runTestCase( + String testName, + byte[] K, + byte[] N, + byte[] A, + byte[] SA, + byte[] P, + byte[] C, + byte[] T) + throws InvalidCipherTextException + { + AEADParameters parameters = new AEADParameters(new KeyParameter(K), T.length * 8, N, A); + ChaCha20Poly1305 encCipher = initCipher(true, parameters); + ChaCha20Poly1305 decCipher = initCipher(false, parameters); + checkTestCase(encCipher, decCipher, testName, SA, P, C, T); + encCipher = initCipher(true, parameters); + checkTestCase(encCipher, decCipher, testName + " (reused)", SA, P, C, T); + + // Key reuse + AEADParameters keyReuseParams = AEADTestUtil.reuseKey(parameters); + + try + { + encCipher.init(true, keyReuseParams); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isTrue("wrong message", "cannot reuse nonce for ChaCha20Poly1305 encryption".equals(e.getMessage())); + } + } + + private void testExceptions() throws InvalidCipherTextException + { + ChaCha20Poly1305 c = new ChaCha20Poly1305(); + + try + { + c = new ChaCha20Poly1305(new SipHash()); + + fail("incorrect mac size not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + c.init(false, new KeyParameter(new byte[32])); + + fail("illegal argument not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + AEADTestUtil.testTampering(this, c, new AEADParameters(new KeyParameter(new byte[32]), 128, new byte[12])); + + byte[] P = Strings.toByteArray("Hello world!"); + byte[] buf = new byte[100]; + + c = new ChaCha20Poly1305(); + AEADParameters aeadParameters = new AEADParameters(new KeyParameter(new byte[32]), 128, new byte[12]); + c.init(true, aeadParameters); + + c.processBytes(P, 0, P.length, buf, 0); + + c.doFinal(buf, 0); + + try + { + c.doFinal(buf, 0); + fail("no exception on reuse"); + } + catch (IllegalStateException e) + { + isTrue("wrong message", e.getMessage().equals("ChaCha20Poly1305 cannot be reused for encryption")); + } + + try + { + c.init(true, aeadParameters); + fail("no exception on reuse"); + } + catch (IllegalArgumentException e) + { + isTrue("wrong message", e.getMessage().equals("cannot reuse nonce for ChaCha20Poly1305 encryption")); + } + } + + public static void main(String[] args) + { + runTest(new ChaCha20Poly1305Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ChaChaTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ChaChaTest.java new file mode 100644 index 000000000..f338161e5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ChaChaTest.java @@ -0,0 +1,403 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.engines.ChaChaEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * ChaCha Test + *

+ * Test cases generated using ref version of ChaCha20 in estreambench-20080905. + */ +public class ChaChaTest + extends SimpleTest +{ + byte[] zeroes = Hex.decode( + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"); + + String set1v0_0 = "FBB87FBB8395E05DAA3B1D683C422046" + + "F913985C2AD9B23CFC06C1D8D04FF213" + + "D44A7A7CDB84929F915420A8A3DC58BF" + + "0F7ECB4B1F167BB1A5E6153FDAF4493D"; + + String set1v0_192 = "D9485D55B8B82D792ED1EEA8E93E9BC1" + + "E2834AD0D9B11F3477F6E106A2F6A5F2" + + "EA8244D5B925B8050EAB038F58D4DF57" + + "7FAFD1B89359DAE508B2B10CBD6B488E"; + + String set1v0_256 = "08661A35D6F02D3D9ACA8087F421F7C8" + + "A42579047D6955D937925BA21396DDD4" + + "74B1FC4ACCDCAA33025B4BCE817A4FBF" + + "3E5D07D151D7E6FE04934ED466BA4779"; + + String set1v0_448 = "A7E16DD38BA48CCB130E5BE9740CE359" + + "D631E91600F85C8A5D0785A612D1D987" + + "90780ACDDC26B69AB106CCF6D866411D" + + "10637483DBF08CC5591FD8B3C87A3AE0"; + + String set1v9_0 = "A276339F99316A913885A0A4BE870F06" + + "91E72B00F1B3F2239F714FE81E88E00C" + + "BBE52B4EBBE1EA15894E29658C4CB145" + + "E6F89EE4ABB045A78514482CE75AFB7C"; + + String set1v9_192 = "0DFB9BD4F87F68DE54FBC1C6428FDEB0" + + "63E997BE8490C9B7A4694025D6EBA2B1" + + "5FE429DB82A7CAE6AAB22918E8D00449" + + "6FB6291467B5AE81D4E85E81D8795EBB"; + + String set1v9_256 = "546F5BB315E7F71A46E56D4580F90889" + + "639A2BA528F757CF3B048738BA141AF3" + + "B31607CB21561BAD94721048930364F4" + + "B1227CFEB7CDECBA881FB44903550E68"; + + String set1v9_448 = "6F813586E76691305A0CF048C0D8586D" + + "C89460207D8B230CD172398AA33D19E9" + + "2D24883C3A9B0BB7CD8C6B2668DB142E" + + "37A97948A7A01498A21110297984CD20"; + + String set6v0_0 = "57459975BC46799394788DE80B928387" + + "862985A269B9E8E77801DE9D874B3F51" + + "AC4610B9F9BEE8CF8CACD8B5AD0BF17D" + + "3DDF23FD7424887EB3F81405BD498CC3"; + + String set6v0_65472 = "EF9AEC58ACE7DB427DF012B2B91A0C1E" + + "8E4759DCE9CDB00A2BD59207357BA06C" + + "E02D327C7719E83D6348A6104B081DB0" + + "3908E5186986AE41E3AE95298BB7B713"; + + String set6v0_65536 = "17EF5FF454D85ABBBA280F3A94F1D26E" + + "950C7D5B05C4BB3A78326E0DC5731F83" + + "84205C32DB867D1B476CE121A0D7074B" + + "AA7EE90525D15300F48EC0A6624BD0AF"; + + String set6v1_0 = "92A2508E2C4084567195F2A1005E552B" + + "4874EC0504A9CD5E4DAF739AB553D2E7" + + "83D79C5BA11E0653BEBB5C116651302E" + + "8D381CB728CA627B0B246E83942A2B99"; + + String set6v1_65472 = "E1974EC3063F7BD0CBA58B1CE34BC874" + + "67AAF5759B05EA46682A5D4306E5A76B" + + "D99A448DB8DE73AF97A73F5FBAE2C776" + + "35040464524CF14D7F08D4CE1220FD84"; + + String set6v1_65536 = "BE3436141CFD62D12FF7D852F80C1344" + + "81F152AD0235ECF8CA172C55CA8C031B" + + "2E785D773A988CA8D4BDA6FAE0E493AA" + + "71DCCC4C894D1F106CAC62A9FC0A9607"; + + // ChaCha12 + String chacha12_set1v0_0 = "36CF0D56E9F7FBF287BC5460D95FBA94" + + "AA6CBF17D74E7C784DDCF7E0E882DDAE" + + "3B5A58243EF32B79A04575A8E2C2B73D" + + "C64A52AA15B9F88305A8F0CA0B5A1A25"; + + String chacha12_set1v0_192 = "83496792AB68FEC75ADB16D3044420A4" + + "A00A6E9ADC41C3A63DBBF317A8258C85" + + "A9BC08B4F76B413A4837324AEDF8BC2A" + + "67D53C9AB9E1C5BC5F379D48DF9AF730"; + + String chacha12_set1v0_256 = "BAA28ED593690FD760ADA07C95E3B888" + + "4B4B64E488CA7A2D9BDC262243AB9251" + + "394C5037E255F8BCCDCD31306C508FFB" + + "C9E0161380F7911FCB137D46D9269250"; + + String chacha12_set1v0_448 = "B7ECFB6AE0B51915762FE1FD03A14D0C" + + "9E54DA5DC76EB16EBA5313BC535DE63D" + + "C72D7F9F1874E301E99C8531819F4E37" + + "75793F6A5D19C717FA5C78A39EB804A6"; + + // ChaCha8 + String chacha8_set1v0_0 = "BEB1E81E0F747E43EE51922B3E87FB38" + + "D0163907B4ED49336032AB78B67C2457" + + "9FE28F751BD3703E51D876C017FAA435" + + "89E63593E03355A7D57B2366F30047C5"; + + String chacha8_set1v0_192 = "33B8B7CA8F8E89F0095ACE75A379C651" + + "FD6BDD55703C90672E44C6BAB6AACDD8" + + "7C976A87FD264B906E749429284134C2" + + "38E3B88CF74A68245B860D119A8BDF43"; + + String chacha8_set1v0_256 = "F7CA95BF08688BD3BE8A27724210F9DC" + + "16F32AF974FBFB09E9F757C577A245AB" + + "F35F824B70A4C02CB4A8D7191FA8A5AD" + + "6A84568743844703D353B7F00A8601F4"; + + String chacha8_set1v0_448 = "7B4117E8BFFD595CD8482270B08920FB" + + "C9B97794E1809E07BB271BF07C861003" + + "4C38DBA6ECA04E5474F399A284CBF6E2" + + "7F70142E604D0977797DE5B58B6B25E0"; + + + + public String getName() + { + return "ChaCha"; + } + + public void performTest() + { + chachaTest1(20, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + set1v0_0, set1v0_192, set1v0_256, set1v0_448); + chachaTest1(20, new ParametersWithIV(new KeyParameter(Hex.decode("00400000000000000000000000000000")), Hex.decode("0000000000000000")), + set1v9_0, set1v9_192, set1v9_256, set1v9_448); + chachaTest1(12, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + chacha12_set1v0_0, chacha12_set1v0_192, chacha12_set1v0_256, chacha12_set1v0_448); + chachaTest1(8, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + chacha8_set1v0_0, chacha8_set1v0_192, chacha8_set1v0_256, chacha8_set1v0_448); + chachaTest2(new ParametersWithIV(new KeyParameter(Hex.decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.decode("0D74DB42A91077DE")), + set6v0_0, set6v0_65472, set6v0_65536); + chachaTest2(new ParametersWithIV(new KeyParameter(Hex.decode("0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12")), Hex.decode("167DE44BB21980E7")), + set6v1_0, set6v1_65472, set6v1_65536); + reinitBug(); + skipTest(); + } + + private void chachaTest1(int rounds, CipherParameters params, String v0, String v192, String v256, String v448) + { + StreamCipher chaCha = new ChaChaEngine(rounds); + byte[] buf = new byte[64]; + + chaCha.init(true, params); + + for (int i = 0; i != 7; i++) + { + chaCha.processBytes(zeroes, 0, 64, buf, 0); + switch (i) + { + case 0: + if (!areEqual(buf, Hex.decode(v0))) + { + mismatch("v0/" + rounds, v0, buf); + } + break; + case 3: + if (!areEqual(buf, Hex.decode(v192))) + { + mismatch("v192/" + rounds, v192, buf); + } + break; + case 4: + if (!areEqual(buf, Hex.decode(v256))) + { + mismatch("v256/" + rounds, v256, buf); + } + break; + default: + // ignore + } + } + + for (int i = 0; i != 64; i++) + { + buf[i] = chaCha.returnByte(zeroes[i]); + } + + if (!areEqual(buf, Hex.decode(v448))) + { + mismatch("v448", v448, buf); + } + } + + private void chachaTest2(CipherParameters params, String v0, String v65472, String v65536) + { + StreamCipher chaCha = new ChaChaEngine(); + byte[] buf = new byte[64]; + + chaCha.init(true, params); + + for (int i = 0; i != 1025; i++) + { + chaCha.processBytes(zeroes, 0, 64, buf, 0); + switch (i) + { + case 0: + if (!areEqual(buf, Hex.decode(v0))) + { + mismatch("v0", v0, buf); + } + break; + case 1023: + if (!areEqual(buf, Hex.decode(v65472))) + { + mismatch("v65472", v65472, buf); + } + break; + case 1024: + if (!areEqual(buf, Hex.decode(v65536))) + { + mismatch("v65536", v65536, buf); + } + break; + default: + // ignore + } + } + } + + private void mismatch(String name, String expected, byte[] found) + { + fail("mismatch on " + name, expected, new String(Hex.encode(found))); + } + + + private void reinitBug() + { + KeyParameter key = new KeyParameter(Hex.decode("80000000000000000000000000000000")); + ParametersWithIV parameters = new ParametersWithIV(key, Hex.decode("0000000000000000")); + + StreamCipher salsa = new ChaChaEngine(); + + salsa.init(true, parameters); + + try + { + salsa.init(true, key); + fail("Salsa20 should throw exception if no IV in Init"); + } + catch (IllegalArgumentException e) + { + } + } + + private boolean areEqual(byte[] a, int aOff, byte[] b, int bOff) + { + for (int i = bOff; i != b.length; i++) + { + if (a[aOff + i - bOff] != b[i]) + { + return false; + } + } + + return true; + } + + private void skipTest() + { + SecureRandom rand = new SecureRandom(); + byte[] plain = new byte[5000]; + byte[] cipher = new byte[5000]; + + rand.nextBytes(plain); + + CipherParameters params = new ParametersWithIV(new KeyParameter(Hex.decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.decode("0D74DB42A91077DE")); + ChaChaEngine engine = new ChaChaEngine(); + + engine.init(true, params); + + engine.processBytes(plain, 0, plain.length, cipher, 0); + + byte[] fragment = new byte[20]; + + engine.init(true, params); + + engine.skip(10); + + engine.processBytes(plain, 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 10, fragment, 0)) + { + fail("skip forward 10 failed"); + } + + engine.skip(1000); + + engine.processBytes(plain, 1010 + fragment.length, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + fragment.length, fragment, 0)) + { + fail("skip forward 1000 failed"); + } + + engine.skip(-10); + + engine.processBytes(plain, 1010 + 2 * fragment.length - 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + 2 * fragment.length - 10, fragment, 0)) + { + fail("skip back 10 failed"); + } + + engine.skip(-1000); + + if (engine.getPosition() != 60) + { + fail("skip position incorrect - " + 60 + " got " + engine.getPosition()); + } + + engine.processBytes(plain, 60, fragment.length, fragment, 0); + + if (!areEqual(cipher, 60, fragment, 0)) + { + fail("skip back 1000 failed"); + } + + long pos = engine.seekTo(1010); + if (pos != 1010) + { + fail("position wrong"); + } + + engine.processBytes(plain, 1010, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010, fragment, 0)) + { + fail("seek to 1010 failed"); + } + + engine.reset(); + + for (int i = 0; i != 1000; i++) + { + engine.skip(i); + + if (engine.getPosition() != i) + { + fail("skip forward at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip forward i failed: " + i); + } + + if (engine.getPosition() != i + fragment.length) + { + fail("cipher at wrong position: " + engine.getPosition() + " [" + i + "]"); + } + + engine.skip(-fragment.length); + + if (engine.getPosition() != i) + { + fail("skip back at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip back i failed: " + i); + } + + engine.reset(); + } + } + + public static void main( + String[] args) + { + runTest(new ChaChaTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CipherStreamTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CipherStreamTest.java new file mode 100644 index 000000000..65d4256e2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CipherStreamTest.java @@ -0,0 +1,706 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.BlowfishEngine; +import com.fr.third.org.bouncycastle.crypto.engines.CAST5Engine; +import com.fr.third.org.bouncycastle.crypto.engines.CAST6Engine; +import com.fr.third.org.bouncycastle.crypto.engines.CamelliaEngine; +import com.fr.third.org.bouncycastle.crypto.engines.ChaChaEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.engines.Grain128Engine; +import com.fr.third.org.bouncycastle.crypto.engines.Grainv1Engine; +import com.fr.third.org.bouncycastle.crypto.engines.HC128Engine; +import com.fr.third.org.bouncycastle.crypto.engines.HC256Engine; +import com.fr.third.org.bouncycastle.crypto.engines.NoekeonEngine; +import com.fr.third.org.bouncycastle.crypto.engines.RC2Engine; +import com.fr.third.org.bouncycastle.crypto.engines.RC4Engine; +import com.fr.third.org.bouncycastle.crypto.engines.RC6Engine; +import com.fr.third.org.bouncycastle.crypto.engines.SEEDEngine; +import com.fr.third.org.bouncycastle.crypto.engines.Salsa20Engine; +import com.fr.third.org.bouncycastle.crypto.engines.SerpentEngine; +import com.fr.third.org.bouncycastle.crypto.engines.TEAEngine; +import com.fr.third.org.bouncycastle.crypto.engines.ThreefishEngine; +import com.fr.third.org.bouncycastle.crypto.engines.TwofishEngine; +import com.fr.third.org.bouncycastle.crypto.engines.XSalsa20Engine; +import com.fr.third.org.bouncycastle.crypto.engines.XTEAEngine; +import com.fr.third.org.bouncycastle.crypto.io.CipherInputStream; +import com.fr.third.org.bouncycastle.crypto.io.CipherOutputStream; +import com.fr.third.org.bouncycastle.crypto.io.InvalidCipherTextIOException; +import com.fr.third.org.bouncycastle.crypto.modes.AEADBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CCMBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CTSBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.EAXBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.NISTCTSBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.OCBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.OFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.SICBlockCipher; +import com.fr.third.org.bouncycastle.crypto.paddings.PKCS7Padding; +import com.fr.third.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class CipherStreamTest + extends SimpleTest +{ + private int streamSize; + + public String getName() + { + return "CipherStreamTest"; + } + + private void testMode(Object cipher, CipherParameters params) + throws Exception + { + testWriteRead(cipher, params, false); + testWriteRead(cipher, params, true); + testReadWrite(cipher, params, false); + testReadWrite(cipher, params, true); + + if (!(cipher instanceof CTSBlockCipher || cipher instanceof NISTCTSBlockCipher)) + { + testWriteReadEmpty(cipher, params, false); + testWriteReadEmpty(cipher, params, true); + } + + if (cipher instanceof AEADBlockCipher) + { + testTamperedRead((AEADBlockCipher)cipher, params); + testTruncatedRead((AEADBlockCipher)cipher, params); + testTamperedWrite((AEADBlockCipher)cipher, params); + } + } + + private OutputStream createCipherOutputStream(OutputStream output, Object cipher) + { + if (cipher instanceof BufferedBlockCipher) + { + return new CipherOutputStream(output, (BufferedBlockCipher)cipher); + } + else if (cipher instanceof AEADBlockCipher) + { + return new CipherOutputStream(output, (AEADBlockCipher)cipher); + } + else + { + return new CipherOutputStream(output, (StreamCipher)cipher); + } + } + + private InputStream createCipherInputStream(byte[] data, Object cipher) + { + ByteArrayInputStream input = new ByteArrayInputStream(data); + if (cipher instanceof BufferedBlockCipher) + { + return new CipherInputStream(input, (BufferedBlockCipher)cipher); + } + else if (cipher instanceof AEADBlockCipher) + { + return new CipherInputStream(input, (AEADBlockCipher)cipher); + } + else + { + return new CipherInputStream(input, (StreamCipher)cipher); + } + } + + /** + * Test tampering of ciphertext followed by read from decrypting CipherInputStream + */ + private void testTamperedRead(AEADBlockCipher cipher, CipherParameters params) + throws Exception + { + cipher.init(true, params); + + byte[] ciphertext = new byte[cipher.getOutputSize(streamSize)]; + cipher.doFinal(ciphertext, cipher.processBytes(new byte[streamSize], 0, streamSize, ciphertext, 0)); + + // Tamper + ciphertext[0] += 1; + + cipher.init(false, params); + InputStream input = createCipherInputStream(ciphertext, cipher); + try + { + while (input.read() >= 0) + { + } + fail("Expected invalid ciphertext after tamper and read : " + cipher.getAlgorithmName()); + } + catch (InvalidCipherTextIOException e) + { + // Expected + } + try + { + input.close(); + } + catch (Exception e) + { + fail("Unexpected exception after tamper and read : " + cipher.getAlgorithmName()); + } + } + + /** + * Test truncation of ciphertext to make tag calculation impossible, followed by read from + * decrypting CipherInputStream + */ + private void testTruncatedRead(AEADBlockCipher cipher, CipherParameters params) + throws Exception + { + cipher.init(true, params); + + byte[] ciphertext = new byte[cipher.getOutputSize(streamSize)]; + cipher.doFinal(ciphertext, cipher.processBytes(new byte[streamSize], 0, streamSize, ciphertext, 0)); + + // Truncate to just smaller than complete tag + byte[] truncated = new byte[ciphertext.length - streamSize - 1]; + System.arraycopy(ciphertext, 0, truncated, 0, truncated.length); + + cipher.init(false, params); + InputStream input = createCipherInputStream(truncated, cipher); + while (true) + { + int read = 0; + try + { + read = input.read(); + } + catch (InvalidCipherTextIOException e) + { + // Expected + break; + } + catch (Exception e) + { + fail("Unexpected exception on truncated read : " + cipher.getAlgorithmName()); + break; + } + if (read < 0) + { + fail("Expected invalid ciphertext after truncate and read : " + cipher.getAlgorithmName()); + break; + } + } + try + { + input.close(); + } + catch (Exception e) + { + fail("Unexpected exception after truncate and read : " + cipher.getAlgorithmName()); + } + } + + /** + * Test tampering of ciphertext followed by write to decrypting CipherOutputStream + */ + private void testTamperedWrite(AEADBlockCipher cipher, CipherParameters params) + throws Exception + { + cipher.init(true, params); + + byte[] ciphertext = new byte[cipher.getOutputSize(streamSize)]; + cipher.doFinal(ciphertext, cipher.processBytes(new byte[streamSize], 0, streamSize, ciphertext, 0)); + + // Tamper + ciphertext[0] += 1; + + cipher.init(false, params); + ByteArrayOutputStream plaintext = new ByteArrayOutputStream(); + OutputStream output = createCipherOutputStream(plaintext, cipher); + + for (int i = 0; i < ciphertext.length; i++) + { + output.write(ciphertext[i]); + } + try + { + output.close(); + fail("Expected invalid ciphertext after tamper and write : " + cipher.getAlgorithmName()); + } + catch (InvalidCipherTextIOException e) + { + // Expected + } + } + + /** + * Test CipherOutputStream in ENCRYPT_MODE, CipherInputStream in DECRYPT_MODE + */ + private void testWriteRead(Object cipher, CipherParameters params, boolean blocks) + throws Exception + { + byte[] data = new byte[streamSize]; + for (int i = 0; i < data.length; i++) + { + data[i] = (byte)(i % 255); + } + + testWriteRead(cipher, params, blocks, data); + } + + /** + * Test CipherOutputStream in ENCRYPT_MODE, CipherInputStream in DECRYPT_MODE + */ + private void testWriteReadEmpty(Object cipher, CipherParameters params, boolean blocks) + throws Exception + { + byte[] data = new byte[0]; + + testWriteRead(cipher, params, blocks, data); + } + + private void testWriteRead(Object cipher, CipherParameters params, boolean blocks, byte[] data) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try + { + init(cipher, true, params); + + OutputStream cOut = createCipherOutputStream(bOut, cipher); + if (blocks) + { + int chunkSize = Math.max(1, data.length / 8); + for (int i = 0; i < data.length; i += chunkSize) + { + cOut.write(data, i, Math.min(chunkSize, data.length - i)); + } + } + else + { + for (int i = 0; i < data.length; i++) + { + cOut.write(data[i]); + } + } + cOut.close(); + + byte[] cipherText = bOut.toByteArray(); + bOut.reset(); + init(cipher, false, params); + InputStream cIn = createCipherInputStream(cipherText, cipher); + + if (blocks) + { + byte[] block = new byte[getBlockSize(cipher) + 1]; + int c; + while ((c = cIn.read(block)) >= 0) + { + bOut.write(block, 0, c); + } + } + else + { + int c; + while ((c = cIn.read()) >= 0) + { + bOut.write(c); + } + + } + cIn.close(); + + } + catch (Exception e) + { + fail("Unexpected exception " + getName(cipher), e); + } + + byte[] decrypted = bOut.toByteArray(); + if (!Arrays.areEqual(data, decrypted)) + { + fail("Failed - decrypted data doesn't match: " + getName(cipher)); + } + } + + private String getName(Object cipher) + { + if (cipher instanceof BufferedBlockCipher) + { + return ((BufferedBlockCipher)cipher).getUnderlyingCipher().getAlgorithmName(); + } + else if (cipher instanceof AEADBlockCipher) + { + return ((AEADBlockCipher)cipher).getUnderlyingCipher().getAlgorithmName(); + } + else if (cipher instanceof StreamCipher) + { + return ((StreamCipher)cipher).getAlgorithmName(); + } + return null; + } + + private int getBlockSize(Object cipher) + { + if (cipher instanceof BlockCipher) + { + return ((BlockCipher)cipher).getBlockSize(); + } + else if (cipher instanceof BufferedBlockCipher) + { + return ((BufferedBlockCipher)cipher).getBlockSize(); + } + else if (cipher instanceof AEADBlockCipher) + { + return ((AEADBlockCipher)cipher).getUnderlyingCipher().getBlockSize(); + } + else if (cipher instanceof StreamCipher) + { + return 1; + } + return 0; + } + + private void init(Object cipher, boolean forEncrypt, CipherParameters params) + { + if (cipher instanceof BufferedBlockCipher) + { + ((BufferedBlockCipher)cipher).init(forEncrypt, params); + } + else if (cipher instanceof AEADBlockCipher) + { + ((AEADBlockCipher)cipher).init(forEncrypt, params); + } + else if (cipher instanceof StreamCipher) + { + ((StreamCipher)cipher).init(forEncrypt, params); + } + } + + protected void fail(String message, boolean authenticated, boolean bc) + { + if (bc || !authenticated) + { + super.fail(message); + } + else + { + // javax.crypto.CipherInputStream/CipherOutputStream + // are broken wrt handling AEAD failures + System.err.println("Broken JCE Streams: " + message); + } + } + + /** + * Test CipherInputStream in ENCRYPT_MODE, CipherOutputStream in DECRYPT_MODE + */ + private void testReadWrite(Object cipher, CipherParameters params, boolean blocks) + throws Exception + { + String lCode = "ABCDEFGHIJKLMNOPQRSTU"; + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try + { + init(cipher, true, params); + + InputStream cIn = createCipherInputStream(lCode.getBytes(), cipher); + ByteArrayOutputStream ct = new ByteArrayOutputStream(); + + if (blocks) + { + byte[] block = new byte[getBlockSize(cipher) + 1]; + int c; + while ((c = cIn.read(block)) >= 0) + { + ct.write(block, 0, c); + } + } + else + { + int c; + while ((c = cIn.read()) >= 0) + { + ct.write(c); + } + } + cIn.close(); + + init(cipher, false, params); + ByteArrayInputStream dataIn = new ByteArrayInputStream(ct.toByteArray()); + OutputStream cOut = createCipherOutputStream(bOut, cipher); + + if (blocks) + { + byte[] block = new byte[getBlockSize(cipher) + 1]; + int c; + while ((c = dataIn.read(block)) >= 0) + { + cOut.write(block, 0, c); + } + } + else + { + int c; + while ((c = dataIn.read()) >= 0) + { + cOut.write(c); + } + } + cOut.flush(); + cOut.close(); + + } + catch (Exception e) + { + fail("Unexpected exception " + getName(cipher), e); + } + + String res = new String(bOut.toByteArray()); + if (!res.equals(lCode)) + { + fail("Failed read/write - decrypted data doesn't match: " + getName(cipher), lCode, res); + } + } + + public void performTest() + throws Exception + { + int[] testSizes = new int[]{0, 1, 7, 8, 9, 15, 16, 17, 1023, 1024, 1025, 2047, 2048, 2049, 4095, 4096, 4097}; + for (int i = 0; i < testSizes.length; i++) + { + this.streamSize = testSizes[i]; + performTests(); + } + } + + private void performTests() + throws Exception + { + testModes(new BlowfishEngine(), new BlowfishEngine(), 16); + testModes(new DESEngine(), new DESEngine(), 8); + testModes(new DESedeEngine(), new DESedeEngine(), 24); + testModes(new TEAEngine(), new TEAEngine(), 16); + testModes(new CAST5Engine(), new CAST5Engine(), 16); + testModes(new RC2Engine(), new RC2Engine(), 16); + testModes(new XTEAEngine(), new XTEAEngine(), 16); + + testModes(new AESEngine(), new AESEngine(), 16); + testModes(new NoekeonEngine(), new NoekeonEngine(), 16); + testModes(new TwofishEngine(), new TwofishEngine(), 16); + testModes(new CAST6Engine(), new CAST6Engine(), 16); + testModes(new SEEDEngine(), new SEEDEngine(), 16); + testModes(new SerpentEngine(), new SerpentEngine(), 16); + testModes(new RC6Engine(), new RC6Engine(), 16); + testModes(new CamelliaEngine(), new CamelliaEngine(), 16); + testModes(new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), + new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), 64); + + testMode(new RC4Engine(), new KeyParameter(new byte[16])); + testMode(new Salsa20Engine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[8])); + testMode(new XSalsa20Engine(), new ParametersWithIV(new KeyParameter(new byte[32]), new byte[24])); + testMode(new ChaChaEngine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[8])); + testMode(new Grainv1Engine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[8])); + testMode(new Grain128Engine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[12])); + testMode(new HC128Engine(), new KeyParameter(new byte[16])); + testMode(new HC256Engine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + + testSkipping(new Salsa20Engine(), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[8])); + testSkipping(new SICBlockCipher(new AESEngine()), new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16])); + } + + private void testModes(BlockCipher cipher1, BlockCipher cipher2, int keySize) + throws Exception + { + final KeyParameter key = new KeyParameter(new byte[keySize]); + final int blockSize = getBlockSize(cipher1); + final CipherParameters withIv = new ParametersWithIV(key, new byte[blockSize]); + + if (blockSize > 1) + { + testMode(new PaddedBufferedBlockCipher(cipher1, new PKCS7Padding()), key); + + testMode(new PaddedBufferedBlockCipher(new CBCBlockCipher(cipher1), new PKCS7Padding()), withIv); + + testMode(new BufferedBlockCipher(new OFBBlockCipher(cipher1, blockSize)), withIv); + testMode(new BufferedBlockCipher(new CFBBlockCipher(cipher1, blockSize)), withIv); + testMode(new BufferedBlockCipher(new SICBlockCipher(cipher1)), withIv); + } + // CTS requires at least one block + if (blockSize <= 16 && streamSize >= blockSize) + { + testMode(new CTSBlockCipher(cipher1), key); + } + if (blockSize <= 16 && streamSize >= blockSize) + { + testMode(new NISTCTSBlockCipher(NISTCTSBlockCipher.CS1, cipher1), key); + testMode(new NISTCTSBlockCipher(NISTCTSBlockCipher.CS2, cipher1), key); + testMode(new NISTCTSBlockCipher(NISTCTSBlockCipher.CS3, cipher1), key); + } + if (blockSize == 8 || blockSize == 16) + { + testMode(new EAXBlockCipher(cipher1), withIv); + } + if (blockSize == 16) + { + testMode(new CCMBlockCipher(cipher1), new ParametersWithIV(key, new byte[7])); + // TODO: need to have a GCM safe version of testMode. +// testMode(new GCMBlockCipher(cipher1), withIv); + testMode(new OCBBlockCipher(cipher1, cipher2), new ParametersWithIV(key, new byte[15])); + } + } + + private void testSkipping(StreamCipher cipher, CipherParameters params) + throws Exception + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + init(cipher, true, params); + + OutputStream cOut = createCipherOutputStream(bOut, cipher); + byte[] data = new byte[5000]; + + new SecureRandom().nextBytes(data); + + cOut.write(data); + + cOut.close(); + + init(cipher, false, params); + + InputStream cIn = createCipherInputStream(bOut.toByteArray(), cipher); + + long skip = cIn.skip(50); + if (skip != 50) + { + fail("wrong number of bytes skipped: " + skip); + } + + byte[] block = new byte[50]; + + cIn.read(block); + + if (!areEqual(data, 50, block, 0)) + { + fail("initial skip mismatch"); + } + + skip = cIn.skip(3000); + if (skip != 3000) + { + fail("wrong number of bytes skipped: " + skip); + } + + cIn.read(block); + + if (!areEqual(data, 3100, block, 0)) + { + fail("second skip mismatch"); + } + + cipher.reset(); + + cIn = createCipherInputStream(bOut.toByteArray(), cipher); + if (!cIn.markSupported()) + { + fail("marking not supported"); + } + + cIn.mark(100); + + cIn.read(block); + + if (!areEqual(data, 0, block, 0)) + { + fail("initial mark read failed"); + } + + cIn.reset(); + + cIn.read(block); + + if (!areEqual(data, 0, block, 0)) + { + fail(cipher.getAlgorithmName() + " initial reset read failed"); + } + + cIn.reset(); + + cIn.read(block); + + cIn.mark(100); + + cIn.read(block); + + if (!areEqual(data, 50, block, 0)) + { + fail("second mark read failed"); + } + + cIn.reset(); + + cIn.read(block); + + if (!areEqual(data, 50, block, 0)) + { + fail(cipher.getAlgorithmName() + " second reset read failed"); + } + + cIn.mark(3000); + + skip = cIn.skip(2050); + if (skip != 2050) + { + fail("wrong number of bytes skipped: " + skip); + } + + cIn.reset(); + + cIn.read(block); + + if (!areEqual(data, 100, block, 0)) + { + fail(cipher.getAlgorithmName() + " third reset read failed"); + } + + cIn.read(new byte[2150]); + + cIn.reset(); + + cIn.read(block); + + if (!areEqual(data, 100, block, 0)) + { + fail(cipher.getAlgorithmName() + " fourth reset read failed"); + } + + cIn.close(); + } + + private boolean areEqual(byte[] a, int aOff, byte[] b, int bOff) + { + for (int i = bOff; i != b.length; i++) + { + if (a[aOff + i - bOff] != b[i]) + { + return false; + } + } + + return true; + } + + public static void main(String[] args) + { + runTest(new CipherStreamTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CipherTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CipherTest.java new file mode 100644 index 000000000..9d5de887e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CipherTest.java @@ -0,0 +1,117 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public abstract class CipherTest + extends SimpleTest +{ + private SimpleTest[] _tests; + private BlockCipher _engine; + private KeyParameter _validKey; + +// protected CipherTest( +// SimpleTest[] tests) +// { +// _tests = tests; +// } + + protected CipherTest( + SimpleTest[] tests, + BlockCipher engine, + KeyParameter validKey) + { + _tests = tests; + _engine = engine; + _validKey = validKey; + } + + public abstract String getName(); + + public void performTest() + throws Exception + { + for (int i = 0; i != _tests.length; i++) + { + _tests[i].performTest(); + } + + if (_engine != null) + { + // + // state tests + // + byte[] buf = new byte[128]; + + try + { + _engine.processBlock(buf, 0, buf, 0); + + fail("failed initialisation check"); + } + catch (IllegalStateException e) + { + // expected + } + + bufferSizeCheck((_engine)); + } + } + + private void bufferSizeCheck( + BlockCipher engine) + { + byte[] correctBuf = new byte[engine.getBlockSize()]; + byte[] shortBuf = new byte[correctBuf.length / 2]; + + engine.init(true, _validKey); + + try + { + engine.processBlock(shortBuf, 0, correctBuf, 0); + + fail("failed short input check"); + } + catch (DataLengthException e) + { + // expected + } + + try + { + engine.processBlock(correctBuf, 0, shortBuf, 0); + + fail("failed short output check"); + } + catch (DataLengthException e) + { + // expected + } + + engine.init(false, _validKey); + + try + { + engine.processBlock(shortBuf, 0, correctBuf, 0); + + fail("failed short input check"); + } + catch (DataLengthException e) + { + // expected + } + + try + { + engine.processBlock(correctBuf, 0, shortBuf, 0); + + fail("failed short output check"); + } + catch (DataLengthException e) + { + // expected + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CramerShoupTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CramerShoupTest.java new file mode 100644 index 000000000..953882212 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/CramerShoupTest.java @@ -0,0 +1,147 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.agreement.DHStandardGroups; +import com.fr.third.org.bouncycastle.crypto.engines.CramerShoupCiphertext; +import com.fr.third.org.bouncycastle.crypto.engines.CramerShoupCoreEngine; +import com.fr.third.org.bouncycastle.crypto.engines.CramerShoupCoreEngine.CramerShoupCiphertextException; +import com.fr.third.org.bouncycastle.crypto.generators.CramerShoupKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.CramerShoupParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.params.CramerShoupKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.CramerShoupParameters; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class CramerShoupTest + extends SimpleTest +{ + private static final BigInteger ONE = BigInteger.valueOf(1); + + private static final SecureRandom RND = new SecureRandom(); + + private AsymmetricCipherKeyPair keyPair; + + public static void main(String[] args) + { + runTest(new CramerShoupTest()); + } + + public String getName() + { + return "CramerShoup"; + } + + + public void performTest() + throws Exception + { + BigInteger pSubOne = DHStandardGroups.rfc3526_2048.getP().subtract(ONE); + for (int i = 0; i < 10; ++i) + { + BigInteger message = BigIntegers.createRandomInRange(ONE, pSubOne, RND); + + BigInteger m1 = encDecTest(message); + BigInteger m2 = labelledEncDecTest(message, "myRandomLabel"); + BigInteger m3 = encDecEncodingTest(message); + BigInteger m4 = labelledEncDecEncodingTest(message, "myOtherCoolLabel"); + + if (!message.equals(m1) || !message.equals(m2) || !message.equals(m3) || !message.equals(m4)) + { + fail("decrypted message != original message"); + } + } + } + + private BigInteger encDecEncodingTest(BigInteger m) + { + CramerShoupCiphertext ciphertext = encrypt(m); + byte[] c = ciphertext.toByteArray(); + CramerShoupCiphertext decC = new CramerShoupCiphertext(c); + return decrypt(decC); + } + + private BigInteger labelledEncDecEncodingTest(BigInteger m, String l) + { + byte[] c = encrypt(m, l).toByteArray(); + return decrypt(new CramerShoupCiphertext(c), l); + } + + private BigInteger encDecTest(BigInteger m) + { + CramerShoupCiphertext c = encrypt(m); + return decrypt(c); + } + + private BigInteger labelledEncDecTest(BigInteger m, String l) + { + CramerShoupCiphertext c = encrypt(m, l); + return decrypt(c, l); + } + + + private BigInteger decrypt(CramerShoupCiphertext ciphertext) + { + return decrypt(ciphertext, null); + } + + private BigInteger decrypt(CramerShoupCiphertext ciphertext, String label) + { + + CramerShoupCoreEngine engine = new CramerShoupCoreEngine(); + if (label != null) + { + engine.init(false, keyPair.getPrivate(), label); + } + else + { + engine.init(false, keyPair.getPrivate()); + } + try + { + BigInteger m = engine.decryptBlock(ciphertext); + + return m; + } + catch (CramerShoupCiphertextException e) + { + e.printStackTrace(); + } + + return null; + } + + private CramerShoupCiphertext encrypt(BigInteger message) + { + return encrypt(message, null); + } + + private CramerShoupCiphertext encrypt(BigInteger message, String label) + { + CramerShoupKeyPairGenerator kpGen = new CramerShoupKeyPairGenerator(); + CramerShoupParametersGenerator pGen = new CramerShoupParametersGenerator(); + + pGen.init(2048, 1, RND); + CramerShoupParameters params = pGen.generateParameters(DHStandardGroups.rfc3526_2048); + CramerShoupKeyGenerationParameters param = new CramerShoupKeyGenerationParameters(RND, params); + + kpGen.init(param); + keyPair = kpGen.generateKeyPair(); + + CramerShoupCoreEngine engine = new CramerShoupCoreEngine(); + if (label != null) + { + engine.init(true, keyPair.getPublic(), label); + } + else + { + engine.init(true, keyPair.getPublic()); + } + + CramerShoupCiphertext ciphertext = engine.encryptBlock(message); + + return ciphertext; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DESTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DESTest.java new file mode 100644 index 000000000..bbe968585 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DESTest.java @@ -0,0 +1,206 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.generators.DESKeyGenerator; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.OFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.DESParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +import java.security.SecureRandom; + +class DESParityTest + extends SimpleTest +{ + public String getName() + { + return "DESParityTest"; + } + + public void performTest() + { + byte[] k1In = { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff, + (byte)0xff, (byte)0xff, (byte)0xff, (byte)0xff }; + byte[] k1Out = { (byte)0xfe, (byte)0xfe, (byte)0xfe, (byte)0xfe, + (byte)0xfe, (byte)0xfe, (byte)0xfe, (byte)0xfe }; + + byte[] k2In = { (byte)0xef, (byte)0xcb, (byte)0xda, (byte)0x4f, + (byte)0xaa, (byte)0x99, (byte)0x7f, (byte)0x63 }; + byte[] k2Out = { (byte)0xef, (byte)0xcb, (byte)0xda, (byte)0x4f, + (byte)0xab, (byte)0x98, (byte)0x7f, (byte)0x62 }; + + DESParameters.setOddParity(k1In); + + for (int i = 0; i != k1In.length; i++) + { + if (k1In[i] != k1Out[i]) + { + fail("Failed " + + "got " + new String(Hex.encode(k1In)) + + " expected " + new String(Hex.encode(k1Out))); + } + } + + DESParameters.setOddParity(k2In); + + for (int i = 0; i != k2In.length; i++) + { + if (k2In[i] != k2Out[i]) + { + fail("Failed " + + "got " + new String(Hex.encode(k2In)) + + " expected " + new String(Hex.encode(k2Out))); + } + } + } +} + +class KeyGenTest + extends SimpleTest +{ + public String getName() + { + return "KeyGenTest"; + } + + public void performTest() + { + DESKeyGenerator keyGen = new DESKeyGenerator(); + + keyGen.init(new KeyGenerationParameters(new SecureRandom(), 56)); + + byte[] kB = keyGen.generateKey(); + + if (kB.length != 8) + { + fail("DES bit key wrong length."); + } + } +} + +class DESParametersTest + extends SimpleTest +{ + static private byte[] weakKeys = + { + (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, + (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e, + (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1, + (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, (byte)0xfe,(byte)0xfe,(byte)0xfe,(byte)0xfe, + /* semi-weak keys */ + (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, (byte)0x01,(byte)0xfe,(byte)0x01,(byte)0xfe, + (byte)0x1f,(byte)0xe0,(byte)0x1f,(byte)0xe0, (byte)0x0e,(byte)0xf1,(byte)0x0e,(byte)0xf1, + (byte)0x01,(byte)0xe0,(byte)0x01,(byte)0xe0, (byte)0x01,(byte)0xf1,(byte)0x01,(byte)0xf1, + (byte)0x1f,(byte)0xfe,(byte)0x1f,(byte)0xfe, (byte)0x0e,(byte)0xfe,(byte)0x0e,(byte)0xfe, + (byte)0x01,(byte)0x1f,(byte)0x01,(byte)0x1f, (byte)0x01,(byte)0x0e,(byte)0x01,(byte)0x0e, + (byte)0xe0,(byte)0xfe,(byte)0xe0,(byte)0xfe, (byte)0xf1,(byte)0xfe,(byte)0xf1,(byte)0xfe, + (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, (byte)0xfe,(byte)0x01,(byte)0xfe,(byte)0x01, + (byte)0xe0,(byte)0x1f,(byte)0xe0,(byte)0x1f, (byte)0xf1,(byte)0x0e,(byte)0xf1,(byte)0x0e, + (byte)0xe0,(byte)0x01,(byte)0xe0,(byte)0x01, (byte)0xf1,(byte)0x01,(byte)0xf1,(byte)0x01, + (byte)0xfe,(byte)0x1f,(byte)0xfe,(byte)0x1f, (byte)0xfe,(byte)0x0e,(byte)0xfe,(byte)0x0e, + (byte)0x1f,(byte)0x01,(byte)0x1f,(byte)0x01, (byte)0x0e,(byte)0x01,(byte)0x0e,(byte)0x01, + (byte)0xfe,(byte)0xe0,(byte)0xfe,(byte)0xe0, (byte)0xfe,(byte)0xf1,(byte)0xfe,(byte)0xf1 + }; + + public String getName() + { + return "DESParameters"; + } + + public void performTest() throws Exception + { + try + { + DESParameters.isWeakKey(new byte[4], 0); + fail("no exception on small key"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("key material too short.")) + { + fail("wrong exception"); + } + } + + try + { + new DESParameters(weakKeys); + fail("no exception on weak key"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("attempt to create weak DES key")) + { + fail("wrong exception"); + } + } + + for (int i = 0; i != weakKeys.length; i += 8) + { + if (!DESParameters.isWeakKey(weakKeys, i)) + { + fail("weakKey test failed"); + } + } + } +} + +/** + * DES tester - vectors from FIPS 81 + */ +public class DESTest + extends CipherTest +{ + static String input1 = "4e6f77206973207468652074696d6520666f7220616c6c20"; + static String input2 = "4e6f7720697320746865"; + static String input3 = "4e6f7720697320746865aabbcc"; + + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new DESEngine(), + new KeyParameter(Hex.decode("0123456789abcdef")), + input1, "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"), + new BlockCipherVectorTest(1, new CBCBlockCipher(new DESEngine()), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input1, "e5c7cdde872bf27c43e934008c389c0f683788499a7c05f6"), + new BlockCipherVectorTest(2, new CFBBlockCipher(new DESEngine(), 8), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input2, "f31fda07011462ee187f"), + new BlockCipherVectorTest(3, new CFBBlockCipher(new DESEngine(), 64), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input1, "f3096249c7f46e51a69e839b1a92f78403467133898ea622"), + new BlockCipherVectorTest(4, new OFBBlockCipher(new DESEngine(), 8), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input2, "f34a2850c9c64985d684"), + new BlockCipherVectorTest(5, new CFBBlockCipher(new DESEngine(), 64), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input3, "f3096249c7f46e51a69e0954bf"), + new BlockCipherVectorTest(6, new OFBBlockCipher(new DESEngine(), 64), + new ParametersWithIV(new KeyParameter(Hex.decode("0123456789abcdef")), Hex.decode("1234567890abcdef")), + input3, "f3096249c7f46e5135f2c0eb8b"), + new DESParityTest(), + new DESParametersTest(), + new KeyGenTest() + }; + + public DESTest() + { + super(tests, new DESEngine(), new KeyParameter(new byte[8])); + } + + public String getName() + { + return "DES"; + } + + public static void main( + String[] args) + { + runTest(new DESTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DESedeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DESedeTest.java new file mode 100644 index 000000000..30434c156 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DESedeTest.java @@ -0,0 +1,177 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.Wrapper; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeWrapEngine; +import com.fr.third.org.bouncycastle.crypto.generators.DESedeKeyGenerator; +import com.fr.third.org.bouncycastle.crypto.params.DESedeParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +import java.security.SecureRandom; + +/** + * DESede tester + */ +public class DESedeTest + extends CipherTest +{ + static private byte[] weakKey = // first 8 bytes non-weak + { + (byte)0x06,(byte)0x01,(byte)0x01,(byte)0x01, (byte)0x01,(byte)0x01,(byte)0x01,(byte)0x01, + (byte)0x1f,(byte)0x1f,(byte)0x1f,(byte)0x1f, (byte)0x0e,(byte)0x0e,(byte)0x0e,(byte)0x0e, + (byte)0xe0,(byte)0xe0,(byte)0xe0,(byte)0xe0, (byte)0xf1,(byte)0xf1,(byte)0xf1,(byte)0xf1, + }; + + static String input1 = "4e6f77206973207468652074696d6520666f7220616c6c20"; + static String input2 = "4e6f7720697320746865"; + + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new DESedeEngine(), + new DESedeParameters(Hex.decode("0123456789abcdef0123456789abcdef")), + input1, "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"), + new BlockCipherVectorTest(1, new DESedeEngine(), + new DESedeParameters(Hex.decode("0123456789abcdeffedcba9876543210")), + input1, "d80a0d8b2bae5e4e6a0094171abcfc2775d2235a706e232c"), + new BlockCipherVectorTest(2, new DESedeEngine(), + new DESedeParameters(Hex.decode("0123456789abcdef0123456789abcdef0123456789abcdef")), + input1, "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"), + new BlockCipherVectorTest(3, new DESedeEngine(), + new DESedeParameters(Hex.decode("0123456789abcdeffedcba98765432100123456789abcdef")), + input1, "d80a0d8b2bae5e4e6a0094171abcfc2775d2235a706e232c") + }; + + DESedeTest() + { + super(tests, new DESedeEngine(), new KeyParameter(new byte[16])); + } + + private void wrapTest( + int id, + byte[] kek, + byte[] iv, + byte[] in, + byte[] out) + { + Wrapper wrapper = new DESedeWrapEngine(); + + wrapper.init(true, new ParametersWithIV(new KeyParameter(kek), iv)); + + try + { + byte[] cText = wrapper.wrap(in, 0, in.length); + if (!areEqual(cText, out)) + { + fail(": failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + } + catch (Exception e) + { + fail("failed wrap test exception: " + e.toString(), e); + } + + wrapper.init(false, new KeyParameter(kek)); + + try + { + byte[] pText = wrapper.unwrap(out, 0, out.length); + if (!areEqual(pText, in)) + { + fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); + } + } + catch (Exception e) + { + fail("failed unwrap test exception: " + e.toString(), e); + } + } + + public void performTest() + throws Exception + { + super.performTest(); + + byte[] kek1 = Hex.decode("255e0d1c07b646dfb3134cc843ba8aa71f025b7c0838251f"); + byte[] iv1 = Hex.decode("5dd4cbfc96f5453b"); + byte[] in1 = Hex.decode("2923bf85e06dd6ae529149f1f1bae9eab3a7da3d860d3e98"); + byte[] out1 = Hex.decode("690107618ef092b3b48ca1796b234ae9fa33ebb4159604037db5d6a84eb3aac2768c632775a467d4"); + + wrapTest(1, kek1, iv1, in1, out1); + + // + // key generation + // + SecureRandom random = new SecureRandom(); + DESedeKeyGenerator keyGen = new DESedeKeyGenerator(); + + keyGen.init(new KeyGenerationParameters(random, 112)); + + byte[] kB = keyGen.generateKey(); + + if (kB.length != 16) + { + fail("112 bit key wrong length."); + } + + keyGen.init(new KeyGenerationParameters(random, 168)); + + kB = keyGen.generateKey(); + + if (kB.length != 24) + { + fail("168 bit key wrong length."); + } + + try + { + keyGen.init(new KeyGenerationParameters(random, 200)); + + fail("invalid key length not detected."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + DESedeParameters.isWeakKey(new byte[4], 0); + fail("no exception on small key"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("key material too short.")) + { + fail("wrong exception"); + } + } + + try + { + new DESedeParameters(weakKey); + fail("no exception on weak key"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("attempt to create weak DESede key")) + { + fail("wrong exception"); + } + } + } + + public String getName() + { + return "DESede"; + } + + public static void main( + String[] args) + { + runTest(new DESedeTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DHKEKGeneratorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DHKEKGeneratorTest.java new file mode 100644 index 000000000..f80d665df --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DHKEKGeneratorTest.java @@ -0,0 +1,70 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.DerivationFunction; +import com.fr.third.org.bouncycastle.crypto.DerivationParameters; +import com.fr.third.org.bouncycastle.crypto.agreement.kdf.DHKDFParameters; +import com.fr.third.org.bouncycastle.crypto.agreement.kdf.DHKEKGenerator; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * DHKEK Generator tests - from RFC 2631. + */ +public class DHKEKGeneratorTest + extends SimpleTest +{ + private byte[] seed1 = Hex.decode("000102030405060708090a0b0c0d0e0f10111213"); + private ASN1ObjectIdentifier alg1 = PKCSObjectIdentifiers.id_alg_CMS3DESwrap; + private byte[] result1 = Hex.decode("a09661392376f7044d9052a397883246b67f5f1ef63eb5fb"); + + private byte[] seed2 = Hex.decode("000102030405060708090a0b0c0d0e0f10111213"); + private ASN1ObjectIdentifier alg2 = PKCSObjectIdentifiers.id_alg_CMSRC2wrap; + private byte[] partyAInfo = Hex.decode( + "0123456789abcdeffedcba9876543201" + + "0123456789abcdeffedcba9876543201" + + "0123456789abcdeffedcba9876543201" + + "0123456789abcdeffedcba9876543201"); + private byte[] result2 = Hex.decode("48950c46e0530075403cce72889604e0"); + + public DHKEKGeneratorTest() + { + } + + public void performTest() + { + checkMask(1, new DHKEKGenerator(new SHA1Digest()), new DHKDFParameters(alg1, 192, seed1), result1); + checkMask(2, new DHKEKGenerator(new SHA1Digest()), new DHKDFParameters(alg2, 128, seed2, partyAInfo), result2); + } + + private void checkMask( + int count, + DerivationFunction kdf, + DerivationParameters params, + byte[] result) + { + byte[] data = new byte[result.length]; + + kdf.init(params); + + kdf.generateBytes(data, 0, data.length); + + if (!areEqual(result, data)) + { + fail("DHKEKGenerator failed generator test " + count); + } + } + + public String getName() + { + return "DHKEKGenerator"; + } + + public static void main( + String[] args) + { + runTest(new DHKEKGeneratorTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DHTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DHTest.java new file mode 100644 index 000000000..f172ad740 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DHTest.java @@ -0,0 +1,540 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.agreement.DHAgreement; +import com.fr.third.org.bouncycastle.crypto.agreement.DHBasicAgreement; +import com.fr.third.org.bouncycastle.crypto.agreement.DHUnifiedAgreement; +import com.fr.third.org.bouncycastle.crypto.generators.DHBasicKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.DHKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.DHParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.params.DHKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHUPrivateParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHUPublicParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class DHTest + extends SimpleTest +{ + private BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + private BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + private BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16); + private BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16); + + private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16); + private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16); + + public String getName() + { + return "DH"; + } + + private void testDH( + int size, + BigInteger g, + BigInteger p) + { + DHKeyPairGenerator kpGen = getDHKeyPairGenerator(g, p); + + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + // + // generate second pair + // + pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.getPrivate(); + + // + // two way + // + DHAgreement e1 = new DHAgreement(); + DHAgreement e2 = new DHAgreement(); + + e1.init(pv1); + e2.init(pv2); + + BigInteger m1 = e1.calculateMessage(); + BigInteger m2 = e2.calculateMessage(); + + BigInteger k1 = e1.calculateAgreement(pu2, m2); + BigInteger k2 = e2.calculateAgreement(pu1, m1); + + if (!k1.equals(k2)) + { + fail(size + " bit 2-way test failed"); + } + } + + private void testDHBasic( + int size, + int privateValueSize, + BigInteger g, + BigInteger p) + { + DHBasicKeyPairGenerator kpGen = getDHBasicKeyPairGenerator(g, p, privateValueSize); + + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + + checkKeySize(privateValueSize, pv1); + // + // generate second pair + // + pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.getPrivate(); + + checkKeySize(privateValueSize, pv2); + // + // two way + // + DHBasicAgreement e1 = new DHBasicAgreement(); + DHBasicAgreement e2 = new DHBasicAgreement(); + + e1.init(pv1); + e2.init(pv2); + + BigInteger k1 = e1.calculateAgreement(pu2); + BigInteger k2 = e2.calculateAgreement(pu1); + + if (!k1.equals(k2)) + { + fail("basic " + size + " bit 2-way test failed"); + } + } + + private void checkKeySize( + int privateValueSize, + DHPrivateKeyParameters priv) + { + if (privateValueSize != 0) + { + if (priv.getX().bitLength() != privateValueSize) + { + fail("limited key check failed for key size " + privateValueSize); + } + } + } + + private void testGPWithRandom( + DHKeyPairGenerator kpGen) + { + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + // + // generate second pair + // + pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.getPrivate(); + + // + // two way + // + DHAgreement e1 = new DHAgreement(); + DHAgreement e2 = new DHAgreement(); + + e1.init(new ParametersWithRandom(pv1, new SecureRandom())); + e2.init(new ParametersWithRandom(pv2, new SecureRandom())); + + BigInteger m1 = e1.calculateMessage(); + BigInteger m2 = e2.calculateMessage(); + + BigInteger k1 = e1.calculateAgreement(pu2, m2); + BigInteger k2 = e2.calculateAgreement(pu1, m1); + + if (!k1.equals(k2)) + { + fail("basic with random 2-way test failed"); + } + } + + private void testSimpleWithRandom( + DHBasicKeyPairGenerator kpGen) + { + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + // + // generate second pair + // + pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.getPrivate(); + + // + // two way + // + DHBasicAgreement e1 = new DHBasicAgreement(); + DHBasicAgreement e2 = new DHBasicAgreement(); + + e1.init(new ParametersWithRandom(pv1, new SecureRandom())); + e2.init(new ParametersWithRandom(pv2, new SecureRandom())); + + BigInteger k1 = e1.calculateAgreement(pu2); + BigInteger k2 = e2.calculateAgreement(pu1); + + if (!k1.equals(k2)) + { + fail("basic with random 2-way test failed"); + } + } + + private DHBasicKeyPairGenerator getDHBasicKeyPairGenerator( + BigInteger g, + BigInteger p, + int privateValueSize) + { + DHParameters dhParams = new DHParameters(p, g, null, privateValueSize); + DHKeyGenerationParameters params = new DHKeyGenerationParameters(new SecureRandom(), dhParams); + DHBasicKeyPairGenerator kpGen = new DHBasicKeyPairGenerator(); + + kpGen.init(params); + + return kpGen; + } + + private DHKeyPairGenerator getDHKeyPairGenerator( + BigInteger g, + BigInteger p) + { + DHParameters dhParams = new DHParameters(p, g); + DHKeyGenerationParameters params = new DHKeyGenerationParameters(new SecureRandom(), dhParams); + DHKeyPairGenerator kpGen = new DHKeyPairGenerator(); + + kpGen.init(params); + + return kpGen; + } + + /** + * this test is can take quiet a while + */ + private void testGeneration( + int size) + { + DHParametersGenerator pGen = new DHParametersGenerator(); + + pGen.init(size, 10, new SecureRandom()); + + DHParameters dhParams = pGen.generateParameters(); + + if (dhParams.getL() != 0) + { + fail("DHParametersGenerator failed to set J to 0 in generated DHParameters"); + } + + DHKeyGenerationParameters params = new DHKeyGenerationParameters(new SecureRandom(), dhParams); + + DHBasicKeyPairGenerator kpGen = new DHBasicKeyPairGenerator(); + + kpGen.init(params); + + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + + // + // generate second pair + // + params = new DHKeyGenerationParameters(new SecureRandom(), pu1.getParameters()); + + kpGen.init(params); + + pair = kpGen.generateKeyPair(); + + DHPublicKeyParameters pu2 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv2 = (DHPrivateKeyParameters)pair.getPrivate(); + + // + // two way + // + DHBasicAgreement e1 = new DHBasicAgreement(); + DHBasicAgreement e2 = new DHBasicAgreement(); + + e1.init(new ParametersWithRandom(pv1, new SecureRandom())); + e2.init(new ParametersWithRandom(pv2, new SecureRandom())); + + BigInteger k1 = e1.calculateAgreement(pu2); + BigInteger k2 = e2.calculateAgreement(pu1); + + if (!k1.equals(k2)) + { + fail("basic with " + size + " bit 2-way test failed"); + } + } + + private void testBounds() + { + BigInteger p1 = new BigInteger("00C8028E9151C6B51BCDB35C1F6B2527986A72D8546AE7A4BF41DC4289FF9837EE01592D36C324A0F066149B8B940C86C87D194206A39038AE3396F8E12435BB74449B70222D117B8A2BB77CB0D67A5D664DDE7B75E0FEC13CE0CAF258DAF3ADA0773F6FF0F2051D1859929AAA53B07809E496B582A89C3D7DA8B6E38305626621", 16); + BigInteger g1 = new BigInteger("1F869713181464577FE4026B47102FA0D7675503A4FCDA810881FAEC3524E6DBAEA9B96561EF7F8BEA76466DF11C2F3EB1A90CC5851735BF860606481257EECE6418C0204E61004E85D7131CE54BCBC7AD67E53C79DCB715E7C8D083DCD85D728283EC8F96839B4C9FA7C0727C472BEB94E4613CAFA8D580119C0AF4BF8AF252", 16); + int l1 = 1023; + + BigInteger p2 = new BigInteger("00B333C98720220CC3946F494E25231B3E19F9AD5F6B19F4E7ABF80D8826C491C3224D4F7415A14A7C11D1BE584405FED12C3554F103E56A72D986CA5E325BB9DE07AC37D1EAE5E5AC724D32EF638F0E4462D4C1FC7A45B9FD3A5DF5EC36A1FA4DAA3FBB66AA42B1B71DF416AB547E987513426C7BB8634F5F4D37705514FDC1E1", 16); + BigInteger g2 = new BigInteger("2592F5A99FE46313650CCE66C94C15DBED9F4A45BD05C329986CF5D3E12139F0405A47C6385FEA27BFFEDC4CBABC5BB151F3BEE7CC3D51567F1E2B12A975AA9F48A70BDAAE7F5B87E70ADCF902490A3CBEFEDA41EBA8E12E02B56120B5FDEFBED07F5EAD3AE020DF3C8233216F8F0D35E13A7AE4DA5CBCC0D91EADBF20C281C6", 16); + int l2 = 1024; + + DHKeyGenerationParameters params1 = new DHKeyGenerationParameters(new SecureRandom(), new DHParameters(p1, g1, null, l1)); + DHKeyGenerationParameters params2 = new DHKeyGenerationParameters(new SecureRandom(), new DHParameters(p2, g2, null, l2)); + + DHBasicKeyPairGenerator kpGen = new DHBasicKeyPairGenerator(); + + kpGen.init(params1); + kpGen.init(params2); + } + + private void testCombinedTestVector1() + { + // Test Vector from NIST sample data + + BigInteger P = new BigInteger("eedb3431b31d30851ddcd4dce57e1b8fc3b83cc7913bc049281d713d9f8fa91bfd0fde2e1ec5eb45a0d6483cfa6b5055ffa88622a1aa83b9f9c1df561e88b702866f17af2defea0b04cf3fbdd817140ad49c415909fc2bb2c5d160b77273e958a181bf73cf72118e1c8670d53d0e459d14d61ecb5b7c7f63a9cb019cd66aecb3a01d0402f1c18218f142653f4bc922e5baa35964b7432f311fa5a9b34e3b91582db366ad1493f25ea659540f87758ae34678dc864fb2c9d4aba18cb757285292c7d0bac73cc4632a2d54b89f2dc9656d1c50edd49dcbe2102510c70563a96f35dd8a21f0fdc5a1e23ce31fce0ee3023eafdca623508ffd2412fe4dc5b5dd0f75", 16); + BigInteger Q = new BigInteger("e90a78d5da01e926462e5c17a61ff97b09b6ac18f9137e7b99298705", 16); + BigInteger G = new BigInteger("9da3567e2f7396dd2ee4716d3477a53a47f811b2275a95ed07024d7231b739c79e88e5377479b23d460a41f981b1af619915e4d8b2dabf2cb716168d02dfb81e76048e23fff6c773f496b2ac3ae06e2eb12c39787a8244452aef404ce631aec9cf4027eefae492ce55517db0af3939354c5414e23205ae3bcd17faedecf80101fa75c619249a43b41aa15ee2d7699ee32e227b641129fe1c78b20c6655b09fa7fead338e179b4b4416c359b16e3773d141e1a876b7ee4281b61120607717f7edc8da8de42b16b54d0802d67d41fc173cd33227436f7c66bd2fe711b37fb0162543c268857414f4188f243fbf92e128388329c9f2df8db4e7808ab539891da798", 16); + + DHParameters p = new DHParameters(P, G, Q); + + AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair( + new DHPublicKeyParameters( + new BigInteger("e485cd4b82e82dafd35f89d40361049e6100c16b17ca156d072832319a40bf7a3f5081182397b8fbd9d33391896bb35d9cc890d8c0a9e5b642b773ce0690f1bbd4596a9604708edb9c27f45117a7395b7407b43eebd8b82bef4a925e2a93185df21fbf012ec9059a9c9efc0b64afe0505aa1864d79a2a9833863c16163b48c9fcc26a9b9e2741097bdeabc2b7208589e4154e1de7ecf77e928668b28abb8113b322c6d426701df979d47ccd50d493b7fb6f20050c3e67cb876c1550d8c8677527600eab07196213252bd9a48d5023788fdb4b65f85144cf6654e092550646be4882125b286ced6578eedc981304ff88725e4138f90a7a4a07c94105d796b038f", 16), p), + new DHPrivateKeyParameters( + new BigInteger("8a10c0be8f4efaf3019b99698bc4c102f2dac93b993d52ab10ae93f0", 16), p)); + + AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair( + new DHPublicKeyParameters( + new BigInteger("3e84fbbb785bbdc43881b04ec6221b69a557b8b708d72cec8627a8342787554702d5021153ff1246ba5311553f740835c4b82ebc28c5fac05ad37f6c619649750e8dc41af9176af0099f18d36ee43535e7f35fb5f70a37b25dedd87cb6035bb938531c0430cee9c5c8f4321eae72590122bff1f636dcd6a32116ea3945d23a17acc1bfd1e7ad12390e6e13b456bc4a613b1356a7ca95c2660ac5c9f064a6b9c6d584c7e23bc1ff56745d92d0efc06384b3f59125f7c0918ae3a40074d229e22d8ca7573f9fbe89bc7afb344498d6a85b823e1fa20c3d6eccdd69abafe5e43273e71b6d32aa8dc3a349ec4ae41304e6e159c2e5c4b1555a538d58b46a4c8c87d9", 16), p), + new DHPrivateKeyParameters( + new BigInteger("5cb398bfbc3f69744de1f9611e03ab97aba0c5dbe1f6d74ac60fecdf", 16), p)); + + AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair( + new DHPublicKeyParameters( + new BigInteger("2d6e1bb1ed6cc967027f2eb76d069369ac26f38fc87110fe55cc6487988a7d7bf2525a1b65cd02e30fcaa12d626f3b18d9191e6dcbf9fbe4b1f421dd2cb8ca804a7ca535c05bcb850561edb477eafe0a1e1e2468e89bb58899293d65cde98db5200b5eb32b1d80d4489fbab14a68f74453513658bda56067e8b41add0f13f5980ceb77c52f205e3d8b36f436ff0b313860197972de0da8b554b47091b8a69cf6ce7efd6cae6e17f090e0f71fc5332a9999cf880ff5c031132463b0eb56083885cee842f85540418b68d0250b18181b0dfb9487e39aad1d0402dc910cf679fd87d765222812ec66cf0a981f950de94b0fd1f45370bc2176748d20fe099c1f498c", 16), p), + new DHPrivateKeyParameters( + new BigInteger("9b6038b952d3491d937a41e1bf8857bd79b80a96c99783a96ff1ef93", 16), p)); + + AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair( + new DHPublicKeyParameters( + new BigInteger("991805c775da39e0b92dc71f212e332cbab2b62a86114836bbe091c5ba2ce12cca5011483e220c0f24bba23f24a32c2c11b966064beba99b0b21eb19c7f46b328dc30af094ec116248e6f3f856aab622da4eb36b6056d7c5a3e0a0f1c45acc24321fccd1d0e0f4503e3e3aae3748ae6adeb1b85e0f708b4877b7a8d97acab093a57820b9d861da6d919126ae1c0b2d28dccca03a1808c03d5c5b6847d5e43a70b0a07190ced3ccf419e9f790281cf4676cad5dc6c7d3591a9fde2251850e072ffbc0411d8559460303c56738a1dbf76c8dd165b62a407e8cac9455c9257016fa0c7892cbcb978489a909f74d38d10746c1d5756329607ab0479c994c5d6f30e3", 16), p), + new DHPrivateKeyParameters( + new BigInteger("2775ab7578d5c0e18d12ed02f8c38ddfe272712902ee6a256270b041", 16), p)); + + byte[] x = calculateUnifiedAgreement(U1, U2, V1, V2); + + if (x == null + || !areEqual(Hex.decode("0f028c915a5ff77f5997791b66f08261995f7b459a574d66412f00afe5af4b838da0b9a4ed371077f1160f063844bca86ae83838cce0974d130f489532a8aeee5d55df17c13a15f79f27144aa3533665a47867f3eb43feb963ac2201d2766fb62a3979c19411c94cedf2c283b59fc616fbeeca585deb726fc7002900dc300e7b9bc055261708fee0f1f9b90de4f3720b7ec85d68745f41d495f1001dd7ccbbacf42ff2edc28e33454c5c59897d9782142db3f47972e2a79f16028f5fc6cdce4c729c57e9f63b55e25e80e3663528942b79749d7d66f7d84d4c8c4e877e221a8e06c7f001cd50b008086a4b0981e5fe000b7896dee152b24ed9cdb9907a5d64f0e4225b3cba8268c45c0846a60a697218a683e1b33843cb0153d8634769882a7fef5db4653d827bd75b54dda96666944b5d836b875d76936f73520e57be069f6aba7c36d42fc07be3e7ea49d0dabfad3177aa673553ba93a990cb79df9bcd8fa979f81c75b280cb99ff8e09713546cae8dbaea1021d2c29902793d483f29c1153f432e8b00e039286b085df0260d4949703a4a7a46492d1cb586d1845182c5b5461a432c5ebe60650de40e9e25502a0dfb931c4d5e5d9b624dcab3cbb5bf7cc51e5dbf35cd7029e724840c660dd4a6014de92a2bbb8a1b6ce28f6448d28cf1975017f66bc6904d244fe91ec39e509568d1c8256fa79931875b7ab69e29e432cce"), x)) + { + fail("DH Combined Test Vector #1 agreement failed"); + } + } + + private void testCombinedTestVector2() + { + // Test Vector from NIST sample data + + BigInteger P = new BigInteger("ea40cd647d0a1d3bcbdfa721a837e4d4dfd328340892a00aa2317f2fc532fe1e185d4ef0718281959943fc949964e542310deb687f7fcc45696c829a491b7dc5c46fff01673e71d92520465b4115dbb7edaeb32ec2688d0a5a9be93a322f3023b96d5f54e02d4a72dec479f68b40caff79f810f3a5cdaa3bda9eb87151b4c0663ceef4b50ca22ac63e4ab1343978e8ec148b5523734b23aa9ca92a21ca1cbe652c9a01b1724a1b10285778287cb5bf87c45e45dc54998e5e5308c00003131be4a62add4f5acbb0c4e2229e0fccd1633e4cf024f96dcbf012e5b629394500b1b5ceb6707957bde445671ba9a1d5b9a7d1dfe2f1419d1abf236b4b49bcfd7563df", 16); + BigInteger Q = new BigInteger("aa6b31da31408f637670a1fc36ca3625a5eebea9bdcc4398124bb9a006ac21f1", 16); + BigInteger G = new BigInteger("380ad19f75e5c666aa24daf545d74c51a4374f9002de09744bc338a33a3ab2017fdeb59f1f8552125ade4dceb7094d125ffad694662e3fe924d23c7a404806631e353887bbc4bf9f892f581880975918aca5b8a7d5108b791469f2e35f0a4095ce253bec246a8cdce190507018a4f844685eb2e0ba0146d5bb2d7ff7f1c5624fa2d7f6d20834c453457eb0227c26ae5d422cde461cfe1cd2f5ff909388dcd6ccdbfb8617b54d9038c1b9b1b2f15febbd5215db893f3a8f340bd18ac74d025a63b321ec537fa5d2c04c651f0431f75bc490ddd2a846595c6d10d0a085ab3835d025a334cdb0b25c3d993fa22aecaf5f87ca417a7aa278cb765344195f2a45201b", 16); + + DHParameters p = new DHParameters(P, G, Q); + + AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair( + new DHPublicKeyParameters( + new BigInteger("a2c43dc18321063dac3cd7793fb3a6cc3b38cbce99f233ba295660aa6cbba1449b0783acb7da1118bd0530f022336a2bb8845ac26bb71c3647369e8aa29ef7b5ddc4a3b4fe70291c9acf1bc1ce5666a3401b885fd7b1906ed27a985efdb643464398036ed79eb1a79cd7b88c5bfa4418df6439ac2297b946f125f7086537082f2144545da570835b23f27ebd400ceae6670168fece4ce3780a59d6eebb3a76f91de308d4aa9a1617b4005b6b089af5c5247af6a5dea1693861151e0a5aaa4b86884ab2969f5bc3008f19ac54118939b2efccf307dc2e3aa675aea0d80dcaec7160408d6e12b0b041544c831b9ae3d06b5d51e2e77035f0b5439fb375a9bd7664", 16), p), + new DHPrivateKeyParameters( + new BigInteger("7b4957b799a08816f9c48c2aff5dcc0aa6ad93a765a664e67899f09d1fa8949e", 16), p)); + + AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair( + new DHPublicKeyParameters( + new BigInteger("5ceca3f30cb6eb8bef123518d9b569fb9df47ac54944e381da3f69ab4a3f0484e49ea8e54d87b2bcad6f78c82f9a1969b72c7b1314ccf2ff7aa857e69ae24dbbce023f8d3cfcb2b5fe942750597b1ada12b685bb12c6ddfddf0a9d2b95e0692d431f5735b71d456fabc7362581cad88ca97b69cf185ec2d6097b07a1da80291c4d93285b21604540dc1da0807009b8f708e4eb4bdd40672b875076d5f4e712b54922c6506de4280f2cf8b34d78ea59a91dd45c7eee8cd77d8640af48342ea348abed040f7dd085181bda8f9ce88cc602407ae91b4fcb051cfcff7e7479fb6e24f6b7fb013d5b3d2ccc3dc3088c331fc9644b73e1b47e3f585f97e6f2c57e9983", 16), p), + new DHPrivateKeyParameters( + new BigInteger("8f9fe1ecd00b427a211f9d52b973aad9451b5985757a2204473f06de07eb39e2", 16), p)); + + AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair( + new DHPublicKeyParameters( + new BigInteger("b823ca4d470c714efb57420cc50acbb56eb4a4664abb3fe233496c2a0f70e52a0af08f87490724819d8bfc10203dc62b38ee032f5e14e612e1b23d5b014359ab4fe3584f49475c9d117f9ad89511d88c79dcc284d39d722939b0b5d24ad7374af70db712344755fc54502d0ae428860f63fcdcd9537c0f89f451ada1a30676481154129de022019e5a6ac1c117820896ebd97d06db887d6fd088ab71ad0fd2f3c87a015abe428aeadee7a8a65a7b823edcf4b7d9b2faf98691126b885e5804bac1a8fa1d05c186de218816e0aa75e939b731621a424b39d19e47a81d3638ff3d663e38a802361fb9bd1e79b2f3d1f4955b3d7d63bcb373f2ee70659a270f5087", 16), p), + new DHPrivateKeyParameters( + new BigInteger("2c8c6202bb519b17361418f48ef346328db6be65b4aa6a25561e165b6958682e", 16), p)); + + AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair( + new DHPublicKeyParameters( + new BigInteger("dae7f69a4a318f506181bd97320777e9256dcf992057eb951585fbd5b6e22e0a57255f316315e462ee38e15a0e5c5b9fc3f6f0611929bfe681f0d093cdcda18e35e13f09d5c73cbab5f659b2c55669410e5a772b621acbfa365db6046b08bce1bac4c379ad0f2bee10eddb040645ab75d5888c93e91efdc442053e5e935541b80afa911881daa91488bceab9585facbbdb010575387eac4f6657fbdc85a37dedbfccbd9b37d671861c5853de9078bdf905f15b191f2dcc1c93ee7258dc6854a8d3882ff4f03753373305fa4a00a839c3853e128f51004a17641f37ed9035665c4a6d6240cbeefb9c36b618a50e3b75d6128f732b34d81ce8b316ddefe8c0630d", 16), p), + new DHPrivateKeyParameters( + new BigInteger("35f5bf981241cff39e43b93bf31f5612a364595a881e75315de0b42b82f0d596", 16), p)); + + byte[] x = calculateUnifiedAgreement(U1, U2, V1, V2); + + if (x == null + || !areEqual(Hex.decode("6d1eae28340c2095ab915b6655c96d23986c49e53f38de42a9c906eeeae3686744855b940de8377ad23053d923116f6dce7c91eea69714092a4e182cef01b362937c9bc66cc892948e79bac85bf0b9ee5c402c7725def46f754e5cd743e89247e84a4fe6e50b249c7aecf62114cb3beb6a0f8af8b0f3a19799c67372109fe0e01af6517d4108888cd3864b801a8566516b454219ee74b86a2e1a4cfbb2407198a1382858b947f9258404764fee9a0a99198c594fee426e04453b41051cfa22359d2b10d425142045b1a186056413203f4553ce0d7977012f1d3aa3df571f041f7422d4518da7abdf5a32bbbc86615cd2217b73719cb0b5ee5228a74ed0cb8202b862c68e46ab8282a482a9c94365e3dcb3b9b511bc65e7741f7d90f1180ef9c926ed9209cb10291d0ea472e675ac7704244723d788985aa6f5a73c83be4cdaba402453dfa572ac6d5bafb51b130556481e98a5ab5ede13364b886fbbf57f282b8f560f4ceafb2f29d953c8244aa3fea0c227a1a88e012e814267ecf36ac72793acf2ee02713d8980f30bc9231aae91a8181ed4645aa969625990cbdc7f4f646929132ef73354950c2490f91847a3350ece763a1869f6e446e4995296d4c024bf6998dd11aea59220e81e1aade984ba650150621f17e4bbca5f0f49fd21924c3a605d1e7e4fd3e32b93e1df6cd6a0d28cd9105537b513144e8ad1d3007bffbb15"), x)) + { + fail("DH Combined Test Vector #2 agreement failed"); + } + } + + private byte[] calculateUnifiedAgreement( + AsymmetricCipherKeyPair U1, + AsymmetricCipherKeyPair U2, + AsymmetricCipherKeyPair V1, + AsymmetricCipherKeyPair V2) + { + DHUnifiedAgreement u = new DHUnifiedAgreement(); + u.init(new DHUPrivateParameters( + (DHPrivateKeyParameters)U1.getPrivate(), + (DHPrivateKeyParameters)U2.getPrivate(), + (DHPublicKeyParameters)U2.getPublic())); + byte[] ux = u.calculateAgreement(new DHUPublicParameters( + (DHPublicKeyParameters)V1.getPublic(), + (DHPublicKeyParameters)V2.getPublic())); + + DHUnifiedAgreement v = new DHUnifiedAgreement(); + v.init(new DHUPrivateParameters( + (DHPrivateKeyParameters)V1.getPrivate(), + (DHPrivateKeyParameters)V2.getPrivate(), + (DHPublicKeyParameters)V2.getPublic())); + byte[] vx = v.calculateAgreement(new DHUPublicParameters( + (DHPublicKeyParameters)U1.getPublic(), + (DHPublicKeyParameters)U2.getPublic())); + + if (areEqual(ux, vx)) + { + return ux; + } + + return null; + } + + public void performTest() + { + testDHBasic(512, 0, g512, p512); + testDHBasic(768, 0, g768, p768); + testDHBasic(1024, 0, g1024, p1024); + + testDHBasic(512, 64, g512, p512); + testDHBasic(768, 128, g768, p768); + testDHBasic(1024, 256, g1024, p1024); + + testDH(512, g512, p512); + testDH(768, g768, p768); + testDH(1024, g1024, p1024); + + testBounds(); + + testCombinedTestVector1(); + testCombinedTestVector2(); + + // + // generation test. + // + testGeneration(256); + + // + // with random test + // + DHBasicKeyPairGenerator kpBasicGen = getDHBasicKeyPairGenerator(g512, p512, 0); + + testSimpleWithRandom(kpBasicGen); + + DHKeyPairGenerator kpGen = getDHKeyPairGenerator(g512, p512); + + testGPWithRandom(kpGen); + + // + // parameter tests + // + DHAgreement dh = new DHAgreement(); + AsymmetricCipherKeyPair dhPair = kpGen.generateKeyPair(); + + try + { + dh.init(dhPair.getPublic()); + fail("DHAgreement key check failed"); + } + catch (IllegalArgumentException e) + { + // ignore + } + + DHKeyPairGenerator kpGen768 = getDHKeyPairGenerator(g768, p768); + + try + { + dh.init(dhPair.getPrivate()); + + dh.calculateAgreement((DHPublicKeyParameters)kpGen768.generateKeyPair().getPublic(), BigInteger.valueOf(100)); + + fail("DHAgreement agreement check failed"); + } + catch (IllegalArgumentException e) + { + // ignore + } + + DHBasicAgreement dhBasic = new DHBasicAgreement(); + AsymmetricCipherKeyPair dhBasicPair = kpBasicGen.generateKeyPair(); + + try + { + dhBasic.init(dhBasicPair.getPublic()); + fail("DHBasicAgreement key check failed"); + } + catch (IllegalArgumentException e) + { + // expected + } + + DHBasicKeyPairGenerator kpBasicGen768 = getDHBasicKeyPairGenerator(g768, p768, 0); + + try + { + dhBasic.init(dhPair.getPrivate()); + + dhBasic.calculateAgreement((DHPublicKeyParameters)kpBasicGen768.generateKeyPair().getPublic()); + + fail("DHBasicAgreement agreement check failed"); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + public static void main( + String[] args) + { + runTest(new DHTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSATest.java new file mode 100644 index 000000000..d101d7da8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSATest.java @@ -0,0 +1,725 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.digests.SHA224Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA3Digest; +import com.fr.third.org.bouncycastle.crypto.generators.DSAKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.DSAParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.params.DSAKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAParameterGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAValidationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.signers.DSADigestSigner; +import com.fr.third.org.bouncycastle.crypto.signers.DSASigner; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.FixedSecureRandom; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; +import com.fr.third.org.bouncycastle.util.test.TestRandomData; + +/** + * Test based on FIPS 186-2, Appendix 5, an example of DSA, and FIPS 168-3 test vectors. + */ +public class DSATest + extends SimpleTest +{ + byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); + byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); + + SecureRandom random = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2) }); + + byte[] keyData = Hex.decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); + + SecureRandom keyRandom = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(Hex.decode("01020304"))}); + + BigInteger pValue = new BigInteger("8df2a494492276aa3d25759bb06869cbeac0d83afb8d0cf7cbb8324f0d7882e5d0762fc5b7210eafc2e9adac32ab7aac49693dfbf83724c2ec0736ee31c80291", 16); + BigInteger qValue = new BigInteger("c773218c737ec8ee993b4f2ded30f48edace915f", 16); + + public String getName() + { + return "DSA"; + } + + public void performTest() + { + BigInteger r = new BigInteger("68076202252361894315274692543577577550894681403"); + BigInteger s = new BigInteger("1089214853334067536215539335472893651470583479365"); + DSAParametersGenerator pGen = new DSAParametersGenerator(); + + pGen.init(512, 80, random); + + DSAParameters params = pGen.generateParameters(); + DSAValidationParameters pValid = params.getValidationParameters(); + + if (pValid.getCounter() != 105) + { + fail("Counter wrong"); + } + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + fail("p or q wrong"); + } + + DSAKeyPairGenerator dsaKeyGen = new DSAKeyPairGenerator(); + DSAKeyGenerationParameters genParam = new DSAKeyGenerationParameters(keyRandom, params); + + dsaKeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = dsaKeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), keyRandom); + + DSASigner dsa = new DSASigner(); + + dsa.init(true, param); + + byte[] message = BigIntegers.asUnsignedByteArray(new BigInteger("968236873715988614170569073515315707566766479517")); + BigInteger[] sig = dsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong.", r, sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong.", s, sig[1]); + } + + dsa.init(false, pair.getPublic()); + + if (!dsa.verifySignature(message, sig[0], sig[1])) + { + fail("verification fails"); + } + + dsa2Test1(); + dsa2Test2(); + dsa2Test3(); + dsa2Test4(); + + testDSAsha3(224, new BigInteger("613202af2a7f77e02b11b5c3a5311cf6b412192bc0032aac3ec127faebfc6bd0", 16)); + testDSAsha3(256, new BigInteger("2450755c5e15a691b121bc833b97864e34a61ee025ecec89289c949c1858091e", 16)); + testDSAsha3(384, new BigInteger("7aad97c0b71bb1e1a6483b6948a03bbe952e4780b0cee699a11731f90d84ddd1", 16)); + testDSAsha3(512, new BigInteger("725ad64d923c668e64e7c3898b5efde484cab49ce7f98c2885d2a13a9e355ad4", 16)); + } + + private void testDSAsha3(int size, BigInteger s) + { + DSAParameters dsaParams = new DSAParameters( + new BigInteger( + "F56C2A7D366E3EBDEAA1891FD2A0D099" + + "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" + + "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" + + "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" + + "5909132627F51A0C866877E672E555342BDF9355347DBD43" + + "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" + + "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" + + "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" + + "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" + + "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" + + "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16), + new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16), + new BigInteger( + "8DC6CC814CAE4A1C05A3E186A6FE27EA" + + "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" + + "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" + + "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" + + "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" + + "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" + + "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" + + "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" + + "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" + + "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" + + "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16) + ); + + BigInteger x = new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16); + + BigInteger y = new BigInteger( + "2828003D7C747199143C370FDD07A286" + + "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" + + "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" + + "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" + + "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" + + "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" + + "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" + + "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" + + "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" + + "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" + + "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16); + + DSAPrivateKeyParameters priKey = new DSAPrivateKeyParameters(x, dsaParams); + SecureRandom k = new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))), + new FixedSecureRandom.Data(Hex.decode("01020304")) + }); + + byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); + + DSADigestSigner dsa = new DSADigestSigner(new DSASigner(), new SHA3Digest(size)); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + dsa.update(M, 0, M.length); + + byte[] encSig = dsa.generateSignature(); + + ASN1Sequence sig = ASN1Sequence.getInstance(encSig); + + BigInteger r = new BigInteger("4864074fe30e6601268ee663440e4d9b703f62673419864e91e9edb0338ce510", 16); + + BigInteger sigR = ASN1Integer.getInstance(sig.getObjectAt(0)).getValue(); + if (!r.equals(sigR)) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sigR.toString(16)); + } + + BigInteger sigS = ASN1Integer.getInstance(sig.getObjectAt(1)).getValue(); + if (!s.equals(sigS)) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sigS.toString(16)); + } + + // Verify the signature + DSAPublicKeyParameters pubKey = new DSAPublicKeyParameters(y, dsaParams); + + dsa.init(false, pubKey); + + dsa.update(M, 0, M.length); + + if (!dsa.verifySignature(encSig)) + { + fail("signature fails"); + } + } + + private void dsa2Test1() + { + byte[] seed = Hex.decode("ED8BEE8D1CB89229D2903CBF0E51EE7377F48698"); + + DSAParametersGenerator pGen = new DSAParametersGenerator(); + + pGen.init(new DSAParameterGenerationParameters(1024, 160, 80, new DSATestSecureRandom(seed))); + + DSAParameters params = pGen.generateParameters(); + + DSAValidationParameters pv = params.getValidationParameters(); + + if (pv.getCounter() != 5) + { + fail("counter incorrect"); + } + + if (!Arrays.areEqual(seed, pv.getSeed())) + { + fail("seed incorrect"); + } + + if (!params.getQ().equals(new BigInteger("E950511EAB424B9A19A2AEB4E159B7844C589C4F", 16))) + { + fail("Q incorrect"); + } + + if (!params.getP().equals(new BigInteger( + "E0A67598CD1B763B" + + "C98C8ABB333E5DDA0CD3AA0E5E1FB5BA8A7B4EABC10BA338" + + "FAE06DD4B90FDA70D7CF0CB0C638BE3341BEC0AF8A7330A3" + + "307DED2299A0EE606DF035177A239C34A912C202AA5F83B9" + + "C4A7CF0235B5316BFC6EFB9A248411258B30B839AF172440" + + "F32563056CB67A861158DDD90E6A894C72A5BBEF9E286C6B", 16))) + { + fail("P incorrect"); + } + + if (!params.getG().equals(new BigInteger( + "D29D5121B0423C27" + + "69AB21843E5A3240FF19CACC792264E3BB6BE4F78EDD1B15" + + "C4DFF7F1D905431F0AB16790E1F773B5CE01C804E509066A" + + "9919F5195F4ABC58189FD9FF987389CB5BEDF21B4DAB4F8B" + + "76A055FFE2770988FE2EC2DE11AD92219F0B351869AC24DA" + + "3D7BA87011A701CE8EE7BFE49486ED4527B7186CA4610A75", 16))) + { + fail("G incorrect"); + } + + DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); + + kpGen.init(new DSAKeyGenerationParameters(new TestRandomBigInteger("D0EC4E50BB290A42E9E355C73D8809345DE2E139", 16), params)); + + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic(); + DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate(); + + if (!pub.getY().equals(new BigInteger( + "25282217F5730501" + + "DD8DBA3EDFCF349AAFFEC20921128D70FAC44110332201BB" + + "A3F10986140CBB97C726938060473C8EC97B4731DB004293" + + "B5E730363609DF9780F8D883D8C4D41DED6A2F1E1BBBDC97" + + "9E1B9D6D3C940301F4E978D65B19041FCF1E8B518F5C0576" + + "C770FE5A7A485D8329EE2914A2DE1B5DA4A6128CEAB70F79", 16))) + { + fail("Y value incorrect"); + } + + if (!priv.getX().equals( + new BigInteger("D0EC4E50BB290A42E9E355C73D8809345DE2E139", 16))) + { + fail("X value incorrect"); + } + + DSASigner signer = new DSASigner(); + + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger("349C55648DCF992F3F33E8026CFAC87C1D2BA075"), + new FixedSecureRandom.Data(Hex.decode("01020304")) }))); + + byte[] msg = Hex.decode("A9993E364706816ABA3E25717850C26C9CD0D89D"); + + BigInteger[] sig = signer.generateSignature(msg); + + if (!sig[0].equals(new BigInteger("636155AC9A4633B4665D179F9E4117DF68601F34", 16))) + { + fail("R value incorrect"); + } + + if (!sig[1].equals(new BigInteger("6C540B02D9D4852F89DF8CFC99963204F4347704", 16))) + { + fail("S value incorrect"); + } + + signer.init(false, kp.getPublic()); + + if (!signer.verifySignature(msg, sig[0], sig[1])) + { + fail("signature not verified"); + } + + } + + private void dsa2Test2() + { + byte[] seed = Hex.decode("5AFCC1EFFC079A9CCA6ECA86D6E3CC3B18642D9BE1CC6207C84002A9"); + + DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA224Digest()); + + pGen.init(new DSAParameterGenerationParameters(2048, 224, 80, new DSATestSecureRandom(seed))); + + DSAParameters params = pGen.generateParameters(); + + DSAValidationParameters pv = params.getValidationParameters(); + + if (pv.getCounter() != 21) + { + fail("counter incorrect"); + } + + if (!Arrays.areEqual(seed, pv.getSeed())) + { + fail("seed incorrect"); + } + + if (!params.getQ().equals(new BigInteger("90EAF4D1AF0708B1B612FF35E0A2997EB9E9D263C9CE659528945C0D", 16))) + { + fail("Q incorrect"); + } + + if (!params.getP().equals(new BigInteger( + "C196BA05AC29E1F9C3C72D56DFFC6154" + + "A033F1477AC88EC37F09BE6C5BB95F51C296DD20D1A28A06" + + "7CCC4D4316A4BD1DCA55ED1066D438C35AEBAABF57E7DAE4" + + "28782A95ECA1C143DB701FD48533A3C18F0FE23557EA7AE6" + + "19ECACC7E0B51652A8776D02A425567DED36EABD90CA33A1" + + "E8D988F0BBB92D02D1D20290113BB562CE1FC856EEB7CDD9" + + "2D33EEA6F410859B179E7E789A8F75F645FAE2E136D252BF" + + "FAFF89528945C1ABE705A38DBC2D364AADE99BE0D0AAD82E" + + "5320121496DC65B3930E38047294FF877831A16D5228418D" + + "E8AB275D7D75651CEFED65F78AFC3EA7FE4D79B35F62A040" + + "2A1117599ADAC7B269A59F353CF450E6982D3B1702D9CA83", 16))) + { + fail("P incorrect"); + } + + if (!params.getG().equals(new BigInteger( + "A59A749A11242C58C894E9E5A91804E8"+ + "FA0AC64B56288F8D47D51B1EDC4D65444FECA0111D78F35F"+ + "C9FDD4CB1F1B79A3BA9CBEE83A3F811012503C8117F98E50"+ + "48B089E387AF6949BF8784EBD9EF45876F2E6A5A495BE64B"+ + "6E770409494B7FEE1DBB1E4B2BC2A53D4F893D418B715959"+ + "2E4FFFDF6969E91D770DAEBD0B5CB14C00AD68EC7DC1E574"+ + "5EA55C706C4A1C5C88964E34D09DEB753AD418C1AD0F4FDF"+ + "D049A955E5D78491C0B7A2F1575A008CCD727AB376DB6E69"+ + "5515B05BD412F5B8C2F4C77EE10DA48ABD53F5DD498927EE"+ + "7B692BBBCDA2FB23A516C5B4533D73980B2A3B60E384ED20"+ + "0AE21B40D273651AD6060C13D97FD69AA13C5611A51B9085", 16))) + { + fail("G incorrect"); + } + + DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); + + kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17")), params)); + + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic(); + DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate(); + + if (!pub.getY().equals(new BigInteger( + "70035C9A3B225B258F16741F3941FBF0" + + "6F3D056CD7BD864604CBB5EE9DD85304EE8E8E4ABD5E9032" + + "11DDF25CE149075510ACE166970AFDC7DF552B7244F342FA" + + "02F7A621405B754909D757F97290E1FE5036E904CF593446" + + "0C046D95659821E1597ED9F2B1F0E20863A6BBD0CE74DACB" + + "A5D8C68A90B29C2157CDEDB82EC12B81EE3068F9BF5F7F34" + + "6ECA41ED174CCCD7D154FA4F42F80FFE1BF46AE9D8125DEB" + + "5B4BA08A72BDD86596DBEDDC9550FDD650C58F5AE5133509" + + "A702F79A31ECB490F7A3C5581631F7C5BE4FF7F9E9F27FA3" + + "90E47347AD1183509FED6FCF198BA9A71AB3335B4F38BE8D" + + "15496A00B6DC2263E20A5F6B662320A3A1EC033AA61E3B68", 16))) + { + fail("Y value incorrect"); + } + + if (!priv.getX().equals( + new BigInteger("00D0F09ED3E2568F6CADF9224117DA2AEC5A4300E009DE1366023E17", 16))) + { + fail("X value incorrect"); + } + + DSASigner signer = new DSASigner(); + + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger(Hex.decode("735959CC4463B8B440E407EECA8A473BF6A6D1FE657546F67D401F05")), + new FixedSecureRandom.Data(Hex.decode("01020304")) + }))); + + byte[] msg = Hex.decode("23097D223405D8228642A477BDA255B32AADBCE4BDA0B3F7E36C9DA7"); + + BigInteger[] sig = signer.generateSignature(msg); + + if (!sig[0].equals(new BigInteger("4400138D05F9639CAF54A583CAAF25D2B76D0C3EAD752CE17DBC85FE", 16))) + { + fail("R value incorrect"); + } + + if (!sig[1].equals(new BigInteger("874D4F12CB13B61732D398445698CFA9D92381D938AA57EE2C9327B3", 16))) + { + fail("S value incorrect"); + } + + signer.init(false, kp.getPublic()); + + if (!signer.verifySignature(msg, sig[0], sig[1])) + { + fail("signature not verified"); + } + } + + private void dsa2Test3() + { + byte[] seed = Hex.decode("4783081972865EA95D43318AB2EAF9C61A2FC7BBF1B772A09017BDF5A58F4FF0"); + + DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA256Digest()); + + pGen.init(new DSAParameterGenerationParameters(2048, 256, 80, new DSATestSecureRandom(seed))); + + DSAParameters params = pGen.generateParameters(); + + DSAValidationParameters pv = params.getValidationParameters(); + + if (pv.getCounter() != 12) + { + fail("counter incorrect"); + } + + if (!Arrays.areEqual(seed, pv.getSeed())) + { + fail("seed incorrect"); + } + + if (!params.getQ().equals(new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16))) + { + fail("Q incorrect"); + } + + if (!params.getP().equals(new BigInteger( + "F56C2A7D366E3EBDEAA1891FD2A0D099" + + "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" + + "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" + + "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" + + "5909132627F51A0C866877E672E555342BDF9355347DBD43" + + "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" + + "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" + + "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" + + "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" + + "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" + + "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16))) + { + fail("P incorrect"); + } + + if (!params.getG().equals(new BigInteger( + "8DC6CC814CAE4A1C05A3E186A6FE27EA" + + "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" + + "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" + + "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" + + "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" + + "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" + + "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" + + "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" + + "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" + + "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" + + "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16))) + { + fail("G incorrect"); + } + + DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); + + kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), params)); + + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic(); + DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate(); + + if (!pub.getY().equals(new BigInteger( + "2828003D7C747199143C370FDD07A286" + + "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" + + "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" + + "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" + + "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" + + "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" + + "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" + + "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" + + "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" + + "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" + + "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16))) + { + fail("Y value incorrect"); + } + + if (!priv.getX().equals( + new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16))) + { + fail("X value incorrect"); + } + + DSASigner signer = new DSASigner(); + + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] { + new FixedSecureRandom.BigInteger(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C")), + new FixedSecureRandom.Data(Hex.decode("01020304")) + }))); + + byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"); + + BigInteger[] sig = signer.generateSignature(msg); + + if (!sig[0].equals(new BigInteger("315C875DCD4850E948B8AC42824E9483A32D5BA5ABE0681B9B9448D444F2BE3C", 16))) + { + fail("R value incorrect"); + } + + if (!sig[1].equals(new BigInteger("89718D12E54A8D9ED066E4A55F7ED5A2229CD23B9A3CEE78F83ED6AA61F6BCB9", 16))) + { + fail("S value incorrect"); + } + + signer.init(false, kp.getPublic()); + + if (!signer.verifySignature(msg, sig[0], sig[1])) + { + fail("signature not verified"); + } + } + + private void dsa2Test4() + { + byte[] seed = Hex.decode("193AFCA7C1E77B3C1ECC618C81322E47B8B8B997C9C83515C59CC446C2D9BD47"); + + DSAParametersGenerator pGen = new DSAParametersGenerator(new SHA256Digest()); + + pGen.init(new DSAParameterGenerationParameters(3072, 256, 80, new DSATestSecureRandom(seed))); + + DSAParameters params = pGen.generateParameters(); + + DSAValidationParameters pv = params.getValidationParameters(); + + if (pv.getCounter() != 20) + { + fail("counter incorrect"); + } + + if (!Arrays.areEqual(seed, pv.getSeed())) + { + fail("seed incorrect"); + } + + if (!params.getQ().equals(new BigInteger("CFA0478A54717B08CE64805B76E5B14249A77A4838469DF7F7DC987EFCCFB11D", 16))) + { + fail("Q incorrect"); + } + + if (!params.getP().equals(new BigInteger( + "90066455B5CFC38F9CAA4A48B4281F292C260FEEF01FD610" + + "37E56258A7795A1C7AD46076982CE6BB956936C6AB4DCFE0" + + "5E6784586940CA544B9B2140E1EB523F009D20A7E7880E4E" + + "5BFA690F1B9004A27811CD9904AF70420EEFD6EA11EF7DA1" + + "29F58835FF56B89FAA637BC9AC2EFAAB903402229F491D8D" + + "3485261CD068699B6BA58A1DDBBEF6DB51E8FE34E8A78E54" + + "2D7BA351C21EA8D8F1D29F5D5D15939487E27F4416B0CA63" + + "2C59EFD1B1EB66511A5A0FBF615B766C5862D0BD8A3FE7A0" + + "E0DA0FB2FE1FCB19E8F9996A8EA0FCCDE538175238FC8B0E" + + "E6F29AF7F642773EBE8CD5402415A01451A840476B2FCEB0" + + "E388D30D4B376C37FE401C2A2C2F941DAD179C540C1C8CE0" + + "30D460C4D983BE9AB0B20F69144C1AE13F9383EA1C08504F" + + "B0BF321503EFE43488310DD8DC77EC5B8349B8BFE97C2C56" + + "0EA878DE87C11E3D597F1FEA742D73EEC7F37BE43949EF1A" + + "0D15C3F3E3FC0A8335617055AC91328EC22B50FC15B941D3" + + "D1624CD88BC25F3E941FDDC6200689581BFEC416B4B2CB73", 16))) + { + fail("P incorrect"); + } + + if (!params.getG().equals(new BigInteger( + "5E5CBA992E0A680D885EB903AEA78E4A45A469103D448EDE" + + "3B7ACCC54D521E37F84A4BDD5B06B0970CC2D2BBB715F7B8" + + "2846F9A0C393914C792E6A923E2117AB805276A975AADB52" + + "61D91673EA9AAFFEECBFA6183DFCB5D3B7332AA19275AFA1" + + "F8EC0B60FB6F66CC23AE4870791D5982AAD1AA9485FD8F4A" + + "60126FEB2CF05DB8A7F0F09B3397F3937F2E90B9E5B9C9B6" + + "EFEF642BC48351C46FB171B9BFA9EF17A961CE96C7E7A7CC" + + "3D3D03DFAD1078BA21DA425198F07D2481622BCE45969D9C" + + "4D6063D72AB7A0F08B2F49A7CC6AF335E08C4720E31476B6" + + "7299E231F8BD90B39AC3AE3BE0C6B6CACEF8289A2E2873D5" + + "8E51E029CAFBD55E6841489AB66B5B4B9BA6E2F784660896" + + "AFF387D92844CCB8B69475496DE19DA2E58259B090489AC8" + + "E62363CDF82CFD8EF2A427ABCD65750B506F56DDE3B98856" + + "7A88126B914D7828E2B63A6D7ED0747EC59E0E0A23CE7D8A" + + "74C1D2C2A7AFB6A29799620F00E11C33787F7DED3B30E1A2" + + "2D09F1FBDA1ABBBFBF25CAE05A13F812E34563F99410E73B", 16))) + { + fail("G incorrect"); + } + + DSAKeyPairGenerator kpGen = new DSAKeyPairGenerator(); + + kpGen.init(new DSAKeyGenerationParameters(new TestRandomData(Hex.decode("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764")), params)); + + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + DSAPublicKeyParameters pub = (DSAPublicKeyParameters)kp.getPublic(); + DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)kp.getPrivate(); + + if (!pub.getY().equals(new BigInteger( + "8B891C8692D3DE875879390F2698B26FBECCA6B075535DCE" + + "6B0C862577F9FA0DEF6074E7A7624121224A595896ABD4CD" + + "A56B2CEFB942E025D2A4282FFAA98A48CDB47E1A6FCB5CFB" + + "393EF35AF9DF913102BB303C2B5C36C3F8FC04ED7B8B69FE" + + "FE0CF3E1FC05CFA713B3435B2656E913BA8874AEA9F93600" + + "6AEB448BCD005D18EC3562A33D04CF25C8D3D69844343442" + + "FA3DB7DE618C5E2DA064573E61E6D5581BFB694A23AC87FD" + + "5B52D62E954E1376DB8DDB524FFC0D469DF978792EE44173" + + "8E5DB05A7DC43E94C11A2E7A4FBE383071FA36D2A7EC8A93" + + "88FE1C4F79888A99D3B6105697C2556B79BB4D7E781CEBB3" + + "D4866AD825A5E830846072289FDBC941FA679CA82F5F78B7" + + "461B2404DB883D215F4E0676CF5493950AC5591697BFEA8D" + + "1EE6EC016B89BA51CAFB5F9C84C989FA117375E94578F28B" + + "E0B34CE0545DA46266FD77F62D8F2CEE92AB77012AFEBC11" + + "008985A821CD2D978C7E6FE7499D1AAF8DE632C21BB48CA5" + + "CBF9F31098FD3FD3854C49A65D9201744AACE540354974F9", 16))) + { + fail("Y value incorrect"); + } + + if (!priv.getX().equals( + new BigInteger("3ABC1587297CE7B9EA1AD6651CF2BC4D7F92ED25CABC8553F567D1B40EBB8764", 16))) + { + fail("X value incorrect"); + } + + DSASigner signer = new DSASigner(); + + signer.init(true, new ParametersWithRandom(kp.getPrivate(), new FixedSecureRandom( + new FixedSecureRandom.Source[] + { new FixedSecureRandom.BigInteger("A6902C1E6E3943C5628061588A8B007BCCEA91DBF12915483F04B24AB0678BEE"), + new FixedSecureRandom.Data(Hex.decode("01020304")) }))); + + byte[] msg = Hex.decode("BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"); + + BigInteger[] sig = signer.generateSignature(msg); + + if (!sig[0].equals(new BigInteger("5F184E645A38BE8FB4A6871B6503A9D12924C7ABE04B71410066C2ECA6E3BE3E", 16))) + { + fail("R value incorrect"); + } + + if (!sig[1].equals(new BigInteger("91EB0C7BA3D4B9B60B825C3D9F2CADA8A2C9D7723267B033CBCDCF8803DB9C18", 16))) + { + fail("S value incorrect"); + } + + signer.init(false, kp.getPublic()); + + if (!signer.verifySignature(msg, sig[0], sig[1])) + { + fail("signature not verified"); + } + } + + public static void main( + String[] args) + { + runTest(new DSATest()); + } + + private class DSATestSecureRandom + extends TestRandomData + { + private boolean first = true; + + public DSATestSecureRandom(byte[] value) + { + super(value); + } + + public void nextBytes(byte[] bytes) + { + if (first) + { + super.nextBytes(bytes); + first = false; + } + else + { + bytes[bytes.length - 1] = 2; + } + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSTU4145Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSTU4145Test.java new file mode 100644 index 000000000..bb11e38b8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSTU4145Test.java @@ -0,0 +1,278 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.signers.DSTU4145Signer; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomData; + +public class DSTU4145Test + extends SimpleTest +{ + private static final BigInteger ZERO = BigInteger.valueOf(0); + private static final BigInteger ONE = BigInteger.valueOf(1); + + public static void main(String[] args) + { + runTest(new DSTU4145Test()); + } + + public String getName() + { + return "DSTU4145"; + } + + private void test163() + throws Exception + { + SecureRandom random = new TestRandomData(Hex.decode("01025e40bd97db012b7a1d79de8e12932d247f61c6")); + + byte[] hash = Hex.decode("09c9c44277910c9aaee486883a2eb95b7180166ddf73532eeb76edaef52247ff"); + for (int i = 0; i < hash.length / 2; i++) + { + byte tmp = hash[i]; + hash[i] = hash[hash.length - 1 - i]; + hash[hash.length - 1 - i] = tmp; + } + + BigInteger r = new BigInteger("274ea2c0caa014a0d80a424f59ade7a93068d08a7", 16); + BigInteger s = new BigInteger("2100d86957331832b8e8c230f5bd6a332b3615aca", 16); + + ECCurve.F2m curve = new ECCurve.F2m(163, 3, 6, 7, ONE, new BigInteger("5FF6108462A2DC8210AB403925E638A19C1455D21", 16)); + ECPoint P = curve.createPoint(new BigInteger("72d867f93a93ac27df9ff01affe74885c8c540420", 16), new BigInteger("0224a9c3947852b97c5599d5f4ab81122adc3fd9b", 16)); + BigInteger n = new BigInteger("400000000000000000002BEC12BE2262D39BCF14D", 16); + + BigInteger d = new BigInteger("183f60fdf7951ff47d67193f8d073790c1c9b5a3e", 16); + ECPoint Q = P.multiply(d).negate(); + + ECDomainParameters domain = new ECDomainParameters(curve, P, n); + CipherParameters privKey = new ParametersWithRandom(new ECPrivateKeyParameters(d, domain), random); + ECPublicKeyParameters pubKey = new ECPublicKeyParameters(Q, domain); + + DSTU4145Signer dstuSigner = new DSTU4145Signer(); + dstuSigner.init(true, privKey); + BigInteger[] rs = dstuSigner.generateSignature(hash); + + if (rs[0].compareTo(r) != 0) + { + fail("r component wrong"); + } + + if (rs[1].compareTo(s) != 0) + { + fail("s component wrong"); + } + + dstuSigner.init(false, pubKey); + if (!dstuSigner.verifySignature(hash, r, s)) + { + fail("verification fails"); + } + } + + private void test173() + throws Exception + { + SecureRandom random = new TestRandomData(Hex.decode("0000137449348C1249971759D99C252FFE1E14D8B31F")); + + byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8"); + for (int i = 0; i < hash.length / 2; i++) + { + byte tmp = hash[i]; + hash[i] = hash[hash.length - 1 - i]; + hash[hash.length - 1 - i] = tmp; + } + + BigInteger r = new BigInteger("13ae89746386709cdbd237cc5ec20ca30004a82ead8", 16); + BigInteger s = new BigInteger("3597912cdd093b3e711ccb74a79d3c4ab4c7cccdc60", 16); + + ECCurve.F2m curve = new ECCurve.F2m(173, 1, 2, 10, ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16)); + ECPoint P = curve.createPoint(new BigInteger("BE6628EC3E67A91A4E470894FBA72B52C515F8AEE9", 16), new BigInteger("D9DEEDF655CF5412313C11CA566CDC71F4DA57DB45C", 16)); + BigInteger n = new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16); + + BigInteger d = new BigInteger("955CD7E344303D1034E66933DC21C8044D42ADB8", 16); + ECPoint Q = P.multiply(d).negate(); + + ECDomainParameters domain = new ECDomainParameters(curve, P, n); + CipherParameters privKey = new ParametersWithRandom(new ECPrivateKeyParameters(d, domain), random); + ECPublicKeyParameters pubKey = new ECPublicKeyParameters(Q, domain); + + DSTU4145Signer dstuSigner = new DSTU4145Signer(); + dstuSigner.init(true, privKey); + BigInteger[] rs = dstuSigner.generateSignature(hash); + + if (rs[0].compareTo(r) != 0) + { + fail("r component wrong"); + } + + if (rs[1].compareTo(s) != 0) + { + fail("s component wrong"); + } + + dstuSigner.init(false, pubKey); + if (!dstuSigner.verifySignature(hash, r, s)) + { + fail("verification fails"); + } + } + + private void test283() + throws Exception + { + SecureRandom random = new TestRandomData(Hex.decode("00000000245383CB3AD41BF30F5F7E8FBA858509B2D5558C92D539A6D994BFA98BC6940E")); + + byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8"); + for (int i = 0; i < hash.length / 2; i++) + { + byte tmp = hash[i]; + hash[i] = hash[hash.length - 1 - i]; + hash[hash.length - 1 - i] = tmp; + } + + BigInteger r = new BigInteger("12a5edcc38d92208ff23036d75b000c7e4bc0f9af2d40b35f15d6fd15e01234e67781a8", 16); + BigInteger s = new BigInteger("2de0775577f75b643cf5afc80d4fe10b21100690f17e2cab7bdc9b50ec87c5727aeb515", 16); + + ECCurve.F2m curve = new ECCurve.F2m(283, 5, 7, 12, ONE, new BigInteger("27B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", 16)); + ECPoint P = curve.createPoint(new BigInteger("4D95820ACE761110824CE425C8089129487389B7F0E0A9D043DDC0BB0A4CC9EB25", 16), new BigInteger("954C9C4029B2C62DE35C2B9C2A164984BF1101951E3A68ED03DF234DDE5BB2013152F2", 16)); + BigInteger n = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", 16); + + BigInteger d = new BigInteger("B844EEAF15213E4BAD4FB84796D68F2448DB8EB7B4621EC0D51929874892C43E", 16); + ECPoint Q = P.multiply(d).negate(); + + ECDomainParameters domain = new ECDomainParameters(curve, P, n); + CipherParameters privKey = new ParametersWithRandom(new ECPrivateKeyParameters(d, domain), random); + ECPublicKeyParameters pubKey = new ECPublicKeyParameters(Q, domain); + + DSTU4145Signer dstuSigner = new DSTU4145Signer(); + dstuSigner.init(true, privKey); + BigInteger[] rs = dstuSigner.generateSignature(hash); + + if (rs[0].compareTo(r) != 0) + { + fail("r component wrong"); + } + + if (rs[1].compareTo(s) != 0) + { + fail("s component wrong"); + } + + dstuSigner.init(false, pubKey); + if (!dstuSigner.verifySignature(hash, r, s)) + { + fail("verification fails"); + } + } + + private void test431() + throws Exception + { + SecureRandom random = new TestRandomData(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457")); + + byte[] hash = Hex.decode("0137187EA862117EF1484289470ECAC802C5A651FDA8"); + for (int i = 0; i < hash.length / 2; i++) + { + byte tmp = hash[i]; + hash[i] = hash[hash.length - 1 - i]; + hash[hash.length - 1 - i] = tmp; + } + + BigInteger r = new BigInteger("1911fefb1f494bebcf8dffdf5276946ff9c9f662192ee18c718db47310a439c784fe07577b16e1edbe16179876e0792a634f1c9c3a2e", 16); + BigInteger s = new BigInteger("3852170ee801c2083c52f1ea77b987a5432acecd9c654f064e87bf179e0a397151edbca430082e43bd38a67b55424b5bbc7f2713f620", 16); + + ECCurve.F2m curve = new ECCurve.F2m(431, 1, 3, 5, ONE, new BigInteger("3CE10490F6A708FC26DFE8C3D27C4F94E690134D5BFF988D8D28AAEAEDE975936C66BAC536B18AE2DC312CA493117DAA469C640CAF3", 16)); + ECPoint P = curve.createPoint(new BigInteger("9548BCDF314CEEEAF099C780FFEFBF93F9FE5B5F55547603C9C8FC1A2774170882B3BE35E892C6D4296B8DEA282EC30FB344272791", 16), new BigInteger("4C6CBD7C62A8EEEFDE17A8B5E196E49A22CE6DE128ABD9FBD81FA4411AD5A38E2A810BEDE09A7C6226BCDCB4A4A5DA37B4725E00AA74", 16)); + BigInteger n = new BigInteger("3FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBA3175458009A8C0A724F02F81AA8A1FCBAF80D90C7A95110504CF", 16); + + BigInteger d = new BigInteger("D0F97354E314191FD773E2404F478C8AEE0FF5109F39E6F37D1FEEC8B2ED1691D84C9882CC729E716A71CC013F66CAC60E29E22C", 16); + ECPoint Q = P.multiply(d).negate(); + + ECDomainParameters domain = new ECDomainParameters(curve, P, n); + CipherParameters privKey = new ParametersWithRandom(new ECPrivateKeyParameters(d, domain), random); + ECPublicKeyParameters pubKey = new ECPublicKeyParameters(Q, domain); + + DSTU4145Signer dstuSigner = new DSTU4145Signer(); + dstuSigner.init(true, privKey); + BigInteger[] rs = dstuSigner.generateSignature(hash); + + if (rs[0].compareTo(r) != 0) + { + fail("r component wrong"); + } + + if (rs[1].compareTo(s) != 0) + { + fail("s component wrong"); + } + + dstuSigner.init(false, pubKey); + if (!dstuSigner.verifySignature(hash, r, s)) + { + fail("verification fails"); + } + } + + private void testTruncation() + { + SecureRandom random = new TestRandomData(Hex.decode("0000C4224DBBD800988DBAA39DE838294C345CDA5F5929D1174AA8D9340A5E79D10ACADE6B53CF873E7301A3871C2073AD75AB530457")); + + // use extra long "hash" with set bits... + byte[] hash = Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"); + + ECCurve.F2m curve = new ECCurve.F2m(173, 1, 2, 10, ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16)); + ECPoint P = curve.createPoint(new BigInteger("BE6628EC3E67A91A4E470894FBA72B52C515F8AEE9", 16), new BigInteger("D9DEEDF655CF5412313C11CA566CDC71F4DA57DB45C", 16)); + BigInteger n = new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16); + + BigInteger d = new BigInteger("955CD7E344303D1034E66933DC21C8044D42ADB8", 16); + ECPoint Q = P.multiply(d).negate(); + + ECDomainParameters domain = new ECDomainParameters(curve, P, n); + CipherParameters privKey = new ParametersWithRandom(new ECPrivateKeyParameters(d, domain), random); + ECPublicKeyParameters pubKey = new ECPublicKeyParameters(Q, domain); + + DSTU4145Signer dstuSigner = new DSTU4145Signer(); + dstuSigner.init(true, privKey); + BigInteger[] rs = dstuSigner.generateSignature(hash); + + BigInteger r = new BigInteger("6bb5c0cb82e5067485458ebfe81025f03b687c63a27", 16); + BigInteger s = new BigInteger("34d6b1868969b86ecf934167c8fe352c63d1074bd", 16); + + if (rs[0].compareTo(r) != 0) + { + fail("r component wrong"); + } + + if (rs[1].compareTo(s) != 0) + { + fail("s component wrong"); + } + + dstuSigner.init(false, pubKey); + if (!dstuSigner.verifySignature(hash, rs[0], rs[1])) + { + fail("verification fails"); + } + } + + public void performTest() + throws Exception + { + test163(); + test173(); + test283(); + test431(); + testTruncation(); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSTU7564Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSTU7564Test.java new file mode 100644 index 000000000..405ea8472 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSTU7564Test.java @@ -0,0 +1,679 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.digests.DSTU7564Digest; +import com.fr.third.org.bouncycastle.crypto.macs.DSTU7564Mac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +public class DSTU7564Test + extends DigestTest +{ + + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + }; + + private static String[] digests = + { + "cd5101d1ccdf0d1d1f4ada56e888cd724ca1a0838a3521e7131d4fb78d0f5eb6", + "c51a1d639596fb613d86557314a150c40f8fff3de48bc93a3b03c161f4105ee4", + "0bd1b36109f1318411a0517315aa46b8839df06622a278676f5487996c9cfc04", + "02621dbb53f2c7001be64d7308ecb80d21ba7797c92e98d1efc240d41e4c414b" + }; + + protected Digest cloneDigest(Digest digest) + { + return new DSTU7564Digest((DSTU7564Digest)digest); + } + + public DSTU7564Test() + { + super(new DSTU7564Digest(256), messages, digests); + } + + public static void main(String[] args) + { + runTest(new DSTU7564Test()); + } + + public void performTest() + { + super.performTest(); + + hash256Tests(); + hash384Tests(); + hash512Tests(); + macTests(); + overflowTest(); + keySizeTest(); + } + + private void overflowTest() + { + int macBitSize = 256; + byte[] input = new byte[1024]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + byte[] key = Hex.decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); + + byte[] expectedMac = Hex.decode("165382df70adcb040b17c1aced117d26d598b239ab631271a05f6d0f875ae9ea"); + byte[] mac = new byte[macBitSize / 8]; + + DSTU7564Mac dstu7564mac = new DSTU7564Mac(macBitSize); + + dstu7564mac.init(new KeyParameter(key)); + dstu7564mac.update(input, 0, input.length); + dstu7564mac.doFinal(mac, 0); + + if (!Arrays.areEqual(expectedMac, mac)) + { + fail("Failed overflow test 1 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + macBitSize = 256; + input = new byte[1023]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + key = Hex.decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); + + expectedMac = Hex.decode("ed45f163e694d990d2d835dca2f3f869a55a31396c8138161b190d5914d50686"); + mac = new byte[macBitSize / 8]; + + dstu7564mac = new DSTU7564Mac(macBitSize); + + dstu7564mac.init(new KeyParameter(key)); + dstu7564mac.update(input, 0, input.length); + dstu7564mac.doFinal(mac, 0); + + if (!Arrays.areEqual(expectedMac, mac)) + { + fail("Failed overflow test 2 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + DSTU7564Digest digest = new DSTU7564Digest(macBitSize); + byte[] expectedDigest = Hex.decode("6bfc5ec8c1f5963fbed89da115d86e9330634eca341dd42fd94a7007e4af7942"); + byte[] digestBuf = new byte[macBitSize / 8]; + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 3 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + + expectedDigest = Hex.decode("6f8f0a3f8261af77581ab01cb89d4cb5ed87ca1d9954f11d5586e94b45c82fb8"); + + input = new byte[51]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 4 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + + input = new byte[52]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + + expectedDigest = Hex.decode("8b6fe2ba77e684b2a1ac82232f4efc49f681cd18c82a0cfff530186a2fc642d2"); + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 5 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + + + input = new byte[53]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + + expectedDigest = Hex.decode("837f2b0cbe39a4defdfcb44272288d4091cab850161c70695d7831fc5f00e171"); + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 6 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + + input = new byte[54]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + + expectedDigest = Hex.decode("21d423d5b8c7f18a0da42cdd95b36b66344125e2adc6edeab5899926442113bc"); + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 7 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + + input = new byte[55]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + + expectedDigest = Hex.decode("0e7bf74464b81b3ae7d904170776d29f4b02a7227da578dd562d01027af7fd0e"); + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 8 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + + input = new byte[56]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + + expectedDigest = Hex.decode("badea1f49cbcec94acec52b4c695acdddd786cca5a6763929f341a58c5134b3b"); + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 9 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + + input = new byte[57]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + + expectedDigest = Hex.decode("a13b5f6f53ee043292ed65b66c1d49759be4d2fe0c2f6148f2416487965f7bde"); + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 10 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + + input = new byte[63]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + + expectedDigest = Hex.decode("03a44a02c9ffafb43addb290bbcf3b8168f624e8cbd332dc6a9dc7df9d39cbc2"); + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 11 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + + input = new byte[64]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + + expectedDigest = Hex.decode("08f4ee6f1be6903b324c4e27990cb24ef69dd58dbe84813ee0a52f6631239875"); + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 12 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + + input = new byte[65]; + for (int i = 0; i != input.length; i++) + { + input[i] = (byte)(i & 0xff); + } + + expectedDigest = Hex.decode("a81c2fb92351f370050b7c36cd51736d5603a50ec1106cbd5fe1c9be2e5c77a6"); + + digest.update(input, 0, input.length); + digest.doFinal(digestBuf, 0); + + if (!Arrays.areEqual(expectedDigest, digestBuf)) + { + fail("Failed overflow test 13 - expected " + + Hex.toHexString(expectedDigest) + + " got " + Hex.toHexString(digestBuf)); + } + } + + private void macTests() + { + + //test1 + int macBitSize = 256; + byte[] input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E"); + byte[] key = Hex.decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); + + byte[] expectedMac = Hex.decode("B60594D56FA79BA210314C72C2495087CCD0A99FC04ACFE2A39EF669925D98EE"); + byte[] mac = new byte[macBitSize / 8]; + + DSTU7564Mac dstu7564mac = new DSTU7564Mac(macBitSize); + + dstu7564mac.init(new KeyParameter(key)); + dstu7564mac.update(input, 0, input.length); + dstu7564mac.doFinal(mac, 0); + + if (!Arrays.areEqual(expectedMac, mac)) + { + fail("Failed mac test 1 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + //test1a + input = Hex.decode("0001020304050607"); + key = Hex.decode("08F4EE6F1BE6903B324C4E27990CB24EF69DD58DBE84813EE0A52F6631239875"); + + expectedMac = Hex.decode("383A0B11989ABF61B2CF3EB489351EB7C9AEF70CF5A9D6DBD90F340FF151BA2D"); + mac = new byte[macBitSize / 8]; + + dstu7564mac = new DSTU7564Mac(macBitSize); + + dstu7564mac.init(new KeyParameter(key)); + dstu7564mac.update(input, 0, input.length); + dstu7564mac.doFinal(mac, 0); + + if (!Arrays.areEqual(expectedMac, mac)) + { + fail("Failed mac test 1a - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + //test 2 + macBitSize = 384; + input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E"); + key = Hex.decode("2F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); + + expectedMac = Hex.decode("BEBFD8D730336F043ABACB41829E79A4D320AEDDD8D14024D5B805DA70C396FA295C281A38B30AE728A304B3F5AE490E"); + mac = new byte[macBitSize / 8]; + + dstu7564mac = new DSTU7564Mac(macBitSize); + + dstu7564mac.init(new KeyParameter(key)); + dstu7564mac.update(input, 0, input.length); + dstu7564mac.doFinal(mac, 0); + + if (!Arrays.areEqual(expectedMac, mac)) + { + fail("Failed mac test 2 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + //test 3 + macBitSize = 512; + input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E"); + key = Hex.decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100"); + + expectedMac = Hex.decode("F270043C06A5C37E65D9D791C5FBFB966E5EE709F8F54019C9A55B76CA40B70100579F269CEC24E347A9D864614CF3ABBF6610742E4DB3BD2ABC000387C49D24"); + mac = new byte[macBitSize / 8]; + + dstu7564mac = new DSTU7564Mac(macBitSize); + + dstu7564mac.init(new KeyParameter(key)); + dstu7564mac.update(input, 0, input.length); + dstu7564mac.doFinal(mac, 0); + + if (!Arrays.areEqual(expectedMac, mac)) + { + fail("Failed mac test 3 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + // check doFinal() has reset + dstu7564mac.update(input, 0, input.length); + dstu7564mac.doFinal(mac, 0); + + if (!Arrays.areEqual(expectedMac, mac)) + { + fail("Failed mac test reset - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + // check that init reset correctly + dstu7564mac.init(new KeyParameter(key)); + dstu7564mac.init(new KeyParameter(key)); + dstu7564mac.update(input, 0, input.length); + dstu7564mac.doFinal(mac, 0); + + if (!Arrays.areEqual(expectedMac, mac)) + { + fail("Failed mac test double init - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + // check simple reset + dstu7564mac = new DSTU7564Mac(macBitSize); + dstu7564mac.reset(); + } + + private void hash512Tests() + { + + int hashBitSize = 512; + + //test 1 + byte[] input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + byte[] expectedHash = Hex.decode("3813E2109118CDFB5A6D5E72F7208DCCC80A2DFB3AFDFB02F46992B5EDBE536B3560DD1D7E29C6F53978AF58B444E37BA685C0DD910533BA5D78EFFFC13DE62A"); + byte[] hash = new byte[hashBitSize / 8]; + + + DSTU7564Digest dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-512 test 1 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + + //test 2 + input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + expectedHash = Hex.decode("76ED1AC28B1D0143013FFA87213B4090B356441263C13E03FA060A8CADA32B979635657F256B15D5FCA4A174DE029F0B1B4387C878FCC1C00E8705D783FD7FFE"); + hash = new byte[hashBitSize / 8]; + + + dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-512 test 2 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + + //test 3 + input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"); + expectedHash = Hex.decode("0DD03D7350C409CB3C29C25893A0724F6B133FA8B9EB90A64D1A8FA93B56556611EB187D715A956B107E3BFC76482298133A9CE8CBC0BD5E1436A5B197284F7E"); + hash = new byte[hashBitSize / 8]; + + + dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-512 test 3 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + + //test 4 + input = Hex.decode("FF"); + expectedHash = Hex.decode("871B18CF754B72740307A97B449ABEB32B64444CC0D5A4D65830AE5456837A72D8458F12C8F06C98C616ABE11897F86263B5CB77C420FB375374BEC52B6D0292"); + hash = new byte[hashBitSize / 8]; + + + dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-512 test 4 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + + //test 5 + input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); + expectedHash = Hex.decode("B189BFE987F682F5F167F0D7FA565330E126B6E592B1C55D44299064EF95B1A57F3C2D0ECF17869D1D199EBBD02E8857FB8ADD67A8C31F56CD82C016CF743121"); + hash = new byte[hashBitSize / 8]; + + + dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-512 test 5 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + + + //test 6 + input = Hex.decode(""); + expectedHash = Hex.decode("656B2F4CD71462388B64A37043EA55DBE445D452AECD46C3298343314EF04019BCFA3F04265A9857F91BE91FCE197096187CEDA78C9C1C021C294A0689198538"); + hash = new byte[hashBitSize / 8]; + + + dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-512 test 6 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + } + + private void hash384Tests() + { + + int hashBitSize = 384; + + //test 1 + byte[] input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E"); + byte[] expectedHash = Hex.decode("D9021692D84E5175735654846BA751E6D0ED0FAC36DFBC0841287DCB0B5584C75016C3DECC2A6E47C50B2F3811E351B8"); + byte[] hash = new byte[hashBitSize / 8]; + + + DSTU7564Digest dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-384 test 1 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + } + + private void keySizeTest() + { + doKeySizeTest(new DSTU7564Mac(512)); + doKeySizeTest(new DSTU7564Mac(256)); + } + + private void doKeySizeTest(Mac dstuMac) + { + /* Define message */ + final byte[] myMessage = "1234567890123456".getBytes(); + + /* Determine underlying engine size */ + final int myEngineSize = dstuMac.getMacSize() == 32 ? 64 : 128; + + /* Define key (can be any multiple of engineSize) */ + final byte[] myKey = new byte[myEngineSize]; + + /* Initialise Mac (will fail with ArrayIndexOutOfBoundsException) */ + dstuMac.init(new KeyParameter(myKey)); + final int myOutSize = dstuMac.getMacSize(); + final byte[] myOut = new byte[myOutSize]; + dstuMac.update(myMessage, 0, myMessage.length); + dstuMac.doFinal(myOut, 0); + } + + private void hash256Tests() + { + + int hashBitSize = 256; + + //test 1 + byte[] input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + byte[] expectedHash = Hex.decode("08F4EE6F1BE6903B324C4E27990CB24EF69DD58DBE84813EE0A52F6631239875"); + byte[] hash = new byte[hashBitSize / 8]; + + + DSTU7564Digest dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-256 test 1 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + + //test 2 + input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + expectedHash = Hex.decode("0A9474E645A7D25E255E9E89FFF42EC7EB31349007059284F0B182E452BDA882"); + hash = new byte[hashBitSize / 8]; + + + dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-256 test 2 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + + //test 3 + input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"); + expectedHash = Hex.decode("D305A32B963D149DC765F68594505D4077024F836C1BF03806E1624CE176C08F"); + hash = new byte[hashBitSize / 8]; + + dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-256 test 3 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + + //test 4 + input = Hex.decode("FF"); + expectedHash = Hex.decode("EA7677CA4526555680441C117982EA14059EA6D0D7124D6ECDB3DEEC49E890F4"); + hash = new byte[hashBitSize / 8]; + + dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-256 test 4 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + + //test 5 + input = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E"); + expectedHash = Hex.decode("1075C8B0CB910F116BDA5FA1F19C29CF8ECC75CAFF7208BA2994B68FC56E8D16"); + hash = new byte[hashBitSize / 8]; + + dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-256 test 5 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + + //test 6 + input = Hex.decode(""); + expectedHash = Hex.decode("CD5101D1CCDF0D1D1F4ADA56E888CD724CA1A0838A3521E7131D4FB78D0F5EB6"); + hash = new byte[hashBitSize / 8]; + + dstu7564 = new DSTU7564Digest(hashBitSize); + dstu7564.update(input, 0, input.length); + dstu7564.doFinal(hash, 0); + + if (!Arrays.areEqual(expectedHash, hash)) + { + fail("Failed hash-256 test 6 - expected " + + Hex.toHexString(expectedHash) + + " got " + Hex.toHexString(hash)); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSTU7624Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSTU7624Test.java new file mode 100644 index 000000000..439929912 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DSTU7624Test.java @@ -0,0 +1,1467 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.engines.DSTU7624Engine; +import com.fr.third.org.bouncycastle.crypto.engines.DSTU7624WrapEngine; +import com.fr.third.org.bouncycastle.crypto.macs.DSTU7624Mac; +import com.fr.third.org.bouncycastle.crypto.macs.KGMac; +import com.fr.third.org.bouncycastle.crypto.modes.AEADBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.KCCMBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.KCTRBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.KGCMBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.KXTSBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.OFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class DSTU7624Test + extends CipherTest +{ + private static final SecureRandom RANDOM = new SecureRandom(); + + private static byte[] randomBytes(int min, int max) + { + int count = min + RNGUtils.nextInt(RANDOM,max - min); + byte[] result = new byte[count]; + RANDOM.nextBytes(result); + return result; + } + + static SimpleTest[] tests = + { + //ECB mode + new BlockCipherVectorTest(0, new DSTU7624Engine(128), new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F")), "101112131415161718191A1B1C1D1E1F", "81BF1C7D779BAC20E1C9EA39B4D2AD06"), + new BlockCipherVectorTest(1, new DSTU7624Engine(128), new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F", "58EC3E091000158A1148F7166F334F14"), + new BlockCipherVectorTest(2, new DSTU7624Engine(256), new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F", "F66E3D570EC92135AEDAE323DCBD2A8CA03963EC206A0D5A88385C24617FD92C"), + new BlockCipherVectorTest(3, new DSTU7624Engine(256), new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F", "606990E9E6B7B67A4BD6D893D72268B78E02C83C3CD7E102FD2E74A8FDFE5DD9"), + new BlockCipherVectorTest(4, new DSTU7624Engine(512), new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F", "4A26E31B811C356AA61DD6CA0596231A67BA8354AA47F3A13E1DEEC320EB56B895D0F417175BAB662FD6F134BB15C86CCB906A26856EFEB7C5BC6472940DD9D9"), + + //CBC mode + new BlockCipherVectorTest(5, new CBCBlockCipher(new DSTU7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F")), Hex.decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "A73625D7BE994E85469A9FAABCEDAAB6DBC5F65DD77BB35E06BD7D1D8EAFC8624D6CB31CE189C82B8979F2936DE9BF14"), + new BlockCipherVectorTest(6, new CBCBlockCipher(new DSTU7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.decode("0F0E0D0C0B0A09080706050403020100")), Hex.decode("1F1E1D1C1B1A19181716151413121110")), "88F2F048BA696170E3818915E0DBC0AFA6F141FEBC2F817138DA4AAB2DBF9CE490A488C9C82AC83FB0A6C0EEB64CFD22", "4F4E4D4C4B4A494847464544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A29282726252423222120"), + new BlockCipherVectorTest(7, new CBCBlockCipher(new DSTU7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), Hex.decode("202122232425262728292A2B2C2D2E2F")), "303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D8000", "13EA15843AD14C50BC03ECEF1F43E398E4217752D3EB046AC393DACC5CA1D6FA0EB9FCEB229362B4F1565527EE3D8433"), + new BlockCipherVectorTest(8, new CBCBlockCipher(new DSTU7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.decode("2F2E2D2C2B2A29282726252423222120")), "BC8F026FC603ECE05C24FDE87542730999B381870882AC0535D4368C4BABD81B884E96E853EE7E055262D9D204FBE212", "5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A39383736353433323130"), + new BlockCipherVectorTest(9, new CBCBlockCipher(new DSTU7624Engine(256)), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F", "9CDFDAA75929E7C2A5CFC1BF16B42C5AE3886D0258E8C577DC01DAF62D185FB999B9867736B87110F5F1BC7481912C593F48FF79E2AFDFAB9F704A277EC3E557B1B0A9F223DAE6ED5AF591C4F2D6FB22E48334F5E9B96B1A2EA5200F30A406CE"), + new BlockCipherVectorTest(10, new CBCBlockCipher(new DSTU7624Engine(256)), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")), "606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF", "B8A2474578C2FEBF3F94703587BD5FDC3F4A4D2F43575B6144A1E1031FB3D1452B7FD52F5E3411461DAC506869FF8D2FAEF4FEE60379AE00B33AA3EAF911645AF8091CD8A45D141D1FB150E5A01C1F26FF3DBD26AC4225EC7577B2CE57A5B0FF"), + new BlockCipherVectorTest(11, new CBCBlockCipher(new DSTU7624Engine(256)), new ParametersWithIV(new KeyParameter(Hex.decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.decode("5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "C69A59E10D00F087319B62288A57417C074EAD07C732A87055F0A5AD2BB288105705C45E091A9A6726E9672DC7D8C76FC45C782BCFEF7C39D94DEB84B17035BC8651255A0D34373451B6E1A2C827DB97566C9FF5506C5579F982A0EFC5BA7C28", "BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160"), + new BlockCipherVectorTest(12, new CBCBlockCipher(new DSTU7624Engine(512)), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")), "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF", "D4739B829EF901B24C1162AE4FDEF897EDA41FAC7F5770CDC90E1D1CDF124E8D7831E06B4498A4B6F6EC815DF2461DC99BB0449B0F09FCAA2C84090534BCC9329626FD74EF8F0A0BCB5765184629C3CBF53B0FB134F6D0421174B1C4E884D1CD1069A7AD19752DCEBF655842E79B7858BDE01390A760D85E88925BFE38B0FA57"), + new BlockCipherVectorTest(13, new CBCBlockCipher(new DSTU7624Engine(512)), new ParametersWithIV(new KeyParameter(Hex.decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.decode("7F7E7D7C7B7A797877767574737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "5D5B3E3DE5BAA70E0A0684D458856CE759C6018D0B3F087FC1DAC101D380236DD934F2880B02D56A575BCA35A0CE4B0D9BA1F4A39C16CA7D80D59956630F09E54EC91E32B6830FE08323ED393F8028D150BF03CAD0629A5AFEEFF6E44257980618DB2F32B7B2B65B96E8451F1090829D2FFFC615CC1581E9221438DCEAD1FD12", "FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A89888786858483828180"), + + //CFB mode + new BlockCipherVectorTest(14, new CFBBlockCipher(new DSTU7624Engine(128), 128), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F")), Hex.decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "A19E3E5E53BE8A07C9E0C01298FF83291F8EE6212110BE3FA5C72C88A082520B265570FE28680719D9B4465E169BC37A"), + + //OFB mode + new BlockCipherVectorTest(15, new OFBBlockCipher(new DSTU7624Engine(128), 128), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F")), Hex.decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "A19E3E5E53BE8A07C9E0C01298FF832953205C661BD85A51F3A94113BC785CAB634B36E89A8FDD16A12E4467F5CC5A26"), + new BlockCipherVectorTest(16, new OFBBlockCipher(new DSTU7624Engine(128), 128), new ParametersWithIV(new KeyParameter(Hex.decode("0F0E0D0C0B0A09080706050403020100")), Hex.decode("1F1E1D1C1B1A19181716151413121110")), "649A1EAAE160AF20F5B3EF2F58D66C1178B82E00D26F30689C8EC22E8E86E9CBB0BD4FFEE39EB13C2311276A906DD636", "4F4E4D4C4B4A494847464544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A29282726252423222120"), + new BlockCipherVectorTest(17, new OFBBlockCipher(new DSTU7624Engine(128), 128), new ParametersWithIV(new KeyParameter(Hex.decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.decode("2F2E2D2C2B2A29282726252423222120")), "1A66CFBFEC00C6D52E39923E858DD64B214AB787798D3D5059A6B498AD66B34EAC48C4074BEC0D98C6", "5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A393837"), + new BlockCipherVectorTest(18, new OFBBlockCipher(new DSTU7624Engine(256), 256), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), "404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F90", "B62F7F144A8C6772E693A96890F064C3F06831BF743F5B0DD061067F3D22877331AA6A99D939F05B7550E9402BD1615CC7B2D4A167E83EC0D8A894F92C72E176F3880B61C311D69CE1210C59184E818E19"), + new BlockCipherVectorTest(19, new OFBBlockCipher(new DSTU7624Engine(256), 256), new ParametersWithIV(new KeyParameter(Hex.decode("1F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A29282726252423222120")), "7758A939DD6BD00CAF9153E5A5D5A66129105CA1EA54A97C06FA4A40960A068F55E34F9339A14436216948F92FA2FB5286D3AB1E81543FC0018A0C4E8C493475F4D35DCFB0A7A5377F6669B857CDC978E4", "9F9E9D9C9B9A999897969594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F"), + new BlockCipherVectorTest(20, new OFBBlockCipher(new DSTU7624Engine(256), 256), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F")), "606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0", "0008F28A82D2D01D23BFB2F8BB4F06D8FE73BA4F48A2977585570ED3818323A668883C9DCFF610CC7E3EA5C025FBBC5CA6520F8F11CA35CEB9B07031E6DBFABE39001E9A3CC0A24BBC565939592B4DEDBD"), + new BlockCipherVectorTest(21, new OFBBlockCipher(new DSTU7624Engine(256), 256), new ParametersWithIV(new KeyParameter(Hex.decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.decode("5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "98E122708FDABB1B1A5765C396DC79D7573221EC486ADDABD1770B147A6DD00B5FBC4F1EC68C59775B7AAA4D43C4CCE4F396D982DF64D30B03EF6C3B997BA0ED940BBC590BD30D64B5AE207147D71086B5", "BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F"), + new BlockCipherVectorTest(22, new OFBBlockCipher(new DSTU7624Engine(512), 512), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F")), Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F")), "808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0", "CAA761980599B3ED2E945C41891BAD95F72B11C73ED26536A6847458BC76C827357156B4B3FE0DC1877F5B9F17B866C37B21D89531DB48007D05DEC928B06766C014BB9080385EDF0677E48A0A39B5E7489E28E82FFFD1F84694F17296CB701656"), + new BlockCipherVectorTest(23, new OFBBlockCipher(new DSTU7624Engine(512), 512), new ParametersWithIV(new KeyParameter(Hex.decode("3F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100")), Hex.decode("7F7E7D7C7B7A797877767574737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746454443424140")), "06C061A4A66DFC0910034B3CFBDC4206D8908241C56BF41C4103CFD6DF322210B87F57EAE9F9AD815E606A7D1E8E6BD7CB1EBFBDBCB085C2D06BF3CC1586CB2EE1D81D38437F425131321647E42F5DE309D33F25B89DE37124683E4B44824FC56D", "EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F"), + + //CTR mode + new BlockCipherVectorTest(24, new KCTRBlockCipher(new DSTU7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F")), Hex.decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748", "A90A6B9780ABDFDFF64D14F5439E88F266DC50EDD341528DD5E698E2F000CE21F872DAF9FE1811844A"), + new BlockCipherVectorTest(25, new KCTRBlockCipher(new DSTU7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F")), Hex.decode("101112131415161718191A1B1C1D1E1F")), "303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "B91A7B8790BBCFCFE65D04E5538E98E216AC209DA33122FDA596E8928070BE51"), + new StreamCipherVectorTest(26, new KCTRBlockCipher(new DSTU7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F")), Hex.decode("101112131415161718191A1B1C1D1E1F")), "202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748", "A90A6B9780ABDFDFF64D14F5439E88F266DC50EDD341528DD5E698E2F000CE21F872DAF9FE1811844A"), + new StreamCipherVectorTest(27, new KCTRBlockCipher(new DSTU7624Engine(128)), new ParametersWithIV(new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F")), Hex.decode("101112131415161718191A1B1C1D1E1F")), "303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F", "B91A7B8790BBCFCFE65D04E5538E98E216AC209DA33122FDA596E8928070BE51") + }; + + + public DSTU7624Test() + { + super(tests, new DSTU7624Engine(128), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "DSTU7624"; + } + + public void performTest() + throws Exception + { + super.performTest(); + + MacTests(); + KeyWrapTests(); + CCMModeTests(); + XTSModeTests(); + GCMModeTests(); + } + + public static void main( + String[] args) + { + runTest(new DSTU7624Test()); + } + + + private void MacTests() + { + + //test 1 + byte[] key = Hex.decode("000102030405060708090A0B0C0D0E0F"); + + byte[] authtext = Hex.decode("202122232425262728292A2B2C2D2E2F" + + "303132333435363738393A3B3C3D3E3F" + + "404142434445464748494A4B4C4D4E4F"); + + byte[] expectedMac = Hex.decode("123B4EAB8E63ECF3E645A99C1115E241"); + + byte[] mac = new byte[expectedMac.length]; + + DSTU7624Mac dstu7624Mac = new DSTU7624Mac(128, 128); + dstu7624Mac.init(new KeyParameter(key)); + dstu7624Mac.update(authtext, 0, authtext.length); + dstu7624Mac.doFinal(mac, 0); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed MAC test 1 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + + //test 2 + key = Hex.decode("000102030405060708090A0B0C0D0E0F" + + "101112131415161718191A1B1C1D1E1F" + + "202122232425262728292A2B2C2D2E2F" + + "303132333435363738393A3B3C3D3E3F"); + + authtext = Hex.decode("404142434445464748494A4B4C4D4E4F" + + "505152535455565758595A5B5C5D5E5F" + + "606162636465666768696A6B6C6D6E6F" + + "707172737475767778797A7B7C7D7E7F" + + "808182838485868788898A8B8C8D8E8F" + + "909192939495969798999A9B9C9D9E9F" + + "A0A1A2A3A4A5A6A7A8A9AAABACADAEAF" + + "B0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); + + expectedMac = Hex.decode("7279FA6BC8EF7525B2B35260D00A1743"); + + dstu7624Mac = new DSTU7624Mac(512, 128); + dstu7624Mac.init(new KeyParameter(key)); + dstu7624Mac.update(authtext, 0, authtext.length); + dstu7624Mac.doFinal(mac, 0); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed MAC test 2 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + // check that reset correctly on doFinal() + dstu7624Mac.update(authtext, 0, authtext.length); + dstu7624Mac.doFinal(mac, 0); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed MAC test reset - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + // check that init reset correctly + dstu7624Mac.init(new KeyParameter(key)); + dstu7624Mac.init(new KeyParameter(key)); + dstu7624Mac.update(authtext, 0, authtext.length); + dstu7624Mac.doFinal(mac, 0); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed MAC test double init - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + // check simple reset + dstu7624Mac = new DSTU7624Mac(512, 128); + dstu7624Mac.reset(); + } + + private void KeyWrapTests() + throws Exception + { + //test 1 + /* + * Initial implementation had bugs handling offset and length correctly, so for + * this first test case we embed the input inside a larger buffer. + */ + byte[] textA = randomBytes(1, 64); + byte[] textB = randomBytes(1, 64); + byte[] textToWrap = Arrays.concatenate(new byte[][]{ textA, Hex.decode("101112131415161718191A1B1C1D1E1F"), textB }); + + byte[] key = Hex.decode("000102030405060708090A0B0C0D0E0F"); + byte[] expectedWrappedText = Hex.decode("1DC91DC6E52575F6DBED25ADDA95A1B6AD3E15056E489738972C199FB9EE2913"); + byte[] output = new byte[expectedWrappedText.length]; + + DSTU7624WrapEngine wrapper = new DSTU7624WrapEngine(128); + wrapper.init(true, new KeyParameter(key)); + output = wrapper.wrap(textToWrap, textA.length, textToWrap.length - textA.length - textB.length); + + if (!Arrays.areEqual(output, expectedWrappedText)) + { + fail("Failed KW (wrapping) test 1 - expected " + + Hex.toHexString(expectedWrappedText) + + " got " + Hex.toHexString(output)); + } + + output = Arrays.concatenate(new byte[][]{ textB, output, textA }); + + wrapper.init(false, new KeyParameter(key)); + output = wrapper.unwrap(output, textB.length, output.length - textB.length - textA.length); + + byte[] expected = Arrays.copyOfRange(textToWrap, textA.length, textToWrap.length - textB.length); + if (!Arrays.areEqual(output, expected)) + { + fail("Failed KW (unwrapping) test 1 - expected " + + Hex.toHexString(expected) + + " got " + Hex.toHexString(output)); + } + + //test 2 + key = Hex.decode("000102030405060708090A0B0C0D0E0F"); + textToWrap = Hex.decode("101112131415161718191A1B1C1D1E1F20219000000000000000800000000000"); + expectedWrappedText = Hex.decode("0EA983D6CE48484D51462C32CC61672210FCC44196ABE635BAF878FDB83E1A63114128585D49DB355C5819FD38039169"); + + output = new byte[expectedWrappedText.length]; + + wrapper.init(true, new KeyParameter(key)); + output = wrapper.wrap(textToWrap, 0, textToWrap.length); + + + if (!Arrays.areEqual(output, expectedWrappedText)) + { + fail("Failed KW (wrapping) test 2 - expected " + + Hex.toHexString(expectedWrappedText) + + " got " + Hex.toHexString(output)); + } + + + wrapper.init(false, new KeyParameter(key)); + + output = wrapper.unwrap(expectedWrappedText, 0, expectedWrappedText.length); + if (!Arrays.areEqual(output, textToWrap)) + { + fail("Failed KW (unwrapping) test 2 - expected " + + Hex.toHexString(textToWrap) + + " got " + Hex.toHexString(output)); + } + + //test 3 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + textToWrap = Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F"); + expectedWrappedText = Hex.decode("2D09A7C18E6A5A0816331EC27CEA596903F77EC8D63F3BDB73299DE7FD9F4558E05992B0B24B39E02EA496368E0841CC1E3FA44556A3048C5A6E9E335717D17D"); + + output = new byte[expectedWrappedText.length]; + + wrapper = new DSTU7624WrapEngine(128); + wrapper.init(true, new KeyParameter(key)); + output = wrapper.wrap(textToWrap, 0, textToWrap.length); + + + if (!Arrays.areEqual(output, expectedWrappedText)) + { + fail("Failed KW (wrapping) test 3 - expected " + + Hex.toHexString(expectedWrappedText) + + " got " + Hex.toHexString(output)); + } + + wrapper.init(false, new KeyParameter(key)); + + output = wrapper.unwrap(expectedWrappedText, 0, expectedWrappedText.length); + + if (!Arrays.areEqual(output, textToWrap)) + { + fail("Failed KW (unwrapping) test 3 - expected " + + Hex.toHexString(textToWrap) + + " got " + Hex.toHexString(output)); + } + + //test 4 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + textToWrap = Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464E8040000000000020"); + expectedWrappedText = Hex.decode("37E3EECB91150C6FA04CFD19D6FC57B7168C9FA5C5ED18601C68EE4AFD7301F8C8C51D7A0A5CD34F6FAB0D8AF11845CC1E4B16E0489FDA1D76BA4EFCFD161F76"); + + output = new byte[expectedWrappedText.length]; + + wrapper = new DSTU7624WrapEngine(128); + wrapper.init(true, new KeyParameter(key)); + output = wrapper.wrap(textToWrap, 0, textToWrap.length); + + + if (!Arrays.areEqual(output, expectedWrappedText)) + { + fail("Failed KW (wrapping) test 4 - expected " + + Hex.toHexString(expectedWrappedText) + + " got " + Hex.toHexString(output)); + } + + wrapper.init(false, new KeyParameter(key)); + + output = wrapper.unwrap(expectedWrappedText, 0, expectedWrappedText.length); + + if (!Arrays.areEqual(output, textToWrap)) + { + fail("Failed KW (unwrapping) test 4 - expected " + + Hex.toHexString(textToWrap) + + " got " + Hex.toHexString(output)); + } + + //test 5 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + textToWrap = Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + expectedWrappedText = Hex.decode("BE59D3C3C31B2685A8FA57CD000727F16AF303F0D87BC2D7ABD80DC2796BBC4CDBC4E0408943AF4DAF7DE9084DC81BFEF15FDCDD0DF399983DF69BF730D7AE2A199CA4F878E4723B7171DD4D1E8DF59C0F25FA0C20946BA64F9037D724BB1D50B6C2BD9788B2AF83EF6163087CD2D4488BC19F3A858D813E3A8947A529B6D65D"); + + output = new byte[expectedWrappedText.length]; + + wrapper = new DSTU7624WrapEngine(256); + wrapper.init(true, new KeyParameter(key)); + output = wrapper.wrap(textToWrap, 0, textToWrap.length); + + + if (!Arrays.areEqual(output, expectedWrappedText)) + { + fail("Failed KW (wrapping) test 5 - expected " + + Hex.toHexString(expectedWrappedText) + + " got " + Hex.toHexString(output)); + } + + wrapper.init(false, new KeyParameter(key)); + + output = wrapper.unwrap(expectedWrappedText, 0, expectedWrappedText.length); + + if (!Arrays.areEqual(output, textToWrap)) + { + fail("Failed KW (unwrapping) test 5 - expected " + + Hex.toHexString(textToWrap) + + " got " + Hex.toHexString(output)); + } + } + + private void CCMModeTests() + throws Exception + { + //test 1 + byte[] key = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] iv = Hex.decode("101112131415161718191a1b1c1d1e1f"); + byte[] input = Hex.decode("303132333435363738393a3b3c3d3e3f"); + byte[] authText = Hex.decode("202122232425262728292a2b2c2d2e2f"); + + byte[] expectedMac = Hex.decode("26a936173a4dc9160d6e3fda3a974060"); + byte[] expectedEncrypted = Hex.decode("b91a7b8790bbcfcfe65d04e5538e98e2704454c9dd39adace0b19d03f6aab07e"); + + byte[] mac; + byte[] encrypted = new byte[expectedEncrypted.length]; + + byte[] decrypted = new byte[encrypted.length]; + byte[] expectedDecrypted = new byte[input.length + expectedMac.length]; + System.arraycopy(input, 0, expectedDecrypted, 0, input.length); + System.arraycopy(expectedMac, 0, expectedDecrypted, input.length, expectedMac.length); + int len; + + + AEADParameters param = new AEADParameters(new KeyParameter(key), 128, iv); + + KCCMBlockCipher dstu7624ccm = new KCCMBlockCipher(new DSTU7624Engine(128)); + + dstu7624ccm.init(true, param); + + dstu7624ccm.processAADBytes(authText, 0, authText.length); + + len = dstu7624ccm.processBytes(input, 0, input.length, encrypted, 0); + + + dstu7624ccm.doFinal(encrypted, len); + + mac = dstu7624ccm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed CCM mac test 1 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + if (!Arrays.areEqual(encrypted, expectedEncrypted)) + { + fail("Failed CCM encrypt test 1 - expected " + + Hex.toHexString(expectedEncrypted) + + " got " + Hex.toHexString(encrypted)); + } + + dstu7624ccm.init(false, param); + + dstu7624ccm.processAADBytes(authText, 0, authText.length); + + len = dstu7624ccm.processBytes(expectedEncrypted, 0, expectedEncrypted.length, decrypted, 0); + + dstu7624ccm.doFinal(decrypted, len); + + if (!Arrays.areEqual(decrypted, expectedDecrypted)) + { + fail("Failed CCM decrypt/verify mac test 1 - expected " + + Hex.toHexString(expectedDecrypted) + + " got " + Hex.toHexString(decrypted)); + } + + //test 2 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + iv = Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + input = Hex.decode("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F"); + authText = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"); + + expectedMac = Hex.decode("9AB831B4B0BF0FDBC36E4B4FD58F0F00"); + expectedEncrypted = Hex.decode("7EC15C54BB553CB1437BE0EFDD2E810F6058497EBCE4408A08A73FADF3F459D56B0103702D13AB73ACD2EB33A8B5E9CFFF5EB21865A6B499C10C810C4BAEBE809C48AD90A9E12A68380EF1C1B7C83EE1"); + + mac = new byte[expectedMac.length]; + encrypted = new byte[expectedEncrypted.length]; + + decrypted = new byte[encrypted.length]; + expectedDecrypted = new byte[input.length + expectedMac.length]; + System.arraycopy(input, 0, expectedDecrypted, 0, input.length); + System.arraycopy(expectedMac, 0, expectedDecrypted, input.length, expectedMac.length); + + + param = new AEADParameters(new KeyParameter(key), 128, iv); + + dstu7624ccm = new KCCMBlockCipher(new DSTU7624Engine(256)); + + dstu7624ccm.init(true, param); + + dstu7624ccm.processAADBytes(authText, 0, authText.length); + + len = dstu7624ccm.processBytes(input, 0, input.length, encrypted, 0); + + dstu7624ccm.doFinal(encrypted, len); + + mac = dstu7624ccm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed CCM mac test 2 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + if (!Arrays.areEqual(encrypted, expectedEncrypted)) + { + fail("Failed CCM encrypt test 2 - expected " + + Hex.toHexString(expectedEncrypted) + + " got " + Hex.toHexString(encrypted)); + } + + dstu7624ccm.init(false, param); + + dstu7624ccm.processAADBytes(authText, 0, authText.length); + + len = dstu7624ccm.processBytes(expectedEncrypted, 0, expectedEncrypted.length, decrypted, 0); + + dstu7624ccm.doFinal(decrypted, len); + + if (!Arrays.areEqual(decrypted, expectedDecrypted)) + { + fail("Failed CCM decrypt/verify mac test 2 - expected " + + Hex.toHexString(expectedDecrypted) + + " got " + Hex.toHexString(decrypted)); + } + + //test 3 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + iv = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"); + input = Hex.decode("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); + authText = Hex.decode("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + + expectedMac = Hex.decode("924FA0326824355595C98028E84D86279CEA9135FAB35F22054AE3203E68AE46"); + expectedEncrypted = Hex.decode("3EBDB4584B5169A26FBEBA0295B4223F58D5D8A031F2950A1D7764FAB97BA058E9E2DAB90FF0C519AA88435155A71B7B53BB100F5D20AFFAC0552F5F2813DEE8DD3653491737B9615A5CCD83DB32F1E479BF227C050325BBBFF60BCA9558D7FE"); + + mac = new byte[expectedMac.length]; + encrypted = new byte[expectedEncrypted.length]; + + decrypted = new byte[encrypted.length]; + expectedDecrypted = new byte[input.length + expectedMac.length]; + System.arraycopy(input, 0, expectedDecrypted, 0, input.length); + System.arraycopy(expectedMac, 0, expectedDecrypted, input.length, expectedMac.length); + + + param = new AEADParameters(new KeyParameter(key), 256, iv); + + dstu7624ccm = new KCCMBlockCipher(new DSTU7624Engine(256), 6); + + dstu7624ccm.init(true, param); + + dstu7624ccm.processAADBytes(authText, 0, authText.length); + + len = dstu7624ccm.processBytes(input, 0, input.length, encrypted, 0); + + dstu7624ccm.doFinal(encrypted, len); + + mac = dstu7624ccm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed CCM mac test 3 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + if (!Arrays.areEqual(encrypted, expectedEncrypted)) + { + fail("Failed CCM encrypt test 3 - expected " + + Hex.toHexString(expectedEncrypted) + + " got " + Hex.toHexString(encrypted)); + } + + dstu7624ccm.init(false, param); + + dstu7624ccm.processAADBytes(authText, 0, authText.length); + + len = dstu7624ccm.processBytes(expectedEncrypted, 0, expectedEncrypted.length, decrypted, 0); + + dstu7624ccm.doFinal(decrypted, len); + + if (!Arrays.areEqual(decrypted, expectedDecrypted)) + { + fail("Failed CCM decrypt/verify mac test 3 - expected " + + Hex.toHexString(expectedDecrypted) + + " got " + Hex.toHexString(decrypted)); + } + + //test 4 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + iv = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + input = Hex.decode("C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"); + authText = Hex.decode("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); + + expectedMac = Hex.decode("D4155EC3D888C8D32FE184AC260FD60F567705E1DF362A6F1F9C287156AA96D91BC4C56F9709E72F3D79CF0A9AC8BDC2BA836BE50E823AB50FB1B39080390923"); + expectedEncrypted = Hex.decode("220642D7277D104788CF97B10210984F506435512F7BF153C5CDABFECC10AFB4A2E2FC51F616AF80FFDD0607FAD4F542B8EF0667717CE3EAAA8FBC303CE76C99BD8F80CE149143C04FC2490272A31B029DDADA82F055FE4ABEF452A7D438B21E59C1D8B3DD4606BAD66A6F36300EF3CE0E5F3BB59F11416E80B7FC5A8E8B057A"); + + mac = new byte[expectedMac.length]; + encrypted = new byte[expectedEncrypted.length]; + + decrypted = new byte[encrypted.length]; + expectedDecrypted = new byte[input.length + expectedMac.length]; + System.arraycopy(input, 0, expectedDecrypted, 0, input.length); + System.arraycopy(expectedMac, 0, expectedDecrypted, input.length, expectedMac.length); + + + param = new AEADParameters(new KeyParameter(key), 512, iv); + + dstu7624ccm = new KCCMBlockCipher(new DSTU7624Engine(512), 8); + + dstu7624ccm.init(true, param); + + dstu7624ccm.processAADBytes(authText, 0, authText.length); + + len = dstu7624ccm.processBytes(input, 0, input.length, encrypted, 0); + + dstu7624ccm.doFinal(encrypted, len); + + mac = dstu7624ccm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed CCM mac test 4 - expected " + + Hex.toHexString(expectedMac) + + " got " + Hex.toHexString(mac)); + } + + if (!Arrays.areEqual(encrypted, expectedEncrypted)) + { + fail("Failed CCM encrypt test 4 - expected " + + Hex.toHexString(expectedEncrypted) + + " got " + Hex.toHexString(encrypted)); + } + + dstu7624ccm.init(false, param); + + dstu7624ccm.processAADBytes(authText, 0, authText.length); + + len = dstu7624ccm.processBytes(expectedEncrypted, 0, expectedEncrypted.length, decrypted, 0); + + dstu7624ccm.doFinal(decrypted, len); + + if (!Arrays.areEqual(decrypted, expectedDecrypted)) + { + fail("Failed CCM decrypt/verify mac test 4 - expected " + + Hex.toHexString(expectedDecrypted) + + " got " + Hex.toHexString(decrypted)); + } + + doFinalTest(new KCCMBlockCipher(new DSTU7624Engine(512), 8), key, iv, authText, input, expectedEncrypted); + } + + private void XTSModeTests() + throws Exception + { + + //test 1 + byte[] key = Hex.decode("000102030405060708090A0B0C0D0E0F"); + byte[] iv = Hex.decode("101112131415161718191A1B1C1D1E1F"); + byte[] plainText = Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + + byte[] output = new byte[plainText.length]; + byte[] expectedCipherText = Hex.decode("B3E431B3FBAF31108C302669EE7116D1CF518B6D329D30618DF5628E426BDEF1"); + + byte[] decrypted = new byte[plainText.length]; + + + int len; + + KXTSBlockCipher dstu7624xts = new KXTSBlockCipher(new DSTU7624Engine(128)); + ParametersWithIV param = new ParametersWithIV(new KeyParameter(key), iv); + + dstu7624xts.init(true, param); + len = dstu7624xts.processBytes(plainText, 0, plainText.length, output, 0); + + dstu7624xts.doFinal(output, len); + + if (!Arrays.areEqual(output, expectedCipherText)) + { + fail("Failed XTS encrypt test 1 - expected " + + Hex.toHexString(expectedCipherText) + + " got " + Hex.toHexString(output)); + } + + + dstu7624xts.init(false, param); + len = dstu7624xts.processBytes(expectedCipherText, 0, expectedCipherText.length, decrypted, 0); + dstu7624xts.doFinal(decrypted, len); + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed XTS decrypt test 1 - expected " + + Hex.toHexString(plainText) + + " got " + Hex.toHexString(decrypted)); + } + + //test 2 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + iv = Hex.decode("202122232425262728292A2B2C2D2E2F"); + plainText = Hex.decode("303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F"); + + output = new byte[plainText.length]; + expectedCipherText = Hex.decode("830AC78A6F629CB4C7D5D156FD84955BD0998CA1E0BC1FF135676BF2A2598FA1"); + + decrypted = new byte[plainText.length]; + + + dstu7624xts = new KXTSBlockCipher(new DSTU7624Engine(128)); + param = new ParametersWithIV(new KeyParameter(key), iv); + + dstu7624xts.init(true, param); + len = dstu7624xts.processBytes(plainText, 0, plainText.length, output, 0); + dstu7624xts.doFinal(output, len); + + if (!Arrays.areEqual(output, expectedCipherText)) + { + fail("Failed XTS encrypt test 2 - expected " + + Hex.toHexString(expectedCipherText) + + " got " + Hex.toHexString(output)); + } + + + dstu7624xts.init(false, param); + len = dstu7624xts.processBytes(expectedCipherText, 0, expectedCipherText.length, decrypted, 0); + dstu7624xts.doFinal(decrypted, len); + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed XTS decrypt test 2 - expected " + + Hex.toHexString(plainText) + + " got " + Hex.toHexString(decrypted)); + } + + + //test 3 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + iv = Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + plainText = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F"); + + output = new byte[plainText.length]; + expectedCipherText = Hex.decode("E0E51EAEA6A3134600758EA7F87E88025D8B82897C8DB099B843054C3A51883756913571530BA8FA23003E337627E698674B807E847EC6B2292627736562F9F62B2DE9E6AAC5DF74C09A0C5CF80280174AEC9BDD4E73F7D63EDBC29A6922637A"); + + decrypted = new byte[plainText.length]; + + dstu7624xts = new KXTSBlockCipher(new DSTU7624Engine(256)); + param = new ParametersWithIV(new KeyParameter(key), iv); + + dstu7624xts.init(true, param); + len = dstu7624xts.processBytes(plainText, 0, plainText.length, output, 0); + dstu7624xts.doFinal(output, len); + + if (!Arrays.areEqual(output, expectedCipherText)) + { + fail("Failed XTS encrypt test 3 - expected " + + Hex.toHexString(expectedCipherText) + + " got " + Hex.toHexString(output)); + } + + dstu7624xts.init(false, param); + len = dstu7624xts.processBytes(expectedCipherText, 0, expectedCipherText.length, decrypted, 0); + dstu7624xts.doFinal(decrypted, len); + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed XTS decrypt test 3 - expected " + + Hex.toHexString(plainText) + + " got " + Hex.toHexString(decrypted)); + } + + //test 4 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + iv = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"); + plainText = Hex.decode("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); + + output = new byte[plainText.length]; + expectedCipherText = Hex.decode("30663E4686574B343A1898E46973CD37DB9D775D356512EB59E723397F2A333CE2C0E96538781FF48EA1D93BDF88FFF8BB7BC4FB80A609881220C7FE21881C7374F65B232A8F94CD0E3DDC7614830C23CFCE98ADC5113496F9E106E8C8BFF3AB"); + + decrypted = new byte[plainText.length]; + + dstu7624xts = new KXTSBlockCipher(new DSTU7624Engine(256)); + param = new ParametersWithIV(new KeyParameter(key), iv); + + dstu7624xts.init(true, param); + len = dstu7624xts.processBytes(plainText, 0, plainText.length, output, 0); + dstu7624xts.doFinal(output, len); + + if (!Arrays.areEqual(output, expectedCipherText)) + { + fail("Failed XTS encrypt test 4 - expected " + + Hex.toHexString(expectedCipherText) + + " got " + Hex.toHexString(output)); + } + + + dstu7624xts.init(false, param); + len = dstu7624xts.processBytes(expectedCipherText, 0, expectedCipherText.length, decrypted, 0); + dstu7624xts.doFinal(decrypted, len); + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed XTS decrypt test 4 - expected " + + Hex.toHexString(plainText) + + " got " + Hex.toHexString(decrypted)); + } + + //test 5 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + iv = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + plainText = Hex.decode("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"); + + output = new byte[plainText.length]; + expectedCipherText = Hex.decode("5C6250BD2E40AAE27E1E57512CD38E6A51D0C2B04F0D6A50E0CB43358B8C4E8BA361331436C6FFD38D77BBBBF5FEC56A234108A6CC8CB298360943E849E5BD64D26ECA2FA8AEAD070656C3777BA412BCAF3D2F08C26CF86CA8F0921043A15D709AE1112611E22D4396E582CCB661E0F778B6F38561BC338AFD5D1036ED8B322D"); + + decrypted = new byte[plainText.length]; + + dstu7624xts = new KXTSBlockCipher(new DSTU7624Engine(512)); + param = new ParametersWithIV(new KeyParameter(key), iv); + + dstu7624xts.init(true, param); + len = dstu7624xts.processBytes(plainText, 0, plainText.length, output, 0); + dstu7624xts.doFinal(output, len); + + if (!Arrays.areEqual(output, expectedCipherText)) + { + fail("Failed XTS encrypt test 5 - expected " + + Hex.toHexString(expectedCipherText) + + " got " + Hex.toHexString(output)); + } + + + dstu7624xts.init(false, param); + len = dstu7624xts.processBytes(expectedCipherText, 0, expectedCipherText.length, decrypted, 0); + dstu7624xts.doFinal(decrypted, len); + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed XTS decrypt test 5 - expected " + + Hex.toHexString(plainText) + + " got " + Hex.toHexString(decrypted)); + } + } + + private void GCMModeTests() + throws Exception + { + //test 1 + byte[] key = Hex.decode("000102030405060708090A0B0C0D0E0F"); + + byte[] iv = Hex.decode("101112131415161718191A1B1C1D1E1F"); + + byte[] authText = Hex.decode("202122232425262728292A2B2C2D2E2F"); + + byte[] plainText = Hex.decode("303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F"); + + byte[] expectedEncrypted = Hex.decode("B91A7B8790BBCFCFE65D04E5538E98E216AC209DA33122FDA596E8928070BE51"); + + byte[] expectedMac = Hex.decode("C8310571CD60F9584B45C1B4ECE179AF"); + + byte[] expectedOutput = new byte[expectedEncrypted.length + expectedMac.length]; + System.arraycopy(expectedEncrypted, 0, expectedOutput, 0, expectedEncrypted.length); + System.arraycopy(expectedMac, 0, expectedOutput, expectedEncrypted.length, expectedMac.length); + + byte[] mac = new byte[expectedMac.length]; + + byte[] encrypted = new byte[expectedEncrypted.length + mac.length]; + + byte[] decrypted = new byte[plainText.length + mac.length]; + + System.arraycopy(expectedMac, 0, decrypted, plainText.length, mac.length); + + int len; + + AEADParameters parameters = new AEADParameters(new KeyParameter(key), 128, iv); + + KGCMBlockCipher dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(128)); + + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + + len = dstu7624gcm.processBytes(plainText, 0, plainText.length, encrypted, 0); + dstu7624gcm.doFinal(encrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 1 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + if (!Arrays.areEqual(encrypted, expectedOutput)) + { + fail("Failed GCM/GMAC test 1 - expected encrypted: " + + Hex.toHexString(expectedOutput) + + " got encrypted: " + Hex.toHexString(encrypted)); + } + + + dstu7624gcm.init(false, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + + len = dstu7624gcm.processBytes(expectedOutput, 0, expectedOutput.length, decrypted, 0); + dstu7624gcm.doFinal(decrypted, len); + + + mac = dstu7624gcm.getMac(); + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 1 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + //remove mac at the end of decrypted data + byte[] tempDecrypted = new byte[plainText.length]; + System.arraycopy(decrypted, 0, tempDecrypted, 0, plainText.length); + decrypted = tempDecrypted; + + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed GCM/GMAC test 1 - expected decrypted: " + + Hex.toHexString(plainText) + + " got decrypted: " + Hex.toHexString(decrypted)); + } + + //test 2 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + + iv = Hex.decode("202122232425262728292A2B2C2D2E2F"); + + authText = Hex.decode("303132333435363738393A3B3C3D3E3F"); + + plainText = Hex.decode("505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F"); + + expectedEncrypted = Hex.decode("FF83F27C6D4EA26101B1986235831406A297940D6C0E695596D612623E0E7CDC"); + + expectedMac = Hex.decode("3C474281AFEAE4FD6D61E995258747AB"); + + expectedOutput = new byte[expectedEncrypted.length + expectedMac.length]; + System.arraycopy(expectedEncrypted, 0, expectedOutput, 0, expectedEncrypted.length); + System.arraycopy(expectedMac, 0, expectedOutput, expectedEncrypted.length, expectedMac.length); + + + mac = new byte[expectedMac.length]; + + encrypted = new byte[expectedEncrypted.length + mac.length]; + + decrypted = new byte[plainText.length + mac.length]; + + System.arraycopy(expectedMac, 0, decrypted, plainText.length, mac.length); + + parameters = new AEADParameters(new KeyParameter(key), 128, iv); + + dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(128)); + + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + len = dstu7624gcm.processBytes(plainText, 0, plainText.length, encrypted, 0); + + dstu7624gcm.doFinal(encrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 2 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + if (!Arrays.areEqual(encrypted, expectedOutput)) + { + fail("Failed GCM/GMAC test 2 - expected encrypted: " + + Hex.toHexString(expectedOutput) + + " got encrypted: " + Hex.toHexString(encrypted)); + } + + + dstu7624gcm.init(false, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + len = dstu7624gcm.processBytes(expectedOutput, 0, expectedOutput.length, decrypted, 0); + + dstu7624gcm.doFinal(decrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 2 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + //remove mac at the end of decrypted data + tempDecrypted = new byte[plainText.length]; + System.arraycopy(decrypted, 0, tempDecrypted, 0, plainText.length); + decrypted = tempDecrypted; + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed GCM/GMAC test 2 - expected decrypted: " + + Hex.toHexString(plainText) + + " got decrypted: " + Hex.toHexString(decrypted)); + } + + //test 3 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + + iv = Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + + authText = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"); + + plainText = Hex.decode("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F"); + + expectedEncrypted = Hex.decode("7EC15C54BB553CB1437BE0EFDD2E810F6058497EBCE4408A08A73FADF3F459D56B0103702D13AB73ACD2EB33A8B5E9CFFF5EB21865A6B499C10C810C4BAEBE80"); + + expectedMac = Hex.decode("1D61B0A3018F6B849CBA20AF1DDDA245"); + + expectedOutput = new byte[expectedEncrypted.length + expectedMac.length]; + System.arraycopy(expectedEncrypted, 0, expectedOutput, 0, expectedEncrypted.length); + System.arraycopy(expectedMac, 0, expectedOutput, expectedEncrypted.length, expectedMac.length); + + + mac = new byte[expectedMac.length]; + + encrypted = new byte[expectedEncrypted.length + mac.length]; + + decrypted = new byte[plainText.length + mac.length]; + + System.arraycopy(expectedMac, 0, decrypted, plainText.length, mac.length); + + + parameters = new AEADParameters(new KeyParameter(key), 128, iv); + + dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(256)); + + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + len = dstu7624gcm.processBytes(plainText, 0, plainText.length, encrypted, 0); + + dstu7624gcm.doFinal(encrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 3 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + if (!Arrays.areEqual(encrypted, expectedOutput)) + { + fail("Failed GCM/GMAC test 3 - expected encrypted: " + + Hex.toHexString(expectedOutput) + + " got encrypted: " + Hex.toHexString(encrypted)); + } + + dstu7624gcm.init(false, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + len = dstu7624gcm.processBytes(expectedOutput, 0, expectedOutput.length, decrypted, 0); + + dstu7624gcm.doFinal(decrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 3 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + //remove mac at the end of decrypted data + tempDecrypted = new byte[plainText.length]; + System.arraycopy(decrypted, 0, tempDecrypted, 0, plainText.length); + decrypted = tempDecrypted; + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed GCM/GMAC test 3 - expected decrypted: " + + Hex.toHexString(plainText) + + " got decrypted: " + Hex.toHexString(decrypted)); + } + + //test 4 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + + iv = Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + + authText = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"); + + plainText = Hex.decode("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F"); + + expectedEncrypted = Hex.decode("7EC15C54BB553CB1437BE0EFDD2E810F6058497EBCE4408A08A73FADF3F459D56B0103702D13AB73ACD2EB33A8B5E9CFFF5EB21865A6B499C10C810C4BAEBE80"); + + expectedMac = Hex.decode("1D61B0A3018F6B849CBA20AF1DDDA245B1B296258AC0352A52D3F372E72224CE"); + + expectedOutput = new byte[expectedEncrypted.length + expectedMac.length]; + System.arraycopy(expectedEncrypted, 0, expectedOutput, 0, expectedEncrypted.length); + System.arraycopy(expectedMac, 0, expectedOutput, expectedEncrypted.length, expectedMac.length); + + + mac = new byte[expectedMac.length]; + + encrypted = new byte[expectedEncrypted.length + mac.length]; + + decrypted = new byte[plainText.length + mac.length]; + + System.arraycopy(expectedMac, 0, decrypted, plainText.length, mac.length); + + parameters = new AEADParameters(new KeyParameter(key), 256, iv); + + dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(256)); + + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + len = dstu7624gcm.processBytes(plainText, 0, plainText.length, encrypted, 0); + + dstu7624gcm.doFinal(encrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 4 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + if (!Arrays.areEqual(encrypted, expectedOutput)) + { + fail("Failed GCM/GMAC test 4 - expected encrypted: " + + Hex.toHexString(expectedOutput) + + " got encrypted: " + Hex.toHexString(encrypted)); + } + + + dstu7624gcm.init(false, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + len = dstu7624gcm.processBytes(expectedOutput, 0, expectedOutput.length, decrypted, 0); + + dstu7624gcm.doFinal(decrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 4 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + //remove mac at the end of decrypted data + tempDecrypted = new byte[plainText.length]; + System.arraycopy(decrypted, 0, tempDecrypted, 0, plainText.length); + decrypted = tempDecrypted; + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed GCM/GMAC test 4 - expected decrypted: " + + Hex.toHexString(plainText) + + " got decrypted: " + Hex.toHexString(decrypted)); + } + + //test 5 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + + iv = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"); + + authText = Hex.decode("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + + plainText = Hex.decode("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); + + expectedEncrypted = Hex.decode("3EBDB4584B5169A26FBEBA0295B4223F58D5D8A031F2950A1D7764FAB97BA058E9E2DAB90FF0C519AA88435155A71B7B53BB100F5D20AFFAC0552F5F2813DEE8"); + + expectedMac = Hex.decode("8555FD3D9B02C2325ACA3CC9309D6B4B9AFC697D13BBBFF067198D5D86CB9820"); + + expectedOutput = new byte[expectedEncrypted.length + expectedMac.length]; + System.arraycopy(expectedEncrypted, 0, expectedOutput, 0, expectedEncrypted.length); + System.arraycopy(expectedMac, 0, expectedOutput, expectedEncrypted.length, expectedMac.length); + + + mac = new byte[expectedMac.length]; + + encrypted = new byte[expectedEncrypted.length + mac.length]; + + decrypted = new byte[plainText.length + mac.length]; + + System.arraycopy(expectedMac, 0, decrypted, plainText.length, mac.length); + + + parameters = new AEADParameters(new KeyParameter(key), 256, iv); + + dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(256)); + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + len = dstu7624gcm.processBytes(plainText, 0, plainText.length, encrypted, 0); + + dstu7624gcm.doFinal(encrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 5 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + if (!Arrays.areEqual(encrypted, expectedOutput)) + { + fail("Failed GCM/GMAC test 5 - expected encrypted: " + + Hex.toHexString(expectedOutput) + + " got encrypted: " + Hex.toHexString(encrypted)); + } + + + dstu7624gcm.init(false, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + len = dstu7624gcm.processBytes(expectedOutput, 0, expectedOutput.length, decrypted, 0); + + dstu7624gcm.doFinal(decrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 5 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + //remove mac at the end of decrypted data + tempDecrypted = new byte[plainText.length]; + System.arraycopy(decrypted, 0, tempDecrypted, 0, plainText.length); + decrypted = tempDecrypted; + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed GCM/GMAC test 5 - expected decrypted: " + + Hex.toHexString(plainText) + + " got decrypted: " + Hex.toHexString(decrypted)); + } + + //test 6 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + + iv = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + + authText = Hex.decode("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); + + plainText = Hex.decode("C0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"); + + expectedEncrypted = Hex.decode("220642D7277D104788CF97B10210984F506435512F7BF153C5CDABFECC10AFB4A2E2FC51F616AF80FFDD0607FAD4F542B8EF0667717CE3EAAA8FBC303CE76C99"); + + expectedMac = Hex.decode("78A77E5948F5DC05F551486FDBB44898C9AB1BD439D7519841AE31007C09E1B312E5EA5929F952F6A3EEF5CBEAEF262B8EC1884DFCF4BAAF7B5C9291A22489E1"); + + expectedOutput = new byte[expectedEncrypted.length + expectedMac.length]; + System.arraycopy(expectedEncrypted, 0, expectedOutput, 0, expectedEncrypted.length); + System.arraycopy(expectedMac, 0, expectedOutput, expectedEncrypted.length, expectedMac.length); + + + mac = new byte[expectedMac.length]; + + encrypted = new byte[expectedEncrypted.length + mac.length]; + + decrypted = new byte[plainText.length + mac.length]; + + System.arraycopy(expectedMac, 0, decrypted, plainText.length, mac.length); + + parameters = new AEADParameters(new KeyParameter(key), 512, iv); + + dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(512)); + + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + len = dstu7624gcm.processBytes(plainText, 0, plainText.length, encrypted, 0); + + dstu7624gcm.doFinal(encrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 6 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + if (!Arrays.areEqual(encrypted, expectedOutput)) + { + fail("Failed GCM/GMAC test 6 - expected encrypted: " + + Hex.toHexString(expectedOutput) + + " got encrypted: " + Hex.toHexString(encrypted)); + } + + dstu7624gcm.init(false, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + len = dstu7624gcm.processBytes(expectedOutput, 0, expectedOutput.length, decrypted, 0); + + dstu7624gcm.doFinal(decrypted, len); + + mac = dstu7624gcm.getMac(); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 6 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + //remove mac at the end of decrypted data + tempDecrypted = new byte[plainText.length]; + System.arraycopy(decrypted, 0, tempDecrypted, 0, plainText.length); + decrypted = tempDecrypted; + + if (!Arrays.areEqual(decrypted, plainText)) + { + fail("Failed GCM/GMAC test 6 - expected decrypted: " + + Hex.toHexString(plainText) + + " got decrypted: " + Hex.toHexString(decrypted)); + } + + /* Testing mac producing without encryption */ + //test 7 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + + authText = Hex.decode("303132333435363738393A3B3C3D3E3F"); + + expectedMac = Hex.decode("5AE309EE80B583C6523397ADCB5704C4"); + + mac = new byte[expectedMac.length]; + + parameters = new AEADParameters(new KeyParameter(key), 128, new byte[16]); + + dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(128)); + + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + dstu7624gcm.doFinal(mac, 0); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 7 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + //test 8 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + + authText = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"); + + expectedMac = Hex.decode("FF48B56F2C26CC484B8F5952D7B3E1FE"); + + mac = new byte[expectedMac.length]; + + parameters = new AEADParameters(new KeyParameter(key), 128, new byte[16]); + + dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(256)); + + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + dstu7624gcm.doFinal(mac, 0); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 8 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + //test 9 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"); + + authText = Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"); + + expectedMac = Hex.decode("FF48B56F2C26CC484B8F5952D7B3E1FE69577701C50BE96517B33921E44634CD"); + + mac = new byte[expectedMac.length]; + + parameters = new AEADParameters(new KeyParameter(key), 256, new byte[32]); + + dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(256)); + + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + dstu7624gcm.doFinal(mac, 0); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 9 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + //test 10 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + + authText = Hex.decode("606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"); + + expectedMac = Hex.decode("96F61FA0FDE92883C5041D748F9AE91F3A0A50415BFA1466855340A5714DC01F"); + + mac = new byte[expectedMac.length]; + + parameters = new AEADParameters(new KeyParameter(key), 256, new byte[32]); + + dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(256)); + + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + dstu7624gcm.doFinal(mac, 0); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 10 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + //test 11 + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + + authText = Hex.decode("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); + + expectedMac = Hex.decode("897C32E05E776FD988C5171FE70BB72949172E514E3308A871BA5BD898FB6EBD6E3897D2D55697D90D6428216C08052E3A5E7D4626F4DBBF1546CE21637357A3"); + + mac = new byte[expectedMac.length]; + + parameters = new AEADParameters(new KeyParameter(key), 512, new byte[32]); + + dstu7624gcm = new KGCMBlockCipher(new DSTU7624Engine(512)); + + dstu7624gcm.init(true, parameters); + dstu7624gcm.processAADBytes(authText, 0, authText.length); + dstu7624gcm.doFinal(mac, 0); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 11 - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + + doFinalTest(new KGCMBlockCipher(new DSTU7624Engine(512)), key, new byte[32], authText, null, expectedMac); + + //test 11 - as KGMac + key = Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"); + + authText = Hex.decode("808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBF"); + + expectedMac = Hex.decode("897C32E05E776FD988C5171FE70BB72949172E514E3308A871BA5BD898FB6EBD6E3897D2D55697D90D6428216C08052E3A5E7D4626F4DBBF1546CE21637357A3"); + + mac = new byte[expectedMac.length]; + + KGMac dstuGmac = new KGMac(new KGCMBlockCipher(new DSTU7624Engine(512))); + + dstuGmac.init(new ParametersWithIV(new KeyParameter(key), new byte[32])); + + dstuGmac.update(authText, 0, authText.length); + + dstuGmac.doFinal(mac, 0); + + if (!Arrays.areEqual(mac, expectedMac)) + { + fail("Failed GCM/GMAC test 11 (mac) - expected mac: " + + Hex.toHexString(expectedMac) + + " got mac: " + Hex.toHexString(mac)); + } + } + + private void doFinalTest(AEADBlockCipher cipher, byte[] key, byte[] iv, byte[] authText, byte[] input, byte[] expected) + throws Exception + { + byte[] output = new byte[expected.length]; + + AEADParameters parameters = new AEADParameters(new KeyParameter(key), cipher.getUnderlyingCipher().getBlockSize() * 8, iv); + + cipher.init(true, parameters); + cipher.processAADBytes(authText, 0, authText.length); + + int off = 0; + if (input != null) + { + off = cipher.processBytes(input, 0, input.length, output, 0); + } + + cipher.doFinal(output, off); + + if (!Arrays.areEqual(output, expected)) + { + System.err.println(Hex.toHexString(output)); + System.err.println(Hex.toHexString(expected)); + fail("Failed doFinal test - init: " + cipher.getAlgorithmName()); + } + + cipher.processAADBytes(authText, 0, authText.length); + + off = 0; + if (input != null) + { + off = cipher.processBytes(input, 0, input.length, output, 0); + } + + cipher.doFinal(output, off); + + if (!Arrays.areEqual(output, expected)) + { + fail("Failed doFinal test - after: " + cipher.getAlgorithmName()); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DeterministicDSATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DeterministicDSATest.java new file mode 100644 index 000000000..4d26e114c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DeterministicDSATest.java @@ -0,0 +1,524 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.nist.NISTNamedCurves; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA224Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA384Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA3Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.signers.DSASigner; +import com.fr.third.org.bouncycastle.crypto.signers.ECDSASigner; +import com.fr.third.org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Tests are taken from RFC 6979 - "Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)" + */ +public class DeterministicDSATest + extends SimpleTest +{ + + public static final byte[] SAMPLE = Hex.decode("73616d706c65"); // "sample" + public static final byte[] TEST = Hex.decode("74657374"); // "test" + + // test vectors from appendix in RFC 6979 + private void testHMacDeterministic() + { + DSAParameters dsaParameters = new DSAParameters( + new BigInteger("86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447" + + "E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88" + + "73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C" + + "881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779", 16), + new BigInteger("996F967F6C8E388D9E28D01E205FBA957A5698B1", 16), + new BigInteger("07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D" + + "89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD" + + "87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4" + + "17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD", 16)); + + DSAPrivateKeyParameters privKey = new DSAPrivateKeyParameters(new BigInteger("411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", 16), dsaParameters); + + doTestHMACDetDSASample(new SHA1Digest(), privKey, new BigInteger("2E1A0C2562B2912CAAF89186FB0F42001585DA55", 16), new BigInteger("29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5", 16)); + doTestHMACDetDSASample(new SHA224Digest(), privKey, new BigInteger("4BC3B686AEA70145856814A6F1BB53346F02101E", 16), new BigInteger("410697B92295D994D21EDD2F4ADA85566F6F94C1", 16)); + doTestHMACDetDSASample(new SHA256Digest(), privKey, new BigInteger("81F2F5850BE5BC123C43F71A3033E9384611C545", 16), new BigInteger("4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89", 16)); + doTestHMACDetDSASample(new SHA384Digest(), privKey, new BigInteger("07F2108557EE0E3921BC1774F1CA9B410B4CE65A", 16), new BigInteger("54DF70456C86FAC10FAB47C1949AB83F2C6F7595", 16)); + doTestHMACDetDSASample(new SHA512Digest(), privKey, new BigInteger("16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B", 16), new BigInteger("02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C", 16)); + + doTestHMACDetDSATest(new SHA1Digest(), privKey, new BigInteger("42AB2052FD43E123F0607F115052A67DCD9C5C77", 16), new BigInteger("183916B0230D45B9931491D4C6B0BD2FB4AAF088", 16)); + doTestHMACDetDSATest(new SHA224Digest(), privKey, new BigInteger("6868E9964E36C1689F6037F91F28D5F2C30610F2", 16), new BigInteger("49CEC3ACDC83018C5BD2674ECAAD35B8CD22940F", 16)); + doTestHMACDetDSATest(new SHA256Digest(), privKey, new BigInteger("22518C127299B0F6FDC9872B282B9E70D0790812", 16), new BigInteger("6837EC18F150D55DE95B5E29BE7AF5D01E4FE160", 16)); + doTestHMACDetDSATest(new SHA384Digest(), privKey, new BigInteger("854CF929B58D73C3CBFDC421E8D5430CD6DB5E66", 16), new BigInteger("91D0E0F53E22F898D158380676A871A157CDA622", 16)); + doTestHMACDetDSATest(new SHA512Digest(), privKey, new BigInteger("8EA47E475BA8AC6F2D821DA3BD212D11A3DEB9A0", 16), new BigInteger("7C670C7AD72B6C050C109E1790008097125433E8", 16)); + + doTestHMACDetDSATest(new SHA3Digest(224), privKey, new BigInteger("58748b6ca41d25e41f7bfa51fed204a10a1bd1d3", 16), new BigInteger("86de2fdad0bc848dd20ddd9dc6253fc6d7553268", 16)); + doTestHMACDetDSATest(new SHA3Digest(256), privKey, new BigInteger("98c7a7906ada494285b3ab15cf9188a425f26bd4", 16), new BigInteger("21c5ed876037470d3959fa12f918674a4bf190e9", 16)); + doTestHMACDetDSATest(new SHA3Digest(384), privKey, new BigInteger("445ec584ec15c14abc67c99886a30a286cc83b33", 16), new BigInteger("21f564d5bb4b175e89a1a6fb2f27cd34c861142d", 16)); + doTestHMACDetDSATest(new SHA3Digest(512), privKey, new BigInteger("16918083f4c3ff4fc9b327e9e120a30ec39faaf6", 16), new BigInteger("1e9183a1dc7c20dbb596920cd94da3844a087203", 16)); + + dsaParameters = new DSAParameters( + new BigInteger("9DB6FB5951B66BB6FE1E140F1D2CE5502374161FD6538DF1648218642F0B5C48" + + "C8F7A41AADFA187324B87674FA1822B00F1ECF8136943D7C55757264E5A1A44F" + + "FE012E9936E00C1D3E9310B01C7D179805D3058B2A9F4BB6F9716BFE6117C6B5" + + "B3CC4D9BE341104AD4A80AD6C94E005F4B993E14F091EB51743BF33050C38DE2" + + "35567E1B34C3D6A5C0CEAA1A0F368213C3D19843D0B4B09DCB9FC72D39C8DE41" + + "F1BF14D4BB4563CA28371621CAD3324B6A2D392145BEBFAC748805236F5CA2FE" + + "92B871CD8F9C36D3292B5509CA8CAA77A2ADFC7BFD77DDA6F71125A7456FEA15" + + "3E433256A2261C6A06ED3693797E7995FAD5AABBCFBE3EDA2741E375404AE25B", 16), + new BigInteger("F2C3119374CE76C9356990B465374A17F23F9ED35089BD969F61C6DDE9998C1F", 16), + new BigInteger("5C7FF6B06F8F143FE8288433493E4769C4D988ACE5BE25A0E24809670716C613" + + "D7B0CEE6932F8FAA7C44D2CB24523DA53FBE4F6EC3595892D1AA58C4328A06C4" + + "6A15662E7EAA703A1DECF8BBB2D05DBE2EB956C142A338661D10461C0D135472" + + "085057F3494309FFA73C611F78B32ADBB5740C361C9F35BE90997DB2014E2EF5" + + "AA61782F52ABEB8BD6432C4DD097BC5423B285DAFB60DC364E8161F4A2A35ACA" + + "3A10B1C4D203CC76A470A33AFDCBDD92959859ABD8B56E1725252D78EAC66E71" + + "BA9AE3F1DD2487199874393CD4D832186800654760E1E34C09E4D155179F9EC0" + + "DC4473F996BDCE6EED1CABED8B6F116F7AD9CF505DF0F998E34AB27514B0FFE7", 16)); + + privKey = new DSAPrivateKeyParameters(new BigInteger("69C7548C21D0DFEA6B9A51C9EAD4E27C33D3B3F180316E5BCAB92C933F0E4DBC", 16), dsaParameters); + + doTestHMACDetDSASample(new SHA1Digest(), privKey, new BigInteger("3A1B2DBD7489D6ED7E608FD036C83AF396E290DBD602408E8677DAABD6E7445A", 16), new BigInteger("D26FCBA19FA3E3058FFC02CA1596CDBB6E0D20CB37B06054F7E36DED0CDBBCCF", 16)); + doTestHMACDetDSASample(new SHA224Digest(), privKey, new BigInteger("DC9F4DEADA8D8FF588E98FED0AB690FFCE858DC8C79376450EB6B76C24537E2C", 16), new BigInteger("A65A9C3BC7BABE286B195D5DA68616DA8D47FA0097F36DD19F517327DC848CEC", 16)); + doTestHMACDetDSASample(new SHA256Digest(), privKey, new BigInteger("EACE8BDBBE353C432A795D9EC556C6D021F7A03F42C36E9BC87E4AC7932CC809", 16), new BigInteger("7081E175455F9247B812B74583E9E94F9EA79BD640DC962533B0680793A38D53", 16)); + doTestHMACDetDSASample(new SHA384Digest(), privKey, new BigInteger("B2DA945E91858834FD9BF616EBAC151EDBC4B45D27D0DD4A7F6A22739F45C00B", 16), new BigInteger("19048B63D9FD6BCA1D9BAE3664E1BCB97F7276C306130969F63F38FA8319021B", 16)); + doTestHMACDetDSASample(new SHA512Digest(), privKey, new BigInteger("2016ED092DC5FB669B8EFB3D1F31A91EECB199879BE0CF78F02BA062CB4C942E", 16), new BigInteger("D0C76F84B5F091E141572A639A4FB8C230807EEA7D55C8A154A224400AFF2351", 16)); + + doTestHMACDetDSATest(new SHA1Digest(), privKey, new BigInteger("C18270A93CFC6063F57A4DFA86024F700D980E4CF4E2CB65A504397273D98EA0", 16), new BigInteger("414F22E5F31A8B6D33295C7539C1C1BA3A6160D7D68D50AC0D3A5BEAC2884FAA", 16)); + doTestHMACDetDSATest(new SHA224Digest(), privKey, new BigInteger("272ABA31572F6CC55E30BF616B7A265312018DD325BE031BE0CC82AA17870EA3", 16), new BigInteger("E9CC286A52CCE201586722D36D1E917EB96A4EBDB47932F9576AC645B3A60806", 16)); + doTestHMACDetDSATest(new SHA256Digest(), privKey, new BigInteger("8190012A1969F9957D56FCCAAD223186F423398D58EF5B3CEFD5A4146A4476F0", 16), new BigInteger("7452A53F7075D417B4B013B278D1BB8BBD21863F5E7B1CEE679CF2188E1AB19E", 16)); + doTestHMACDetDSATest(new SHA384Digest(), privKey, new BigInteger("239E66DDBE8F8C230A3D071D601B6FFBDFB5901F94D444C6AF56F732BEB954BE", 16), new BigInteger("6BD737513D5E72FE85D1C750E0F73921FE299B945AAD1C802F15C26A43D34961", 16)); + doTestHMACDetDSATest(new SHA512Digest(), privKey, new BigInteger("89EC4BB1400ECCFF8E7D9AA515CD1DE7803F2DAFF09693EE7FD1353E90A68307", 16), new BigInteger("C9F0BDABCC0D880BB137A994CC7F3980CE91CC10FAF529FC46565B15CEA854E1", 16)); + } + + private void doTestHMACDetDSASample(Digest digest, DSAPrivateKeyParameters privKey, BigInteger r, BigInteger s) + { + doTestHMACDetECDSA(new DSASigner(new HMacDSAKCalculator(digest)), digest, SAMPLE, privKey, r, s); + } + + private void doTestHMACDetDSATest(Digest digest, DSAPrivateKeyParameters privKey, BigInteger r, BigInteger s) + { + doTestHMACDetECDSA(new DSASigner(new HMacDSAKCalculator(digest)), digest, TEST, privKey, r, s); + } + + // test vectors from appendix in RFC 6979 + private void testECHMacDeterministic() + { + X9ECParameters x9ECParameters = NISTNamedCurves.getByName("P-192"); + ECDomainParameters ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + ECPrivateKeyParameters privKey = new ECPrivateKeyParameters(new BigInteger("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF", 16), new BigInteger("57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("A1F00DAD97AEEC91C95585F36200C65F3C01812AA60378F5", 16), new BigInteger("E07EC1304C7C6C9DEBBE980B9692668F81D4DE7922A0F97A", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55", 16), new BigInteger("CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5", 16), new BigInteger("C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8", 16), new BigInteger("3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("0F2141A0EBBC44D2E1AF90A50EBCFCE5E197B3B7D4DE036D", 16), new BigInteger("EB18BC9E1F3D7387500CB99CF5F7C157070A8961E38700B7", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("6945A1C1D1B2206B8145548F633BB61CEF04891BAF26ED34", 16), new BigInteger("B7FB7FDFC339C0B9BD61A9F5A8EAF9BE58FC5CBA2CB15293", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE", 16), new BigInteger("5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367", 16), new BigInteger("7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739", 16), new BigInteger("74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290", 16)); + + doTestHMACDetECDSATest(new SHA3Digest(224), privKey, new BigInteger("abfcb817d04cc223f0d9c02c6db9230a91f955bf4556e0c6", 16), new BigInteger("ec2c29065a50d8ea39533d49472ccf538a5388cb31900e8f", 16)); + doTestHMACDetECDSATest(new SHA3Digest(256), privKey, new BigInteger("a2c2d5362d3cea77191edb239bf22a14dcc59d6500a744fc", 16), new BigInteger("6c63f3012353082026be7e2c6f37e6d7811066ddc9b9ee47", 16)); + doTestHMACDetECDSATest(new SHA3Digest(384), privKey, new BigInteger("2ff2c37d48cd6691c8adb9d2b1c1af203a1a6b8769c588dd", 16), new BigInteger("79c8171097f845c608dafd218ba096a51e0e4882faf2c08d", 16)); + doTestHMACDetECDSATest(new SHA3Digest(512), privKey, new BigInteger("384619b82461f4cc852dfa1e87cd87105e8eb3cfd0fb6461", 16), new BigInteger("d0aac03f72e90942821e3af1f77fd8a6ae82d1ed31b8ed06", 16)); + + x9ECParameters = NISTNamedCurves.getByName("P-224"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("F220266E1105BFE3083E03EC7A3A654651F45E37167E88600BF257C1", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("22226F9D40A96E19C4A301CE5B74B115303C0F3A4FD30FC257FB57AC", 16), new BigInteger("66D1CDD83E3AF75605DD6E2FEFF196D30AA7ED7A2EDF7AF475403D69", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("1CDFE6662DDE1E4A1EC4CDEDF6A1F5A2FB7FBD9145C12113E6ABFD3E", 16), new BigInteger("A6694FD7718A21053F225D3F46197CA699D45006C06F871808F43EBC", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("61AA3DA010E8E8406C656BC477A7A7189895E7E840CDFE8FF42307BA", 16), new BigInteger("BC814050DAB5D23770879494F9E0A680DC1AF7161991BDE692B10101", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("0B115E5E36F0F9EC81F1325A5952878D745E19D7BB3EABFABA77E953", 16), new BigInteger("830F34CCDFE826CCFDC81EB4129772E20E122348A2BBD889A1B1AF1D", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("074BD1D979D5F32BF958DDC61E4FB4872ADCAFEB2256497CDAC30397", 16), new BigInteger("A4CECA196C3D5A1FF31027B33185DC8EE43F288B21AB342E5D8EB084", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("DEAA646EC2AF2EA8AD53ED66B2E2DDAA49A12EFD8356561451F3E21C", 16), new BigInteger("95987796F6CF2062AB8135271DE56AE55366C045F6D9593F53787BD2", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("C441CE8E261DED634E4CF84910E4C5D1D22C5CF3B732BB204DBEF019", 16), new BigInteger("902F42847A63BDC5F6046ADA114953120F99442D76510150F372A3F4", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("AD04DDE87B84747A243A631EA47A1BA6D1FAA059149AD2440DE6FBA6", 16), new BigInteger("178D49B1AE90E3D8B629BE3DB5683915F4E8C99FDF6E666CF37ADCFD", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("389B92682E399B26518A95506B52C03BC9379A9DADF3391A21FB0EA4", 16), new BigInteger("414A718ED3249FF6DBC5B50C27F71F01F070944DA22AB1F78F559AAB", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("049F050477C5ADD858CAC56208394B5A55BAEBBE887FDF765047C17C", 16), new BigInteger("077EB13E7005929CEFA3CD0403C7CDCC077ADF4E44F3C41B2F60ECFF", 16)); + + x9ECParameters = NISTNamedCurves.getByName("P-256"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D32", 16), new BigInteger("6D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("53B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3F", 16), new BigInteger("B9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716", 16), new BigInteger("F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF7719", 16), new BigInteger("4861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F00", 16), new BigInteger("2362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("0CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A89", 16), new BigInteger("01B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692", 16), new BigInteger("C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367", 16), new BigInteger("019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("83910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB6", 16), new BigInteger("8DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A04", 16), new BigInteger("39AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55", 16)); + + x9ECParameters = NISTNamedCurves.getByName("P-384"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D8" + + "96D5724E4C70A825F872C9EA60D2EDF5", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA3" + + "7B9BA002899F6FDA3A4A9386790D4EB2", 16), + new BigInteger("A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF" + + "26F49CA031D4857570CCB5CA4424A443", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("42356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366" + + "450F76EE3DE43F5A125333A6BE060122", 16), + new BigInteger("9DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E483" + + "4C082C03D83028EFBF93A3C23940CA8D", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33" + + "BDE1E888E63355D92FA2B3C36D8FB2CD", 16), + new BigInteger("F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEB" + + "EFDC63ECCD1AC42EC0CB8668A4FA0AB0", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C" + + "81A648152E44ACF96E36DD1E80FABE46", 16), + new BigInteger("99EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94F" + + "A329C145786E679E7B82C71A38628AC8", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799C" + + "FE30F35CC900056D7C99CD7882433709", 16), + new BigInteger("512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112" + + "DC7CC3EF3446DEFCEB01A45C2667FDD5", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("4BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678" + + "ACD9D29876DAF46638645F7F404B11C7", 16), + new BigInteger("D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A29916" + + "95BA1C84541327E966FA7B50F7382282", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E624" + + "64A9A817C47FF78B8C11066B24080E72", 16), + new BigInteger("07041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C614" + + "1C53EA5ABEF0D8231077A04540A96B66", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("6D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559" + + "F918EEDAF2293BE5B475CC8F0188636B", 16), + new BigInteger("2D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D" + + "51AB373F9845C0514EEFB14024787265", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB" + + "0542A7F0812998DA8F1DD3CA3CF023DB", 16), + new BigInteger("DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E0" + + "6A739F040649A667BF3B828246BAA5A5", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D0" + + "6FB6495CD21B4B6E340FC236584FB277", 16), + new BigInteger("976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B22463" + + "4A2092CD3792E0159AD9CEE37659C736", 16)); + + x9ECParameters = NISTNamedCurves.getByName("P-521"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("0FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75C" + + "AA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83" + + "538", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("0343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910" + + "FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D" + + "75D", 16), + new BigInteger("0E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D" + + "5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5" + + "D16", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("1776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A3" + + "0715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2E" + + "D2E", 16), + new BigInteger("050CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17B" + + "A41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B" + + "41F", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("1511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659" + + "D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E" + + "1A7", 16), + new BigInteger("04A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916" + + "E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7E" + + "CFC", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("1EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4" + + "B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C67" + + "451", 16), + new BigInteger("1F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5" + + "FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65" + + "D61", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("0C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F1" + + "74E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E37" + + "7FA", 16), + new BigInteger("0617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF2" + + "82623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A" + + "67A", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("13BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0" + + "693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D0" + + "367", 16), + new BigInteger("1E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90" + + "F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC91679" + + "7FF", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("1C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086" + + "BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE1" + + "7FB", 16), + new BigInteger("177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5" + + "BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD51" + + "9A4", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("00E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D807104" + + "2EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656" + + "AA8", 16), + new BigInteger("0CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9" + + "FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694" + + "E86", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("14BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C" + + "89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF60755" + + "78C", 16), + new BigInteger("133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0E" + + "D94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B" + + "979", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("13E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10" + + "CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47E" + + "E6D", 16), + new BigInteger("1FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78" + + "A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4D" + + "CE3", 16)); + + x9ECParameters = NISTNamedCurves.getByName("B-163"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("35318FC447D48D7E6BC93B48617DDDEDF26AA658F", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("153FEBD179A69B6122DEBF5BC61EB947B24C93526", 16), new BigInteger("37AC9C670F8CF18045049BAE7DD35553545C19E49", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("0A379E69C44F9C16EA3215EA39EB1A9B5D58CC955", 16), new BigInteger("04BAFF5308DA2A7FE2C1742769265AD3ED1D24E74", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("134E00F78FC1CB9501675D91C401DE20DDF228CDC", 16), new BigInteger("373273AEC6C36CB7BAFBB1903A5F5EA6A1D50B624", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("29430B935AF8E77519B0CA4F6903B0B82E6A21A66", 16), new BigInteger("1EA1415306E9353FA5AA54BC7C2581DFBB888440D", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("0B2F177A99F9DF2D51CCAF55F015F326E4B65E7A0", 16), new BigInteger("0DF1FB4487E9B120C5E970EFE48F55E406306C3A1", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("256D4079C6C7169B8BC92529D701776A269D56308", 16), new BigInteger("341D3FFEC9F1EB6A6ACBE88E3C86A1C8FDEB8B8E1", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("28ECC6F1272CE80EA59DCF32F7AC2D861BA803393", 16), new BigInteger("0AD4AE2C06E60183C1567D2B82F19421FE3053CE2", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("227DF377B3FA50F90C1CB3CDCBBDBA552C1D35104", 16), new BigInteger("1F7BEAD92583FE920D353F368C1960D0E88B46A56", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("11811DAFEEA441845B6118A0DFEE8A0061231337D", 16), new BigInteger("36258301865EE48C5C6F91D63F62695002AB55B57", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("3B6BB95CA823BE2ED8E3972FF516EB8972D765571", 16), new BigInteger("13DC6F420628969DF900C3FCC48220B38BE24A541", 16)); + + x9ECParameters = NISTNamedCurves.getByName("B-233"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("07ADC13DD5BF34D1DDEEB50B2CE23B5F5E6D18067306D60C5F6FF11E5D3", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("015CC6FD78BB06E0878E71465515EA5A21A2C18E6FC77B4B158DBEB3944", 16), new BigInteger("0822A4A6C2EB2DF213A5E90BF40377956365EE8C4B4A5A4E2EB9270CB6A", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("05D9920B53471148E10502AB49AB7A3F11084820A074FD89883CF51BC1A", 16), new BigInteger("04D3938900C0A9AAA7080D1DFEB56CFB0FADABE4214536C7ED5117ED13A", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("0A797F3B8AEFCE7456202DF1E46CCC291EA5A49DA3D4BDDA9A4B62D5E0D", 16), new BigInteger("01F6F81DA55C22DA4152134C661588F4BD6F82FDBAF0C5877096B070DC2", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("015E85A8D46225DD7E314A1C4289731FC14DECE949349FE535D11043B85", 16), new BigInteger("03F189D37F50493EFD5111A129443A662AB3C6B289129AD8C0CAC85119C", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("03B62A4BF783919098B1E42F496E65F7621F01D1D466C46940F0F132A95", 16), new BigInteger("0F4BE031C6E5239E7DAA014CBBF1ED19425E49DAEB426EC9DF4C28A2E30", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("02F1FEDC57BE203E4C8C6B8C1CEB35E13C1FCD956AB41E3BD4C8A6EFB1F", 16), new BigInteger("05738EC8A8EDEA8E435EE7266AD3EDE1EEFC2CEBE2BE1D614008D5D2951", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("0CCE175124D3586BA7486F7146894C65C2A4A5A1904658E5C7F9DF5FA5D", 16), new BigInteger("08804B456D847ACE5CA86D97BF79FD6335E5B17F6C0D964B5D0036C867E", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("035C3D6DFEEA1CFB29B93BE3FDB91A7B130951770C2690C16833A159677", 16), new BigInteger("0600F7301D12AB376B56D4459774159ADB51F97E282FF384406AFD53A02", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("061602FC8068BFD5FB86027B97455D200EC603057446CCE4D76DB8EF42C", 16), new BigInteger("03396DD0D59C067BB999B422D9883736CF9311DFD6951F91033BD03CA8D", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("07E12CB60FDD614958E8E34B3C12DDFF35D85A9C5800E31EA2CC2EF63B1", 16), new BigInteger("0E8970FD99D836F3CC1C807A2C58760DE6EDAA23705A82B9CB1CE93FECC", 16)); + + x9ECParameters = NISTNamedCurves.getByName("B-283"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("14510D4BC44F2D26F4553942C98073C1BD35545CEABB5CC138853C5158D2729EA408836", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("201E18D48C6DB3D5D097C4DCE1E25587E1501FC3CF47BDB5B4289D79E273D6A9" + + "ACB8285", 16), new BigInteger("151AE05712B024CE617358260774C8CA8B0E7A7E72EF8229BF2ACE7609560CB3" + + "0322C4F", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("143E878DDFD4DF40D97B8CD638B3C4706501C2201CF7108F2FB91478C11D6947" + + "3246925", 16), new BigInteger("0CBF1B9717FEEA3AABB09D9654110144267098E0E1E8D0289A6211BE0EEDFDD8" + + "6A3DB79", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("29FD82497FB3E5CEF65579272138DE59E2B666B8689466572B3B69A172CEE83B" + + "E145659", 16), new BigInteger("05A89D9166B40795AF0FE5958201B9C0523E500013CA12B4840EA2BC53F25F9B" + + "3CE87C0", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("2F00689C1BFCD2A8C7A41E0DE55AE182E6463A152828EF89FE3525139B660329" + + "4E69353", 16), new BigInteger("1744514FE0A37447250C8A329EAAADA81572226CABA16F39270EE5DD03F27B1F" + + "665EB5D", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("0DA43A9ADFAA6AD767998A054C6A8F1CF77A562924628D73C62761847AD8286E" + + "0D91B47", 16), new BigInteger("1D118733AE2C88357827CAFC6F68ABC25C80C640532925E95CFE66D40F8792F3" + + "AC44C42", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("05A408133919F2CDCDBE5E4C14FBC706C1F71BADAFEF41F5DE4EC27272FC1CA9" + + "366FBB2", 16), new BigInteger("012966272872C097FEA7BCE64FAB1A81982A773E26F6E4EF7C99969846E67CA9" + + "CBE1692", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("08F3824E40C16FF1DDA8DC992776D26F4A5981AB5092956C4FDBB4F1AE0A711E" + + "EAA10E5", 16), new BigInteger("0A64B91EFADB213E11483FB61C73E3EF63D3B44EEFC56EA401B99DCC60CC28E9" + + "9F0F1FA", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("3597B406F5329D11A79E887847E5EC60861CCBB19EC61F252DB7BD549C699951" + + "C182796", 16), new BigInteger("0A6A100B997BC622D91701D9F5C6F6D3815517E577622DA69D3A0E8917C1CBE6" + + "3ACD345", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("1BB490926E5A1FDC7C5AA86D0835F9B994EDA315CA408002AF54A298728D422E" + + "BF59E4C", 16), new BigInteger("36C682CFC9E2C89A782BFD3A191609D1F0C1910D5FD6981442070393159D65FB" + + "CC0A8BA", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("19944AA68F9778C2E3D6E240947613E6DA60EFCE9B9B2C063FF5466D72745B5A" + + "0B25BA2", 16), new BigInteger("03F1567B3C5B02DF15C874F0EE22850824693D5ADC4663BAA19E384E550B1DD4" + + "1F31EE6", 16)); + + x9ECParameters = NISTNamedCurves.getByName("B-409"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("0494994CC325B08E7B4CE038BD9436F90B5E59A2C13C3140CD3AE07C04A01FC489F572CE0569A6DB7B8060393DE76330C624177", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("0D8783188E1A540E2022D389E1D35B32F56F8C2BB5636B8ABF7718806B27A713" + + "EBAE37F63ECD4B61445CEF5801B62594EF3E982", 16), new BigInteger("03A6B4A80E204DB0DE12E7415C13C9EC091C52935658316B4A0C591216A38791" + + "54BEB1712560E346E7EF26517707435B55C3141", 16)); + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("0EE4F39ACC2E03CE96C3D9FCBAFA5C22C89053662F8D4117752A9B10F09ADFDA" + + "59DB061E247FE5321D6B170EE758ACE1BE4D157", 16), new BigInteger("00A2B83265B456A430A8BF27DCC8A9488B3F126C10F0D6D64BF7B8A218FAAF20" + + "E51A295A3AE78F205E5A4A6AE224C3639F1BB34", 16)); + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("02D8B1B31E33E74D7EB46C30FDE5AD2CA04EC8FE08FBA0E73BA5E568953AC5EA" + + "307C072942238DFC07F4A4D7C7C6A9F86436D17", 16), new BigInteger("079F7D471E6CB73234AF7F7C381D2CE15DE35BAF8BB68393B73235B3A26EC2DF" + + "4842CE433FB492D6E074E604D4870024D42189A", 16)); + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("07BC638B7E7CE6FEE5E9C64A0F966D722D01BB4BC3F3A35F30D4CDDA92DFC5F7" + + "F0B4BBFE8065D9AD452FD77A1914BE3A2440C18", 16), new BigInteger("06D904429850521B28A32CBF55C7C0FDF35DC4E0BDA2552C7BF68A171E970E67" + + "88ACC0B9521EACB4796E057C70DD9B95FED5BFB", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("05D178DECAFD2D02A3DA0D8BA1C4C1D95EE083C760DF782193A9F7B4A8BE6FC5" + + "C21FD60613BCA65C063A61226E050A680B3ABD4", 16), new BigInteger("013B7581E98F6A63FBBCB3E49BCDA60F816DB230B888506D105DC229600497C3" + + "B46588C784BE3AA9343BEF82F7C9C80AEB63C3B", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("049F54E7C10D2732B4638473053782C6919218BBEFCEC8B51640FC193E832291" + + "F05FA12371E9B448417B3290193F08EE9319195", 16), new BigInteger("0499E267DEC84E02F6F108B10E82172C414F15B1B7364BE8BFD66ADC0C5DE23F" + + "EE3DF0D811134C25AFE0E05A6672F98889F28F1", 16)); + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("0B1527FFAA7DD7C7E46B628587A5BEC0539A2D04D3CF27C54841C2544E1BBDB4" + + "2FDBDAAF8671A4CA86DFD619B1E3732D7BB56F2", 16), new BigInteger("0442C68C044868DF4832C807F1EDDEBF7F5052A64B826FD03451440794063F52" + + "B022DF304F47403D4069234CA9EB4C964B37C02", 16)); + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("0BB27755B991D6D31757BCBF68CB01225A38E1CFA20F775E861055DD108ED7EA" + + "455E4B96B2F6F7CD6C6EC2B3C70C3EDDEB9743B", 16), new BigInteger("0C5BE90980E7F444B5F7A12C9E9AC7A04CA81412822DD5AD1BE7C45D5032555E" + + "A070864245CF69266871FEB8CD1B7EDC30EF6D5", 16)); + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("04EFEB7098772187907C87B33E0FBBA4584226C50C11E98CA7AAC6986F8D3BE0" + + "44E5B52D201A410B852536527724CA5F8CE6549", 16), new BigInteger("09574102FEB3EF87E6D66B94119F5A6062950FF4F902EA1E6BD9E2037F33FF99" + + "1E31F5956C23AFE48FCDC557FD6F088C7C9B2B3", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("07E0249C68536AE2AEC2EC30090340DA49E6DC9E9EEC8F85E5AABFB234B6DA7D" + + "2E9524028CF821F21C6019770474CC40B01FAF6", 16), new BigInteger("08125B5A03FB44AE81EA46D446130C2A415ECCA265910CA69D55F2453E16CD7B" + + "2DFA4E28C50FA8137F9C0C6CEE4CD37ABCCF6D8", 16)); + + x9ECParameters = NISTNamedCurves.getByName("B-571"); + ecDomainParameters = new ECDomainParameters(x9ECParameters.getCurve(), x9ECParameters.getG(), x9ECParameters.getN()); + + privKey = new ECPrivateKeyParameters(new BigInteger("028A04857F24C1C082DF0D909C0E72F453F2E2340CCB071F0E389BCA2575DA19" + + "124198C57174929AD26E348CF63F78D28021EF5A9BF2D5CBEAF6B7CCB6C4DA82" + + "4DD5C82CFB24E11", 16), ecDomainParameters); + + doTestHMACDetECDSASample(new SHA1Digest(), privKey, new BigInteger("147D3EB0EDA9F2152DFD014363D6A9CE816D7A1467D326A625FC4AB0C786E1B7" + + "4DDF7CD4D0E99541391B266C704BB6B6E8DCCD27B460802E0867143727AA4155" + + "55454321EFE5CB6", 16), + new BigInteger("17319571CAF533D90D2E78A64060B9C53169AB7FC908947B3EDADC54C79CCF0A" + + "7920B4C64A4EAB6282AFE9A459677CDA37FD6DD50BEF18709590FE18B923BDF7" + + "4A66B189A850819", 16)); + + doTestHMACDetECDSASample(new SHA224Digest(), privKey, new BigInteger("10F4B63E79B2E54E4F4F6A2DBC786D8F4A143ECA7B2AD97810F6472AC6AE2085" + + "3222854553BE1D44A7974599DB7061AE8560DF57F2675BE5F9DD94ABAF3D47F1" + + "582B318E459748B", 16), + new BigInteger("3BBEA07C6B269C2B7FE9AE4DDB118338D0C2F0022920A7F9DCFCB7489594C03B" + + "536A9900C4EA6A10410007222D3DAE1A96F291C4C9275D75D98EB290DC0EEF17" + + "6037B2C7A7A39A3", 16)); + + doTestHMACDetECDSASample(new SHA256Digest(), privKey, new BigInteger("213EF9F3B0CFC4BF996B8AF3A7E1F6CACD2B87C8C63820000800AC787F17EC99" + + "C04BCEDF29A8413CFF83142BB88A50EF8D9A086AF4EB03E97C567500C21D8657" + + "14D832E03C6D054", 16), + new BigInteger("3D32322559B094E20D8935E250B6EC139AC4AAB77920812C119AF419FB62B332" + + "C8D226C6C9362AE3C1E4AABE19359B8428EA74EC8FBE83C8618C2BCCB6B43FBA" + + "A0F2CCB7D303945", 16)); + + doTestHMACDetECDSASample(new SHA384Digest(), privKey, new BigInteger("375D8F49C656A0BBD21D3F54CDA287D853C4BB1849983CD891EF6CD6BB56A62B" + + "687807C16685C2C9BCA2663C33696ACCE344C45F3910B1DF806204FF731ECB28" + + "9C100EF4D1805EC", 16), + new BigInteger("1CDEC6F46DFEEE44BCE71D41C60550DC67CF98D6C91363625AC2553E4368D2DF" + + "B734A8E8C72E118A76ACDB0E58697940A0F3DF49E72894BD799450FC9E550CC0" + + "4B9FF9B0380021C", 16)); + doTestHMACDetECDSASample(new SHA512Digest(), privKey, new BigInteger("1C26F40D940A7EAA0EB1E62991028057D91FEDA0366B606F6C434C361F04E545" + + "A6A51A435E26416F6838FFA260C617E798E946B57215284182BE55F29A355E60" + + "24FE32A47289CF0", 16), + new BigInteger("3691DE4369D921FE94EDDA67CB71FBBEC9A436787478063EB1CC778B3DCDC1C4" + + "162662752D28DEEDF6F32A269C82D1DB80C87CE4D3B662E03AC347806E3F19D1" + + "8D6D4DE7358DF7E", 16)); + + doTestHMACDetECDSATest(new SHA1Digest(), privKey, new BigInteger("133F5414F2A9BC41466D339B79376038A64D045E5B0F792A98E5A7AA87E0AD01" + + "6419E5F8D176007D5C9C10B5FD9E2E0AB8331B195797C0358BA05ECBF24ACE59" + + "C5F368A6C0997CC", 16), + new BigInteger("3D16743AE9F00F0B1A500F738719C5582550FEB64689DA241665C4CE4F328BA0" + + "E34A7EF527ED13BFA5889FD2D1D214C11EB17D6BC338E05A56F41CAFF1AF7B8D" + + "574DB62EF0D0F21", 16)); + + doTestHMACDetECDSATest(new SHA224Digest(), privKey, new BigInteger("3048E76506C5C43D92B2E33F62B33E3111CEEB87F6C7DF7C7C01E3CDA28FA5E8" + + "BE04B5B23AA03C0C70FEF8F723CBCEBFF0B7A52A3F5C8B84B741B4F6157E69A5" + + "FB0524B48F31828", 16), + new BigInteger("2C99078CCFE5C82102B8D006E3703E020C46C87C75163A2CD839C885550BA5CB" + + "501AC282D29A1C26D26773B60FBE05AAB62BFA0BA32127563D42F7669C97784C" + + "8897C22CFB4B8FA", 16)); + + doTestHMACDetECDSATest(new SHA256Digest(), privKey, new BigInteger("184BC808506E11A65D628B457FDA60952803C604CC7181B59BD25AEE1411A66D" + + "12A777F3A0DC99E1190C58D0037807A95E5080FA1B2E5CCAA37B50D401CFFC34" + + "17C005AEE963469", 16), + new BigInteger("27280D45F81B19334DBDB07B7E63FE8F39AC7E9AE14DE1D2A6884D2101850289" + + "D70EE400F26ACA5E7D73F534A14568478E59D00594981ABE6A1BA18554C13EB5" + + "E03921E4DC98333", 16)); + + doTestHMACDetECDSATest(new SHA384Digest(), privKey, new BigInteger("319EE57912E7B0FAA1FBB145B0505849A89C6DB1EC06EA20A6A7EDE072A6268A" + + "F6FD9C809C7E422A5F33C6C3326EAD7402467DF3272A1B2726C1C20975950F0F" + + "50D8324578F13EC", 16), + new BigInteger("2CF3EA27EADD0612DD2F96F46E89AB894B01A10DF985C5FC099CFFE0EA083EB4" + + "4BE682B08BFE405DAD5F37D0A2C59015BA41027E24B99F8F75A70B6B7385BF39" + + "BBEA02513EB880C", 16)); + doTestHMACDetECDSATest(new SHA512Digest(), privKey, new BigInteger("2AA1888EAB05F7B00B6A784C4F7081D2C833D50794D9FEAF6E22B8BE728A2A90" + + "BFCABDC803162020AA629718295A1489EE7ED0ECB8AAA197B9BDFC49D18DDD78" + + "FC85A48F9715544", 16), + new BigInteger("0AA5371FE5CA671D6ED9665849C37F394FED85D51FEF72DA2B5F28EDFB2C6479" + + "CA63320C19596F5E1101988E2C619E302DD05112F47E8823040CE540CD3E90DC" + + "F41DBC461744EE9", 16)); + + } + + private void doTestHMACDetECDSASample(Digest digest, ECPrivateKeyParameters privKey, BigInteger r, BigInteger s) + { + doTestHMACDetECDSA(new ECDSASigner(new HMacDSAKCalculator(digest)), digest, SAMPLE, privKey, r, s); + } + + private void doTestHMACDetECDSATest(Digest digest, ECPrivateKeyParameters privKey, BigInteger r, BigInteger s) + { + doTestHMACDetECDSA(new ECDSASigner(new HMacDSAKCalculator(digest)), digest, TEST, privKey, r, s); + } + + private void doTestHMACDetECDSA(DSA detSigner, Digest digest, byte[] data, CipherParameters privKey, BigInteger r, BigInteger s) + { + byte[] m = new byte[digest.getDigestSize()]; + + digest.update(data, 0, data.length); + + digest.doFinal(m, 0); + + detSigner.init(true, privKey); + + BigInteger[] rs = detSigner.generateSignature(m); + + if (!r.equals(rs[0])) + { + fail("r value wrong, got " + rs[0].toString(16)); + } + if (!s.equals(rs[1])) + { + fail("s value wrong, got " + rs[1].toString(16)); + } + } + + public String getName() + { + return "DeterministicDSA"; + } + + public void performTest() + { + testHMacDeterministic(); + testECHMacDeterministic(); + } + + + public static void main( + String[] args) + { + runTest(new DeterministicDSATest()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DigestRandomNumberTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DigestRandomNumberTest.java new file mode 100644 index 000000000..62d7b5f6f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DigestRandomNumberTest.java @@ -0,0 +1,152 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.crypto.prng.DigestRandomGenerator; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.Digest; + +public class DigestRandomNumberTest + extends SimpleTest +{ + private static final byte[] ZERO_SEED = { 0, 0, 0, 0, 0, 0, 0, 0 }; + + private static final byte[] TEST_SEED = Hex.decode("81dcfafc885914057876"); + + private static final byte[] expected0SHA1 = Hex.decode("95bca677b3d4ff793213c00892d2356ec729ee02"); + private static final byte[] noCycle0SHA1 = Hex.decode("d57ccd0eb12c3938d59226412bc1268037b6b846"); + private static final byte[] expected0SHA256 = Hex.decode("587e2dfd597d086e47ddcd343eac983a5c913bef8c6a1a560a5c1bc3a74b0991"); + private static final byte[] noCycle0SHA256 = Hex.decode("e5776c4483486ba7be081f4e1b9dafbab25c8fae290fd5474c1ceda2c16f9509"); + private static final byte[] expected100SHA1 = Hex.decode("b9d924092546e0876cafd4937d7364ebf9efa4be"); + private static final byte[] expected100SHA256 = Hex.decode("fbc4aa54b948b99de104c44563a552899d718bb75d1941cc62a2444b0506abaf"); + private static final byte[] expectedTestSHA1 = Hex.decode("e9ecef9f5306daf1ac51a89a211a64cb24415649"); + private static final byte[] expectedTestSHA256 = Hex.decode("bdab3ca831b472a2fa09bd1bade541ef16c96640a91fcec553679a136061de98"); + + private static final byte[] sha1Xors = Hex.decode("7edcc1216934f3891b03ffa65821611a3e2b1f79"); + private static final byte[] sha256Xors = Hex.decode("5ec48189cc0aa71e79c707bc3c33ffd47bbba368a83d6cfebf3cd3969d7f3eed"); + + public String getName() + { + return "DigestRandomNumber"; + } + + private void doExpectedTest(Digest digest, int seed, byte[] expected) + { + doExpectedTest(digest, seed, expected, null); + } + + private void doExpectedTest(Digest digest, int seed, byte[] expected, byte[] noCycle) + { + DigestRandomGenerator rGen = new DigestRandomGenerator(digest); + byte[] output = new byte[digest.getDigestSize()]; + + rGen.addSeedMaterial(seed); + + for (int i = 0; i != 1024; i++) + { + rGen.nextBytes(output); + } + + if (noCycle != null) + { + if (Arrays.areEqual(noCycle, output)) + { + fail("seed not being cycled!"); + } + } + + if (!Arrays.areEqual(expected, output)) + { + fail("expected output doesn't match"); + } + } + + private void doExpectedTest(Digest digest, byte[] seed, byte[] expected) + { + DigestRandomGenerator rGen = new DigestRandomGenerator(digest); + byte[] output = new byte[digest.getDigestSize()]; + + rGen.addSeedMaterial(seed); + + for (int i = 0; i != 1024; i++) + { + rGen.nextBytes(output); + } + + if (!Arrays.areEqual(expected, output)) + { + fail("expected output doesn't match"); + } + } + + private void doCountTest(Digest digest, byte[] seed, byte[] expectedXors) + { + DigestRandomGenerator rGen = new DigestRandomGenerator(digest); + byte[] output = new byte[digest.getDigestSize()]; + int[] averages = new int[digest.getDigestSize()]; + byte[] ands = new byte[digest.getDigestSize()]; + byte[] xors = new byte[digest.getDigestSize()]; + byte[] ors = new byte[digest.getDigestSize()]; + + rGen.addSeedMaterial(seed); + + for (int i = 0; i != 1000000; i++) + { + rGen.nextBytes(output); + for (int j = 0; j != output.length; j++) + { + averages[j] += output[j] & 0xff; + ands[j] &= output[j]; + xors[j] ^= output[j]; + ors[j] |= output[j]; + } + } + + for (int i = 0; i != output.length; i++) + { + if ((averages[i] / 1000000) != 127) + { + fail("average test failed for " + digest.getAlgorithmName()); + } + if (ands[i] != 0) + { + fail("and test failed for " + digest.getAlgorithmName()); + } + if ((ors[i] & 0xff) != 0xff) + { + fail("or test failed for " + digest.getAlgorithmName()); + } + if (xors[i] != expectedXors[i]) + { + fail("xor test failed for " + digest.getAlgorithmName()); + } + } + } + + public void performTest() + throws Exception + { + doExpectedTest(new SHA1Digest(), 0, expected0SHA1, noCycle0SHA1); + doExpectedTest(new SHA256Digest(), 0, expected0SHA256, noCycle0SHA256); + + doExpectedTest(new SHA1Digest(), 100, expected100SHA1); + doExpectedTest(new SHA256Digest(), 100, expected100SHA256); + + doExpectedTest(new SHA1Digest(), ZERO_SEED, expected0SHA1); + doExpectedTest(new SHA256Digest(), ZERO_SEED, expected0SHA256); + + doExpectedTest(new SHA1Digest(), TEST_SEED, expectedTestSHA1); + doExpectedTest(new SHA256Digest(), TEST_SEED, expectedTestSHA256); + + doCountTest(new SHA1Digest(), TEST_SEED, sha1Xors); + doCountTest(new SHA256Digest(), TEST_SEED, sha256Xors); + } + + public static void main( + String[] args) + { + runTest(new DigestRandomNumberTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DigestTest.java new file mode 100644 index 000000000..70c2e1ea9 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/DigestTest.java @@ -0,0 +1,246 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.EncodableDigest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Memoable; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public abstract class DigestTest + extends SimpleTest +{ + private Digest digest; + private String[] input; + private String[] results; + + DigestTest( + Digest digest, + String[] input, + String[] results) + { + this.digest = digest; + this.input = input; + this.results = results; + } + + public String getName() + { + return digest.getAlgorithmName(); + } + + public void performTest() + { + byte[] resBuf = new byte[digest.getDigestSize()]; + + for (int i = 0; i < input.length - 1; i++) + { + byte[] m = toByteArray(input[i]); + + vectorTest(digest, i, resBuf, m, Hex.decode(results[i])); + } + + offsetTest(digest, 0, toByteArray(input[0]), Hex.decode(results[0])); + + byte[] lastV = toByteArray(input[input.length - 1]); + byte[] lastDigest = Hex.decode(results[input.length - 1]); + + vectorTest(digest, input.length - 1, resBuf, lastV, Hex.decode(results[input.length - 1])); + + testClone(resBuf, lastV, lastDigest); + testMemo(resBuf, lastV, lastDigest); + if (digest instanceof EncodableDigest) + { + testEncodedState(resBuf, lastV, lastDigest); + } + } + + private void testEncodedState(byte[] resBuf, byte[] input, byte[] expected) + { + // test state encoding; + digest.update(input, 0, input.length / 2); + + // copy the Digest + Digest copy1 = cloneDigest(((EncodableDigest)digest).getEncodedState()); + Digest copy2 = cloneDigest(((EncodableDigest)copy1).getEncodedState()); + + digest.update(input, input.length / 2, input.length - input.length / 2); + + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state vector test", expected, new String(Hex.encode(resBuf))); + } + + copy1.update(input, input.length / 2, input.length - input.length / 2); + copy1.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state copy1 vector test", expected, new String(Hex.encode(resBuf))); + } + + copy2.update(input, input.length / 2, input.length - input.length / 2); + copy2.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing state copy2 vector test", expected, new String(Hex.encode(resBuf))); + } + } + + private void testMemo(byte[] resBuf, byte[] input, byte[] expected) + { + Memoable m = (Memoable)digest; + + digest.update(input, 0, input.length/2); + + // copy the Digest + Memoable copy1 = m.copy(); + Memoable copy2 = copy1.copy(); + + digest.update(input, input.length/2, input.length - input.length/2); + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + + m.reset(copy1); + + digest.update(input, input.length/2, input.length - input.length/2); + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo reset vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + + Digest md = (Digest)copy2; + + md.update(input, input.length/2, input.length - input.length/2); + md.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing memo copy vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + } + + private void testClone(byte[] resBuf, byte[] input, byte[] expected) + { + digest.update(input, 0, input.length / 2); + + // clone the Digest + Digest d = cloneDigest(digest); + + digest.update(input, input.length/2, input.length - input.length/2); + digest.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing clone vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + + d.update(input, input.length/2, input.length - input.length/2); + d.doFinal(resBuf, 0); + + if (!areEqual(expected, resBuf)) + { + fail("failing second clone vector test", results[results.length - 1], new String(Hex.encode(resBuf))); + } + } + + protected byte[] toByteArray(String input) + { + byte[] bytes = new byte[input.length()]; + + for (int i = 0; i != bytes.length; i++) + { + bytes[i] = (byte)input.charAt(i); + } + + return bytes; + } + + private void vectorTest( + Digest digest, + int count, + byte[] resBuf, + byte[] input, + byte[] expected) + { + digest.update(input, 0, input.length); + digest.doFinal(resBuf, 0); + + if (!areEqual(resBuf, expected)) + { + fail("Vector " + count + " failed got " + new String(Hex.encode(resBuf))); + } + } + + private void offsetTest( + Digest digest, + int count, + byte[] input, + byte[] expected) + { + byte[] resBuf = new byte[expected.length + 11]; + + digest.update(input, 0, input.length); + digest.doFinal(resBuf, 11); + + if (!areEqual(Arrays.copyOfRange(resBuf, 11, resBuf.length), expected)) + { + fail("Offset " + count + " failed got " + new String(Hex.encode(resBuf))); + } + } + + protected abstract Digest cloneDigest(Digest digest); + + protected Digest cloneDigest(byte[] encodedState) + { + throw new IllegalStateException("Unsupported"); + } + + // + // optional tests + // + protected void millionATest( + String expected) + { + byte[] resBuf = new byte[digest.getDigestSize()]; + + for (int i = 0; i < 1000000; i++) + { + digest.update((byte)'a'); + } + + digest.doFinal(resBuf, 0); + + if (!areEqual(resBuf, Hex.decode(expected))) + { + fail("Million a's failed", expected, new String(Hex.encode(resBuf))); + } + } + + protected void sixtyFourKTest( + String expected) + { + byte[] resBuf = new byte[digest.getDigestSize()]; + + for (int i = 0; i < 65536; i++) + { + digest.update((byte)(i & 0xff)); + } + + digest.doFinal(resBuf, 0); + + if (!areEqual(resBuf, Hex.decode(expected))) + { + fail("64k test failed", expected, new String(Hex.encode(resBuf))); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/EAXTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/EAXTest.java new file mode 100644 index 000000000..cb5e746d1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/EAXTest.java @@ -0,0 +1,354 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.modes.AEADBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.EAXBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class EAXTest + extends SimpleTest +{ + private byte[] K1 = Hex.decode("233952DEE4D5ED5F9B9C6D6FF80FF478"); + private byte[] N1 = Hex.decode("62EC67F9C3A4A407FCB2A8C49031A8B3"); + private byte[] A1 = Hex.decode("6BFB914FD07EAE6B"); + private byte[] P1 = Hex.decode(""); + private byte[] C1 = Hex.decode("E037830E8389F27B025A2D6527E79D01"); + private byte[] T1 = Hex.decode("E037830E8389F27B025A2D6527E79D01"); + + private byte[] K2 = Hex.decode("91945D3F4DCBEE0BF45EF52255F095A4"); + private byte[] N2 = Hex.decode("BECAF043B0A23D843194BA972C66DEBD"); + private byte[] A2 = Hex.decode("FA3BFD4806EB53FA"); + private byte[] P2 = Hex.decode("F7FB"); + private byte[] C2 = Hex.decode("19DD5C4C9331049D0BDAB0277408F67967E5"); + private byte[] T2 = Hex.decode("5C4C9331049D0BDAB0277408F67967E5"); + + private byte[] K3 = Hex.decode("01F74AD64077F2E704C0F60ADA3DD523"); + private byte[] N3 = Hex.decode("70C3DB4F0D26368400A10ED05D2BFF5E"); + private byte[] A3 = Hex.decode("234A3463C1264AC6"); + private byte[] P3 = Hex.decode("1A47CB4933"); + private byte[] C3 = Hex.decode("D851D5BAE03A59F238A23E39199DC9266626C40F80"); + private byte[] T3 = Hex.decode("3A59F238A23E39199DC9266626C40F80"); + + private byte[] K4 = Hex.decode("D07CF6CBB7F313BDDE66B727AFD3C5E8"); + private byte[] N4 = Hex.decode("8408DFFF3C1A2B1292DC199E46B7D617"); + private byte[] A4 = Hex.decode("33CCE2EABFF5A79D"); + private byte[] P4 = Hex.decode("481C9E39B1"); + private byte[] C4 = Hex.decode("632A9D131AD4C168A4225D8E1FF755939974A7BEDE"); + private byte[] T4 = Hex.decode("D4C168A4225D8E1FF755939974A7BEDE"); + + private byte[] K5 = Hex.decode("35B6D0580005BBC12B0587124557D2C2"); + private byte[] N5 = Hex.decode("FDB6B06676EEDC5C61D74276E1F8E816"); + private byte[] A5 = Hex.decode("AEB96EAEBE2970E9"); + private byte[] P5 = Hex.decode("40D0C07DA5E4"); + private byte[] C5 = Hex.decode("071DFE16C675CB0677E536F73AFE6A14B74EE49844DD"); + private byte[] T5 = Hex.decode("CB0677E536F73AFE6A14B74EE49844DD"); + + private byte[] K6 = Hex.decode("BD8E6E11475E60B268784C38C62FEB22"); + private byte[] N6 = Hex.decode("6EAC5C93072D8E8513F750935E46DA1B"); + private byte[] A6 = Hex.decode("D4482D1CA78DCE0F"); + private byte[] P6 = Hex.decode("4DE3B35C3FC039245BD1FB7D"); + private byte[] C6 = Hex.decode("835BB4F15D743E350E728414ABB8644FD6CCB86947C5E10590210A4F"); + private byte[] T6 = Hex.decode("ABB8644FD6CCB86947C5E10590210A4F"); + + private byte[] K7 = Hex.decode("7C77D6E813BED5AC98BAA417477A2E7D"); + private byte[] N7 = Hex.decode("1A8C98DCD73D38393B2BF1569DEEFC19"); + private byte[] A7 = Hex.decode("65D2017990D62528"); + private byte[] P7 = Hex.decode("8B0A79306C9CE7ED99DAE4F87F8DD61636"); + private byte[] C7 = Hex.decode("02083E3979DA014812F59F11D52630DA30137327D10649B0AA6E1C181DB617D7F2"); + private byte[] T7 = Hex.decode("137327D10649B0AA6E1C181DB617D7F2"); + + private byte[] K8 = Hex.decode("5FFF20CAFAB119CA2FC73549E20F5B0D"); + private byte[] N8 = Hex.decode("DDE59B97D722156D4D9AFF2BC7559826"); + private byte[] A8 = Hex.decode("54B9F04E6A09189A"); + private byte[] P8 = Hex.decode("1BDA122BCE8A8DBAF1877D962B8592DD2D56"); + private byte[] C8 = Hex.decode("2EC47B2C4954A489AFC7BA4897EDCDAE8CC33B60450599BD02C96382902AEF7F832A"); + private byte[] T8 = Hex.decode("3B60450599BD02C96382902AEF7F832A"); + + private byte[] K9 = Hex.decode("A4A4782BCFFD3EC5E7EF6D8C34A56123"); + private byte[] N9 = Hex.decode("B781FCF2F75FA5A8DE97A9CA48E522EC"); + private byte[] A9 = Hex.decode("899A175897561D7E"); + private byte[] P9 = Hex.decode("6CF36720872B8513F6EAB1A8A44438D5EF11"); + private byte[] C9 = Hex.decode("0DE18FD0FDD91E7AF19F1D8EE8733938B1E8E7F6D2231618102FDB7FE55FF1991700"); + private byte[] T9 = Hex.decode("E7F6D2231618102FDB7FE55FF1991700"); + + private byte[] K10 = Hex.decode("8395FCF1E95BEBD697BD010BC766AAC3"); + private byte[] N10 = Hex.decode("22E7ADD93CFC6393C57EC0B3C17D6B44"); + private byte[] A10 = Hex.decode("126735FCC320D25A"); + private byte[] P10 = Hex.decode("CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7"); + private byte[] C10 = Hex.decode("CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC253B4652B1AF3795B124AB6E"); + private byte[] T10 = Hex.decode("CFC46AFC253B4652B1AF3795B124AB6E"); + + private byte[] K11 = Hex.decode("8395FCF1E95BEBD697BD010BC766AAC3"); + private byte[] N11 = Hex.decode("22E7ADD93CFC6393C57EC0B3C17D6B44"); + private byte[] A11 = Hex.decode("126735FCC320D25A"); + private byte[] P11 = Hex.decode("CA40D7446E545FFAED3BD12A740A659FFBBB3CEAB7"); + private byte[] C11 = Hex.decode("CB8920F87A6C75CFF39627B56E3ED197C552D295A7CFC46AFC"); + private byte[] T11 = Hex.decode("CFC46AFC"); + + private static final int NONCE_LEN = 8; + private static final int MAC_LEN = 8; + private static final int AUTHEN_LEN = 20; + + public String getName() + { + return "EAX"; + } + + public void performTest() + throws Exception + { + checkVectors(1, K1, 128, N1, A1, P1, T1, C1); + checkVectors(2, K2, 128, N2, A2, P2, T2, C2); + checkVectors(3, K3, 128, N3, A3, P3, T3, C3); + checkVectors(4, K4, 128, N4, A4, P4, T4, C4); + checkVectors(5, K5, 128, N5, A5, P5, T5, C5); + checkVectors(6, K6, 128, N6, A6, P6, T6, C6); + checkVectors(7, K7, 128, N7, A7, P7, T7, C7); + checkVectors(8, K8, 128, N8, A8, P8, T8, C8); + checkVectors(9, K9, 128, N9, A9, P9, T9, C9); + checkVectors(10, K10, 128, N10, A10, P10, T10, C10); + checkVectors(11, K11, 32, N11, A11, P11, T11, C11); + + EAXBlockCipher eax = new EAXBlockCipher(new AESEngine()); + ivParamTest(1, eax, K1, N1); + + // + // exception tests + // + + try + { + eax.init(false, new AEADParameters(new KeyParameter(K1), 32, N2, A2)); + + byte[] enc = new byte[C2.length]; + int len = eax.processBytes(C2, 0, C2.length, enc, 0); + + len += eax.doFinal(enc, len); + + fail("invalid cipher text not picked up"); + } + catch (InvalidCipherTextException e) + { + // expected + } + + try + { + eax.init(false, new KeyParameter(K1)); + + fail("illegal argument not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + randomTests(); + AEADTestUtil.testReset(this, new EAXBlockCipher(new AESEngine()), new EAXBlockCipher(new AESEngine()), new AEADParameters(new KeyParameter(K1), 32, N2)); + AEADTestUtil.testTampering(this, eax, new AEADParameters(new KeyParameter(K1), 32, N2)); + AEADTestUtil.testOutputSizes(this, new EAXBlockCipher(new AESEngine()), new AEADParameters( + new KeyParameter(K1), 32, N2)); + AEADTestUtil.testBufferSizeChecks(this, new EAXBlockCipher(new AESEngine()), new AEADParameters( + new KeyParameter(K1), 32, N2)); + } + + private void checkVectors( + int count, + byte[] k, + int macSize, + byte[] n, + byte[] a, + byte[] p, + byte[] t, + byte[] c) + throws InvalidCipherTextException + { + byte[] fa = new byte[a.length / 2]; + byte[] la = new byte[a.length - (a.length / 2)]; + System.arraycopy(a, 0, fa, 0, fa.length); + System.arraycopy(a, fa.length, la, 0, la.length); + + checkVectors(count, "all initial associated data", k, macSize, n, a, null, p, t, c); + checkVectors(count, "subsequent associated data", k, macSize, n, null, a, p, t, c); + checkVectors(count, "split associated data", k, macSize, n, fa, la, p, t, c); + } + + private void checkVectors( + int count, + String additionalDataType, + byte[] k, + int macSize, + byte[] n, + byte[] a, + byte[] sa, + byte[] p, + byte[] t, + byte[] c) + throws InvalidCipherTextException + { + EAXBlockCipher encEax = new EAXBlockCipher(new AESEngine()); + EAXBlockCipher decEax = new EAXBlockCipher(new AESEngine()); + + AEADParameters parameters = new AEADParameters(new KeyParameter(k), macSize, n, a); + encEax.init(true, parameters); + decEax.init(false, parameters); + + runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c); + runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c); + + // key reuse test + parameters = new AEADParameters(null, macSize, n, a); + encEax.init(true, parameters); + decEax.init(false, parameters); + + runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c); + runCheckVectors(count, encEax, decEax, additionalDataType, sa, p, t, c); + } + + private void runCheckVectors( + int count, + EAXBlockCipher encEax, + EAXBlockCipher decEax, + String additionalDataType, + byte[] sa, + byte[] p, + byte[] t, + byte[] c) + throws InvalidCipherTextException + { + byte[] enc = new byte[c.length]; + + if (sa != null) + { + encEax.processAADBytes(sa, 0, sa.length); + } + + int len = encEax.processBytes(p, 0, p.length, enc, 0); + + len += encEax.doFinal(enc, len); + + if (!areEqual(c, enc)) + { + fail("encrypted stream fails to match in test " + count + " with " + additionalDataType); + } + + byte[] tmp = new byte[enc.length]; + + if (sa != null) + { + decEax.processAADBytes(sa, 0, sa.length); + } + + len = decEax.processBytes(enc, 0, enc.length, tmp, 0); + + len += decEax.doFinal(tmp, len); + + byte[] dec = new byte[len]; + + System.arraycopy(tmp, 0, dec, 0, len); + + if (!areEqual(p, dec)) + { + fail("decrypted stream fails to match in test " + count + " with " + additionalDataType); + } + + if (!areEqual(t, decEax.getMac())) + { + fail("MAC fails to match in test " + count + " with " + additionalDataType); + } + } + + private void ivParamTest( + int count, + AEADBlockCipher eax, + byte[] k, + byte[] n) + throws InvalidCipherTextException + { + byte[] p = Strings.toByteArray("hello world!!"); + + eax.init(true, new ParametersWithIV(new KeyParameter(k), n)); + + byte[] enc = new byte[p.length + 8]; + + int len = eax.processBytes(p, 0, p.length, enc, 0); + + len += eax.doFinal(enc, len); + + eax.init(false, new ParametersWithIV(new KeyParameter(k), n)); + + byte[] tmp = new byte[enc.length]; + + len = eax.processBytes(enc, 0, enc.length, tmp, 0); + + len += eax.doFinal(tmp, len); + + byte[] dec = new byte[len]; + + System.arraycopy(tmp, 0, dec, 0, len); + + if (!areEqual(p, dec)) + { + fail("decrypted stream fails to match in test " + count); + } + } + + private void randomTests() + throws InvalidCipherTextException + { + SecureRandom srng = new SecureRandom(); + for (int i = 0; i < 10; ++i) + { + randomTest(srng); + } + } + + private void randomTest( + SecureRandom srng) + throws InvalidCipherTextException + { + int DAT_LEN = srng.nextInt() >>> 22; // Note: JDK1.0 compatibility + byte[] nonce = new byte[NONCE_LEN]; + byte[] authen = new byte[AUTHEN_LEN]; + byte[] datIn = new byte[DAT_LEN]; + byte[] key = new byte[16]; + srng.nextBytes(nonce); + srng.nextBytes(authen); + srng.nextBytes(datIn); + srng.nextBytes(key); + + AESEngine engine = new AESEngine(); + KeyParameter sessKey = new KeyParameter(key); + EAXBlockCipher eaxCipher = new EAXBlockCipher(engine); + + AEADParameters params = new AEADParameters(sessKey, MAC_LEN * 8, nonce, authen); + eaxCipher.init(true, params); + + byte[] intrDat = new byte[eaxCipher.getOutputSize(datIn.length)]; + int outOff = eaxCipher.processBytes(datIn, 0, DAT_LEN, intrDat, 0); + outOff += eaxCipher.doFinal(intrDat, outOff); + + eaxCipher.init(false, params); + byte[] datOut = new byte[eaxCipher.getOutputSize(outOff)]; + int resultLen = eaxCipher.processBytes(intrDat, 0, outOff, datOut, 0); + eaxCipher.doFinal(datOut, resultLen); + + if (!areEqual(datIn, datOut)) + { + fail("EAX roundtrip failed to match"); + } + } + + public static void main(String[] args) + { + runTest(new EAXTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECDHKEKGeneratorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECDHKEKGeneratorTest.java new file mode 100644 index 000000000..bd8f6e79e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECDHKEKGeneratorTest.java @@ -0,0 +1,71 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.DerivationFunction; +import com.fr.third.org.bouncycastle.crypto.DerivationParameters; +import com.fr.third.org.bouncycastle.crypto.agreement.kdf.DHKDFParameters; +import com.fr.third.org.bouncycastle.crypto.agreement.kdf.ECDHKEKGenerator; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * ECDHKEK Generator tests. + */ +public class ECDHKEKGeneratorTest + extends SimpleTest +{ + private byte[] seed1 = Hex.decode("db4a8daba1f98791d54e940175dd1a5f3a0826a1066aa9b668d4dc1e1e0790158dcad1533c03b44214d1b61fefa8b579"); + private ASN1ObjectIdentifier alg1 = NISTObjectIdentifiers.id_aes256_wrap; + private byte[] result1 = Hex.decode("8ecc6d85caf25eaba823a7d620d4ab0d33e4c645f2"); + + private byte[] seed2 = Hex.decode("75d7487b5d3d2bfb3c69ce0365fe64e3bfab5d0d63731628a9f47eb8fddfa28c65decaf228a0b38f0c51c6a3356d7c56"); + private ASN1ObjectIdentifier alg2 = NISTObjectIdentifiers.id_aes128_wrap; + private byte[] result2 = Hex.decode("042be1faca3a4a8fc859241bfb87ba35"); + + private byte[] seed3 = Hex.decode("fdeb6d809f997e8ac174d638734dc36d37aaf7e876e39967cd82b1cada3de772449788461ee7f856bad9305627f8e48b"); + private ASN1ObjectIdentifier alg3 = PKCSObjectIdentifiers.id_alg_CMS3DESwrap; + private byte[] result3 = Hex.decode("bcd701fc92109b1b9d6f3b6497ad5ca9627fa8a597010305"); + + public ECDHKEKGeneratorTest() + { + } + + public void performTest() + { + checkMask(1, new ECDHKEKGenerator(new SHA1Digest()), new DHKDFParameters(alg1, 256, seed1), result1); + checkMask(2, new ECDHKEKGenerator(new SHA1Digest()), new DHKDFParameters(alg2, 128, seed2), result2); + checkMask(3, new ECDHKEKGenerator(new SHA1Digest()), new DHKDFParameters(alg3, 192, seed3), result3); + } + + private void checkMask( + int count, + DerivationFunction kdf, + DerivationParameters params, + byte[] result) + { + byte[] data = new byte[result.length]; + + kdf.init(params); + + kdf.generateBytes(data, 0, data.length); + + if (!areEqual(result, data)) + { + fail("ECDHKEKGenerator failed generator test " + count); + } + } + + public String getName() + { + return "ECDHKEKGenerator"; + } + + public static void main( + String[] args) + { + runTest(new ECDHKEKGeneratorTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECGOST3410Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECGOST3410Test.java new file mode 100644 index 000000000..64781d79c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECGOST3410Test.java @@ -0,0 +1,327 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.digests.GOST3411Digest; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.signers.ECGOST3410Signer; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomData; + +/** + * ECGOST3410 tests are taken from GOST R 34.10-2001. + */ +public class ECGOST3410Test + extends SimpleTest + { + byte[] hashmessage = Hex.decode("3042453136414534424341374533364339313734453431443642453241453435"); + + /** + * ECGOST3410 over the field Fp
+ */ + BigInteger r = new BigInteger("29700980915817952874371204983938256990422752107994319651632687982059210933395"); + BigInteger s = new BigInteger("574973400270084654178925310019147038455227042649098563933718999175515839552"); + + byte[] kData = new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395").toByteArray(); + + SecureRandom k = new TestRandomData(kData); + + private void ecGOST3410_TEST() + { + BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p + BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("7"), // a + new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b + mod_q, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.createPoint( + new BigInteger("2"), // x + new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y + mod_q); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("55441196065363246126355624130324183196576709222340016572108097750006097525544"), // d + params); + + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ECGOST3410Signer ecgost3410 = new ECGOST3410Signer(); + + ecgost3410.init(true, param); + + byte[] mVal = new BigInteger("20798893674476452017134061561508270130637142515379653289952617252661468872421").toByteArray(); + byte[] message = new byte[mVal.length]; + + for (int i = 0; i != mVal.length; i++) + { + message[i] = mVal[mVal.length - 1 - i]; + } + + BigInteger[] sig = ecgost3410.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong.", r, sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong.", s, sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.createPoint( + new BigInteger("57520216126176808443631405023338071176630104906313632182896741342206604859403"), // x + new BigInteger("17614944419213781543809391949654080031942662045363639260709847859438286763994")), // y + params); + + ecgost3410.init(false, pubKey); + if (!ecgost3410.verifySignature(message, sig[0], sig[1])) + { + fail("verification fails"); + } + } + + /** + * Test Sign & Verify with test parameters + * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt + * gostR3410-2001-TestParamSet P.46 + */ + private void ecGOST3410_TestParam() + { + SecureRandom random = new SecureRandom(); + + BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p + BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("7"), // a + new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b + mod_q, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.createPoint( + new BigInteger("2"), // x + new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y + mod_q); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + ECGOST3410Signer ecgost3410 = new ECGOST3410Signer(); + + ecgost3410.init(true, param); + + //get hash message using the digest GOST3411. + byte[] message = "Message for sign".getBytes(); + GOST3411Digest gost3411 = new GOST3411Digest(); + gost3411.update(message, 0, message.length); + byte[] hashmessage = new byte[gost3411.getDigestSize()]; + gost3411.doFinal(hashmessage, 0); + + BigInteger[] sig = ecgost3410.generateSignature(hashmessage); + + ecgost3410.init(false, pair.getPublic()); + + if (!ecgost3410.verifySignature(hashmessage, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * Test Sign & Verify with A parameters + * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt + * gostR3410-2001-CryptoPro-A-ParamSet P.47 + */ + public void ecGOST3410_AParam() + { + SecureRandom random = new SecureRandom(); + + BigInteger mod_p = new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639319"); //p + BigInteger mod_q = new BigInteger("115792089237316195423570985008687907853073762908499243225378155805079068850323"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("115792089237316195423570985008687907853269984665640564039457584007913129639316"), // a + new BigInteger("166"), // b + mod_q, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.createPoint( + new BigInteger("1"), // x + new BigInteger("64033881142927202683649881450433473985931760268884941288852745803908878638612")), // y + mod_q); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + ECGOST3410Signer ecgost3410 = new ECGOST3410Signer(); + + ecgost3410.init(true, param); + + BigInteger[] sig = ecgost3410.generateSignature(hashmessage); + + ecgost3410.init(false, pair.getPublic()); + + if (!ecgost3410.verifySignature(hashmessage, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * Test Sign & Verify with B parameters + * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt + * gostR3410-2001-CryptoPro-B-ParamSet P.47-48 + */ + private void ecGOST3410_BParam() + { + SecureRandom random = new SecureRandom(); + + BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823193"); //p + BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927102133160255826820068844496087732066703"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564823190"), // a + new BigInteger("28091019353058090096996979000309560759124368558014865957655842872397301267595"), // b + mod_q, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.createPoint( + new BigInteger("1"), // x + new BigInteger("28792665814854611296992347458380284135028636778229113005756334730996303888124")), // y + mod_q); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + ECGOST3410Signer ecgost3410 = new ECGOST3410Signer(); + + ecgost3410.init(true, param); + + BigInteger[] sig = ecgost3410.generateSignature(hashmessage); + + ecgost3410.init(false, pair.getPublic()); + + if (!ecgost3410.verifySignature(hashmessage, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * Test Sign & Verify with C parameters + * see: http://www.ietf.org/internet-drafts/draft-popov-cryptopro-cpalgs-01.txt + * gostR3410-2001-CryptoPro-C-ParamSet P.48 + */ + private void ecGOST3410_CParam() + { + SecureRandom random = new SecureRandom(); + + BigInteger mod_p = new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502619"); //p + BigInteger mod_q = new BigInteger("70390085352083305199547718019018437840920882647164081035322601458352298396601"); + + ECCurve.Fp curve = new ECCurve.Fp( + mod_p, // p + new BigInteger("70390085352083305199547718019018437841079516630045180471284346843705633502616"), // a + new BigInteger("32858"), // b + mod_q, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.createPoint( + new BigInteger("0"), // x + new BigInteger("29818893917731240733471273240314769927240550812383695689146495261604565990247")), // y + mod_q); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + ECGOST3410Signer ecgost3410 = new ECGOST3410Signer(); + + ecgost3410.init(true, param); + + BigInteger[] sig = ecgost3410.generateSignature(hashmessage); + + ecgost3410.init(false, pair.getPublic()); + + if (!ecgost3410.verifySignature(hashmessage, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + public String getName() + { + return "ECGOST3410"; + } + + public void performTest() + { + ecGOST3410_TEST(); + ecGOST3410_TestParam(); + ecGOST3410_AParam(); + ecGOST3410_BParam(); + ecGOST3410_CParam(); + } + + public static void main( + String[] args) + { + runTest(new ECGOST3410Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECIESKeyEncapsulationTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECIESKeyEncapsulationTest.java new file mode 100644 index 000000000..b70d66f95 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECIESKeyEncapsulationTest.java @@ -0,0 +1,138 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.sec.SECNamedCurves; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.KDF2BytesGenerator; +import com.fr.third.org.bouncycastle.crypto.kems.ECIESKeyEncapsulation; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Tests for the ECIES Key Encapsulation Mechanism + */ +public class ECIESKeyEncapsulationTest + extends SimpleTest +{ + public String getName() + { + return "ECIESKeyEncapsulation"; + } + + public void performTest() + throws Exception + { + + // Set EC domain parameters and generate key pair + X9ECParameters spec = SECNamedCurves.getByName("secp224r1"); + ECDomainParameters ecDomain = new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN()); + ECKeyPairGenerator ecGen = new ECKeyPairGenerator(); + + ecGen.init(new ECKeyGenerationParameters(ecDomain, new SecureRandom())); + + AsymmetricCipherKeyPair keys = ecGen.generateKeyPair(); + + // Set ECIES-KEM parameters + ECIESKeyEncapsulation kem; + KDF2BytesGenerator kdf = new KDF2BytesGenerator(new SHA1Digest()); + SecureRandom rnd = new SecureRandom(); + byte[] out = new byte[57]; + KeyParameter key1, key2; + + // Test basic ECIES-KEM + kem = new ECIESKeyEncapsulation(kdf, rnd); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed basic test"); + } + + // Test ECIES-KEM using new cofactor mode + kem = new ECIESKeyEncapsulation(kdf, rnd, true, false, false); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed cofactor test"); + } + + // Test ECIES-KEM using old cofactor mode + kem = new ECIESKeyEncapsulation(kdf, rnd, false, true, false); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed old cofactor test"); + } + + // Test ECIES-KEM using single hash mode + kem = new ECIESKeyEncapsulation(kdf, rnd, false, false, true); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed single hash test"); + } + + // Test ECIES-KEM using new cofactor mode and single hash mode + kem = new ECIESKeyEncapsulation(kdf, rnd, true, false, true); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed cofactor and single hash test"); + } + + // Test ECIES-KEM using old cofactor mode and single hash mode + kem = new ECIESKeyEncapsulation(kdf, rnd, false, true, true); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed old cofactor and single hash test"); + } + } + + public static void main( + String[] args) + { + runTest(new ECIESKeyEncapsulationTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECIESTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECIESTest.java new file mode 100644 index 000000000..3d8b66e9c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECIESTest.java @@ -0,0 +1,545 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.KeyEncoder; +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.agreement.ECDHBasicAgreement; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.engines.IESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.TwofishEngine; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.KDF2BytesGenerator; +import com.fr.third.org.bouncycastle.crypto.kems.ECIESKeyEncapsulation; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECNamedDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.IESParameters; +import com.fr.third.org.bouncycastle.crypto.params.IESWithCipherParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.crypto.parsers.ECIESPublicKeyParser; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * test for ECIES - Elliptic Curve Integrated Encryption Scheme + */ +public class ECIESTest + extends SimpleTest +{ + private static byte[] TWOFISH_IV = Hex.decode("000102030405060708090a0b0c0d0e0f"); + + ECIESTest() + { + } + + public String getName() + { + return "ECIES"; + } + + private void doStaticTest(byte[] iv) + throws Exception + { + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + AsymmetricCipherKeyPair p1 = new AsymmetricCipherKeyPair(pubKey, priKey); + AsymmetricCipherKeyPair p2 = new AsymmetricCipherKeyPair(pubKey, priKey); + + // + // stream test + // + IESEngine i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + IESEngine i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + CipherParameters p = new IESParameters(d, e, 64); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + byte[] message = Hex.decode("1234567890abcdef"); + + byte[] out1 = i1.processBlock(message, 0, message.length); + + if (!areEqual(out1, Hex.decode("468d89877e8238802403ec4cb6b329faeccfa6f3a730f2cdb3c0a8e8"))) + { + fail("stream cipher test failed on enc"); + } + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // twofish with CBC + // + BufferedBlockCipher c1 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + BufferedBlockCipher c2 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c1); + i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c2); + d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + p = new IESWithCipherParameters(d, e, 64, 128); + + if (iv != null) + { + p = new ParametersWithIV(p, iv); + } + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + message = Hex.decode("1234567890abcdef"); + + out1 = i1.processBlock(message, 0, message.length); + + if (!areEqual(out1, (iv == null) ? + Hex.decode("b8a06ea5c2b9df28b58a0a90a734cde8c9c02903e5c220021fe4417410d1e53a32a71696") + : Hex.decode("f246b0e26a2711992cac9c590d08e45c5e730b7c0f4218bb064e27b7dd7c8a3bd8bf01c3"))) + { + fail("twofish cipher test failed on enc"); + } + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("twofish cipher test failed"); + } + } + + private void doShortTest(byte[] iv) + throws Exception + { + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + AsymmetricCipherKeyPair p1 = new AsymmetricCipherKeyPair(pubKey, priKey); + AsymmetricCipherKeyPair p2 = new AsymmetricCipherKeyPair(pubKey, priKey); + + // + // stream test - V 0 + // + IESEngine i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + IESEngine i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + CipherParameters p = new IESParameters(d, e, 64); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + byte[] message = new byte[0]; + + byte[] out1 = i1.processBlock(message, 0, message.length); + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + try + { + i2.processBlock(out1, 0, out1.length - 1); + fail("no exception"); + } + catch (InvalidCipherTextException ex) + { + if (!"Length of input must be greater than the MAC and V combined".equals(ex.getMessage())) + { + fail("wrong exception"); + } + } + + // with ephemeral key pair + + // Generate the ephemeral key pair + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + gen.init(new ECKeyGenerationParameters(params, new SecureRandom())); + + EphemeralKeyPairGenerator ephKeyGen = new EphemeralKeyPairGenerator(gen, new KeyEncoder() + { + public byte[] getEncoded(AsymmetricKeyParameter keyParameter) + { + return ((ECPublicKeyParameters)keyParameter).getQ().getEncoded(false); + } + }); + + i1.init(p2.getPublic(), p, ephKeyGen); + i2.init(p2.getPrivate(), p, new ECIESPublicKeyParser(params)); + + out1 = i1.processBlock(message, 0, message.length); + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("V cipher test failed"); + } + + try + { + i2.processBlock(out1, 0, out1.length - 1); + fail("no exception"); + } + catch (InvalidCipherTextException ex) + { + if (!"Length of input must be greater than the MAC and V combined".equals(ex.getMessage())) + { + fail("wrong exception"); + } + } + } + + private void doEphemeralTest(byte[] iv, final boolean usePointCompression) + throws Exception + { + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + AsymmetricCipherKeyPair p1 = new AsymmetricCipherKeyPair(pubKey, priKey); + AsymmetricCipherKeyPair p2 = new AsymmetricCipherKeyPair(pubKey, priKey); + + // Generate the ephemeral key pair + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + gen.init(new ECKeyGenerationParameters(params, new SecureRandom())); + + EphemeralKeyPairGenerator ephKeyGen = new EphemeralKeyPairGenerator(gen, new KeyEncoder() + { + public byte[] getEncoded(AsymmetricKeyParameter keyParameter) + { + return ((ECPublicKeyParameters)keyParameter).getQ().getEncoded(usePointCompression); + } + }); + + // + // stream test + // + IESEngine i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + IESEngine i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + + byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + CipherParameters p = new IESParameters(d, e, 64); + + i1.init(p2.getPublic(), p, ephKeyGen); + i2.init(p2.getPrivate(), p, new ECIESPublicKeyParser(params)); + + byte[] message = Hex.decode("1234567890abcdef"); + + byte[] out1 = i1.processBlock(message, 0, message.length); + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // twofish with CBC + // + BufferedBlockCipher c1 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + BufferedBlockCipher c2 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c1); + i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c2); + d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + p = new IESWithCipherParameters(d, e, 64, 128); + + if (iv != null) + { + p = new ParametersWithIV(p, iv); + } + + i1.init(p2.getPublic(), p, ephKeyGen); + i2.init(p2.getPrivate(), p, new ECIESPublicKeyParser(params)); + + message = Hex.decode("1234567890abcdef"); + + out1 = i1.processBlock(message, 0, message.length); + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("twofish cipher test failed"); + } + } + + private void doTest(AsymmetricCipherKeyPair p1, AsymmetricCipherKeyPair p2) + throws Exception + { + // + // stream test + // + IESEngine i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + IESEngine i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest())); + byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + IESParameters p = new IESParameters(d, e, 64); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + byte[] message = Hex.decode("1234567890abcdef"); + + byte[] out1 = i1.processBlock(message, 0, message.length); + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // twofish with CBC + // + BufferedBlockCipher c1 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + BufferedBlockCipher c2 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + i1 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c1); + i2 = new IESEngine( + new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + c2); + d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + p = new IESWithCipherParameters(d, e, 64, 128); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + message = Hex.decode("1234567890abcdef"); + + out1 = i1.processBlock(message, 0, message.length); + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("twofish cipher test failed"); + } + } + + public void performTest() + throws Exception + { + doStaticTest(null); + doStaticTest(TWOFISH_IV); + doShortTest(null); + + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECKeyPairGenerator eGen = new ECKeyPairGenerator(); + KeyGenerationParameters gParam = new ECKeyGenerationParameters(params, new SecureRandom()); + + eGen.init(gParam); + + AsymmetricCipherKeyPair p1 = eGen.generateKeyPair(); + AsymmetricCipherKeyPair p2 = eGen.generateKeyPair(); + + doTest(p1, p2); + + doEphemeralTest(null, false); + doEphemeralTest(null, true); + doEphemeralTest(TWOFISH_IV, false); + doEphemeralTest(TWOFISH_IV, true); + + doCofactorTest(true, false); + doCofactorTest(false, false); + doCofactorTest(false, true); + doCofactorTest(true, true); + } + + private void doCofactorTest(boolean newCofactorMode, boolean oldCofactorMode) + { + + /* Create the generator */ + ECKeyPairGenerator myGenerator = new ECKeyPairGenerator(); + SecureRandom myRandom = new SecureRandom(); + String myCurve = "sect571k1"; /* Any curve will do */ + + /* Lookup the parameters */ + X9ECParameters x9 = ECNamedCurveTable.getByName(myCurve); + + /* Initialise the generator */ + ASN1ObjectIdentifier myOid = ECNamedCurveTable.getOID(myCurve); + ECNamedDomainParameters myDomain = new ECNamedDomainParameters(myOid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + ECKeyGenerationParameters myParams = new ECKeyGenerationParameters(myDomain, myRandom); + myGenerator.init(myParams); + + /* Create the key Pair */ + AsymmetricCipherKeyPair myPair = myGenerator.generateKeyPair(); + + /* Determine message length */ + int myFieldSize = x9.getCurve().getFieldSize(); + myFieldSize = (myFieldSize + 8 - 1) / 8; + int myLen = 2 * myFieldSize + 1; + byte[] myMessage = new byte[myLen]; + int myKeyLen = 256 / 8; + + /* Create agreement */ + ECIESKeyEncapsulation myAgreement = new ECIESKeyEncapsulation(new KDF2BytesGenerator(new SHA512Digest()), myRandom, newCofactorMode, oldCofactorMode, false); + myAgreement.init(myPair.getPublic()); + KeyParameter mySender = (KeyParameter) myAgreement.encrypt(myMessage, myKeyLen); + byte[] mySenderKey = mySender.getKey(); + + /* Accept agreement */ + myAgreement.init(myPair.getPrivate()); + KeyParameter myReceiver = (KeyParameter) myAgreement.decrypt(myMessage, myKeyLen); + byte[] myReceiverKey = myReceiver.getKey(); + + /* Check that keys match */ + isTrue("new " + newCofactorMode + " old " + oldCofactorMode, Arrays.areEqual(mySenderKey, myReceiverKey)); + } + + public static void main( + String[] args) + { + runTest(new ECIESTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECNRTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECNRTest.java new file mode 100644 index 000000000..a98e59785 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECNRTest.java @@ -0,0 +1,168 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.TigerDigest; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECNamedDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.signers.ECNRSigner; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; + +/** + * ECNR tests. + */ +public class ECNRTest + extends SimpleTest +{ + /** + * a basic regression test with 239 bit prime + */ + BigInteger r = new BigInteger("308636143175167811492623515537541734843573549327605293463169625072911693"); + BigInteger s = new BigInteger("852401710738814635664888632022555967400445256405412579597015412971797143"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); + + SecureRandom k = new TestRandomBigInteger(kData); + + private void ecNR239bitPrime() + { + BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d + params); + + ECNRSigner ecnr = new ECNRSigner(); + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ecnr.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecnr.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong.", r, sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong.", s, sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q + params); + + ecnr.init(false, pubKey); + if (!ecnr.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + private void rangeTest() + { + /* Create the generator */ + ECKeyPairGenerator myGenerator = new ECKeyPairGenerator(); + SecureRandom myRandom = new SecureRandom(); + String myCurve = "brainpoolP192t1"; + + /* Lookup the parameters */ + final X9ECParameters x9 = ECNamedCurveTable.getByName(myCurve); + + /* Initialise the generator */ + final ASN1ObjectIdentifier myOid = ECNamedCurveTable.getOID(myCurve); + ECNamedDomainParameters myDomain = new ECNamedDomainParameters(myOid, x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + ECKeyGenerationParameters myParams = new ECKeyGenerationParameters(myDomain, myRandom); + myGenerator.init(myParams); + + /* Create the key Pair */ + AsymmetricCipherKeyPair myPair = myGenerator.generateKeyPair(); + + /* Create the digest and the output buffer */ + Digest myDigest = new TigerDigest(); + byte[] myArtifact = new byte[myDigest.getDigestSize()]; + final byte[] myMessage = "Hello there. How is life treating you?".getBytes(); + myDigest.update(myMessage, 0, myMessage.length); + myDigest.doFinal(myArtifact, 0); + + /* Create signer */ + ECNRSigner signer = new ECNRSigner(); + signer.init(true, myPair.getPrivate()); + + try + { + signer.generateSignature(myArtifact); + fail("out of range input not caught"); + } + catch (DataLengthException e) + { + isTrue(e.getMessage().equals("input too large for ECNR key")); + } + + // + // check upper bound + BigInteger order = ((ECPublicKeyParameters)myPair.getPublic()).getParameters().getN(); + + signer.init(true, myPair.getPrivate()); + byte[] msg = BigIntegers.asUnsignedByteArray(order.subtract(BigIntegers.ONE)); + BigInteger[] sig = signer.generateSignature(msg); + + signer.init(false, myPair.getPublic()); + if (!signer.verifySignature(msg, sig[0], sig[1])) + { + fail("ECNR failed 2"); + } + + isTrue(Arrays.areEqual(msg, signer.getRecoveredMessage(sig[0], sig[1]))); + } + + public String getName() + { + return "ECNR"; + } + + public void performTest() + { + ecNR239bitPrime(); + rangeTest(); + } + + public static void main( + String[] args) + { + runTest(new ECNRTest()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECTest.java new file mode 100644 index 000000000..81123f3e3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ECTest.java @@ -0,0 +1,1137 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.nist.NISTNamedCurves; +import com.fr.third.org.bouncycastle.asn1.sec.SECNamedCurves; +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.BasicAgreement; +import com.fr.third.org.bouncycastle.crypto.agreement.ECDHBasicAgreement; +import com.fr.third.org.bouncycastle.crypto.agreement.ECDHCBasicAgreement; +import com.fr.third.org.bouncycastle.crypto.agreement.ECDHCUnifiedAgreement; +import com.fr.third.org.bouncycastle.crypto.agreement.ECMQVBasicAgreement; +import com.fr.third.org.bouncycastle.crypto.digests.SHA3Digest; +import com.fr.third.org.bouncycastle.crypto.ec.CustomNamedCurves; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ECDHUPrivateParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECDHUPublicParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.MQVPrivateParameters; +import com.fr.third.org.bouncycastle.crypto.params.MQVPublicParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.signers.DSADigestSigner; +import com.fr.third.org.bouncycastle.crypto.signers.ECDSASigner; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; + +/** + * ECDSA tests are taken from X9.62. + */ +public class ECTest + extends SimpleTest +{ + /** + * X9.62 - 1998,
+ * J.3.1, Page 152, ECDSA over the field Fp
+ * an example with 192 bit prime + */ + private void testECDSA192bitPrime() + { + BigInteger r = new BigInteger("3342403536405981729393488334694600415596881826869351677613"); + BigInteger s = new BigInteger("5735822328888155254683894997897571951568553642892029982342"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("6140507067065001063065065565667405560006161556565665656654")); + + SecureRandom k = new TestRandomBigInteger(kData); + + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ECDSASigner ecdsa = new ECDSASigner(); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + ecdsa.init(false, pubKey); + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("verification fails"); + } + } + + private void decodeTest() + { + X9ECParameters x9 = ECNamedCurveTable.getByName("prime192v1"); + ECPoint p = x9.getG(); + + if (!p.getAffineXCoord().toBigInteger().equals(new BigInteger("188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", 16))) + { + fail("x uncompressed incorrectly"); + } + + if (!p.getAffineYCoord().toBigInteger().equals(new BigInteger("7192b95ffc8da78631011ed6b24cdd573f977a11e794811", 16))) + { + fail("y uncompressed incorrectly"); + } + + byte[] encoding = p.getEncoded(true); + + if (!areEqual(encoding, Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012"))) + { + fail("point compressed incorrectly"); + } + } + + /** + * X9.62 - 1998,
+ * J.3.2, Page 155, ECDSA over the field Fp
+ * an example with 239 bit prime + */ + private void testECDSA239bitPrime() + { + BigInteger r = new BigInteger("308636143175167811492622547300668018854959378758531778147462058306432176"); + BigInteger s = new BigInteger("323813553209797357708078776831250505931891051755007842781978505179448783"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); + + SecureRandom k = new TestRandomBigInteger(kData); + + BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d + params); + + ECDSASigner ecdsa = new ECDSASigner(); + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q + params); + + ecdsa.init(false, pubKey); + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + + /** + * X9.62 - 1998,
+ * J.2.1, Page 100, ECDSA over the field F2m
+ * an example with 191 bit binary field + */ + private void testECDSA191bitBinary() + { + BigInteger r = new BigInteger("87194383164871543355722284926904419997237591535066528048"); + BigInteger s = new BigInteger("308992691965804947361541664549085895292153777025772063598"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("1542725565216523985789236956265265265235675811949404040041")); + + SecureRandom k = new TestRandomBigInteger(kData); + + BigInteger n = new BigInteger("1569275433846670190958947355803350458831205595451630533029"); + BigInteger h = BigInteger.valueOf(2); + + ECCurve.F2m curve = new ECCurve.F2m( + 191, // m + 9, //k + new BigInteger("2866537B676752636A68F56554E12640276B649EF7526267", 16), // a + new BigInteger("2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", 16), // b + n, h); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("0436B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D765BE73433B3F95E332932E70EA245CA2418EA0EF98018FB")), // G + n, h); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("1275552191113212300012030439187146164646146646466749494799"), // d + params); + + ECDSASigner ecdsa = new ECDSASigner(); + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("045DE37E756BD55D72E3768CB396FFEB962614DEA4CE28A2E755C0E0E02F5FB132CAF416EF85B229BBB8E1352003125BA1")), // Q + params); + + ecdsa.init(false, pubKey); + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + + /** + * X9.62 - 1998,
+ * J.2.1, Page 100, ECDSA over the field F2m
+ * an example with 191 bit binary field + */ + private void testECDSA239bitBinary() + { + BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552"); + BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); + + SecureRandom k = new TestRandomBigInteger(kData); + + BigInteger n = new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve.F2m curve = new ECCurve.F2m( + 239, // m + 36, //k + new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a + new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16), // b + n, h); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G + n, h); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d + params); + + ECDSASigner ecdsa = new ECDSASigner(); + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q + params); + + ecdsa.init(false, pubKey); + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + // L 4.1 X9.62 2005 + private void testECDSAP224sha224() + { + X9ECParameters p = NISTNamedCurves.getByName("P-224"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("6081831502424510080126737029209236539191290354021104541805484120491"), // d + params); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601"))); + + byte[] M = Hex.decode("8797A3C693CC292441039A4E6BAB7387F3B4F2A63D00ED384B378C79"); + + ECDSASigner dsa = new ECDSASigner(); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + BigInteger[] sig = dsa.generateSignature(M); + + BigInteger r = new BigInteger("26477406756127720855365980332052585411804331993436302005017227573742"); + BigInteger s = new BigInteger("17694958233103667059888193972742186995283044672015112738919822429978"); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("03FD44EC11F9D43D9D23B1E1D1C9ED6519B40ECF0C79F48CF476CC43F1")), // Q + params); + + dsa.init(false, pubKey); + if (!dsa.verifySignature(M, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + private void testECDSASecP224k1sha256() + { + X9ECParameters p = SECNamedCurves.getByName("secp224k1"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("BE6F6E91FE96840A6518B56F3FE21689903A64FA729057AB872A9F51", 16), // d + params); + SecureRandom k = new TestRandomBigInteger(Hex.decode("00c39beac93db21c3266084429eb9b846b787c094f23a4de66447efbb3")); + + byte[] M = Hex.decode("E5D5A7ADF73C5476FAEE93A2C76CE94DC0557DB04CDC189504779117920B896D"); + + ECDSASigner dsa = new ECDSASigner(); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + BigInteger[] sig = dsa.generateSignature(M); + + BigInteger r = new BigInteger("8163E5941BED41DA441B33E653C632A55A110893133351E20CE7CB75", 16); + BigInteger s = new BigInteger("D12C3FC289DDD5F6890DCE26B65792C8C50E68BF551D617D47DF15A8", 16); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("04C5C9B38D3603FCCD6994CBB9594E152B658721E483669BB42728520F484B537647EC816E58A8284D3B89DFEDB173AFDC214ECA95A836FA7C")), // Q + params); + + dsa.init(false, pubKey); + if (!dsa.verifySignature(M, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + // L4.2 X9.62 2005 + private void testECDSAP256sha256() + { + X9ECParameters p = NISTNamedCurves.getByName("P-256"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("20186677036482506117540275567393538695075300175221296989956723148347484984008"), // d + params); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); + + byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); + + ECDSASigner dsa = new ECDSASigner(); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + BigInteger[] sig = dsa.generateSignature(M); + + BigInteger r = new BigInteger("97354732615802252173078420023658453040116611318111190383344590814578738210384"); + BigInteger s = new BigInteger("98506158880355671805367324764306888225238061309262649376965428126566081727535"); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("03596375E6CE57E0F20294FC46BDFCFD19A39F8161B58695B3EC5B3D16427C274D")), // Q + params); + + dsa.init(false, pubKey); + if (!dsa.verifySignature(M, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + private void testECDSAP256sha3(int size, BigInteger s) + { + X9ECParameters p = NISTNamedCurves.getByName("P-256"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("20186677036482506117540275567393538695075300175221296989956723148347484984008"), // d + params); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); + + byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); + + DSADigestSigner dsa = new DSADigestSigner(new ECDSASigner(), new SHA3Digest(size)); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + dsa.update(M, 0, M.length); + + byte[] encSig = dsa.generateSignature(); + + ASN1Sequence sig = ASN1Sequence.getInstance(encSig); + + BigInteger r = new BigInteger("97354732615802252173078420023658453040116611318111190383344590814578738210384"); + + BigInteger sigR = ASN1Integer.getInstance(sig.getObjectAt(0)).getValue(); + if (!r.equals(sigR)) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sigR.toString(16)); + } + + BigInteger sigS = ASN1Integer.getInstance(sig.getObjectAt(1)).getValue(); + if (!s.equals(sigS)) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sigS.toString(16)); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("03596375E6CE57E0F20294FC46BDFCFD19A39F8161B58695B3EC5B3D16427C274D")), // Q + params); + + dsa.init(false, pubKey); + + dsa.update(M, 0, M.length); + + if (!dsa.verifySignature(encSig)) + { + fail("signature fails"); + } + } + + private void testECDSAP224OneByteOver() + { + X9ECParameters p = NISTNamedCurves.getByName("P-224"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("6081831502424510080126737029209236539191290354021104541805484120491"), // d + params); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("15456715103636396133226117016818339719732885723579037388121116732601"))); + + byte[] M = Hex.decode("8797A3C693CC292441039A4E6BAB7387F3B4F2A63D00ED384B378C79FF"); + + ECDSASigner dsa = new ECDSASigner(); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + BigInteger[] sig = dsa.generateSignature(M); + + BigInteger r = new BigInteger("26477406756127720855365980332052585411804331993436302005017227573742"); + BigInteger s = new BigInteger("17694958233103667059888193972742186995283044672015112738919822429978"); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("03FD44EC11F9D43D9D23B1E1D1C9ED6519B40ECF0C79F48CF476CC43F1")), // Q + params); + + dsa.init(false, pubKey); + if (!dsa.verifySignature(M, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + // L4.3 X9.62 2005 + private void testECDSAP521sha512() + { + X9ECParameters p = NISTNamedCurves.getByName("P-521"); + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("617573726813476282316253885608633222275541026607493641741273231656161177732180358888434629562647985511298272498852936680947729040673640492310550142822667389"), // d + params); + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("6806532878215503520845109818432174847616958675335397773700324097584974639728725689481598054743894544060040710846048585856076812050552869216017728862957612913"))); + + byte[] M = Hex.decode("6893B64BD3A9615C39C3E62DDD269C2BAAF1D85915526083183CE14C2E883B48B193607C1ED871852C9DF9C3147B574DC1526C55DE1FE263A676346A20028A66"); + + ECDSASigner dsa = new ECDSASigner(); + + dsa.init(true, new ParametersWithRandom(priKey, k)); + + BigInteger[] sig = dsa.generateSignature(M); + + BigInteger r = new BigInteger("1368926195812127407956140744722257403535864168182534321188553460365652865686040549247096155740756318290773648848859639978618869784291633651685766829574104630"); + BigInteger s = new BigInteger("1624754720348883715608122151214003032398685415003935734485445999065609979304811509538477657407457976246218976767156629169821116579317401249024208611945405790"); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + params.getCurve().decodePoint(Hex.decode("020145E221AB9F71C5FE740D8D2B94939A09E2816E2167A7D058125A06A80C014F553E8D6764B048FB6F2B687CEC72F39738F223D4CE6AFCBFF2E34774AA5D3C342CB3")), // Q + params); + + dsa.init(false, pubKey); + if (!dsa.verifySignature(M, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * General test for long digest. + */ + private void testECDSA239bitBinaryAndLargeDigest() + { + BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552"); + BigInteger s = new BigInteger("144940322424411242416373536877786566515839911620497068645600824084578597"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); + + SecureRandom k = new TestRandomBigInteger(kData); + + BigInteger n = new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"); + BigInteger h = BigInteger.valueOf(4); + + ECCurve.F2m curve = new ECCurve.F2m( + 239, // m + 36, //k + new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a + new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16), // b + n, h); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G + n, h); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d + params); + + ECDSASigner ecdsa = new ECDSASigner(); + ParametersWithRandom param = new ParametersWithRandom(priKey, k); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517968236873715988614170569073515315707566766479517968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + // Verify the signature + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q + params); + + ecdsa.init(false, pubKey); + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * key generation test + */ + private void testECDSAKeyGenTest() + { + SecureRandom random = new SecureRandom(); + + BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + n); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + ECDSASigner ecdsa = new ECDSASigner(); + + ecdsa.init(true, param); + + byte[] message = new BigInteger("968236873715988614170569073515315707566766479517").toByteArray(); + BigInteger[] sig = ecdsa.generateSignature(message); + + ecdsa.init(false, pair.getPublic()); + + if (!ecdsa.verifySignature(message, sig[0], sig[1])) + { + fail("signature fails"); + } + } + + /** + * Basic Key Agreement Test + */ + private void testECDHBasicAgreement() + { + SecureRandom random = new SecureRandom(); + + BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + n); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + ECKeyGenerationParameters genParam = new ECKeyGenerationParameters( + params, + random); + + pGen.init(genParam); + + AsymmetricCipherKeyPair p1 = pGen.generateKeyPair(); + AsymmetricCipherKeyPair p2 = pGen.generateKeyPair(); + + // + // two way + // + BasicAgreement e1 = new ECDHBasicAgreement(); + BasicAgreement e2 = new ECDHBasicAgreement(); + + e1.init(p1.getPrivate()); + e2.init(p2.getPrivate()); + + BigInteger k1 = e1.calculateAgreement(p2.getPublic()); + BigInteger k2 = e2.calculateAgreement(p1.getPublic()); + + if (!k1.equals(k2)) + { + fail("calculated agreement test failed"); + } + + // + // two way + // + e1 = new ECDHCBasicAgreement(); + e2 = new ECDHCBasicAgreement(); + + e1.init(p1.getPrivate()); + e2.init(p2.getPrivate()); + + k1 = e1.calculateAgreement(p2.getPublic()); + k2 = e2.calculateAgreement(p1.getPublic()); + + if (!k1.equals(k2)) + { + fail("calculated agreement test failed"); + } + } + + private void testECDHBasicAgreementCofactor() + { + SecureRandom random = new SecureRandom(); + + X9ECParameters x9 = CustomNamedCurves.getByName("curve25519"); + ECDomainParameters ec = new ECDomainParameters(x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + + ECKeyPairGenerator kpg = new ECKeyPairGenerator(); + kpg.init(new ECKeyGenerationParameters(ec, random)); + + AsymmetricCipherKeyPair p1 = kpg.generateKeyPair(); + AsymmetricCipherKeyPair p2 = kpg.generateKeyPair(); + + BasicAgreement e1 = new ECDHBasicAgreement(); + BasicAgreement e2 = new ECDHBasicAgreement(); + + e1.init(p1.getPrivate()); + e2.init(p2.getPrivate()); + + BigInteger k1 = e1.calculateAgreement(p2.getPublic()); + BigInteger k2 = e2.calculateAgreement(p1.getPublic()); + + if (!k1.equals(k2)) + { + fail("calculated agreement test failed"); + } + } + + private void testECMQVTestVector1() + { + // Test Vector from GEC-2 + + X9ECParameters x9 = SECNamedCurves.getByName("secp160r1"); + ECDomainParameters p = new ECDomainParameters( + x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + + AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("0251B4496FECC406ED0E75A24A3C03206251419DC0")), p), + new ECPrivateKeyParameters( + new BigInteger("AA374FFC3CE144E6B073307972CB6D57B2A4E982", 16), p)); + + AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("03D99CE4D8BF52FA20BD21A962C6556B0F71F4CA1F")), p), + new ECPrivateKeyParameters( + new BigInteger("149EC7EA3A220A887619B3F9E5B4CA51C7D1779C", 16), p)); + + AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("0349B41E0E9C0369C2328739D90F63D56707C6E5BC")), p), + new ECPrivateKeyParameters( + new BigInteger("45FB58A92A17AD4B15101C66E74F277E2B460866", 16), p)); + + AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("02706E5D6E1F640C6E9C804E75DBC14521B1E5F3B5")), p), + new ECPrivateKeyParameters( + new BigInteger("18C13FCED9EADF884F7C595C8CB565DEFD0CB41E", 16), p)); + + BigInteger x = calculateAgreement(U1, U2, V1, V2); + + if (x == null + || !x.equals(new BigInteger("5A6955CEFDB4E43255FB7FCF718611E4DF8E05AC", 16))) + { + fail("MQV Test Vector #1 agreement failed"); + } + } + + private void testECMQVTestVector2() + { + // Test Vector from GEC-2 + + X9ECParameters x9 = SECNamedCurves.getByName("sect163k1"); + ECDomainParameters p = new ECDomainParameters( + x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + + AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("03037D529FA37E42195F10111127FFB2BB38644806BC")), p), + new ECPrivateKeyParameters( + new BigInteger("03A41434AA99C2EF40C8495B2ED9739CB2155A1E0D", 16), p)); + + AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("02015198E74BC2F1E5C9A62B80248DF0D62B9ADF8429")), p), + new ECPrivateKeyParameters( + new BigInteger("032FC4C61A8211E6A7C4B8B0C03CF35F7CF20DBD52", 16), p)); + + AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("03072783FAAB9549002B4F13140B88132D1C75B3886C")), p), + new ECPrivateKeyParameters( + new BigInteger("57E8A78E842BF4ACD5C315AA0569DB1703541D96", 16), p)); + + AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("03067E3AEA3510D69E8EDD19CB2A703DDC6CF5E56E32")), p), + new ECPrivateKeyParameters( + new BigInteger("02BD198B83A667A8D908EA1E6F90FD5C6D695DE94F", 16), p)); + + BigInteger x = calculateAgreement(U1, U2, V1, V2); + + if (x == null + || !x.equals(new BigInteger("038359FFD30C0D5FC1E6154F483B73D43E5CF2B503", 16))) + { + fail("MQV Test Vector #2 agreement failed"); + } + } + + private void testECMQVRandom() + { + SecureRandom random = new SecureRandom(); + + BigInteger n = new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839"), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16), // b + n, ECConstants.ONE); + + ECDomainParameters parameters = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + n); + + ECKeyPairGenerator pGen = new ECKeyPairGenerator(); + + pGen.init(new ECKeyGenerationParameters(parameters, random)); + + + // Pre-established key pairs + AsymmetricCipherKeyPair U1 = pGen.generateKeyPair(); + AsymmetricCipherKeyPair V1 = pGen.generateKeyPair(); + + // Ephemeral key pairs + AsymmetricCipherKeyPair U2 = pGen.generateKeyPair(); + AsymmetricCipherKeyPair V2 = pGen.generateKeyPair(); + + BigInteger x = calculateAgreement(U1, U2, V1, V2); + + if (x == null) + { + fail("MQV Test Vector (random) agreement failed"); + } + } + + private static BigInteger calculateAgreement( + AsymmetricCipherKeyPair U1, + AsymmetricCipherKeyPair U2, + AsymmetricCipherKeyPair V1, + AsymmetricCipherKeyPair V2) + { + ECMQVBasicAgreement u = new ECMQVBasicAgreement(); + u.init(new MQVPrivateParameters( + (ECPrivateKeyParameters)U1.getPrivate(), + (ECPrivateKeyParameters)U2.getPrivate(), + (ECPublicKeyParameters)U2.getPublic())); + BigInteger ux = u.calculateAgreement(new MQVPublicParameters( + (ECPublicKeyParameters)V1.getPublic(), + (ECPublicKeyParameters)V2.getPublic())); + + ECMQVBasicAgreement v = new ECMQVBasicAgreement(); + v.init(new MQVPrivateParameters( + (ECPrivateKeyParameters)V1.getPrivate(), + (ECPrivateKeyParameters)V2.getPrivate(), + (ECPublicKeyParameters)V2.getPublic())); + BigInteger vx = v.calculateAgreement(new MQVPublicParameters( + (ECPublicKeyParameters)U1.getPublic(), + (ECPublicKeyParameters)U2.getPublic())); + + if (ux.equals(vx)) + { + return ux; + } + + return null; + } + + private void testECUnifiedTestVector1() + { + // Test Vector from NIST sample data + + X9ECParameters x9 = NISTNamedCurves.getByName("P-224"); + ECDomainParameters p = new ECDomainParameters( + x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + + AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("040784e946ef1fae0cfe127042a310a018ba639d3f6b41f265904f0a7b21b7953efe638b45e6c0c0d34a883a510ce836d143d831daa9ce8a12")), p), + new ECPrivateKeyParameters( + new BigInteger("86d1735ca357890aeec8eccb4859275151356ecee9f1b2effb76b092", 16), p)); + + AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("04b33713dc0d56215be26ee6c5e60ad36d12e02e78529ae3ff07873c6b39598bda41c1cf86ee3981f40e102333c15fef214bda034291c1aca6")), p), + new ECPrivateKeyParameters( + new BigInteger("764010b3137ef8d34a3552955ada572a4fa1bb1f5289f27c1bf18344", 16), p)); + + AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("0484c22d9575d09e280613c8758467f84869c6eede4f6c1b644517d6a72c4fc5c68fa12b4c259032fc5949c630259948fca38fb3342d9cb0a8")), p), + new ECPrivateKeyParameters( + new BigInteger("e37964e391f5058fb43435352a9913438a1ec10831f755273285230a", 16), p)); + + AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("044b917e9ce693b277c8095e535ea81c2dea089446a8c55438eda750fb6170c85b86390481fff2dff94b7dff3e42d35ff623921cb558967b48")), p), + new ECPrivateKeyParameters( + new BigInteger("ab40d67f59ba7265d8ad33ade8f704d13a7ba2298b69172a7cd02515", 16), p)); + + byte[] x = calculateUnifiedAgreement(U1, U2, V1, V2); + + if (x == null + || !areEqual(Hex.decode("80315a208b1cd6119264e5c03242b7db96379986fdc4c2f06bf88d0655cda75d4dc7e94a8df9f03239d5da9a18d364cebc6c63f01b6f4378"), x)) + { + fail("EC combined Test Vector #1 agreement failed"); + } + } + + private void testECUnifiedTestVector2() + { + // Test Vector from NIST sample data + + X9ECParameters x9 = NISTNamedCurves.getByName("P-256"); + ECDomainParameters p = new ECDomainParameters( + x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + + AsymmetricCipherKeyPair U1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("047581b35964a983414ebdd56f4ebb1ddcad10881b200666a51ae41306e1ecf1db368468a5e8a65ca10ccea526472c8982db68316c468800e171c11f4ee694fce4")), p), + new ECPrivateKeyParameters( + new BigInteger("2eb7ef76d4936123b6f13035045aedf45c1c7731f35d529d25941926b5bb38bb", 16), p)); + + AsymmetricCipherKeyPair U2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("045b1e4cdeb0728333c0a51631b1a75269e4878d10732f4cb94d600483db4bd9ee625c374592c3db7e9f8b4f2c91a0098a158bc37b922e4243bd9cbdefe67d6ab0")), p), + new ECPrivateKeyParameters( + new BigInteger("78acde388a022261767e6b3dd6dd016c53b70a084260ec87d395aec761c082de", 16), p)); + + AsymmetricCipherKeyPair V1 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("04e4916d616803ff1bd9569f35b7d06f792f19c1fb4e6fa916d686c027a17d8dffd570193d8e101624ac2ea0bcb762d5613f05452670f09af66ef70861fb528868")), p), + new ECPrivateKeyParameters( + new BigInteger("9c85898640a1b1de8ce7f557492dc1460530b9e17afaaf742eb953bb644e9c5a", 16), p)); + + AsymmetricCipherKeyPair V2 = new AsymmetricCipherKeyPair( + new ECPublicKeyParameters( + p.getCurve().decodePoint(Hex.decode("04d1cd23c29d0fc865c316d44a1fd5adb6605ee47c9ddfec3a9b0a5e532d52704e74ff5d149aeb50856fefb38d5907b6dbb580fe6dc166bcfcbee4eb376d77e95c")), p), + new ECPrivateKeyParameters( + new BigInteger("d6e11d5d3b85b201b8f4c12dadfad3000e267961a806a0658a2b859d44389599", 16), p)); + + byte[] x = calculateUnifiedAgreement(U1, U2, V1, V2); + + if (x == null + || !areEqual(Hex.decode("02886e53998b06d92f04e4579cbfa5f35c96334d3890298264e7f956da70966af07bf1b3abbaa8d76fbaf435508bdabbbbbdae1a191d91480ed88374c3552233"), x)) + { + fail("EC combined Test Vector #2 agreement failed"); + } + } + + private byte[] calculateUnifiedAgreement( + AsymmetricCipherKeyPair U1, + AsymmetricCipherKeyPair U2, + AsymmetricCipherKeyPair V1, + AsymmetricCipherKeyPair V2) + { + ECDHCUnifiedAgreement u = new ECDHCUnifiedAgreement(); + u.init(new ECDHUPrivateParameters( + (ECPrivateKeyParameters)U1.getPrivate(), + (ECPrivateKeyParameters)U2.getPrivate(), + (ECPublicKeyParameters)U2.getPublic())); + byte[] ux = u.calculateAgreement(new ECDHUPublicParameters( + (ECPublicKeyParameters)V1.getPublic(), + (ECPublicKeyParameters)V2.getPublic())); + + ECDHCUnifiedAgreement v = new ECDHCUnifiedAgreement(); + v.init(new ECDHUPrivateParameters( + (ECPrivateKeyParameters)V1.getPrivate(), + (ECPrivateKeyParameters)V2.getPrivate(), + (ECPublicKeyParameters)V2.getPublic())); + byte[] vx = v.calculateAgreement(new ECDHUPublicParameters( + (ECPublicKeyParameters)U1.getPublic(), + (ECPublicKeyParameters)U2.getPublic())); + + if (areEqual(ux, vx)) + { + return ux; + } + + return null; + } + + public String getName() + { + return "EC"; + } + + public void performTest() + { + decodeTest(); + testECDSA192bitPrime(); + testECDSA239bitPrime(); + testECDSA191bitBinary(); + testECDSA239bitBinary(); + testECDSAKeyGenTest(); + testECDHBasicAgreement(); + testECDHBasicAgreementCofactor(); + + testECDSAP224sha224(); + testECDSAP224OneByteOver(); + testECDSAP256sha256(); + testECDSAP521sha512(); + testECDSASecP224k1sha256(); + testECDSA239bitBinaryAndLargeDigest(); + + testECDSAP256sha3(224, new BigInteger("84d7d8e68e405064109cd9fc3e3026d74d278aada14ce6b7a9dd0380c154dc94", 16)); + testECDSAP256sha3(256, new BigInteger("99a43bdab4af989aaf2899079375642f2bae2dce05bcd8b72ec8c4a8d9a143f", 16)); + testECDSAP256sha3(384, new BigInteger("aa27726509c37aaf601de6f7e01e11c19add99530c9848381c23365dc505b11a", 16)); + testECDSAP256sha3(512, new BigInteger("f8306b57a1f5068bf12e53aabaae39e2658db39bc56747eaefb479995130ad16", 16)); + + testECMQVTestVector1(); + testECMQVTestVector2(); + testECMQVRandom(); + + testECUnifiedTestVector1(); + testECUnifiedTestVector2(); + } + + + public static void main( + String[] args) + { + runTest(new ECTest()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Ed25519Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Ed25519Test.java new file mode 100644 index 000000000..5d056f56d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Ed25519Test.java @@ -0,0 +1,148 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.Signer; +import com.fr.third.org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.signers.Ed25519Signer; +import com.fr.third.org.bouncycastle.crypto.signers.Ed25519ctxSigner; +import com.fr.third.org.bouncycastle.crypto.signers.Ed25519phSigner; +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed25519; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Ed25519Test + extends SimpleTest +{ + private static final SecureRandom RANDOM = new SecureRandom(); + + public String getName() + { + return "Ed25519"; + } + + public static void main(String[] args) + { + runTest(new Ed25519Test()); + } + + public void performTest() throws Exception + { + for (int i = 0; i < 10; ++i) + { + testConsistency(Ed25519.Algorithm.Ed25519, null); + + byte[] context = randomContext(RANDOM.nextInt() & 255); + testConsistency(Ed25519.Algorithm.Ed25519ctx, context); + testConsistency(Ed25519.Algorithm.Ed25519ph, context); + } + + basicSigTest(); + } + + private void basicSigTest() + throws Exception + { + Ed25519PrivateKeyParameters privateKey = new Ed25519PrivateKeyParameters( + Hex.decode("9d61b19deffd5a60ba844af492ec2cc44449c5697b326919703bac031cae7f60"), 0); + Ed25519PublicKeyParameters publicKey = new Ed25519PublicKeyParameters( + Hex.decode("d75a980182b10ab7d54bfed3c964073a0ee172f3daa62325af021a68f707511a"), 0); + + byte[] sig = Hex.decode("e5564300c360ac729086e2cc806e828a84877f1eb8e5d974d873e065224901555fb8821590a33bacc61e39701cf9b46bd25bf5f0595bbe24655141438e7a100b"); + + Signer signer = new Ed25519Signer(); + + signer.init(true, privateKey); + + areEqual(sig, signer.generateSignature()); + + signer.init(false, publicKey); + + isTrue(signer.verifySignature(sig)); + } + + private Signer createSigner(int algorithm, byte[] context) + { + switch (algorithm) + { + case Ed25519.Algorithm.Ed25519: + return new Ed25519Signer(); + case Ed25519.Algorithm.Ed25519ctx: + return new Ed25519ctxSigner(context); + case Ed25519.Algorithm.Ed25519ph: + return new Ed25519phSigner(context); + default: + throw new IllegalArgumentException("algorithm"); + } + } + + private byte[] randomContext(int length) + { + byte[] context = new byte[length]; + RANDOM.nextBytes(context); + return context; + } + + private void testConsistency(int algorithm, byte[] context) throws Exception + { + Ed25519KeyPairGenerator kpg = new Ed25519KeyPairGenerator(); + kpg.init(new Ed25519KeyGenerationParameters(RANDOM)); + + AsymmetricCipherKeyPair kp = kpg.generateKeyPair(); + Ed25519PrivateKeyParameters privateKey = (Ed25519PrivateKeyParameters)kp.getPrivate(); + Ed25519PublicKeyParameters publicKey = (Ed25519PublicKeyParameters)kp.getPublic(); + + byte[] msg = new byte[RANDOM.nextInt() & 255]; + RANDOM.nextBytes(msg); + + Signer signer = createSigner(algorithm, context); + signer.init(true, privateKey); + signer.update(msg, 0, msg.length); + byte[] signature = signer.generateSignature(); + + Signer verifier = createSigner(algorithm, context); + + { + verifier.init(false, publicKey); + verifier.update(msg, 0, msg.length); + boolean shouldVerify = verifier.verifySignature(signature); + + if (!shouldVerify) + { + fail("Ed25519(" + algorithm + ") signature failed to verify"); + } + } + + { + byte[] wrongLengthSignature = Arrays.append(signature, (byte)0x00); + + verifier.init(false, publicKey); + verifier.update(msg, 0, msg.length); + boolean shouldNotVerify = verifier.verifySignature(wrongLengthSignature); + + if (shouldNotVerify) + { + fail("Ed25519(" + algorithm + ") wrong length signature incorrectly verified"); + } + } + + { + byte[] badSignature = Arrays.clone(signature); + badSignature[(RANDOM.nextInt() >>> 1) % badSignature.length] ^= 1 << (RANDOM.nextInt() & 7); + + verifier.init(false, publicKey); + verifier.update(msg, 0, msg.length); + boolean shouldNotVerify = verifier.verifySignature(badSignature); + + if (shouldNotVerify) + { + fail("Ed25519(" + algorithm + ") bad signature incorrectly verified"); + } + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Ed448Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Ed448Test.java new file mode 100644 index 000000000..dfa8e3322 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Ed448Test.java @@ -0,0 +1,157 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.Signer; +import com.fr.third.org.bouncycastle.crypto.generators.Ed448KeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.Ed448KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.signers.Ed448Signer; +import com.fr.third.org.bouncycastle.crypto.signers.Ed448phSigner; +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed448; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Ed448Test + extends SimpleTest +{ + private static final SecureRandom RANDOM = new SecureRandom(); + + public String getName() + { + return "Ed448"; + } + + public static void main(String[] args) + { + runTest(new Ed448Test()); + } + + public void performTest() throws Exception + { + basicSigTest(); + + for (int i = 0; i < 10; ++i) + { + byte[] context = randomContext(RANDOM.nextInt() & 255); + testConsistency(Ed448.Algorithm.Ed448, context); + testConsistency(Ed448.Algorithm.Ed448ph, context); + } + } + + private void basicSigTest() + throws Exception + { + Ed448PrivateKeyParameters privateKey = new Ed448PrivateKeyParameters( + Hex.decode( + "6c82a562cb808d10d632be89c8513ebf" + + "6c929f34ddfa8c9f63c9960ef6e348a3" + + "528c8a3fcc2f044e39a3fc5b94492f8f" + + "032e7549a20098f95b"), 0); + Ed448PublicKeyParameters publicKey = new Ed448PublicKeyParameters( + Hex.decode("5fd7449b59b461fd2ce787ec616ad46a" + + "1da1342485a70e1f8a0ea75d80e96778" + + "edf124769b46c7061bd6783df1e50f6c" + + "d1fa1abeafe8256180"), 0); + + byte[] sig = Hex.decode("533a37f6bbe457251f023c0d88f976ae" + + "2dfb504a843e34d2074fd823d41a591f" + + "2b233f034f628281f2fd7a22ddd47d78" + + "28c59bd0a21bfd3980ff0d2028d4b18a" + + "9df63e006c5d1c2d345b925d8dc00b41" + + "04852db99ac5c7cdda8530a113a0f4db" + + "b61149f05a7363268c71d95808ff2e65" + + "2600"); + + Signer signer = new Ed448Signer(new byte[0]); + + signer.init(true, privateKey); + + areEqual(sig, signer.generateSignature()); + + signer.init(false, publicKey); + + isTrue(signer.verifySignature(sig)); + } + + private Signer createSigner(int algorithm, byte[] context) + { + switch (algorithm) + { + case Ed448.Algorithm.Ed448: + return new Ed448Signer(context); + case Ed448.Algorithm.Ed448ph: + return new Ed448phSigner(context); + default: + throw new IllegalArgumentException("algorithm"); + } + } + + private byte[] randomContext(int length) + { + byte[] context = new byte[length]; + RANDOM.nextBytes(context); + return context; + } + + private void testConsistency(int algorithm, byte[] context) throws Exception + { + Ed448KeyPairGenerator kpg = new Ed448KeyPairGenerator(); + kpg.init(new Ed448KeyGenerationParameters(RANDOM)); + + AsymmetricCipherKeyPair kp = kpg.generateKeyPair(); + Ed448PrivateKeyParameters privateKey = (Ed448PrivateKeyParameters)kp.getPrivate(); + Ed448PublicKeyParameters publicKey = (Ed448PublicKeyParameters)kp.getPublic(); + + byte[] msg = new byte[RANDOM.nextInt() & 255]; + RANDOM.nextBytes(msg); + + Signer signer = createSigner(algorithm, context); + signer.init(true, privateKey); + signer.update(msg, 0, msg.length); + byte[] signature = signer.generateSignature(); + + Signer verifier = createSigner(algorithm, context); + + { + verifier.init(false, publicKey); + verifier.update(msg, 0, msg.length); + boolean shouldVerify = verifier.verifySignature(signature); + + if (!shouldVerify) + { + fail("Ed448(" + algorithm + ") signature failed to verify"); + } + } + + { + byte[] wrongLengthSignature = Arrays.append(signature, (byte)0x00); + + verifier.init(false, publicKey); + verifier.update(msg, 0, msg.length); + boolean shouldNotVerify = verifier.verifySignature(wrongLengthSignature); + + if (shouldNotVerify) + { + fail("Ed448(" + algorithm + ") wrong length signature incorrectly verified"); + } + } + + { + byte[] badSignature = Arrays.clone(signature); + badSignature[(RANDOM.nextInt() >>> 1) % badSignature.length] ^= 1 << (RANDOM.nextInt() & 7); + + verifier.init(false, publicKey); + verifier.update(msg, 0, msg.length); + boolean shouldNotVerify = verifier.verifySignature(badSignature); + + if (shouldNotVerify) + { + fail("Ed448(" + algorithm + ") bad signature incorrectly verified"); + } + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ElGamalTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ElGamalTest.java new file mode 100644 index 000000000..226bac5cc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ElGamalTest.java @@ -0,0 +1,285 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.engines.ElGamalEngine; +import com.fr.third.org.bouncycastle.crypto.generators.ElGamalKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.ElGamalParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ElGamalKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ElGamalParameters; +import com.fr.third.org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ElGamalPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ElGamalTest + extends SimpleTest +{ + private BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + private BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + private BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16); + private BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16); + + private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16); + private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16); + + private BigInteger yPgpBogusPSamp = new BigInteger("de4688497cc05b45fe8559bc9918c45afcad69b74123a7236eba409fd9de8ea34c7869839ee9df35e3d97576145d089841aa65b5b4e061fae52c37e430354269a02496b8ed8456f2d0d7c9b0db985fbcb21ae9f78507ed6e3a29db595b201b1a4f931c7d791eede65ccf918e8a61cf146859151c78c41ad48853694623467d78", 16); + private BigInteger xPgpBogusPSamp = new BigInteger("cbaf780f2cfe4f987bbc5fcb0738bbd7912060ccfdf37cbfeea65c0fd857e74a8df6cc359375f28cf5725d081813c614410a78cbe4b06d677beea9ff0fa10b1dbc47a6ed8c5b8466d6a95d6574029dbdf72596392e1b6b230faf9916dc8455821c10527a375a4d1c8a54947d1fe714d321aca25ad486b4b456506999fd2fd11a", 16); + private BigInteger gPgpBogusPSamp = new BigInteger("153ffe9522076d1cbd6e75f0816a0fc2ebd8b0e0091406587387a1763022088a03b411eed07ff50efb82b21f1608c352d10f63ba7e7e981a2f3387cec8af2915953d00493857663ae8919f517fe90f1d2abe7af4305a344b10d1a25d75f65902cd7fd775853d3ac43d7c5253ad666e1e63ee98cdcb10af81273d4ff053ff07d51", 16); + private BigInteger pPgpBogusPSamp = new BigInteger("15061b26cdab4e865098a01c86f13b03220104c5443e950658b36b85245aa0c616a0c0d8d99c454bea087c172315e45b3bc9b925443948a2b6ba47608a6035b9a79a4ef34a78d7274a12ede8364f02d5030db864988643d7e92753df603bd69fbd2682ab0af64d1a866d1131a2cb13333cedb0a9e6eefddd9fff8154d34c2daab", 16); + private int lPgpBogusPSamp = 0; + + public String getName() + { + return "ElGamal"; + } + + private void testEnc( + int size, + int privateValueSize, + BigInteger g, + BigInteger p) + { + ElGamalParameters dhParams = new ElGamalParameters(p, g, privateValueSize); + ElGamalKeyGenerationParameters params = new ElGamalKeyGenerationParameters(new SecureRandom(), dhParams); + ElGamalKeyPairGenerator kpGen = new ElGamalKeyPairGenerator(); + + kpGen.init(params); + + // + // generate pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + ElGamalPublicKeyParameters pu = (ElGamalPublicKeyParameters)pair.getPublic(); + ElGamalPrivateKeyParameters pv = (ElGamalPrivateKeyParameters)pair.getPrivate(); + + checkKeySize(privateValueSize, pv); + + ElGamalEngine e = new ElGamalEngine(); + + e.init(true, pu); + + if (e.getOutputBlockSize() != size / 4) + { + fail(size + " getOutputBlockSize() on encryption failed."); + } + + byte[] message = Hex.decode("5468697320697320612074657374"); + + byte[] pText = message; + byte[] cText = e.processBlock(pText, 0, pText.length); + + e.init(false, pv); + + if (e.getOutputBlockSize() != (size / 8) - 1) + { + fail(size + " getOutputBlockSize() on decryption failed."); + } + + pText = e.processBlock(cText, 0, cText.length); + + if (!Arrays.areEqual(message, pText)) + { + fail(size + " bit test failed"); + } + + e.init(true, pu); + + byte[] bytes = new byte[e.getInputBlockSize() + 2]; + + try + { + e.processBlock(bytes, 0, bytes.length); + + fail("out of range block not detected"); + } + catch (DataLengthException ex) + { + // expected + } + + try + { + bytes[0] = (byte)0xff; + + e.processBlock(bytes, 0, bytes.length - 1); + + fail("out of range block not detected"); + } + catch (DataLengthException ex) + { + // expected + } + + try + { + bytes[0] = (byte)0x7f; + + e.processBlock(bytes, 0, bytes.length - 1); + } + catch (DataLengthException ex) + { + fail("in range block failed"); + } + + try + { + bytes = BigIntegers.asUnsignedByteArray(p); + + e.processBlock(bytes, 0, bytes.length); + + fail("out of range block not detected"); + } + catch (DataLengthException ex) + { + // expected + } + + try + { + bytes = BigIntegers.asUnsignedByteArray(p.subtract(BigInteger.valueOf(1))); + + e.processBlock(bytes, 0, bytes.length); + } + catch (DataLengthException ex) + { + fail("boundary block rejected"); + } + } + + private void checkKeySize( + int privateValueSize, + ElGamalPrivateKeyParameters priv) + { + if (privateValueSize != 0) + { + if (priv.getX().bitLength() != privateValueSize) + { + fail("limited key check failed for key size " + privateValueSize); + } + } + } + + /** + * this test is can take quiet a while + * + * @param size size of key in bits. + */ + private void testGeneration( + int size) + { + ElGamalParametersGenerator pGen = new ElGamalParametersGenerator(); + + pGen.init(size, 10, new SecureRandom()); + + ElGamalParameters elParams = pGen.generateParameters(); + + if (elParams.getL() != 0) + { + fail("ElGamalParametersGenerator failed to set L to 0 in generated ElGamalParameters"); + } + + ElGamalKeyGenerationParameters params = new ElGamalKeyGenerationParameters(new SecureRandom(), elParams); + + ElGamalKeyPairGenerator kpGen = new ElGamalKeyPairGenerator(); + + kpGen.init(params); + + // + // generate first pair + // + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + + ElGamalPublicKeyParameters pu = (ElGamalPublicKeyParameters)pair.getPublic(); + ElGamalPrivateKeyParameters pv = (ElGamalPrivateKeyParameters)pair.getPrivate(); + + ElGamalEngine e = new ElGamalEngine(); + + e.init(true, new ParametersWithRandom(pu, new SecureRandom())); + + byte[] message = Hex.decode("5468697320697320612074657374"); + + byte[] pText = message; + byte[] cText = e.processBlock(pText, 0, pText.length); + + e.init(false, pv); + + pText = e.processBlock(cText, 0, cText.length); + + if (!Arrays.areEqual(message, pText)) + { + fail("generation test failed"); + } + } + + private void testInitCheck() + { + try + { + new ElGamalEngine().processBlock(new byte[]{ 1 }, 0, 1); + fail("failed initialisation check"); + } + catch (IllegalStateException e) + { + // expected + } + } + + private void testInvalidP() + { + ElGamalParameters dhParams = new ElGamalParameters(pPgpBogusPSamp, gPgpBogusPSamp, lPgpBogusPSamp); + ElGamalPublicKeyParameters pu = new ElGamalPublicKeyParameters(yPgpBogusPSamp, dhParams); + ElGamalPrivateKeyParameters pv = new ElGamalPrivateKeyParameters(xPgpBogusPSamp, dhParams); + + ElGamalEngine e = new ElGamalEngine(); + + e.init(true, pu); + + byte[] message = Hex.decode("5468697320697320612074657374"); + + byte[] pText = message; + byte[] cText = e.processBlock(pText, 0, pText.length); + + e.init(false, pv); + + pText = e.processBlock(cText, 0, cText.length); + + if (Arrays.areEqual(message, pText)) + { + fail("invalid test failed"); + } + } + + public void performTest() + { + testInvalidP(); + + testEnc(512, 0, g512, p512); + testEnc(768, 0, g768, p768); + testEnc(1024, 0, g1024, p1024); + + testEnc(512, 64, g512, p512); + testEnc(768, 128, g768, p768); + + // + // generation test. + // + testGeneration(258); + + testInitCheck(); + } + + public static void main( + String[] args) + { + runTest(new ElGamalTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/EqualsHashCodeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/EqualsHashCodeTest.java new file mode 100644 index 000000000..fb49f5446 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/EqualsHashCodeTest.java @@ -0,0 +1,261 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.generators.DHKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.ElGamalKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.DHKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHValidationParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAValidationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ElGamalKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ElGamalKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ElGamalParameters; +import com.fr.third.org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ElGamalPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.GOST3410Parameters; +import com.fr.third.org.bouncycastle.crypto.params.GOST3410ValidationParameters; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +import java.math.BigInteger; +import java.security.SecureRandom; + +class DHTestKeyParameters + extends DHKeyParameters +{ + protected DHTestKeyParameters(boolean isPrivate, DHParameters params) + { + super(isPrivate, params); + } +} + +class ElGamalTestKeyParameters + extends ElGamalKeyParameters +{ + protected ElGamalTestKeyParameters(boolean isPrivate, ElGamalParameters params) + { + super(isPrivate, params); + } +} + +public class EqualsHashCodeTest + extends SimpleTest +{ + private static Object OTHER = new Object(); + + public String getName() + { + return "EqualsHashCode"; + } + + private void doTest(Object a, Object equalsA, Object notEqualsA) + { + if (a.equals(null)) + { + fail("a equaled null"); + } + + if (!a.equals(equalsA) || !equalsA.equals(a)) + { + fail("equality failed"); + } + + if (a.equals(OTHER)) + { + fail("other inequality failed"); + } + + if (a.equals(notEqualsA) || notEqualsA.equals(a)) + { + fail("inequality failed"); + } + + if (a.hashCode() != equalsA.hashCode()) + { + fail("hashCode equality failed"); + } + } + + private void dhTest() + { + BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + DHParameters dhParams = new DHParameters(p512, g512); + DHKeyGenerationParameters params = new DHKeyGenerationParameters(new SecureRandom(), dhParams); DHKeyPairGenerator kpGen = new DHKeyPairGenerator(); + + kpGen.init(params); + + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + DHPublicKeyParameters pu1 = (DHPublicKeyParameters)pair.getPublic(); + DHPrivateKeyParameters pv1 = (DHPrivateKeyParameters)pair.getPrivate(); + + DHPublicKeyParameters pu2 = new DHPublicKeyParameters(pu1.getY(), pu1.getParameters()); + DHPrivateKeyParameters pv2 = new DHPrivateKeyParameters(pv1.getX(), pv1.getParameters()); + DHPublicKeyParameters pu3 = new DHPublicKeyParameters(pv1.getX(), pu1.getParameters()); + DHPrivateKeyParameters pv3 = new DHPrivateKeyParameters(pu1.getY(), pu1.getParameters()); + + doTest(pu1, pu2, pu3); + doTest(pv1, pv2, pv3); + + DHParameters pr1 = pu1.getParameters(); + DHParameters pr2 = new DHParameters(pr1.getP(), pr1.getG(), pr1.getQ(), pr1.getM(), pr1.getL(), pr1.getJ(), pr1.getValidationParameters()); + DHParameters pr3 = new DHParameters(pr1.getG(), pr1.getP(), pr1.getQ(), pr1.getM(), pr1.getL(), pr1.getJ(), pr1.getValidationParameters()); + + doTest(pr1, pr2, pr3); + + pr3 = new DHParameters(pr1.getG(), pr1.getP(), null, pr1.getM(), pr1.getL(), pr1.getJ(), pr1.getValidationParameters()); + + doTest(pr1, pr2, pr3); + + pu2 = new DHPublicKeyParameters(pu1.getY(), pr2); + pv2 = new DHPrivateKeyParameters(pv1.getX(), pr2); + + doTest(pu1, pu2, pu3); + doTest(pv1, pv2, pv3); + + DHValidationParameters vp1 = new DHValidationParameters(new byte[20], 1024); + DHValidationParameters vp2 = new DHValidationParameters(new byte[20], 1024); + DHValidationParameters vp3 = new DHValidationParameters(new byte[24], 1024); + + doTest(vp1, vp1, vp3); + doTest(vp1, vp2, vp3); + + byte[] bytes = new byte[20]; + bytes[0] = 1; + + vp3 = new DHValidationParameters(bytes, 1024); + + doTest(vp1, vp2, vp3); + + vp3 = new DHValidationParameters(new byte[20], 2048); + + doTest(vp1, vp2, vp3); + + DHTestKeyParameters k1 = new DHTestKeyParameters(false, null); + DHTestKeyParameters k2 = new DHTestKeyParameters(false, null); + DHTestKeyParameters k3 = new DHTestKeyParameters(false, pu1.getParameters()); + + doTest(k1, k2, k3); + } + + private void elGamalTest() + { + BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + ElGamalParameters dhParams = new ElGamalParameters(p512, g512); + ElGamalKeyGenerationParameters params = new ElGamalKeyGenerationParameters(new SecureRandom(), dhParams); ElGamalKeyPairGenerator kpGen = new ElGamalKeyPairGenerator(); + + kpGen.init(params); + + AsymmetricCipherKeyPair pair = kpGen.generateKeyPair(); + ElGamalPublicKeyParameters pu1 = (ElGamalPublicKeyParameters)pair.getPublic(); + ElGamalPrivateKeyParameters pv1 = (ElGamalPrivateKeyParameters)pair.getPrivate(); + + ElGamalPublicKeyParameters pu2 = new ElGamalPublicKeyParameters(pu1.getY(), pu1.getParameters()); + ElGamalPrivateKeyParameters pv2 = new ElGamalPrivateKeyParameters(pv1.getX(), pv1.getParameters()); + ElGamalPublicKeyParameters pu3 = new ElGamalPublicKeyParameters(pv1.getX(), pu1.getParameters()); + ElGamalPrivateKeyParameters pv3 = new ElGamalPrivateKeyParameters(pu1.getY(), pu1.getParameters()); + + doTest(pu1, pu2, pu3); + doTest(pv1, pv2, pv3); + + ElGamalParameters pr1 = pu1.getParameters(); + ElGamalParameters pr2 = new ElGamalParameters(pr1.getP(), pr1.getG()); + ElGamalParameters pr3 = new ElGamalParameters(pr1.getG(), pr1.getP()); + + doTest(pr1, pr2, pr3); + + pu2 = new ElGamalPublicKeyParameters(pu1.getY(), pr2); + pv2 = new ElGamalPrivateKeyParameters(pv1.getX(), pr2); + + doTest(pu1, pu2, pu3); + doTest(pv1, pv2, pv3); + + ElGamalTestKeyParameters k1 = new ElGamalTestKeyParameters(false, null); + ElGamalTestKeyParameters k2 = new ElGamalTestKeyParameters(false, null); + ElGamalTestKeyParameters k3 = new ElGamalTestKeyParameters(false, pu1.getParameters()); + + doTest(k1, k2, k3); + } + + private void dsaTest() + { + BigInteger a = BigInteger.valueOf(1), b = BigInteger.valueOf(2), c = BigInteger.valueOf(3); + + DSAParameters dsaP1 = new DSAParameters(a, b, c); + DSAParameters dsaP2 = new DSAParameters(a, b, c); + DSAParameters dsaP3 = new DSAParameters(b, c, a); + + doTest(dsaP1, dsaP2, dsaP3); + + DSAValidationParameters vp1 = new DSAValidationParameters(new byte[20], 1024); + DSAValidationParameters vp2 = new DSAValidationParameters(new byte[20], 1024); + DSAValidationParameters vp3 = new DSAValidationParameters(new byte[24], 1024); + + doTest(vp1, vp1, vp3); + doTest(vp1, vp2, vp3); + + byte[] bytes = new byte[20]; + bytes[0] = 1; + + vp3 = new DSAValidationParameters(bytes, 1024); + + doTest(vp1, vp2, vp3); + + vp3 = new DSAValidationParameters(new byte[20], 2048); + + doTest(vp1, vp2, vp3); + } + + private void gost3410Test() + { + BigInteger a = BigInteger.valueOf(1), b = BigInteger.valueOf(2), c = BigInteger.valueOf(3); + + GOST3410Parameters g1 = new GOST3410Parameters(a, b, c); + GOST3410Parameters g2 = new GOST3410Parameters(a, b, c); + GOST3410Parameters g3 = new GOST3410Parameters(a, c, c); + + doTest(g1, g2, g3); + + GOST3410ValidationParameters v1 = new GOST3410ValidationParameters(100, 1); + GOST3410ValidationParameters v2 = new GOST3410ValidationParameters(100, 1); + GOST3410ValidationParameters v3 = new GOST3410ValidationParameters(101, 1); + + doTest(v1, v2, v3); + + v3 = new GOST3410ValidationParameters(100, 2); + + doTest(v1, v2, v3); + + v1 = new GOST3410ValidationParameters(100L, 1L); + v2 = new GOST3410ValidationParameters(100L, 1L); + v3 = new GOST3410ValidationParameters(101L, 1L); + + doTest(v1, v2, v3); + + v3 = new GOST3410ValidationParameters(100L, 2L); + + doTest(v1, v2, v3); + + } + + public void performTest() + throws Exception + { + dhTest(); + elGamalTest(); + gost3410Test(); + dsaTest(); + } + + public static void main( + String[] args) + { + runTest(new EqualsHashCodeTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/EthereumIESTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/EthereumIESTest.java new file mode 100644 index 000000000..67e482691 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/EthereumIESTest.java @@ -0,0 +1,510 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.KeyEncoder; +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.agreement.ECDHBasicAgreement; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.engines.EthereumIESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.TwofishEngine; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.EphemeralKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.IESParameters; +import com.fr.third.org.bouncycastle.crypto.params.IESWithCipherParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.crypto.parsers.ECIESPublicKeyParser; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * test for Ethereum flavor of ECIES - Elliptic Curve Integrated Encryption Scheme + *

+ * Note the IV is always required when passing parameters, as the IV is added to the MAC. + */ +public class EthereumIESTest + extends SimpleTest +{ + private static byte[] TWOFISH_IV = Hex.decode("000102030405060708090a0b0c0d0e0f"); + + EthereumIESTest() + { + } + + public String getName() + { + return "EthereumIES"; + } + + private void doStaticTest(byte[] iv) + throws Exception + { + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + AsymmetricCipherKeyPair p1 = new AsymmetricCipherKeyPair(pubKey, priKey); + AsymmetricCipherKeyPair p2 = new AsymmetricCipherKeyPair(pubKey, priKey); + + byte[] commonMac = Hex.decode("0262b12d60690cdcf330baba03188da80eb03090f67cbf2043a18800f4ff0a0262b12d60690cdcf330bab6e69763b471f994dd2d16a5fd82ff1012b6e69763b4"); + + // + // stream test + // + EthereumIESEngine i1 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac); + EthereumIESEngine i2 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac); + byte[] d = new byte[]{1, 2, 3, 4, 5, 6, 7, 8}; + byte[] e = new byte[]{8, 7, 6, 5, 4, 3, 2, 1}; + CipherParameters p = new ParametersWithIV(new IESParameters(d, e, 64), new byte[32]); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + byte[] message = Hex.decode("1234567890abcdef"); + + byte[] out1 = i1.processBlock(message, 0, message.length); + + if (!areEqual(out1, Hex.decode("fb493cdaaa2938daaa2fbbf0886f3b9575c810db240eb9f4adb9089b"))) + { + fail("stream cipher test failed on enc"); + } + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // twofish with CBC + // + BufferedBlockCipher c1 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + BufferedBlockCipher c2 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + i1 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac, + c1); + i2 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac, + c2); + d = new byte[]{1, 2, 3, 4, 5, 6, 7, 8}; + e = new byte[]{8, 7, 6, 5, 4, 3, 2, 1}; + p = new IESWithCipherParameters(d, e, 64, 128); + + if (iv != null) + { + p = new ParametersWithIV(p, iv); + } + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + message = Hex.decode("1234567890abcdef"); + + out1 = i1.processBlock(message, 0, message.length); + + if (!areEqual(out1, (iv == null) ? + Hex.decode("b8a06ea5c2b9df28b58a0a90a734cde8c9c02903e5c220021fe4417410d1e53a32a71696") + : Hex.decode("34bb9676b087d0b3a016e70a93c4afcb507882a53c5ca7a770913e654ff1422c4b236cbf"))) + { + fail("twofish cipher test failed on enc"); + } + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("twofish cipher test failed"); + } + } + + private void doShortTest(byte[] iv) + throws Exception + { + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + AsymmetricCipherKeyPair p1 = new AsymmetricCipherKeyPair(pubKey, priKey); + AsymmetricCipherKeyPair p2 = new AsymmetricCipherKeyPair(pubKey, priKey); + + byte[] commonMac = Hex.decode("0262b12d60690cdcf330baba03188da80eb03090f67cbf2043a18800f4ff0a0262b12d60690cdcf330bab6e69763b471f994dd2d16a5fd82ff1012b6e69763b4"); + + // + // stream test - V 0 + // + EthereumIESEngine i1 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac); + EthereumIESEngine i2 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac); + byte[] d = new byte[]{1, 2, 3, 4, 5, 6, 7, 8}; + byte[] e = new byte[]{8, 7, 6, 5, 4, 3, 2, 1}; + CipherParameters p = new ParametersWithIV(new IESParameters(d, e, 64), new byte[32]); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + byte[] message = new byte[0]; + + byte[] out1 = i1.processBlock(message, 0, message.length); + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + try + { + i2.processBlock(out1, 0, out1.length - 1); + fail("no exception"); + } + catch (InvalidCipherTextException ex) + { + if (!"length of input must be greater than the MAC and V combined".equals(ex.getMessage())) + { + fail("wrong exception"); + } + } + + // with ephemeral key pair + + // Generate the ephemeral key pair + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + gen.init(new ECKeyGenerationParameters(params, new SecureRandom())); + + EphemeralKeyPairGenerator ephKeyGen = new EphemeralKeyPairGenerator(gen, new KeyEncoder() + { + public byte[] getEncoded(AsymmetricKeyParameter keyParameter) + { + return ((ECPublicKeyParameters)keyParameter).getQ().getEncoded(false); + } + }); + + i1.init(p2.getPublic(), p, ephKeyGen); + i2.init(p2.getPrivate(), p, new ECIESPublicKeyParser(params)); + + out1 = i1.processBlock(message, 0, message.length); + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("V cipher test failed"); + } + + try + { + i2.processBlock(out1, 0, out1.length - 1); + fail("no exception"); + } + catch (InvalidCipherTextException ex) + { + if (!"length of input must be greater than the MAC and V combined".equals(ex.getMessage())) + { + fail("wrong exception"); + } + } + } + + private void doEphemeralTest(byte[] iv, final boolean usePointCompression) + throws Exception + { + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECPrivateKeyParameters priKey = new ECPrivateKeyParameters( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + params); + + ECPublicKeyParameters pubKey = new ECPublicKeyParameters( + curve.decodePoint(Hex.decode("0262b12d60690cdcf330babab6e69763b471f994dd702d16a5")), // Q + params); + + AsymmetricCipherKeyPair p1 = new AsymmetricCipherKeyPair(pubKey, priKey); + AsymmetricCipherKeyPair p2 = new AsymmetricCipherKeyPair(pubKey, priKey); + + // Generate the ephemeral key pair + ECKeyPairGenerator gen = new ECKeyPairGenerator(); + gen.init(new ECKeyGenerationParameters(params, new SecureRandom())); + + EphemeralKeyPairGenerator ephKeyGen = new EphemeralKeyPairGenerator(gen, new KeyEncoder() + { + public byte[] getEncoded(AsymmetricKeyParameter keyParameter) + { + return ((ECPublicKeyParameters)keyParameter).getQ().getEncoded(usePointCompression); + } + }); + + byte[] commonMac = Hex.decode("0262b12d60690cdcf330baba03188da80eb03090f67cbf2043a18800f4ff0a0262b12d60690cdcf330bab6e69763b471f994dd2d16a5fd82ff1012b6e69763b4"); + + // + // stream test + // + EthereumIESEngine i1 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac); + EthereumIESEngine i2 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac); + + byte[] d = new byte[]{1, 2, 3, 4, 5, 6, 7, 8}; + byte[] e = new byte[]{8, 7, 6, 5, 4, 3, 2, 1}; + CipherParameters p = new ParametersWithIV(new IESParameters(d, e, 64), new byte[32]); + + i1.init(p2.getPublic(), p, ephKeyGen); + i2.init(p2.getPrivate(), p, new ECIESPublicKeyParser(params)); + + byte[] message = Hex.decode("1234567890abcdef"); + + byte[] out1 = i1.processBlock(message, 0, message.length); + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // twofish with CBC + // + BufferedBlockCipher c1 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + BufferedBlockCipher c2 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + i1 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac, + c1); + i2 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac, + c2); + d = new byte[]{1, 2, 3, 4, 5, 6, 7, 8}; + e = new byte[]{8, 7, 6, 5, 4, 3, 2, 1}; + p = new IESWithCipherParameters(d, e, 64, 128); + + if (iv != null) + { + p = new ParametersWithIV(p, iv); + } + + i1.init(p2.getPublic(), p, ephKeyGen); + i2.init(p2.getPrivate(), p, new ECIESPublicKeyParser(params)); + + message = Hex.decode("1234567890abcdef"); + + out1 = i1.processBlock(message, 0, message.length); + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("twofish cipher test failed"); + } + } + + private void doTest(AsymmetricCipherKeyPair p1, AsymmetricCipherKeyPair p2) + throws Exception + { + byte[] commonMac = Hex.decode("0262b12d60690cdcf330baba03188da80eb03090f67cbf2043a18800f4ff0a0262b12d60690cdcf330bab6e69763b471f994dd2d16a5fd82ff1012b6e69763b4"); + + // + // stream test + // + EthereumIESEngine i1 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac); + EthereumIESEngine i2 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac); + byte[] d = new byte[]{1, 2, 3, 4, 5, 6, 7, 8}; + byte[] e = new byte[]{8, 7, 6, 5, 4, 3, 2, 1}; + ParametersWithIV p = new ParametersWithIV(new IESParameters(d, e, 64), new byte[32]); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + byte[] message = Hex.decode("1234567890abcdef"); + + byte[] out1 = i1.processBlock(message, 0, message.length); + + byte[] out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // twofish with CBC + // + BufferedBlockCipher c1 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + BufferedBlockCipher c2 = new PaddedBufferedBlockCipher( + new CBCBlockCipher(new TwofishEngine())); + i1 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac, + c1); + i2 = new EthereumIESEngine( + new ECDHBasicAgreement(), + new EthereumIESEngine.HandshakeKDFFunction(1, new SHA1Digest()), + new HMac(new SHA1Digest()), + commonMac, + c2); + d = new byte[]{1, 2, 3, 4, 5, 6, 7, 8}; + e = new byte[]{8, 7, 6, 5, 4, 3, 2, 1}; + p = new ParametersWithIV(new IESWithCipherParameters(d, e, 64, 128), new byte[16]); + + i1.init(true, p1.getPrivate(), p2.getPublic(), p); + i2.init(false, p2.getPrivate(), p1.getPublic(), p); + + message = Hex.decode("1234567890abcdef"); + + out1 = i1.processBlock(message, 0, message.length); + + out2 = i2.processBlock(out1, 0, out1.length); + + if (!areEqual(out2, message)) + { + fail("twofish cipher test failed"); + } + } + + public void performTest() + throws Exception + { + doStaticTest(TWOFISH_IV); + doShortTest(null); + + BigInteger n = new BigInteger("6277101735386680763835789423176059013767194773182842284081"); + + ECCurve.Fp curve = new ECCurve.Fp( + new BigInteger("6277101735386680763835789423207666416083908700390324961279"), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16), // b + n, ECConstants.ONE); + + ECDomainParameters params = new ECDomainParameters( + curve, + curve.decodePoint(Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")), // G + n); + + ECKeyPairGenerator eGen = new ECKeyPairGenerator(); + KeyGenerationParameters gParam = new ECKeyGenerationParameters(params, new SecureRandom()); + + eGen.init(gParam); + + AsymmetricCipherKeyPair p1 = eGen.generateKeyPair(); + AsymmetricCipherKeyPair p2 = eGen.generateKeyPair(); + + doTest(p1, p2); + + doEphemeralTest(TWOFISH_IV, false); + doEphemeralTest(TWOFISH_IV, true); + } + + public static void main( + String[] args) + { + runTest(new EthereumIESTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GCMTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GCMTest.java new file mode 100644 index 000000000..5b7cf82e9 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GCMTest.java @@ -0,0 +1,725 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.modes.GCMBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.gcm.BasicGCMMultiplier; +import com.fr.third.org.bouncycastle.crypto.modes.gcm.GCMMultiplier; +import com.fr.third.org.bouncycastle.crypto.modes.gcm.Tables4kGCMMultiplier; +import com.fr.third.org.bouncycastle.crypto.modes.gcm.Tables64kGCMMultiplier; +import com.fr.third.org.bouncycastle.crypto.modes.gcm.Tables8kGCMMultiplier; +import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.Times; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test vectors from "The Galois/Counter Mode of Operation (GCM)", McGrew/Viega, Appendix B + */ +public class GCMTest + extends SimpleTest +{ + private static final String[][] TEST_VECTORS = new String[][] { + { + "Test Case 1", + "00000000000000000000000000000000", + "", + "", + "000000000000000000000000", + "", + "58e2fccefa7e3061367f1d57a4e7455a", + }, + { + "Test Case 2", + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "", + "000000000000000000000000", + "0388dace60b6a392f328c2b971b2fe78", + "ab6e47d42cec13bdf53a67b21257bddf", + }, + { + "Test Case 3", + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b391aafd255", + "", + "cafebabefacedbaddecaf888", + "42831ec2217774244b7221b784d0d49c" + + "e3aa212f2c02a4e035c17e2329aca12e" + + "21d514b25466931c7d8f6a5aac84aa05" + + "1ba30b396a0aac973d58e091473f5985", + "4d5c2af327cd64a62cf35abd2ba6fab4", + }, + { + "Test Case 4", + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbaddecaf888", + "42831ec2217774244b7221b784d0d49c" + + "e3aa212f2c02a4e035c17e2329aca12e" + + "21d514b25466931c7d8f6a5aac84aa05" + + "1ba30b396a0aac973d58e091", + "5bc94fbc3221a5db94fae95ae7121a47", + }, + { + "Test Case 5", + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbad", + "61353b4c2806934a777ff51fa22a4755" + + "699b2a714fcdc6f83766e5f97b6c7423" + + "73806900e49f24b22b097544d4896b42" + + "4989b5e1ebac0f07c23f4598", + "3612d2e79e3b0785561be14aaca2fccb", + }, + { + "Test Case 6", + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "9313225df88406e555909c5aff5269aa" + + "6a7a9538534f7da1e4c303d2a318a728" + + "c3c0c95156809539fcf0e2429a6b5254" + + "16aedbf5a0de6a57a637b39b", + "8ce24998625615b603a033aca13fb894" + + "be9112a5c3a211a8ba262a3cca7e2ca7" + + "01e4a9a4fba43c90ccdcb281d48c7c6f" + + "d62875d2aca417034c34aee5", + "619cc5aefffe0bfa462af43c1699d050", + }, + { + "Test Case 7", + "00000000000000000000000000000000" + + "0000000000000000", + "", + "", + "000000000000000000000000", + "", + "cd33b28ac773f74ba00ed1f312572435", + }, + { + "Test Case 8", + "00000000000000000000000000000000" + + "0000000000000000", + "00000000000000000000000000000000", + "", + "000000000000000000000000", + "98e7247c07f0fe411c267e4384b0f600", + "2ff58d80033927ab8ef4d4587514f0fb", + }, + { + "Test Case 9", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b391aafd255", + "", + "cafebabefacedbaddecaf888", + "3980ca0b3c00e841eb06fac4872a2757" + + "859e1ceaa6efd984628593b40ca1e19c" + + "7d773d00c144c525ac619d18c84a3f47" + + "18e2448b2fe324d9ccda2710acade256", + "9924a7c8587336bfb118024db8674a14", + }, + { + "Test Case 10", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbaddecaf888", + "3980ca0b3c00e841eb06fac4872a2757" + + "859e1ceaa6efd984628593b40ca1e19c" + + "7d773d00c144c525ac619d18c84a3f47" + + "18e2448b2fe324d9ccda2710", + "2519498e80f1478f37ba55bd6d27618c", + }, + { + "Test Case 11", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbad", + "0f10f599ae14a154ed24b36e25324db8" + + "c566632ef2bbb34f8347280fc4507057" + + "fddc29df9a471f75c66541d4d4dad1c9" + + "e93a19a58e8b473fa0f062f7", + "65dcc57fcf623a24094fcca40d3533f8", + }, + { + "Test Case 12", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "9313225df88406e555909c5aff5269aa" + + "6a7a9538534f7da1e4c303d2a318a728" + + "c3c0c95156809539fcf0e2429a6b5254" + + "16aedbf5a0de6a57a637b39b", + "d27e88681ce3243c4830165a8fdcf9ff" + + "1de9a1d8e6b447ef6ef7b79828666e45" + + "81e79012af34ddd9e2f037589b292db3" + + "e67c036745fa22e7e9b7373b", + "dcf566ff291c25bbb8568fc3d376a6d9", + }, + { + "Test Case 13", + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + "", + "", + "000000000000000000000000", + "", + "530f8afbc74536b9a963b4f1c4cb738b", + }, + { + "Test Case 14", + "00000000000000000000000000000000" + + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "", + "000000000000000000000000", + "cea7403d4d606b6e074ec5d3baf39d18", + "d0d1c8a799996bf0265b98b5d48ab919", + }, + { + "Test Case 15", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b391aafd255", + "", + "cafebabefacedbaddecaf888", + "522dc1f099567d07f47f37a32a84427d" + + "643a8cdcbfe5c0c97598a2bd2555d1aa" + + "8cb08e48590dbb3da7b08b1056828838" + + "c5f61e6393ba7a0abcc9f662898015ad", + "b094dac5d93471bdec1a502270e3cc6c", + }, + { + "Test Case 16", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbaddecaf888", + "522dc1f099567d07f47f37a32a84427d" + + "643a8cdcbfe5c0c97598a2bd2555d1aa" + + "8cb08e48590dbb3da7b08b1056828838" + + "c5f61e6393ba7a0abcc9f662", + "76fc6ece0f4e1768cddf8853bb2d551b", + }, + { + "Test Case 17", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "cafebabefacedbad", + "c3762df1ca787d32ae47c13bf19844cb" + + "af1ae14d0b976afac52ff7d79bba9de0" + + "feb582d33934a4f0954cc2363bc73f78" + + "62ac430e64abe499f47c9b1f", + "3a337dbf46a792c45e454913fe2ea8f2", + }, + { + "Test Case 18", + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308", + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b39", + "feedfacedeadbeeffeedfacedeadbeef" + + "abaddad2", + "9313225df88406e555909c5aff5269aa" + + "6a7a9538534f7da1e4c303d2a318a728" + + "c3c0c95156809539fcf0e2429a6b5254" + + "16aedbf5a0de6a57a637b39b", + "5a8def2f0c9e53f1f75d7853659e2a20" + + "eeb2b22aafde6419a058ab4f6f746bf4" + + "0fc0c3b780f244452da3ebf1c5d82cde" + + "a2418997200ef82e44ae7e3f", + "a44a8266ee1c8eb0c8b5d4cf5ae9f19a", + }, + }; + + public String getName() + { + return "GCM"; + } + + public void performTest() throws Exception + { + for (int i = 0; i < TEST_VECTORS.length; ++i) + { + runTestCase(TEST_VECTORS[i]); + } + + randomTests(); + outputSizeTests(); + testExceptions(); + } + + protected BlockCipher createAESEngine() + { + return new AESEngine(); + } + + private void testExceptions() throws InvalidCipherTextException + { + GCMBlockCipher gcm = new GCMBlockCipher(createAESEngine()); + + try + { + gcm = new GCMBlockCipher(new DESEngine()); + + fail("incorrect block size not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + gcm.init(false, new KeyParameter(new byte[16])); + + fail("illegal argument not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + AEADTestUtil.testTampering(this, gcm, new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16])); + + byte[] P = Strings.toByteArray("Hello world!"); + byte[] buf = new byte[100]; + + GCMBlockCipher c = new GCMBlockCipher(createAESEngine()); + AEADParameters aeadParameters = new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[16]); + c.init(true, aeadParameters); + + c.processBytes(P, 0, P.length, buf, 0); + + c.doFinal(buf, 0); + + try + { + c.doFinal(buf, 0); + fail("no exception on reuse"); + } + catch (IllegalStateException e) + { + isTrue("wrong message", e.getMessage().equals("GCM cipher cannot be reused for encryption")); + } + + try + { + c.init(true, aeadParameters); + fail("no exception on reuse"); + } + catch (IllegalArgumentException e) + { + isTrue("wrong message", e.getMessage().equals("cannot reuse nonce for GCM encryption")); + } + } + + private void runTestCase(String[] testVector) + throws InvalidCipherTextException + { + for (int macLength = 12; macLength <= 16; ++macLength) + { + runTestCase(testVector, macLength); + } + } + + private void runTestCase(String[] testVector, int macLength) + throws InvalidCipherTextException + { + int pos = 0; + String testName = testVector[pos++]; + byte[] K = Hex.decode(testVector[pos++]); + byte[] P = Hex.decode(testVector[pos++]); + byte[] A = Hex.decode(testVector[pos++]); + byte[] IV = Hex.decode(testVector[pos++]); + byte[] C = Hex.decode(testVector[pos++]); + + // For short MAC, take leading bytes + byte[] t = Hex.decode(testVector[pos++]); + byte[] T = new byte[macLength]; + System.arraycopy(t, 0, T, 0, T.length); + + // Default multiplier + runTestCase(null, null, testName, K, IV, A, P, C, T); + + runTestCase(new BasicGCMMultiplier(), new BasicGCMMultiplier(), testName, K, IV, A, P, C, T); + runTestCase(new Tables4kGCMMultiplier(), new Tables4kGCMMultiplier(), testName, K, IV, A, P, C, T); + runTestCase(new Tables8kGCMMultiplier(), new Tables8kGCMMultiplier(), testName, K, IV, A, P, C, T); + runTestCase(new Tables64kGCMMultiplier(), new Tables64kGCMMultiplier(), testName, K, IV, A, P, C, T); + } + + private void runTestCase( + GCMMultiplier encM, + GCMMultiplier decM, + String testName, + byte[] K, + byte[] IV, + byte[] A, + byte[] P, + byte[] C, + byte[] T) + throws InvalidCipherTextException + { + byte[] fa = new byte[A.length / 2]; + byte[] la = new byte[A.length - (A.length / 2)]; + System.arraycopy(A, 0, fa, 0, fa.length); + System.arraycopy(A, fa.length, la, 0, la.length); + + runTestCase(encM, decM, testName + " all initial associated data", K, IV, A, null, P, C, T); + runTestCase(encM, decM, testName + " all subsequent associated data", K, IV, null, A, P, C, T); + runTestCase(encM, decM, testName + " split associated data", K, IV, fa, la, P, C, T); + } + + private void runTestCase( + GCMMultiplier encM, + GCMMultiplier decM, + String testName, + byte[] K, + byte[] IV, + byte[] A, + byte[] SA, + byte[] P, + byte[] C, + byte[] T) + throws InvalidCipherTextException + { + AEADParameters parameters = new AEADParameters(new KeyParameter(K), T.length * 8, IV, A); + GCMBlockCipher encCipher = initCipher(encM, true, parameters); + GCMBlockCipher decCipher = initCipher(decM, false, parameters); + checkTestCase(encCipher, decCipher, testName, SA, P, C, T); + encCipher = initCipher(encM, true, parameters); + checkTestCase(encCipher, decCipher, testName + " (reused)", SA, P, C, T); + + // Key reuse + AEADParameters keyReuseParams = AEADTestUtil.reuseKey(parameters); + + try + { + encCipher.init(true, keyReuseParams); + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isTrue("wrong message", "cannot reuse nonce for GCM encryption".equals(e.getMessage())); + } + } + + private GCMBlockCipher initCipher(GCMMultiplier m, boolean forEncryption, AEADParameters parameters) + { + GCMBlockCipher c = new GCMBlockCipher(createAESEngine(), m); + c.init(forEncryption, parameters); + return c; + } + + private void checkTestCase( + GCMBlockCipher encCipher, + GCMBlockCipher decCipher, + String testName, + byte[] SA, + byte[] P, + byte[] C, + byte[] T) + throws InvalidCipherTextException + { + byte[] enc = new byte[encCipher.getOutputSize(P.length)]; + if (SA != null) + { + encCipher.processAADBytes(SA, 0, SA.length); + } + int len = encCipher.processBytes(P, 0, P.length, enc, 0); + len += encCipher.doFinal(enc, len); + + if (enc.length != len) + { +// System.out.println("" + enc.length + "/" + len); + fail("encryption reported incorrect length: " + testName); + } + + byte[] mac = encCipher.getMac(); + + byte[] data = new byte[P.length]; + System.arraycopy(enc, 0, data, 0, data.length); + byte[] tail = new byte[enc.length - P.length]; + System.arraycopy(enc, P.length, tail, 0, tail.length); + + if (!areEqual(C, data)) + { + fail("incorrect encrypt in: " + testName); + } + + if (!areEqual(T, mac)) + { + fail("getMac() returned wrong mac in: " + testName); + } + + if (!areEqual(T, tail)) + { + fail("stream contained wrong mac in: " + testName); + } + + byte[] dec = new byte[decCipher.getOutputSize(enc.length)]; + if (SA != null) + { + decCipher.processAADBytes(SA, 0, SA.length); + } + len = decCipher.processBytes(enc, 0, enc.length, dec, 0); + len += decCipher.doFinal(dec, len); + mac = decCipher.getMac(); + + data = new byte[C.length]; + System.arraycopy(dec, 0, data, 0, data.length); + + if (!areEqual(P, data)) + { + fail("incorrect decrypt in: " + testName); + } + } + + private void randomTests() + throws InvalidCipherTextException + { + SecureRandom srng = new SecureRandom(); + srng.setSeed(Times.nanoTime()); + randomTests(srng, null); + randomTests(srng, new BasicGCMMultiplier()); + randomTests(srng, new Tables4kGCMMultiplier()); + randomTests(srng, new Tables8kGCMMultiplier()); + randomTests(srng, new Tables64kGCMMultiplier()); + } + + private void randomTests(SecureRandom srng, GCMMultiplier m) + throws InvalidCipherTextException + { + for (int i = 0; i < 10; ++i) + { + randomTest(srng, m); + } + } + + private void randomTest(SecureRandom srng, GCMMultiplier m) + throws InvalidCipherTextException + { + int kLength = 16 + 8 * (Math.abs(srng.nextInt()) % 3); + byte[] K = new byte[kLength]; + srng.nextBytes(K); + + int pLength = srng.nextInt() >>> 16; + byte[] P = new byte[pLength]; + srng.nextBytes(P); + + int aLength = srng.nextInt() >>> 24; + byte[] A = new byte[aLength]; + srng.nextBytes(A); + + int saLength = srng.nextInt() >>> 24; + byte[] SA = new byte[saLength]; + srng.nextBytes(SA); + + int ivLength = 1 + (srng.nextInt() >>> 24); + byte[] IV = new byte[ivLength]; + srng.nextBytes(IV); + + AEADParameters parameters = new AEADParameters(new KeyParameter(K), 16 * 8, IV, A); + GCMBlockCipher cipher = initCipher(m, true, parameters); + byte[] C = new byte[cipher.getOutputSize(P.length)]; + int predicted = cipher.getUpdateOutputSize(P.length); + + int split = nextInt(srng, SA.length + 1); + cipher.processAADBytes(SA, 0, split); + int len = cipher.processBytes(P, 0, P.length, C, 0); + cipher.processAADBytes(SA, split, SA.length - split); + + if (predicted != len) + { + fail("encryption reported incorrect update length in randomised test"); + } + + len += cipher.doFinal(C, len); + + if (C.length != len) + { + fail("encryption reported incorrect length in randomised test"); + } + + byte[] encT = cipher.getMac(); + byte[] tail = new byte[C.length - P.length]; + System.arraycopy(C, P.length, tail, 0, tail.length); + + if (!areEqual(encT, tail)) + { + fail("stream contained wrong mac in randomised test"); + } + + cipher.init(false, parameters); + byte[] decP = new byte[cipher.getOutputSize(C.length)]; + predicted = cipher.getUpdateOutputSize(C.length); + + split = nextInt(srng, SA.length + 1); + cipher.processAADBytes(SA, 0, split); + len = cipher.processBytes(C, 0, C.length, decP, 0); + cipher.processAADBytes(SA, split, SA.length - split); + + if (predicted != len) + { + fail("decryption reported incorrect update length in randomised test"); + } + + len += cipher.doFinal(decP, len); + + if (!areEqual(P, decP)) + { + fail("incorrect decrypt in randomised test"); + } + + byte[] decT = cipher.getMac(); + if (!areEqual(encT, decT)) + { + fail("decryption produced different mac from encryption"); + } + + // + // key reuse test + // + cipher.init(false, AEADTestUtil.reuseKey(parameters)); + decP = new byte[cipher.getOutputSize(C.length)]; + + split = nextInt(srng, SA.length + 1); + cipher.processAADBytes(SA, 0, split); + len = cipher.processBytes(C, 0, C.length, decP, 0); + cipher.processAADBytes(SA, split, SA.length - split); + + len += cipher.doFinal(decP, len); + + if (!areEqual(P, decP)) + { + fail("incorrect decrypt in randomised test"); + } + + decT = cipher.getMac(); + if (!areEqual(encT, decT)) + { + fail("decryption produced different mac from encryption"); + } + } + + private void outputSizeTests() + { + byte[] K = new byte[16]; + byte[] A = null; + byte[] IV = new byte[16]; + + AEADParameters parameters = new AEADParameters(new KeyParameter(K), 16 * 8, IV, A); + GCMBlockCipher cipher = initCipher(null, true, parameters); + + if (cipher.getUpdateOutputSize(0) != 0) + { + fail("incorrect getUpdateOutputSize for initial 0 bytes encryption"); + } + + if (cipher.getOutputSize(0) != 16) + { + fail("incorrect getOutputSize for initial 0 bytes encryption"); + } + + cipher.init(false, parameters); + + if (cipher.getUpdateOutputSize(0) != 0) + { + fail("incorrect getUpdateOutputSize for initial 0 bytes decryption"); + } + + // NOTE: 0 bytes would be truncated data, but we want it to fail in the doFinal, not here + if (cipher.getOutputSize(0) != 0) + { + fail("fragile getOutputSize for initial 0 bytes decryption"); + } + + if (cipher.getOutputSize(16) != 0) + { + fail("incorrect getOutputSize for initial MAC-size bytes decryption"); + } + } + + private static int nextInt(SecureRandom rand, int n) + { + if ((n & -n) == n) // i.e., n is a power of 2 + { + return (int)((n * (long)(rand.nextInt() >>> 1)) >> 31); + } + + int bits, value; + do + { + bits = rand.nextInt() >>> 1; + value = bits % n; + } + while (bits - value + (n - 1) < 0); + + return value; + } + + public static void main(String[] args) + { + runTest(new GCMTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GMacTest.java new file mode 100644 index 000000000..58f1ccd0e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GMacTest.java @@ -0,0 +1,177 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.macs.GMac; +import com.fr.third.org.bouncycastle.crypto.modes.GCMBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test vectors for AES-GMAC, extracted from NIST CAVP GCM test + * vectors. + * + */ +public class GMacTest extends SimpleTest +{ + private static class TestCase + { + private byte[] key; + private byte[] iv; + private byte[] ad; + private byte[] tag; + private String name; + + private TestCase(final String name, final String key, final String iv, final String ad, final String tag) + { + this.name = name; + this.key = Hex.decode(key); + this.iv = Hex.decode(iv); + this.ad = Hex.decode(ad); + this.tag = Hex.decode(tag); + } + + public String getName() + { + return name; + } + + public byte[] getKey() + { + return key; + } + + public byte[] getIv() + { + return iv; + } + + public byte[] getAd() + { + return ad; + } + + public byte[] getTag() + { + return tag; + } + } + + private static TestCase[] TEST_VECTORS = new TestCase[] { + // Count = 0, from each of the PTlen = 0 test vector sequences + new TestCase("128/96/0/128", "11754cd72aec309bf52f7687212e8957", "3c819d9a9bed087615030b65", "", + "250327c674aaf477aef2675748cf6971"), + new TestCase("128/96/0/120", "272f16edb81a7abbea887357a58c1917", "794ec588176c703d3d2a7a07", "", + "b6e6f197168f5049aeda32dafbdaeb"), + new TestCase("128/96/0/112", "81b6844aab6a568c4556a2eb7eae752f", "ce600f59618315a6829bef4d", "", + "89b43e9dbc1b4f597dbbc7655bb5"), + new TestCase("128/96/0/104", "cde2f9a9b1a004165ef9dc981f18651b", "29512c29566c7322e1e33e8e", "", + "2e58ce7dabd107c82759c66a75"), + new TestCase("128/96/0/96", "b01e45cc3088aaba9fa43d81d481823f", "5a2c4a66468713456a4bd5e1", "", + "014280f944f53c681164b2ff"), + + new TestCase("128/96/128/128", "77be63708971c4e240d1cb79e8d77feb", "e0e00f19fed7ba0136a797f3", + "7a43ec1d9c0a5a78a0b16533a6213cab", "209fcc8d3675ed938e9c7166709dd946"), + new TestCase("128/96/128/96", "bea48ae4980d27f357611014d4486625", "32bddb5c3aa998a08556454c", + "8a50b0b8c7654bced884f7f3afda2ead", "8e0f6d8bf05ffebe6f500eb1"), + + new TestCase("128/96/384/128", "99e3e8793e686e571d8285c564f75e2b", "c2dd0ab868da6aa8ad9c0d23", + "b668e42d4e444ca8b23cfdd95a9fedd5178aa521144890b093733cf5cf22526c5917ee476541809ac6867a8c399309fc", + "3f4fba100eaf1f34b0baadaae9995d85"), + new TestCase("128/96/384/96", "c77acd1b0918e87053cb3e51651e7013", "39ff857a81745d10f718ac00", + "407992f82ea23b56875d9a3cb843ceb83fd27cb954f7c5534d58539fe96fb534502a1b38ea4fac134db0a42de4be1137", + "2a5dc173285375dc82835876"), + + new TestCase( + "128/1024/0/128", + "d0f1f4defa1e8c08b4b26d576392027c", + "42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac", + "", "7ab49b57ddf5f62c427950111c5c4f0d"), + new TestCase( + "128/1024/384/96", + "3cce72d37933394a8cac8a82deada8f0", + "aa2f0d676d705d9733c434e481972d4888129cf7ea55c66511b9c0d25a92a174b1e28aa072f27d4de82302828955aadcb817c4907361869bd657b45ff4a6f323871987fcf9413b0702d46667380cd493ed24331a28b9ce5bbfa82d3a6e7679fcce81254ba64abcad14fd18b22c560a9d2c1cd1d3c42dac44c683edf92aced894", + "5686b458e9c176f4de8428d9ebd8e12f569d1c7595cf49a4b0654ab194409f86c0dd3fdb8eb18033bb4338c70f0b97d1", + "a3a9444b21f330c3df64c8b6"), }; + + public void performTest() + { + for (int i = 0; i < TEST_VECTORS.length; i++) + { + TestCase testCase = TEST_VECTORS[i]; + + Mac mac = new GMac(new GCMBlockCipher(new AESEngine()), testCase.getTag().length * 8); + CipherParameters key = new KeyParameter(testCase.getKey()); + mac.init(new ParametersWithIV(key, testCase.getIv())); + + testSingleByte(mac, testCase); + + mac = new GMac(new GCMBlockCipher(new AESEngine()), testCase.getTag().length * 8); + mac.init(new ParametersWithIV(key, testCase.getIv())); + testMultibyte(mac, testCase); + } + + // Invalid mac size + testInvalidMacSize(97); + testInvalidMacSize(136); + testInvalidMacSize(24); + } + + private void testInvalidMacSize(int size) + { + try + { + GMac mac = new GMac(new GCMBlockCipher(new AESEngine()), size); + mac.init(new ParametersWithIV(null, new byte[16])); + fail("Expected failure for illegal mac size " + size); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().startsWith("Invalid value for MAC size")) + { + fail("Illegal mac size failed with unexpected message"); + } + } + } + + private void testMultibyte(Mac mac, TestCase testCase) + { + mac.update(testCase.getAd(), 0, testCase.getAd().length); + checkMac(mac, testCase); + } + + private void testSingleByte(Mac mac, TestCase testCase) + { + final byte[] ad = testCase.getAd(); + for (int i = 0; i < ad.length; i++) + { + mac.update(ad[i]); + } + checkMac(mac, testCase); + } + + private void checkMac(Mac mac, TestCase testCase) + { + final byte[] generatedMac = new byte[mac.getMacSize()]; + mac.doFinal(generatedMac, 0); + if (!areEqual(testCase.getTag(), generatedMac)) + { + fail("Failed " + testCase.getName() + " - expected " + new String(Hex.encode(testCase.getTag())) + " got " + + new String(Hex.encode(generatedMac))); + } + } + + public String getName() + { + return "GMac"; + } + + public static void main(String[] args) + { + runTest(new GMacTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST28147MacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST28147MacTest.java new file mode 100644 index 000000000..e32e07486 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST28147MacTest.java @@ -0,0 +1,89 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.engines.GOST28147Engine; +import com.fr.third.org.bouncycastle.crypto.macs.GOST28147Mac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithSBox; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * GOST 28147 MAC tester + */ +public class GOST28147MacTest + implements Test +{ + // + // these GOSTMac for testing. + // + static byte[] gkeyBytes1 = Hex.decode("6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49"); + static byte[] gkeyBytes2 = Hex.decode("6d145dc993f4019e104280df6fcd8cd8e01e101e4c113d7ec4f469ce6dcd9e49"); + + static byte[] input3 = Hex.decode("7768617420646f2079612077616e7420666f72206e6f7468696e673f"); + static byte[] input4 = Hex.decode("7768617420646f2079612077616e7420666f72206e6f7468696e673f"); + + static byte[] output7 = Hex.decode("93468a46"); + static byte[] output8 = Hex.decode("93468a46"); + + public GOST28147MacTest() + { + } + + public TestResult perform() + { + // test1 + Mac mac = new GOST28147Mac(); + KeyParameter key = new KeyParameter(gkeyBytes1); + + mac.init(key); + + mac.update(input3, 0, input3.length); + + byte[] out = new byte[4]; + + mac.doFinal(out, 0); + + if (!Arrays.areEqual(out, output7)) + { + return new SimpleTestResult(false, getName() + ": Failed test 1 - expected " + new String(Hex.encode(output7)) + " got " + new String(Hex.encode(out))); + } + + // test2 + key = new KeyParameter(gkeyBytes2); + + ParametersWithSBox gparam = new ParametersWithSBox(key, GOST28147Engine.getSBox("E-A")); + + mac.init(gparam); + + mac.update(input4, 0, input4.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!Arrays.areEqual(out, output8)) + { + return new SimpleTestResult(false, getName() + ": Failed test 2 - expected " + new String(Hex.encode(output8)) + " got " + new String(Hex.encode(out))); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public String getName() + { + return "GOST28147Mac"; + } + + public static void main( + String[] args) + { + GOST28147MacTest test = new GOST28147MacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST28147Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST28147Test.java new file mode 100644 index 000000000..d887ba4a8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST28147Test.java @@ -0,0 +1,371 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.CryptoException; +import com.fr.third.org.bouncycastle.crypto.digests.GOST3411Digest; +import com.fr.third.org.bouncycastle.crypto.engines.GOST28147Engine; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.GOFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithSBox; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class GOST28147Test + extends CipherTest +{ + static String input1 = "0000000000000000"; + static String output1 = "1b0bbc32cebcab42"; + static String input2 = "bc350e71aac5f5c2"; + static String output2 = "d35ab653493b49f5"; + static String input3 = "bc350e71aa11345709acde"; + static String output3 = "8824c124c4fd14301fb1e8"; + static String input4 = "000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"; + static String output4 = "29b7083e0a6d955ca0ec5b04fdb4ea41949f1dd2efdf17baffc1780b031f3934"; + + static byte TestSBox[] = { + 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF, + 0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0, + 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF, + 0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0, + 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF, + 0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0, + 0x0,0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,0x9,0xA,0xB,0xC,0xD,0xE,0xF, + 0xF,0xE,0xD,0xC,0xB,0xA,0x9,0x8,0x7,0x6,0x5,0x4,0x3,0x2,0x1,0x0 + }; + + static byte[] TestSBox_1 = + { + 0xE, 0x3, 0xC, 0xD, 0x1, 0xF, 0xA, 0x9, 0xB, 0x6, 0x2, 0x7, 0x5, 0x0, 0x8, 0x4, + 0xD, 0x9, 0x0, 0x4, 0x7, 0x1, 0x3, 0xB, 0x6, 0xC, 0x2, 0xA, 0xF, 0xE, 0x5, 0x8, + 0x8, 0xB, 0xA, 0x7, 0x1, 0xD, 0x5, 0xC, 0x6, 0x3, 0x9, 0x0, 0xF, 0xE, 0x2, 0x4, + 0xD, 0x7, 0xC, 0x9, 0xF, 0x0, 0x5, 0x8, 0xA, 0x2, 0xB, 0x6, 0x4, 0x3, 0x1, 0xE, + 0xB, 0x4, 0x6, 0x5, 0x0, 0xF, 0x1, 0xC, 0x9, 0xE, 0xD, 0x8, 0x3, 0x7, 0xA, 0x2, + 0xD, 0xF, 0x9, 0x4, 0x2, 0xC, 0x5, 0xA, 0x6, 0x0, 0x3, 0x8, 0x7, 0xE, 0x1, 0xB, + 0xF, 0xE, 0x9, 0x5, 0xB, 0x2, 0x1, 0x8, 0x6, 0x0, 0xD, 0x3, 0x4, 0x7, 0xC, 0xA, + 0xA, 0x3, 0xE, 0x2, 0x0, 0x1, 0x4, 0x6, 0xB, 0x8, 0xC, 0x7, 0xD, 0x5, 0xF, 0x9 + }; + + static SimpleTest[] tests = + { new BlockCipherVectorTest(1, new GOST28147Engine(), + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), + input1, output1), + new BlockCipherVectorTest(2, new CBCBlockCipher(new GOST28147Engine()), + new ParametersWithIV(new KeyParameter(Hex.decode("00112233445566778899AABBCCDDEEFF00112233445566778899AABBCCDDEEFF")), + Hex.decode("1234567890abcdef")), input2, output2), + new BlockCipherVectorTest(3, new GOFBBlockCipher(new GOST28147Engine()), + new ParametersWithIV(new KeyParameter(Hex.decode("0011223344556677889900112233445566778899001122334455667788990011")), + Hex.decode("1234567890abcdef")), //IV + input3, output3), + new BlockCipherVectorTest(4, new CFBBlockCipher(new GOST28147Engine(), 64), + new ParametersWithIV(new KeyParameter(Hex.decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5")), + Hex.decode("aafd12f659cae634")), input4, output4), + + //tests with parameters, set S-box. + new BlockCipherVectorTest(5, new GOST28147Engine(), + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")),//key , default parameter S-box set to D-Test + input1, output1), + new BlockCipherVectorTest(6, new CFBBlockCipher(new GOST28147Engine(), 64), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("D-Test")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "b587f7a0814c911d"), //encrypt message + new BlockCipherVectorTest(7, new CFBBlockCipher(new GOST28147Engine(), 64), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("E-Test")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "e8287f53f991d52b"), //encrypt message + new BlockCipherVectorTest(8, new CFBBlockCipher(new GOST28147Engine(), 64), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("E-A")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "c41009dba22ebe35"), //encrypt message + new BlockCipherVectorTest(9, new CFBBlockCipher(new GOST28147Engine(), 8), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("E-B")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "80d8723fcd3aba28"), //encrypt message + new BlockCipherVectorTest(10, new CFBBlockCipher(new GOST28147Engine(), 8), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("E-C")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "739f6f95068499b5"), //encrypt message + new BlockCipherVectorTest(11, new CFBBlockCipher(new GOST28147Engine(), 8), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("E-D")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "4663f720f4340f57"), //encrypt message + new BlockCipherVectorTest(12, new CFBBlockCipher(new GOST28147Engine(), 8), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + GOST28147Engine.getSBox("D-A")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "5bb0a31d218ed564"), //encrypt message + new BlockCipherVectorTest(13, new CFBBlockCipher(new GOST28147Engine(), 8), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("546d203368656c326973652073736e62206167796967747473656865202c3d73")), //key + TestSBox), //set own S-box + Hex.decode("1234567890abcdef")), //IV + "0000000000000000", //input message + "c3af96ef788667c5"), //encrypt message + new BlockCipherVectorTest(14, new GOFBBlockCipher(new GOST28147Engine()), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("4ef72b778f0b0bebeef4f077551cb74a927b470ad7d7f2513454569a247e989d")), //key + GOST28147Engine.getSBox("E-A")), //type S-box + Hex.decode("1234567890abcdef")), //IV + "bc350e71aa11345709acde", //input message + "1bcc2282707c676fb656dc"), //encrypt message + new BlockCipherVectorTest(15, new GOFBBlockCipher(new GOST28147Engine()), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("0A43145BA8B9E9FF0AEA67D3F26AD87854CED8D9017B3D33ED81301F90FDF993")), //key + TestSBox_1), //type, IV, S-box + Hex.decode("8001069080010690")), + "094C912C5EFDD703D42118971694580B", //input message + "2707B58DF039D1A64460735FFE76D55F"), //encrypt message + new BlockCipherVectorTest(16, new GOFBBlockCipher(new GOST28147Engine()), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("0A43145BA8B9E9FF0AEA67D3F26AD87854CED8D9017B3D33ED81301F90FDF993")), //key + TestSBox_1), //type, S-box + Hex.decode("800107A0800107A0")), + "FE780800E0690083F20C010CF00C0329", //input message + "9AF623DFF948B413B53171E8D546188D"), //encrypt message + new BlockCipherVectorTest(17, new GOFBBlockCipher(new GOST28147Engine()), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("0A43145BA8B9E9FF0AEA67D3F26AD87854CED8D9017B3D33ED81301F90FDF993")), //key + TestSBox_1), //type, S-box + Hex.decode("8001114080011140")), + "D1088FD8C0A86EE8F1DCD1088FE8C058", //input message + "62A6B64D12253BCD8241A4BB0CFD3E7C"), //encrypt message + new BlockCipherVectorTest(18, new GOFBBlockCipher(new GOST28147Engine()), + new ParametersWithIV( + new ParametersWithSBox( + new KeyParameter(Hex.decode("0A43145BA8B9E9FF0AEA67D3F26AD87854CED8D9017B3D33ED81301F90FDF993")), //key + TestSBox_1), //type, IV, S-box + Hex.decode("80011A3080011A30")), + "D431FACD011C502C501B500A12921090", //input message + "07313C89D302FF73234B4A0506AB00F3"), //encrypt message + }; + + static private final int GOST28147_KEY_LENGTH = 32; + + private byte[] generateKey(byte[] startkey) + { + byte[] newKey = new byte[GOST28147_KEY_LENGTH]; + + GOST3411Digest digest = new GOST3411Digest(); + + digest.update(startkey, 0, startkey.length); + digest.doFinal(newKey, 0); + + return newKey; + } + + GOST28147Test() + { + super(tests, new GOST28147Engine(), new KeyParameter(new byte[32])); + } + + public void performTest() + throws Exception + { + super.performTest(); + + //advanced tests with GOST28147KeyGenerator: + //encrypt on hesh message; ECB mode: + byte[] in = Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20"); + byte[] output = Hex.decode("8ad3c8f56b27ff1fbd46409359bdc796bc350e71aac5f5c0"); + byte[] out = new byte[in.length]; + + byte[] key = generateKey(Hex.decode("0123456789abcdef")); //!!! heshing start_key - get 256 bits !!! +// System.out.println(new String(Hex.encode(key))); + CipherParameters param = new ParametersWithSBox(new KeyParameter(key), GOST28147Engine.getSBox("E-A")); + //CipherParameters param = new GOST28147Parameters(key,"D-Test"); + BufferedBlockCipher cipher = new BufferedBlockCipher(new GOST28147Engine()); + + cipher.init(true, param); + int len1 = cipher.processBytes(in, 0, in.length, out, 0); + try + { + cipher.doFinal(out, len1); + } + catch (CryptoException e) + { + fail("failed - exception " + e.toString(), e); + } + if (out.length != output.length) + { + fail("failed - " + + "expected " + new String(Hex.encode(output)) + " got " + + new String(Hex.encode(out))); + } + for (int i = 0; i != out.length; i++) + { + if (out[i] != output[i]) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + + //encrypt on hesh message; CFB mode: + in = Hex.decode("bc350e71aac5f5c2"); + output = Hex.decode("0ebbbafcf38f14a5"); + out = new byte[in.length]; + + key = generateKey(Hex.decode("0123456789abcdef")); //!!! heshing start_key - get 256 bits !!! + param = new ParametersWithIV(new ParametersWithSBox( + new KeyParameter(key), //key + GOST28147Engine.getSBox("E-A")), //type S-box + Hex.decode("1234567890abcdef")); //IV + + cipher = new BufferedBlockCipher(new CFBBlockCipher(new GOST28147Engine(), 64)); + + cipher.init(true, param); + len1 = cipher.processBytes(in, 0, in.length, out, 0); + try + { + cipher.doFinal(out, len1); + } + catch (CryptoException e) + { + fail("failed - exception " + e.toString(), e); + } + if (out.length != output.length) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + for (int i = 0; i != out.length; i++) + { + if (out[i] != output[i]) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + + //encrypt on hesh message; CFB mode: + in = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); + output = Hex.decode("64988982819f0a1655e226e19ecad79d10cc73bac95c5d7da034786c12294225"); + out = new byte[in.length]; + + key = generateKey(Hex.decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f659cae63489b479e5")); //!!! heshing start_key - get 256 bits !!! + param = new ParametersWithIV(new ParametersWithSBox( + new KeyParameter(key), //key + GOST28147Engine.getSBox("E-A")), //type S-box + Hex.decode("aafd12f659cae634")); //IV + + cipher = new BufferedBlockCipher(new CFBBlockCipher(new GOST28147Engine(), 64)); + + cipher.init(true, param); + len1 = cipher.processBytes(in, 0, in.length, out, 0); + + cipher.doFinal(out, len1); + + if (out.length != output.length) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + for (int i = 0; i != out.length; i++) + { + if (out[i] != output[i]) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + //encrypt on hesh message; OFB mode: + in = Hex.decode("bc350e71aa11345709acde"); + output = Hex.decode("1bcc2282707c676fb656dc"); + out = new byte[in.length]; + + key = generateKey(Hex.decode("0123456789abcdef")); //!!! heshing start_key - get 256 bits !!! + param = new ParametersWithIV(new ParametersWithSBox( + new KeyParameter(key), //key + GOST28147Engine.getSBox("E-A")), //type S-box + Hex.decode("1234567890abcdef")); //IV + + cipher = new BufferedBlockCipher(new GOFBBlockCipher(new GOST28147Engine())); + + cipher.init(true, param); + len1 = cipher.processBytes(in, 0, in.length, out, 0); + + cipher.doFinal(out, len1); + + if (out.length != output.length) + { + fail("failed - " + "expected " + + new String(Hex.encode(output)) + " got " + + new String(Hex.encode(out))); + } + for (int i = 0; i != out.length; i++) + { + if (out[i] != output[i]) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + // key reuse test + param = new ParametersWithIV(null, // key and sbox reused + Hex.decode("1234567890abcdef")); //IV + + cipher.init(true, param); + len1 = cipher.processBytes(in, 0, in.length, out, 0); + + cipher.doFinal(out, len1); + + if (out.length != output.length) + { + fail("failed - " + "expected " + + new String(Hex.encode(output)) + " got " + + new String(Hex.encode(out))); + } + for (int i = 0; i != out.length; i++) + { + if (out[i] != output[i]) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + } + + public String getName() + { + return "GOST28147"; + } + + public static void main( + String[] args) + { + runTest(new GOST28147Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3410Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3410Test.java new file mode 100644 index 000000000..3b84e3be7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3410Test.java @@ -0,0 +1,2428 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.GOST3410KeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.GOST3410ParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ECGOST3410Parameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECNamedDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.GOST3410KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.GOST3410Parameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.signers.GOST3410Signer; +import com.fr.third.org.bouncycastle.crypto.util.PrivateKeyFactory; +import com.fr.third.org.bouncycastle.crypto.util.PrivateKeyInfoFactory; +import com.fr.third.org.bouncycastle.crypto.util.PublicKeyFactory; +import com.fr.third.org.bouncycastle.crypto.util.SubjectPublicKeyInfoFactory; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.FixedSecureRandom; +import com.fr.third.org.bouncycastle.util.test.NumberParsing; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestRandomData; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class GOST3410Test + implements Test +{ + byte[] hashmessage = Hex.decode("3042453136414534424341374533364339313734453431443642453241453435"); + + private byte[] zeroTwo(int length) + { + byte[] data = new byte[length]; + data[data.length - 1] = 0x02; + return data; + } + + + Test tests[] = + { + new GOST3410EncodingDecoding(), + new GOST3410_TEST1_512(), + new GOST3410_TEST2_512(), + new GOST3410_TEST1_1024(), + new GOST3410_TEST2_1024(), + new GOST3410_AParam(), + new GOST3410_BParam(), + new GOST3410_CParam(), + new GOST3410_DParam(), + new GOST3410_AExParam(), + new GOST3410_BExParam(), + new GOST3410_CExParam() + }; + + public static void main( + String[] args) + { + GOST3410Test test = new GOST3410Test(); + TestResult result = test.perform(); + + System.out.println(result); + } + + public TestResult perform() + { + for (int i = 0; i != tests.length; i++) + { + TestResult result = tests[i].perform(); + + if (!result.isSuccessful()) + { + return result; + } + } + + return new SimpleTestResult(true, "GOST3410: Okay"); + } + + private class GOST3410EncodingDecoding + implements Test + { + + public String getName() + { + return "GOST3410ParameterEncodeDecode"; + } + + + private SimpleTestResult encodeRecodePrivateKeyGost2006() + { + try + { + ASN1ObjectIdentifier oid = ECGOST3410NamedCurves.getOID("GostR3410-2001-CryptoPro-A"); + ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGOST3410NamedCurves.getByOID(oid)); + ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid, CryptoProObjectIdentifiers.gostR3411); + ECKeyGenerationParameters params = new ECKeyGenerationParameters(gostParams, new SecureRandom()); + ECKeyPairGenerator engine = new ECKeyPairGenerator(); + engine.init(params); + AsymmetricCipherKeyPair pair = engine.generateKeyPair(); + + ECPrivateKeyParameters generatedKeyParameters = (ECPrivateKeyParameters)pair.getPrivate(); + ECPrivateKeyParameters keyParameters = generatedKeyParameters; + + + // + // Continuously encode/decode the key and check for loss of information. + // + + + for (int t = 0; t < 3; t++) + { + PrivateKeyInfo info = PrivateKeyInfoFactory.createPrivateKeyInfo(keyParameters); + keyParameters = (ECPrivateKeyParameters)PrivateKeyFactory.createKey(info); + + { // Specifically cast and test gost parameters. + ECGOST3410Parameters gParam = (ECGOST3410Parameters)generatedKeyParameters.getParameters(); + ECGOST3410Parameters rParam = (ECGOST3410Parameters)keyParameters.getParameters(); + + boolean ok = safeEquals(gParam.getDigestParamSet(), rParam.getDigestParamSet()) && + safeEquals(gParam.getEncryptionParamSet(), rParam.getEncryptionParamSet()) && + safeEquals(gParam.getPublicKeyParamSet(), rParam.getPublicKeyParamSet()); + + if (!ok) + { + return new SimpleTestResult(false, "GOST parameters does not match"); + } + + } + + if (keyParameters.isPrivate() != generatedKeyParameters.isPrivate()) + { + return new SimpleTestResult(false, "isPrivate does not match"); + } + + if (!keyParameters.getD().equals(generatedKeyParameters.getD())) + { + return new SimpleTestResult(false, "D does not match"); + } + + if (!((ECGOST3410Parameters)keyParameters.getParameters()).getName().equals( + ((ECGOST3410Parameters)generatedKeyParameters.getParameters()).getName())) + { + return new SimpleTestResult(false, "Name does not match"); + } + + if (!keyParameters.getParameters().getCurve().equals(generatedKeyParameters.getParameters().getCurve())) + { + return new SimpleTestResult(false, "Curve does not match"); + } + + if (!Arrays.areEqual( + keyParameters.getParameters().getG().getEncoded(true), + generatedKeyParameters.getParameters().getG().getEncoded(true))) + { + return new SimpleTestResult(false, "G does not match"); + } + + if (!keyParameters.getParameters().getH().equals(generatedKeyParameters.getParameters().getH())) + { + return new SimpleTestResult(false, "H does not match"); + } + + if (!keyParameters.getParameters().getHInv().equals(generatedKeyParameters.getParameters().getHInv())) + { + return new SimpleTestResult(false, "Hinv does not match"); + } + + if (!keyParameters.getParameters().getN().equals(generatedKeyParameters.getParameters().getN())) + { + return new SimpleTestResult(false, "N does not match"); + } + + if (!Arrays.areEqual(keyParameters.getParameters().getSeed(), generatedKeyParameters.getParameters().getSeed())) + { + return new SimpleTestResult(false, "Seed does not match"); + } + } + + + } + catch (Exception ex) + { + return new SimpleTestResult(false, ex.getMessage(), ex); + } + + return new SimpleTestResult(true, null); + } + + + public SimpleTestResult encodeRecodePublicKeyGost2006() + { + ASN1ObjectIdentifier oid = ECGOST3410NamedCurves.getOID("GostR3410-2001-CryptoPro-A"); + ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGOST3410NamedCurves.getByOID(oid)); + ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid, CryptoProObjectIdentifiers.gostR3411); + ECKeyGenerationParameters params = new ECKeyGenerationParameters(gostParams, new SecureRandom()); + ECKeyPairGenerator engine = new ECKeyPairGenerator(); + engine.init(params); + AsymmetricCipherKeyPair pair = engine.generateKeyPair(); + + ECPublicKeyParameters generatedKeyParameters = (ECPublicKeyParameters)pair.getPublic(); + ECPublicKeyParameters keyParameters = generatedKeyParameters; + + try + { + for (int t = 0; t < 3; t++) + { + + SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(keyParameters); + keyParameters = (ECPublicKeyParameters)PublicKeyFactory.createKey(info); + + { // Specifically cast and test gost parameters. + ECGOST3410Parameters gParam = (ECGOST3410Parameters)generatedKeyParameters.getParameters(); + ECGOST3410Parameters rParam = (ECGOST3410Parameters)keyParameters.getParameters(); + + + boolean ok = safeEquals(gParam.getDigestParamSet(), rParam.getDigestParamSet()) && + safeEquals(gParam.getEncryptionParamSet(), rParam.getEncryptionParamSet()) && + safeEquals(gParam.getPublicKeyParamSet(), rParam.getPublicKeyParamSet()); + + if (!ok) + { + return new SimpleTestResult(false, "GOST parameters does not match"); + } + + } + + if (!((ECGOST3410Parameters)keyParameters.getParameters()).getName().equals( + ((ECGOST3410Parameters)generatedKeyParameters.getParameters()).getName())) + { + return new SimpleTestResult(false, "Name does not match"); + } + + + if (keyParameters.isPrivate() != generatedKeyParameters.isPrivate()) + { + return new SimpleTestResult(false, "isPrivate does not match"); + } + + if (!Arrays.areEqual(keyParameters.getQ().getEncoded(true), generatedKeyParameters.getQ().getEncoded(true))) + { + return new SimpleTestResult(false, "Q does not match"); + } + + if (!keyParameters.getParameters().getCurve().equals(generatedKeyParameters.getParameters().getCurve())) + { + return new SimpleTestResult(false, "Curve does not match"); + } + + if (!Arrays.areEqual( + keyParameters.getParameters().getG().getEncoded(true), + generatedKeyParameters.getParameters().getG().getEncoded(true))) + { + return new SimpleTestResult(false, "G does not match"); + } + + if (!keyParameters.getParameters().getH().equals(generatedKeyParameters.getParameters().getH())) + { + return new SimpleTestResult(false, "H does not match"); + } + + if (!keyParameters.getParameters().getHInv().equals(generatedKeyParameters.getParameters().getHInv())) + { + return new SimpleTestResult(false, "Hinv does not match"); + } + + if (!keyParameters.getParameters().getN().equals(generatedKeyParameters.getParameters().getN())) + { + return new SimpleTestResult(false, "N does not match"); + } + + if (!Arrays.areEqual(keyParameters.getParameters().getSeed(), generatedKeyParameters.getParameters().getSeed())) + { + return new SimpleTestResult(false, "Seed does not match"); + } + } + return new SimpleTestResult(true, null); + } + catch (Exception ex) + { + return new SimpleTestResult(false, ex.getMessage(), ex); + } + + + } + + + public SimpleTestResult encodeRecodePublicKey() + { + + ASN1ObjectIdentifier oid = ECGOST3410NamedCurves.getOID("Tc26-Gost-3410-12-512-paramSetA"); + ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGOST3410NamedCurves.getByOID(oid)); + ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512); + ECKeyGenerationParameters params = new ECKeyGenerationParameters(gostParams, new SecureRandom()); + ECKeyPairGenerator engine = new ECKeyPairGenerator(); + engine.init(params); + AsymmetricCipherKeyPair pair = engine.generateKeyPair(); + + ECPublicKeyParameters generatedKeyParameters = (ECPublicKeyParameters)pair.getPublic(); + ECPublicKeyParameters keyParameters = generatedKeyParameters; + + + // + // Continuously encode/decode the key and check for loss of information. + // + try + { + for (int t = 0; t < 3; t++) + { + + SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(keyParameters); + keyParameters = (ECPublicKeyParameters)PublicKeyFactory.createKey(info); + + { // Specifically cast and test gost parameters. + ECGOST3410Parameters gParam = (ECGOST3410Parameters)generatedKeyParameters.getParameters(); + ECGOST3410Parameters rParam = (ECGOST3410Parameters)keyParameters.getParameters(); + + + boolean ok = safeEquals(gParam.getDigestParamSet(), rParam.getDigestParamSet()) && + safeEquals(gParam.getEncryptionParamSet(), rParam.getEncryptionParamSet()) && + safeEquals(gParam.getPublicKeyParamSet(), rParam.getPublicKeyParamSet()); + + if (!ok) + { + return new SimpleTestResult(false, "GOST parameters does not match"); + } + + } + + if (!((ECGOST3410Parameters)keyParameters.getParameters()).getName().equals( + ((ECGOST3410Parameters)generatedKeyParameters.getParameters()).getName())) + { + return new SimpleTestResult(false, "Name does not match"); + } + + + if (keyParameters.isPrivate() != generatedKeyParameters.isPrivate()) + { + return new SimpleTestResult(false, "isPrivate does not match"); + } + + if (!Arrays.areEqual(keyParameters.getQ().getEncoded(true), generatedKeyParameters.getQ().getEncoded(true))) + { + return new SimpleTestResult(false, "Q does not match"); + } + + if (!keyParameters.getParameters().getCurve().equals(generatedKeyParameters.getParameters().getCurve())) + { + return new SimpleTestResult(false, "Curve does not match"); + } + + if (!Arrays.areEqual( + keyParameters.getParameters().getG().getEncoded(true), + generatedKeyParameters.getParameters().getG().getEncoded(true))) + { + return new SimpleTestResult(false, "G does not match"); + } + + if (!keyParameters.getParameters().getH().equals(generatedKeyParameters.getParameters().getH())) + { + return new SimpleTestResult(false, "H does not match"); + } + + if (!keyParameters.getParameters().getHInv().equals(generatedKeyParameters.getParameters().getHInv())) + { + return new SimpleTestResult(false, "Hinv does not match"); + } + + if (!keyParameters.getParameters().getN().equals(generatedKeyParameters.getParameters().getN())) + { + return new SimpleTestResult(false, "N does not match"); + } + + if (!Arrays.areEqual(keyParameters.getParameters().getSeed(), generatedKeyParameters.getParameters().getSeed())) + { + return new SimpleTestResult(false, "Seed does not match"); + } + } + return new SimpleTestResult(true, null); + } + catch (Exception ex) + { + return new SimpleTestResult(false, ex.getMessage(), ex); + } + + + } + + + private SimpleTestResult encodeRecodePrivateKey() + { + try + { + ASN1ObjectIdentifier oid = ECGOST3410NamedCurves.getOID("Tc26-Gost-3410-12-512-paramSetA"); + ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGOST3410NamedCurves.getByOID(oid)); + ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512); + ECKeyGenerationParameters params = new ECKeyGenerationParameters(gostParams, new SecureRandom()); + ECKeyPairGenerator engine = new ECKeyPairGenerator(); + engine.init(params); + AsymmetricCipherKeyPair pair = engine.generateKeyPair(); + + ECPrivateKeyParameters generatedKeyParameters = (ECPrivateKeyParameters)pair.getPrivate(); + ECPrivateKeyParameters keyParameters = generatedKeyParameters; + + + // + // Continuously encode/decode the key and check for loss of information. + // + + + for (int t = 0; t < 3; t++) + { + PrivateKeyInfo info = PrivateKeyInfoFactory.createPrivateKeyInfo(keyParameters); + keyParameters = (ECPrivateKeyParameters)PrivateKeyFactory.createKey(info); + + { // Specifically cast and test gost parameters. + ECGOST3410Parameters gParam = (ECGOST3410Parameters)generatedKeyParameters.getParameters(); + ECGOST3410Parameters rParam = (ECGOST3410Parameters)keyParameters.getParameters(); + + boolean ok = safeEquals(gParam.getDigestParamSet(), rParam.getDigestParamSet()) && + safeEquals(gParam.getEncryptionParamSet(), rParam.getEncryptionParamSet()) && + safeEquals(gParam.getPublicKeyParamSet(), rParam.getPublicKeyParamSet()); + + if (!ok) + { + return new SimpleTestResult(false, "GOST parameters does not match"); + } + + } + + if (keyParameters.isPrivate() != generatedKeyParameters.isPrivate()) + { + return new SimpleTestResult(false, "isPrivate does not match"); + } + + if (!keyParameters.getD().equals(generatedKeyParameters.getD())) + { + return new SimpleTestResult(false, "D does not match"); + } + + if (!((ECGOST3410Parameters)keyParameters.getParameters()).getName().equals( + ((ECGOST3410Parameters)generatedKeyParameters.getParameters()).getName())) + { + return new SimpleTestResult(false, "Name does not match"); + } + + if (!keyParameters.getParameters().getCurve().equals(generatedKeyParameters.getParameters().getCurve())) + { + return new SimpleTestResult(false, "Curve does not match"); + } + + if (!Arrays.areEqual( + keyParameters.getParameters().getG().getEncoded(true), + generatedKeyParameters.getParameters().getG().getEncoded(true))) + { + return new SimpleTestResult(false, "G does not match"); + } + + if (!keyParameters.getParameters().getH().equals(generatedKeyParameters.getParameters().getH())) + { + return new SimpleTestResult(false, "H does not match"); + } + + if (!keyParameters.getParameters().getHInv().equals(generatedKeyParameters.getParameters().getHInv())) + { + return new SimpleTestResult(false, "Hinv does not match"); + } + + if (!keyParameters.getParameters().getN().equals(generatedKeyParameters.getParameters().getN())) + { + return new SimpleTestResult(false, "N does not match"); + } + + if (!Arrays.areEqual(keyParameters.getParameters().getSeed(), generatedKeyParameters.getParameters().getSeed())) + { + return new SimpleTestResult(false, "Seed does not match"); + } + } + + + } + catch (Exception ex) + { + return new SimpleTestResult(false, ex.getMessage(), ex); + } + + return new SimpleTestResult(true, null); + } + + + private SimpleTestResult decodeJCEPublic() + { + byte[] pub256 = Hex.decode("3068302106082a85030701010101301506092a850307010201010106082a850307010102020343000440292335c87d892510c35a033819a13e2b0dc606d911676af2bad8872d74a4b7bae6c729e98ace04c3dee626343f794731e1489edb7bc26f1c8c56e1448c96501a"); + + try + { + ECPublicKeyParameters pkInfo = (ECPublicKeyParameters)PublicKeyFactory.createKey(pub256); + + if (pkInfo.isPrivate()) + { + return new SimpleTestResult(false, "isPrivate should be false"); + } + + if ( + !Arrays.areEqual( + pkInfo.getQ().getEncoded(true), + Hex.decode("02bab7a4742d87d8baf26a6711d906c60d2b3ea11938035ac31025897dc8352329"))) + { + return new SimpleTestResult(false, "Q does not match"); + } + + if (!((ECGOST3410Parameters)pkInfo.getParameters()).getPublicKeyParamSet().toString().equals("1.2.643.7.1.2.1.1.1")) + { + return new SimpleTestResult(false, "PublicKeyParamSet does not match"); + } + + if (!((ECGOST3410Parameters)pkInfo.getParameters()).getDigestParamSet().toString().equals("1.2.643.7.1.1.2.2")) + { + return new SimpleTestResult(false, "DigestParamSet does not match"); + } + + if (((ECGOST3410Parameters)pkInfo.getParameters()).getEncryptionParamSet() != null) + { + return new SimpleTestResult(false, "EncryptionParamSet is not null"); + } + + + byte[] pub512 = Hex.decode("3081aa302106082a85030701010102301506092a850307010201020106082a850307010102030381840004818043ccc22692ee8a1870c7c9de0566d7e3a494cf0e3c80f9e8852a3d1ec10d2a829d357253e0864aee2eaacd5e2d327578dee771f62f24decfd6358e06199efe540e7912db43c4c80fe0fd31f7f67a862f9d44fd0075cfee6e3d638c7520063d26311ef962547e8129fb8c5b194e129370cd30313884b4a60872254a10772fe595"); + + pkInfo = (ECPublicKeyParameters)PublicKeyFactory.createKey(pub512); + + if (pkInfo.isPrivate()) + { + return new SimpleTestResult(false, "isPrivate should be true"); + } + + if ( + !Arrays.areEqual( + pkInfo.getQ().getEncoded(true), + Hex.decode("0254fe9e19068e35d6cfde242ff671e7de7875322d5ecdaa2eee4a86e05372359d822a0dc11e3d2a85e8f9803c0ecf94a4e3d76605dec9c770188aee9226c2cc43"))) + { + return new SimpleTestResult(false, "Q does not match"); + } + + + if (!((ECGOST3410Parameters)pkInfo.getParameters()).getPublicKeyParamSet().toString().equals("1.2.643.7.1.2.1.2.1")) + { + return new SimpleTestResult(false, "PublicKeyParamSet does not match"); + } + + if (!((ECGOST3410Parameters)pkInfo.getParameters()).getDigestParamSet().toString().equals("1.2.643.7.1.1.2.3")) + { + return new SimpleTestResult(false, "DigestParamSet does not match"); + } + + if (((ECGOST3410Parameters)pkInfo.getParameters()).getEncryptionParamSet() != null) + { + return new SimpleTestResult(false, "EncryptionParamSet is not null"); + } + + } + catch (Exception ex) + { + return new SimpleTestResult(false, ex.getMessage(), ex); + } + + return new SimpleTestResult(true, null); + } + + + private SimpleTestResult decodeJCEPrivate() + { + byte[] priv256 = Hex.decode("304a020100302106082a85030701010101301506092a850307010201010106082a8503070101020204220420fe75ba328d5439ed4859e6dc7e6ca2e9aab0818f094eddeb0d57d1c16a90762b"); + + try + { + ECPrivateKeyParameters pkInfo = (ECPrivateKeyParameters)PrivateKeyFactory.createKey(priv256); + + if (!pkInfo.isPrivate()) + { + return new SimpleTestResult(false, "isPrivate should be true"); + } + + if ( + !Arrays.areEqual( + Hex.decode("2b76906ac1d1570debdd4e098f81b0aae9a26c7edce65948ed39548d32ba75fe"), + pkInfo.getD().toByteArray())) + { + return new SimpleTestResult(false, "D does not match"); + } + + if (!((ECGOST3410Parameters)pkInfo.getParameters()).getPublicKeyParamSet().toString().equals("1.2.643.7.1.2.1.1.1")) + { + return new SimpleTestResult(false, "PublicKeyParamSet does not match"); + } + + if (!((ECGOST3410Parameters)pkInfo.getParameters()).getDigestParamSet().toString().equals("1.2.643.7.1.1.2.2")) + { + return new SimpleTestResult(false, "DigestParamSet does not match"); + } + + if (((ECGOST3410Parameters)pkInfo.getParameters()).getEncryptionParamSet() != null) + { + return new SimpleTestResult(false, "EncryptionParamSet is not null"); + } + + + byte[] priv512 = Hex.decode("306a020100302106082a85030701010102301506092a850307010201020106082a85030701010203044204402fc35576152f6e873236608b592b4b98d0793bf5184f8dc4a99512be703716991a96061ef46aceeae5319b5c69e6fcbfa7e339207878597ce50f9b7cbf857ff1"); + + pkInfo = (ECPrivateKeyParameters)PrivateKeyFactory.createKey(priv512); + + if (!pkInfo.isPrivate()) + { + return new SimpleTestResult(false, "isPrivate should be true"); + } + + if ( + !Arrays.areEqual( + Hex.decode("00f17f85bf7c9b0fe57c5978782039e3a7bffce6695c9b31e5eace6af41e06961a99163770be1295a9c48d4f18f53b79d0984b2b598b603632876e2f157655c32f"), + pkInfo.getD().toByteArray())) + { + return new SimpleTestResult(false, "D does not match"); + } + + if (!((ECGOST3410Parameters)pkInfo.getParameters()).getPublicKeyParamSet().toString().equals("1.2.643.7.1.2.1.2.1")) + { + return new SimpleTestResult(false, "PublicKeyParamSet does not match"); + } + + if (!((ECGOST3410Parameters)pkInfo.getParameters()).getDigestParamSet().toString().equals("1.2.643.7.1.1.2.3")) + { + return new SimpleTestResult(false, "DigestParamSet does not match"); + } + + if (((ECGOST3410Parameters)pkInfo.getParameters()).getEncryptionParamSet() != null) + { + return new SimpleTestResult(false, "EncryptionParamSet is not null"); + } + + } + catch (Exception ex) + { + return new SimpleTestResult(false, ex.getMessage(), ex); + } + + return new SimpleTestResult(true, null); + } + + + private SimpleTestResult encodeDecodePrivateLW(String oidStr, ASN1ObjectIdentifier digest) + { + try + { + ASN1ObjectIdentifier oid = ECGOST3410NamedCurves.getOID(oidStr); + ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGOST3410NamedCurves.getByOID(oid)); + ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid, digest); + ECKeyGenerationParameters params = new ECKeyGenerationParameters(gostParams, new SecureRandom()); + ECKeyPairGenerator engine = new ECKeyPairGenerator(); + engine.init(params); + AsymmetricCipherKeyPair pair = engine.generateKeyPair(); + + ECPrivateKeyParameters generatedKeyParameters = (ECPrivateKeyParameters)pair.getPrivate(); + + PrivateKeyInfo info = PrivateKeyInfoFactory.createPrivateKeyInfo(generatedKeyParameters); + + ECPrivateKeyParameters recoveredKeyParameters = (ECPrivateKeyParameters)PrivateKeyFactory.createKey(info); + + { // Specifically cast and test gost parameters. + ECGOST3410Parameters gParam = (ECGOST3410Parameters)generatedKeyParameters.getParameters(); + ECGOST3410Parameters rParam = (ECGOST3410Parameters)recoveredKeyParameters.getParameters(); + + boolean ok = safeEquals(gParam.getDigestParamSet(), rParam.getDigestParamSet()) && + safeEquals(gParam.getEncryptionParamSet(), rParam.getEncryptionParamSet()) && + safeEquals(gParam.getPublicKeyParamSet(), rParam.getPublicKeyParamSet()); + + if (!ok) + { + return new SimpleTestResult(false, "GOST parameters does not match"); + } + + } + + + if (recoveredKeyParameters.isPrivate() != generatedKeyParameters.isPrivate()) + { + return new SimpleTestResult(false, "isPrivate does not match"); + } + + if (!((ECGOST3410Parameters)recoveredKeyParameters.getParameters()).getName().equals( + ((ECGOST3410Parameters)generatedKeyParameters.getParameters()).getName())) + { + return new SimpleTestResult(false, "Name does not match"); + } + + + if (!recoveredKeyParameters.getD().equals(generatedKeyParameters.getD())) + { + return new SimpleTestResult(false, "D does not match"); + } + + if (!recoveredKeyParameters.getParameters().getCurve().equals(generatedKeyParameters.getParameters().getCurve())) + { + return new SimpleTestResult(false, "Curve does not match"); + } + + if (!Arrays.areEqual( + recoveredKeyParameters.getParameters().getG().getEncoded(true), + generatedKeyParameters.getParameters().getG().getEncoded(true))) + { + return new SimpleTestResult(false, "G does not match"); + } + + if (!recoveredKeyParameters.getParameters().getH().equals(generatedKeyParameters.getParameters().getH())) + { + return new SimpleTestResult(false, "H does not match"); + } + + if (!recoveredKeyParameters.getParameters().getHInv().equals(generatedKeyParameters.getParameters().getHInv())) + { + return new SimpleTestResult(false, "Hinv does not match"); + } + + if (!recoveredKeyParameters.getParameters().getN().equals(generatedKeyParameters.getParameters().getN())) + { + return new SimpleTestResult(false, "N does not match"); + } + + if (!Arrays.areEqual(recoveredKeyParameters.getParameters().getSeed(), generatedKeyParameters.getParameters().getSeed())) + { + return new SimpleTestResult(false, "Seed does not match"); + } + + return new SimpleTestResult(true, null); + } + catch (Exception t) + { + // Any exception is bad. + return new SimpleTestResult(false, t.getMessage(), t); + } + } + + + private SimpleTestResult encodeDecodePublicLW(String oidStr, ASN1ObjectIdentifier digest) + { + try + { + ASN1ObjectIdentifier oid = ECGOST3410NamedCurves.getOID(oidStr); + ECNamedDomainParameters ecp = new ECNamedDomainParameters(oid, ECGOST3410NamedCurves.getByOID(oid)); + ECGOST3410Parameters gostParams = new ECGOST3410Parameters(ecp, oid, digest); + ECKeyGenerationParameters params = new ECKeyGenerationParameters(gostParams, new SecureRandom()); + ECKeyPairGenerator engine = new ECKeyPairGenerator(); + engine.init(params); + AsymmetricCipherKeyPair pair = engine.generateKeyPair(); + + ECPublicKeyParameters generatedKeyParameters = (ECPublicKeyParameters)pair.getPublic(); + + SubjectPublicKeyInfo info = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(generatedKeyParameters); + + ECPublicKeyParameters recoveredKeyParameters = (ECPublicKeyParameters)PublicKeyFactory.createKey(info); + + { // Specifically cast and test gost parameters. + ECGOST3410Parameters gParam = (ECGOST3410Parameters)generatedKeyParameters.getParameters(); + ECGOST3410Parameters rParam = (ECGOST3410Parameters)recoveredKeyParameters.getParameters(); + + + boolean ok = safeEquals(gParam.getDigestParamSet(), rParam.getDigestParamSet()) && + safeEquals(gParam.getEncryptionParamSet(), rParam.getEncryptionParamSet()) && + safeEquals(gParam.getPublicKeyParamSet(), rParam.getPublicKeyParamSet()); + + if (!ok) + { + return new SimpleTestResult(false, "GOST parameters does not match"); + } + + } + + if (!((ECGOST3410Parameters)recoveredKeyParameters.getParameters()).getName().equals( + ((ECGOST3410Parameters)generatedKeyParameters.getParameters()).getName())) + { + return new SimpleTestResult(false, "Name does not match"); + } + + + if (recoveredKeyParameters.isPrivate() != generatedKeyParameters.isPrivate()) + { + return new SimpleTestResult(false, "isPrivate does not match"); + } + + if (!Arrays.areEqual(recoveredKeyParameters.getQ().getEncoded(true), generatedKeyParameters.getQ().getEncoded(true))) + { + return new SimpleTestResult(false, "Q does not match"); + } + + if (!recoveredKeyParameters.getParameters().getCurve().equals(generatedKeyParameters.getParameters().getCurve())) + { + return new SimpleTestResult(false, "Curve does not match"); + } + + if (!Arrays.areEqual( + recoveredKeyParameters.getParameters().getG().getEncoded(true), + generatedKeyParameters.getParameters().getG().getEncoded(true))) + { + return new SimpleTestResult(false, "G does not match"); + } + + if (!recoveredKeyParameters.getParameters().getH().equals(generatedKeyParameters.getParameters().getH())) + { + return new SimpleTestResult(false, "H does not match"); + } + + if (!recoveredKeyParameters.getParameters().getHInv().equals(generatedKeyParameters.getParameters().getHInv())) + { + return new SimpleTestResult(false, "Hinv does not match"); + } + + if (!recoveredKeyParameters.getParameters().getN().equals(generatedKeyParameters.getParameters().getN())) + { + return new SimpleTestResult(false, "N does not match"); + } + + if (!Arrays.areEqual(recoveredKeyParameters.getParameters().getSeed(), generatedKeyParameters.getParameters().getSeed())) + { + return new SimpleTestResult(false, "Seed does not match"); + } + + return new SimpleTestResult(true, null); + } + catch (Exception t) + { + // Any exception is bad. + return new SimpleTestResult(false, t.getMessage(), t); + } + } + + + private boolean safeEquals(Object left, Object right) + { + if (left == null || right == null) + { + return left == null && right == null; + } + + return left.equals(right); + } + + public TestResult perform() + { + + SimpleTestResult str = encodeDecodePublicLW("Tc26-Gost-3410-12-512-paramSetA", RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512); + if (!str.isSuccessful()) + { + return str; + } + + str = encodeDecodePrivateLW("Tc26-Gost-3410-12-512-paramSetA", RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512); + if (!str.isSuccessful()) + { + return str; + } + + + str = encodeDecodePublicLW("Tc26-Gost-3410-12-256-paramSetA", RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256); + if (!str.isSuccessful()) + { + return str; + } + + str = encodeDecodePrivateLW("Tc26-Gost-3410-12-256-paramSetA", RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256); + if (!str.isSuccessful()) + { + return str; + } + + str = decodeJCEPrivate(); + if (!str.isSuccessful()) + { + return str; + } + + str = decodeJCEPublic(); + if (!str.isSuccessful()) + { + return str; + } + + str = encodeRecodePrivateKey(); + if (!str.isSuccessful()) + { + return str; + } + + str = encodeRecodePublicKey(); + if (!str.isSuccessful()) + { + return str; + } + + + str = encodeRecodePublicKeyGost2006(); + if (!str.isSuccessful()) + { + return str; + } + + str = encodeRecodePrivateKeyGost2006(); + if (!str.isSuccessful()) + { + return str; + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + } + + private class GOST3410_TEST1_512 + implements Test + { + public String getName() + { + return "GOST3410-TEST1-512"; + } + + FixedSecureRandom init_random = new FixedSecureRandom( + new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(Hex.decode("00005EC900007341")), new FixedSecureRandom.Data(zeroTwo(64))}); + FixedSecureRandom random = new TestRandomData(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A")); + FixedSecureRandom keyRandom = new TestRandomData(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046")); + + BigInteger pValue = new BigInteger("EE8172AE8996608FB69359B89EB82A69854510E2977A4D63BC97322CE5DC3386EA0A12B343E9190F23177539845839786BB0C345D165976EF2195EC9B1C379E3", 16); + BigInteger qValue = new BigInteger("98915E7EC8265EDFCDA31E88F24809DDB064BDC7285DD50D7289F0AC6F49DD2D", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("3e5f895e276d81d2d52c0763270a458157b784c57abdbd807bc44fd43a32ac06", 16); + BigInteger s = new BigInteger("3f0dd5d4400d47c08e4ce505ff7434b6dbf729592e37c74856dab85115a60955", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(512, 1, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (params.getValidationParameters() == null) + { + return new SimpleTestResult(false, getName() + "validation parameters wrong"); + } + if (params.getValidationParameters().getC() != 29505 + || params.getValidationParameters().getX0() != 24265) + { + return new SimpleTestResult(false, getName() + "validation parameters values wrong"); + } + if (!init_random.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'init_random'."); + } + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + if (!keyRandom.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'keyRandom'."); + } + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer gost3410 = new GOST3410Signer(); + + gost3410.init(true, param); + + BigInteger[] sig = gost3410.generateSignature(hashmessage); + + if (!random.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'random'."); + } + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + gost3410.init(false, pair.getPublic()); + + if (gost3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_TEST2_512 + implements Test + { + public String getName() + { + return "GOST3410-TEST2-512"; + } + + FixedSecureRandom init_random = new FixedSecureRandom( + new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(Hex.decode("000000003DFC46F1000000000000000D")), new FixedSecureRandom.Data(zeroTwo(64))}); + FixedSecureRandom random = new TestRandomData(Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A")); + FixedSecureRandom keyRandom = new TestRandomData(Hex.decode("3036314538303830343630454235324435324234314132373832433138443046")); + + BigInteger pValue = new BigInteger("8b08eb135af966aab39df294538580c7da26765d6d38d30cf1c06aae0d1228c3316a0e29198460fad2b19dc381c15c888c6dfd0fc2c565abb0bf1faff9518f85", 16); + BigInteger qValue = new BigInteger("931a58fb6f0dcdf2fe7549bc3f19f4724b56898f7f921a076601edb18c93dc75", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("7c07c8cf035c2a1cb2b7fae5807ac7cd623dfca7a1a68f6d858317822f1ea00d", 16); + BigInteger s = new BigInteger("7e9e036a6ff87dbf9b004818252b1f6fc310bdd4d17cb8c37d9c36c7884de60c", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(512, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!init_random.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'init_random'."); + } + + if (params.getValidationParameters() == null) + { + return new SimpleTestResult(false, getName() + ": validation parameters wrong"); + } + + if (params.getValidationParameters().getCL() != 13 + || params.getValidationParameters().getX0L() != 1039943409) + { + return new SimpleTestResult(false, getName() + ": validation parameters values wrong"); + } + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + if (!keyRandom.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'keyRandom'."); + } + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!random.isExhausted()) + { + return new SimpleTestResult(false, getName() + + ": unexpected number of bytes used from 'random'."); + } + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_TEST1_1024 + implements Test + { + public String getName() + { + return "GOST3410-TEST1-1024"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstInt = true; + + public int nextInt() + { + String x0 = "0xA565"; + String c = "0x538B"; + + if (firstInt) + { + firstInt = false; + return NumberParsing.decodeIntFromHex(x0); + } + return NumberParsing.decodeIntFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + + byte[] d = Hex.decode("02"); + + System.arraycopy(d, 0, bytes, bytes.length - d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("ab8f37938356529e871514c1f48c5cbce77b2f4fc9a2673ac2c1653da8984090c0ac73775159a26bef59909d4c9846631270e16653a6234668f2a52a01a39b921490e694c0f104b58d2e14970fccb478f98d01e975a1028b9536d912de5236d2dd2fc396b77153594d4178780e5f16f718471e2111c8ce64a7d7e196fa57142d", 16); + BigInteger qValue = new BigInteger("bcc02ca0ce4f0753ec16105ee5d530aa00d39f3171842ab2c334a26b5f576e0f", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("a8790aabbd5a998ff524bad048ac69cd1faff2dab048265c8d60d1471c44a9ee", 16); + BigInteger s = new BigInteger("30df5ba32ac77170b9632559bef7d37620017756dff3fea1088b4267db0944b8", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 1, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_TEST2_1024 + implements Test + { + public String getName() + { + return "GOST3410-TEST2-1024"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x3DFC46F1"; + String c = "0xD"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + + byte[] d = Hex.decode("02"); + + System.arraycopy(d, 0, bytes, bytes.length - d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("e2c4191c4b5f222f9ac2732562f6d9b4f18e7fb67a290ea1e03d750f0b9806755fc730d975bf3faa606d05c218b35a6c3706919aab92e0c58b1de4531c8fa8e7af43c2bff016251e21b2870897f6a27ac4450bca235a5b748ad386e4a0e4dfcb09152435abcfe48bd0b126a8122c7382f285a9864615c66decddf6afd355dfb7", 16); + BigInteger qValue = new BigInteger("931a58fb6f0dcdf2fe7549bc3f19f4724b56898f7f921a076601edb18c93dc75", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("81d69a192e9c7ac21fc07da41bd07e230ba6a94eb9f3c1fd104c7bd976733ca5", 16); + BigInteger s = new BigInteger("315c879c8414f35feb4deb15e7cc0278c48e6ca1596325d6959338d860b0c47a", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_AParam + implements Test + { + public String getName() + { + return "GOST3410-AParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x520874F5"; + String c = "0xEE39ADB3"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + + byte[] d = Hex.decode("02"); + + System.arraycopy(d, 0, bytes, bytes.length - d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("b4e25efb018e3c8b87505e2a67553c5edc56c2914b7e4f89d23f03f03377e70a2903489dd60e78418d3d851edb5317c4871e40b04228c3b7902963c4b7d85d52b9aa88f2afdbeb28da8869d6df846a1d98924e925561bd69300b9ddd05d247b5922d967cbb02671881c57d10e5ef72d3e6dad4223dc82aa1f7d0294651a480df", 16); + BigInteger qValue = new BigInteger("972432a437178b30bd96195b773789ab2fff15594b176dd175b63256ee5af2cf", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("64a8856628e5669d85f62cd763dd4a99bc56d33dc0e1859122855d141e9e4774", 16); + BigInteger s = new BigInteger("319ebac97092b288d469a4b988248794f60c865bc97858d9a3135c6d1a1bf2dd", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_BParam + implements Test + { + public String getName() + { + return "GOST3410-BParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x5B977CDB"; + String c = "0x6E9692DD"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + byte[] d = Hex.decode("bc3cbbdb7e6f848286e19ad9a27a8e297e5b71c53dd974cdf60f937356df69cbc97a300ccc71685c553046147f11568c4fddf363d9d886438345a62c3b75963d6546adfabf31b31290d12cae65ecb8309ef66782"); + + System.arraycopy(d, 0, bytes, bytes.length - d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("c6971fc57524b30c9018c5e621de15499736854f56a6f8aee65a7a404632b3540f09020f67f04dc2e6783b141dceffd21a703035b7d0187c6e12cb4229922bafdb2225b73e6b23a0de36e20047065aea000c1a374283d0ad8dc1981e3995f0bb8c72526041fcb98ae6163e1e71a669d8364e9c4c3188f673c5f8ee6fadb41abf", 16); + BigInteger qValue = new BigInteger("b09d634c10899cd7d4c3a7657403e05810b07c61a688bab2c37f475e308b0607", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("860d82c60e9502cd00c0e9e1f6563feafec304801974d745c5e02079946f729e", 16); + BigInteger s = new BigInteger("7ef49264ef022801aaa03033cd97915235fbab4c823ed936b0f360c22114688a", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_CParam + implements Test + { + public String getName() + { + return "GOST3410-CParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x43848744"; + String c = "0xB50A826D"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + byte[] d = Hex.decode("7F575E8194BC5BDF"); + + System.arraycopy(d, 0, bytes, bytes.length - d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("9d88e6d7fe3313bd2e745c7cdd2ab9ee4af3c8899e847de74a33783ea68bc30588ba1f738c6aaf8ab350531f1854c3837cc3c860ffd7e2e106c3f63b3d8a4c034ce73942a6c3d585b599cf695ed7a3c4a93b2b947b7157bb1a1c043ab41ec8566c6145e938a611906de0d32e562494569d7e999a0dda5c879bdd91fe124df1e9", 16); + BigInteger qValue = new BigInteger("fadd197abd19a1b4653eecf7eca4d6a22b1f7f893b641f901641fbb555354faf", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("4deb95a0b35e7ed7edebe9bef5a0f93739e16b7ff27fe794d989d0c13159cfbc", 16); + BigInteger s = new BigInteger("e1d0d30345c24cfeb33efde3deee5fbbda78ddc822b719d860cd0ba1fb6bd43b", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_DParam + implements Test + { + public String getName() + { + return "GOST3410-DParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x13DA8B9D"; + String c = "0xA0E9DE4B"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + + byte[] d = Hex.decode("41ab97857f42614355d32db0b1069f109a4da283676c7c53a68185b4"); + + System.arraycopy(d, 0, bytes, bytes.length - d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("80f102d32b0fd167d069c27a307adad2c466091904dbaa55d5b8cc7026f2f7a1919b890cb652c40e054e1e9306735b43d7b279eddf9102001cd9e1a831fe8a163eed89ab07cf2abe8242ac9dedddbf98d62cddd1ea4f5f15d3a42a6677bdd293b24260c0f27c0f1d15948614d567b66fa902baa11a69ae3bceadbb83e399c9b5", 16); + BigInteger qValue = new BigInteger("f0f544c418aac234f683f033511b65c21651a6078bda2d69bb9f732867502149", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("712592d285b792e33b8a9a11e8e6c4f512ddf0042972bbfd1abb0a93e8fc6f54", 16); + BigInteger s = new BigInteger("2cf26758321258b130d5612111339f09ceb8668241f3482e38baa56529963f07", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_AExParam + implements Test + { + public String getName() + { + return "GOST3410-AExParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0xD05E9F14"; + String c = "0x46304C5F"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + byte[] d = Hex.decode("35ab875399cda33c146ca629660e5a5e5c07714ca326db032dd6751995cdb90a612b9228932d8302704ec24a5def7739c5813d83"); + + System.arraycopy(d, 0, bytes, bytes.length - d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("ca3b3f2eee9fd46317d49595a9e7518e6c63d8f4eb4d22d10d28af0b8839f079f8289e603b03530784b9bb5a1e76859e4850c670c7b71c0df84ca3e0d6c177fe9f78a9d8433230a883cd82a2b2b5c7a3306980278570cdb79bf01074a69c9623348824b0c53791d53c6a78cab69e1cfb28368611a397f50f541e16db348dbe5f", 16); + BigInteger qValue = new BigInteger("cae4d85f80c147704b0ca48e85fb00a9057aa4acc44668e17f1996d7152690d9", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("90892707282f433398488f19d31ac48523a8e2ded68944e0da91c6895ee7045e", 16); + BigInteger s = new BigInteger("3be4620ee88f1ee8f9dd63c7d145b7e554839feeca125049118262ea4651e9de", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + public String getName() + { + return "GOST3410"; + } + + private class GOST3410_BExParam + implements Test + { + public String getName() + { + return "GOST3410-BExParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x7A007804"; + String c = "0xD31A4FF7"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + byte[] d = Hex.decode("7ec123d161477762838c2bea9dbdf33074af6d41d108a066a1e7a07ab3048de2"); + + System.arraycopy(d, 0, bytes, bytes.length - d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("9286dbda91eccfc3060aa5598318e2a639f5ba90a4ca656157b2673fb191cd0589ee05f4cef1bd13508408271458c30851ce7a4ef534742bfb11f4743c8f787b11193ba304c0e6bca25701bf88af1cb9b8fd4711d89f88e32b37d95316541bf1e5dbb4989b3df13659b88c0f97a3c1087b9f2d5317d557dcd4afc6d0a754e279", 16); + BigInteger qValue = new BigInteger("c966e9b3b8b7cdd82ff0f83af87036c38f42238ec50a876cd390e43d67b6013f", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("8f79a582513df84dc247bcb624340cc0e5a34c4324a20ce7fe3ab8ff38a9db71", 16); + BigInteger s = new BigInteger("7508d22fd6cbb45efd438cb875e43f137247088d0f54b29a7c91f68a65b5fa85", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } + + private class GOST3410_CExParam + implements Test + { + public String getName() + { + return "GOST3410-CExParam"; + } + + SecureRandom init_random = new SecureRandom() + { + boolean firstLong = true; + + public long nextLong() + { + String x0 = "0x162AB910"; + String c = "0x93F828D3"; + + if (firstLong) + { + firstLong = false; + return NumberParsing.decodeLongFromHex(x0); + } + return NumberParsing.decodeLongFromHex(c); + } + + public void nextBytes(byte[] bytes) + { + byte[] d = Hex.decode("ca82cce78a738bc46f103d53b9bf809745ec845e4f6da462606c51f60ecf302e31204b81"); + + System.arraycopy(d, 0, bytes, bytes.length - d.length, d.length); + } + }; + + SecureRandom random = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] k = Hex.decode("90F3A564439242F5186EBB224C8E223811B7105C64E4F5390807E6362DF4C72A"); + + int i; + + for (i = 0; i < (bytes.length - k.length); i += k.length) + { + System.arraycopy(k, 0, bytes, i, k.length); + } + + if (i > bytes.length) + { + System.arraycopy(k, 0, bytes, i - k.length, bytes.length - (i - k.length)); + } + else + { + System.arraycopy(k, 0, bytes, i, bytes.length - i); + } + } + }; + + SecureRandom keyRandom = new SecureRandom() + { + public void nextBytes(byte[] bytes) + { + byte[] x = Hex.decode("3036314538303830343630454235324435324234314132373832433138443046"); + + int i; + + for (i = 0; i < (bytes.length - x.length); i += x.length) + { + System.arraycopy(x, 0, bytes, i, x.length); + } + + if (i > bytes.length) + { + System.arraycopy(x, 0, bytes, i - x.length, bytes.length - (i - x.length)); + } + else + { + System.arraycopy(x, 0, bytes, i, bytes.length - i); + } + } + }; + + BigInteger pValue = new BigInteger("b194036ace14139d36d64295ae6c50fc4b7d65d8b340711366ca93f383653908ee637be428051d86612670ad7b402c09b820fa77d9da29c8111a8496da6c261a53ed252e4d8a69a20376e6addb3bdcd331749a491a184b8fda6d84c31cf05f9119b5ed35246ea4562d85928ba1136a8d0e5a7e5c764ba8902029a1336c631a1d", 16); + BigInteger qValue = new BigInteger("96120477df0f3896628e6f4a88d83c93204c210ff262bccb7dae450355125259", 16); + + public TestResult perform() + { + BigInteger r = new BigInteger("169fdb2dc09f690b71332432bfec806042e258fa9a21dafe73c6abfbc71407d9", 16); + BigInteger s = new BigInteger("9002551808ae40d19f6f31fb67e4563101243cf07cffd5f2f8ff4c537b0c9866", 16); + GOST3410ParametersGenerator pGen = new GOST3410ParametersGenerator(); + + pGen.init(1024, 2, init_random); + + GOST3410Parameters params = pGen.generateParameters(); + + if (!pValue.equals(params.getP()) || !qValue.equals(params.getQ())) + { + return new SimpleTestResult(false, getName() + ": p or q wrong"); + } + + GOST3410KeyPairGenerator GOST3410KeyGen = new GOST3410KeyPairGenerator(); + GOST3410KeyGenerationParameters genParam = new GOST3410KeyGenerationParameters(keyRandom, params); + + GOST3410KeyGen.init(genParam); + + AsymmetricCipherKeyPair pair = GOST3410KeyGen.generateKeyPair(); + + ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), random); + + GOST3410Signer GOST3410 = new GOST3410Signer(); + + GOST3410.init(true, param); + + BigInteger[] sig = GOST3410.generateSignature(hashmessage); + + if (!r.equals(sig[0])) + { + return new SimpleTestResult(false, getName() + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + return new SimpleTestResult(false, getName() + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + + GOST3410.init(false, pair.getPublic()); + + if (GOST3410.verifySignature(hashmessage, sig[0], sig[1])) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": verification fails"); + } + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3411DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3411DigestTest.java new file mode 100644 index 000000000..6d70e8780 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3411DigestTest.java @@ -0,0 +1,82 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.GOST3411Digest; +import com.fr.third.org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +public class GOST3411DigestTest + extends DigestTest +{ + private static final String[] messages = + { + "", + "This is message, length=32 bytes", + "Suppose the original message has length = 50 bytes", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789" + }; + +// If S-box = D-A (see: digest/GOST3411Digest.java; function: E(byte[] in, byte[] key); string: CipherParameters param = new GOST28147Parameters(key,"D-A");) + private static final String[] digests = + { + "981e5f3ca30c841487830f84fb433e13ac1101569b9c13584ac483234cd656c0", + "2cefc2f7b7bdc514e18ea57fa74ff357e7fa17d652c75f69cb1be7893ede48eb", + "c3730c5cbccacf915ac292676f21e8bd4ef75331d9405e5f1a61dc3130a65011", + "73b70a39497de53a6e08c67b6d4db853540f03e9389299d9b0156ef7e85d0f61" + }; + +// If S-box = D-Test (see: digest/GOST3411Digest.java; function:E(byte[] in, byte[] key); string: CipherParameters param = new GOST28147Parameters(key,"D-Test");) +// private static final String[] digests = +// { +// "ce85b99cc46752fffee35cab9a7b0278abb4c2d2055cff685af4912c49490f8d", +// "b1c466d37519b82e8319819ff32595e047a28cb6f83eff1c6916a815a637fffa", +// "471aba57a60a770d3a76130635c1fbea4ef14de51f78b4ae57dd893b62f55208", +// "95c1af627c356496d80274330b2cff6a10c67b5f597087202f94d06d2338cf8e" +// }; + + // 1 million 'a' + static private String million_a_digest = "8693287aa62f9478f7cb312ec0866b6c4e4a0f11160441e8f4ffcd2715dd554f"; + + GOST3411DigestTest() + { + super(new GOST3411Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + + HMac gMac = new HMac(new GOST3411Digest()); + + gMac.init(new KeyParameter(PKCS5S1ParametersGenerator.PKCS5PasswordToUTF8Bytes("1".toCharArray()))); + + byte[] data = Strings.toByteArray("fred"); + + gMac.update(data, 0, data.length); + byte[] mac = new byte[gMac.getMacSize()]; + + gMac.doFinal(mac, 0); + + if (!Arrays.areEqual(Hex.decode("e9f98610cfc80084462b175a15d2b4ec10b2ab892eae5a6179d572d9b1db6b72"), mac)) + { + fail("mac calculation failed."); + } + } + + protected Digest cloneDigest(Digest digest) + { + return new GOST3411Digest((GOST3411Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new GOST3411DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3411_2012_256DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3411_2012_256DigestTest.java new file mode 100644 index 000000000..4501d13ed --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3411_2012_256DigestTest.java @@ -0,0 +1,90 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.util.ArrayList; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.GOST3411_2012_256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.GOST3411_2012_512Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +public class GOST3411_2012_256DigestTest + extends DigestTest +{ + private static final String[] messages; + + private static char[] M1 = + { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x30, 0x31, 0x32 + }; + + private static char[] M2= + { + 0xd1,0xe5,0x20,0xe2,0xe5,0xf2,0xf0,0xe8,0x2c,0x20,0xd1,0xf2,0xf0,0xe8,0xe1,0xee,0xe6,0xe8,0x20,0xe2, + 0xed,0xf3,0xf6,0xe8,0x2c,0x20,0xe2,0xe5,0xfe,0xf2,0xfa,0x20,0xf1,0x20,0xec,0xee,0xf0,0xff,0x20,0xf1, + 0xf2,0xf0,0xe5,0xeb,0xe0,0xec,0xe8,0x20,0xed,0xe0,0x20,0xf5,0xf0,0xe0,0xe1,0xf0,0xfb,0xff,0x20,0xef, + 0xeb,0xfa,0xea,0xfb,0x20,0xc8,0xe3,0xee,0xf0,0xe5,0xe2,0xfb + }; + + static + { + + ArrayList strList = new ArrayList(); + + strList.add(new String(M1)); + strList.add(new String(M2)); + + messages = new String[strList.size()]; + for (int i = 0; i < strList.size(); i++) + { + messages[i] = (String)strList.get(i); + } + } + + private static final String[] digests = { + "9d151eefd8590b89daa6ba6cb74af9275dd051026bb149a452fd84e5e57b5500", + "9dd2fe4e90409e5da87f53976d7405b0c0cac628fc669a741d50063c557e8f50" + }; + + GOST3411_2012_256DigestTest() + { + super(new GOST3411_2012_256Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + HMac gMac = new HMac(new GOST3411_2012_256Digest()); + + gMac.init(new KeyParameter(Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"))); + + byte[] data = Hex.decode("0126bdb87800af214341456563780100"); + + gMac.update(data, 0, data.length); + byte[] mac = new byte[gMac.getMacSize()]; + + gMac.doFinal(mac, 0); + + if (!Arrays.areEqual(Hex.decode("a1aa5f7de402d7b3d323f2991c8d4534013137010a83754fd0af6d7cd4922ed9"), mac)) + { + fail("mac calculation failed."); + } + } + + protected Digest cloneDigest(Digest digest) + { + return new GOST3411_2012_256Digest((GOST3411_2012_256Digest)digest); + } + + public static void main(String[] args) + { + runTest(new GOST3411_2012_256DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3411_2012_512DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3411_2012_512DigestTest.java new file mode 100644 index 000000000..cbe20a666 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3411_2012_512DigestTest.java @@ -0,0 +1,89 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.util.ArrayList; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.GOST3411Digest; +import com.fr.third.org.bouncycastle.crypto.digests.GOST3411_2012_512Digest; +import com.fr.third.org.bouncycastle.crypto.generators.PKCS5S1ParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +public class GOST3411_2012_512DigestTest + extends DigestTest +{ + private static final String[] messages; + + private static char[] M1 = + { + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, + 0x30, 0x31, 0x32 + }; + + private static char[] M2= + { + 0xd1,0xe5,0x20,0xe2,0xe5,0xf2,0xf0,0xe8,0x2c,0x20,0xd1,0xf2,0xf0,0xe8,0xe1,0xee,0xe6,0xe8,0x20,0xe2, + 0xed,0xf3,0xf6,0xe8,0x2c,0x20,0xe2,0xe5,0xfe,0xf2,0xfa,0x20,0xf1,0x20,0xec,0xee,0xf0,0xff,0x20,0xf1, + 0xf2,0xf0,0xe5,0xeb,0xe0,0xec,0xe8,0x20,0xed,0xe0,0x20,0xf5,0xf0,0xe0,0xe1,0xf0,0xfb,0xff,0x20,0xef, + 0xeb,0xfa,0xea,0xfb,0x20,0xc8,0xe3,0xee,0xf0,0xe5,0xe2,0xfb + }; + + static + { + ArrayList strList = new ArrayList(); + + strList.add(new String(M1)); + strList.add(new String(M2)); + messages = new String[strList.size()]; + for (int i = 0; i < strList.size(); i++) + { + messages[i] = (String)strList.get(i); + } + } + + private static final String[] digests = { + "1b54d01a4af5b9d5cc3d86d68d285462b19abc2475222f35c085122be4ba1ffa00ad30f8767b3a82384c6574f024c311e2a481332b08ef7f41797891c1646f48", + "1e88e62226bfca6f9994f1f2d51569e0daf8475a3b0fe61a5300eee46d961376035fe83549ada2b8620fcd7c496ce5b33f0cb9dddc2b6460143b03dabac9fb28", + }; + + public GOST3411_2012_512DigestTest() + { + super(new GOST3411_2012_512Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + HMac gMac = new HMac(new GOST3411_2012_512Digest()); + + gMac.init(new KeyParameter(Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"))); + + byte[] data = Hex.decode("0126bdb87800af214341456563780100"); + + gMac.update(data, 0, data.length); + byte[] mac = new byte[gMac.getMacSize()]; + + gMac.doFinal(mac, 0); + + if (!Arrays.areEqual(Hex.decode("a59bab22ecae19c65fbde6e5f4e9f5d8549d31f037f9df9b905500e171923a773d5f1530f2ed7e964cb2eedc29e9ad2f3afe93b2814f79f5000ffc0366c251e6"), mac)) + { + fail("mac calculation failed."); + } + } + + protected Digest cloneDigest(Digest digest) + { + return new GOST3411_2012_512Digest((GOST3411_2012_512Digest)digest); + } + + public static void main(String[] args) + { + runTest(new GOST3411_2012_512DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3412MacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3412MacTest.java new file mode 100644 index 000000000..94902617b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3412MacTest.java @@ -0,0 +1,71 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.engines.GOST3412_2015Engine; +import com.fr.third.org.bouncycastle.crypto.macs.CMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * see GOST_R_3413-2015 + */ +public class GOST3412MacTest + implements Test +{ + + public String getName() + { + return "GOST 3412 2015 MAC test"; + } + + public TestResult perform() + { + + + byte[][] inputs = new byte[][]{ + Hex.decode("1122334455667700ffeeddccbbaa9988"), + Hex.decode("00112233445566778899aabbcceeff0a"), + Hex.decode("112233445566778899aabbcceeff0a00"), + Hex.decode("2233445566778899aabbcceeff0a0011"), + }; + Mac mac = new CMac(new GOST3412_2015Engine(), 64); + + byte[] output = Hex.decode("336f4d296059fbe3"); + + KeyParameter key = + new KeyParameter(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")); + mac.init(key); + + for (int i = 0; i != inputs.length; i++) + { + mac.update(inputs[i], 0, inputs[i].length); + } + + byte[] out = new byte[8]; + + mac.doFinal(out, 0); + + if (!Arrays.areEqual(out, output)) + { + return new SimpleTestResult(false, getName() + ": Failed test 1 - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + + } + + + public static void main(String[] args) + { + GOST3412MacTest test = new GOST3412MacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } + + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3412Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3412Test.java new file mode 100644 index 000000000..197269812 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GOST3412Test.java @@ -0,0 +1,99 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.GOST3412_2015Engine; +import com.fr.third.org.bouncycastle.crypto.modes.G3413CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.G3413CFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.G3413CTRBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.G3413OFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class GOST3412Test + extends CipherTest +{ + + private byte[][] inputs = new byte[][]{ + Hex.decode("1122334455667700ffeeddccbbaa9988"), + Hex.decode("00112233445566778899aabbcceeff0a"), + Hex.decode("112233445566778899aabbcceeff0a00"), + Hex.decode("2233445566778899aabbcceeff0a0011") + }; + + + static SimpleTest[] tests = { + +// ECB + new BlockCipherVectorTest(1, new GOST3412_2015Engine(), + new KeyParameter(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")), + "1122334455667700ffeeddccbbaa9988", "7f679d90bebc24305a468d42b9d4edcd"), + + // CFB + new BlockCipherVectorTest(2, new G3413CFBBlockCipher(new GOST3412_2015Engine()), + new ParametersWithIV(new KeyParameter(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")), + Hex.decode("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819")), + "1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011", + "81800a59b1842b24ff1f795e897abd95ed5b47a7048cfab48fb521369d9326bf79f2a8eb5cc68d38842d264e97a238b54ffebecd4e922de6c75bd9dd44fbf4d1"), + + new BlockCipherVectorTest(3, new G3413CFBBlockCipher(new GOST3412_2015Engine(), 8), + new ParametersWithIV( + new KeyParameter(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")), + Hex.decode("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819")), + "1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011", + "819b19c5867e61f1cf1b16f664f66e46ed8fcb82b1110b1e7ec03bfa6611f2eabd7a32363691cbdc3bbe403bc80552d822c2cdf483981cd71d5595453d7f057d"), + + // OFB + new BlockCipherVectorTest(4, new G3413OFBBlockCipher(new GOST3412_2015Engine()), + new ParametersWithIV( + new KeyParameter(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")), + Hex.decode("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819")), + "1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011", + "81800a59b1842b24ff1f795e897abd95ed5b47a7048cfab48fb521369d9326bf66a257ac3ca0b8b1c80fe7fc10288a13203ebbc066138660a0292243f6903150"), + +//CBC + new BlockCipherVectorTest(5, new G3413CBCBlockCipher(new GOST3412_2015Engine()), + new ParametersWithIV(new KeyParameter(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")), Hex.decode("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819")), + "1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011", + "689972d4a085fa4d90e52e3d6d7dcc272826e661b478eca6af1e8e448d5ea5acfe7babf1e91999e85640e8b0f49d90d0167688065a895c631a2d9a1560b63970"), +//CTR + new BlockCipherVectorTest(6, new G3413CTRBlockCipher(new GOST3412_2015Engine()), + new ParametersWithIV(new KeyParameter(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")), + Hex.decode("1234567890abcef0")), + "1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011", + "f195d8bec10ed1dbd57b5fa240bda1b885eee733f6a13e5df33ce4b33c45dee4a5eae88be6356ed3d5e877f13564a3a5cb91fab1f20cbab6d1c6d15820bdba73"), + new BlockCipherVectorTest(7, new G3413CTRBlockCipher(new GOST3412_2015Engine(), 8), + new ParametersWithIV(new KeyParameter(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef")), + Hex.decode("1234567890abcef0")), + "1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011", + "f1a787ad3a88f9a0bc735293f98c12c3eb31621b9b2e6461c7ef73a2e6a6b1793ddf722f7b1d22a722ec4d3edbc313bcd356b313d37af9e5ef934fa223c13fe2") + + + }; + + + protected GOST3412Test() + { + super(tests, new GOST3412_2015Engine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "GOST 34.12 2015"; + } + + public void performTest() + throws Exception + { + super.performTest(); + +// cfbTest(); +// ofbTest(); + } + + public static void main( + String[] args) + { + runTest(new GOST3412Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GSKKDFTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GSKKDFTest.java new file mode 100644 index 000000000..1c810532a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/GSKKDFTest.java @@ -0,0 +1,63 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.agreement.kdf.GSKKDFParameters; +import com.fr.third.org.bouncycastle.crypto.agreement.kdf.GSKKFDGenerator; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class GSKKDFTest + extends SimpleTest +{ + public String getName() + { + return "GSKKDFTest"; + } + + public void performTest() + throws Exception + { + GSKKFDGenerator gen = new GSKKFDGenerator(new SHA256Digest()); + + byte[] key = new byte[16]; + + gen.init(new GSKKDFParameters(Hex.decode("0102030405060708090a"), 1, Hex.decode("27252622"))); + + gen.generateBytes(key, 0, key.length); + areEqual(Hex.decode("bd9ff24b9cc4d91b70af951989b4d719"), key); + + gen.generateBytes(key, 0, key.length); + areEqual(Hex.decode("d5934f681ad1e860981eb1792af68e20"), key); + + gen = new GSKKFDGenerator(new SHA256Digest()); + + gen.init(new GSKKDFParameters(Hex.decode("0102030405060708090a"), 2, Hex.decode("27252622"))); + + gen.generateBytes(key, 0, key.length); + areEqual(Hex.decode("d5934f681ad1e860981eb1792af68e20"), key); + + gen.init(new GSKKDFParameters(Hex.decode("0102030405060708090a"), 1)); + + gen.generateBytes(key, 0, key.length); + areEqual(Hex.decode("3c6e999b2cb08d8d8dd261cd23f15ed6"), key); + + gen.generateBytes(key, 0, key.length); + areEqual(Hex.decode("019ce1fcf81b94602f2f8678be905e0e"), key); + + try + { + gen.generateBytes(key, 1, key.length); + } + catch (DataLengthException e) + { + isEquals("output buffer too small", e.getMessage()); + } + } + + public static void main( + String[] args) + { + runTest(new GSKKDFTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Grain128Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Grain128Test.java new file mode 100644 index 000000000..02a902066 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Grain128Test.java @@ -0,0 +1,117 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.engines.Grain128Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Grain-128 Test + */ +public class Grain128Test + extends SimpleTest +{ + + String keyStream1 = "f09b7bf7d7f6b5c2de2ffc73ac21397f"; + String keyStream2 = "afb5babfa8de896b4b9c6acaf7c4fbfd"; + + public String getName() + { + return "Grain-128"; + } + + public void performTest() + { + Grain128Test1(new ParametersWithIV(new KeyParameter(Hex + .decode("00000000000000000000000000000000")), Hex + .decode("000000000000000000000000"))); + Grain128Test2(new ParametersWithIV(new KeyParameter(Hex + .decode("0123456789abcdef123456789abcdef0")), Hex + .decode("0123456789abcdef12345678"))); + Grain128Test3(new ParametersWithIV(new KeyParameter(Hex + .decode("0123456789abcdef123456789abcdef0")), Hex + .decode("0123456789abcdef12345678"))); + } + + private void Grain128Test1(CipherParameters params) + { + StreamCipher grain = new Grain128Engine(); + byte[] in = new byte[16]; + byte[] out = new byte[16]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream1))) + { + mismatch("Keystream 1", keyStream1, out); + } + + grain.reset(); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream1))) + { + mismatch("Keystream 1", keyStream1, out); + } + } + + private void Grain128Test2(CipherParameters params) + { + StreamCipher grain = new Grain128Engine(); + byte[] in = new byte[16]; + byte[] out = new byte[16]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream2))) + { + mismatch("Keystream 2", keyStream2, out); + } + + grain.reset(); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream2))) + { + mismatch("Keystream 2", keyStream2, out); + } + } + + private void Grain128Test3(CipherParameters params) + { + StreamCipher grain = new Grain128Engine(); + byte[] in = "Encrypt me!".getBytes(); + byte[] cipher = new byte[in.length]; + byte[] clear = new byte[in.length]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, cipher, 0); + grain.reset(); + grain.processBytes(cipher, 0, cipher.length, clear, 0); + + if (!areEqual(in, clear)) + { + mismatch("Test 3", new String(Hex.encode(in)), clear); + } + } + + private void mismatch(String name, String expected, byte[] found) + { + fail("mismatch on " + name, expected, new String(Hex.encode(found))); + } + + public static void main(String[] args) + { + runTest(new Grain128Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Grainv1Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Grainv1Test.java new file mode 100644 index 000000000..1b6a8ad92 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Grainv1Test.java @@ -0,0 +1,140 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.engines.Grainv1Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Grain v1 Test + */ +public class Grainv1Test + extends SimpleTest +{ + + String keyStream1 = "dee931cf1662a72f77d0"; + String keyStream2 = "7f362bd3f7abae203664"; + String keyStream4 = "017D13ECB20AE0C9ACF784CB06525F72" + + "CE6D52BEBB948F124668C35064559024" + + "49EEA505C19F3EE4D052C3D19DA9C4D1" + + "B92DBC7F07AFEA6A3D845DE60D8471FD"; + + public String getName() + { + return "Grain v1"; + } + + public void performTest() + { + Grainv1Test1(new ParametersWithIV(new KeyParameter(Hex + .decode("00000000000000000000")), Hex + .decode("0000000000000000"))); + Grainv1Test2(new ParametersWithIV(new KeyParameter(Hex + .decode("0123456789abcdef1234")), Hex + .decode("0123456789abcdef"))); + Grainv1Test3(new ParametersWithIV(new KeyParameter(Hex + .decode("0123456789abcdef1234")), Hex + .decode("0123456789abcdef"))); + Grainv1Test4(new ParametersWithIV(new KeyParameter(Hex + .decode("0F62B5085BAE0154A7FA")), Hex + .decode("288FF65DC42B92F9"))); + } + + private void Grainv1Test1(CipherParameters params) + { + StreamCipher grain = new Grainv1Engine(); + byte[] in = new byte[10]; + byte[] out = new byte[10]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream1))) + { + mismatch("Keystream 1", keyStream1, out); + } + + grain.reset(); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream1))) + { + mismatch("Keystream 1", keyStream1, out); + } + } + + private void Grainv1Test2(CipherParameters params) + { + StreamCipher grain = new Grainv1Engine(); + byte[] in = new byte[10]; + byte[] out = new byte[10]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream2))) + { + mismatch("Keystream 2", keyStream2, out); + } + + grain.reset(); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream2))) + { + mismatch("Keystream 2", keyStream2, out); + } + } + + private void Grainv1Test3(CipherParameters params) + { + StreamCipher grain = new Grainv1Engine(); + byte[] in = "Encrypt me!".getBytes(); + byte[] cipher = new byte[in.length]; + byte[] clear = new byte[in.length]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, cipher, 0); + grain.reset(); + grain.processBytes(cipher, 0, cipher.length, clear, 0); + + if (!areEqual(in, clear)) + { + mismatch("Test 3", new String(Hex.encode(in)), clear); + } + } + + private void Grainv1Test4(CipherParameters params) + { + StreamCipher grain = new Grainv1Engine(); + byte[] in = new byte[keyStream4.length() / 2]; + byte[] out = new byte[in.length]; + + grain.init(true, params); + + grain.processBytes(in, 0, in.length, out, 0); + + if (!areEqual(out, Hex.decode(keyStream4))) + { + mismatch("Keystream 4", keyStream4, out); + } + } + + private void mismatch(String name, String expected, byte[] found) + { + fail("mismatch on " + name, expected, new String(Hex.encode(found))); + } + + public static void main(String[] args) + { + runTest(new Grainv1Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HCFamilyTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HCFamilyTest.java new file mode 100644 index 000000000..b4d7f2bf5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HCFamilyTest.java @@ -0,0 +1,192 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.engines.HC128Engine; +import com.fr.third.org.bouncycastle.crypto.engines.HC256Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * HC-128 and HC-256 Tests. Based on the test vectors in the official reference + * papers, respectively: + *

+ * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf
+ * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf
+ * 
+ * See HCFamilyVecTest for a more exhaustive test based on the ecrypt vectors. + */ +public class HCFamilyTest + extends SimpleTest +{ + private static final byte[] MSG = new byte[64]; + + private static String[][] HC128_VerifiedTest = + { + { + "Set 2, vector# 0", + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "82001573A003FD3B7FD72FFB0EAF63AA" + + "C62F12DEB629DCA72785A66268EC758B" + + "1EDB36900560898178E0AD009ABF1F49" + + "1330DC1C246E3D6CB264F6900271D59C" + }, + { + "Set 6, vector# 0", + "0053A6F94C9FF24598EB3E91E4378ADD", + "0D74DB42A91077DE45AC137AE148AF16", + "2E1ED12A8551C05AF41FF39D8F9DF933" + + "122B5235D48FC2A6F20037E69BDBBCE8" + + "05782EFC16C455A4B3FF06142317535E" + + "F876104C32445138CB26EBC2F88A684C" + }, + { + "Set 6, vector# 1", + "0558ABFE51A4F74A9DF04396E93C8FE2", + "167DE44BB21980E74EB51C83EA51B81F", + "4F864BF3C96D0363B1903F0739189138" + + "F6ED2BC0AF583FEEA0CEA66BA7E06E63" + + "FB28BF8B3CA0031D24ABB511C57DD17B" + + "FC2861C32400072CB680DF2E58A5CECC" + }, + { + "Set 6, vector# 2", + "0A5DB00356A9FC4FA2F5489BEE4194E7", + "1F86ED54BB2289F057BE258CF35AC128", + "82168AB0023B79AAF1E6B4D823855E14" + + "A7084378036A951B1CFEF35173875ED8" + + "6CB66AB8410491A08582BE40080C3102" + + "193BA567F9E95D096C3CC60927DD7901" + }, + { + "Set 6, vector# 3", + "0F62B5085BAE0154A7FA4DA0F34699EC", + "288FF65DC42B92F960C72E95FC63CA31", + "1CD8AEDDFE52E217E835D0B7E84E2922" + + "D04B1ADBCA53C4522B1AA604C42856A9" + + "0AF83E2614BCE65C0AECABDD8975B557" + + "00D6A26D52FFF0888DA38F1DE20B77B7" + } + }; + + private static String[][] HC256_VerifiedTest = + { + { + "Set 2, vector# 0", + "00000000000000000000000000000000", + "00000000000000000000000000000000", + "5B078985D8F6F30D42C5C02FA6B67951" + + "53F06534801F89F24E74248B720B4818" + + "CD9227ECEBCF4DBF8DBF6977E4AE14FA" + + "E8504C7BC8A9F3EA6C0106F5327E6981" + }, + { + "Set 2, vector# 9", + "09090909090909090909090909090909", + "00000000000000000000000000000000", + "F5C2926651AEED9AF1A9C2F04C03D081" + + "2145B56AEA46EB283A25A4C9E3D8BEB4" + + "821B418F06F2B9DCDF1A85AB8C02CD14" + + "62E1BBCAEC9AB0E99AA6AFF918BA627C" + }, + { + "Set 2, vector#135", + "87878787878787878787878787878787", + "00000000000000000000000000000000", + "CEC0C3852E3B98233EBCB975C10B1191" + + "3C69F2275EB97A1402EDF16C6FBE19BE" + + "79D65360445BCB63676E6553B609A065" + + "0155C3B22DD1975AC0F3F65063A2E16E" + }, + { + "Set 6, vector# 0", + "0053A6F94C9FF24598EB3E91E4378ADD" + + "3083D6297CCF2275C81B6EC11467BA0D", + "0D74DB42A91077DE45AC137AE148AF16" + + "7DE44BB21980E74EB51C83EA51B81F86", + "23D9E70A45EB0127884D66D9F6F23C01" + + "D1F88AFD629270127247256C1FFF91E9" + + "1A797BD98ADD23AE15BEE6EEA3CEFDBF" + + "A3ED6D22D9C4F459DB10C40CDF4F4DFF" + }, + { + "Set 6, vector# 1", + "0558ABFE51A4F74A9DF04396E93C8FE2" + + "3588DB2E81D4277ACD2073C6196CBF12", + "167DE44BB21980E74EB51C83EA51B81F" + + "86ED54BB2289F057BE258CF35AC1288F", + "C44B5262F2EAD9C018213127686DB742" + + "A72D3F2D61D18F0F4E7DE5B4F7ADABE0" + + "7E0C82033B139F02BAACB4E2F2D0BE30" + + "110C3A8A2B621523756692877C905DD0" + }, + { + "Set 6, vector# 2", + "0A5DB00356A9FC4FA2F5489BEE4194E7" + + "3A8DE03386D92C7FD22578CB1E71C417", + "1F86ED54BB2289F057BE258CF35AC128" + + "8FF65DC42B92F960C72E95FC63CA3198", + "9D13AA06122F4F03AE60D507701F1ED0" + + "63D7530FF35EE76CAEDCBFB01D8A239E" + + "FA4A44B272DE9B4092E2AD56E87C3A60" + + "89F5A074D1F6E5B8FC6FABEE0C936F06" + }, + { + "Set 6, vector# 3", + "0F62B5085BAE0154A7FA4DA0F34699EC" + + "3F92E5388BDE3184D72A7DD02376C91C", + "288FF65DC42B92F960C72E95FC63CA31" + + "98FF66CD349B0269D0379E056CD33AA1", + "C8632038DA61679C4685288B37D3E232" + + "7BC2D28C266B041FE0CA0D3CFEED8FD5" + + "753259BAB757168F85EA96ADABD823CA" + + "4684E918423E091565713FEDDE2CCFE0" + } + }; + + public String getName() + { + return "HC-128 and HC-256"; + } + + public void performTest() + { + StreamCipher hc = new HC256Engine(); + + for (int i = 0; i != HC256_VerifiedTest.length; i++) + { + String[] test = HC256_VerifiedTest[i]; + HCTest(hc, "HC-256 - " + test[0], Hex.decode(test[1]), Hex.decode(test[2]), Hex.decode(test[3])); + } + + hc = new HC128Engine(); + + for (int i = 0; i != HC128_VerifiedTest.length; i++) + { + String[] test = HC128_VerifiedTest[i]; + HCTest(hc, "HC-128 - " + test[0], Hex.decode(test[1]), Hex.decode(test[2]), Hex.decode(test[3])); + } + } + + private void HCTest(StreamCipher hc, String test, byte[] key, byte[] IV, byte[] expected) + { + KeyParameter kp = new KeyParameter(key); + ParametersWithIV ivp = new ParametersWithIV(kp, IV); + + hc.init(true, ivp); + for (int i = 0; i < 64; i++) + { + if (hc.returnByte(MSG[i]) != expected[i]) + { + fail(test + " failure at byte " + i); + } + } + } + + public static void main(String[] args) + { + runTest(new HCFamilyTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HCFamilyVecTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HCFamilyVecTest.java new file mode 100644 index 000000000..3e886ba2d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HCFamilyVecTest.java @@ -0,0 +1,199 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.engines.HC128Engine; +import com.fr.third.org.bouncycastle.crypto.engines.HC256Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * HC-128 and HC-256 Tests. Based on the test vectors in the official reference + * papers, respectively: + * + * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc128_p3.pdf + * http://www.ecrypt.eu.org/stream/p3ciphers/hc/hc256_p3.pdf + */ +public class HCFamilyVecTest + extends SimpleTest +{ + private static class PeekableLineReader extends BufferedReader + { + public PeekableLineReader(Reader r) throws IOException + { + super(r); + + peek = super.readLine(); + } + + public String peekLine() + { + return peek; + } + + public String readLine() throws IOException + { + String tmp = peek; + peek = super.readLine(); + return tmp; + } + + private String peek; + } + + public String getName() + { + return "HC-128 and HC-256 (ecrypt)"; + } + + public void performTest() throws Exception + { + runTests(new HC128Engine(), "ecrypt_HC-128.txt"); + runTests(new HC256Engine(), "ecrypt_HC-256_128K_128IV.txt"); + runTests(new HC256Engine(), "ecrypt_HC-256_256K_128IV.txt"); + runTests(new HC256Engine(), "ecrypt_HC-256_128K_256IV.txt"); + runTests(new HC256Engine(), "ecrypt_HC-256_256K_256IV.txt"); + } + + private void runTests(StreamCipher hc, String fileName) throws IOException + { + Reader resource = new InputStreamReader(getClass().getResourceAsStream(fileName)); + PeekableLineReader r = new PeekableLineReader(resource); + runAllVectors(hc, fileName, r); + } + + private void runAllVectors(StreamCipher hc, String fileName, PeekableLineReader r) + throws IOException + { + for (;;) + { + String line = r.readLine(); + if (line == null) + { + break; + } + + line = line.trim(); + + if (line.startsWith("Set ")) + { + runVector(hc, fileName, r, dellChar(line, ':')); + } + } + } + + private String dellChar(String s, char c) + { + StringBuffer b = new StringBuffer(); + + for (int i = 0; i != s.length(); i++) + { + if (s.charAt(i) != c) + { + b.append(s.charAt(i)); + } + } + + return b.toString(); + } + + private void runVector(StreamCipher hc, String fileName, PeekableLineReader r, String vectorName) + throws IOException + { +// System.out.println(fileName + " => " + vectorName); + String hexKey = readBlock(r); + String hexIV = readBlock(r); + + CipherParameters cp = new KeyParameter(Hex.decode(hexKey)); + cp = new ParametersWithIV(cp, Hex.decode(hexIV)); + hc.init(true, cp); + + byte[] input = new byte[64]; + byte[] output = new byte[64]; + byte[] digest = new byte[64]; + int pos = 0; + + for (;;) + { + String line1 = r.peekLine().trim(); + int equalsPos = line1.indexOf('='); + String lead = line1.substring(0, equalsPos - 1); + + String hexData = readBlock(r); + byte[] data = Hex.decode(hexData); + + if (lead.equals("xor-digest")) + { + if (!Arrays.areEqual(data, digest)) + { + fail("Failed in " + fileName + " for test vector: " + vectorName + " at " + lead); +// System.out.println(fileName + " => " + vectorName + " failed at " + lead); return; + } + break; + } + + int posA = lead.indexOf('['); + int posB = lead.indexOf(".."); + int posC = lead.indexOf(']'); + int start = Integer.parseInt(lead.substring(posA + 1, posB)); + int end = Integer.parseInt(lead.substring(posB + 2, posC)); + + if (start % 64 != 0 || (end - start != 63)) + { + throw new IllegalStateException(vectorName + ": " + lead + " not on 64 byte boundaries"); + } + + while (pos < end) + { + hc.processBytes(input, 0, input.length, output, 0); + xor(digest, output); + pos += 64; + } + + if (!Arrays.areEqual(data, output)) + { + fail("Failed in " + fileName + " for test vector: " + vectorName + " at " + lead); +// System.out.println(fileName + " => " + vectorName + " failed at " + lead); return; + } + } + } + + private static String readBlock(PeekableLineReader r) throws IOException + { + String first = r.readLine().trim(); + String result = first.substring(first.lastIndexOf(' ') + 1); + + for (;;) + { + String peek = r.peekLine().trim(); + if (peek.length() < 1 || peek.indexOf('=') >= 0) + { + break; + } + result += r.readLine().trim(); + } + + return result; + } + + private static void xor(byte[] digest, byte[] block) + { + for (int i = 0; i < digest.length; ++i) + { + digest[i] ^= block[i]; + } + } + + public static void main(String[] args) + { + runTest(new HCFamilyVecTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HKDFGeneratorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HKDFGeneratorTest.java new file mode 100644 index 000000000..83c596f57 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HKDFGeneratorTest.java @@ -0,0 +1,304 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.generators.HKDFBytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.HKDFParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * HKDF tests - vectors from RFC 5869, + 2 more, 101 and 102 + */ +public class HKDFGeneratorTest + extends SimpleTest +{ + + public HKDFGeneratorTest() + { + } + + private void compareOKM(int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!areEqual(calculatedOKM, testOKM)) + { + fail("HKDF failed generator test " + test); + } + } + + public void performTest() + { + { + // === A.1. Test Case 1 - Basic test case with SHA-256 === + + Digest hash = new SHA256Digest(); + byte[] ikm = Hex + .decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); + byte[] salt = Hex.decode("000102030405060708090a0b0c"); + byte[] info = Hex.decode("f0f1f2f3f4f5f6f7f8f9"); + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(1, okm, Hex.decode( + "3cb25f25faacd57a90434f64d0362f2a" + + "2d2d0a90cf1a5a4c5db02d56ecc4c5bf" + + "34007208d5b887185865")); + } + + // === A.2. Test Case 2 - Test with SHA-256 and longer inputs/outputs + // === + { + Digest hash = new SHA256Digest(); + byte[] ikm = Hex.decode("000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f" + + "404142434445464748494a4b4c4d4e4f"); + byte[] salt = Hex.decode("606162636465666768696a6b6c6d6e6f" + + "707172737475767778797a7b7c7d7e7f" + + "808182838485868788898a8b8c8d8e8f" + + "909192939495969798999a9b9c9d9e9f" + + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"); + byte[] info = Hex.decode("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); + int l = 82; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(2, okm, Hex.decode( + "b11e398dc80327a1c8e7f78c596a4934" + + "4f012eda2d4efad8a050cc4c19afa97c" + + "59045a99cac7827271cb41c65e590e09" + + "da3275600c2f09b8367793a9aca3db71" + + "cc30c58179ec3e87c14c01d5c1f3434f" + + "1d87")); + } + + { + // === A.3. Test Case 3 - Test with SHA-256 and zero-length + // salt/info === + + // setting salt to an empty byte array means that the salt is set to + // HashLen zero valued bytes + // setting info to null generates an empty byte array as info + // structure + + Digest hash = new SHA256Digest(); + byte[] ikm = Hex + .decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); + byte[] salt = new byte[0]; + byte[] info = null; + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(3, okm, Hex.decode( + "8da4e775a563c18f715f802a063c5a31" + + "b8a11f5c5ee1879ec3454e5f3c738d2d" + + "9d201395faa4b61a96c8")); + } + + { + // === A.4. Test Case 4 - Basic test case with SHA-1 === + + Digest hash = new SHA1Digest(); + byte[] ikm = Hex.decode("0b0b0b0b0b0b0b0b0b0b0b"); + byte[] salt = Hex.decode("000102030405060708090a0b0c"); + byte[] info = Hex.decode("f0f1f2f3f4f5f6f7f8f9"); + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(4, okm, Hex.decode( + "085a01ea1b10f36933068b56efa5ad81" + + "a4f14b822f5b091568a9cdd4f155fda2" + + "c22e422478d305f3f896")); + } + + // === A.5. Test Case 5 - Test with SHA-1 and longer inputs/outputs === + { + Digest hash = new SHA1Digest(); + byte[] ikm = Hex.decode("000102030405060708090a0b0c0d0e0f" + + "101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f" + + "404142434445464748494a4b4c4d4e4f"); + byte[] salt = Hex.decode("606162636465666768696a6b6c6d6e6f" + + "707172737475767778797a7b7c7d7e7f" + + "808182838485868788898a8b8c8d8e8f" + + "909192939495969798999a9b9c9d9e9f" + + "a0a1a2a3a4a5a6a7a8a9aaabacadaeaf"); + byte[] info = Hex.decode("b0b1b2b3b4b5b6b7b8b9babbbcbdbebf" + + "c0c1c2c3c4c5c6c7c8c9cacbcccdcecf" + + "d0d1d2d3d4d5d6d7d8d9dadbdcdddedf" + + "e0e1e2e3e4e5e6e7e8e9eaebecedeeef" + + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff"); + int l = 82; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(5, okm, Hex.decode( + "0bd770a74d1160f7c9f12cd5912a06eb" + + "ff6adcae899d92191fe4305673ba2ffe" + + "8fa3f1a4e5ad79f3f334b3b202b2173c" + + "486ea37ce3d397ed034c7f9dfeb15c5e" + + "927336d0441f4c4300e2cff0d0900b52" + + "d3b4")); + } + + { + // === A.6. Test Case 6 - Test with SHA-1 and zero-length salt/info + // === + + // setting salt to null should generate a new salt of HashLen zero + // valued bytes + + Digest hash = new SHA1Digest(); + byte[] ikm = Hex + .decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); + byte[] salt = null; + byte[] info = new byte[0]; + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(6, okm, Hex.decode( + "0ac1af7002b3d761d1e55298da9d0506" + + "b9ae52057220a306e07b6b87e8df21d0" + + "ea00033de03984d34918")); + } + + { + // === A.7. Test Case 7 - Test with SHA-1, salt not provided, + // zero-length info === + // (salt defaults to HashLen zero octets) + + // this test is identical to test 6 in all ways bar the IKM value + + Digest hash = new SHA1Digest(); + byte[] ikm = Hex + .decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c"); + byte[] salt = null; + byte[] info = new byte[0]; + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = new HKDFParameters(ikm, salt, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(7, okm, Hex.decode( + "2c91117204d745f3500d636a62f64f0a" + + "b3bae548aa53d423b0d1f27ebba6f5e5" + + "673a081d70cce7acfc48")); + } + + { + // === A.101. Additional Test Case - Test with SHA-1, skipping extract + // zero-length info === + // (salt defaults to HashLen zero octets) + + // this test is identical to test 7 in all ways bar the IKM value + // which is set to the PRK value + + Digest hash = new SHA1Digest(); + byte[] ikm = Hex + .decode("2adccada18779e7c2077ad2eb19d3f3e731385dd"); + byte[] info = new byte[0]; + int l = 42; + byte[] okm = new byte[l]; + + HKDFParameters params = HKDFParameters.skipExtractParameters(ikm, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + compareOKM(101, okm, Hex.decode( + "2c91117204d745f3500d636a62f64f0a" + + "b3bae548aa53d423b0d1f27ebba6f5e5" + + "673a081d70cce7acfc48")); + } + + // === A.102. Additional Test Case - Test with SHA-1, maximum output === + // (salt defaults to HashLen zero octets) + + // this test is identical to test 7 in all ways bar the IKM value + + Digest hash = new SHA1Digest(); + byte[] ikm = Hex + .decode("2adccada18779e7c2077ad2eb19d3f3e731385dd"); + byte[] info = new byte[0]; + int l = 255 * hash.getDigestSize(); + byte[] okm = new byte[l]; + + HKDFParameters params = HKDFParameters.skipExtractParameters(ikm, info); + + HKDFBytesGenerator hkdf = new HKDFBytesGenerator(hash); + hkdf.init(params); + hkdf.generateBytes(okm, 0, l); + + int zeros = 0; + for (int i = 0; i < hash.getDigestSize(); i++) + { + if (okm[i] == 0) + { + zeros++; + } + } + + if (zeros == hash.getDigestSize()) + { + fail("HKDF failed generator test " + 102); + } + } + + public String getName() + { + return "HKDF"; + } + + public static void main( + String[] args) + { + runTest(new HKDFGeneratorTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Haraka256DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Haraka256DigestTest.java new file mode 100644 index 000000000..8f24d8549 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Haraka256DigestTest.java @@ -0,0 +1,186 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.Haraka256Digest; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Haraka256DigestTest + extends SimpleTest +{ + public String getName() + { + return "Haraka 256"; + } + + public void testKnownVector() + { + byte[] in = new byte[32]; + for (int t = 0; t < in.length; t++) + { + in[t] = (byte)t; + } + + // From Appendix B, Haraka-256 v2, https://eprint.iacr.org/2016/098.pdf + byte[] expected256 = Hex.decode("8027ccb87949774b78d0545fb72bf70c695c2a0923cbd47bba1159efbf2b2c1c"); + + Haraka256Digest haraka = new Haraka256Digest(); + haraka.update(in, 0, in.length); + byte[] out = new byte[haraka.getDigestSize()]; + haraka.doFinal(out, 0); + isTrue("Did not match vector", this.areEqual(expected256, out)); + } + + + public void testInputTooShort() + { + try + { + Haraka256Digest haraka = new Haraka256Digest(); + byte[] in = new byte[31]; + haraka.update(in, 0, in.length); + haraka.doFinal(null, 0); + fail("fail on input not 32 bytes."); + } + catch (IllegalStateException ilarex) + { + isTrue("message", contains(ilarex.getMessage(), "input must be exactly 32 bytes")); + } + } + + public void testInputTooLong() + { + try + { + Haraka256Digest haraka = new Haraka256Digest(); + byte[] in = new byte[33]; + haraka.update(in, 0, in.length); + haraka.doFinal(null, 0); + fail("fail on input not 32 bytes."); + } + catch (IllegalArgumentException ilarex) + { + isTrue("long message", contains(ilarex.getMessage(), "total input cannot be more than 32 bytes")); + } + } + + public void testOutput() + { + + // + // Buffer too short. + // + try + { + Haraka256Digest haraka = new Haraka256Digest(); + byte[] in = new byte[32]; + haraka.update(in, 0, in.length); + byte[] out = new byte[31]; + haraka.doFinal(out, 0); + fail("Output too short for digest result."); + } + catch (IllegalArgumentException ilarex) + { + isTrue("message 1", contains(ilarex.getMessage(), "output too short to receive digest")); + } + + // + // Offset puts end past length of buffer. + // + try + { + Haraka256Digest haraka = new Haraka256Digest(); + byte[] in = new byte[32]; + haraka.update(in, 0, in.length); + byte[] out = new byte[48]; + haraka.doFinal(out, 17); + fail("Output too short for digest result."); + } + catch (IllegalArgumentException ilarex) + { + isTrue("message 2", contains(ilarex.getMessage(), "output too short to receive digest")); + } + + + // + // Offset output.. + // + byte[] in = new byte[32]; + for (int t = 0; t < in.length; t++) + { + in[t] = (byte)t; + } + + byte[] expected256 = Hex.decode("000000008027ccb87949774b78d0545fb72bf70c695c2a0923cbd47bba1159efbf2b2c1c"); + + Haraka256Digest haraka = new Haraka256Digest(); + haraka.update(in, 0, in.length); + byte[] out = new byte[haraka.getDigestSize() + 4]; + haraka.doFinal(out, 4); + isTrue(this.areEqual(expected256, out)); + } + + void testMonty() + { + int c = 0; + String[][] vectors = new String[][]{ + { + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "e78599d7163ab58f1c90f0171c6fc4e852eb4b8cc29a4af63194fd9977c1de84" + }, + { + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "c4cebda63c00c4cd312f36ea92afd4b0f6048507c5b367326ef9d8fdd2d5c09a" + } + }; + + for (int i = 0; i != vectors.length; i++) + { + // + // 1000 rounds of digest application, where alternative outputs are copied over alternate halves of the input. + // + String[] vector = vectors[i]; + + byte[] expected = Hex.decode(vector[1]); + + // Load initial message. + + Haraka256Digest haraka = new Haraka256Digest(); + byte[] result = Hex.decode(vector[0]); + for (int t = 0; t < 1000; t++) + { + haraka.update(result, 0, result.length); + haraka.doFinal(result, 0); + } + isTrue("Monte Carlo test: " + c, this.areEqual(expected, result)); + + // + // Deliberately introduce incorrect value. + // + + result[0] ^= 1; + isTrue("Monte Carlo test: " + c, !this.areEqual(expected, result)); + c++; + } + } + + private boolean contains(String message, String sub) + { + return message.indexOf(sub) >= 0; + } + + public void performTest() + throws Exception + { + testKnownVector(); + testInputTooLong(); + testInputTooShort(); + testOutput(); + testMonty(); + } + + public static void main( + String[] args) + { + runTest(new Haraka256DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Haraka512DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Haraka512DigestTest.java new file mode 100644 index 000000000..31c2738d0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Haraka512DigestTest.java @@ -0,0 +1,192 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.Haraka512Digest; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Haraka512DigestTest + extends SimpleTest +{ + public String getName() + { + return "Haraka 512"; + } + + public void testKnownVector() + { + byte[] in = new byte[64]; + for (int t = 0; t < in.length; t++) + { + in[t] = (byte)t; + } + + // From Appendix B, Haraka-512 v2, https://eprint.iacr.org/2016/098.pdf + byte[] expected512 = Hex.decode("be7f723b4e80a99813b292287f306f625a6d57331cae5f34dd9277b0945be2aa"); + + Haraka512Digest haraka = new Haraka512Digest(); + haraka.update(in, 0, in.length); + byte[] out = new byte[haraka.getDigestSize()]; + haraka.doFinal(out, 0); + isTrue("Did not match vector",this.areEqual(expected512, out)); + } + + public void testInputTooShort() + { + try + { + Haraka512Digest haraka = new Haraka512Digest(); + byte[] in = new byte[63]; + haraka.update(in, 0, in.length); + haraka.doFinal(null, 0); + fail("fail on input not 64 bytes."); + } + catch (IllegalStateException ilarex) + { + isTrue("message", contains(ilarex.getMessage(), "input must be exactly 64 bytes")); + } + } + + public void testInputTooLong() + { + try + { + Haraka512Digest haraka = new Haraka512Digest(); + byte[] in = new byte[65]; + haraka.update(in, 0, in.length); + haraka.doFinal(null, 0); + fail("fail on input not 64 bytes."); + } + catch (IllegalArgumentException ilarex) + { + isTrue("message", contains(ilarex.getMessage(), "total input cannot be more than 64 bytes")); + } + } + + public void testOutput() + { + // + // Buffer too short. + // + try + { + Haraka512Digest haraka = new Haraka512Digest(); + byte[] in = new byte[64]; + haraka.update(in, 0, in.length); + byte[] out = new byte[31]; + haraka.doFinal(out, 0); + fail("Output too short for digest result."); + } + catch (IllegalArgumentException ilarex) + { + isTrue("message", contains(ilarex.getMessage(), "output too short to receive digest")); + } + + // + // Offset puts end past length of buffer. + // + try + { + Haraka512Digest haraka = new Haraka512Digest(); + byte[] in = new byte[64]; + haraka.update(in, 0, in.length); + byte[] out = new byte[48]; + haraka.doFinal(out, 17); + fail("Output too short for digest result."); + } + catch (IllegalArgumentException ilarex) + { + isTrue("message", contains(ilarex.getMessage(), "output too short to receive digest")); + } + + // + // Offset output.. + // + byte[] in = new byte[64]; + for (int t = 0; t < in.length; t++) + { + in[t] = (byte)t; + } + + byte[] expected512 = Hex.decode("00000000be7f723b4e80a99813b292287f306f625a6d57331cae5f34dd9277b0945be2aa"); + + Haraka512Digest haraka = new Haraka512Digest(); + haraka.update(in, 0, in.length); + byte[] out = new byte[haraka.getDigestSize() + 4]; + haraka.doFinal(out, 4); + isTrue(this.areEqual(expected512, out)); + } + + void testMonty() + { + int c = 0; + String[][] vectors = new String[][]{ + { + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F", + "ABE210FE673F3B28E70E5100C476D82F61A7E2BDB3D8423FB0A15E5DE3D3A4DE" + }, + { + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", + "5F5ECB52C61F5036C96BE555D2E18C520AB3ED093954700C283A322D14DBFE02" + } + }; + + for (int i = 0; i != vectors.length; i++) + { + // + // 1000 rounds of digest application, where alternative outputs are copied over alternate halves of the input. + // + String[] vector = vectors[i]; + + byte[] expected = Hex.decode(vector[1]); + + // Load initial message. + byte[] in = Hex.decode(vector[0]); + Haraka512Digest haraka = new Haraka512Digest(); + byte[] result = new byte[haraka.getDigestSize()]; + for (int t = 0; t < 1000; t++) + { + haraka.update(in, 0, in.length); + haraka.doFinal(result, 0); + + if ((t & 0x01) == 1) + { + System.arraycopy(result, 0, in, 0, result.length); + } + else + { + System.arraycopy(result, 0, in, result.length, result.length); + } + } + isTrue("Monte Carlo test: " + c, this.areEqual(expected, result)); + + // + // Deliberately introduce incorrect value. + // + + result[0] ^= 1; + isTrue("Monte Carlo test: " + c, !this.areEqual(expected, result)); + c++; + } + } + + private boolean contains(String message, String sub) + { + return message.indexOf(sub) >= 0; + } + + public void performTest() + throws Exception + { + testKnownVector(); + testInputTooLong(); + testInputTooShort(); + testOutput(); + testMonty(); + } + + public static void main( + String[] args) + { + runTest(new Haraka512DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HashCommitmentTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HashCommitmentTest.java new file mode 100644 index 000000000..4095187af --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/HashCommitmentTest.java @@ -0,0 +1,152 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.Commitment; +import com.fr.third.org.bouncycastle.crypto.Committer; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.commitments.GeneralHashCommitter; +import com.fr.third.org.bouncycastle.crypto.commitments.HashCommitter; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class HashCommitmentTest + extends SimpleTest +{ + public String getName() + { + return "HashCommitmentTest"; + } + + public void performBasicTest() + throws Exception + { + byte[] data = Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20"); + + Committer committer = new HashCommitter(new SHA256Digest(), new SecureRandom()); + + Commitment c = committer.commit(data); + + committer = new HashCommitter(new SHA256Digest(), new SecureRandom()); + + if (!committer.isRevealed(c, data)) + { + fail("commitment failed to validate"); + } + + committer = new HashCommitter(new SHA1Digest(), new SecureRandom()); + + if (committer.isRevealed(c, data)) + { + fail("commitment validated!!"); + } + + try + { + committer.isRevealed(c, new byte[data.length + 1]); + } + catch (Exception e) + { + if (!e.getMessage().equals("Message and witness secret lengths do not match.")) + { + fail("exception thrown but wrong message"); + } + } + + // SHA1 has a block size of 512 bits, try a message that's too big + + try + { + c = committer.commit(new byte[33]); + } + catch (DataLengthException e) + { + if (!e.getMessage().equals("Message to be committed to too large for digest.")) + { + fail("exception thrown but wrong message"); + } + } + } + + public void performGeneralTest() + throws Exception + { + byte[] data = Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20"); + + Committer committer = new GeneralHashCommitter(new SHA256Digest(), new SecureRandom()); + + Commitment c = committer.commit(data); + + committer = new GeneralHashCommitter(new SHA256Digest(), new SecureRandom()); + + if (!committer.isRevealed(c, data)) + { + fail("general commitment failed to validate"); + } + + committer = new GeneralHashCommitter(new SHA1Digest(), new SecureRandom()); + + if (committer.isRevealed(c, data)) + { + fail("general commitment validated!!"); + } + + c = committer.commit(data); + + // try and fool it. + byte[] s = c.getSecret(); + byte[] newS = Arrays.copyOfRange(s, 0, s.length - 1); + byte[] newData = new byte[data.length + 1]; + + newData[0] = s[s.length - 1]; + System.arraycopy(data, 0, newData, 1, data.length); + + c = new Commitment(newS, c.getCommitment()); + + if (committer.isRevealed(c, newData)) + { + fail("general commitment validated!!"); + } + + try + { + committer.isRevealed(c, new byte[data.length + 1]); + } + catch (Exception e) + { + if (!e.getMessage().equals("Message and witness secret lengths do not match.")) + { + fail("exception thrown but wrong message"); + } + } + + // SHA1 has a block size of 512 bits, try a message that's too big + + try + { + c = committer.commit(new byte[33]); + } + catch (DataLengthException e) + { + if (!e.getMessage().equals("Message to be committed to too large for digest.")) + { + fail("exception thrown but wrong message"); + } + } + } + + public void performTest() + throws Exception + { + performBasicTest(); + performGeneralTest(); + } + + public static void main(String[] args) + { + runTest(new HashCommitmentTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/IDEATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/IDEATest.java new file mode 100644 index 000000000..f2bee4370 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/IDEATest.java @@ -0,0 +1,38 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.IDEAEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + */ +public class IDEATest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new IDEAEngine(), + new KeyParameter(Hex.decode("00112233445566778899AABBCCDDEEFF")), + "000102030405060708090a0b0c0d0e0f", "ed732271a7b39f475b4b2b6719f194bf"), + new BlockCipherVectorTest(0, new IDEAEngine(), + new KeyParameter(Hex.decode("00112233445566778899AABBCCDDEEFF")), + "f0f1f2f3f4f5f6f7f8f9fafbfcfdfeff", "b8bc6ed5c899265d2bcfad1fc6d4287d") + }; + + IDEATest() + { + super(tests, new IDEAEngine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "IDEA"; + } + + public static void main( + String[] args) + { + runTest(new IDEATest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ISAACTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ISAACTest.java new file mode 100644 index 000000000..d480a8a66 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ISAACTest.java @@ -0,0 +1,180 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.ISAACEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * ISAAC Test - see http://www.burtleburtle.net/bob/rand/isaacafa.html + */ +public class ISAACTest + extends SimpleTest +{ + byte[] out = Hex.decode( + "f650e4c8e448e96d98db2fb4f5fad54f433f1afbedec154ad837048746ca4f9a" + + "5de3743e88381097f1d444eb823cedb66a83e1e04a5f6355c744243325890e2e" + + "7452e31957161df638a824f3002ed71329f5544951c08d83d78cb99ea0cc74f3" + + "8f651659cbc8b7c2f5f71c6912ad6419e5792e1b860536b809b3ce98d45d6d81" + + "f3b2612917e38f8529cf72ce349947b0c998f9ffb5e13dae32ae2a2bf7cf814c" + + "8ebfa303cf22e0640b923200eca4d58aef53cec4d0f7b37d9c411a2affdf8a80" + + "b40e27bcb4d2f97644b89b08f37c71d51a70e7e90bdb9c3060dc5207b3c3f24b" + + "d7386806229749b54e232cd091dabc65a70e11018b87437e5781414fcdbc62e2" + + "8107c9ff69d2e4ae3b18e752b143b6886f4e077295138769943c3c74afc17a97" + + "0fd439636a529b0bd8c58a6aa8bcc22d2db35dfea7a2f4026cb167db538e1f4e" + + "7275e2771d3b8e97ecc5dc9115e3a5b90369661430ab93ecac9fe69d7bc76811" + + "60eda8da28833522d5295ebc5adb60e7f7e1cdd097166d14b67ec13a210f3925" + + "64af0fef0d0286843aea3decb058bafbb8b0ccfcf2b5cc05e3a662d9814bc24c" + + "2364a1aa37c0ed052b36505c451e7ec85d2a542fe43d0fbb91c8d92560d4d5f8" + + "12a0594b9e8a51dacd49ebdb1b0dcdc1cd57c7f7e63444517ded386f2f36fa86" + + "a6d1210133bc405db388d96cdb6dbe96fe29661c13edc0cbcb0eee4a70cc94ae" + + "de11ed340606cf9f3a6ce38923d74f4ea37f63ff917bdec2d73f72d40e7e0e67" + + "3d77d9a213add9228891b3db01a9bd7056a001e3d51f093dcc033ce35ad0d3b0" + + "34105a8c6a123f57bd2e50247364944be89b1a3b21835c4d9f39e2d9d405ded8" + + "294d37e5bccaaeed35a124b56708a2bcb00960ba2a98121a4d8fae820bb3263f" + + "12595a196a1075890809e49421c171ec884d682514c8009bb0b84e7b03fb88f4" + + "28e7cb789388b13bdd2dc1d5848f520a07c28cd168a3935872c9137d127dd430" + + "c613f1578c2f0d55f7d3f39f309bfb788406b13746c0a6f53718d59708607f04" + + "76904b6d04db4e13cd7411a7b510ce0ebfc7f7ccb83f957afdfef62dc35e4580" + + "3ff1e5244112d96c02c9b944d5990dfbe7e265810d9c7e7e826dfa8966f1e0ab" + + "30bcc764eadebeaced35e5ee0c571a7de4f3a26af7f58f7badf6bc235d023e65" + + "1ed3ff4eec46b0b6d2a93b51e75b41c97e315aeb61119a5a53245b7933f6d7b1" + + "cae8deba50fc8194afa92a6dc87c80064188bfcd8bace62e78ffa5685597ec0f" + + "b4415f7d08294766ad56764309c36f903dde9f394a0a283c18080c8e080c79ec" + + "79ae4c10cb9e15637cdd662f62d31911a4ca0cf15cf824cd3b708f991e16614c" + + "b6b9d7665de87abb7229ea81d5b2d75056e6cd21fe1e42d596da2655c2b9aa36" + + "b8f6fd4a6a158d1001913fd3af7d1fb80b5e435f90c107576554abda7a68710f" + + "82ac484fd7e1c7be95c85eaa94a302f44d3cfbda786b29081010b27582d53d12" + + "21e2a51c3d1e9150b059261dd0638e1a31860f0581f2864dff4cfc350451516d" + + "bd086f26bc5654c165dfa427a82427f5582e3014b8d2486dc79a17499a1d7745" + + "8766bb541e04a7f73d3dff8ad5ec6bf4dbef7d9f36ec0ea31feb2e4f15cfcc5c" + + "d8c423fbd0ef3cc9eb244925ba5590c8a5f48ac433c5321c613b67b2479c3a22" + + "e21339cc10d210aa931dd7e2ef05ee06b82f2703a385cb2c5d67133c877eb7b4" + + "1e3437f75afb43ae53c078f394d904811d96458908063a85e13222281956b1e5" + + "31860f132e7b022f21182ca396f703ac46819e2e0d28fe523724d4dca0eabe6b" + + "c66699fdc6112fdd19c1e69c04d3658a4b55dd9931907d62f854b5224d678f26" + + "22ae0582eafed133e4a51d2184bd6dd6c1a513753f28ee63fb737b1a70a1660e" + + "8a8dfaa31be79937f7476978513c1764531ac6bf12c06908001cdb951a4b6a53" + + "d067fce512b2cfb69ddb477f740e006639ddf25acc8bfa2df1b20eaf64f2632c" + + "9783cdee63bfd4d80084cfe575f4e9e219b48fd06c48ddd87a36af9371865c4c" + + "9ce0199d867027d72cb7b77f84ef01da72f5972f040f7074df9afa29c921f94e" + + "75c08a3618c1ef9ad649a428c5b719378a30738ad97cd348858129a6239e3b0a" + + "bbb8abc480fac4c2ecfcf20bd9d711f9e2a4ef71b5fe87c0be8b06b2aafef5a7" + + "9c15db3b0aeb81654389a84a253b1d7a19047c797cdc78a2d20adf0356f55a71" + + "3e730fa8fd8650d8959e234eb7546681dad1b22a142a6e858ef4bce668235b9d" + + "85a13f8574096ae7a949bea229322d0dd568385882846526403dae086dd1943a" + + "e1279bff9e7e4f041c3a4524484525e481d4cc5fe24124c0037464c0bf1bd691" + + "26ceb003275ead3ac5bde90826414ff3a30519add7b43abe2ce5d3d588412761" + + "97ca2070e5fbb9c7276df0b4308f751f37a97df6c9cd808cfe4cb3803d469303" + + "aee19096c0d5d42a4e823ad3f5f9cc3b4286619c9ca45e1c66c97340891aec49" + + "45bae606c798f04752649d6cce86fdfc80c6e402d6ec2f2b27c822821fe26ce0" + + "92f57ea7de462f4d07497cae5a48755c721502dd6cbe7935836d80039ead7f70" + + "9ab3a42f4c8652d632e39273e8fa38601da4f25a0cd6ef8102503f7d8854a0a1" + + "9a30c4e88815715305efe29457c4c9252887d96fc1a71e3ce9f841632d0985de" + + "d21e796c6fb5ce5602614abfc3c7be2cb54fed6fa617a083c3142d8f6079e4ce" + + "ceffc1471d0cb81bdc153e5fe36ef5bbd531161a165b10157aa114ed3f7579b3" + + "f7f395f1bc6172c7a86f875e0e6c51b3cdfec2af73c0e762824c2009c5a87748" + + "94d401258aba3ffbd32be0608c17eff021e2547e07cffad905340e15f3310c92" + + "9d8d190886ba527ff943f672ef73fbf046d95ca5c54cd95b9d855e894bb5af29"); + + byte[] outFFFFFFFF = Hex.decode( + "de3b3f3c19e0629c1fc8b7836695d523e7804edd86ff7ce9b106f52caebae9d9" + + "72f845d49ce17d7da44e49bae954aac0d0b1284b98a88eec1524fb6bc91a16b5" + + "1192ac5334131446ac2442de9ff3d5867b9b9148881ee30a6e87dd88e5d1f7cd" + + "98db31ff36f70d9850cfefaef42abb00ecc39ed308bf4b8030cdc2b6b7e42f0e" + + "908030dd282f96edacc888b3a986e109c129998f89baa1b5da8970b07a6ab012" + + "f10264f23c315c9c8e0c164955c68517b6a4f982b2626db70787f869ac6d551b" + + "e34931627c7058e965c502e18d2cd370e6db3b70d947d61aa9717cf8394f48c6" + + "3c796f3a154950846badb28b70d982f29bc670254e3e5e0f8e36b0a5f6da0a04" + + "6b235ed6a42988c012bde74d879fa8eb5d59f5f40ed5e76601c9847b3edb2690"); + + byte[] outFFFF0000 = Hex.decode( + "26c54b1f8c4e3fc582e9e8180f7aba5380463dcf58b03cbeda0ecc8ba90ccff8" + + "5bd50896313d7efed44015faeac6964b241a7fb8a2e37127a7cbea0fd7c020f2" + + "406371b87ef5185089504751e5e44352eff63e00e5c28f5dff0616a9a3a00f1f" + + "4a1350e3a17be9abddfc2c94571450a0dc4c3c0c7c7f98e80c95f607d50c676a" + + "9a3006f9d279a79a4d66b2ab0c52930c9ee84bc09895e70fa041b1a3a2966f11" + + "6a47fd09705124b1f5c7ae055e54536e66584b1608f3612d81b72f109a385831" + + "121945b207b90ac72437a248f27a121c2801f4153a8699fb047e193f7ba69e1b" + + "b117869675d4c963e6070c2ca3d332ce830cb5e3d9ed2eee7faf0acc20fbe154" + + "188ae789e95bd5c1f459dbd150aab6eb833170257084bc5d44e9df09f5624f9d" + + "afecd0c9340ac8587f8625d343f7efd1cc8abcf7a6f90eabd4e8e2d906278d6e" + + "431fcade165c8c467887fbf5c26d341557b064b98c60dd40ab262dc046d69647" + + "56f3ddc1a07ae5f87be878b9334fcde40add68d2ca1dc05fb1670f998c7c4607" + + "9a6e48bdb330ad8d30b61b5cc8dc156f5733905931949783f89ac396b65aa4b8" + + "51f746b53ed8ea66130e1d75e8eab136e60450e3e600226bc8e17d03744ce94c" + + "0eec9234fea5f18eef65d81f2f10cfbc0b112b8cde17c32eb33ed81d7356eac3" + + "eb1cb9cefa6604c2d707949b6e5a83e60705bf6aae76dcc7d35d68ff149c1ac5" + + "424bb4a39e2f496f886637fce3db4ba4ad12c1a32d25e1606f6635ff636486f6" + + "714997b45477f38813c02afce4bebf196b813332f0decd567c745f441e736364"); + + byte[] out0000FFFF = Hex.decode( + "bc31712f2a2f467a5abc737c57ce0f8d49d2f775eb850fc8f856daf19310fee2"+ + "5bab40e78403c9ef4ccd971418992faf4e85ca643fa6b482f30c4659066158a6"+ + "5bc3e620ba7ea5c34dd0eac5aabb2cf078d915fd1f8c437ed00423076c10f701"+ + "eefa7fc7c461aca5db8a87be29d925c4212d4adcfa71ff5b06af15c048aa0dfd"+ + "f0e645bc09fea200c430a88eb38c466ff358b836f1159656a078f6fc752f6db1"+ + "6680bb30fc771a6a785bbb2298e947d7b3500e557775962248bedf4e82c16e66"+ + "f39283ccb95e5399061056a11c4a280f00f7487888199487905273c7aa13012b"+ + "4849eca626cbf071c782e084f9fded57de92313e5f61a6e81117fb1115eff275"+ + "66fd5c755bb3b01bba69aeb8f1b1b1cc9709734be31b35bc707d372ba6fe70d1"+ + "e2c3b0e5e74a7058faff6b11d3a168f19fecc9fcb36b3e6a5f828c01c22ac0c2"+ + "5da2a3a9eec7e0ebbbf51472e430ed4cf1c7ab57ef9aea511e40250846d260b6"+ + "17a3fdeba16cf4afaf700144d3296b58b22a3c79ed96f3e2fc8d9e3c660ae153"+ + "8e0c285ccdc48b59117e80413bd0ad24c6a8d4f133fe1496f14351bb89904fa5"+ + "e10c4b8d50e0604578389c336a9ab3d292beb90ce640fc028e697cf54e021e2f"+ + "c0ca3fe0471fde5e5462f221739a74f5a13ae0621fe2a82e752bc294f63de48d"+ + "e85430af71307a30441b861ab5380e6a6dbe1251c9baa567da14e38e5a0ccddf"+ + "0127205c38fc3b77065e98101d219246103438d223ec7f8f533d4bb3a3d3407a"+ + "944910f11e8e5492e86de7a0471250eca32f0838b3db02fffe71898712af3261"); + + public String getName() + { + return "ISAAC"; + } + + public void performTest() + { + ISAACEngine engine = new ISAACEngine(); + + doTest(engine, Hex.decode("00000000"), out); + doTest(engine, Hex.decode("ffffffff"), outFFFFFFFF); + + byte[] k = new byte[256 * 4]; + for (int i = 0; i != k.length; i++) + { + k[i] = (byte)((i % 4 == 0 || i % 4 == 1) ? 0xff : 0x00); + } + doTest(engine, k, outFFFF0000); + k = new byte[256 * 4]; + for (int i = 0; i != k.length; i++) + { + k[i] = (byte)((i % 4 == 2 || i % 4 == 3) ? 0xff : 0x00); + } + doTest(engine, k, out0000FFFF); + } + + private void doTest(ISAACEngine engine, byte[] key, byte[] output) + { + byte[] in = new byte[output.length]; + byte[] enc = new byte[output.length]; + engine.init(true, new KeyParameter(key)); + engine.processBytes(in, 0, in.length, enc, 0); + if (!areEqual(enc, output)) + { + fail("ciphertext mismatch"); + } + engine.init(false, new KeyParameter(key)); + engine.processBytes(enc, 0, enc.length, enc, 0); + if (!areEqual(enc, in)) + { + fail("plaintext mismatch"); + } + } + + public static void main( + String[] args) + { + runTest(new ISAACTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ISO9796Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ISO9796Test.java new file mode 100644 index 000000000..60950f3c6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ISO9796Test.java @@ -0,0 +1,1028 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricBlockCipher; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD128Digest; +import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD160Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.encodings.ISO9796d1Encoding; +import com.fr.third.org.bouncycastle.crypto.engines.RSABlindedEngine; +import com.fr.third.org.bouncycastle.crypto.engines.RSAEngine; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithSalt; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.signers.ISO9796d2PSSSigner; +import com.fr.third.org.bouncycastle.crypto.signers.ISO9796d2Signer; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * test vectors from ISO 9796-1 and ISO 9796-2 edition 1. + */ +public class ISO9796Test + extends SimpleTest +{ + static BigInteger mod1 = new BigInteger("0100000000000000000000000000000000bba2d15dbb303c8a21c5ebbcbae52b7125087920dd7cdf358ea119fd66fb064012ec8ce692f0a0b8e8321b041acd40b7", 16); + + static BigInteger pub1 = new BigInteger("03", 16); + + static BigInteger pri1 = new BigInteger("2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac9f0783a49dd5f6c5af651f4c9d0dc9281c96a3f16a85f9572d7cc3f2d0f25a9dbf1149e4cdc32273faadd3fda5dcda7", 16); + + static BigInteger mod2 = new BigInteger("ffffff7fa27087c35ebead78412d2bdffe0301edd494df13458974ea89b364708f7d0f5a00a50779ddf9f7d4cb80b8891324da251a860c4ec9ef288104b3858d", 16); + + static BigInteger pub2 = new BigInteger("03", 16); + + static BigInteger pri2 = new BigInteger("2aaaaa9545bd6bf5e51fc7940adcdca5550080524e18cfd88b96e8d1c19de6121b13fac0eb0495d47928e047724d91d1740f6968457ce53ec8e24c9362ce84b5", 16); + + static byte msg1[] = Hex.decode("0cbbaa99887766554433221100"); + + // + // you'll need to see the ISO 9796 to make sense of this + // + static byte sig1[] = mod1.subtract(new BigInteger("309f873d8ded8379490f6097eaafdabc137d3ebfd8f25ab5f138d56a719cdc526bdd022ea65dabab920a81013a85d092e04d3e421caab717c90d89ea45a8d23a", 16)).toByteArray(); + + static byte msg2[] = Hex.decode("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"); + + static byte sig2[] = new BigInteger("319bb9becb49f3ed1bca26d0fcf09b0b0a508e4d0bd43b350f959b72cd25b3af47d608fdcd248eada74fbe19990dbeb9bf0da4b4e1200243a14e5cab3f7e610c", 16).toByteArray(); + + static byte msg3[] = Hex.decode("0112233445566778899aabbccd"); + + static byte sig3[] = mod2.subtract(new BigInteger("58e59ffb4b1fb1bcdbf8d1fe9afa3730c78a318a1134f5791b7313d480ff07ac319b068edf8f212945cb09cf33df30ace54f4a063fcca0b732f4b662dc4e2454", 16)).toByteArray(); + + // + // ISO 9796-2 + // + static BigInteger mod3 = new BigInteger("ffffffff78f6c55506c59785e871211ee120b0b5dd644aa796d82413a47b24573f1be5745b5cd9950f6b389b52350d4e01e90009669a8720bf265a2865994190a661dea3c7828e2e7ca1b19651adc2d5", 16); + + static BigInteger pub3 = new BigInteger("03", 16); + + static BigInteger pri3 = new BigInteger("2aaaaaaa942920e38120ee965168302fd0301d73a4e60c7143ceb0adf0bf30b9352f50e8b9e4ceedd65343b2179005b2f099915e4b0c37e41314bb0821ad8330d23cba7f589e0f129b04c46b67dfce9d", 16); + + static BigInteger mod4 = new BigInteger("FFFFFFFF45f1903ebb83d4d363f70dc647b839f2a84e119b8830b2dec424a1ce0c9fd667966b81407e89278283f27ca8857d40979407fc6da4cc8a20ecb4b8913b5813332409bc1f391a94c9c328dfe46695daf922259174544e2bfbe45cc5cd", 16); + static BigInteger pub4 = new BigInteger("02", 16); + static BigInteger pri4 = new BigInteger("1fffffffe8be3207d7707a9a6c7ee1b8c8f7073e5509c2337106165bd8849439c193faccf2cd70280fd124f0507e4f94cb66447680c6b87b6599d1b61c8f3600854a618262e9c1cb1438e485e47437be036d94b906087a61ee74ab0d9a1accd8", 16); + + static byte msg4[] = Hex.decode("6162636462636465636465666465666765666768666768696768696a68696a6b696a6b6c6a6b6c6d6b6c6d6e6c6d6e6f6d6e6f706e6f7071"); + static byte sig4[] = Hex.decode("374695b7ee8b273925b4656cc2e008d41463996534aa5aa5afe72a52ffd84e118085f8558f36631471d043ad342de268b94b080bee18a068c10965f581e7f32899ad378835477064abed8ef3bd530fce"); + + static byte msg5[] = Hex.decode("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"); + static byte sig5[] = Hex.decode("5cf9a01854dbacaec83aae8efc563d74538192e95466babacd361d7c86000fe42dcb4581e48e4feb862d04698da9203b1803b262105104d510b365ee9c660857ba1c001aa57abfd1c8de92e47c275cae"); + + // + // scheme 2 data + // + static BigInteger mod6 = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16); + static BigInteger pub6 = new BigInteger("11", 16); + static BigInteger pri6 = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16); + + static byte sig6[] = new BigInteger("0073FEAF13EB12914A43FE635022BB4AB8188A8F3ABD8D8A9E4AD6C355EE920359C7F237AE36B1212FE947F676C68FE362247D27D1F298CA9302EB21F4A64C26CE44471EF8C0DFE1A54606F0BA8E63E87CDACA993BFA62973B567473B4D38FAE73AB228600934A9CC1D3263E632E21FD52D2B95C5F7023DA63DE9509C01F6C7BBC", 16).modPow(pri6, mod6).toByteArray(); + + static byte msg7[] = Hex.decode("6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70716F70717270717273"); + static byte sig7[] = new BigInteger("296B06224010E1EC230D4560A5F88F03550AAFCE31C805CE81E811E5E53E5F71AE64FC2A2A486B193E87972D90C54B807A862F21A21919A43ECF067240A8C8C641DE8DCDF1942CF790D136728FFC0D98FB906E7939C1EC0E64C0E067F0A7443D6170E411DF91F797D1FFD74009C4638462E69D5923E7433AEC028B9A90E633CC", 16).modPow(pri6, mod6).toByteArray(); + + static byte msg8[] = Hex.decode("FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA9876543210FEDCBA98"); + static byte sig8[] = new BigInteger("01402B29ABA104079677CE7FC3D5A84DB24494D6F9508B4596484F5B3CC7E8AFCC4DDE7081F21CAE9D4F94D6D2CCCB43FCEDA0988FFD4EF2EAE72CFDEB4A2638F0A34A0C49664CD9DB723315759D758836C8BA26AC4348B66958AC94AE0B5A75195B57ABFB9971E21337A4B517F2E820B81F26BCE7C66F48A2DB12A8F3D731CC", 16).modPow(pri6, mod6).toByteArray(); + + static byte msg9[] = Hex.decode("6162636462636465636465666465666765666768666768696768696A68696A6B696A6B6C6A6B6C6D6B6C6D6E6C6D6E6F6D6E6F706E6F70716F707172707172737172737472737475737475767475767775767778767778797778797A78797A61797A61627A6162636162636462636465"); + static byte sig9[] = new BigInteger("6F2BB97571FE2EF205B66000E9DD06656655C1977F374E8666D636556A5FEEEEAF645555B25F45567C4EE5341F96FED86508C90A9E3F11B26E8D496139ED3E55ECE42860A6FB3A0817DAFBF13019D93E1D382DA07264FE99D9797D2F0B7779357CA7E74EE440D8855B7DDF15F000AC58EE3FFF144845E771907C0C83324A6FBC", 16).modPow(pri6, mod6).toByteArray(); + + public String getName() + { + return "ISO9796"; + } + + private boolean isSameAs( + byte[] a, + int off, + byte[] b) + { + if ((a.length - off) != b.length) + { + return false; + } + + for (int i = 0; i != b.length; i++) + { + if (a[i + off] != b[i]) + { + return false; + } + } + + return true; + } + + private boolean startsWith( + byte[] a, + byte[] b) + { + if (a.length < b.length) + { + return false; + } + + for (int i = 0; i != b.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + private void doTest1() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod1, pub1); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod1, pri1); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-1 - public encrypt, private decrypt + // + ISO9796d1Encoding eng = new ISO9796d1Encoding(rsa); + + eng.init(true, privParameters); + + eng.setPadBits(4); + + data = eng.processBlock(msg1, 0, msg1.length); + + eng.init(false, pubParameters); + + if (!areEqual(sig1, data)) + { + fail("failed ISO9796-1 generation Test 1"); + } + + data = eng.processBlock(data, 0, data.length); + + if (!areEqual(msg1, data)) + { + fail("failed ISO9796-1 retrieve Test 1"); + } + } + + private void doTest2() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod1, pub1); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod1, pri1); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-1 - public encrypt, private decrypt + // + ISO9796d1Encoding eng = new ISO9796d1Encoding(rsa); + + eng.init(true, privParameters); + + data = eng.processBlock(msg2, 0, msg2.length); + + eng.init(false, pubParameters); + + if (!isSameAs(data, 1, sig2)) + { + fail("failed ISO9796-1 generation Test 2"); + } + + data = eng.processBlock(data, 0, data.length); + + + if (!areEqual(msg2, data)) + { + fail("failed ISO9796-1 retrieve Test 2"); + } + } + + public void doTest3() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod2, pub2); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod2, pri2); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-1 - public encrypt, private decrypt + // + ISO9796d1Encoding eng = new ISO9796d1Encoding(rsa); + + eng.init(true, privParameters); + + eng.setPadBits(4); + + data = eng.processBlock(msg3, 0, msg3.length); + + eng.init(false, pubParameters); + + if (!isSameAs(sig3, 1, data)) + { + fail("failed ISO9796-1 generation Test 3"); + } + + data = eng.processBlock(data, 0, data.length); + + if (!isSameAs(msg3, 0, data)) + { + fail("failed ISO9796-1 retrieve Test 3"); + } + } + + public void doTest4() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod3, pub3); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod3, pri3); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - Signing + // + ISO9796d2Signer eng = new ISO9796d2Signer(rsa, new RIPEMD128Digest()); + + eng.init(true, privParameters); + + eng.update(msg4[0]); + eng.update(msg4, 1, msg4.length - 1); + + data = eng.generateSignature(); + + byte[] recovered = new byte[eng.getRecoveredMessage().length]; + + if (!eng.hasFullMessage()) + { + fail("full message not detected"); + } + + System.arraycopy(eng.getRecoveredMessage(), 0, recovered, 0, recovered.length); + + eng.init(false, pubParameters); + + if (!isSameAs(sig4, 0, data)) + { + fail("failed ISO9796-2 generation Test 4"); + } + + eng.update(msg4[0]); + eng.update(msg4, 1, msg4.length - 1); + + if (!eng.verifySignature(sig4)) + { + fail("failed ISO9796-2 verify Test 4"); + } + + if (eng.hasFullMessage()) + { + eng = new ISO9796d2Signer(rsa, new RIPEMD128Digest()); + + eng.init(false, pubParameters); + + if (!eng.verifySignature(sig4)) + { + fail("failed ISO9796-2 verify and recover Test 4"); + } + + if (!isSameAs(eng.getRecoveredMessage(), 0, msg4)) + { + fail("failed ISO9796-2 recovered message Test 4"); + } + + // try update with recovered + eng.updateWithRecoveredMessage(sig4); + + if (!isSameAs(eng.getRecoveredMessage(), 0, msg4)) + { + fail("failed ISO9796-2 updateWithRecovered recovered message Test 4"); + } + + if (!eng.verifySignature(sig4)) + { + fail("failed ISO9796-2 updateWithRecovered verify and recover Test 4"); + } + + if (!isSameAs(eng.getRecoveredMessage(), 0, msg4)) + { + fail("failed ISO9796-2 updateWithRecovered recovered verify message Test 4"); + } + + if (!isSameAs(eng.getRecoveredMessage(), 0, recovered)) + { + fail("failed ISO9796-2 updateWithRecovered recovered verify message Test 4 generate check"); + } + + // should fail + eng.updateWithRecoveredMessage(sig4); + + eng.update(msg4, 0, msg4.length); + + if (eng.verifySignature(sig4)) + { + fail("failed ISO9796-2 updateWithRecovered verify and recover Test 4"); + } + } + else + { + fail("full message flag false - Test 4"); + } + } + + public void doTest5() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod3, pub3); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod3, pri3); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - Signing + // + ISO9796d2Signer eng = new ISO9796d2Signer(rsa, new RIPEMD160Digest(), true); + + eng.init(true, privParameters); + + eng.update(msg5[0]); + eng.update(msg5, 1, msg5.length - 1); + + data = eng.generateSignature(); + + byte[] recovered = new byte[eng.getRecoveredMessage().length]; + + System.arraycopy(eng.getRecoveredMessage(), 0, recovered, 0, recovered.length); + + eng.init(false, pubParameters); + + if (!isSameAs(sig5, 0, data)) + { + fail("failed ISO9796-2 generation Test 5"); + } + + eng.update(msg5[0]); + eng.update(msg5, 1, msg5.length - 1); + + if (!eng.verifySignature(sig5)) + { + fail("failed ISO9796-2 verify Test 5"); + } + + if (eng.hasFullMessage()) + { + fail("fullMessage true - Test 5"); + } + + if (!startsWith(msg5, eng.getRecoveredMessage())) + { + fail("failed ISO9796-2 partial recovered message Test 5"); + } + + int length = eng.getRecoveredMessage().length; + + if (length >= msg5.length) + { + fail("Test 5 recovered message too long"); + } + + eng = new ISO9796d2Signer(rsa, new RIPEMD160Digest(), true); + + eng.init(false, pubParameters); + + eng.updateWithRecoveredMessage(sig5); + + if (!startsWith(msg5, eng.getRecoveredMessage())) + { + fail("failed ISO9796-2 updateWithRecovered partial recovered message Test 5"); + } + + if (!isSameAs(recovered, 0, eng.getRecoveredMessage())) + { + fail("failed ISO9796-2 updateWithRecovered partial recovered message Test 5 recovery check"); + } + + if (eng.hasFullMessage()) + { + fail("fullMessage updateWithRecovered true - Test 5"); + } + + for (int i = length; i != msg5.length; i++) + { + eng.update(msg5[i]); + } + + if (!eng.verifySignature(sig5)) + { + fail("failed ISO9796-2 verify Test 5"); + } + + if (eng.hasFullMessage()) + { + fail("fullMessage updateWithRecovered true - Test 5"); + } + + // should fail + eng.updateWithRecoveredMessage(sig5); + + eng.update(msg5, 0, msg5.length); + + if (eng.verifySignature(sig5)) + { + fail("failed ISO9796-2 updateWithRecovered verify fail Test 5"); + } + } + + // + // against a zero length string + // + + public void doTest6() + throws Exception + { + byte[] salt = Hex.decode("61DF870C4890FE85D6E3DD87C3DCE3723F91DB49"); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod6, pub6); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod6, pri6); + ParametersWithSalt sigParameters = new ParametersWithSalt(privParameters, salt); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - PSS Signing + // + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, new RIPEMD160Digest(), 20, true); + + eng.init(true, sigParameters); + + data = eng.generateSignature(); + + if (eng.getRecoveredMessage().length != 0) + { + fail("failed zero check"); + } + + eng.init(false, pubParameters); + + if (!isSameAs(sig6, 1, data)) + { + fail("failed ISO9796-2 generation Test 6"); + } + + if (!eng.verifySignature(data)) + { + fail("failed ISO9796-2 verify Test 6"); + } + } + + public void doTest7() + throws Exception + { + byte[] salt = new byte[0]; + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod6, pub6); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod6, pri6); + ParametersWithSalt sigParameters = new ParametersWithSalt(privParameters, salt); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - PSS Signing + // + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, new SHA1Digest(), 0, false); + + eng.init(true, sigParameters); + + eng.update(msg7[0]); + eng.update(msg7, 1, msg7.length - 1); + + data = eng.generateSignature(); + + if (!eng.hasFullMessage()) + { + fail("full message not detected"); + } + + byte[] recovered = new byte[eng.getRecoveredMessage().length]; + + System.arraycopy(eng.getRecoveredMessage(), 0, recovered, 0, recovered.length); + + eng.init(false, pubParameters); + + if (!isSameAs(sig7, 0, data)) + { + fail("failed ISO9796-2 generation Test 7"); + } + + eng.update(msg7[0]); + eng.update(msg7, 1, msg7.length - 1); + + if (!eng.verifySignature(sig7)) + { + fail("failed ISO9796-2 verify Test 7"); + } + + if (!eng.hasFullMessage()) + { + fail("full message not detected"); + } + + if (!isSameAs(msg7, 0, eng.getRecoveredMessage())) + { + fail("failed ISO9796-2 recovery Test 7"); + } + + if (!isSameAs(recovered, 0, eng.getRecoveredMessage())) + { + fail("failed ISO9796-2 recovery Test 7 recover"); + } + } + + public void doTest8() + throws Exception + { + byte[] salt = Hex.decode("78E293203CBA1B7F92F05F4D171FF8CA3E738FF8"); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod6, pub6); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod6, pri6); + ParametersWithSalt sigParameters = new ParametersWithSalt(privParameters, salt); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - PSS Signing + // + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, new RIPEMD160Digest(), 20, false); + + eng.init(true, sigParameters); + + eng.update(msg8[0]); + eng.update(msg8, 1, msg8.length - 1); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + if (!isSameAs(sig8, 0, data)) + { + fail("failed ISO9796-2 generation Test 8"); + } + + eng.update(msg8[0]); + eng.update(msg8, 1, msg8.length - 1); + + if (!eng.verifySignature(sig8)) + { + fail("failed ISO9796-2 verify Test 8"); + } + } + + public void doTest9() + throws Exception + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod6, pub6); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod6, pri6); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - PSS Signing + // + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, new RIPEMD160Digest(), 0, true); + + eng.init(true, privParameters); + + eng.update(msg9[0]); + eng.update(msg9, 1, msg9.length - 1); + + data = eng.generateSignature(); + + byte[] recovered = new byte[eng.getRecoveredMessage().length]; + + System.arraycopy(eng.getRecoveredMessage(), 0, recovered, 0, recovered.length); + + eng.init(false, pubParameters); + + if (!isSameAs(sig9, 0, data)) + { + fail("failed ISO9796-2 generation Test 9"); + } + + eng.update(msg9[0]); + eng.update(msg9, 1, msg9.length - 1); + + if (!eng.verifySignature(sig9)) + { + fail("failed ISO9796-2 verify Test 9"); + } + + if (!isSameAs(recovered, 0, eng.getRecoveredMessage())) + { + fail("failed ISO9796-2 recovery Test 7 recover"); + } + } + + public void doTest10() + throws Exception + { + BigInteger mod = new BigInteger("B3ABE6D91A4020920F8B3847764ECB34C4EB64151A96FDE7B614DC986C810FF2FD73575BDF8532C06004C8B4C8B64F700A50AEC68C0701ED10E8D211A4EA554D", 16); + BigInteger pubExp = new BigInteger("65537", 10); + BigInteger priExp = new BigInteger("AEE76AE4716F77C5782838F328327012C097BD67E5E892E75C1356E372CCF8EE1AA2D2CBDFB4DA19F703743F7C0BA42B2D69202BA7338C294D1F8B6A5771FF41", 16); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod, priExp); + RSAEngine rsa = new RSAEngine(); + byte[] data; + + // + // ISO 9796-2 - PSS Signing + // + Digest dig = new SHA1Digest(); + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, dig, dig.getDigestSize()); + + // + // as the padding is random this test needs to repeat a few times to + // make sure + // + for (int i = 0; i != 500; i++) + { + eng.init(true, privParameters); + + eng.update(msg9[0]); + eng.update(msg9, 1, msg9.length - 1); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + eng.update(msg9[0]); + eng.update(msg9, 1, msg9.length - 1); + + if (!eng.verifySignature(data)) + { + fail("failed ISO9796-2 verify Test 10"); + } + } + } + + public void doTest11() + throws Exception + { + BigInteger mod = new BigInteger("B3ABE6D91A4020920F8B3847764ECB34C4EB64151A96FDE7B614DC986C810FF2FD73575BDF8532C06004C8B4C8B64F700A50AEC68C0701ED10E8D211A4EA554D", 16); + BigInteger pubExp = new BigInteger("65537", 10); + BigInteger priExp = new BigInteger("AEE76AE4716F77C5782838F328327012C097BD67E5E892E75C1356E372CCF8EE1AA2D2CBDFB4DA19F703743F7C0BA42B2D69202BA7338C294D1F8B6A5771FF41", 16); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod, priExp); + RSAEngine rsa = new RSAEngine(); + byte[] data; + byte[] m1 = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + byte[] m2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + byte[] m3 = {1, 2, 3, 4, 5, 6, 7, 8}; + + // + // ISO 9796-2 - PSS Signing + // + Digest dig = new SHA1Digest(); + ISO9796d2PSSSigner eng = new ISO9796d2PSSSigner(rsa, dig, dig.getDigestSize()); + + // + // check message bounds + // + eng.init(true, privParameters); + + eng.update(m1, 0, m1.length); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + eng.update(m2, 0, m2.length); + + if (eng.verifySignature(data)) + { + fail("failed ISO9796-2 m2 verify Test 11"); + } + + eng.init(false, pubParameters); + + eng.update(m3, 0, m3.length); + + if (eng.verifySignature(data)) + { + fail("failed ISO9796-2 m3 verify Test 11"); + } + + eng.init(false, pubParameters); + + eng.update(m1, 0, m1.length); + + if (!eng.verifySignature(data)) + { + fail("failed ISO9796-2 verify Test 11"); + } + } + + public void doTest12() + throws Exception + { + BigInteger mod = new BigInteger("B3ABE6D91A4020920F8B3847764ECB34C4EB64151A96FDE7B614DC986C810FF2FD73575BDF8532C06004C8B4C8B64F700A50AEC68C0701ED10E8D211A4EA554D", 16); + BigInteger pubExp = new BigInteger("65537", 10); + BigInteger priExp = new BigInteger("AEE76AE4716F77C5782838F328327012C097BD67E5E892E75C1356E372CCF8EE1AA2D2CBDFB4DA19F703743F7C0BA42B2D69202BA7338C294D1F8B6A5771FF41", 16); + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAKeyParameters(true, mod, priExp); + RSAEngine rsa = new RSAEngine(); + byte[] data; + byte[] m1 = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + byte[] m2 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + byte[] m3 = {1, 2, 3, 4, 5, 6, 7, 8}; + + // + // ISO 9796-2 - Signing + // + Digest dig = new SHA1Digest(); + ISO9796d2Signer eng = new ISO9796d2Signer(rsa, dig); + + // + // check message bounds + // + eng.init(true, privParameters); + + eng.update(m1, 0, m1.length); + + data = eng.generateSignature(); + + eng.init(false, pubParameters); + + eng.update(m2, 0, m2.length); + + if (eng.verifySignature(data)) + { + fail("failed ISO9796-2 m2 verify Test 12"); + } + + eng.init(false, pubParameters); + + eng.update(m3, 0, m3.length); + + if (eng.verifySignature(data)) + { + fail("failed ISO9796-2 m3 verify Test 12"); + } + + eng.init(false, pubParameters); + + eng.update(m1, 0, m1.length); + + if (!eng.verifySignature(data)) + { + fail("failed ISO9796-2 verify Test 12"); + } + } + + private void doTest13() + throws Exception + { + BigInteger modulus = new BigInteger(1, Hex.decode("CDCBDABBF93BE8E8294E32B055256BBD0397735189BF75816341BB0D488D05D627991221DF7D59835C76A4BB4808ADEEB779E7794504E956ADC2A661B46904CDC71337DD29DDDD454124EF79CFDD7BC2C21952573CEFBA485CC38C6BD2428809B5A31A898A6B5648CAA4ED678D9743B589134B7187478996300EDBA16271A861")); + BigInteger pubExp = new BigInteger(1, Hex.decode("010001")); + BigInteger privExp = new BigInteger(1, Hex.decode("4BA6432AD42C74AA5AFCB6DF60FD57846CBC909489994ABD9C59FE439CC6D23D6DE2F3EA65B8335E796FD7904CA37C248367997257AFBD82B26F1A30525C447A236C65E6ADE43ECAAF7283584B2570FA07B340D9C9380D88EAACFFAEEFE7F472DBC9735C3FF3A3211E8A6BBFD94456B6A33C17A2C4EC18CE6335150548ED126D")); + + RSAKeyParameters pubParams = new RSAKeyParameters(false, modulus, pubExp); + RSAKeyParameters privParams = new RSAKeyParameters(true, modulus, privExp); + + AsymmetricBlockCipher rsaEngine = new RSABlindedEngine(); + Digest digest = new SHA256Digest(); + + // set challenge to all zero's for verification + byte[] challenge = new byte[8]; + + // DOES NOT USE FINAL BOOLEAN TO INDICATE RECOVERY + ISO9796d2Signer signer = new ISO9796d2Signer(rsaEngine, digest, false); + + // sign + signer.init(true, privParams); + signer.update(challenge, 0, challenge.length); + + byte[] sig = signer.generateSignature(); + + // verify + signer.init(false, pubParams); + signer.update(challenge, 0, challenge.length); + + if (!signer.verifySignature(sig)) + { + fail("basic verification failed"); + } + + // === LETS ACTUALLY DO SOME RECOVERY, USING INPUT FROM INTERNAL AUTHENTICATE === + + signer.reset(); + + final String args0 = "482E20D1EDDED34359C38F5E7C01203F9D6B2641CDCA5C404D49ADAEDE034C7481D781D043722587761C90468DE69C6585A1E8B9C322F90E1B580EEDAB3F6007D0C366CF92B4DB8B41C8314929DCE2BE889C0129123484D2FD3D12763D2EBFD12AC8E51D7061AFCA1A53DEDEC7B9A617472A78C952CCC72467AE008E5F132994"; + + digest = new SHA1Digest(); + + signer = new ISO9796d2Signer(rsaEngine, digest, true); + + + signer.init(false, pubParams); + final byte[] signature = Hex.decode(args0); + signer.updateWithRecoveredMessage(signature); + signer.update(challenge, 0, challenge.length); + + if (!signer.verifySignature(signature)) + { + fail("recovered + challenge signature failed"); + } + + // === FINALLY, USING SHA-256 === + + signer.reset(); + + digest = new SHA256Digest(); + + // NOTE setting implit to false does not actually do anything for verification !!! + signer = new ISO9796d2Signer(rsaEngine, digest, false); + + + signer.init(true, privParams); + // generate NONCE of correct length using some inner knowledge + int nonceLength = modulus.bitLength() / 8 - 1 - digest.getDigestSize() - 2; + final byte[] nonce = new byte[nonceLength]; + SecureRandom rnd = new SecureRandom(); + + rnd.nextBytes(nonce); + + signer.update(nonce, 0, nonce.length); + signer.update(challenge, 0, challenge.length); + byte[] sig3 = signer.generateSignature(); + + signer.init(false, pubParams); + signer.updateWithRecoveredMessage(sig3); + signer.update(challenge, 0, challenge.length); + if (signer.verifySignature(sig3)) + { + if (signer.hasFullMessage()) + { + fail("signer indicates full message"); + } + byte[] recoverableMessage = signer.getRecoveredMessage(); + + // sanity check, normally the nonce is ignored in eMRTD specs (PKI Technical Report) + if (!Arrays.areEqual(nonce, recoverableMessage)) + { + fail("Nonce compare with recoverable part of message failed"); + } + } + else + { + fail("recoverable + nonce failed."); + } + } + + private static final byte[] longMessage = Base64.decode( + "VVNIKzErU0U2ODAxNTMyOTcxOSsyKzErNisyKzErMTo6OTk5OTk5OTk5OTk5" + + "OTo6OSsyOjo3Nzc3Nzc3Nzc3Nzc3Ojo5Kys1OjIwMTMwNDA1OjExMzUyMCdV" + + "U0ErMTo6OjE2OjEnVVNDKzRmYjk3YzFhNDI5ZGIyZDYnVVNBKzY6MTY6MTox" + + "MDoxKzE0OjIwNDgrMTI6/vn3S0h96eNhfmPN6OZUxXhd815h0tP871Hl+V1r" + + "fHHUXvrPXmjHV0vdb8fYY1zxwvnQUcFBWXT43PFi7Xbow0/9e9l6/mhs1UJq" + + "VPvp+ELbeXfn4Nj02ttk0e3H5Hfa69NYRuHv1WBO6lfizNnM9m9XYmh9TOrg" + + "f9rDRtd+ZNbf4lz9fPTt9OXyxOJWRPr/0FLzxUVsddplfHxM3ndETFD7ffjI" + + "/mhRYuL8WXZ733LeWFRCeOzKzmDz/HvT3GZx/XJMbFpqyOZjedzh6vZr1vrD" + + "615TQfN7wtJJ29bN2Hvzb2f1xGHaXl7af0/w9dpR2dr7/HzuZEJKYc7JSkv4" + + "/k37yERIbcrfbVTeVtR+dcVoeeRT41fmzMfzf8RnWOX4YMNifl0rMTM68EFA" + + "QSdCR00rMzgwKzk5OTk5OTk5J0RUTSsxMzc6MjAxMzA0MDU6MTAyJ0ZUWCtB" + + "QUkrKytJTlZPSUNFIFRFU1QnUkZGK09OOjEyMzQ1NidSRkYrRFE6MjIyMjIy" + + "MjIyJ0RUTSsxNzE6MjAxMzA0MDE6MTAyJ05BRCtTVSs5OTk5OTk5OTk5OTk5" + + "Ojo5KytURVNUIFNVUFBMSUVSOjpUcmFzZSByZWdpc3RlciBYWFhYWFhYK1Rl" + + "c3QgYWRkcmVzcyBzdXBwbGllcitDaXR5KysxMjM0NStERSdSRkYrVkE6QTEy" + + "MzQ1Njc4J05BRCtTQ08rOTk5OTk5OTk5OTk5OTo6OSsrVEVTVCBTVVBQTElF" + + "Ujo6VHJhc2UgcmVnaXN0ZXIgWFhYWFhYWCtUZXN0IGFkZHJlc3Mgc3VwcGxp" + + "ZXIrQ2l0eSsrMTIzNDUrREUnUkZGK1ZBOkExMjM0NTY3OCdOQUQrQlkrODg4" + + "ODg4ODg4ODg4ODo6OSdOQUQrSVYrNzc3Nzc3Nzc3Nzc3Nzo6OSsrVEVTVCBC" + + "VVlFUitUZXN0IGFkZHJlc3MgYnV5ZXIrQ2l0eTIrKzU0MzIxK0RFJ1JGRitW" + + "QTpKODc2NTQzMjEnTkFEK0JDTys3Nzc3Nzc3Nzc3Nzc3Ojo5KytURVNUIEJV" + + "WUVSK1Rlc3QgYWRkcmVzcyBidXllcitDaXR5MisrNTQzMjErREUnUkZGK1ZB" + + "Oko4NzY1NDMyMSdOQUQrRFArODg4ODg4ODg4ODg4ODo6OSdOQUQrUFIrNzc3" + + "Nzc3Nzc3Nzc3Nzo6OSdDVVgrMjpFVVI6NCdQQVQrMzUnRFRNKzEzOjIwMTMw" + + "NjI0OjEwMidMSU4rMSsrMTExMTExMTExMTExMTpFTidQSUErMStBQUFBQUFB" + + "OlNBJ0lNRCtGK00rOjo6UFJPRFVDVCBURVNUIDEnUVRZKzQ3OjEwLjAwMCdN" + + "T0ErNjY6Ny4wMCdQUkkrQUFCOjEuMDAnUFJJK0FBQTowLjcwJ1JGRitPTjox" + + "MjM0NTYnUkZGK0RROjIyMjIyMjIyMidUQVgrNytWQVQrKys6OjoyMS4wMDAn" + + "QUxDK0ErKysxK1REJ1BDRCsxOjMwLjAwMCdNT0ErMjA0OjMuMDAnTElOKzIr" + + "KzIyMjIyMjIyMjIyMjI6RU4nUElBKzErQkJCQkJCQjpTQSdJTUQrRitNKzo6" + + "OlBST0RVQ1QgVEVTVCAyJ1FUWSs0NzoyMC4wMDAnTU9BKzY2OjgwLjAwJ1BS" + + "SStBQUI6NS4wMCdQUkkrQUFBOjQuMDAnUkZGK09OOjEyMzQ1NidSRkYrRFE6" + + "MjIyMjIyMjIyJ1RBWCs3K1ZBVCsrKzo6OjIxLjAwMCdBTEMrQSsrKzErVEQn" + + "UENEKzE6MjAuMDAwJ01PQSsyMDQ6MjAuMDAnVU5TK1MnQ05UKzI6MidNT0Er" + + "Nzk6ODcuMDAnTU9BKzEzOToxMDUuMjcnTU9BKzEyNTo4Ny4wMCdNT0ErMjYw" + + "OjAuMDAnTU9BKzI1OTowLjAwJ01PQSsxNzY6MTguMjcnVEFYKzcrVkFUKysr" + + "Ojo6MjEuMDAwJ01PQSsxNzY6MTguMjcnTU9BKzEyNTo4Ny4wMCc="); + + private static final byte[] shortPartialSig = Base64.decode( + "sb8yyKk6HM1cJhICScMx7QRQunRyrZ1fbI42+T+TBGNjOknvzKuvG7aftGX7" + + "O/RXuYgk6LTxpXv7+O5noUhMBsR2PKaHveuylU1WSPmDxDCui3kp4frqVH0w" + + "8Vjpl5CsKqBsmKkbGCKE+smM0xFXhYxV8QUTB2XsWNCQiFiHPgwbpfWzZUNY" + + "QPWd0A99P64EuUIYz1tkkDnLFmwQ19/PJu1a8orIQInmkVYWSsBsZ/7Ks6lx" + + "nDHpAvgiRe+OXmJ/yuQy1O3FJYdyoqvjYRPBu3qYeBK9+9L3lExLilImH5aD" + + "nJznaXcO8QFOxVPbrF2s4GdPIMDonEyAHdrnzoghlg=="); + + private void doShortPartialTest() + throws Exception + { + byte[] recovered = Hex.decode("5553482b312b534536383031353332393731392b322b312b362b322b312b313a3a393939393939393939393939393a3a392b323a3a373737373737373737373737373a3a392b2b353a32303133303430353a313133"); + BigInteger exp = new BigInteger("10001", 16); + BigInteger mod = new BigInteger("b9b70b083da9e37e23cde8e654855db31e21d2d3fc11a5f91d2b3c311efa8f5e28c757dd6fc798631cb1b9d051c14119749cb122ad76e8c3fd7bd93abe282c026a14fba9f8023977a7a0d8b49a24d1ad87e4379a931846a1ef9520ea57e28c998cf65722683d0caaa0da8306973e2496a25cbd3cb4adb4b284e25604fabf12f385456c75da7c3c4cde37440cfb7db8c8fe6851e2bc59767b9f7218540238ac8acef3bc7bd3dc6671320c2c1a2ac8a6799ce1eaf62b9683ab1e1341b37b9249dbd6cd987b2f27b5c4619a1eda7f0fb0b59a519afbbc3cee640261cec90a4bb8fefbc844082dca9f549e56943e758579a453a357e6ccb37fc46718a5b8c3227e5d", 16); + + AsymmetricKeyParameter pubKey = new RSAKeyParameters(false, mod, exp); + + ISO9796d2PSSSigner pssSign = new ISO9796d2PSSSigner(new RSAEngine(), new SHA1Digest(), 20); + + pssSign.init(false, pubKey); + + pssSign.updateWithRecoveredMessage(shortPartialSig); + + pssSign.update(longMessage, pssSign.getRecoveredMessage().length, longMessage.length - pssSign.getRecoveredMessage().length); + + if (!pssSign.verifySignature(shortPartialSig)) + { + fail("short partial PSS sig verification failed."); + } + + byte[] mm = pssSign.getRecoveredMessage(); + + if (!Arrays.areEqual(recovered, mm)) + { + fail("short partial PSS recovery failed"); + } + } + + private void doFullMessageTest() + throws Exception + { + BigInteger modulus = new BigInteger(1, Hex.decode("CDCBDABBF93BE8E8294E32B055256BBD0397735189BF75816341BB0D488D05D627991221DF7D59835C76A4BB4808ADEEB779E7794504E956ADC2A661B46904CDC71337DD29DDDD454124EF79CFDD7BC2C21952573CEFBA485CC38C6BD2428809B5A31A898A6B5648CAA4ED678D9743B589134B7187478996300EDBA16271A861")); + BigInteger pubExp = new BigInteger(1, Hex.decode("010001")); + BigInteger privExp = new BigInteger(1, Hex.decode("4BA6432AD42C74AA5AFCB6DF60FD57846CBC909489994ABD9C59FE439CC6D23D6DE2F3EA65B8335E796FD7904CA37C248367997257AFBD82B26F1A30525C447A236C65E6ADE43ECAAF7283584B2570FA07B340D9C9380D88EAACFFAEEFE7F472DBC9735C3FF3A3211E8A6BBFD94456B6A33C17A2C4EC18CE6335150548ED126D")); + + RSAKeyParameters pubParams = new RSAKeyParameters(false, modulus, pubExp); + RSAKeyParameters privParams = new RSAKeyParameters(true, modulus, privExp); + + AsymmetricBlockCipher rsaEngine = new RSABlindedEngine(); + + // set challenge to all zero's for verification + byte[] challenge = new byte[8]; + + ISO9796d2PSSSigner pssSign = new ISO9796d2PSSSigner(new RSAEngine(), new SHA256Digest(), 20, true); + + pssSign.init(true, privParams); + + pssSign.update(challenge, 0, challenge.length); + + byte[] sig = pssSign.generateSignature(); + + pssSign.init(false, pubParams); + + pssSign.updateWithRecoveredMessage(sig); + + if (!pssSign.verifySignature(sig)) + { + fail("challenge PSS sig verification failed."); + } + + byte[] mm = pssSign.getRecoveredMessage(); + + if (!Arrays.areEqual(challenge, mm)) + { + fail("challenge partial PSS recovery failed"); + } + } + + public void performTest() + throws Exception + { + doTest1(); + doTest2(); + doTest3(); + doTest4(); + doTest5(); + doTest6(); + doTest7(); + doTest8(); + doTest9(); + doTest10(); + doTest11(); + doTest12(); + doTest13(); + doShortPartialTest(); + doFullMessageTest(); + } + + public static void main( + String[] args) + { + runTest(new ISO9796Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ISO9797Alg3MacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ISO9797Alg3MacTest.java new file mode 100644 index 000000000..87075b34d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ISO9797Alg3MacTest.java @@ -0,0 +1,126 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.macs.ISO9797Alg3Mac; +import com.fr.third.org.bouncycastle.crypto.paddings.ISO7816d4Padding; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ISO9797Alg3MacTest + extends SimpleTest +{ + static byte[] keyBytes = Hex.decode("7CA110454A1A6E570131D9619DC1376E"); + + static byte[] input1 = "Hello World !!!!".getBytes(); + + static byte[] output1 = Hex.decode("F09B856213BAB83B"); + + public ISO9797Alg3MacTest() + { + } + + public void performTest() + { + KeyParameter key = new KeyParameter(keyBytes); + BlockCipher cipher = new DESEngine(); + Mac mac = new ISO9797Alg3Mac(cipher); + + // + // standard DAC - zero IV + // + mac.init(key); + + mac.update(input1, 0, input1.length); + + byte[] out = new byte[8]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output1)) + { + fail("Failed - expected " + new String(Hex.encode(output1)) + " got " + new String(Hex.encode(out))); + } + + // + // reset + // + mac.reset(); + + mac.init(key); + + for (int i = 0; i != input1.length / 2; i++) + { + mac.update(input1[i]); + } + + mac.update(input1, input1.length / 2, input1.length - (input1.length / 2)); + + mac.doFinal(out, 0); + + if (!areEqual(out, output1)) + { + fail("Reset failed - expected " + new String(Hex.encode(output1)) + " got " + new String(Hex.encode(out))); + } + + testMacWithIv(); + } + + private void testMacWithIv() + { + byte[] inputData = new byte[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}; + byte[] key = new byte[]{0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8}; + byte[] zeroIv = new byte[8]; + byte[] nonZeroIv = new byte[]{0x5, 0x6, 0x7, 0x8, 0x1, 0x2, 0x3, 0x4}; + + KeyParameter simpleParameter = new KeyParameter(key); + ParametersWithIV zeroIvParameter = new ParametersWithIV(new KeyParameter(key), zeroIv); + + ISO9797Alg3Mac mac1 = new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()); + + // we calculate a reference MAC with a null IV + mac1.init(simpleParameter); + mac1.update(inputData, 0, inputData.length); + byte[] output1 = new byte[mac1.getMacSize()]; + mac1.doFinal(output1, 0); + + // we then check that passing a vector of 0s is the same as not using any IV + ISO9797Alg3Mac mac2 = new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()); + mac2.init(zeroIvParameter); + mac2.update(inputData, 0, inputData.length); + byte[] output2 = new byte[mac2.getMacSize()]; + mac2.doFinal(output2, 0); + if (!Arrays.areEqual(output1, output2)) + { + fail("zero IV test failed"); + } + + // and then check that a non zero IV parameter produces a different results. + ParametersWithIV nonZeroIvParameter = new ParametersWithIV(new KeyParameter(key), nonZeroIv); + mac2 = new ISO9797Alg3Mac(new DESEngine(), new ISO7816d4Padding()); + mac2.init(nonZeroIvParameter); + mac2.update(inputData, 0, inputData.length); + output2 = new byte[mac2.getMacSize()]; + mac2.doFinal(output2, 0); + if (Arrays.areEqual(output1, output2)) + { + fail("non-zero IV test failed"); + } + } + + public String getName() + { + return "ISO9797Alg3Mac"; + } + + public static void main( + String[] args) + { + runTest(new ISO9797Alg3MacTest()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/IsoTrailerTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/IsoTrailerTest.java new file mode 100644 index 000000000..f44d527e3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/IsoTrailerTest.java @@ -0,0 +1,122 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA512tDigest; +import com.fr.third.org.bouncycastle.crypto.engines.RSAEngine; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.signers.ISO9796d2PSSSigner; +import com.fr.third.org.bouncycastle.crypto.signers.ISO9796d2Signer; +import com.fr.third.org.bouncycastle.crypto.signers.X931Signer; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class IsoTrailerTest + extends SimpleTest +{ + private static final byte[] x931SigOld = Hex.decode("33156b44e30640d14940d5f4534de6a91c945fe8355b01f66a896c41c78482ba02457d079327bd7015a875c353c6a0db356d6c568edb07dbbdb0500705e3f8aff9269f8535c1ed27edb09a1c246a366c4f638fd224389bcaebeb2dedc400990b91cddfda4ee0abc67ae1e39b139183dd6193aee9aa3616285ba928af20f89d5c"); + private static final byte[] x931SigCorrect = Hex.decode("3ff8d8c371503a153bb99edb1064984680ef7f70f73d08d28205b8e1ae90d7a00d78d6f16994b872bf613aafb41dd7b60fc9e964d280bde07637ec278b9491ddeeecae53e2b55302801577b20cda4ef2d4a42868de579fa5a50f2f2feb50688d893d9210469bb47134475515a7745744ba99e23d4490400e7a734e00ef2c5476"); + + private static final byte[] iso9796d2Old = Hex.decode("07f7c6a8726aeed821ce7af09b5eb260ade66913c5548438f5f7a613f5e96e1638c36d22d968c24abfa7b5879cbdf55985e7928553fe33a9c7e53b85daab87cc661e33cc1290832c3cfda59256f9501657efead29ee45cc06df1e1c0f3e06110e46377c6ed5ec78327d1c7787af79287e50c810ed17a2b43c56d27ec695b4dbf"); + private static final byte[] iso9796d2Correct = Hex.decode("530c8949deb24d138b175db5be846481f8b22598fcc44476caf87fe4f5f8c9b71f9456791bf47aaafa20650fedc000251f4eee1bcaed57bd5d1b1e64b5d0e460df88e4a5266eb3969577d29a80d7d0038044247ae6fe7705f9d20d0ef42f525445de0560c9c3972c6443be779c762cfb08e403fc2f06bc8e2d7b8f3bf022160a"); + + private static final byte[] iso9796d2PSSOld = Hex.decode("274dbd6e3d93672ee5121022843e37f66b1ff12bb7f04cff059d76932ce9116e8b12efcd19d98a78f8c9d3f262fd3ce7c3bca0edc223f3af54e1401b37f807ef5b6d71591a22a40a34ce8abc10164138835bb63ac8eeb0223d1e1d8c5d18da2acac7f7061023597aa338c4af96bebe6c7935e0b5603cb87977b9e345f697ff98"); + private static final byte[] iso9796d2PSSCorrect = Hex.decode("3a5c1248652cd6fd4419064b894379ad48c8596a3a5a0bdf98b6d6a9d25f5df164591beddff9e2ae88100dd165053f0edd2e4154834ea7b7c1f56312c4fe23a5407cf73a2c4540c8c19e91187f709529ebb779db2f8fa39f6bef923c392abecf9e7596927a71f62990dafd8bf00d298863d07680e75b1bb9bb655ba25ff48d1e"); + + public String getName() + { + return "IsoTrailerTest"; + } + + private void x931Sha512_256Test() + { + BigInteger rsaPubMod = new BigInteger(Base64.decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt")); + BigInteger rsaPubExp = new BigInteger(Base64.decode("EQ==")); + + RSAKeyParameters rsaPublic = new RSAKeyParameters(false, rsaPubMod, rsaPubExp); + + byte[] msg = new byte[] { 1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23 }; + + X931Signer signer = new X931Signer(new RSAEngine(), new SHA512tDigest(256)); + signer.init(false, rsaPublic); + signer.update(msg, 0, msg.length); + if (!signer.verifySignature(x931SigCorrect)) + { + fail("X9.31 Signer failed."); + } + + signer.init(false, rsaPublic); + signer.update(msg, 0, msg.length); + if (!signer.verifySignature(x931SigOld)) + { + fail("X9.31 old Signer failed."); + } + } + + private void iso9796_2Sha512_256Test() + { + BigInteger rsaPubMod = new BigInteger(Base64.decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt")); + BigInteger rsaPubExp = new BigInteger(Base64.decode("EQ==")); + + RSAKeyParameters rsaPublic = new RSAKeyParameters(false, rsaPubMod, rsaPubExp); + + byte[] msg = new byte[] { 1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23 }; + + ISO9796d2Signer signer = new ISO9796d2Signer(new RSAEngine(), new SHA512tDigest(256)); + + signer.init(false, rsaPublic); + signer.update(msg, 0, msg.length); + if (!signer.verifySignature(iso9796d2Correct)) + { + fail("ISO9796-2 Signer failed."); + } + + signer.init(false, rsaPublic); + signer.update(msg, 0, msg.length); + if (!signer.verifySignature(iso9796d2Old)) + { + fail("ISO9796-2 old Signer failed."); + } + } + + private void iso9796_2PSSSha512_256Test() + { + BigInteger rsaPubMod = new BigInteger(Base64.decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt")); + BigInteger rsaPubExp = new BigInteger(Base64.decode("EQ==")); + + RSAKeyParameters rsaPublic = new RSAKeyParameters(false, rsaPubMod, rsaPubExp); + + byte[] msg = new byte[] { 1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23 }; + + ISO9796d2PSSSigner signer = new ISO9796d2PSSSigner(new RSAEngine(), new SHA512tDigest(256), 32); + + signer.init(false, rsaPublic); + signer.update(msg, 0, msg.length); + if (!signer.verifySignature(iso9796d2PSSCorrect)) + { + fail("ISO9796-2PSS Signer failed."); + } + + signer.init(false, rsaPublic); + signer.update(msg, 0, msg.length); + if (!signer.verifySignature(iso9796d2PSSOld)) + { + fail("ISO9796-2PSS old Signer failed."); + } + } + + public void performTest() + throws Exception + { + x931Sha512_256Test(); + iso9796_2Sha512_256Test(); + iso9796_2PSSSha512_256Test(); + } + + public static void main( + String[] args) + { + runTest(new IsoTrailerTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/JournalingSecureRandomTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/JournalingSecureRandomTest.java new file mode 100644 index 000000000..b8ac8a926 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/JournalingSecureRandomTest.java @@ -0,0 +1,53 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.util.JournalingSecureRandom; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class JournalingSecureRandomTest + extends SimpleTest +{ + public String getName() + { + return "JournalingSecureRandom"; + } + + public void performTest() + throws Exception + { + SecureRandom rand = new SecureRandom(); + + JournalingSecureRandom jRandom1 = new JournalingSecureRandom(rand); + + byte[] base = new byte[1024]; + + jRandom1.nextBytes(base); + + byte[] transcript = jRandom1.getTranscript(); + + byte[] block = new byte[512]; + + JournalingSecureRandom jRandom2 = new JournalingSecureRandom(transcript, rand); + + jRandom2.nextBytes(block); + + areEqual(Arrays.copyOfRange(base, 0, 512), block); + + jRandom2.nextBytes(block); + + areEqual(Arrays.copyOfRange(base, 512, 1024), block); + + jRandom2.nextBytes(block); + + isTrue(!Arrays.areEqual(Arrays.copyOfRange(base, 0, 512), block)); + + } + + public static void main( + String[] args) + { + runTest(new JournalingSecureRandomTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDF1GeneratorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDF1GeneratorTest.java new file mode 100644 index 000000000..272d8937e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDF1GeneratorTest.java @@ -0,0 +1,93 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.DerivationFunction; +import com.fr.third.org.bouncycastle.crypto.digests.ShortenedDigest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.generators.KDF1BytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ISO18033KDFParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * KDF1 tests - vectors from ISO 18033. + */ +public class KDF1GeneratorTest + extends SimpleTest +{ + private byte[] seed1 = Hex.decode("d6e168c5f256a2dcff7ef12facd390f393c7a88d"); + private byte[] mask1 = Hex.decode( + "0742ba966813af75536bb6149cc44fc256fd6406df79665bc31dc5" + + "a62f70535e52c53015b9d37d412ff3c1193439599e1b628774c50d9c" + + "cb78d82c425e4521ee47b8c36a4bcffe8b8112a89312fc04420a39de" + + "99223890e74ce10378bc515a212b97b8a6447ba6a8870278"); + + private byte[] seed2 = Hex.decode( + "032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d7643741" + + "52e0ac009e509e7ba30cd2f1778e113b64e135cf4e2292c75efe5288edfda4"); + private byte[] mask2 = Hex.decode( + "5f8de105b5e96b2e490ddecbd147dd1def7e3b8e0e6a26eb7b956ccb8b3bdc1ca9" + + "75bc57c3989e8fbad31a224655d800c46954840ff32052cdf0d640562bdfadfa263c" + + "fccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842dbff8e13efee5b7e" + + "7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837eea4e0a2f04"); + + private byte[] seed3 = seed2; + private byte[] mask3= Hex.decode( + "09e2decf2a6e1666c2f6071ff4298305e2643fd510a2403db42a8743cb989de86e" + + "668d168cbe604611ac179f819a3d18412e9eb45668f2923c087c12fee0c5a0d2a8aa" + + "70185401fbbd99379ec76c663e875a60b4aacb1319fa11c3365a8b79a44669f26fb5" + + "55c80391847b05eca1cb5cf8c2d531448d33fbaca19f6410ee1fcb"); + + + public KDF1GeneratorTest() + { + } + + public void performTest() + { + checkMask(1, new KDF1BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed1, mask1); + checkMask(2, new KDF1BytesGenerator(new SHA1Digest()), seed2, mask2); + checkMask(3, new KDF1BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed3, mask3); + + try + { + new KDF1BytesGenerator(new SHA1Digest()).generateBytes(new byte[10], 0, 20); + + fail("short input array not caught"); + } + catch (DataLengthException e) + { + // expected + } + } + + private void checkMask( + int count, + DerivationFunction kdf, + byte[] seed, + byte[] result) + { + byte[] data = new byte[result.length]; + + kdf.init(new ISO18033KDFParameters(seed)); + + kdf.generateBytes(data, 0, data.length); + + if (!areEqual(result, data)) + { + fail("KDF1 failed generator test " + count); + } + } + + public String getName() + { + return "KDF1"; + } + + public static void main( + String[] args) + { + runTest(new KDF1GeneratorTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDF2GeneratorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDF2GeneratorTest.java new file mode 100644 index 000000000..1950066cb --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDF2GeneratorTest.java @@ -0,0 +1,105 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.DerivationFunction; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.ShortenedDigest; +import com.fr.third.org.bouncycastle.crypto.generators.KDF2BytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.KDFParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * KDF2 tests - vectors from ISO 18033. + */ +public class KDF2GeneratorTest + extends SimpleTest +{ + private byte[] seed1 = Hex.decode("d6e168c5f256a2dcff7ef12facd390f393c7a88d"); + private byte[] mask1 = Hex.decode( + "df79665bc31dc5a62f70535e52c53015b9d37d412ff3c119343959" + + "9e1b628774c50d9ccb78d82c425e4521ee47b8c36a4bcffe8b8112a8" + + "9312fc04420a39de99223890e74ce10378bc515a212b97b8a6447ba6" + + "a8870278f0262727ca041fa1aa9f7b5d1cf7f308232fe861"); + + private byte[] seed2 = Hex.decode( + "032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d7643741" + + "52e0ac009e509e7ba30cd2f1778e113b64e135cf4e2292c75efe5288edfda4"); + private byte[] mask2 = Hex.decode( + "10a2403db42a8743cb989de86e668d168cbe604611ac179f819a3d18412e9eb456" + + "68f2923c087c12fee0c5a0d2a8aa70185401fbbd99379ec76c663e875a60b4aacb13" + + "19fa11c3365a8b79a44669f26fb555c80391847b05eca1cb5cf8c2d531448d33fbac" + + "a19f6410ee1fcb260892670e0814c348664f6a7248aaf998a3acc6"); + private byte[] adjustedMask2 = Hex.decode( + "10a2403db42a8743cb989de86e668d168cbe6046e23ff26f741e87949a3bba1311ac1" + + "79f819a3d18412e9eb45668f2923c087c1299005f8d5fd42ca257bc93e8fee0c5a0d2" + + "a8aa70185401fbbd99379ec76c663e9a29d0b70f3fe261a59cdc24875a60b4aacb131" + + "9fa11c3365a8b79a44669f26fba933d012db213d7e3b16349"); + + private byte[] sha1Mask = Hex.decode( + "0e6a26eb7b956ccb8b3bdc1ca975bc57c3989e8fbad31a224655d800c46954840ff32" + + "052cdf0d640562bdfadfa263cfccf3c52b29f2af4a1869959bc77f854cf15bd7a2519" + + "2985a842dbff8e13efee5b7e7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837ee" + + "a4e0a2f04b53ca8f50fb31225c1be2d0126c8c7a4753b0807"); + + private byte[] seed3 = Hex.decode("CA7C0F8C3FFA87A96E1B74AC8E6AF594347BB40A"); + private byte[] mask3 = Hex.decode("744AB703F5BC082E59185F6D049D2D367DB245C2"); + + private byte[] seed4 = Hex.decode("0499B502FC8B5BAFB0F4047E731D1F9FD8CD0D8881"); + private byte[] mask4 = Hex.decode("03C62280C894E103C680B13CD4B4AE740A5EF0C72547292F82DC6B1777F47D63BA9D1EA732DBF386"); + + public KDF2GeneratorTest() + { + } + + public void performTest() + { + checkMask(1, new KDF2BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed1, mask1); + checkMask(2, new KDF2BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed2, mask2); + checkMask(3, new KDF2BytesGenerator(new SHA256Digest()), seed2, adjustedMask2); + checkMask(4, new KDF2BytesGenerator(new SHA1Digest()), seed2, sha1Mask); + checkMask(5, new KDF2BytesGenerator(new SHA1Digest()), seed3, mask3); + checkMask(6, new KDF2BytesGenerator(new SHA1Digest()), seed4, mask4); + + try + { + new KDF2BytesGenerator(new SHA1Digest()).generateBytes(new byte[10], 0, 20); + + fail("short input array not caught"); + } + catch (DataLengthException e) + { + // expected + } + } + + private void checkMask( + int count, + DerivationFunction kdf, + byte[] seed, + byte[] result) + { + byte[] data = new byte[result.length]; + + kdf.init(new KDFParameters(seed, new byte[0])); + + kdf.generateBytes(data, 0, data.length); + + if (!areEqual(result, data)) + { + fail("KDF2 failed generator test " + count); + } + } + + public String getName() + { + return "KDF2"; + } + + public static void main( + String[] args) + { + runTest(new KDF2GeneratorTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDFCounterGeneratorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDFCounterGeneratorTest.java new file mode 100644 index 000000000..b4b2beb1d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDFCounterGeneratorTest.java @@ -0,0 +1,51 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +import com.fr.third.org.bouncycastle.crypto.test.cavp.CAVPReader; +import com.fr.third.org.bouncycastle.crypto.test.cavp.KDFCounterTests; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class KDFCounterGeneratorTest + extends SimpleTest +{ + + private static void testCounter() + { + + CAVPReader cavpReader = new CAVPReader(new KDFCounterTests()); + + final InputStream stream = CAVPReader.class.getResourceAsStream("KDFCTR_gen.rsp"); + final Reader reader = new InputStreamReader(stream, Charset.forName("UTF-8")); + cavpReader.setInput("KDFCounter", reader); + + try + { + cavpReader.readAll(); + } + catch (IOException e) + { + throw new IllegalStateException("Something is rotten in the state of Denmark", e); + } + } + + public String getName() + { + return this.getClass().getSimpleName(); + } + + public void performTest() + throws Exception + { + testCounter(); + } + + public static void main(String[] args) + { + runTest(new KDFCounterGeneratorTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDFDoublePipelineIteratorGeneratorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDFDoublePipelineIteratorGeneratorTest.java new file mode 100644 index 000000000..305012106 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDFDoublePipelineIteratorGeneratorTest.java @@ -0,0 +1,72 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +import com.fr.third.org.bouncycastle.crypto.test.cavp.CAVPReader; +import com.fr.third.org.bouncycastle.crypto.test.cavp.KDFDoublePipelineCounterTests; +import com.fr.third.org.bouncycastle.crypto.test.cavp.KDFDoublePipelineIterationNoCounterTests; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class KDFDoublePipelineIteratorGeneratorTest + extends SimpleTest +{ + public String getName() + { + return this.getClass().getSimpleName(); + } + + public void performTest() + throws Exception + { + testDoublePipelineIterationCounter(); + testDoublePipelineIterationNoCounter(); + } + + private static void testDoublePipelineIterationCounter() + { + + CAVPReader cavpReader = new CAVPReader(new KDFDoublePipelineCounterTests()); + + final InputStream stream = CAVPReader.class.getResourceAsStream("KDFDblPipelineCounter_gen.rsp"); + final Reader reader = new InputStreamReader(stream, Charset.forName("UTF-8")); + cavpReader.setInput("KDFDoublePipelineIterationCounter", reader); + + try + { + cavpReader.readAll(); + } + catch (IOException e) + { + throw new IllegalStateException("Something is rotten in the state of Denmark", e); + } + } + + private static void testDoublePipelineIterationNoCounter() + { + + CAVPReader cavpReader = new CAVPReader(new KDFDoublePipelineIterationNoCounterTests()); + + final InputStream stream = CAVPReader.class.getResourceAsStream("KDFDblPipelineNoCounter_gen.rsp"); + final Reader reader = new InputStreamReader(stream, Charset.forName("UTF-8")); + cavpReader.setInput("KDFDblPipelineIterationNoCounter", reader); + + try + { + cavpReader.readAll(); + } + catch (IOException e) + { + throw new IllegalStateException("Something is rotten in the state of Denmark", e); + } + } + + public static void main(String[] args) + { + runTest(new KDFDoublePipelineIteratorGeneratorTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDFFeedbackGeneratorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDFFeedbackGeneratorTest.java new file mode 100644 index 000000000..3e672c23f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KDFFeedbackGeneratorTest.java @@ -0,0 +1,71 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; + +import com.fr.third.org.bouncycastle.crypto.test.cavp.CAVPReader; +import com.fr.third.org.bouncycastle.crypto.test.cavp.KDFFeedbackCounterTests; +import com.fr.third.org.bouncycastle.crypto.test.cavp.KDFFeedbackNoCounterTests; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class KDFFeedbackGeneratorTest + extends SimpleTest +{ + public String getName() + { + return this.getClass().getSimpleName(); + } + + public void performTest() + throws Exception + { + testFeedbackCounter(); + testFeedbackNoCounter(); + } + + private static void testFeedbackCounter() + { + + CAVPReader cavpReader = new CAVPReader(new KDFFeedbackCounterTests()); + + final InputStream stream = CAVPReader.class.getResourceAsStream("KDFFeedbackCounter_gen.rsp"); + final Reader reader = new InputStreamReader(stream, Charset.forName("UTF-8")); + cavpReader.setInput("KDFFeedbackCounter", reader); + + try + { + cavpReader.readAll(); + } + catch (IOException e) + { + throw new IllegalStateException("Something is rotten in the state of Denmark ", e); + } + } + + private static void testFeedbackNoCounter() + { + + CAVPReader cavpReader = new CAVPReader(new KDFFeedbackNoCounterTests()); + + final InputStream stream = CAVPReader.class.getResourceAsStream("KDFFeedbackNoCounter_gen.rsp"); + final Reader reader = new InputStreamReader(stream, Charset.forName("UTF-8")); + cavpReader.setInput("KDFFeedbackNoCounter", reader); + + try + { + cavpReader.readAll(); + } + catch (IOException e) + { + throw new IllegalStateException("Something is rotten in the state of Denmark", e); + } + } + + public static void main(String[] args) + { + runTest(new KDFDoublePipelineIteratorGeneratorTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KeccakDigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KeccakDigestTest.java new file mode 100644 index 000000000..3b80189f8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/KeccakDigestTest.java @@ -0,0 +1,364 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.digests.KeccakDigest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Keccak Digest Test + */ +public class KeccakDigestTest + extends SimpleTest +{ + final static String[] messages = { + "", + "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67", + "54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f672e" + }; + + final static String[] digests288 = { // the default settings + "6753e3380c09e385d0339eb6b050a68f66cfd60a73476e6fd6adeb72f5edd7c6f04a5d01", // message[0] + "0bbe6afae0d7e89054085c1cc47b1689772c89a41796891e197d1ca1b76f288154933ded", // message[1] + "82558a209b960ddeb531e6dcb281885b2400ca160472462486e79f071e88a3330a8a303d", // message[2] + "94049e1ad7ef5d5b0df2b880489e7ab09ec937c3bfc1b04470e503e1ac7b1133c18f86da", // 64k a-test + "a9cb5a75b5b81b7528301e72553ed6770214fa963956e790528afe420de33c074e6f4220", // random alphabet test + "eadaf5ba2ad6a2f6f338fce0e1efdad2a61bb38f6be6068b01093977acf99e97a5d5827c" // extremely long data test + }; + + final static String[] digests224 = { + "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd", + "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe", + "c59d4eaeac728671c635ff645014e2afa935bebffdb5fbd207ffdeab", + "f621e11c142fbf35fa8c22841c3a812ba1e0151be4f38d80b9f1ff53", + "68b5fc8c87193155bba68a2485377e809ee4f81a85ef023b9e64add0", + "c42e4aee858e1a8ad2976896b9d23dd187f64436ee15969afdbc68c5" + }; + + final static String[] digests256 = { + "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15", + "578951e24efd62a3d63a86f7cd19aaa53c898fe287d2552133220370240b572d", + "0047a916daa1f92130d870b542e22d3108444f5a7e4429f05762fb647e6ed9ed", + "db368762253ede6d4f1db87e0b799b96e554eae005747a2ea687456ca8bcbd03", + "5f313c39963dcf792b5470d4ade9f3a356a3e4021748690a958372e2b06f82a4" + }; + + final static String[] digests384 = { + "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff", + "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3", + "9ad8e17325408eddb6edee6147f13856ad819bb7532668b605a24a2d958f88bd5c169e56dc4b2f89ffd325f6006d820b", + "c704cfe7a1a53208ca9526cd24251e0acdc252ecd978eee05acd16425cfb404ea81f5a9e2e5e97784d63ee6a0618a398", + "d4fe8586fd8f858dd2e4dee0bafc19b4c12b4e2a856054abc4b14927354931675cdcaf942267f204ea706c19f7beefc4", + "9b7168b4494a80a86408e6b9dc4e5a1837c85dd8ff452ed410f2832959c08c8c0d040a892eb9a755776372d4a8732315" + }; + + final static String[] digests512 = { + "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e", + "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609", + "ab7192d2b11f51c7dd744e7b3441febf397ca07bf812cceae122ca4ded6387889064f8db9230f173f6d1ab6e24b6e50f065b039f799f5592360a6558eb52d760", + "34341ead153aa1d1fdcf6cf624c2b4f6894b6fd16dc38bd4ec971ac0385ad54fafcb2e0ed86a1e509456f4246fdcb02c3172824cd649d9ad54c51f7fb49ea67c", + "dc44d4f4d36b07ab5fc04016cbe53548e5a7778671c58a43cb379fd00c06719b8073141fc22191ffc3db5f8b8983ae8341fa37f18c1c969664393aa5ceade64e", + "3e122edaf37398231cfaca4c7c216c9d66d5b899ec1d7ac617c40c7261906a45fc01617a021e5da3bd8d4182695b5cb785a28237cbb167590e34718e56d8aab8" + }; + + // test vectors from http://www.di-mgt.com.au/hmac_sha3_testvectors.html + final static byte[][] macKeys = + { + Hex.decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"), + Hex.decode("4a656665"), + Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"), + Hex.decode("0102030405060708090a0b0c0d0e0f10111213141516171819"), + Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaa"), + Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaa"), + Hex.decode("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") + }; + + final static String[] macData = + { + "4869205468657265", + "7768617420646f2079612077616e7420666f72206e6f7468696e673f", + "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd" + + "dddddddddddddddddddddddddddddddddddd", + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd" + + "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "54657374205573696e67204c6172676572205468616e20426c6f636b2d53697a" + + "65204b6579202d2048617368204b6579204669727374", + "5468697320697320612074657374207573696e672061206c6172676572207468" + + "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" + + "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" + + "647320746f20626520686173686564206265666f7265206265696e6720757365" + + "642062792074686520484d414320616c676f726974686d2e", + "5468697320697320612074657374207573696e672061206c6172676572207468" + + "616e20626c6f636b2d73697a65206b657920616e642061206c61726765722074" + + "68616e20626c6f636b2d73697a6520646174612e20546865206b6579206e6565" + + "647320746f20626520686173686564206265666f7265206265696e6720757365\n" + + "642062792074686520484d414320616c676f726974686d2e" + }; + + final static String[] mac224 = + { + "b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc", + "e824fec96c074f22f99235bb942da1982664ab692ca8501053cbd414", + "770df38c99d6e2bacd68056dcfe07d4c89ae20b2686a6185e1faa449", + "305a8f2dfb94bad28861a03cbc4d590febe775c58cb4961c28428a0b", + "e7a52dfa45f95a217c100066b239aa8ad519be9b35d667268b1b57ff", + "ba13009405a929f398b348885caa5419191bb948ada32194afc84104", + "92649468be236c3c72c189909c063b13f994be05749dc91310db639e" + }; + + final static String[] mac256 = + { + "9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821", + "aa9aed448c7abc8b5e326ffa6a01cdedf7b4b831881468c044ba8dd4566369a1", + "95f43e50f8df80a21977d51a8db3ba572dcd71db24687e6f86f47c1139b26260", + "6331ba9b4af5804a68725b3663eb74814494b63c6093e35fb320a85d507936fd", + "b4d0cdee7ec2ba81a88b86918958312300a15622377929a054a9ce3ae1fac2b6", + "1fdc8cb4e27d07c10d897dec39c217792a6e64fa9c63a77ce42ad106ef284e02", + "fdaa10a0299aecff9bb411cf2d7748a4022e4a26be3fb5b11b33d8c2b7ef5484" + }; + + final static String[] mac384 = + { + "892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048", + "5af5c9a77a23a6a93d80649e562ab77f4f3552e3c5caffd93bdf8b3cfc6920e3023fc26775d9df1f3c94613146ad2c9d", + "4243c29f2201992ff96441e3b91ff81d8c601d706fbc83252684a4bc51101ca9b2c06ddd03677303c502ac5331752a3c", + "b730724d3d4090cda1be799f63acbbe389fef7792fc18676fa5453aab398664650ed029c3498bbe8056f06c658e1e693", + "d62482ef601d7847439b55236e9679388ffcd53c62cd126f39be6ea63de762e26cd5974cb9a8de401b786b5555040f6f", + "4860ea191ac34994cf88957afe5a836ef36e4cc1a66d75bf77defb7576122d75f60660e4cf731c6effac06402787e2b9", + "fe9357e3cfa538eb0373a2ce8f1e26ad6590afdaf266f1300522e8896d27e73f654d0631c8fa598d4bb82af6b744f4f5" + }; + + final static String[] mac512 = + { + "8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755", + "c2962e5bbe1238007852f79d814dbbecd4682e6f097d37a363587c03bfa2eb0859d8d9c701e04cececfd3dd7bfd438f20b8b648e01bf8c11d26824b96cebbdcb", + "eb0ed9580e0ec11fc66cbb646b1be904eaff6da4556d9334f65ee4b2c85739157bae9027c51505e49d1bb81cfa55e6822db55262d5a252c088a29a5e95b84a66", + "b46193bb59f4f696bf702597616da91e2a4558a593f4b015e69141ba81e1e50ea580834c2b87f87baa25a3a03bfc9bb389847f2dc820beae69d30c4bb75369cb", + "d05888a6ebf8460423ea7bc85ea4ffda847b32df32291d2ce115fd187707325c7ce4f71880d91008084ce24a38795d20e6a28328a0f0712dc38253370da3ebb5", + "2c6b9748d35c4c8db0b4407dd2ed2381f133bdbd1dfaa69e30051eb6badfcca64299b88ae05fdbd3dd3dd7fe627e42e39e48b0fe8c7f1e85f2dbd52c2d753572", + "6adc502f14e27812402fc81a807b28bf8a53c87bea7a1df6256bf66f5de1a4cb741407ad15ab8abc136846057f881969fbb159c321c904bfb557b77afb7778c8" + }; + + final static KeyParameter truncKey = new KeyParameter(Hex.decode("0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c")); + final static byte[] truncData = Hex.decode("546573742057697468205472756e636174696f6e"); + + final static byte[] trunc224 = Hex.decode("f52bbcfd654264e7133085c5e69b72c3"); + final static byte[] trunc256 = Hex.decode("745e7e687f8335280d54202ef13cecc6"); + final static byte[] trunc384 = Hex.decode("fa9aea2bc1e181e47cbb8c3df243814d"); + final static byte[] trunc512 = Hex.decode("04c929fead434bba190dacfa554ce3f5"); + + final static byte[] xtremeData = Hex.decode("61626364656667686263646566676869636465666768696a6465666768696a6b65666768696a6b6c666768696a6b6c6d6768696a6b6c6d6e68696a6b6c6d6e6f"); + + KeccakDigestTest() + { + } + + public String getName() + { + return "Keccak"; + } + + private void testDigest(Digest digest, String[] expected) + { + byte[] hash = new byte[digest.getDigestSize()]; + + for (int i = 0; i != messages.length; i++) + { + if (messages.length != 0) + { + byte[] data = Hex.decode(messages[i]); + + digest.update(data, 0, data.length); + } + + digest.doFinal(hash, 0); + + if (!Arrays.areEqual(Hex.decode(expected[i]), hash)) + { + fail("Keccak mismatch on " + digest.getAlgorithmName() + " index " + i); + } + } + + byte[] k64 = new byte[1024 * 64]; + + for (int i = 0; i != k64.length; i++) + { + k64[i] = (byte)'a'; + } + + digest.update(k64, 0, k64.length); + + digest.doFinal(hash, 0); + + if (!Arrays.areEqual(Hex.decode(expected[messages.length]), hash)) + { + fail("Keccak mismatch on " + digest.getAlgorithmName() + " 64k a"); + } + + for (int i = 0; i != k64.length; i++) + { + digest.update((byte)'a'); + } + + digest.doFinal(hash, 0); + + if (!Arrays.areEqual(Hex.decode(expected[messages.length]), hash)) + { + fail("Keccak mismatch on " + digest.getAlgorithmName() + " 64k a single"); + } + + + for (int i = 0; i != k64.length; i++) + { + k64[i] = (byte)('a' + (i % 26)); + } + + digest.update(k64, 0, k64.length); + + digest.doFinal(hash, 0); + + if (!Arrays.areEqual(Hex.decode(expected[messages.length + 1]), hash)) + { + fail("Keccak mismatch on " + digest.getAlgorithmName() + " 64k alpha"); + } + + for (int i = 0; i != 64; i++) + { + digest.update(k64[i * 1024]); + digest.update(k64, i * 1024 + 1, 1023); + } + + digest.doFinal(hash, 0); + + if (!Arrays.areEqual(Hex.decode(expected[messages.length + 1]), hash)) + { + fail("Keccak mismatch on " + digest.getAlgorithmName() + " 64k chunked alpha"); + } + + testDigestDoFinal(digest); + + // + // extremely long data test + // +// long start = System.currentTimeMillis(); +// System.out.println("Starting very long"); +// for (int i = 0; i != 16384; i++) +// { +// for (int j = 0; j != 1024; j++) +// { +// digest.update(xtremeData, 0, xtremeData.length); +// } +// } +// +// digest.doFinal(hash, 0); +// +// if (!Arrays.areEqual(Hex.decode(expected[messages.length + 2]), hash)) +// { +// fail("Keccak mismatch on " + digest.getAlgorithmName() + " extreme data test"); +// } +// System.out.println("Done " + (System.currentTimeMillis() - start)); + } + + private void testDigestDoFinal(Digest digest) + { + byte[] hash = new byte[digest.getDigestSize()]; + digest.doFinal(hash, 0); + + for (int i = 0; i <= digest.getDigestSize(); ++i) + { + byte[] cmp = new byte[2 * digest.getDigestSize()]; + System.arraycopy(hash, 0, cmp, i, hash.length); + + byte[] buf = new byte[2 * digest.getDigestSize()]; + digest.doFinal(buf, i); + + if (!Arrays.areEqual(cmp, buf)) + { + fail("Keccak offset doFinal on " + digest.getAlgorithmName()); + } + } + } + + private void testMac(Digest digest, byte[][] keys, String[] data, String[] expected, byte[] truncExpected) + { + Mac mac = new HMac(digest); + + for (int i = 0; i != keys.length; i++) + { + mac.init(new KeyParameter(keys[i])); + + byte[] mData = Hex.decode(data[i]); + + mac.update(mData, 0, mData.length); + + byte[] macV = new byte[mac.getMacSize()]; + + mac.doFinal(macV, 0); + + if (!Arrays.areEqual(Hex.decode(expected[i]), macV)) + { + fail("Keccak HMAC mismatch on " + digest.getAlgorithmName()); + } + } + + mac = new HMac(digest); + + mac.init(truncKey); + + mac.update(truncData, 0, truncData.length); + + byte[] macV = new byte[mac.getMacSize()]; + + mac.doFinal(macV, 0); + + for (int i = 0; i != truncExpected.length; i++) + { + if (macV[i] != truncExpected[i]) + { + fail("mismatch on truncated HMAC for " + digest.getAlgorithmName()); + } + } + } + + public void performTest() throws Exception + { + testDigest(new KeccakDigest(), digests288); + testDigest(new KeccakDigest(224), digests224); + testDigest(new KeccakDigest(256), digests256); + testDigest(new KeccakDigest(384), digests384); + testDigest(new KeccakDigest(512), digests512); + + testMac(new KeccakDigest(224), macKeys, macData, mac224, trunc224); + testMac(new KeccakDigest(256), macKeys, macData, mac256, trunc256); + testMac(new KeccakDigest(384), macKeys, macData, mac384, trunc384); + testMac(new KeccakDigest(512), macKeys, macData, mac512, trunc512); + } + + protected Digest cloneDigest(Digest digest) + { + return new KeccakDigest((KeccakDigest)digest); + } + + public static void main( + String[] args) + { + runTest(new KeccakDigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD2DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD2DigestTest.java new file mode 100644 index 000000000..43307c38c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD2DigestTest.java @@ -0,0 +1,52 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.MD2Digest; + +/** + * standard vector test for MD2 + * from RFC1319 by B.Kaliski of RSA Laboratories April 1992 + * + */ +public class MD2DigestTest + extends DigestTest +{ + static final String messages[] = + { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + static final String digests[] = + { + "8350e5a3e24c153df2275c9f80692773", + "32ec01ec4a6dac72c0ab96fb34c0b5d1", + "da853b0d3f88d99b30283a69e6ded6bb", + "ab4f496bfb2a530b219ff33031fe06b0", + "4e8ddff3650292ab5a4108c3aa47940b", + "da33def2a42df13975352846c30338cd", + "d5976f79d83d3a0dc9806c3c66f3efd8" + }; + + MD2DigestTest() + { + super(new MD2Digest(), messages, digests); + } + + protected Digest cloneDigest( + Digest digest) + { + return new MD2Digest((MD2Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new MD2DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD4DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD4DigestTest.java new file mode 100644 index 000000000..c9f6678a5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD4DigestTest.java @@ -0,0 +1,43 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.MD4Digest; + +/** + * standard vector test for MD4 from RFC 1320. + */ +public class MD4DigestTest + extends DigestTest +{ + static private String[] messages = + { + "", + "a", + "abc", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + static private String[] digests = + { + "31d6cfe0d16ae931b73c59d7e0c089c0", + "bde52cb31de33e46245e05fbdbd6fb24", + "a448017aaf21d8525fc10ae87aa6729d", + "e33b4ddc9c38f2199c3e7b164fcc0536" + }; + + MD4DigestTest() + { + super(new MD4Digest(), messages, digests); + } + + protected Digest cloneDigest(Digest digest) + { + return new MD4Digest((MD4Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new MD4DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD5DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD5DigestTest.java new file mode 100644 index 000000000..a393cb56b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD5DigestTest.java @@ -0,0 +1,48 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.MD5Digest; + +/** + * standard vector test for MD5 from "Handbook of Applied Cryptography", page 345. + */ +public class MD5DigestTest + extends DigestTest +{ + static final String[] messages = + { + "", + "a", + "abc", + "abcdefghijklmnopqrstuvwxyz" + }; + + static final String[] digests = + { + "d41d8cd98f00b204e9800998ecf8427e", + "0cc175b9c0f1b6a831c399e269772661", + "900150983cd24fb0d6963f7d28e17f72", + "c3fcd3d76192e4007dfb496cca67e13b" + }; + + MD5DigestTest() + { + super(new MD5Digest(), messages, digests); + } + + protected Digest cloneDigest(Digest digest) + { + return new MD5Digest((MD5Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new MD5Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new MD5DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD5HMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD5HMacTest.java new file mode 100644 index 000000000..5e467965e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MD5HMacTest.java @@ -0,0 +1,98 @@ + +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.MD5Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * MD5 HMac Test, test vectors from RFC 2202 + */ +public class MD5HMacTest + extends SimpleTest +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "9294727a3638bb1c13f48ef8158bfc9d", + "750c783e6ab0b503eaa86e310a5db738", + "56be34521d144c88dbb8c733f0e8b3f6", + "697eaf0aca3a3aea3a75164746ffaa79", + "56461ef2342edc00f9bab995690efd4c", + "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd", + "6f630fad67cda0ee1fb1f562db3aa53e" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" + }; + + public String getName() + { + return "MD5HMac"; + } + + public void performTest() + { + HMac hmac = new HMac(new MD5Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!areEqual(resBuf, Hex.decode(digests[i]))) + { + fail("Vector " + i + " failed"); + } + } + + // test reset + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!areEqual(resBuf, Hex.decode(digests[vector]))) + { + fail("Reset with vector " + vector + " failed"); + } + } + + public static void main( + String[] args) + { + runTest(new MD5HMacTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MGF1GeneratorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MGF1GeneratorTest.java new file mode 100644 index 000000000..a8fcc035b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MGF1GeneratorTest.java @@ -0,0 +1,88 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.DerivationFunction; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.ShortenedDigest; +import com.fr.third.org.bouncycastle.crypto.generators.MGF1BytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.MGFParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * MGF1 tests - vectors from ISO 18033 for KDF1 (equivalent). + */ +public class MGF1GeneratorTest + extends SimpleTest +{ + private byte[] seed1 = Hex.decode("d6e168c5f256a2dcff7ef12facd390f393c7a88d"); + private byte[] mask1 = Hex.decode( + "0742ba966813af75536bb6149cc44fc256fd6406df79665bc31dc5" + + "a62f70535e52c53015b9d37d412ff3c1193439599e1b628774c50d9c" + + "cb78d82c425e4521ee47b8c36a4bcffe8b8112a89312fc04420a39de" + + "99223890e74ce10378bc515a212b97b8a6447ba6a8870278"); + + private byte[] seed2 = Hex.decode( + "032e45326fa859a72ec235acff929b15d1372e30b207255f0611b8f785d7643741" + + "52e0ac009e509e7ba30cd2f1778e113b64e135cf4e2292c75efe5288edfda4"); + private byte[] mask2 = Hex.decode( + "5f8de105b5e96b2e490ddecbd147dd1def7e3b8e0e6a26eb7b956ccb8b3bdc1ca9" + + "75bc57c3989e8fbad31a224655d800c46954840ff32052cdf0d640562bdfadfa263c" + + "fccf3c52b29f2af4a1869959bc77f854cf15bd7a25192985a842dbff8e13efee5b7e" + + "7e55bbe4d389647c686a9a9ab3fb889b2d7767d3837eea4e0a2f04"); + + private byte[] seed3 = seed2; + private byte[] mask3= Hex.decode( + "09e2decf2a6e1666c2f6071ff4298305e2643fd510a2403db42a8743cb989de86e" + + "668d168cbe604611ac179f819a3d18412e9eb45668f2923c087c12fee0c5a0d2a8aa" + + "70185401fbbd99379ec76c663e875a60b4aacb1319fa11c3365a8b79a44669f26fb5" + + "55c80391847b05eca1cb5cf8c2d531448d33fbaca19f6410ee1fcb"); + + public void performTest() + { + checkMask(1, new MGF1BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed1, mask1); + checkMask(2, new MGF1BytesGenerator(new SHA1Digest()), seed2, mask2); + checkMask(3, new MGF1BytesGenerator(new ShortenedDigest(new SHA256Digest(), 20)), seed3, mask3); + + try + { + new MGF1BytesGenerator(new SHA1Digest()).generateBytes(new byte[10], 0, 20); + + fail("short input array not caught"); + } + catch (DataLengthException e) + { + // expected + } + } + + private void checkMask( + int count, + DerivationFunction kdf, + byte[] seed, + byte[] result) + { + byte[] data = new byte[result.length]; + + kdf.init(new MGFParameters(seed)); + + kdf.generateBytes(data, 0, data.length); + + if (!areEqual(result, data)) + { + fail("MGF1 failed generator test " + count); + } + } + + public String getName() + { + return "MGF1"; + } + + public static void main( + String[] args) + { + runTest(new MGF1GeneratorTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MacTest.java new file mode 100644 index 000000000..36dd993a8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/MacTest.java @@ -0,0 +1,181 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.macs.CBCBlockCipherMac; +import com.fr.third.org.bouncycastle.crypto.macs.CFBBlockCipherMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.crypto.paddings.PKCS7Padding; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * MAC tester - vectors from + * FIP 81 and + * FIP 113. + */ +public class MacTest + extends SimpleTest +{ + static byte[] keyBytes = Hex.decode("0123456789abcdef"); + static byte[] ivBytes = Hex.decode("1234567890abcdef"); + + static byte[] input1 = Hex.decode("37363534333231204e6f77206973207468652074696d6520666f7220"); + + static byte[] output1 = Hex.decode("f1d30f68"); + static byte[] output2 = Hex.decode("58d2e77e"); + static byte[] output3 = Hex.decode("cd647403"); + + // + // these aren't NIST vectors, just for regression testing. + // + static byte[] input2 = Hex.decode("3736353433323120"); + + static byte[] output4 = Hex.decode("3af549c9"); + static byte[] output5 = Hex.decode("188fbdd5"); + static byte[] output6 = Hex.decode("7045eecd"); + + public MacTest() + { + } + + public void performTest() + { + KeyParameter key = new KeyParameter(keyBytes); + BlockCipher cipher = new DESEngine(); + Mac mac = new CBCBlockCipherMac(cipher); + + // + // standard DAC - zero IV + // + mac.init(key); + + mac.update(input1, 0, input1.length); + + byte[] out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output1)) + { + fail("Failed - expected " + new String(Hex.encode(output1)) + " got " + new String(Hex.encode(out))); + } + + // + // mac with IV. + // + ParametersWithIV param = new ParametersWithIV(key, ivBytes); + + mac.init(param); + + mac.update(input1, 0, input1.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output2)) + { + fail("Failed - expected " + new String(Hex.encode(output2)) + " got " + new String(Hex.encode(out))); + } + + // + // CFB mac with IV - 8 bit CFB mode + // + param = new ParametersWithIV(key, ivBytes); + + mac = new CFBBlockCipherMac(cipher); + + mac.init(param); + + mac.update(input1, 0, input1.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output3)) + { + fail("Failed - expected " + new String(Hex.encode(output3)) + " got " + new String(Hex.encode(out))); + } + + // + // word aligned data - zero IV + // + mac.init(key); + + mac.update(input2, 0, input2.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output4)) + { + fail("Failed - expected " + new String(Hex.encode(output4)) + " got " + new String(Hex.encode(out))); + } + + // + // word aligned data - zero IV - CBC padding + // + mac = new CBCBlockCipherMac(cipher, new PKCS7Padding()); + + mac.init(key); + + mac.update(input2, 0, input2.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output5)) + { + fail("Failed - expected " + new String(Hex.encode(output5)) + " got " + new String(Hex.encode(out))); + } + + // + // non-word aligned data - zero IV - CBC padding + // + mac.reset(); + + mac.update(input1, 0, input1.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output6)) + { + fail("Failed - expected " + new String(Hex.encode(output6)) + " got " + new String(Hex.encode(out))); + } + + // + // non-word aligned data - zero IV - CBC padding + // + mac.init(key); + + mac.update(input1, 0, input1.length); + + out = new byte[4]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output6)) + { + fail("Failed - expected " + new String(Hex.encode(output6)) + " got " + new String(Hex.encode(out))); + } + } + + public String getName() + { + return "Mac"; + } + + public static void main( + String[] args) + { + runTest(new MacTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ModeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ModeTest.java new file mode 100644 index 000000000..2ec69a058 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ModeTest.java @@ -0,0 +1,115 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.modes.CFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.OFBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * CFB/OFB Mode test of IV padding. + */ +public class ModeTest + implements Test +{ + public ModeTest() + { + } + + private boolean isEqualTo( + byte[] a, + byte[] b) + { + for (int i = 0; i != a.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + public TestResult perform() + { + KeyParameter key = new KeyParameter(Hex.decode("0011223344556677")); + byte[] input = Hex.decode("4e6f7720"); + byte[] out1 = new byte[4]; + byte[] out2 = new byte[4]; + + + BlockCipher ofb = new OFBBlockCipher(new DESEngine(), 32); + + ofb.init(true, new ParametersWithIV(key, Hex.decode("1122334455667788"))); + + ofb.processBlock(input, 0, out1, 0); + + ofb.init(false, new ParametersWithIV(key, Hex.decode("1122334455667788"))); + ofb.processBlock(out1, 0, out2, 0); + + if (!isEqualTo(out2, input)) + { + return new SimpleTestResult(false, getName() + ": test 1 - in != out"); + } + + ofb.init(true, new ParametersWithIV(key, Hex.decode("11223344"))); + + ofb.processBlock(input, 0, out1, 0); + + ofb.init(false, new ParametersWithIV(key, Hex.decode("0000000011223344"))); + ofb.processBlock(out1, 0, out2, 0); + + if (!isEqualTo(out2, input)) + { + return new SimpleTestResult(false, getName() + ": test 2 - in != out"); + } + + BlockCipher cfb = new CFBBlockCipher(new DESEngine(), 32); + + cfb.init(true, new ParametersWithIV(key, Hex.decode("1122334455667788"))); + + cfb.processBlock(input, 0, out1, 0); + + cfb.init(false, new ParametersWithIV(key, Hex.decode("1122334455667788"))); + cfb.processBlock(out1, 0, out2, 0); + + if (!isEqualTo(out2, input)) + { + return new SimpleTestResult(false, getName() + ": test 3 - in != out"); + } + + cfb.init(true, new ParametersWithIV(key, Hex.decode("11223344"))); + + cfb.processBlock(input, 0, out1, 0); + + cfb.init(false, new ParametersWithIV(key, Hex.decode("0000000011223344"))); + cfb.processBlock(out1, 0, out2, 0); + + if (!isEqualTo(out2, input)) + { + return new SimpleTestResult(false, getName() + ": test 4 - in != out"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public String getName() + { + return "ModeTest"; + } + + public static void main( + String[] args) + { + ModeTest test = new ModeTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NISTCTSTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NISTCTSTest.java new file mode 100644 index 000000000..f0bb0948b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NISTCTSTest.java @@ -0,0 +1,170 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.modes.NISTCTSBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * CTS tester + */ +public class NISTCTSTest + extends SimpleTest +{ + private static KeyParameter key = new KeyParameter(Hex.decode("000102030405060708090a0b0c0d0e0f")); + private static byte[] iv = Hex.decode("101112131415161718191a1b1c1d1e1f"); + + private static byte[] singleBlock = Hex.decode("4920616d206f6e6520626c6f636b2e2e"); + private static byte[] singleOut = Hex.decode("8aad2098847a2d74ac87de22745d2537"); + + private static byte[] twoBlock = Hex.decode("4920616d206174206c656173742074776f20626c6f636b73206c6f6e672e2e2e"); + + private static byte[] cs1TwoBlockOut = Hex.decode("3f07fd5816c3b96349eb9f6a074909d67237eb8aa9a7467b8a388c61d0e8f35a"); + private static byte[] cs2TwoBlockOut = Hex.decode("3f07fd5816c3b96349eb9f6a074909d67237eb8aa9a7467b8a388c61d0e8f35a"); + private static byte[] cs3TwoBlockOut = Hex.decode("7237eb8aa9a7467b8a388c61d0e8f35a3f07fd5816c3b96349eb9f6a074909d6"); + + private static byte[] notQuiteTwo = Hex.decode("4920616d206e6f742071756974652074776f2e2e2e"); + + private static byte[] cs1NotQuiteTwoBlockOut = Hex.decode("22ecf2ac77f098097ca69b72e3a46e9ca21bb5ebbc"); + private static byte[] cs2NotQuiteTwoBlockOut = Hex.decode("f098097ca69b72e3a46e9ca21bb5ebbc22ecf2ac77"); + private static byte[] cs3NotQuiteTwoBlockOut = Hex.decode("f098097ca69b72e3a46e9ca21bb5ebbc22ecf2ac77"); + + static byte[] in1 = Hex.decode("4e6f7720697320746865207420"); + static byte[] in2 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f0aaa"); + static byte[] out1 = Hex.decode("9952f131588465033fa40e8a98"); + static byte[] out2 = Hex.decode("358f84d01eb42988dc34efb994"); + static byte[] out3 = Hex.decode("170171cfad3f04530c509b0c1f0be0aefbd45a8e3755a873bff5ea198504b71683c6"); + + private void testCTS( + int id, + int type, + BlockCipher cipher, + CipherParameters params, + byte[] input, + byte[] output) + throws Exception + { + byte[] out = new byte[input.length]; + BufferedBlockCipher engine = new NISTCTSBlockCipher(type, cipher); + + engine.init(true, params); + + int len = engine.processBytes(input, 0, input.length, out, 0); + + engine.doFinal(out, len); + + if (!areEqual(output, out)) + { + fail(id + " failed encryption expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + engine.init(false, params); + + len = engine.processBytes(output, 0, output.length, out, 0); + + engine.doFinal(out, len); + + if (!areEqual(input, out)) + { + fail(id + " failed decryption expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + } + + private void testExceptions() throws InvalidCipherTextException + { + BufferedBlockCipher engine = new NISTCTSBlockCipher(NISTCTSBlockCipher.CS1, new AESEngine()); + CipherParameters params = new KeyParameter(new byte[engine.getBlockSize()]); + engine.init(true, params); + + byte[] out = new byte[engine.getOutputSize(engine.getBlockSize())]; + + engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0); + try + { + engine.doFinal(out, 0); + fail("Expected CTS encrypt error on < 1 block input"); + } catch(DataLengthException e) + { + // Expected + } + + engine.init(true, params); + engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0); + try + { + engine.doFinal(out, 0); + } catch(DataLengthException e) + { + fail("Unexpected CTS encrypt error on == 1 block input"); + } + + engine.init(false, params); + engine.processBytes(new byte[engine.getBlockSize() - 1], 0, engine.getBlockSize() - 1, out, 0); + try + { + engine.doFinal(out, 0); + fail("Expected CTS decrypt error on < 1 block input"); + } catch(DataLengthException e) + { + // Expected + } + + engine.init(false, params); + engine.processBytes(new byte[engine.getBlockSize()], 0, engine.getBlockSize(), out, 0); + try + { + engine.doFinal(out, 0); + } catch(DataLengthException e) + { + fail("Unexpected CTS decrypt error on == 1 block input"); + } + + } + + public String getName() + { + return "NISTCTS"; + } + + public void performTest() + throws Exception + { + testCTS(1, NISTCTSBlockCipher.CS1, new AESEngine(), new ParametersWithIV(key, iv), singleBlock, singleOut); + testCTS(2, NISTCTSBlockCipher.CS2, new AESEngine(), new ParametersWithIV(key, iv), singleBlock, singleOut); + testCTS(3, NISTCTSBlockCipher.CS3, new AESEngine(), new ParametersWithIV(key, iv), singleBlock, singleOut); + + testCTS(4, NISTCTSBlockCipher.CS1, new AESEngine(), new ParametersWithIV(key, iv), twoBlock, cs1TwoBlockOut); + testCTS(5, NISTCTSBlockCipher.CS2, new AESEngine(), new ParametersWithIV(key, iv), twoBlock, cs2TwoBlockOut); + testCTS(6, NISTCTSBlockCipher.CS3, new AESEngine(), new ParametersWithIV(key, iv), twoBlock, cs3TwoBlockOut); + + testCTS(7, NISTCTSBlockCipher.CS1, new AESEngine(), new ParametersWithIV(key, iv), notQuiteTwo, cs1NotQuiteTwoBlockOut); + testCTS(8, NISTCTSBlockCipher.CS2, new AESEngine(), new ParametersWithIV(key, iv), notQuiteTwo, cs2NotQuiteTwoBlockOut); + testCTS(9, NISTCTSBlockCipher.CS3, new AESEngine(), new ParametersWithIV(key, iv), notQuiteTwo, cs3NotQuiteTwoBlockOut); + + byte[] aes128b = Hex.decode("aafd12f659cae63489b479e5076ddec2f06cb58faafd12f6"); + byte[] aesIn1b = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); + byte[] aesOut1b = Hex.decode("6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04"); + + testCTS(10, NISTCTSBlockCipher.CS3, new AESEngine(), new ParametersWithIV(new KeyParameter(aes128b), Hex.decode("aafd12f659cae63489b479e5076ddec2")), aesIn1b, aesOut1b); + + byte[] aes128c = Hex.decode("aafd12f659cae63489b479e5076ddec2"); + byte[] aesOut1c = Hex.decode("0af33c005a337af55a5149effc5108eaa1ea87de8a8556e8786b8f230da64e56"); + + testCTS(11, NISTCTSBlockCipher.CS3, new AESEngine(), new ParametersWithIV(new KeyParameter(aes128c), Hex.decode("aafd12f659cae63489b479e5076ddec2")), aesIn1b, aesOut1c); + + testExceptions(); + } + + public static void main( + String[] args) + { + runTest(new NISTCTSTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NaccacheSternTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NaccacheSternTest.java new file mode 100644 index 000000000..5199a79cb --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NaccacheSternTest.java @@ -0,0 +1,354 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.NaccacheSternEngine; +import com.fr.third.org.bouncycastle.crypto.generators.NaccacheSternKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.NaccacheSternKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.NaccacheSternKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.NaccacheSternPrivateKeyParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test case for NaccacheStern cipher. For details on this cipher, please see + * + * http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf + * + * Performs the following tests: + *
    + *
  • Toy example from the NaccacheSternPaper
  • + *
  • 768 bit test with text "Now is the time for all good men." (ripped from RSA test) and + * the same test with the first byte replaced by 0xFF
  • + *
  • 1024 bit test analog to 768 bit test
  • + *
+ */ +public class NaccacheSternTest + extends SimpleTest +{ + static final boolean debug = false; + + static final NaccacheSternEngine cryptEng = new NaccacheSternEngine(); + + static final NaccacheSternEngine decryptEng = new NaccacheSternEngine(); + + // Values from NaccacheStern paper + static final BigInteger a = BigInteger.valueOf(101); + + static final BigInteger u1 = BigInteger.valueOf(3); + + static final BigInteger u2 = BigInteger.valueOf(5); + + static final BigInteger u3 = BigInteger.valueOf(7); + + static final BigInteger b = BigInteger.valueOf(191); + + static final BigInteger v1 = BigInteger.valueOf(11); + + static final BigInteger v2 = BigInteger.valueOf(13); + + static final BigInteger v3 = BigInteger.valueOf(17); + + static final BigInteger ONE = BigInteger.valueOf(1); + + static final BigInteger TWO = BigInteger.valueOf(2); + + static final BigInteger sigma = u1.multiply(u2).multiply(u3).multiply(v1) + .multiply(v2).multiply(v3); + + static final BigInteger p = TWO.multiply(a).multiply(u1).multiply(u2) + .multiply(u3).add(ONE); + + static final BigInteger q = TWO.multiply(b).multiply(v1).multiply(v2) + .multiply(v3).add(ONE); + + static final BigInteger n = p.multiply(q); + + static final BigInteger phi_n = p.subtract(ONE).multiply(q.subtract(ONE)); + + static final BigInteger g = BigInteger.valueOf(131); + + static final Vector smallPrimes = new Vector(); + + // static final BigInteger paperTest = BigInteger.valueOf(202); + + static final String input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + static final BigInteger paperTest = BigInteger.valueOf(202); + + // + // to check that we handling byte extension by big number correctly. + // + static final String edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + static + { + cryptEng.setDebug(debug); + decryptEng.setDebug(debug); + + // First the Parameters from the NaccacheStern Paper + // (see http://www.gemplus.com/smart/rd/publications/pdf/NS98pkcs.pdf ) + + smallPrimes.addElement(u1); + smallPrimes.addElement(u2); + smallPrimes.addElement(u3); + smallPrimes.addElement(v1); + smallPrimes.addElement(v2); + smallPrimes.addElement(v3); + } + + public String getName() + { + return "NaccacheStern"; + } + + public void performTest() + { + // Test with given key from NaccacheSternPaper (totally insecure) + + NaccacheSternKeyParameters pubParameters = new NaccacheSternKeyParameters(false, g, n, sigma.bitLength()); + + NaccacheSternPrivateKeyParameters privParameters = new NaccacheSternPrivateKeyParameters(g, n, sigma.bitLength(), smallPrimes, phi_n); + + AsymmetricCipherKeyPair pair = new AsymmetricCipherKeyPair(pubParameters, privParameters); + + // Initialize Engines with KeyPair + + if (debug) + { + System.out.println("initializing encryption engine"); + } + cryptEng.init(true, pair.getPublic()); + + if (debug) + { + System.out.println("initializing decryption engine"); + } + decryptEng.init(false, pair.getPrivate()); + + byte[] data = paperTest.toByteArray(); + + if (!new BigInteger(data).equals(new BigInteger(enDeCrypt(data)))) + { + fail("failed NaccacheStern paper test"); + } + + // + // key generation test + // + + // + // 768 Bit test + // + + if (debug) + { + System.out.println(); + System.out.println("768 Bit TEST"); + } + + // specify key generation parameters + NaccacheSternKeyGenerationParameters genParam + = new NaccacheSternKeyGenerationParameters(new SecureRandom(), 768, 8, 30, debug); + + // Initialize Key generator and generate key pair + NaccacheSternKeyPairGenerator pGen = new NaccacheSternKeyPairGenerator(); + pGen.init(genParam); + + pair = pGen.generateKeyPair(); + + if (((NaccacheSternKeyParameters)pair.getPublic()).getModulus().bitLength() < 768) + { + System.out.println("FAILED: key size is <786 bit, exactly " + + ((NaccacheSternKeyParameters)pair.getPublic()).getModulus().bitLength() + " bit"); + fail("failed key generation (768) length test"); + } + + // Initialize Engines with KeyPair + + if (debug) + { + System.out.println("initializing " + genParam.getStrength() + " bit encryption engine"); + } + cryptEng.init(true, pair.getPublic()); + + if (debug) + { + System.out.println("initializing " + genParam.getStrength() + " bit decryption engine"); + } + decryptEng.init(false, pair.getPrivate()); + + // Basic data input + data = Hex.decode(input); + + if (!new BigInteger(1, data).equals(new BigInteger(1, enDeCrypt(data)))) + { + fail("failed encryption decryption (" + genParam.getStrength() + ") basic test"); + } + + // Data starting with FF byte (would be interpreted as negative + // BigInteger) + + data = Hex.decode(edgeInput); + + if (!new BigInteger(1, data).equals(new BigInteger(1, enDeCrypt(data)))) + { + fail("failed encryption decryption (" + genParam.getStrength() + ") edgeInput test"); + } + + // + // 1024 Bit Test + // +/* + if (debug) + { + System.out.println(); + System.out.println("1024 Bit TEST"); + } + + // specify key generation parameters + genParam = new NaccacheSternKeyGenerationParameters(new SecureRandom(), 1024, 8, 40); + + pGen.init(genParam); + pair = pGen.generateKeyPair(); + + if (((NaccacheSternKeyParameters)pair.getPublic()).getModulus().bitLength() < 1024) + { + if (debug) + { + System.out.println("FAILED: key size is <1024 bit, exactly " + + ((NaccacheSternKeyParameters)pair.getPublic()).getModulus().bitLength() + " bit"); + } + fail("failed key generation (1024) length test"); + } + + // Initialize Engines with KeyPair + + if (debug) + { + System.out.println("initializing " + genParam.getStrength() + " bit encryption engine"); + } + cryptEng.init(true, pair.getPublic()); + + if (debug) + { + System.out.println("initializing " + genParam.getStrength() + " bit decryption engine"); + } + decryptEng.init(false, pair.getPrivate()); + + if (debug) + { + System.out.println("Data is " + new BigInteger(1, data)); + } + + // Basic data input + data = Hex.decode(input); + + if (!new BigInteger(1, data).equals(new BigInteger(1, enDeCrypt(data)))) + { + fail("failed encryption decryption (" + genParam.getStrength() + ") basic test"); + } + + // Data starting with FF byte (would be interpreted as negative + // BigInteger) + + data = Hex.decode(edgeInput); + + if (!new BigInteger(1, data).equals(new BigInteger(1, enDeCrypt(data)))) + { + fail("failed encryption decryption (" + genParam.getStrength() + ") edgeInput test"); + } +*/ + // END OF TEST CASE + + try + { + new NaccacheSternEngine().processBlock(new byte[]{ 1 }, 0, 1); + fail("failed initialisation check"); + } + catch (IllegalStateException e) + { + // expected + } + catch (InvalidCipherTextException e) + { + fail("failed initialisation check"); + } + + if (debug) + { + System.out.println("All tests successful"); + } + } + + private byte[] enDeCrypt(byte[] input) + { + + // create work array + byte[] data = new byte[input.length]; + System.arraycopy(input, 0, data, 0, data.length); + + // Perform encryption like in the paper from Naccache-Stern + if (debug) + { + System.out.println("encrypting data. Data representation\n" + // + "As String:.... " + new String(data) + "\n" + + "As BigInteger: " + new BigInteger(1, data)); + System.out.println("data length is " + data.length); + } + + try + { + data = cryptEng.processData(data); + } + catch (InvalidCipherTextException e) + { + if (debug) + { + System.out.println("failed - exception " + e.toString() + "\n" + e.getMessage()); + } + fail("failed - exception " + e.toString() + "\n" + e.getMessage()); + } + + if (debug) + { + System.out.println("enrypted data representation\n" + // + "As String:.... " + new String(data) + "\n" + + "As BigInteger: " + new BigInteger(1, data)); + System.out.println("data length is " + data.length); + } + + try + { + data = decryptEng.processData(data); + } + catch (InvalidCipherTextException e) + { + if (debug) + { + System.out.println("failed - exception " + e.toString() + "\n" + e.getMessage()); + } + fail("failed - exception " + e.toString() + "\n" + e.getMessage()); + } + + if (debug) + { + System.out.println("decrypted data representation\n" + // + "As String:.... " + new String(data) + "\n" + + "As BigInteger: " + new BigInteger(1, data)); + System.out.println("data length is " + data.length); + } + + return data; + + } + + public static void main(String[] args) + { + runTest(new NaccacheSternTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NoekeonTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NoekeonTest.java new file mode 100644 index 000000000..28a9c1383 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NoekeonTest.java @@ -0,0 +1,45 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.NoekeonEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Noekeon tester + */ +public class NoekeonTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new NoekeonEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", + "b1656851699e29fa24b70148503d2dfc"), + new BlockCipherVectorTest(1, new NoekeonEngine(), + new KeyParameter(Hex.decode("ffffffffffffffffffffffffffffffff")), + "ffffffffffffffffffffffffffffffff", + "2a78421b87c7d0924f26113f1d1349b2"), + new BlockCipherVectorTest(2, new NoekeonEngine(), + new KeyParameter(Hex.decode("b1656851699e29fa24b70148503d2dfc")), + "2a78421b87c7d0924f26113f1d1349b2", + "e2f687e07b75660ffc372233bc47532c") + }; + + NoekeonTest() + { + super(tests, new NoekeonEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "Noekeon"; + } + + public static void main( + String[] args) + { + runTest(new NoekeonTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NonMemoableDigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NonMemoableDigestTest.java new file mode 100644 index 000000000..d1c18deae --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NonMemoableDigestTest.java @@ -0,0 +1,113 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.NonMemoableDigest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * SHA1 HMac Test, test vectors from RFC 2202 + */ +public class NonMemoableDigestTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "b617318655057264e28bc0b6fb378c8ef146be00", + "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", + "125d7342b9ac11cd91a39af48aa17b4f63f175d3", + "4c9007f4026250c6bc8414f9bf50c86c2d7235da", + "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", + "aa4ae5e15272d00e95705637ce8a3b55ed402112", + "e8e99d0f45237d786d6bbaa7965c7808bbff1a91", + "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", + "aa4ae5e15272d00e95705637ce8a3b55ed402112", + "e8e99d0f45237d786d6bbaa7965c7808bbff1a91" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" + }; + + public String getName() + { + return "NonMemoableDigest"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new NonMemoableDigest(new SHA1Digest())); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = Strings.toByteArray(messages[i]); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed"); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = Strings.toByteArray(messages[vector]); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + ": Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + NonMemoableDigestTest test = new NonMemoableDigestTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NullTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NullTest.java new file mode 100644 index 000000000..ce87c97ca --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/NullTest.java @@ -0,0 +1,77 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.engines.NullEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class NullTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new NullEngine(), + new KeyParameter(Hex.decode("00")), "00", "00") + }; + + NullTest() + { + super(tests, new NullEngine(), new KeyParameter(new byte[2])); + } + + public String getName() + { + return "Null"; + } + + public void performTest() + throws Exception + { + super.performTest(); + + BlockCipher engine = new NullEngine(); + + engine.init(true, null); + + byte[] buf = new byte[1]; + + engine.processBlock(buf, 0, buf, 0); + + if (buf[0] != 0) + { + fail("NullCipher changed data!"); + } + + byte[] shortBuf = new byte[0]; + + try + { + engine.processBlock(shortBuf, 0, buf, 0); + + fail("failed short input check"); + } + catch (DataLengthException e) + { + // expected + } + + try + { + engine.processBlock(buf, 0, shortBuf, 0); + + fail("failed short output check"); + } + catch (DataLengthException e) + { + // expected + } + } + + public static void main( + String[] args) + { + runTest(new NullTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OAEPTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OAEPTest.java new file mode 100644 index 000000000..2c01fdfa3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OAEPTest.java @@ -0,0 +1,907 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.RSAPrivateKey; +import com.fr.third.org.bouncycastle.asn1.pkcs.RSAPublicKey; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.crypto.AsymmetricBlockCipher; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.encodings.OAEPEncoding; +import com.fr.third.org.bouncycastle.crypto.engines.RSAEngine; +import com.fr.third.org.bouncycastle.crypto.generators.RSAKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class OAEPTest + extends SimpleTest +{ + static byte[] pubKeyEnc1 = + { + (byte)0x30, (byte)0x5a, (byte)0x30, (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, + (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, + (byte)0x00, (byte)0x03, (byte)0x49, (byte)0x00, (byte)0x30, (byte)0x46, (byte)0x02, (byte)0x41, + (byte)0x00, (byte)0xaa, (byte)0x36, (byte)0xab, (byte)0xce, (byte)0x88, (byte)0xac, (byte)0xfd, + (byte)0xff, (byte)0x55, (byte)0x52, (byte)0x3c, (byte)0x7f, (byte)0xc4, (byte)0x52, (byte)0x3f, + (byte)0x90, (byte)0xef, (byte)0xa0, (byte)0x0d, (byte)0xf3, (byte)0x77, (byte)0x4a, (byte)0x25, + (byte)0x9f, (byte)0x2e, (byte)0x62, (byte)0xb4, (byte)0xc5, (byte)0xd9, (byte)0x9c, (byte)0xb5, + (byte)0xad, (byte)0xb3, (byte)0x00, (byte)0xa0, (byte)0x28, (byte)0x5e, (byte)0x53, (byte)0x01, + (byte)0x93, (byte)0x0e, (byte)0x0c, (byte)0x70, (byte)0xfb, (byte)0x68, (byte)0x76, (byte)0x93, + (byte)0x9c, (byte)0xe6, (byte)0x16, (byte)0xce, (byte)0x62, (byte)0x4a, (byte)0x11, (byte)0xe0, + (byte)0x08, (byte)0x6d, (byte)0x34, (byte)0x1e, (byte)0xbc, (byte)0xac, (byte)0xa0, (byte)0xa1, + (byte)0xf5, (byte)0x02, (byte)0x01, (byte)0x11 + }; + + static byte[] privKeyEnc1 = + { + (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x52, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30, + (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, + (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x82, + (byte)0x01, (byte)0x3c, (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x38, (byte)0x02, (byte)0x01, + (byte)0x00, (byte)0x02, (byte)0x41, (byte)0x00, (byte)0xaa, (byte)0x36, (byte)0xab, (byte)0xce, + (byte)0x88, (byte)0xac, (byte)0xfd, (byte)0xff, (byte)0x55, (byte)0x52, (byte)0x3c, (byte)0x7f, + (byte)0xc4, (byte)0x52, (byte)0x3f, (byte)0x90, (byte)0xef, (byte)0xa0, (byte)0x0d, (byte)0xf3, + (byte)0x77, (byte)0x4a, (byte)0x25, (byte)0x9f, (byte)0x2e, (byte)0x62, (byte)0xb4, (byte)0xc5, + (byte)0xd9, (byte)0x9c, (byte)0xb5, (byte)0xad, (byte)0xb3, (byte)0x00, (byte)0xa0, (byte)0x28, + (byte)0x5e, (byte)0x53, (byte)0x01, (byte)0x93, (byte)0x0e, (byte)0x0c, (byte)0x70, (byte)0xfb, + (byte)0x68, (byte)0x76, (byte)0x93, (byte)0x9c, (byte)0xe6, (byte)0x16, (byte)0xce, (byte)0x62, + (byte)0x4a, (byte)0x11, (byte)0xe0, (byte)0x08, (byte)0x6d, (byte)0x34, (byte)0x1e, (byte)0xbc, + (byte)0xac, (byte)0xa0, (byte)0xa1, (byte)0xf5, (byte)0x02, (byte)0x01, (byte)0x11, (byte)0x02, + (byte)0x40, (byte)0x0a, (byte)0x03, (byte)0x37, (byte)0x48, (byte)0x62, (byte)0x64, (byte)0x87, + (byte)0x69, (byte)0x5f, (byte)0x5f, (byte)0x30, (byte)0xbc, (byte)0x38, (byte)0xb9, (byte)0x8b, + (byte)0x44, (byte)0xc2, (byte)0xcd, (byte)0x2d, (byte)0xff, (byte)0x43, (byte)0x40, (byte)0x98, + (byte)0xcd, (byte)0x20, (byte)0xd8, (byte)0xa1, (byte)0x38, (byte)0xd0, (byte)0x90, (byte)0xbf, + (byte)0x64, (byte)0x79, (byte)0x7c, (byte)0x3f, (byte)0xa7, (byte)0xa2, (byte)0xcd, (byte)0xcb, + (byte)0x3c, (byte)0xd1, (byte)0xe0, (byte)0xbd, (byte)0xba, (byte)0x26, (byte)0x54, (byte)0xb4, + (byte)0xf9, (byte)0xdf, (byte)0x8e, (byte)0x8a, (byte)0xe5, (byte)0x9d, (byte)0x73, (byte)0x3d, + (byte)0x9f, (byte)0x33, (byte)0xb3, (byte)0x01, (byte)0x62, (byte)0x4a, (byte)0xfd, (byte)0x1d, + (byte)0x51, (byte)0x02, (byte)0x21, (byte)0x00, (byte)0xd8, (byte)0x40, (byte)0xb4, (byte)0x16, + (byte)0x66, (byte)0xb4, (byte)0x2e, (byte)0x92, (byte)0xea, (byte)0x0d, (byte)0xa3, (byte)0xb4, + (byte)0x32, (byte)0x04, (byte)0xb5, (byte)0xcf, (byte)0xce, (byte)0x33, (byte)0x52, (byte)0x52, + (byte)0x4d, (byte)0x04, (byte)0x16, (byte)0xa5, (byte)0xa4, (byte)0x41, (byte)0xe7, (byte)0x00, + (byte)0xaf, (byte)0x46, (byte)0x12, (byte)0x0d, (byte)0x02, (byte)0x21, (byte)0x00, (byte)0xc9, + (byte)0x7f, (byte)0xb1, (byte)0xf0, (byte)0x27, (byte)0xf4, (byte)0x53, (byte)0xf6, (byte)0x34, + (byte)0x12, (byte)0x33, (byte)0xea, (byte)0xaa, (byte)0xd1, (byte)0xd9, (byte)0x35, (byte)0x3f, + (byte)0x6c, (byte)0x42, (byte)0xd0, (byte)0x88, (byte)0x66, (byte)0xb1, (byte)0xd0, (byte)0x5a, + (byte)0x0f, (byte)0x20, (byte)0x35, (byte)0x02, (byte)0x8b, (byte)0x9d, (byte)0x89, (byte)0x02, + (byte)0x20, (byte)0x59, (byte)0x0b, (byte)0x95, (byte)0x72, (byte)0xa2, (byte)0xc2, (byte)0xa9, + (byte)0xc4, (byte)0x06, (byte)0x05, (byte)0x9d, (byte)0xc2, (byte)0xab, (byte)0x2f, (byte)0x1d, + (byte)0xaf, (byte)0xeb, (byte)0x7e, (byte)0x8b, (byte)0x4f, (byte)0x10, (byte)0xa7, (byte)0x54, + (byte)0x9e, (byte)0x8e, (byte)0xed, (byte)0xf5, (byte)0xb4, (byte)0xfc, (byte)0xe0, (byte)0x9e, + (byte)0x05, (byte)0x02, (byte)0x21, (byte)0x00, (byte)0x8e, (byte)0x3c, (byte)0x05, (byte)0x21, + (byte)0xfe, (byte)0x15, (byte)0xe0, (byte)0xea, (byte)0x06, (byte)0xa3, (byte)0x6f, (byte)0xf0, + (byte)0xf1, (byte)0x0c, (byte)0x99, (byte)0x52, (byte)0xc3, (byte)0x5b, (byte)0x7a, (byte)0x75, + (byte)0x14, (byte)0xfd, (byte)0x32, (byte)0x38, (byte)0xb8, (byte)0x0a, (byte)0xad, (byte)0x52, + (byte)0x98, (byte)0x62, (byte)0x8d, (byte)0x51, (byte)0x02, (byte)0x20, (byte)0x36, (byte)0x3f, + (byte)0xf7, (byte)0x18, (byte)0x9d, (byte)0xa8, (byte)0xe9, (byte)0x0b, (byte)0x1d, (byte)0x34, + (byte)0x1f, (byte)0x71, (byte)0xd0, (byte)0x9b, (byte)0x76, (byte)0xa8, (byte)0xa9, (byte)0x43, + (byte)0xe1, (byte)0x1d, (byte)0x10, (byte)0xb2, (byte)0x4d, (byte)0x24, (byte)0x9f, (byte)0x2d, + (byte)0xea, (byte)0xfe, (byte)0xf8, (byte)0x0c, (byte)0x18, (byte)0x26 + }; + + static byte[] output1 = + { + (byte)0x1b, (byte)0x8f, (byte)0x05, (byte)0xf9, (byte)0xca, (byte)0x1a, (byte)0x79, (byte)0x52, + (byte)0x6e, (byte)0x53, (byte)0xf3, (byte)0xcc, (byte)0x51, (byte)0x4f, (byte)0xdb, (byte)0x89, + (byte)0x2b, (byte)0xfb, (byte)0x91, (byte)0x93, (byte)0x23, (byte)0x1e, (byte)0x78, (byte)0xb9, + (byte)0x92, (byte)0xe6, (byte)0x8d, (byte)0x50, (byte)0xa4, (byte)0x80, (byte)0xcb, (byte)0x52, + (byte)0x33, (byte)0x89, (byte)0x5c, (byte)0x74, (byte)0x95, (byte)0x8d, (byte)0x5d, (byte)0x02, + (byte)0xab, (byte)0x8c, (byte)0x0f, (byte)0xd0, (byte)0x40, (byte)0xeb, (byte)0x58, (byte)0x44, + (byte)0xb0, (byte)0x05, (byte)0xc3, (byte)0x9e, (byte)0xd8, (byte)0x27, (byte)0x4a, (byte)0x9d, + (byte)0xbf, (byte)0xa8, (byte)0x06, (byte)0x71, (byte)0x40, (byte)0x94, (byte)0x39, (byte)0xd2 + }; + + static byte[] pubKeyEnc2 = + { + (byte)0x30, (byte)0x4c, (byte)0x30, (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, + (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, + (byte)0x00, (byte)0x03, (byte)0x3b, (byte)0x00, (byte)0x30, (byte)0x38, (byte)0x02, (byte)0x33, + (byte)0x00, (byte)0xa3, (byte)0x07, (byte)0x9a, (byte)0x90, (byte)0xdf, (byte)0x0d, (byte)0xfd, + (byte)0x72, (byte)0xac, (byte)0x09, (byte)0x0c, (byte)0xcc, (byte)0x2a, (byte)0x78, (byte)0xb8, + (byte)0x74, (byte)0x13, (byte)0x13, (byte)0x3e, (byte)0x40, (byte)0x75, (byte)0x9c, (byte)0x98, + (byte)0xfa, (byte)0xf8, (byte)0x20, (byte)0x4f, (byte)0x35, (byte)0x8a, (byte)0x0b, (byte)0x26, + (byte)0x3c, (byte)0x67, (byte)0x70, (byte)0xe7, (byte)0x83, (byte)0xa9, (byte)0x3b, (byte)0x69, + (byte)0x71, (byte)0xb7, (byte)0x37, (byte)0x79, (byte)0xd2, (byte)0x71, (byte)0x7b, (byte)0xe8, + (byte)0x34, (byte)0x77, (byte)0xcf, (byte)0x02, (byte)0x01, (byte)0x03 + }; + + static byte[] privKeyEnc2 = + { + (byte)0x30, (byte)0x82, (byte)0x01, (byte)0x13, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30, + (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, + (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x81, + (byte)0xfe, (byte)0x30, (byte)0x81, (byte)0xfb, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x02, + (byte)0x33, (byte)0x00, (byte)0xa3, (byte)0x07, (byte)0x9a, (byte)0x90, (byte)0xdf, (byte)0x0d, + (byte)0xfd, (byte)0x72, (byte)0xac, (byte)0x09, (byte)0x0c, (byte)0xcc, (byte)0x2a, (byte)0x78, + (byte)0xb8, (byte)0x74, (byte)0x13, (byte)0x13, (byte)0x3e, (byte)0x40, (byte)0x75, (byte)0x9c, + (byte)0x98, (byte)0xfa, (byte)0xf8, (byte)0x20, (byte)0x4f, (byte)0x35, (byte)0x8a, (byte)0x0b, + (byte)0x26, (byte)0x3c, (byte)0x67, (byte)0x70, (byte)0xe7, (byte)0x83, (byte)0xa9, (byte)0x3b, + (byte)0x69, (byte)0x71, (byte)0xb7, (byte)0x37, (byte)0x79, (byte)0xd2, (byte)0x71, (byte)0x7b, + (byte)0xe8, (byte)0x34, (byte)0x77, (byte)0xcf, (byte)0x02, (byte)0x01, (byte)0x03, (byte)0x02, + (byte)0x32, (byte)0x6c, (byte)0xaf, (byte)0xbc, (byte)0x60, (byte)0x94, (byte)0xb3, (byte)0xfe, + (byte)0x4c, (byte)0x72, (byte)0xb0, (byte)0xb3, (byte)0x32, (byte)0xc6, (byte)0xfb, (byte)0x25, + (byte)0xa2, (byte)0xb7, (byte)0x62, (byte)0x29, (byte)0x80, (byte)0x4e, (byte)0x68, (byte)0x65, + (byte)0xfc, (byte)0xa4, (byte)0x5a, (byte)0x74, (byte)0xdf, (byte)0x0f, (byte)0x8f, (byte)0xb8, + (byte)0x41, (byte)0x3b, (byte)0x52, (byte)0xc0, (byte)0xd0, (byte)0xe5, (byte)0x3d, (byte)0x9b, + (byte)0x59, (byte)0x0f, (byte)0xf1, (byte)0x9b, (byte)0xe7, (byte)0x9f, (byte)0x49, (byte)0xdd, + (byte)0x21, (byte)0xe5, (byte)0xeb, (byte)0x02, (byte)0x1a, (byte)0x00, (byte)0xcf, (byte)0x20, + (byte)0x35, (byte)0x02, (byte)0x8b, (byte)0x9d, (byte)0x86, (byte)0x98, (byte)0x40, (byte)0xb4, + (byte)0x16, (byte)0x66, (byte)0xb4, (byte)0x2e, (byte)0x92, (byte)0xea, (byte)0x0d, (byte)0xa3, + (byte)0xb4, (byte)0x32, (byte)0x04, (byte)0xb5, (byte)0xcf, (byte)0xce, (byte)0x91, (byte)0x02, + (byte)0x1a, (byte)0x00, (byte)0xc9, (byte)0x7f, (byte)0xb1, (byte)0xf0, (byte)0x27, (byte)0xf4, + (byte)0x53, (byte)0xf6, (byte)0x34, (byte)0x12, (byte)0x33, (byte)0xea, (byte)0xaa, (byte)0xd1, + (byte)0xd9, (byte)0x35, (byte)0x3f, (byte)0x6c, (byte)0x42, (byte)0xd0, (byte)0x88, (byte)0x66, + (byte)0xb1, (byte)0xd0, (byte)0x5f, (byte)0x02, (byte)0x1a, (byte)0x00, (byte)0x8a, (byte)0x15, + (byte)0x78, (byte)0xac, (byte)0x5d, (byte)0x13, (byte)0xaf, (byte)0x10, (byte)0x2b, (byte)0x22, + (byte)0xb9, (byte)0x99, (byte)0xcd, (byte)0x74, (byte)0x61, (byte)0xf1, (byte)0x5e, (byte)0x6d, + (byte)0x22, (byte)0xcc, (byte)0x03, (byte)0x23, (byte)0xdf, (byte)0xdf, (byte)0x0b, (byte)0x02, + (byte)0x1a, (byte)0x00, (byte)0x86, (byte)0x55, (byte)0x21, (byte)0x4a, (byte)0xc5, (byte)0x4d, + (byte)0x8d, (byte)0x4e, (byte)0xcd, (byte)0x61, (byte)0x77, (byte)0xf1, (byte)0xc7, (byte)0x36, + (byte)0x90, (byte)0xce, (byte)0x2a, (byte)0x48, (byte)0x2c, (byte)0x8b, (byte)0x05, (byte)0x99, + (byte)0xcb, (byte)0xe0, (byte)0x3f, (byte)0x02, (byte)0x1a, (byte)0x00, (byte)0x83, (byte)0xef, + (byte)0xef, (byte)0xb8, (byte)0xa9, (byte)0xa4, (byte)0x0d, (byte)0x1d, (byte)0xb6, (byte)0xed, + (byte)0x98, (byte)0xad, (byte)0x84, (byte)0xed, (byte)0x13, (byte)0x35, (byte)0xdc, (byte)0xc1, + (byte)0x08, (byte)0xf3, (byte)0x22, (byte)0xd0, (byte)0x57, (byte)0xcf, (byte)0x8d + }; + + static byte[] output2 = + { + (byte)0x14, (byte)0xbd, (byte)0xdd, (byte)0x28, (byte)0xc9, (byte)0x83, (byte)0x35, (byte)0x19, + (byte)0x23, (byte)0x80, (byte)0xe8, (byte)0xe5, (byte)0x49, (byte)0xb1, (byte)0x58, (byte)0x2a, + (byte)0x8b, (byte)0x40, (byte)0xb4, (byte)0x48, (byte)0x6d, (byte)0x03, (byte)0xa6, (byte)0xa5, + (byte)0x31, (byte)0x1f, (byte)0x1f, (byte)0xd5, (byte)0xf0, (byte)0xa1, (byte)0x80, (byte)0xe4, + (byte)0x17, (byte)0x53, (byte)0x03, (byte)0x29, (byte)0xa9, (byte)0x34, (byte)0x90, (byte)0x74, + (byte)0xb1, (byte)0x52, (byte)0x13, (byte)0x54, (byte)0x29, (byte)0x08, (byte)0x24, (byte)0x52, + (byte)0x62, (byte)0x51 + }; + + static byte[] pubKeyEnc3 = + { + (byte)0x30, (byte)0x81, (byte)0x9d, (byte)0x30, (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, + (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, + (byte)0x05, (byte)0x00, (byte)0x03, (byte)0x81, (byte)0x8b, (byte)0x00, (byte)0x30, (byte)0x81, + (byte)0x87, (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xbb, (byte)0xf8, (byte)0x2f, + (byte)0x09, (byte)0x06, (byte)0x82, (byte)0xce, (byte)0x9c, (byte)0x23, (byte)0x38, (byte)0xac, + (byte)0x2b, (byte)0x9d, (byte)0xa8, (byte)0x71, (byte)0xf7, (byte)0x36, (byte)0x8d, (byte)0x07, + (byte)0xee, (byte)0xd4, (byte)0x10, (byte)0x43, (byte)0xa4, (byte)0x40, (byte)0xd6, (byte)0xb6, + (byte)0xf0, (byte)0x74, (byte)0x54, (byte)0xf5, (byte)0x1f, (byte)0xb8, (byte)0xdf, (byte)0xba, + (byte)0xaf, (byte)0x03, (byte)0x5c, (byte)0x02, (byte)0xab, (byte)0x61, (byte)0xea, (byte)0x48, + (byte)0xce, (byte)0xeb, (byte)0x6f, (byte)0xcd, (byte)0x48, (byte)0x76, (byte)0xed, (byte)0x52, + (byte)0x0d, (byte)0x60, (byte)0xe1, (byte)0xec, (byte)0x46, (byte)0x19, (byte)0x71, (byte)0x9d, + (byte)0x8a, (byte)0x5b, (byte)0x8b, (byte)0x80, (byte)0x7f, (byte)0xaf, (byte)0xb8, (byte)0xe0, + (byte)0xa3, (byte)0xdf, (byte)0xc7, (byte)0x37, (byte)0x72, (byte)0x3e, (byte)0xe6, (byte)0xb4, + (byte)0xb7, (byte)0xd9, (byte)0x3a, (byte)0x25, (byte)0x84, (byte)0xee, (byte)0x6a, (byte)0x64, + (byte)0x9d, (byte)0x06, (byte)0x09, (byte)0x53, (byte)0x74, (byte)0x88, (byte)0x34, (byte)0xb2, + (byte)0x45, (byte)0x45, (byte)0x98, (byte)0x39, (byte)0x4e, (byte)0xe0, (byte)0xaa, (byte)0xb1, + (byte)0x2d, (byte)0x7b, (byte)0x61, (byte)0xa5, (byte)0x1f, (byte)0x52, (byte)0x7a, (byte)0x9a, + (byte)0x41, (byte)0xf6, (byte)0xc1, (byte)0x68, (byte)0x7f, (byte)0xe2, (byte)0x53, (byte)0x72, + (byte)0x98, (byte)0xca, (byte)0x2a, (byte)0x8f, (byte)0x59, (byte)0x46, (byte)0xf8, (byte)0xe5, + (byte)0xfd, (byte)0x09, (byte)0x1d, (byte)0xbd, (byte)0xcb, (byte)0x02, (byte)0x01, (byte)0x11 + }; + + static byte[] privKeyEnc3 = + { + (byte)0x30, (byte)0x82, (byte)0x02, (byte)0x75, (byte)0x02, (byte)0x01, (byte)0x00, (byte)0x30, + (byte)0x0d, (byte)0x06, (byte)0x09, (byte)0x2a, (byte)0x86, (byte)0x48, (byte)0x86, (byte)0xf7, + (byte)0x0d, (byte)0x01, (byte)0x01, (byte)0x01, (byte)0x05, (byte)0x00, (byte)0x04, (byte)0x82, + (byte)0x02, (byte)0x5f, (byte)0x30, (byte)0x82, (byte)0x02, (byte)0x5b, (byte)0x02, (byte)0x01, + (byte)0x00, (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xbb, (byte)0xf8, (byte)0x2f, + (byte)0x09, (byte)0x06, (byte)0x82, (byte)0xce, (byte)0x9c, (byte)0x23, (byte)0x38, (byte)0xac, + (byte)0x2b, (byte)0x9d, (byte)0xa8, (byte)0x71, (byte)0xf7, (byte)0x36, (byte)0x8d, (byte)0x07, + (byte)0xee, (byte)0xd4, (byte)0x10, (byte)0x43, (byte)0xa4, (byte)0x40, (byte)0xd6, (byte)0xb6, + (byte)0xf0, (byte)0x74, (byte)0x54, (byte)0xf5, (byte)0x1f, (byte)0xb8, (byte)0xdf, (byte)0xba, + (byte)0xaf, (byte)0x03, (byte)0x5c, (byte)0x02, (byte)0xab, (byte)0x61, (byte)0xea, (byte)0x48, + (byte)0xce, (byte)0xeb, (byte)0x6f, (byte)0xcd, (byte)0x48, (byte)0x76, (byte)0xed, (byte)0x52, + (byte)0x0d, (byte)0x60, (byte)0xe1, (byte)0xec, (byte)0x46, (byte)0x19, (byte)0x71, (byte)0x9d, + (byte)0x8a, (byte)0x5b, (byte)0x8b, (byte)0x80, (byte)0x7f, (byte)0xaf, (byte)0xb8, (byte)0xe0, + (byte)0xa3, (byte)0xdf, (byte)0xc7, (byte)0x37, (byte)0x72, (byte)0x3e, (byte)0xe6, (byte)0xb4, + (byte)0xb7, (byte)0xd9, (byte)0x3a, (byte)0x25, (byte)0x84, (byte)0xee, (byte)0x6a, (byte)0x64, + (byte)0x9d, (byte)0x06, (byte)0x09, (byte)0x53, (byte)0x74, (byte)0x88, (byte)0x34, (byte)0xb2, + (byte)0x45, (byte)0x45, (byte)0x98, (byte)0x39, (byte)0x4e, (byte)0xe0, (byte)0xaa, (byte)0xb1, + (byte)0x2d, (byte)0x7b, (byte)0x61, (byte)0xa5, (byte)0x1f, (byte)0x52, (byte)0x7a, (byte)0x9a, + (byte)0x41, (byte)0xf6, (byte)0xc1, (byte)0x68, (byte)0x7f, (byte)0xe2, (byte)0x53, (byte)0x72, + (byte)0x98, (byte)0xca, (byte)0x2a, (byte)0x8f, (byte)0x59, (byte)0x46, (byte)0xf8, (byte)0xe5, + (byte)0xfd, (byte)0x09, (byte)0x1d, (byte)0xbd, (byte)0xcb, (byte)0x02, (byte)0x01, (byte)0x11, + (byte)0x02, (byte)0x81, (byte)0x81, (byte)0x00, (byte)0xa5, (byte)0xda, (byte)0xfc, (byte)0x53, + (byte)0x41, (byte)0xfa, (byte)0xf2, (byte)0x89, (byte)0xc4, (byte)0xb9, (byte)0x88, (byte)0xdb, + (byte)0x30, (byte)0xc1, (byte)0xcd, (byte)0xf8, (byte)0x3f, (byte)0x31, (byte)0x25, (byte)0x1e, + (byte)0x06, (byte)0x68, (byte)0xb4, (byte)0x27, (byte)0x84, (byte)0x81, (byte)0x38, (byte)0x01, + (byte)0x57, (byte)0x96, (byte)0x41, (byte)0xb2, (byte)0x94, (byte)0x10, (byte)0xb3, (byte)0xc7, + (byte)0x99, (byte)0x8d, (byte)0x6b, (byte)0xc4, (byte)0x65, (byte)0x74, (byte)0x5e, (byte)0x5c, + (byte)0x39, (byte)0x26, (byte)0x69, (byte)0xd6, (byte)0x87, (byte)0x0d, (byte)0xa2, (byte)0xc0, + (byte)0x82, (byte)0xa9, (byte)0x39, (byte)0xe3, (byte)0x7f, (byte)0xdc, (byte)0xb8, (byte)0x2e, + (byte)0xc9, (byte)0x3e, (byte)0xda, (byte)0xc9, (byte)0x7f, (byte)0xf3, (byte)0xad, (byte)0x59, + (byte)0x50, (byte)0xac, (byte)0xcf, (byte)0xbc, (byte)0x11, (byte)0x1c, (byte)0x76, (byte)0xf1, + (byte)0xa9, (byte)0x52, (byte)0x94, (byte)0x44, (byte)0xe5, (byte)0x6a, (byte)0xaf, (byte)0x68, + (byte)0xc5, (byte)0x6c, (byte)0x09, (byte)0x2c, (byte)0xd3, (byte)0x8d, (byte)0xc3, (byte)0xbe, + (byte)0xf5, (byte)0xd2, (byte)0x0a, (byte)0x93, (byte)0x99, (byte)0x26, (byte)0xed, (byte)0x4f, + (byte)0x74, (byte)0xa1, (byte)0x3e, (byte)0xdd, (byte)0xfb, (byte)0xe1, (byte)0xa1, (byte)0xce, + (byte)0xcc, (byte)0x48, (byte)0x94, (byte)0xaf, (byte)0x94, (byte)0x28, (byte)0xc2, (byte)0xb7, + (byte)0xb8, (byte)0x88, (byte)0x3f, (byte)0xe4, (byte)0x46, (byte)0x3a, (byte)0x4b, (byte)0xc8, + (byte)0x5b, (byte)0x1c, (byte)0xb3, (byte)0xc1, (byte)0x02, (byte)0x41, (byte)0x00, (byte)0xee, + (byte)0xcf, (byte)0xae, (byte)0x81, (byte)0xb1, (byte)0xb9, (byte)0xb3, (byte)0xc9, (byte)0x08, + (byte)0x81, (byte)0x0b, (byte)0x10, (byte)0xa1, (byte)0xb5, (byte)0x60, (byte)0x01, (byte)0x99, + (byte)0xeb, (byte)0x9f, (byte)0x44, (byte)0xae, (byte)0xf4, (byte)0xfd, (byte)0xa4, (byte)0x93, + (byte)0xb8, (byte)0x1a, (byte)0x9e, (byte)0x3d, (byte)0x84, (byte)0xf6, (byte)0x32, (byte)0x12, + (byte)0x4e, (byte)0xf0, (byte)0x23, (byte)0x6e, (byte)0x5d, (byte)0x1e, (byte)0x3b, (byte)0x7e, + (byte)0x28, (byte)0xfa, (byte)0xe7, (byte)0xaa, (byte)0x04, (byte)0x0a, (byte)0x2d, (byte)0x5b, + (byte)0x25, (byte)0x21, (byte)0x76, (byte)0x45, (byte)0x9d, (byte)0x1f, (byte)0x39, (byte)0x75, + (byte)0x41, (byte)0xba, (byte)0x2a, (byte)0x58, (byte)0xfb, (byte)0x65, (byte)0x99, (byte)0x02, + (byte)0x41, (byte)0x00, (byte)0xc9, (byte)0x7f, (byte)0xb1, (byte)0xf0, (byte)0x27, (byte)0xf4, + (byte)0x53, (byte)0xf6, (byte)0x34, (byte)0x12, (byte)0x33, (byte)0xea, (byte)0xaa, (byte)0xd1, + (byte)0xd9, (byte)0x35, (byte)0x3f, (byte)0x6c, (byte)0x42, (byte)0xd0, (byte)0x88, (byte)0x66, + (byte)0xb1, (byte)0xd0, (byte)0x5a, (byte)0x0f, (byte)0x20, (byte)0x35, (byte)0x02, (byte)0x8b, + (byte)0x9d, (byte)0x86, (byte)0x98, (byte)0x40, (byte)0xb4, (byte)0x16, (byte)0x66, (byte)0xb4, + (byte)0x2e, (byte)0x92, (byte)0xea, (byte)0x0d, (byte)0xa3, (byte)0xb4, (byte)0x32, (byte)0x04, + (byte)0xb5, (byte)0xcf, (byte)0xce, (byte)0x33, (byte)0x52, (byte)0x52, (byte)0x4d, (byte)0x04, + (byte)0x16, (byte)0xa5, (byte)0xa4, (byte)0x41, (byte)0xe7, (byte)0x00, (byte)0xaf, (byte)0x46, + (byte)0x15, (byte)0x03, (byte)0x02, (byte)0x40, (byte)0x54, (byte)0x49, (byte)0x4c, (byte)0xa6, + (byte)0x3e, (byte)0xba, (byte)0x03, (byte)0x37, (byte)0xe4, (byte)0xe2, (byte)0x40, (byte)0x23, + (byte)0xfc, (byte)0xd6, (byte)0x9a, (byte)0x5a, (byte)0xeb, (byte)0x07, (byte)0xdd, (byte)0xdc, + (byte)0x01, (byte)0x83, (byte)0xa4, (byte)0xd0, (byte)0xac, (byte)0x9b, (byte)0x54, (byte)0xb0, + (byte)0x51, (byte)0xf2, (byte)0xb1, (byte)0x3e, (byte)0xd9, (byte)0x49, (byte)0x09, (byte)0x75, + (byte)0xea, (byte)0xb7, (byte)0x74, (byte)0x14, (byte)0xff, (byte)0x59, (byte)0xc1, (byte)0xf7, + (byte)0x69, (byte)0x2e, (byte)0x9a, (byte)0x2e, (byte)0x20, (byte)0x2b, (byte)0x38, (byte)0xfc, + (byte)0x91, (byte)0x0a, (byte)0x47, (byte)0x41, (byte)0x74, (byte)0xad, (byte)0xc9, (byte)0x3c, + (byte)0x1f, (byte)0x67, (byte)0xc9, (byte)0x81, (byte)0x02, (byte)0x40, (byte)0x47, (byte)0x1e, + (byte)0x02, (byte)0x90, (byte)0xff, (byte)0x0a, (byte)0xf0, (byte)0x75, (byte)0x03, (byte)0x51, + (byte)0xb7, (byte)0xf8, (byte)0x78, (byte)0x86, (byte)0x4c, (byte)0xa9, (byte)0x61, (byte)0xad, + (byte)0xbd, (byte)0x3a, (byte)0x8a, (byte)0x7e, (byte)0x99, (byte)0x1c, (byte)0x5c, (byte)0x05, + (byte)0x56, (byte)0xa9, (byte)0x4c, (byte)0x31, (byte)0x46, (byte)0xa7, (byte)0xf9, (byte)0x80, + (byte)0x3f, (byte)0x8f, (byte)0x6f, (byte)0x8a, (byte)0xe3, (byte)0x42, (byte)0xe9, (byte)0x31, + (byte)0xfd, (byte)0x8a, (byte)0xe4, (byte)0x7a, (byte)0x22, (byte)0x0d, (byte)0x1b, (byte)0x99, + (byte)0xa4, (byte)0x95, (byte)0x84, (byte)0x98, (byte)0x07, (byte)0xfe, (byte)0x39, (byte)0xf9, + (byte)0x24, (byte)0x5a, (byte)0x98, (byte)0x36, (byte)0xda, (byte)0x3d, (byte)0x02, (byte)0x41, + (byte)0x00, (byte)0xb0, (byte)0x6c, (byte)0x4f, (byte)0xda, (byte)0xbb, (byte)0x63, (byte)0x01, + (byte)0x19, (byte)0x8d, (byte)0x26, (byte)0x5b, (byte)0xdb, (byte)0xae, (byte)0x94, (byte)0x23, + (byte)0xb3, (byte)0x80, (byte)0xf2, (byte)0x71, (byte)0xf7, (byte)0x34, (byte)0x53, (byte)0x88, + (byte)0x50, (byte)0x93, (byte)0x07, (byte)0x7f, (byte)0xcd, (byte)0x39, (byte)0xe2, (byte)0x11, + (byte)0x9f, (byte)0xc9, (byte)0x86, (byte)0x32, (byte)0x15, (byte)0x4f, (byte)0x58, (byte)0x83, + (byte)0xb1, (byte)0x67, (byte)0xa9, (byte)0x67, (byte)0xbf, (byte)0x40, (byte)0x2b, (byte)0x4e, + (byte)0x9e, (byte)0x2e, (byte)0x0f, (byte)0x96, (byte)0x56, (byte)0xe6, (byte)0x98, (byte)0xea, + (byte)0x36, (byte)0x66, (byte)0xed, (byte)0xfb, (byte)0x25, (byte)0x79, (byte)0x80, (byte)0x39, + (byte)0xf7 + }; + + static byte[] output3 = Hex.decode( + "b8246b56a6ed5881aeb585d9a25b2ad790c417e080681bf1ac2bc3deb69d8bce" + + "f0c4366fec400af052a72e9b0effb5b3f2f192dbeaca03c12740057113bf1f06" + + "69ac22e9f3a7852e3c15d913cab0b8863a95c99294ce8674214954610346f4d4" + + "74b26f7c48b42ee68e1f572a1fc4026ac456b4f59f7b621ea1b9d88f64202fb1"); + + byte[] seed = { + (byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59, + (byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4, + (byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde, + (byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f + }; + + private class VecRand extends SecureRandom + { + byte[] seed; + + VecRand(byte[] seed) + { + this.seed = seed; + } + + public void nextBytes( + byte[] bytes) + { + System.arraycopy(seed, 0, bytes, 0, bytes.length); + } + } + + private void baseOaepTest( + int id, + byte[] pubKeyEnc, + byte[] privKeyEnc, + byte[] output) + throws Exception + { + ByteArrayInputStream bIn = new ByteArrayInputStream(pubKeyEnc); + ASN1InputStream dIn = new ASN1InputStream(bIn); + + // + // extract the public key info. + // + RSAPublicKey pubStruct; + + pubStruct = RSAPublicKey.getInstance(SubjectPublicKeyInfo.getInstance(dIn.readObject()).parsePublicKey()); + + + bIn = new ByteArrayInputStream(privKeyEnc); + dIn = new ASN1InputStream(bIn); + + // + // extract the private key info. + // + RSAPrivateKey privStruct; + + privStruct = RSAPrivateKey.getInstance(PrivateKeyInfo.getInstance(dIn.readObject()).parsePrivateKey()); + + RSAKeyParameters pubParameters = new RSAKeyParameters( + false, + pubStruct.getModulus(), + pubStruct.getPublicExponent()); + + RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters( + privStruct.getModulus(), + privStruct.getPublicExponent(), + privStruct.getPrivateExponent(), + privStruct.getPrime1(), + privStruct.getPrime2(), + privStruct.getExponent1(), + privStruct.getExponent2(), + privStruct.getCoefficient()); + + byte[] input = new byte[] + { (byte)0x54, (byte)0x85, (byte)0x9b, (byte)0x34, (byte)0x2c, (byte)0x49, (byte)0xea, (byte)0x2a }; + + encDec("id(" + id + ")", pubParameters, privParameters, seed, input, output); + + } + + private void encDec( + String label, + RSAKeyParameters pubParameters, + RSAKeyParameters privParameters, + byte[] seed, + byte[] input, + byte[] output) + throws InvalidCipherTextException + { + AsymmetricBlockCipher cipher = new OAEPEncoding(new RSAEngine()); + + cipher.init(true, new ParametersWithRandom(pubParameters, new VecRand(seed))); + + byte[] out; + + out = cipher.processBlock(input, 0, input.length); + + for (int i = 0; i != output.length; i++) + { + if (out[i] != output[i]) + { + fail(label + " failed encryption"); + } + } + + cipher.init(false, privParameters); + + out = cipher.processBlock(output, 0, output.length); + + for (int i = 0; i != input.length; i++) + { + if (out[i] != input[i]) + { + fail(label + " failed decoding"); + } + } + } + + /* + * RSA vector tests from PKCS#1 page + */ + byte[] modulus_1024 = Hex.decode( + "a8b3b284af8eb50b387034a860f146c4" + + "919f318763cd6c5598c8ae4811a1e0ab" + + "c4c7e0b082d693a5e7fced675cf46685" + + "12772c0cbc64a742c6c630f533c8cc72" + + "f62ae833c40bf25842e984bb78bdbf97" + + "c0107d55bdb662f5c4e0fab9845cb514" + + "8ef7392dd3aaff93ae1e6b667bb3d424" + + "7616d4f5ba10d4cfd226de88d39f16fb"); + + byte[] pubExp_1024 = Hex.decode( + "010001"); + + byte[] privExp_1024 = Hex.decode( + "53339cfdb79fc8466a655c7316aca85c" + + "55fd8f6dd898fdaf119517ef4f52e8fd" + + "8e258df93fee180fa0e4ab29693cd83b" + + "152a553d4ac4d1812b8b9fa5af0e7f55" + + "fe7304df41570926f3311f15c4d65a73" + + "2c483116ee3d3d2d0af3549ad9bf7cbf" + + "b78ad884f84d5beb04724dc7369b31de" + + "f37d0cf539e9cfcdd3de653729ead5d1"); + + byte[] prime1_1024 = Hex.decode( + "d32737e7267ffe1341b2d5c0d150a81b" + + "586fb3132bed2f8d5262864a9cb9f30a" + + "f38be448598d413a172efb802c21acf1" + + "c11c520c2f26a471dcad212eac7ca39d"); + + byte[] prime2_1024 = Hex.decode( + "cc8853d1d54da630fac004f471f281c7" + + "b8982d8224a490edbeb33d3e3d5cc93c" + + "4765703d1dd791642f1f116a0dd852be" + + "2419b2af72bfe9a030e860b0288b5d77"); + + byte[] primeExp1_1024 = Hex.decode( + "0e12bf1718e9cef5599ba1c3882fe804" + + "6a90874eefce8f2ccc20e4f2741fb0a3" + + "3a3848aec9c9305fbecbd2d76819967d" + + "4671acc6431e4037968db37878e695c1"); + + byte[] primeExp2_1024 = Hex.decode( + "95297b0f95a2fa67d00707d609dfd4fc" + + "05c89dafc2ef6d6ea55bec771ea33373" + + "4d9251e79082ecda866efef13c459e1a" + + "631386b7e354c899f5f112ca85d71583"); + + byte[] crtCoef_1024 = Hex.decode( + "4f456c502493bdc0ed2ab756a3a6ed4d" + + "67352a697d4216e93212b127a63d5411" + + "ce6fa98d5dbefd73263e372814274381" + + "8166ed7dd63687dd2a8ca1d2f4fbd8e1"); + + byte[] input_1024_1 = Hex.decode( + "6628194e12073db03ba94cda9ef95323" + + "97d50dba79b987004afefe34"); + + byte[] seed_1024_1 = Hex.decode( + "18b776ea21069d69776a33e96bad48e1" + + "dda0a5ef"); + + byte[] output_1024_1 = Hex.decode( + "354fe67b4a126d5d35fe36c777791a3f" + + "7ba13def484e2d3908aff722fad468fb" + + "21696de95d0be911c2d3174f8afcc201" + + "035f7b6d8e69402de5451618c21a535f" + + "a9d7bfc5b8dd9fc243f8cf927db31322" + + "d6e881eaa91a996170e657a05a266426" + + "d98c88003f8477c1227094a0d9fa1e8c" + + "4024309ce1ecccb5210035d47ac72e8a"); + + byte[] input_1024_2 = Hex.decode( + "750c4047f547e8e41411856523298ac9" + + "bae245efaf1397fbe56f9dd5"); + + byte[] seed_1024_2 = Hex.decode( + "0cc742ce4a9b7f32f951bcb251efd925" + + "fe4fe35f"); + + byte[] output_1024_2 = Hex.decode( + "640db1acc58e0568fe5407e5f9b701df" + + "f8c3c91e716c536fc7fcec6cb5b71c11" + + "65988d4a279e1577d730fc7a29932e3f" + + "00c81515236d8d8e31017a7a09df4352" + + "d904cdeb79aa583adcc31ea698a4c052" + + "83daba9089be5491f67c1a4ee48dc74b" + + "bbe6643aef846679b4cb395a352d5ed1" + + "15912df696ffe0702932946d71492b44"); + + byte[] input_1024_3 = Hex.decode( + "d94ae0832e6445ce42331cb06d531a82" + + "b1db4baad30f746dc916df24d4e3c245" + + "1fff59a6423eb0e1d02d4fe646cf699d" + + "fd818c6e97b051"); + + byte[] seed_1024_3 = Hex.decode( + "2514df4695755a67b288eaf4905c36ee" + + "c66fd2fd"); + + byte[] output_1024_3 = Hex.decode( + "423736ed035f6026af276c35c0b3741b" + + "365e5f76ca091b4e8c29e2f0befee603" + + "595aa8322d602d2e625e95eb81b2f1c9" + + "724e822eca76db8618cf09c5343503a4" + + "360835b5903bc637e3879fb05e0ef326" + + "85d5aec5067cd7cc96fe4b2670b6eac3" + + "066b1fcf5686b68589aafb7d629b02d8" + + "f8625ca3833624d4800fb081b1cf94eb"); + + byte[] input_1024_4 = Hex.decode( + "52e650d98e7f2a048b4f86852153b97e" + + "01dd316f346a19f67a85"); + + byte[] seed_1024_4 = Hex.decode( + "c4435a3e1a18a68b6820436290a37cef" + + "b85db3fb"); + + byte[] output_1024_4 = Hex.decode( + "45ead4ca551e662c9800f1aca8283b05" + + "25e6abae30be4b4aba762fa40fd3d38e" + + "22abefc69794f6ebbbc05ddbb1121624" + + "7d2f412fd0fba87c6e3acd888813646f" + + "d0e48e785204f9c3f73d6d8239562722" + + "dddd8771fec48b83a31ee6f592c4cfd4" + + "bc88174f3b13a112aae3b9f7b80e0fc6" + + "f7255ba880dc7d8021e22ad6a85f0755"); + + byte[] input_1024_5 = Hex.decode( + "8da89fd9e5f974a29feffb462b49180f" + + "6cf9e802"); + + byte[] seed_1024_5 = Hex.decode( + "b318c42df3be0f83fea823f5a7b47ed5" + + "e425a3b5"); + + byte[] output_1024_5 = Hex.decode( + "36f6e34d94a8d34daacba33a2139d00a" + + "d85a9345a86051e73071620056b920e2" + + "19005855a213a0f23897cdcd731b4525" + + "7c777fe908202befdd0b58386b1244ea" + + "0cf539a05d5d10329da44e13030fd760" + + "dcd644cfef2094d1910d3f433e1c7c6d" + + "d18bc1f2df7f643d662fb9dd37ead905" + + "9190f4fa66ca39e869c4eb449cbdc439"); + + byte[] input_1024_6 = Hex.decode( + "26521050844271"); + + byte[] seed_1024_6 = Hex.decode( + "e4ec0982c2336f3a677f6a356174eb0c" + + "e887abc2"); + + byte[] output_1024_6 = Hex.decode( + "42cee2617b1ecea4db3f4829386fbd61" + + "dafbf038e180d837c96366df24c097b4" + + "ab0fac6bdf590d821c9f10642e681ad0" + + "5b8d78b378c0f46ce2fad63f74e0ad3d" + + "f06b075d7eb5f5636f8d403b9059ca76" + + "1b5c62bb52aa45002ea70baace08ded2" + + "43b9d8cbd62a68ade265832b56564e43" + + "a6fa42ed199a099769742df1539e8255"); + + byte[] modulus_1027 = Hex.decode( + "051240b6cc0004fa48d0134671c078c7" + + "c8dec3b3e2f25bc2564467339db38853" + + "d06b85eea5b2de353bff42ac2e46bc97" + + "fae6ac9618da9537a5c8f553c1e35762" + + "5991d6108dcd7885fb3a25413f53efca" + + "d948cb35cd9b9ae9c1c67626d113d57d" + + "de4c5bea76bb5bb7de96c00d07372e96" + + "85a6d75cf9d239fa148d70931b5f3fb0" + + "39"); + + byte[] pubExp_1027 = Hex.decode( + "010001"); + + byte[] privExp_1027 = Hex.decode( + "0411ffca3b7ca5e9e9be7fe38a85105e" + + "353896db05c5796aecd2a725161eb365" + + "1c8629a9b862b904d7b0c7b37f8cb5a1" + + "c2b54001018a00a1eb2cafe4ee4e9492" + + "c348bc2bedab4b9ebbf064e8eff322b9" + + "009f8eec653905f40df88a3cdc49d456" + + "7f75627d41aca624129b46a0b7c698e5" + + "e65f2b7ba102c749a10135b6540d0401"); + + byte[] prime1_1027 = Hex.decode( + "027458c19ec1636919e736c9af25d609" + + "a51b8f561d19c6bf6943dd1ee1ab8a4a" + + "3f232100bd40b88decc6ba235548b6ef" + + "792a11c9de823d0a7922c7095b6eba57" + + "01"); + + byte[] prime2_1027 = Hex.decode( + "0210ee9b33ab61716e27d251bd465f4b" + + "35a1a232e2da00901c294bf22350ce49" + + "0d099f642b5375612db63ba1f2038649" + + "2bf04d34b3c22bceb909d13441b53b51" + + "39"); + + byte[] primeExp1_1027 = Hex.decode( + "39fa028b826e88c1121b750a8b242fa9" + + "a35c5b66bdfd1fa637d3cc48a84a4f45" + + "7a194e7727e49f7bcc6e5a5a412657fc" + + "470c7322ebc37416ef458c307a8c0901"); + + byte[] primeExp2_1027 = Hex.decode( + "015d99a84195943979fa9e1be2c3c1b6" + + "9f432f46fd03e47d5befbbbfd6b1d137" + + "1d83efb330a3e020942b2fed115e5d02" + + "be24fd92c9019d1cecd6dd4cf1e54cc8" + + "99"); + + byte[] crtCoef_1027 = Hex.decode( + "01f0b7015170b3f5e42223ba30301c41" + + "a6d87cbb70e30cb7d3c67d25473db1f6" + + "cbf03e3f9126e3e97968279a865b2c2b" + + "426524cfc52a683d31ed30eb984be412" + + "ba"); + + byte[] input_1027_1 = Hex.decode( + "4a86609534ee434a6cbca3f7e962e76d" + + "455e3264c19f605f6e5ff6137c65c56d" + + "7fb344cd52bc93374f3d166c9f0c6f9c" + + "506bad19330972d2"); + + byte[] seed_1027_1 = Hex.decode( + "1cac19ce993def55f98203f6852896c9" + + "5ccca1f3"); + + byte[] output_1027_1 = Hex.decode( + "04cce19614845e094152a3fe18e54e33" + + "30c44e5efbc64ae16886cb1869014cc5" + + "781b1f8f9e045384d0112a135ca0d12e" + + "9c88a8e4063416deaae3844f60d6e96f" + + "e155145f4525b9a34431ca3766180f70" + + "e15a5e5d8e8b1a516ff870609f13f896" + + "935ced188279a58ed13d07114277d75c" + + "6568607e0ab092fd803a223e4a8ee0b1" + + "a8"); + + byte[] input_1027_2 = Hex.decode( + "b0adc4f3fe11da59ce992773d9059943" + + "c03046497ee9d9f9a06df1166db46d98" + + "f58d27ec074c02eee6cbe2449c8b9fc5" + + "080c5c3f4433092512ec46aa793743c8"); + + byte[] seed_1027_2 = Hex.decode( + "f545d5897585e3db71aa0cb8da76c51d" + + "032ae963"); + + byte[] output_1027_2 = Hex.decode( + "0097b698c6165645b303486fbf5a2a44" + + "79c0ee85889b541a6f0b858d6b6597b1" + + "3b854eb4f839af03399a80d79bda6578" + + "c841f90d645715b280d37143992dd186" + + "c80b949b775cae97370e4ec97443136c" + + "6da484e970ffdb1323a20847821d3b18" + + "381de13bb49aaea66530c4a4b8271f3e" + + "ae172cd366e07e6636f1019d2a28aed1" + + "5e"); + + byte[] input_1027_3 = Hex.decode( + "bf6d42e701707b1d0206b0c8b45a1c72" + + "641ff12889219a82bdea965b5e79a96b" + + "0d0163ed9d578ec9ada20f2fbcf1ea3c" + + "4089d83419ba81b0c60f3606da99"); + + byte[] seed_1027_3 = Hex.decode( + "ad997feef730d6ea7be60d0dc52e72ea" + + "cbfdd275"); + + byte[] output_1027_3 = Hex.decode( + "0301f935e9c47abcb48acbbe09895d9f" + + "5971af14839da4ff95417ee453d1fd77" + + "319072bb7297e1b55d7561cd9d1bb24c" + + "1a9a37c619864308242804879d86ebd0" + + "01dce5183975e1506989b70e5a834341" + + "54d5cbfd6a24787e60eb0c658d2ac193" + + "302d1192c6e622d4a12ad4b53923bca2" + + "46df31c6395e37702c6a78ae081fb9d0" + + "65"); + + byte[] input_1027_4 = Hex.decode( + "fb2ef112f5e766eb94019297934794f7" + + "be2f6fc1c58e"); + + byte[] seed_1027_4 = Hex.decode( + "136454df5730f73c807a7e40d8c1a312" + + "ac5b9dd3"); + + byte[] output_1027_4 = Hex.decode( + "02d110ad30afb727beb691dd0cf17d0a" + + "f1a1e7fa0cc040ec1a4ba26a42c59d0a" + + "796a2e22c8f357ccc98b6519aceb682e" + + "945e62cb734614a529407cd452bee3e4" + + "4fece8423cc19e55548b8b994b849c7e" + + "cde4933e76037e1d0ce44275b08710c6" + + "8e430130b929730ed77e09b015642c55" + + "93f04e4ffb9410798102a8e96ffdfe11" + + "e4"); + + byte[] input_1027_5 = Hex.decode( + "28ccd447bb9e85166dabb9e5b7d1adad" + + "c4b9d39f204e96d5e440ce9ad928bc1c" + + "2284"); + + byte[] seed_1027_5 = Hex.decode( + "bca8057f824b2ea257f2861407eef63d" + + "33208681"); + + byte[] output_1027_5 = Hex.decode( + "00dbb8a7439d90efd919a377c54fae8f" + + "e11ec58c3b858362e23ad1b8a4431079" + + "9066b99347aa525691d2adc58d9b06e3" + + "4f288c170390c5f0e11c0aa3645959f1" + + "8ee79e8f2be8d7ac5c23d061f18dd74b" + + "8c5f2a58fcb5eb0c54f99f01a8324756" + + "8292536583340948d7a8c97c4acd1e98" + + "d1e29dc320e97a260532a8aa7a758a1e" + + "c2"); + + byte[] input_1027_6 = Hex.decode( + "f22242751ec6b1"); + + byte[] seed_1027_6 = Hex.decode( + "2e7e1e17f647b5ddd033e15472f90f68" + + "12f3ac4e"); + + byte[] output_1027_6 = Hex.decode( + "00a5ffa4768c8bbecaee2db77e8f2eec" + + "99595933545520835e5ba7db9493d3e1" + + "7cddefe6a5f567624471908db4e2d83a" + + "0fbee60608fc84049503b2234a07dc83" + + "b27b22847ad8920ff42f674ef79b7628" + + "0b00233d2b51b8cb2703a9d42bfbc825" + + "0c96ec32c051e57f1b4ba528db89c37e" + + "4c54e27e6e64ac69635ae887d9541619" + + "a9"); + + private void oaepVecTest( + int keySize, + int no, + RSAKeyParameters pubParam, + RSAKeyParameters privParam, + byte[] seed, + byte[] input, + byte[] output) + throws Exception + { + encDec(keySize + " " + no, pubParam, privParam, seed, input, output); + } + + public OAEPTest() + { + } + + public String getName() + { + return "OAEP"; + } + + public void performTest() throws Exception + { + baseOaepTest(1, pubKeyEnc1, privKeyEnc1, output1); + baseOaepTest(2, pubKeyEnc2, privKeyEnc2, output2); + baseOaepTest(3, pubKeyEnc3, privKeyEnc3, output3); + + RSAKeyParameters pubParam = new RSAKeyParameters(false, new BigInteger(1, modulus_1024), new BigInteger(1, pubExp_1024)); + RSAKeyParameters privParam = new RSAPrivateCrtKeyParameters(pubParam.getModulus(), pubParam.getExponent(), new BigInteger(1, privExp_1024), new BigInteger(1, prime1_1024), new BigInteger(1, prime2_1024), new BigInteger(1, primeExp1_1024), new BigInteger(1, primeExp2_1024), new BigInteger(1, crtCoef_1024)); + + oaepVecTest(1024, 1, pubParam, privParam, seed_1024_1, input_1024_1, output_1024_1); + oaepVecTest(1024, 2, pubParam, privParam, seed_1024_2, input_1024_2, output_1024_2); + oaepVecTest(1024, 3, pubParam, privParam, seed_1024_3, input_1024_3, output_1024_3); + oaepVecTest(1024, 4, pubParam, privParam, seed_1024_4, input_1024_4, output_1024_4); + oaepVecTest(1024, 5, pubParam, privParam, seed_1024_5, input_1024_5, output_1024_5); + oaepVecTest(1024, 6, pubParam, privParam, seed_1024_6, input_1024_6, output_1024_6); + + pubParam = new RSAKeyParameters(false, new BigInteger(1, modulus_1027), new BigInteger(1, pubExp_1027)); + privParam = new RSAPrivateCrtKeyParameters(pubParam.getModulus(), pubParam.getExponent(), new BigInteger(1, privExp_1027), new BigInteger(1, prime1_1027), new BigInteger(1, prime2_1027), new BigInteger(1, primeExp1_1027), new BigInteger(1, primeExp2_1027), new BigInteger(1, crtCoef_1027)); + + oaepVecTest(1027, 1, pubParam, privParam, seed_1027_1, input_1027_1, output_1027_1); + oaepVecTest(1027, 2, pubParam, privParam, seed_1027_2, input_1027_2, output_1027_2); + oaepVecTest(1027, 3, pubParam, privParam, seed_1027_3, input_1027_3, output_1027_3); + oaepVecTest(1027, 4, pubParam, privParam, seed_1027_4, input_1027_4, output_1027_4); + oaepVecTest(1027, 5, pubParam, privParam, seed_1027_5, input_1027_5, output_1027_5); + oaepVecTest(1027, 6, pubParam, privParam, seed_1027_6, input_1027_6, output_1027_6); + + testForHighByteError("invalidCiphertextOaepTest 1024", 1024); + + // + // OAEP - public encrypt, private decrypt, differing hashes + // + AsymmetricBlockCipher cipher = new OAEPEncoding(new RSAEngine(), new SHA256Digest(), new SHA1Digest(), new byte[10]); + + cipher.init(true, new ParametersWithRandom(pubParam, new SecureRandom())); + + byte[] input = new byte[10]; + + byte[] out = cipher.processBlock(input, 0, input.length); + + cipher.init(false, privParam); + + out = cipher.processBlock(out, 0, out.length); + + for (int i = 0; i != input.length; i++) + { + if (out[i] != input[i]) + { + fail("mixed digest failed decoding"); + } + } + + cipher = new OAEPEncoding(new RSAEngine(), new SHA1Digest(), new SHA256Digest(), new byte[10]); + + cipher.init(true, new ParametersWithRandom(pubParam, new SecureRandom())); + + out = cipher.processBlock(input, 0, input.length); + + cipher.init(false, privParam); + + out = cipher.processBlock(out, 0, out.length); + + for (int i = 0; i != input.length; i++) + { + if (out[i] != input[i]) + { + fail("mixed digest failed decoding"); + } + } + } + + private void testForHighByteError(String label, int keySizeBits) throws Exception + { + // draw a key of the size asked + BigInteger e = BigIntegers.ONE.shiftLeft(16).add(BigIntegers.ONE); + + AsymmetricCipherKeyPairGenerator kpGen = new RSAKeyPairGenerator(); + + kpGen.init(new RSAKeyGenerationParameters(e, new SecureRandom(), keySizeBits, 100)); + + AsymmetricCipherKeyPair kp = kpGen.generateKeyPair(); + + AsymmetricBlockCipher cipher = new OAEPEncoding(new RSAEngine()); + + // obtain a known good ciphertext + cipher.init(true, new ParametersWithRandom(kp.getPublic(), new VecRand(seed))); + byte[] m = { 42 }; + byte[] c = cipher.processBlock(m, 0, m.length); + int keySizeBytes = (keySizeBits+7)>>>3; + if (c.length!=keySizeBytes) + { + fail(label + " failed ciphertext size"); + } + + BigInteger n = ((RSAPrivateCrtKeyParameters)kp.getPrivate()).getModulus(); + + // decipher + cipher.init(false, kp.getPrivate()); + byte[] r = cipher.processBlock(c, 0, keySizeBytes); + if (r.length!=1 || r[0]!=42) + { + fail(label + " failed first decryption of test message"); + } + + // decipher again + r = cipher.processBlock(c, 0, keySizeBytes); + if (r.length!=1 || r[0]!=42) + { + fail(label + " failed second decryption of test message"); + } + + // check hapazard incorrect ciphertexts + for(int i=keySizeBytes*8; --i>=0;) + { + c[i>>>3] ^= 1<<(i&7); + boolean ko = true; + try + { + BigInteger cV = new BigInteger(1, c); + + // don't pass in c if it will be rejected trivially + if (cV.compareTo(n) < 0) + { + r = cipher.processBlock(c, 0, keySizeBytes); + } + else + { + ko = false; // size errors are picked up at start + } + } + catch (InvalidCipherTextException exception) + { + ko = false; + } + if (ko) + { + fail(label + " invalid ciphertext caused no exception"); + } + c[i>>>3] ^= 1<<(i&7); + } + } + + public static void main( + String[] args) + { + runTest(new OAEPTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OCBTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OCBTest.java new file mode 100644 index 000000000..789367888 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OCBTest.java @@ -0,0 +1,520 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.modes.AEADBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.OCBBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Times; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test vectors from RFC 7253 on The OCB + * Authenticated-Encryption Algorithm + */ +public class OCBTest + extends SimpleTest +{ + private static final String KEY_128 = "000102030405060708090A0B0C0D0E0F"; + private static final String KEY_96 = "0F0E0D0C0B0A09080706050403020100"; + + /* + * Test vectors from Appendix A of the specification, containing the strings N, A, P, C in order + */ + + private static final String[][] TEST_VECTORS_128 = new String[][]{ + { "BBAA99887766554433221100", + "", + "", + "785407BFFFC8AD9EDCC5520AC9111EE6" }, + { "BBAA99887766554433221101", + "0001020304050607", + "0001020304050607", + "6820B3657B6F615A5725BDA0D3B4EB3A257C9AF1F8F03009" }, + { "BBAA99887766554433221102", + "0001020304050607", + "", + "81017F8203F081277152FADE694A0A00" }, + { "BBAA99887766554433221103", + "", + "0001020304050607", + "45DD69F8F5AAE72414054CD1F35D82760B2CD00D2F99BFA9" }, + { "BBAA99887766554433221104", + "000102030405060708090A0B0C0D0E0F", + "000102030405060708090A0B0C0D0E0F", + "571D535B60B277188BE5147170A9A22C3AD7A4FF3835B8C5701C1CCEC8FC3358" }, + { "BBAA99887766554433221105", + "000102030405060708090A0B0C0D0E0F", + "", + "8CF761B6902EF764462AD86498CA6B97" }, + { "BBAA99887766554433221106", + "", + "000102030405060708090A0B0C0D0E0F", + "5CE88EC2E0692706A915C00AEB8B2396F40E1C743F52436BDF06D8FA1ECA343D" }, + { "BBAA99887766554433221107", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "1CA2207308C87C010756104D8840CE1952F09673A448A122C92C62241051F57356D7F3C90BB0E07F" }, + { "BBAA99887766554433221108", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "", + "6DC225A071FC1B9F7C69F93B0F1E10DE" }, + { "BBAA99887766554433221109", + "", + "000102030405060708090A0B0C0D0E0F1011121314151617", + "221BD0DE7FA6FE993ECCD769460A0AF2D6CDED0C395B1C3CE725F32494B9F914D85C0B1EB38357FF" }, + { "BBAA9988776655443322110A", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "BD6F6C496201C69296C11EFD138A467ABD3C707924B964DEAFFC40319AF5A48540FBBA186C5553C68AD9F592A79A4240" }, + { "BBAA9988776655443322110B", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "", + "FE80690BEE8A485D11F32965BC9D2A32" }, + { "BBAA9988776655443322110C", + "", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F", + "2942BFC773BDA23CABC6ACFD9BFD5835BD300F0973792EF46040C53F1432BCDFB5E1DDE3BC18A5F840B52E653444D5DF" }, + { "BBAA9988776655443322110D", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "D5CA91748410C1751FF8A2F618255B68A0A12E093FF454606E59F9C1D0DDC54B65E8628E568BAD7AED07BA06A4A69483A7035490C5769E60" }, + { "BBAA9988776655443322110E", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "", + "C5CD9D1850C141E358649994EE701B68" }, + { "BBAA9988776655443322110F", + "", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "4412923493C57D5DE0D700F753CCE0D1D2D95060122E9F15A5DDBFC5787E50B5CC55EE507BCB084E479AD363AC366B95A98CA5F3000B1479" }, + }; + + private static final String[][] TEST_VECTORS_96 = new String[][]{ + { "BBAA9988776655443322110D", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627", + "1792A4E31E0755FB03E31B22116E6C2DDF9EFD6E33D536F1A0124B0A55BAE884ED93481529C76B6AD0C515F4D1CDD4FDAC4F02AA" }, + }; + + public String getName() + { + return "OCB"; + } + + public void performTest() + throws Exception + { + byte[] K128 = Hex.decode(KEY_128); + for (int i = 0; i < TEST_VECTORS_128.length; ++i) + { + runTestCase("Test Case " + i, TEST_VECTORS_128[i], 128, K128); + } + + byte[] K96 = Hex.decode(KEY_96); + for (int i = 0; i < TEST_VECTORS_96.length; ++i) + { + runTestCase("Test Case " + i, TEST_VECTORS_96[i], 96, K96); + } + + runLongerTestCase(128, 128, "67E944D23256C5E0B6C61FA22FDF1EA2"); + runLongerTestCase(192, 128, "F673F2C3E7174AAE7BAE986CA9F29E17"); + runLongerTestCase(256, 128, "D90EB8E9C977C88B79DD793D7FFA161C"); + runLongerTestCase(128, 96, "77A3D8E73589158D25D01209"); + runLongerTestCase(192, 96, "05D56EAD2752C86BE6932C5E"); + runLongerTestCase(256, 96, "5458359AC23B0CBA9E6330DD"); + runLongerTestCase(128, 64, "192C9B7BD90BA06A"); + runLongerTestCase(192, 64, "0066BC6E0EF34E24"); + runLongerTestCase(256, 64, "7D4EA5D445501CBE"); + + randomTests(); + outputSizeTests(); + testExceptions(); + } + + private void testExceptions() throws InvalidCipherTextException + { + AEADBlockCipher ocb = createOCBCipher(); + + try + { + ocb = new OCBBlockCipher(new DESEngine(), new DESEngine()); + + fail("incorrect block size not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + ocb.init(false, new KeyParameter(new byte[16])); + + fail("illegal argument not picked up"); + } + catch (IllegalArgumentException e) + { + // expected + } + + AEADTestUtil.testReset(this, createOCBCipher(), createOCBCipher(), new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[15])); + AEADTestUtil.testTampering(this, ocb, new AEADParameters(new KeyParameter(new byte[16]), 128, new byte[15])); + AEADTestUtil.testOutputSizes(this, createOCBCipher(), new AEADParameters(new KeyParameter(new byte[16]), 128, + new byte[15])); + AEADTestUtil.testBufferSizeChecks(this, createOCBCipher(), new AEADParameters(new KeyParameter(new byte[16]), + 128, new byte[15])); + } + + private void runTestCase(String testName, String[] testVector, int macLengthBits, byte[] K) + throws InvalidCipherTextException + { + int pos = 0; + byte[] N = Hex.decode(testVector[pos++]); + byte[] A = Hex.decode(testVector[pos++]); + byte[] P = Hex.decode(testVector[pos++]); + byte[] C = Hex.decode(testVector[pos++]); + + int macLengthBytes = macLengthBits / 8; + + KeyParameter keyParameter = new KeyParameter(K); + AEADParameters parameters = new AEADParameters(keyParameter, macLengthBits, N, A); + + AEADBlockCipher encCipher = initOCBCipher(true, parameters); + AEADBlockCipher decCipher = initOCBCipher(false, parameters); + + checkTestCase(encCipher, decCipher, testName, macLengthBytes, P, C); + checkTestCase(encCipher, decCipher, testName + " (reused)", macLengthBytes, P, C); + + // Key reuse + AEADParameters keyReuseParams = AEADTestUtil.reuseKey(parameters); + encCipher.init(true, keyReuseParams); + decCipher.init(false, keyReuseParams); + checkTestCase(encCipher, decCipher, testName + " (key reuse)", macLengthBytes, P, C); + } + + private BlockCipher createUnderlyingCipher() + { + return new AESEngine(); + } + + private AEADBlockCipher createOCBCipher() + { + return new OCBBlockCipher(createUnderlyingCipher(), createUnderlyingCipher()); + } + + private AEADBlockCipher initOCBCipher(boolean forEncryption, AEADParameters parameters) + { + AEADBlockCipher c = createOCBCipher(); + c.init(forEncryption, parameters); + return c; + } + + private void checkTestCase(AEADBlockCipher encCipher, AEADBlockCipher decCipher, String testName, + int macLengthBytes, byte[] P, byte[] C) + throws InvalidCipherTextException + { + byte[] tag = Arrays.copyOfRange(C, C.length - macLengthBytes, C.length); + + { + byte[] enc = new byte[encCipher.getOutputSize(P.length)]; + int len = encCipher.processBytes(P, 0, P.length, enc, 0); + len += encCipher.doFinal(enc, len); + + if (enc.length != len) + { + fail("encryption reported incorrect length: " + testName); + } + + if (!areEqual(C, enc)) + { + fail("incorrect encrypt in: " + testName); + } + + if (!areEqual(tag, encCipher.getMac())) + { + fail("getMac() not the same as the appended tag: " + testName); + } + } + + { + byte[] dec = new byte[decCipher.getOutputSize(C.length)]; + int len = decCipher.processBytes(C, 0, C.length, dec, 0); + len += decCipher.doFinal(dec, len); + + if (dec.length != len) + { + fail("decryption reported incorrect length: " + testName); + } + + if (!areEqual(P, dec)) + { + fail("incorrect decrypt in: " + testName); + } + + if (!areEqual(tag, decCipher.getMac())) + { + fail("getMac() not the same as the appended tag: " + testName); + } + } + } + + private void runLongerTestCase(int keyLen, int tagLen, String expectedOutputHex) + throws InvalidCipherTextException + { + byte[] expectedOutput = Hex.decode(expectedOutputHex); + byte[] keyBytes = new byte[keyLen / 8]; + keyBytes[keyBytes.length - 1] = (byte)tagLen; + KeyParameter key = new KeyParameter(keyBytes); + + AEADBlockCipher c1 = initOCBCipher(true, new AEADParameters(key, tagLen, createNonce(385))); + AEADBlockCipher c2 = createOCBCipher(); + + long total = 0; + + byte[] S = new byte[128]; + + int n = 0; + for (int i = 0; i < 128; ++i) + { + c2.init(true, new AEADParameters(key, tagLen, createNonce(++n))); + total += updateCiphers(c1, c2, S, i, true, true); + c2.init(true, new AEADParameters(key, tagLen, createNonce(++n))); + total += updateCiphers(c1, c2, S, i, false, true); + c2.init(true, new AEADParameters(key, tagLen, createNonce(++n))); + total += updateCiphers(c1, c2, S, i, true, false); + } + + long expectedTotal = 16256 + (48 * tagLen); + + if (total != expectedTotal) + { + fail("test generated the wrong amount of input: " + total); + } + + byte[] output = new byte[c1.getOutputSize(0)]; + c1.doFinal(output, 0); + + if (!areEqual(expectedOutput, output)) + { + fail("incorrect encrypt in long-form test"); + } + } + + private byte[] createNonce(int n) + { + return new byte[]{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte)(n >>> 8), (byte)n }; + } + + private int updateCiphers(AEADBlockCipher c1, AEADBlockCipher c2, byte[] S, int i, + boolean includeAAD, boolean includePlaintext) + throws InvalidCipherTextException + { + int inputLen = includePlaintext ? i : 0; + int outputLen = c2.getOutputSize(inputLen); + + byte[] output = new byte[outputLen]; + + int len = 0; + + if (includeAAD) + { + c2.processAADBytes(S, 0, i); + } + + if (includePlaintext) + { + len += c2.processBytes(S, 0, i, output, len); + } + + len += c2.doFinal(output, len); + + c1.processAADBytes(output, 0, len); + + return len; + } + + private void randomTests() + throws InvalidCipherTextException + { + SecureRandom srng = new SecureRandom(); + srng.setSeed(Times.nanoTime()); + for (int i = 0; i < 10; ++i) + { + randomTest(srng); + } + } + + private void randomTest(SecureRandom srng) + throws InvalidCipherTextException + { + int kLength = 16 + 8 * (Math.abs(srng.nextInt()) % 3); + byte[] K = new byte[kLength]; + srng.nextBytes(K); + + int pLength = srng.nextInt() >>> 16; + byte[] P = new byte[pLength]; + srng.nextBytes(P); + + int aLength = srng.nextInt() >>> 24; + byte[] A = new byte[aLength]; + srng.nextBytes(A); + + int saLength = srng.nextInt() >>> 24; + byte[] SA = new byte[saLength]; + srng.nextBytes(SA); + + int ivLength = 1 + nextInt(srng, 15); + byte[] IV = new byte[ivLength]; + srng.nextBytes(IV); + + AEADParameters parameters = new AEADParameters(new KeyParameter(K), 16 * 8, IV, A); + AEADBlockCipher cipher = initOCBCipher(true, parameters); + byte[] C = new byte[cipher.getOutputSize(P.length)]; + int predicted = cipher.getUpdateOutputSize(P.length); + + int split = nextInt(srng, SA.length + 1); + cipher.processAADBytes(SA, 0, split); + int len = cipher.processBytes(P, 0, P.length, C, 0); + cipher.processAADBytes(SA, split, SA.length - split); + + if (predicted != len) + { + fail("encryption reported incorrect update length in randomised test"); + } + + len += cipher.doFinal(C, len); + + if (C.length != len) + { + fail("encryption reported incorrect length in randomised test"); + } + + byte[] encT = cipher.getMac(); + byte[] tail = new byte[C.length - P.length]; + System.arraycopy(C, P.length, tail, 0, tail.length); + + if (!areEqual(encT, tail)) + { + fail("stream contained wrong mac in randomised test"); + } + + cipher.init(false, parameters); + byte[] decP = new byte[cipher.getOutputSize(C.length)]; + predicted = cipher.getUpdateOutputSize(C.length); + + split = nextInt(srng, SA.length + 1); + cipher.processAADBytes(SA, 0, split); + len = cipher.processBytes(C, 0, C.length, decP, 0); + cipher.processAADBytes(SA, split, SA.length - split); + + if (predicted != len) + { + fail("decryption reported incorrect update length in randomised test"); + } + + len += cipher.doFinal(decP, len); + + if (!areEqual(P, decP)) + { + fail("incorrect decrypt in randomised test"); + } + + byte[] decT = cipher.getMac(); + if (!areEqual(encT, decT)) + { + fail("decryption produced different mac from encryption"); + } + + // + // key reuse test + // + cipher.init(false, AEADTestUtil.reuseKey(parameters)); + decP = new byte[cipher.getOutputSize(C.length)]; + + split = nextInt(srng, SA.length + 1); + cipher.processAADBytes(SA, 0, split); + len = cipher.processBytes(C, 0, C.length, decP, 0); + cipher.processAADBytes(SA, split, SA.length - split); + + len += cipher.doFinal(decP, len); + + if (!areEqual(P, decP)) + { + fail("incorrect decrypt in randomised test"); + } + + decT = cipher.getMac(); + if (!areEqual(encT, decT)) + { + fail("decryption produced different mac from encryption"); + } + } + + private void outputSizeTests() + { + byte[] K = new byte[16]; + byte[] A = null; + byte[] IV = new byte[15]; + + AEADParameters parameters = new AEADParameters(new KeyParameter(K), 16 * 8, IV, A); + AEADBlockCipher cipher = initOCBCipher(true, parameters); + + if (cipher.getUpdateOutputSize(0) != 0) + { + fail("incorrect getUpdateOutputSize for initial 0 bytes encryption"); + } + + if (cipher.getOutputSize(0) != 16) + { + fail("incorrect getOutputSize for initial 0 bytes encryption"); + } + + cipher.init(false, parameters); + + if (cipher.getUpdateOutputSize(0) != 0) + { + fail("incorrect getUpdateOutputSize for initial 0 bytes decryption"); + } + + // NOTE: 0 bytes would be truncated data, but we want it to fail in the doFinal, not here + if (cipher.getOutputSize(0) != 0) + { + fail("fragile getOutputSize for initial 0 bytes decryption"); + } + + if (cipher.getOutputSize(16) != 0) + { + fail("incorrect getOutputSize for initial MAC-size bytes decryption"); + } + } + + private static int nextInt(SecureRandom rand, int n) + { + if ((n & -n) == n) // i.e., n is a power of 2 + { + return (int)((n * (long)(rand.nextInt() >>> 1)) >> 31); + } + + int bits, value; + do + { + bits = rand.nextInt() >>> 1; + value = bits % n; + } + while (bits - value + (n - 1) < 0); + + return value; + } + + public static void main(String[] args) + { + runTest(new OCBTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OpenBSDBCryptTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OpenBSDBCryptTest.java new file mode 100644 index 000000000..3b39919c5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OpenBSDBCryptTest.java @@ -0,0 +1,180 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.generators.OpenBSDBCrypt; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class OpenBSDBCryptTest + extends SimpleTest +{ + + private final static String[][] bcryptTest1 = // vectors from http://cvsweb.openwall.com/cgi/cvsweb.cgi/Owl/packages/glibc/crypt_blowfish/wrapper.c?rev=HEAD + { + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.E5YPO9kmyuRGyh0XouQYb4YMJKvyOeW", + "U*U"}, + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.VGOzA784oUp/Z0DY336zx7pLYAy0lwK", + "U*U*"}, + {"$2a$05$XXXXXXXXXXXXXXXXXXXXXOAcXxm9kjPGEMsLznoKqmqw7tc8WCx4a", + "U*U*U"}, + {"$2a$05$CCCCCCCCCCCCCCCCCCCCC.7uG0VCzI2bS7j6ymqJi9CdcdxiRTWNy", + ""}, + {"$2a$05$abcdefghijklmnopqrstuu5s2v8.iXieOjg/.AySBTTZIIVFJeBui", + "0123456789abcdefghijklmnopqrstuvwxyz" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + + "chars after 72 are ignored"}, + }; + + private final static String[] bcryptTest2 = { // from: http://openwall.info/wiki/john/sample-hashes + "$2a$05$bvIG6Nmid91Mu9RcmmWZfO5HJIMCT8riNW0hEp8f6/FuA2/mHZFpe", "password" + }; + + private final static String[] bcryptTest2b = { // from: http://stackoverflow.com/questions/11654684/verifying-a-bcrypt-hash + "$2a$10$.TtQJ4Jr6isd4Hp.mVfZeuh6Gws4rOQ/vdBczhDx.19NFK0Y84Dle", "\u03c0\u03c0\u03c0\u03c0\u03c0\u03c0\u03c0\u03c0" + }; + + private final static String[][] bcryptTest3 = // from: https://bitbucket.org/vadim/bcrypt.net/src/464c41416dc9/BCrypt.Net.Test/TestBCrypt.cs - plain - salt - expected + { + {"", "$2a$06$DCq7YPn5Rq63x1Lad4cll.", "$2a$06$DCq7YPn5Rq63x1Lad4cll.TV4S6ytwfsfvkgY8jIucDrjc8deX1s."}, + {"", "$2a$08$HqWuK6/Ng6sg9gQzbLrgb.", "$2a$08$HqWuK6/Ng6sg9gQzbLrgb.Tl.ZHfXLhvt/SgVyWhQqgqcZ7ZuUtye"}, + {"", "$2a$10$k1wbIrmNyFAPwPVPSVa/ze", "$2a$10$k1wbIrmNyFAPwPVPSVa/zecw2BCEnBwVS2GbrmgzxFUOqW9dk4TCW"}, + {"", "$2a$12$k42ZFHFWqBp3vWli.nIn8u", "$2a$12$k42ZFHFWqBp3vWli.nIn8uYyIkbvYRvodzbfbK18SSsY.CsIQPlxO"}, + {"a", "$2a$06$m0CrhHm10qJ3lXRY.5zDGO", "$2a$06$m0CrhHm10qJ3lXRY.5zDGO3rS2KdeeWLuGmsfGlMfOxih58VYVfxe"}, + {"a", "$2a$08$cfcvVd2aQ8CMvoMpP2EBfe", "$2a$08$cfcvVd2aQ8CMvoMpP2EBfeodLEkkFJ9umNEfPD18.hUF62qqlC/V."}, + {"a", "$2a$10$k87L/MF28Q673VKh8/cPi.", "$2a$10$k87L/MF28Q673VKh8/cPi.SUl7MU/rWuSiIDDFayrKk/1tBsSQu4u"}, + {"a", "$2a$12$8NJH3LsPrANStV6XtBakCe", "$2a$12$8NJH3LsPrANStV6XtBakCez0cKHXVxmvxIlcz785vxAIZrihHZpeS"}, + {"abc", "$2a$06$If6bvum7DFjUnE9p2uDeDu", "$2a$06$If6bvum7DFjUnE9p2uDeDu0YHzrHM6tf.iqN8.yx.jNN1ILEf7h0i"}, + {"abc", "$2a$08$Ro0CUfOqk6cXEKf3dyaM7O", "$2a$08$Ro0CUfOqk6cXEKf3dyaM7OhSCvnwM9s4wIX9JeLapehKK5YdLxKcm"}, + {"abc", "$2a$10$WvvTPHKwdBJ3uk0Z37EMR.", "$2a$10$WvvTPHKwdBJ3uk0Z37EMR.hLA2W6N9AEBhEgrAOljy2Ae5MtaSIUi"}, + {"abc", "$2a$12$EXRkfkdmXn2gzds2SSitu.", "$2a$12$EXRkfkdmXn2gzds2SSitu.MW9.gAVqa9eLS1//RYtYCmB1eLHg.9q"}, + {"abcdefghijklmnopqrstuvwxyz", "$2a$06$.rCVZVOThsIa97pEDOxvGu", "$2a$06$.rCVZVOThsIa97pEDOxvGuRRgzG64bvtJ0938xuqzv18d3ZpQhstC"}, + {"abcdefghijklmnopqrstuvwxyz", "$2a$08$aTsUwsyowQuzRrDqFflhge", "$2a$08$aTsUwsyowQuzRrDqFflhgekJ8d9/7Z3GV3UcgvzQW3J5zMyrTvlz."}, + {"abcdefghijklmnopqrstuvwxyz", "$2a$10$fVH8e28OQRj9tqiDXs1e1u", "$2a$10$fVH8e28OQRj9tqiDXs1e1uxpsjN0c7II7YPKXua2NAKYvM6iQk7dq"}, + {"abcdefghijklmnopqrstuvwxyz", "$2a$12$D4G5f18o7aMMfwasBL7Gpu", "$2a$12$D4G5f18o7aMMfwasBL7GpuQWuP3pkrZrOAnqP.bmezbMng.QwJ/pG"}, + {"~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$06$fPIsBO8qRqkjj273rfaOI.", "$2a$06$fPIsBO8qRqkjj273rfaOI.HtSV9jLDpTbZn782DC6/t7qT67P6FfO"}, + {"~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$08$Eq2r4G/76Wv39MzSX262hu", "$2a$08$Eq2r4G/76Wv39MzSX262huzPz612MZiYHVUJe/OcOql2jo4.9UxTW"}, + {"~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$10$LgfYWkbzEvQ4JakH7rOvHe", "$2a$10$LgfYWkbzEvQ4JakH7rOvHe0y8pHKF9OaFgwUZ2q7W2FFZmZzJYlfS"}, + {"~!@#$%^&*() ~!@#$%^&*()PNBFRD", "$2a$12$WApznUOJfkEGSmYRfnkrPO", "$2a$12$WApznUOJfkEGSmYRfnkrPOr466oFDCaj4b6HY3EXGvfxm43seyhgC"}, + }; + + private static final String[][] bcryptTest4 = { // from: https://github.com/ChrisMcKee/cryptsharp/blob/master/Tests/vectors/BCrypt.txt + {"n6HyjrYTo/r4lgjvM7L<`iM", "$2a$07$XPrYfnqc5ankSHnRfmPVu.A0trKq3VdczdbJjKaWIksKF.GfFCxv."}, + {"~s0quB/K8zRtRT:QtZr`s|^O", "$2a$07$5zzz8omiaStXwOetWwlmuePPRwUt0jhNBPYGGgAMcUDvqsGVqv9Cy"}, + {"r>8y3uE}6<7nI34?Q2rR0JEw", "$2a$07$k5AH9bO9aplPYdZMZ155qOcY1FewMXcupWewW6fViUtsVQ2Umg6LS"}, + {">l_7}xxH3|Cr{dCR[HTUN@k~", "$2a$05$24xz81ZZsMUMm940bbWMCeHsO.s6A3MG0JZzm4y3.Ti6P96bz6RN6"}, + {"D`lCFYTe9_8IW6nEB:oPjEk/S", "$2a$05$bA1xkp4NqFvDmtQJtDO9CugW0INxQLpMZha8AaHmBj9Zg9HlfQtBa"}, + {"UBGYU6|a|RpA:bp[;}p.ZY4f1", "$2a$08$gu4KBnkla.bEqHiwaJ8.z.0ixfzE1Q0/iPfmpfRmUA.NUhUdZboxa"}, + {"O9X[kP6{63F3rXKtN>n?zh2_", "$2a$04$yRZW9xEsqN9DL19jveqFyO1bljZ0r5KNCYqQzMqYpDB7XHWqDWNGC"}, + {":Sa:BknepsG}\\5dOj>kh0KAk", "$2a$04$KhDTFUlakUsPNuLQSgyr7.xQZxkTSIvo0nFw0XyjvrH6n5kZkYDLG"},// extra escape sequence added + {"2_9J6k:{z?SSjCzL/GT/5CMgc", "$2a$05$eN1jCXDxN9HmuIARJlwH4ewsEyYbAmq7Cw99gEHqGRXtWyrRNLScy"}, + + {"2KNy`Kodau14?s8XVruE;h/kdCRd@T]fQiv`Vz]KC0zaIAIeyY4zcooQ0^DfP{hHsw9?atO}CxbkbnK-LxUe;|FiBEluVqO@ysHhXQDdXPt0p", "$2a$07$pNHi/IxrSUohtsD5/eIv4O324ZPGfJE7mUAaNpIPkpyxjW9kqIk76"}, + {"ilWj~2mLBa1Pq`sxrW8fNNq:XF0@KP5RLW9u?[E_wwkROmCSWudYoS5I2HGI-1-?Pd0zVxTIeNbF;nLDUGtce{8dHmx90:;N<8", "$2a$07$ePVgkQl8QKSG2Xv6o0bnOe4SZp4ejag5CP44tjxfmY17F5VzRgwF6"}, + {"dj~OsXmQGj6FXnPGgwg9]G@75~L@G[|e3KWhz.Z~jUF0tt8[5U@8;5:=[v6pf.IEJ", "$2a$08$eXo9KDc1BZyybBgMurpcD.GA1/ch3XhgBnIH10Xvjc2ogZaGg3t/m"}, + }; + + + // 2y vectors generated from htpasswd -nB -C 12, nb leading username was removed. + private static final String[][] twoYVec = new String[][]{ + {"a", "$2y$12$DB3BUbYa/SsEL7kCOVji0OauTkPkB5Y1OeyfxJHM7jvMrbml5sgD2"}, + {"abc", "$2y$12$p.xODEbFcXUlHGbNxWZqAe6AA5FWupqXmN9tZea2ACDhwIx4EA2a6"}, + {"hello world", "$2y$12$wfkxITYXjNLVpEi9nOjz7uXMhCXKSTY7O2y7X4bwY89aGSvRziguq"}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXY", "$2y$12$QwAt5kuG68nW7v.87q0QPuwdki3romFc/RU/RV3Qqk4FPw6WdbQzu"} + }; + + // Same as 2y vectors only version changed to 2b to verify handling of that version. + private static final String[][] twoBVec = new String[][]{ + {"a", "$2b$12$DB3BUbYa/SsEL7kCOVji0OauTkPkB5Y1OeyfxJHM7jvMrbml5sgD2"}, + {"abc", "$2b$12$p.xODEbFcXUlHGbNxWZqAe6AA5FWupqXmN9tZea2ACDhwIx4EA2a6"}, + {"hello world", "$2b$12$wfkxITYXjNLVpEi9nOjz7uXMhCXKSTY7O2y7X4bwY89aGSvRziguq"}, + {"ABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXYABCDEFGHIJKLMNOPQRSTUVWXY", "$2b$12$QwAt5kuG68nW7v.87q0QPuwdki3romFc/RU/RV3Qqk4FPw6WdbQzu"} + }; + + public static void main(String[] args) + { + runTest(new OpenBSDBCryptTest()); + } + + public String getName() + { + return "OpenBSDBCrypt"; + } + + public void performTest() + throws Exception + { + for (int i = 0; i < bcryptTest1.length; i++) + { + String[] testString = bcryptTest1[i]; + String encoded = testString[0]; + String password = testString[1]; + if (!OpenBSDBCrypt.checkPassword(encoded, password.toCharArray())) + { + fail("test1 mismatch: " + "[" + i + "] " + password); + } + } + + String encoded = bcryptTest2[0]; + String password = bcryptTest2[1]; + if (!OpenBSDBCrypt.checkPassword(encoded, password.toCharArray())) + { + fail("bcryptTest2 mismatch: " + password); + } + + + encoded = bcryptTest2b[0]; + password = bcryptTest2b[1]; + if (!OpenBSDBCrypt.checkPassword(encoded, password.toCharArray())) + { + fail("bcryptTest2b mismatch: " + password); + } + + + for (int i = 0; i < bcryptTest3.length; i++) + { + String[] testString = bcryptTest3[i]; + encoded = testString[2]; + password = testString[0]; + if (!OpenBSDBCrypt.checkPassword(encoded, password.toCharArray())) + { + fail("test3 mismatch: " + "[" + i + "] " + password); + } + } + + + for (int i = 0; i < bcryptTest4.length; i++) + { + String[] testString = bcryptTest4[i]; + encoded = testString[1]; + password = testString[0]; + if (!OpenBSDBCrypt.checkPassword(encoded, password.toCharArray())) + { + fail("test4 mismatch: " + "[" + i + "] " + password); + } + } + + for (int i = 0; i < twoYVec.length; i++) + { + password = twoYVec[i][0]; + encoded = twoYVec[i][1]; + + if (!OpenBSDBCrypt.checkPassword(encoded, password.toCharArray())) + { + fail("twoYVec mismatch: " + "[" + i + "] " + password); + } + } + + for (int i = 0; i < twoBVec.length; i++) + { + password = twoBVec[i][0]; + encoded = twoBVec[i][1]; + + if (!OpenBSDBCrypt.checkPassword(encoded, password.toCharArray())) + { + fail("twoBVec mismatch: " + "[" + i + "] " + password); + } + } + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OpenSSHKeyParsingTests.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OpenSSHKeyParsingTests.java new file mode 100644 index 000000000..05e3eea56 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/OpenSSHKeyParsingTests.java @@ -0,0 +1,233 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.StringReader; +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.engines.RSAEngine; +import com.fr.third.org.bouncycastle.crypto.signers.DSASigner; +import com.fr.third.org.bouncycastle.crypto.signers.ECDSASigner; +import com.fr.third.org.bouncycastle.crypto.signers.Ed25519Signer; +import com.fr.third.org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil; +import com.fr.third.org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.io.pem.PemReader; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class OpenSSHKeyParsingTests + extends SimpleTest +{ + private static SecureRandom secureRandom = new SecureRandom(); + + + public static void main( + String[] args) + { + runTest(new OpenSSHKeyParsingTests()); + } + + + public void testDSA() + throws Exception + { + CipherParameters pubSpec = OpenSSHPublicKeyUtil.parsePublicKey(Base64.decode("AAAAB3NzaC1kc3MAAACBAJBB5+S4kZZYZLswaQ/zm3GM7YWmHsumwo/Xxu+z6Cg2l5PUoiBBZ4ET9EhhQuL2ja/zrCMCi0ZwiSRuSp36ayPrHLbNJb3VdOuJg8xExRa6F3YfVZfcTPUEKh6FU72fI31HrQmi4rpyHnWxL/iDX496ZG2Hdq6UkPISQpQwj4TtAAAAFQCP9TXcVahR/2rpfEhvdXR0PfhbRwAAAIBdXzAVqoOtb9zog6lNF1cGS1S06W9W/clvuwq2xF1s3bkoI/xUbFSc0IAPsGl2kcB61PAZqcop50lgpvYzt8cq/tbqz3ypq1dCQ0xdmJHj975QsRFax+w6xQ0kgpBhwcS2EOizKb+C+tRzndGpcDSoSMuVXp9i4wn5pJSTZxAYFQAAAIEAhQZc687zYxrEDR/1q6m4hw5GFxuVvLsC+bSHtMF0c11Qy4IPg7mBeP7K5Kq4WyJPtmZhuc5Bb12bJQR6qgd1uLn692fe1UK2kM6eWXBzhlzZ54BslfSKHGNN4qH+ln3Zaf/4rpKE7fvoinkrgkOZmj0PMx9D6wlpHKkXMUxeXtc=")); + + CipherParameters privSpec = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(new PemReader(new StringReader("-----BEGIN DSA PRIVATE KEY-----\n" + + "MIIBuwIBAAKBgQCQQefkuJGWWGS7MGkP85txjO2Fph7LpsKP18bvs+goNpeT1KIg\n" + + "QWeBE/RIYULi9o2v86wjAotGcIkkbkqd+msj6xy2zSW91XTriYPMRMUWuhd2H1WX\n" + + "3Ez1BCoehVO9nyN9R60JouK6ch51sS/4g1+PemRth3aulJDyEkKUMI+E7QIVAI/1\n" + + "NdxVqFH/aul8SG91dHQ9+FtHAoGAXV8wFaqDrW/c6IOpTRdXBktUtOlvVv3Jb7sK\n" + + "tsRdbN25KCP8VGxUnNCAD7BpdpHAetTwGanKKedJYKb2M7fHKv7W6s98qatXQkNM\n" + + "XZiR4/e+ULERWsfsOsUNJIKQYcHEthDosym/gvrUc53RqXA0qEjLlV6fYuMJ+aSU\n" + + "k2cQGBUCgYEAhQZc687zYxrEDR/1q6m4hw5GFxuVvLsC+bSHtMF0c11Qy4IPg7mB\n" + + "eP7K5Kq4WyJPtmZhuc5Bb12bJQR6qgd1uLn692fe1UK2kM6eWXBzhlzZ54BslfSK\n" + + "HGNN4qH+ln3Zaf/4rpKE7fvoinkrgkOZmj0PMx9D6wlpHKkXMUxeXtcCFELnLOJ8\n" + + "D0akSCUFY/iDLo/KnOIH\n" + + "-----END DSA PRIVATE KEY-----\n")).readPemObject().getContent()); + + DSASigner signer = new DSASigner(); + signer.init(true, privSpec); + + byte[] originalMessage = new byte[10]; + secureRandom.nextBytes(originalMessage); + + BigInteger[] rs = signer.generateSignature(originalMessage); + + signer.init(false, pubSpec); + + isTrue("DSA test", signer.verifySignature(originalMessage, rs[0], rs[1])); + + } + + + public void testECDSA() + throws Exception + { + CipherParameters pubSpec = OpenSSHPublicKeyUtil.parsePublicKey(Base64.decode("AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHq5qxGqnh93Gpbj2w1Avx1UwBl6z5bZC3Viog1yNHDZYcV6Da4YQ3i0/hN7xY7sUy9dNF6g16tJSYXQQ4tvO3g=")); + + CipherParameters privSpec = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(new PemReader(new StringReader("-----BEGIN EC PRIVATE KEY-----\n" + + "MHcCAQEEIHeg/+m02j6nr4bO8ubfbzhs0fqOjiuIoWbvGnVg+FmpoAoGCCqGSM49\n" + + "AwEHoUQDQgAEermrEaqeH3caluPbDUC/HVTAGXrPltkLdWKiDXI0cNlhxXoNrhhD\n" + + "eLT+E3vFjuxTL100XqDXq0lJhdBDi287eA==\n" + + "-----END EC PRIVATE KEY-----\n")).readPemObject().getContent()); + + ECDSASigner signer = new ECDSASigner(); + signer.init(true, privSpec); + + byte[] originalMessage = new byte[10]; + secureRandom.nextBytes(originalMessage); + + BigInteger[] rs = signer.generateSignature(originalMessage); + + signer.init(false, pubSpec); + + isTrue("ECDSA test", signer.verifySignature(originalMessage, rs[0], rs[1])); + + } + + + public void testED25519() + throws Exception + { + + CipherParameters pubSpec = OpenSSHPublicKeyUtil.parsePublicKey(Base64.decode("AAAAC3NzaC1lZDI1NTE5AAAAIM4CaV7WQcy0lht0hclgXf4Olyvzvv2fnUvQ3J8IYsWF")); + + CipherParameters privSpec = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(new PemReader(new StringReader("-----BEGIN OPENSSH PRIVATE KEY-----\n" + + "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n" + + "QyNTUxOQAAACDOAmle1kHMtJYbdIXJYF3+Dpcr8779n51L0NyfCGLFhQAAAKBTr4PvU6+D\n" + + "7wAAAAtzc2gtZWQyNTUxOQAAACDOAmle1kHMtJYbdIXJYF3+Dpcr8779n51L0NyfCGLFhQ\n" + + "AAAED4BTHeR3YD7CFQqusztfL5K+YSD4mRGLBwb7jHiXxIJM4CaV7WQcy0lht0hclgXf4O\n" + + "lyvzvv2fnUvQ3J8IYsWFAAAAG21lZ2Fud29vZHNAdHljaGUtMzI2NS5sb2NhbAEC\n" + + "-----END OPENSSH PRIVATE KEY-----\n")).readPemObject().getContent()); + + Ed25519Signer signer = new Ed25519Signer(); + signer.init(true, privSpec); + + byte[] originalMessage = new byte[10]; + secureRandom.nextBytes(originalMessage); + signer.update(originalMessage, 0, originalMessage.length); + + byte[] sig = signer.generateSignature(); + + signer.init(false, pubSpec); + + signer.update(originalMessage, 0, originalMessage.length); + + + isTrue("ED25519Signer test", signer.verifySignature(sig)); + + } + + + public void testFailures() + throws Exception + { + byte[] blob = new PemReader(new StringReader("-----BEGIN OPENSSH PRIVATE KEY-----\n" + + "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n" + + "QyNTUxOQAAACDOAmle1kHMtJYbdIXJYF3+Dpcr8779n51L0NyfCGLFhQAAAKBTr4PvU6+D\n" + + "7wAAAAtzc2gtZWQyNTUxOQAAACDOAmle1kHMtJYbdIXJYF3+Dpcr8779n51L0NyfCGLFhQ\n" + + "AAAED4BTHeR3YD7CFQqusztfL5K+YSD4mRGLBwb7jHiXxIJM4CaV7WQcy0lht0hclgXf4O\n" + + "lyvzvv2fnUvQ3J8IYsWFAAAAG21lZ2Fud29vZHNAdHljaGUtMzI2NS5sb2NhbAEC\n" + + "-----END OPENSSH PRIVATE KEY-----\n")).readPemObject().getContent(); + + + // + // Altering the check value. + // + + blob[98] ^= 1; + + try + { + CipherParameters privSpec = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(blob); + fail("Change should trigger failure."); + } + catch (IllegalStateException iles) + { + isEquals("Check value mismatch ", iles.getMessage(), "private key check values are not the same"); + } + + + // + // Altering the cipher name. + // + + + blob = new PemReader(new StringReader("-----BEGIN OPENSSH PRIVATE KEY-----\n" + + "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n" + + "QyNTUxOQAAACDOAmle1kHMtJYbdIXJYF3+Dpcr8779n51L0NyfCGLFhQAAAKBTr4PvU6+D\n" + + "7wAAAAtzc2gtZWQyNTUxOQAAACDOAmle1kHMtJYbdIXJYF3+Dpcr8779n51L0NyfCGLFhQ\n" + + "AAAED4BTHeR3YD7CFQqusztfL5K+YSD4mRGLBwb7jHiXxIJM4CaV7WQcy0lht0hclgXf4O\n" + + "lyvzvv2fnUvQ3J8IYsWFAAAAG21lZ2Fud29vZHNAdHljaGUtMzI2NS5sb2NhbAEC\n" + + "-----END OPENSSH PRIVATE KEY-----\n")).readPemObject().getContent(); + + + blob[19] = (byte)'C'; + + try + { + CipherParameters privSpec = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(blob); + fail("Change should trigger failure."); + } + catch (IllegalStateException iles) + { + isEquals("enc keys not supported ", iles.getMessage(), "encrypted keys not supported"); + } + } + + public String getName() + { + return "OpenSSHParsing"; + } + + public void performTest() + throws Exception + { + testDSA(); + testECDSA(); + testRSA(); + testED25519(); + testFailures(); + } + + public void testRSA() + throws Exception + { + CipherParameters pubSpec = OpenSSHPublicKeyUtil.parsePublicKey(Base64.decode("AAAAB3NzaC1yc2EAAAADAQABAAAAgQDvh2BophdIp8ojwGZQR0FQ/awowXnV24nAPm+/na8MOUrdySNhOnlek4LAZl82/+Eu2t21XD6hQUiHKAj6XaNFBthTuss7Cz/tA348DLEMHD9wUtT0FXVmsxqN4BfusunbcULxxVWG2z8FvqeaGgc/Unkp9y7/kyf54pPUCBcClw==")); + + CipherParameters privSpec = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(new PemReader(new StringReader("-----BEGIN RSA PRIVATE KEY-----\n" + + "MIICXgIBAAKBgQDvh2BophdIp8ojwGZQR0FQ/awowXnV24nAPm+/na8MOUrdySNh\n" + + "Onlek4LAZl82/+Eu2t21XD6hQUiHKAj6XaNFBthTuss7Cz/tA348DLEMHD9wUtT0\n" + + "FXVmsxqN4BfusunbcULxxVWG2z8FvqeaGgc/Unkp9y7/kyf54pPUCBcClwIDAQAB\n" + + "AoGBAOMXYEoXHgAeREE9CkOWKtDUkEJbnF0rNSB0kZIDt5BJSTeYmNh3jdYi2FX9\n" + + "OMx2MFIx4v0tJZvQvyiUxl5IJJ9ZJsYUWF+6VbcTVwYYfdVzZzP2TNyGmF9/ADZW\n" + + "wBehqP04uRlYjt94kqb4HoOKF3gJ3LC4uW9xcEltTBeHWCfhAkEA/2biF5St9/Ya\n" + + "540E4zu/FKPsxLSaT8LWCo9+X7IqIzlBQCB4GjM+nZeTm7eZOkfAFZoxwfiNde/9\n" + + "qleXXf6B2QJBAPAW+jDBC3QF4/g8n9cDxm/A3ICmcOFSychLSrydk9ZyRPbTRyQC\n" + + "YlC2mf/pCrO/yO7h189BXyQ3PXOEhnujce8CQQD7gDy0K90EiH0F94AQpA0OLj5B\n" + + "lfc/BAXycEtpwPBtrzvqAg9C/aNzXIgmly10jqNAoo7NDA2BTcrlq0uLa8xBAkBl\n" + + "7Hs+I1XnZXDIO4Rn1VRysN9rRj15ipnbDAuoUwUl7tDUMBFteg2e0kZCW/6NHIgC\n" + + "0aG6fLgVOdY+qi4lYtfFAkEAqqiBgEgSrDmnJLTm6j/Pv1mBA6b9bJbjOqomrDtr\n" + + "AWTXe+/kSCv/jYYdpNA/tDgAwEmtkWWEie6+SwJB5cXXqg==\n" + + "-----END RSA PRIVATE KEY-----\n")).readPemObject().getContent()); + + + byte[] originalMessage = new byte[10]; + secureRandom.nextBytes(originalMessage); + + originalMessage[0] |= 1; + + RSAEngine rsaEngine = new RSAEngine(); + rsaEngine.init(true, privSpec); + + byte[] ct = rsaEngine.processBlock(originalMessage, 0, originalMessage.length); + + rsaEngine.init(false, pubSpec); + byte[] result = rsaEngine.processBlock(ct, 0, ct.length); + + isTrue("Result did not match original message", Arrays.areEqual(originalMessage, result)); + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PKCS12Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PKCS12Test.java new file mode 100644 index 000000000..4bcdab758 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PKCS12Test.java @@ -0,0 +1,206 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.PBEParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * test for PKCS12 key generation - vectors from + * + * http://www.drh-consultancy.demon.co.uk/test.txt + */ +public class PKCS12Test + implements Test +{ + char[] password1 = { 's', 'm', 'e', 'g' }; + char[] password2 = { 'q', 'u', 'e', 'e', 'g' }; + + private boolean isEqual( + byte[] a, + byte[] b) + { + if (a.length != b.length) + { + return false; + } + + for (int i = 0; i != a.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + private TestResult run1( + int id, + char[] password, + byte[] salt, + int iCount, + byte[] result) + { + PBEParametersGenerator generator = new PKCS12ParametersGenerator( + new SHA1Digest()); + + generator.init( + PBEParametersGenerator.PKCS12PasswordToBytes(password), + salt, + iCount); + + CipherParameters key = generator.generateDerivedParameters(24 * 8); + + if (isEqual(result, ((KeyParameter)key).getKey())) + { + return new SimpleTestResult(true, "PKCS12Test: Okay"); + } + else + { + return new SimpleTestResult(false, "PKCS12Test: id " + + id + " Failed"); + } + } + + private TestResult run2( + int id, + char[] password, + byte[] salt, + int iCount, + byte[] result) + { + PBEParametersGenerator generator = new PKCS12ParametersGenerator( + new SHA1Digest()); + + generator.init( + PBEParametersGenerator.PKCS12PasswordToBytes(password), + salt, + iCount); + + ParametersWithIV params = (ParametersWithIV)generator.generateDerivedParameters(64, 64); + + if (isEqual(result, params.getIV())) + { + return new SimpleTestResult(true, "PKCS12Test: Okay"); + } + else + { + return new SimpleTestResult(false, "PKCS12Test: id " + + id + " Failed"); + } + } + + private TestResult run3( + int id, + char[] password, + byte[] salt, + int iCount, + byte[] result) + { + PBEParametersGenerator generator = new PKCS12ParametersGenerator( + new SHA1Digest()); + + generator.init( + PBEParametersGenerator.PKCS12PasswordToBytes(password), + salt, + iCount); + + CipherParameters key = generator.generateDerivedMacParameters(160); + + if (isEqual(result, ((KeyParameter)key).getKey())) + { + return new SimpleTestResult(true, "PKCS12Test: Okay"); + } + else + { + return new SimpleTestResult(false, "PKCS12Test: id " + + id + " Failed"); + } + } + + public String getName() + { + return "PKCS12Test"; + } + + public TestResult perform() + { + TestResult result; + + result = run1(1, password1, Hex.decode("0A58CF64530D823F"), 1, + Hex.decode("8AAAE6297B6CB04642AB5B077851284EB7128F1A2A7FBCA3")); + + if (result.isSuccessful()) + { + result = run2(2, password1, Hex.decode("0A58CF64530D823F"), 1, + Hex.decode("79993DFE048D3B76")); + } + + if (result.isSuccessful()) + { + result = run1(3, password1, Hex.decode("642B99AB44FB4B1F"), 1, + Hex.decode("F3A95FEC48D7711E985CFE67908C5AB79FA3D7C5CAA5D966")); + } + + if (result.isSuccessful()) + { + result = run2(4, password1, Hex.decode("642B99AB44FB4B1F"), 1, + Hex.decode("C0A38D64A79BEA1D")); + } + + if (result.isSuccessful()) + { + result = run3(5, password1, Hex.decode("3D83C0E4546AC140"), 1, + Hex.decode("8D967D88F6CAA9D714800AB3D48051D63F73A312")); + } + + if (result.isSuccessful()) + { + result = run1(6, password2, Hex.decode("05DEC959ACFF72F7"), 1000, + Hex.decode("ED2034E36328830FF09DF1E1A07DD357185DAC0D4F9EB3D4")); + } + + if (result.isSuccessful()) + { + result = run2(7, password2, Hex.decode("05DEC959ACFF72F7"), 1000, + Hex.decode("11DEDAD7758D4860")); + } + + if (result.isSuccessful()) + { + result = run1(8, password2, Hex.decode("1682C0FC5B3F7EC5"), 1000, + Hex.decode("483DD6E919D7DE2E8E648BA8F862F3FBFBDC2BCB2C02957F")); + } + + if (result.isSuccessful()) + { + result = run2(9, password2, Hex.decode("1682C0FC5B3F7EC5"), 1000, + Hex.decode("9D461D1B00355C50")); + } + + if (result.isSuccessful()) + { + result = run3(10, password2, Hex.decode("263216FCC2FAB31C"), 1000, + Hex.decode("5EC4C7A80DF652294C3925B6489A7AB857C83476")); + } + + return result; + } + + public static void main( + String[] args) + { + PKCS12Test test = new PKCS12Test(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PKCS5Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PKCS5Test.java new file mode 100644 index 000000000..2c2cd87a2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PKCS5Test.java @@ -0,0 +1,265 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.ByteArrayInputStream; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.EncryptionScheme; +import com.fr.third.org.bouncycastle.asn1.pkcs.KeyDerivationFunc; +import com.fr.third.org.bouncycastle.asn1.pkcs.PBES2Parameters; +import com.fr.third.org.bouncycastle.asn1.pkcs.PBKDF2Params; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.RC2CBCParameter; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.PBEParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.engines.RC2Engine; +import com.fr.third.org.bouncycastle.crypto.generators.PKCS5S2ParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * A test class for PKCS5 PBES2 with PBKDF2 (PKCS5 v2.0) using + * test vectors provider at + * + * RSA's PKCS5 Page + *
+ * The vectors are Base 64 encoded and encrypted using the password "password" + * (without quotes). They should all yield the same PrivateKeyInfo object. + */ +public class PKCS5Test + extends SimpleTest +{ + /** + * encrypted using des-cbc. + */ + static byte[] sample1 = Base64.decode( + "MIIBozA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIfWBDXwLp4K4CAggA" + + "MBEGBSsOAwIHBAiaCF/AvOgQ6QSCAWDWX4BdAzCRNSQSANSuNsT5X8mWYO27mr3Y" + + "9c9LoBVXGNmYWKA77MI4967f7SmjNcgXj3xNE/jmnVz6hhsjS8E5VPT3kfyVkpdZ" + + "0lr5e9Yk2m3JWpPU7++v5zBkZmC4V/MwV/XuIs6U+vykgzMgpxQg0oZKS9zgmiZo" + + "f/4dOCL0UtCDnyOSvqT7mCVIcMDIEKu8QbVlgZYBop08l60EuEU3gARUo8WsYQmO" + + "Dz/ldx0Z+znIT0SXVuOwc+RVItC5T/Qx+aijmmpt+9l14nmaGBrEkmuhmtdvU/4v" + + "aptewGRgmjOfD6cqK+zs0O5NrrJ3P/6ZSxXj91CQgrThGfOv72bUncXEMNtc8pks" + + "2jpHFjGMdKufnadAD7XuMgzkkaklEXZ4f5tU6heIIwr51g0GBEGF96gYPFnjnSQM" + + "75JE02Clo+DfcfXpcybPTwwFg2jd6JTTOfkdf6OdSlA/1XNK43FA"); + + /** + * encrypted using des-ede3-cbc. + */ + static byte[] sample2 = Base64.decode( + "MIIBpjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIeFeOWl1jywYCAggA" + + "MBQGCCqGSIb3DQMHBAjUJ5eGBhQGtQSCAWBrHrRgqO8UUMLcWzZEtpk1l3mjxiF/" + + "koCMkHsFwowgyWhEbgIkTgbSViK54LVK8PskekcGNLph+rB6bGZ7pPbL5pbXASJ8" + + "+MkQcG3FZdlS4Ek9tTJDApj3O1UubZGFG4uvTlJJFbF1BOJ3MkY3XQ9Gl1qwv7j5" + + "6e103Da7Cq9+oIDKmznza78XXQYrUsPo8mJGjUxPskEYlzwvHjKubRnYm/K6RKhi" + + "5f4zX4BQ/Dt3H812ZjRXrsjAJP0KrD/jyD/jCT7zNBVPH1izBds+RwizyQAHwfNJ" + + "BFR78TH4cgzB619X47FDVOnT0LqQNVd0O3cSwnPrXE9XR3tPayE+iOB15llFSmi8" + + "z0ByOXldEpkezCn92Umk++suzIVj1qfsK+bv2phZWJPbLEIWPDRHUbYf76q5ArAr" + + "u4xtxT/hoK3krEs/IN3d70qjlUJ36SEw1UaZ82PWhakQbdtu39ZraMJB"); + + /** + * encrypted using rc2-cbc. + */ + static byte[] sample3 = Base64.decode( + "MIIBrjBIBgkqhkiG9w0BBQ0wOzAeBgkqhkiG9w0BBQwwEQQIrHyQPBZqWLUCAggA" + + "AgEQMBkGCCqGSIb3DQMCMA0CAToECEhbh7YZKiPSBIIBYCT1zp6o5jpFlIkgwPop" + + "7bW1+8ACr4exqzkeb3WflQ8cWJ4cURxzVdvxUnXeW1VJdaQZtjS/QHs5GhPTG/0f" + + "wtvnaPfwrIJ3FeGaZfcg2CrYhalOFmEb4xrE4KyoEQmUN8tb/Cg94uzd16BOPw21" + + "RDnE8bnPdIGY7TyL95kbkqH23mK53pi7h+xWIgduW+atIqDyyt55f7WMZcvDvlj6" + + "VpN/V0h+qxBHL274WA4dj6GYgeyUFpi60HdGCK7By2TBy8h1ZvKGjmB9h8jZvkx1" + + "MkbRumXxyFsowTZawyYvO8Um6lbfEDP9zIEUq0IV8RqH2MRyblsPNSikyYhxX/cz" + + "tdDxRKhilySbSBg5Kr8OfcwKp9bpinN96nmG4xr3Tch1bnVvqJzOQ5+Vva2WwVvH" + + "2JkWvYm5WaANg4Q6bRxu9vz7DuhbJjQdZbxFezIAgrJdSe92B00jO/0Kny1WjiVO" + + "6DA="); + + static byte[] result = Hex.decode( + "30820155020100300d06092a864886f70d01010105000482013f3082013b020100024100" + + "debbfc2c09d61bada2a9462f24224e54cc6b3cc0755f15ce318ef57e79df17026b6a85cc" + + "a12428027245045df2052a329a2f9ad3d17b78a10572ad9b22bf343b020301000102402d" + + "90a96adcec472743527bc023153d8f0d6e96b40c8ed228276d467d843306429f8670559b" + + "f376dd41857f6397c2fc8d95e0e53ed62de420b855430ee4a1b8a1022100ffcaf0838239" + + "31e073ff534f06a5d415b3d414bc614a4544a3dff7ed271817eb022100deea30242117db" + + "2d3b8837f58f1da530ff83cf9283680da33683ec4e583610f1022100e6026381adb0a683" + + "f16a8f4c096b462979b9e4277cc89f3ed8a905b46fa9ff9f02210097c146d4d1d2b3dbaf" + + "53a504ff51674c5c271800de84d003f4f10ac6ab36e38102202bfa141f10bda874e1017d" + + "845e82767c1c38e82745daf421f0c8cd09d7652387"); + + private class PBETest + extends SimpleTest + { + int id; + BufferedBlockCipher cipher; + byte[] sample; + int keySize; + + PBETest( + int id, + BufferedBlockCipher cipher, + byte[] sample, + int keySize) + { + this.id = id; + this.cipher = cipher; + this.sample = sample; + this.keySize = keySize; + } + + public String getName() + { + return cipher.getUnderlyingCipher().getAlgorithmName() + " PKCS5S2 Test " + id; + } + + public void performTest() + { + char[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' }; + PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(); + ByteArrayInputStream bIn = new ByteArrayInputStream(sample); + ASN1InputStream dIn = new ASN1InputStream(bIn); + EncryptedPrivateKeyInfo info = null; + + try + { + info = EncryptedPrivateKeyInfo.getInstance(dIn.readObject()); + } + catch (Exception e) + { + fail("failed construction - exception " + e.toString(), e); + } + + PBES2Parameters alg = PBES2Parameters.getInstance(info.getEncryptionAlgorithm().getParameters()); + PBKDF2Params func = PBKDF2Params.getInstance(alg.getKeyDerivationFunc().getParameters()); + EncryptionScheme scheme = alg.getEncryptionScheme(); + + if (func.getKeyLength() != null) + { + keySize = func.getKeyLength().intValue() * 8; + } + + int iterationCount = func.getIterationCount().intValue(); + byte[] salt = func.getSalt(); + + generator.init( + PBEParametersGenerator.PKCS5PasswordToBytes(password), + salt, + iterationCount); + + CipherParameters param; + + if (scheme.getAlgorithm().equals(PKCSObjectIdentifiers.RC2_CBC)) + { + RC2CBCParameter rc2Params = RC2CBCParameter.getInstance(scheme.getParameters()); + byte[] iv = rc2Params.getIV(); + + param = new ParametersWithIV(generator.generateDerivedParameters(keySize), iv); + } + else + { + byte[] iv = ASN1OctetString.getInstance(scheme.getParameters()).getOctets(); + + param = new ParametersWithIV(generator.generateDerivedParameters(keySize), iv); + } + + cipher.init(false, param); + + byte[] data = info.getEncryptedData(); + byte[] out = new byte[cipher.getOutputSize(data.length)]; + int len = cipher.processBytes(data, 0, data.length, out, 0); + + try + { + len += cipher.doFinal(out, len); + } + catch (Exception e) + { + fail("failed doFinal - exception " + e.toString()); + } + + if (result.length != len) + { + fail("failed length"); + } + + for (int i = 0; i != len; i++) + { + if (out[i] != result[i]) + { + fail("failed comparison"); + } + } + } + } + + public String getName() + { + return "PKCS5S2"; + } + + public void performTest() + throws Exception + { + BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESEngine())); + SimpleTest test = new PBETest(0, cipher, sample1, 64); + + test.performTest(); + + cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new DESedeEngine())); + test = new PBETest(1, cipher, sample2, 192); + + test.performTest(); + + cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new RC2Engine())); + test = new PBETest(2, cipher, sample3, 0); + test.performTest(); + + // + // RFC 3211 tests + // + char[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' }; + PBEParametersGenerator generator = new PKCS5S2ParametersGenerator(); + + byte[] salt = Hex.decode("1234567878563412"); + + generator.init( + PBEParametersGenerator.PKCS5PasswordToBytes(password), + salt, + 5); + + if (!areEqual(((KeyParameter)generator.generateDerivedParameters(64)).getKey(), Hex.decode("d1daa78615f287e6"))) + { + fail("64 test failed"); + } + + password = "All n-entities must communicate with other n-entities via n-1 entiteeheehees".toCharArray(); + + generator.init( + PBEParametersGenerator.PKCS5PasswordToBytes(password), + salt, + 500); + + if (!areEqual(((KeyParameter)generator.generateDerivedParameters(192)).getKey(), Hex.decode("6a8970bf68c92caea84a8df28510858607126380cc47ab2d"))) + { + fail("192 test failed"); + } + + generator.init(PBEParametersGenerator.PKCS5PasswordToBytes(password), salt, 60000); + if (!areEqual(((KeyParameter)generator.generateDerivedParameters(192)).getKey(), Hex.decode("29aaef810c12ecd2236bbcfb55407f9852b5573dc1c095bb"))) + { + fail("192 (60000) test failed"); + } + } + + public static void main( + String[] args) + { + runTest(new PKCS5Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PSSBlindTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PSSBlindTest.java new file mode 100644 index 000000000..de938182a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PSSBlindTest.java @@ -0,0 +1,398 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.engines.RSABlindingEngine; +import com.fr.third.org.bouncycastle.crypto.engines.RSAEngine; +import com.fr.third.org.bouncycastle.crypto.generators.RSABlindingFactorGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.RSAKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.params.RSABlindingParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.crypto.signers.PSSSigner; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/* + * RSA PSS test vectors for PKCS#1 V2.1 with blinding + */ +public class PSSBlindTest + extends SimpleTest +{ + private final int DATA_LENGTH = 1000; + private final int NUM_TESTS = 50; + private final int NUM_TESTS_WITH_KEY_GENERATION = 10; + + private class FixedRandom + extends SecureRandom + { + byte[] vals; + + FixedRandom( + byte[] vals) + { + this.vals = vals; + } + + public void nextBytes( + byte[] bytes) + { + System.arraycopy(vals, 0, bytes, 0, vals.length); + } + } + + // + // Example 1: A 1024-bit RSA keypair + // + private RSAKeyParameters pub1 = new RSAKeyParameters(false, + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16)); + + private RSAKeyParameters prv1 = new RSAPrivateCrtKeyParameters( + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16), + new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16), + new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16), + new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16), + new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16), + new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16), + new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16)); + + // PSSExample1.1 + + private byte[] msg1a = Hex.decode("cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0"); + + private byte[] slt1a = Hex.decode("dee959c7e06411361420ff80185ed57f3e6776af"); + + private byte[] sig1a = Hex.decode("9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c"); + + // PSSExample1.2 + + private byte[] msg1b = Hex.decode("851384cdfe819c22ed6c4ccb30daeb5cf059bc8e1166b7e3530c4c233e2b5f8f71a1cca582d43ecc72b1bca16dfc7013226b9e"); + + private byte[] slt1b = Hex.decode("ef2869fa40c346cb183dab3d7bffc98fd56df42d"); + + private byte[] sig1b = Hex.decode("3ef7f46e831bf92b32274142a585ffcefbdca7b32ae90d10fb0f0c729984f04ef29a9df0780775ce43739b97838390db0a5505e63de927028d9d29b219ca2c4517832558a55d694a6d25b9dab66003c4cccd907802193be5170d26147d37b93590241be51c25055f47ef62752cfbe21418fafe98c22c4d4d47724fdb5669e843"); + + // + // Example 2: A 1025-bit RSA keypair + // + + private RSAKeyParameters pub2 = new RSAKeyParameters(false, + new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv2 = new RSAPrivateCrtKeyParameters( + new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16), + new BigInteger("010001", 16), + new BigInteger("027d147e4673057377fd1ea201565772176a7dc38358d376045685a2e787c23c15576bc16b9f444402d6bfc5d98a3e88ea13ef67c353eca0c0ddba9255bd7b8bb50a644afdfd1dd51695b252d22e7318d1b6687a1c10ff75545f3db0fe602d5f2b7f294e3601eab7b9d1cecd767f64692e3e536ca2846cb0c2dd486a39fa75b1", 16), + new BigInteger("016601e926a0f8c9e26ecab769ea65a5e7c52cc9e080ef519457c644da6891c5a104d3ea7955929a22e7c68a7af9fcad777c3ccc2b9e3d3650bce404399b7e59d1", 16), + new BigInteger("014eafa1d4d0184da7e31f877d1281ddda625664869e8379e67ad3b75eae74a580e9827abd6eb7a002cb5411f5266797768fb8e95ae40e3e8a01f35ff89e56c079", 16), + new BigInteger("e247cce504939b8f0a36090de200938755e2444b29539a7da7a902f6056835c0db7b52559497cfe2c61a8086d0213c472c78851800b171f6401de2e9c2756f31", 16), + new BigInteger("b12fba757855e586e46f64c38a70c68b3f548d93d787b399999d4c8f0bbd2581c21e19ed0018a6d5d3df86424b3abcad40199d31495b61309f27c1bf55d487c1", 16), + new BigInteger("564b1e1fa003bda91e89090425aac05b91da9ee25061e7628d5f51304a84992fdc33762bd378a59f030a334d532bd0dae8f298ea9ed844636ad5fb8cbdc03cad", 16)); + + // PSS Example 2.1 + + private byte[] msg2a = Hex.decode("daba032066263faedb659848115278a52c44faa3a76f37515ed336321072c40a9d9b53bc05014078adf520875146aae70ff060226dcb7b1f1fc27e9360"); + private byte[] slt2a = Hex.decode("57bf160bcb02bb1dc7280cf0458530b7d2832ff7"); + private byte[] sig2a = Hex.decode("014c5ba5338328ccc6e7a90bf1c0ab3fd606ff4796d3c12e4b639ed9136a5fec6c16d8884bdd99cfdc521456b0742b736868cf90de099adb8d5ffd1deff39ba4007ab746cefdb22d7df0e225f54627dc65466131721b90af445363a8358b9f607642f78fab0ab0f43b7168d64bae70d8827848d8ef1e421c5754ddf42c2589b5b3"); + + // PSS Example 2.2 + + private byte[] msg2b = Hex.decode("e4f8601a8a6da1be34447c0959c058570c3668cfd51dd5f9ccd6ad4411fe8213486d78a6c49f93efc2ca2288cebc2b9b60bd04b1e220d86e3d4848d709d032d1e8c6a070c6af9a499fcf95354b14ba6127c739de1bb0fd16431e46938aec0cf8ad9eb72e832a7035de9b7807bdc0ed8b68eb0f5ac2216be40ce920c0db0eddd3860ed788efaccaca502d8f2bd6d1a7c1f41ff46f1681c8f1f818e9c4f6d91a0c7803ccc63d76a6544d843e084e363b8acc55aa531733edb5dee5b5196e9f03e8b731b3776428d9e457fe3fbcb3db7274442d785890e9cb0854b6444dace791d7273de1889719338a77fe"); + private byte[] slt2b = Hex.decode("7f6dd359e604e60870e898e47b19bf2e5a7b2a90"); + private byte[] sig2b = Hex.decode("010991656cca182b7f29d2dbc007e7ae0fec158eb6759cb9c45c5ff87c7635dd46d150882f4de1e9ae65e7f7d9018f6836954a47c0a81a8a6b6f83f2944d6081b1aa7c759b254b2c34b691da67cc0226e20b2f18b42212761dcd4b908a62b371b5918c5742af4b537e296917674fb914194761621cc19a41f6fb953fbcbb649dea"); + + // + // Example 4: A 1027-bit RSA key pair + // + + private RSAKeyParameters pub4 = new RSAKeyParameters(false, + new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv4 = new RSAPrivateCrtKeyParameters( + new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16), + new BigInteger("010001", 16), + new BigInteger("fa041f8cd9697ceed38ec8caa275523b4dd72b09a301d3541d72f5d31c05cbce2d6983b36183af10690bd46c46131e35789431a556771dd0049b57461bf060c1f68472e8a67c25f357e5b6b4738fa541a730346b4a07649a2dfa806a69c975b6aba64678acc7f5913e89c622f2d8abb1e3e32554e39df94ba60c002e387d9011", 16), + new BigInteger("029232336d2838945dba9dd7723f4e624a05f7375b927a87abe6a893a1658fd49f47f6c7b0fa596c65fa68a23f0ab432962d18d4343bd6fd671a5ea8d148413995", 16), + new BigInteger("020ef5efe7c5394aed2272f7e81a74f4c02d145894cb1b3cab23a9a0710a2afc7e3329acbb743d01f680c4d02afb4c8fde7e20930811bb2b995788b5e872c20bb1", 16), + new BigInteger("026e7e28010ecf2412d9523ad704647fb4fe9b66b1a681581b0e15553a89b1542828898f27243ebab45ff5e1acb9d4df1b051fbc62824dbc6f6c93261a78b9a759", 16), + new BigInteger("012ddcc86ef655998c39ddae11718669e5e46cf1495b07e13b1014cd69b3af68304ad2a6b64321e78bf3bbca9bb494e91d451717e2d97564c6549465d0205cf421", 16), + new BigInteger("010600c4c21847459fe576703e2ebecae8a5094ee63f536bf4ac68d3c13e5e4f12ac5cc10ab6a2d05a199214d1824747d551909636b774c22cac0b837599abcc75", 16)); + + // PSS Example 4.1 + + private byte[] msg4a = Hex.decode("9fb03b827c8217d9"); + + private byte[] slt4a = Hex.decode("ed7c98c95f30974fbe4fbddcf0f28d6021c0e91d"); + + private byte[] sig4a = Hex.decode("0323d5b7bf20ba4539289ae452ae4297080feff4518423ff4811a817837e7d82f1836cdfab54514ff0887bddeebf40bf99b047abc3ecfa6a37a3ef00f4a0c4a88aae0904b745c846c4107e8797723e8ac810d9e3d95dfa30ff4966f4d75d13768d20857f2b1406f264cfe75e27d7652f4b5ed3575f28a702f8c4ed9cf9b2d44948"); + + // PSS Example 4.2 + + private byte[] msg4b = Hex.decode("0ca2ad77797ece86de5bf768750ddb5ed6a3116ad99bbd17edf7f782f0db1cd05b0f677468c5ea420dc116b10e80d110de2b0461ea14a38be68620392e7e893cb4ea9393fb886c20ff790642305bf302003892e54df9f667509dc53920df583f50a3dd61abb6fab75d600377e383e6aca6710eeea27156e06752c94ce25ae99fcbf8592dbe2d7e27453cb44de07100ebb1a2a19811a478adbeab270f94e8fe369d90b3ca612f9f"); + + private byte[] slt4b = Hex.decode("22d71d54363a4217aa55113f059b3384e3e57e44"); + + private byte[] sig4b = Hex.decode("049d0185845a264d28feb1e69edaec090609e8e46d93abb38371ce51f4aa65a599bdaaa81d24fba66a08a116cb644f3f1e653d95c89db8bbd5daac2709c8984000178410a7c6aa8667ddc38c741f710ec8665aa9052be929d4e3b16782c1662114c5414bb0353455c392fc28f3db59054b5f365c49e1d156f876ee10cb4fd70598"); + + + // + // Example 8: A 1031-bit RSA key pair + // + + private RSAKeyParameters pub8 = new RSAKeyParameters(false, + new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv8 = new RSAPrivateCrtKeyParameters( + new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16), + new BigInteger("010001", 16), + new BigInteger("6c66ffe98980c38fcdeab5159898836165f4b4b817c4f6a8d486ee4ea9130fe9b9092bd136d184f95f504a607eac565846d2fdd6597a8967c7396ef95a6eeebb4578a643966dca4d8ee3de842de63279c618159c1ab54a89437b6a6120e4930afb52a4ba6ced8a4947ac64b30a3497cbe701c2d6266d517219ad0ec6d347dbe9", 16), + new BigInteger("08dad7f11363faa623d5d6d5e8a319328d82190d7127d2846c439b0ab72619b0a43a95320e4ec34fc3a9cea876422305bd76c5ba7be9e2f410c8060645a1d29edb", 16), + new BigInteger("0847e732376fc7900f898ea82eb2b0fc418565fdae62f7d9ec4ce2217b97990dd272db157f99f63c0dcbb9fbacdbd4c4dadb6df67756358ca4174825b48f49706d", 16), + new BigInteger("05c2a83c124b3621a2aa57ea2c3efe035eff4560f33ddebb7adab81fce69a0c8c2edc16520dda83d59a23be867963ac65f2cc710bbcfb96ee103deb771d105fd85", 16), + new BigInteger("04cae8aa0d9faa165c87b682ec140b8ed3b50b24594b7a3b2c220b3669bb819f984f55310a1ae7823651d4a02e99447972595139363434e5e30a7e7d241551e1b9", 16), + new BigInteger("07d3e47bf686600b11ac283ce88dbb3f6051e8efd04680e44c171ef531b80b2b7c39fc766320e2cf15d8d99820e96ff30dc69691839c4b40d7b06e45307dc91f3f", 16)); + + // PSS Example 8.1 + + private byte[] msg8a = Hex.decode("81332f4be62948415ea1d899792eeacf6c6e1db1da8be13b5cea41db2fed467092e1ff398914c714259775f595f8547f735692a575e6923af78f22c6997ddb90fb6f72d7bb0dd5744a31decd3dc3685849836ed34aec596304ad11843c4f88489f209735f5fb7fdaf7cec8addc5818168f880acbf490d51005b7a8e84e43e54287977571dd99eea4b161eb2df1f5108f12a4142a83322edb05a75487a3435c9a78ce53ed93bc550857d7a9fb"); + + private byte[] slt8a = Hex.decode("1d65491d79c864b373009be6f6f2467bac4c78fa"); + + private byte[] sig8a = Hex.decode("0262ac254bfa77f3c1aca22c5179f8f040422b3c5bafd40a8f21cf0fa5a667ccd5993d42dbafb409c520e25fce2b1ee1e716577f1efa17f3da28052f40f0419b23106d7845aaf01125b698e7a4dfe92d3967bb00c4d0d35ba3552ab9a8b3eef07c7fecdbc5424ac4db1e20cb37d0b2744769940ea907e17fbbca673b20522380c5"); + + // PSS Example 8.2 + + private byte[] msg8b = Hex.decode("e2f96eaf0e05e7ba326ecca0ba7fd2f7c02356f3cede9d0faabf4fcc8e60a973e5595fd9ea08"); + + private byte[] slt8b = Hex.decode("435c098aa9909eb2377f1248b091b68987ff1838"); + + private byte[] sig8b = Hex.decode("2707b9ad5115c58c94e932e8ec0a280f56339e44a1b58d4ddcff2f312e5f34dcfe39e89c6a94dcee86dbbdae5b79ba4e0819a9e7bfd9d982e7ee6c86ee68396e8b3a14c9c8f34b178eb741f9d3f121109bf5c8172fada2e768f9ea1433032c004a8aa07eb990000a48dc94c8bac8aabe2b09b1aa46c0a2aa0e12f63fbba775ba7e"); + + // + // Example 9: A 1536-bit RSA key pair + // + + private RSAKeyParameters pub9 = new RSAKeyParameters(false, + new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv9 = new RSAPrivateCrtKeyParameters( + new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16), + new BigInteger("010001", 16), + new BigInteger("6a7fd84fb85fad073b34406db74f8d61a6abc12196a961dd79565e9da6e5187bce2d980250f7359575359270d91590bb0e427c71460b55d51410b191bcf309fea131a92c8e702738fa719f1e0041f52e40e91f229f4d96a1e6f172e15596b4510a6daec26105f2bebc53316b87bdf21311666070e8dfee69d52c71a976caae79c72b68d28580dc686d9f5129d225f82b3d615513a882b3db91416b48ce08888213e37eeb9af800d81cab328ce420689903c00c7b5fd31b75503a6d419684d629", 16), + new BigInteger("f8eb97e98df12664eefdb761596a69ddcd0e76daece6ed4bf5a1b50ac086f7928a4d2f8726a77e515b74da41988f220b1cc87aa1fc810ce99a82f2d1ce821edced794c6941f42c7a1a0b8c4d28c75ec60b652279f6154a762aed165d47dee367", 16), + new BigInteger("ed4d71d0a6e24b93c2e5f6b4bbe05f5fb0afa042d204fe3378d365c2f288b6a8dad7efe45d153eef40cacc7b81ff934002d108994b94a5e4728cd9c963375ae49965bda55cbf0efed8d6553b4027f2d86208a6e6b489c176128092d629e49d3d", 16), + new BigInteger("2bb68bddfb0c4f56c8558bffaf892d8043037841e7fa81cfa61a38c5e39b901c8ee71122a5da2227bd6cdeeb481452c12ad3d61d5e4f776a0ab556591befe3e59e5a7fddb8345e1f2f35b9f4cee57c32414c086aec993e9353e480d9eec6289f", 16), + new BigInteger("4ff897709fad079746494578e70fd8546130eeab5627c49b080f05ee4ad9f3e4b7cba9d6a5dff113a41c3409336833f190816d8a6bc42e9bec56b7567d0f3c9c696db619b245d901dd856db7c8092e77e9a1cccd56ee4dba42c5fdb61aec2669", 16), + new BigInteger("77b9d1137b50404a982729316efafc7dfe66d34e5a182600d5f30a0a8512051c560d081d4d0a1835ec3d25a60f4e4d6aa948b2bf3dbb5b124cbbc3489255a3a948372f6978496745f943e1db4f18382ceaa505dfc65757bb3f857a58dce52156", 16)); + + // PSS Example 9.1 + + private byte[] msg9a = Hex.decode("a88e265855e9d7ca36c68795f0b31b591cd6587c71d060a0b3f7f3eaef43795922028bc2b6ad467cfc2d7f659c5385aa70ba3672cdde4cfe4970cc7904601b278872bf51321c4a972f3c95570f3445d4f57980e0f20df54846e6a52c668f1288c03f95006ea32f562d40d52af9feb32f0fa06db65b588a237b34e592d55cf979f903a642ef64d2ed542aa8c77dc1dd762f45a59303ed75e541ca271e2b60ca709e44fa0661131e8d5d4163fd8d398566ce26de8730e72f9cca737641c244159420637028df0a18079d6208ea8b4711a2c750f5"); + + private byte[] slt9a = Hex.decode("c0a425313df8d7564bd2434d311523d5257eed80"); + + private byte[] sig9a = Hex.decode("586107226c3ce013a7c8f04d1a6a2959bb4b8e205ba43a27b50f124111bc35ef589b039f5932187cb696d7d9a32c0c38300a5cdda4834b62d2eb240af33f79d13dfbf095bf599e0d9686948c1964747b67e89c9aba5cd85016236f566cc5802cb13ead51bc7ca6bef3b94dcbdbb1d570469771df0e00b1a8a06777472d2316279edae86474668d4e1efff95f1de61c6020da32ae92bbf16520fef3cf4d88f61121f24bbd9fe91b59caf1235b2a93ff81fc403addf4ebdea84934a9cdaf8e1a9e"); + + // PSS Example 9.2 + + private byte[] msg9b = Hex.decode("c8c9c6af04acda414d227ef23e0820c3732c500dc87275e95b0d095413993c2658bc1d988581ba879c2d201f14cb88ced153a01969a7bf0a7be79c84c1486bc12b3fa6c59871b6827c8ce253ca5fefa8a8c690bf326e8e37cdb96d90a82ebab69f86350e1822e8bd536a2e"); + + private byte[] slt9b = Hex.decode("b307c43b4850a8dac2f15f32e37839ef8c5c0e91"); + + private byte[] sig9b = Hex.decode("80b6d643255209f0a456763897ac9ed259d459b49c2887e5882ecb4434cfd66dd7e1699375381e51cd7f554f2c271704b399d42b4be2540a0eca61951f55267f7c2878c122842dadb28b01bd5f8c025f7e228418a673c03d6bc0c736d0a29546bd67f786d9d692ccea778d71d98c2063b7a71092187a4d35af108111d83e83eae46c46aa34277e06044589903788f1d5e7cee25fb485e92949118814d6f2c3ee361489016f327fb5bc517eb50470bffa1afa5f4ce9aa0ce5b8ee19bf5501b958"); + + + public String getName() + { + return "PSSBlindTest"; + } + + private void testSig( + int id, + RSAKeyParameters pub, + RSAKeyParameters prv, + byte[] slt, + byte[] msg, + byte[] sig) + throws Exception + { + RSABlindingFactorGenerator blindFactorGen = new RSABlindingFactorGenerator(); + RSABlindingEngine blindingEngine = new RSABlindingEngine(); + PSSSigner blindSigner = new PSSSigner(blindingEngine, new SHA1Digest(), 20); + PSSSigner signer = new PSSSigner(new RSAEngine(), new SHA1Digest(), 20); + + blindFactorGen.init(pub); + + BigInteger blindFactor = blindFactorGen.generateBlindingFactor(); + RSABlindingParameters params = new RSABlindingParameters(pub, blindFactor); + + // generate a blind signature + blindSigner.init(true, new ParametersWithRandom(params, new FixedRandom(slt))); + + blindSigner.update(msg, 0, msg.length); + + byte[] blindedData = blindSigner.generateSignature(); + + RSAEngine signerEngine = new RSAEngine(); + + signerEngine.init(true, prv); + + byte[] blindedSig = signerEngine.processBlock(blindedData, 0, blindedData.length); + + // unblind the signature + blindingEngine.init(false, params); + + byte[] s = blindingEngine.processBlock(blindedSig, 0, blindedSig.length); + + //signature verification + if (!areEqual(s, sig)) + { + fail("test " + id + " failed generation"); + } + + //verify signature with PSSSigner + signer.init(false, pub); + signer.update(msg, 0, msg.length); + + if (!signer.verifySignature(s)) + { + fail("test " + id + " failed PSSSigner verification"); + } + } + + private boolean isProcessingOkay( + RSAKeyParameters pub, + RSAKeyParameters prv, + byte[] data, + SecureRandom random) + throws Exception + { + RSABlindingFactorGenerator blindFactorGen = new RSABlindingFactorGenerator(); + RSABlindingEngine blindingEngine = new RSABlindingEngine(); + PSSSigner blindSigner = new PSSSigner(blindingEngine, new SHA1Digest(), 20); + PSSSigner pssEng = new PSSSigner(new RSAEngine(), new SHA1Digest(), 20); + + random.nextBytes(data); + + blindFactorGen.init(pub); + + BigInteger blindFactor = blindFactorGen.generateBlindingFactor(); + RSABlindingParameters params = new RSABlindingParameters(pub, blindFactor); + + // generate a blind signature + blindSigner.init(true, new ParametersWithRandom(params, random)); + + blindSigner.update(data, 0, data.length); + + byte[] blindedData = blindSigner.generateSignature(); + + RSAEngine signerEngine = new RSAEngine(); + + signerEngine.init(true, prv); + + byte[] blindedSig = signerEngine.processBlock(blindedData, 0, blindedData.length); + + // unblind the signature + blindingEngine.init(false, params); + + byte[] s = blindingEngine.processBlock(blindedSig, 0, blindedSig.length); + + //verify signature with PSSSigner + pssEng.init(false, pub); + pssEng.update(data, 0, data.length); + + return pssEng.verifySignature(s); + } + + public void performTest() + throws Exception + { + testSig(1, pub1, prv1, slt1a, msg1a, sig1a); + testSig(2, pub1, prv1, slt1b, msg1b, sig1b); + testSig(3, pub2, prv2, slt2a, msg2a, sig2a); + testSig(4, pub2, prv2, slt2b, msg2b, sig2b); + testSig(5, pub4, prv4, slt4a, msg4a, sig4a); + testSig(6, pub4, prv4, slt4b, msg4b, sig4b); + testSig(7, pub8, prv8, slt8a, msg8a, sig8a); + testSig(8, pub8, prv8, slt8b, msg8b, sig8b); + testSig(9, pub9, prv9, slt9a, msg9a, sig9a); + testSig(10, pub9, prv9, slt9b, msg9b, sig9b); + + // + // loop test + // + int failed = 0; + byte[] data = new byte[DATA_LENGTH]; + + SecureRandom random = new SecureRandom(); + + + RSAKeyParameters[] kprv ={prv1, prv2, prv4, prv8, prv9}; + RSAKeyParameters[] kpub ={pub1, pub2, pub4, pub8, pub9}; + + int i = 0; + for (int j = 0; j < NUM_TESTS; j++, i++) + { + if (i == kprv.length) + { + i = 0; + } + + if (!isProcessingOkay(kpub[i], kprv[i], data, random)) + { + failed++; + } + } + + if (failed != 0) + { + fail("loop test failed - failures: " + failed); + } + + // + // key generation test + // + RSAKeyPairGenerator pGen = new RSAKeyPairGenerator(); + RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters( + BigInteger.valueOf(0x11), new SecureRandom(), 1024, 25); + + pGen.init(genParam); + failed = 0; + + for (int k = 0; k < NUM_TESTS_WITH_KEY_GENERATION; k++) + { + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + for (int j = 0; j < NUM_TESTS; j++) + { + if (!isProcessingOkay((RSAKeyParameters)pair.getPublic(), (RSAKeyParameters)pair.getPrivate(), data, random)) + { + failed++; + } + } + + } + + if (failed != 0) + { + fail("loop test with key generation failed - failures: " + failed); + } + } + + public static void main( + String[] args) + { + runTest(new PSSBlindTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PSSTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PSSTest.java new file mode 100644 index 000000000..b69f391eb --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PSSTest.java @@ -0,0 +1,369 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.engines.RSAEngine; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.crypto.signers.PSSSigner; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/* + * RSA PSS test vectors for PKCS#1 V2.1 + */ +public class PSSTest + extends SimpleTest +{ + private final int DATA_LENGTH = 1000; + private final int NUM_TESTS = 500; + + private class FixedRandom + extends SecureRandom + { + byte[] vals; + + FixedRandom( + byte[] vals) + { + this.vals = vals; + } + + public void nextBytes( + byte[] bytes) + { + System.arraycopy(vals, 0, bytes, 0, vals.length); + } + } + + // + // Example 1: A 1024-bit RSA keypair + // + private RSAKeyParameters pub1 = new RSAKeyParameters(false, + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16)); + + private RSAKeyParameters prv1 = new RSAPrivateCrtKeyParameters( + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16), + new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16), + new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16), + new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16), + new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16), + new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16), + new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16)); + + // PSSExample1.1 + + private byte[] msg1a = Hex.decode("cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0"); + + private byte[] slt1a = Hex.decode("dee959c7e06411361420ff80185ed57f3e6776af"); + + private byte[] sig1a = Hex.decode("9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c"); + + // PSSExample1.2 + + private byte[] msg1b = Hex.decode("851384cdfe819c22ed6c4ccb30daeb5cf059bc8e1166b7e3530c4c233e2b5f8f71a1cca582d43ecc72b1bca16dfc7013226b9e"); + + private byte[] slt1b = Hex.decode("ef2869fa40c346cb183dab3d7bffc98fd56df42d"); + + private byte[] sig1b = Hex.decode("3ef7f46e831bf92b32274142a585ffcefbdca7b32ae90d10fb0f0c729984f04ef29a9df0780775ce43739b97838390db0a5505e63de927028d9d29b219ca2c4517832558a55d694a6d25b9dab66003c4cccd907802193be5170d26147d37b93590241be51c25055f47ef62752cfbe21418fafe98c22c4d4d47724fdb5669e843"); + + // + // Example 2: A 1025-bit RSA keypair + // + + private RSAKeyParameters pub2 = new RSAKeyParameters(false, + new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv2 = new RSAPrivateCrtKeyParameters( + new BigInteger("01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9", 16), + new BigInteger("010001", 16), + new BigInteger("027d147e4673057377fd1ea201565772176a7dc38358d376045685a2e787c23c15576bc16b9f444402d6bfc5d98a3e88ea13ef67c353eca0c0ddba9255bd7b8bb50a644afdfd1dd51695b252d22e7318d1b6687a1c10ff75545f3db0fe602d5f2b7f294e3601eab7b9d1cecd767f64692e3e536ca2846cb0c2dd486a39fa75b1", 16), + new BigInteger("016601e926a0f8c9e26ecab769ea65a5e7c52cc9e080ef519457c644da6891c5a104d3ea7955929a22e7c68a7af9fcad777c3ccc2b9e3d3650bce404399b7e59d1", 16), + new BigInteger("014eafa1d4d0184da7e31f877d1281ddda625664869e8379e67ad3b75eae74a580e9827abd6eb7a002cb5411f5266797768fb8e95ae40e3e8a01f35ff89e56c079", 16), + new BigInteger("e247cce504939b8f0a36090de200938755e2444b29539a7da7a902f6056835c0db7b52559497cfe2c61a8086d0213c472c78851800b171f6401de2e9c2756f31", 16), + new BigInteger("b12fba757855e586e46f64c38a70c68b3f548d93d787b399999d4c8f0bbd2581c21e19ed0018a6d5d3df86424b3abcad40199d31495b61309f27c1bf55d487c1", 16), + new BigInteger("564b1e1fa003bda91e89090425aac05b91da9ee25061e7628d5f51304a84992fdc33762bd378a59f030a334d532bd0dae8f298ea9ed844636ad5fb8cbdc03cad", 16)); + + // PSS Example 2.1 + + private byte[] msg2a = Hex.decode("daba032066263faedb659848115278a52c44faa3a76f37515ed336321072c40a9d9b53bc05014078adf520875146aae70ff060226dcb7b1f1fc27e9360"); + private byte[] slt2a = Hex.decode("57bf160bcb02bb1dc7280cf0458530b7d2832ff7"); + private byte[] sig2a = Hex.decode("014c5ba5338328ccc6e7a90bf1c0ab3fd606ff4796d3c12e4b639ed9136a5fec6c16d8884bdd99cfdc521456b0742b736868cf90de099adb8d5ffd1deff39ba4007ab746cefdb22d7df0e225f54627dc65466131721b90af445363a8358b9f607642f78fab0ab0f43b7168d64bae70d8827848d8ef1e421c5754ddf42c2589b5b3"); + + // PSS Example 2.2 + + private byte[] msg2b = Hex.decode("e4f8601a8a6da1be34447c0959c058570c3668cfd51dd5f9ccd6ad4411fe8213486d78a6c49f93efc2ca2288cebc2b9b60bd04b1e220d86e3d4848d709d032d1e8c6a070c6af9a499fcf95354b14ba6127c739de1bb0fd16431e46938aec0cf8ad9eb72e832a7035de9b7807bdc0ed8b68eb0f5ac2216be40ce920c0db0eddd3860ed788efaccaca502d8f2bd6d1a7c1f41ff46f1681c8f1f818e9c4f6d91a0c7803ccc63d76a6544d843e084e363b8acc55aa531733edb5dee5b5196e9f03e8b731b3776428d9e457fe3fbcb3db7274442d785890e9cb0854b6444dace791d7273de1889719338a77fe"); + private byte[] slt2b = Hex.decode("7f6dd359e604e60870e898e47b19bf2e5a7b2a90"); + private byte[] sig2b = Hex.decode("010991656cca182b7f29d2dbc007e7ae0fec158eb6759cb9c45c5ff87c7635dd46d150882f4de1e9ae65e7f7d9018f6836954a47c0a81a8a6b6f83f2944d6081b1aa7c759b254b2c34b691da67cc0226e20b2f18b42212761dcd4b908a62b371b5918c5742af4b537e296917674fb914194761621cc19a41f6fb953fbcbb649dea"); + + // + // Example 4: A 1027-bit RSA key pair + // + + private RSAKeyParameters pub4 = new RSAKeyParameters(false, + new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv4 = new RSAPrivateCrtKeyParameters( + new BigInteger("054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705", 16), + new BigInteger("010001", 16), + new BigInteger("fa041f8cd9697ceed38ec8caa275523b4dd72b09a301d3541d72f5d31c05cbce2d6983b36183af10690bd46c46131e35789431a556771dd0049b57461bf060c1f68472e8a67c25f357e5b6b4738fa541a730346b4a07649a2dfa806a69c975b6aba64678acc7f5913e89c622f2d8abb1e3e32554e39df94ba60c002e387d9011", 16), + new BigInteger("029232336d2838945dba9dd7723f4e624a05f7375b927a87abe6a893a1658fd49f47f6c7b0fa596c65fa68a23f0ab432962d18d4343bd6fd671a5ea8d148413995", 16), + new BigInteger("020ef5efe7c5394aed2272f7e81a74f4c02d145894cb1b3cab23a9a0710a2afc7e3329acbb743d01f680c4d02afb4c8fde7e20930811bb2b995788b5e872c20bb1", 16), + new BigInteger("026e7e28010ecf2412d9523ad704647fb4fe9b66b1a681581b0e15553a89b1542828898f27243ebab45ff5e1acb9d4df1b051fbc62824dbc6f6c93261a78b9a759", 16), + new BigInteger("012ddcc86ef655998c39ddae11718669e5e46cf1495b07e13b1014cd69b3af68304ad2a6b64321e78bf3bbca9bb494e91d451717e2d97564c6549465d0205cf421", 16), + new BigInteger("010600c4c21847459fe576703e2ebecae8a5094ee63f536bf4ac68d3c13e5e4f12ac5cc10ab6a2d05a199214d1824747d551909636b774c22cac0b837599abcc75", 16)); + + // PSS Example 4.1 + + private byte[] msg4a = Hex.decode("9fb03b827c8217d9"); + + private byte[] slt4a = Hex.decode("ed7c98c95f30974fbe4fbddcf0f28d6021c0e91d"); + + private byte[] sig4a = Hex.decode("0323d5b7bf20ba4539289ae452ae4297080feff4518423ff4811a817837e7d82f1836cdfab54514ff0887bddeebf40bf99b047abc3ecfa6a37a3ef00f4a0c4a88aae0904b745c846c4107e8797723e8ac810d9e3d95dfa30ff4966f4d75d13768d20857f2b1406f264cfe75e27d7652f4b5ed3575f28a702f8c4ed9cf9b2d44948"); + + // PSS Example 4.2 + + private byte[] msg4b = Hex.decode("0ca2ad77797ece86de5bf768750ddb5ed6a3116ad99bbd17edf7f782f0db1cd05b0f677468c5ea420dc116b10e80d110de2b0461ea14a38be68620392e7e893cb4ea9393fb886c20ff790642305bf302003892e54df9f667509dc53920df583f50a3dd61abb6fab75d600377e383e6aca6710eeea27156e06752c94ce25ae99fcbf8592dbe2d7e27453cb44de07100ebb1a2a19811a478adbeab270f94e8fe369d90b3ca612f9f"); + + private byte[] slt4b = Hex.decode("22d71d54363a4217aa55113f059b3384e3e57e44"); + + private byte[] sig4b = Hex.decode("049d0185845a264d28feb1e69edaec090609e8e46d93abb38371ce51f4aa65a599bdaaa81d24fba66a08a116cb644f3f1e653d95c89db8bbd5daac2709c8984000178410a7c6aa8667ddc38c741f710ec8665aa9052be929d4e3b16782c1662114c5414bb0353455c392fc28f3db59054b5f365c49e1d156f876ee10cb4fd70598"); + + + // + // Example 8: A 1031-bit RSA key pair + // + + private RSAKeyParameters pub8 = new RSAKeyParameters(false, + new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv8 = new RSAPrivateCrtKeyParameters( + new BigInteger("495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f", 16), + new BigInteger("010001", 16), + new BigInteger("6c66ffe98980c38fcdeab5159898836165f4b4b817c4f6a8d486ee4ea9130fe9b9092bd136d184f95f504a607eac565846d2fdd6597a8967c7396ef95a6eeebb4578a643966dca4d8ee3de842de63279c618159c1ab54a89437b6a6120e4930afb52a4ba6ced8a4947ac64b30a3497cbe701c2d6266d517219ad0ec6d347dbe9", 16), + new BigInteger("08dad7f11363faa623d5d6d5e8a319328d82190d7127d2846c439b0ab72619b0a43a95320e4ec34fc3a9cea876422305bd76c5ba7be9e2f410c8060645a1d29edb", 16), + new BigInteger("0847e732376fc7900f898ea82eb2b0fc418565fdae62f7d9ec4ce2217b97990dd272db157f99f63c0dcbb9fbacdbd4c4dadb6df67756358ca4174825b48f49706d", 16), + new BigInteger("05c2a83c124b3621a2aa57ea2c3efe035eff4560f33ddebb7adab81fce69a0c8c2edc16520dda83d59a23be867963ac65f2cc710bbcfb96ee103deb771d105fd85", 16), + new BigInteger("04cae8aa0d9faa165c87b682ec140b8ed3b50b24594b7a3b2c220b3669bb819f984f55310a1ae7823651d4a02e99447972595139363434e5e30a7e7d241551e1b9", 16), + new BigInteger("07d3e47bf686600b11ac283ce88dbb3f6051e8efd04680e44c171ef531b80b2b7c39fc766320e2cf15d8d99820e96ff30dc69691839c4b40d7b06e45307dc91f3f", 16)); + + // PSS Example 8.1 + + private byte[] msg8a = Hex.decode("81332f4be62948415ea1d899792eeacf6c6e1db1da8be13b5cea41db2fed467092e1ff398914c714259775f595f8547f735692a575e6923af78f22c6997ddb90fb6f72d7bb0dd5744a31decd3dc3685849836ed34aec596304ad11843c4f88489f209735f5fb7fdaf7cec8addc5818168f880acbf490d51005b7a8e84e43e54287977571dd99eea4b161eb2df1f5108f12a4142a83322edb05a75487a3435c9a78ce53ed93bc550857d7a9fb"); + + private byte[] slt8a = Hex.decode("1d65491d79c864b373009be6f6f2467bac4c78fa"); + + private byte[] sig8a = Hex.decode("0262ac254bfa77f3c1aca22c5179f8f040422b3c5bafd40a8f21cf0fa5a667ccd5993d42dbafb409c520e25fce2b1ee1e716577f1efa17f3da28052f40f0419b23106d7845aaf01125b698e7a4dfe92d3967bb00c4d0d35ba3552ab9a8b3eef07c7fecdbc5424ac4db1e20cb37d0b2744769940ea907e17fbbca673b20522380c5"); + + // PSS Example 8.2 + + private byte[] msg8b = Hex.decode("e2f96eaf0e05e7ba326ecca0ba7fd2f7c02356f3cede9d0faabf4fcc8e60a973e5595fd9ea08"); + + private byte[] slt8b = Hex.decode("435c098aa9909eb2377f1248b091b68987ff1838"); + + private byte[] sig8b = Hex.decode("2707b9ad5115c58c94e932e8ec0a280f56339e44a1b58d4ddcff2f312e5f34dcfe39e89c6a94dcee86dbbdae5b79ba4e0819a9e7bfd9d982e7ee6c86ee68396e8b3a14c9c8f34b178eb741f9d3f121109bf5c8172fada2e768f9ea1433032c004a8aa07eb990000a48dc94c8bac8aabe2b09b1aa46c0a2aa0e12f63fbba775ba7e"); + + // + // Example 9: A 1536-bit RSA key pair + // + + private RSAKeyParameters pub9 = new RSAKeyParameters(false, + new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16), + new BigInteger("010001", 16)); + + private RSAKeyParameters prv9 = new RSAPrivateCrtKeyParameters( + new BigInteger("e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b", 16), + new BigInteger("010001", 16), + new BigInteger("6a7fd84fb85fad073b34406db74f8d61a6abc12196a961dd79565e9da6e5187bce2d980250f7359575359270d91590bb0e427c71460b55d51410b191bcf309fea131a92c8e702738fa719f1e0041f52e40e91f229f4d96a1e6f172e15596b4510a6daec26105f2bebc53316b87bdf21311666070e8dfee69d52c71a976caae79c72b68d28580dc686d9f5129d225f82b3d615513a882b3db91416b48ce08888213e37eeb9af800d81cab328ce420689903c00c7b5fd31b75503a6d419684d629", 16), + new BigInteger("f8eb97e98df12664eefdb761596a69ddcd0e76daece6ed4bf5a1b50ac086f7928a4d2f8726a77e515b74da41988f220b1cc87aa1fc810ce99a82f2d1ce821edced794c6941f42c7a1a0b8c4d28c75ec60b652279f6154a762aed165d47dee367", 16), + new BigInteger("ed4d71d0a6e24b93c2e5f6b4bbe05f5fb0afa042d204fe3378d365c2f288b6a8dad7efe45d153eef40cacc7b81ff934002d108994b94a5e4728cd9c963375ae49965bda55cbf0efed8d6553b4027f2d86208a6e6b489c176128092d629e49d3d", 16), + new BigInteger("2bb68bddfb0c4f56c8558bffaf892d8043037841e7fa81cfa61a38c5e39b901c8ee71122a5da2227bd6cdeeb481452c12ad3d61d5e4f776a0ab556591befe3e59e5a7fddb8345e1f2f35b9f4cee57c32414c086aec993e9353e480d9eec6289f", 16), + new BigInteger("4ff897709fad079746494578e70fd8546130eeab5627c49b080f05ee4ad9f3e4b7cba9d6a5dff113a41c3409336833f190816d8a6bc42e9bec56b7567d0f3c9c696db619b245d901dd856db7c8092e77e9a1cccd56ee4dba42c5fdb61aec2669", 16), + new BigInteger("77b9d1137b50404a982729316efafc7dfe66d34e5a182600d5f30a0a8512051c560d081d4d0a1835ec3d25a60f4e4d6aa948b2bf3dbb5b124cbbc3489255a3a948372f6978496745f943e1db4f18382ceaa505dfc65757bb3f857a58dce52156", 16)); + + // PSS Example 9.1 + + private byte[] msg9a = Hex.decode("a88e265855e9d7ca36c68795f0b31b591cd6587c71d060a0b3f7f3eaef43795922028bc2b6ad467cfc2d7f659c5385aa70ba3672cdde4cfe4970cc7904601b278872bf51321c4a972f3c95570f3445d4f57980e0f20df54846e6a52c668f1288c03f95006ea32f562d40d52af9feb32f0fa06db65b588a237b34e592d55cf979f903a642ef64d2ed542aa8c77dc1dd762f45a59303ed75e541ca271e2b60ca709e44fa0661131e8d5d4163fd8d398566ce26de8730e72f9cca737641c244159420637028df0a18079d6208ea8b4711a2c750f5"); + + private byte[] slt9a = Hex.decode("c0a425313df8d7564bd2434d311523d5257eed80"); + + private byte[] sig9a = Hex.decode("586107226c3ce013a7c8f04d1a6a2959bb4b8e205ba43a27b50f124111bc35ef589b039f5932187cb696d7d9a32c0c38300a5cdda4834b62d2eb240af33f79d13dfbf095bf599e0d9686948c1964747b67e89c9aba5cd85016236f566cc5802cb13ead51bc7ca6bef3b94dcbdbb1d570469771df0e00b1a8a06777472d2316279edae86474668d4e1efff95f1de61c6020da32ae92bbf16520fef3cf4d88f61121f24bbd9fe91b59caf1235b2a93ff81fc403addf4ebdea84934a9cdaf8e1a9e"); + + // PSS Example 9.2 + + private byte[] msg9b = Hex.decode("c8c9c6af04acda414d227ef23e0820c3732c500dc87275e95b0d095413993c2658bc1d988581ba879c2d201f14cb88ced153a01969a7bf0a7be79c84c1486bc12b3fa6c59871b6827c8ce253ca5fefa8a8c690bf326e8e37cdb96d90a82ebab69f86350e1822e8bd536a2e"); + + private byte[] slt9b = Hex.decode("b307c43b4850a8dac2f15f32e37839ef8c5c0e91"); + + private byte[] sig9b = Hex.decode("80b6d643255209f0a456763897ac9ed259d459b49c2887e5882ecb4434cfd66dd7e1699375381e51cd7f554f2c271704b399d42b4be2540a0eca61951f55267f7c2878c122842dadb28b01bd5f8c025f7e228418a673c03d6bc0c736d0a29546bd67f786d9d692ccea778d71d98c2063b7a71092187a4d35af108111d83e83eae46c46aa34277e06044589903788f1d5e7cee25fb485e92949118814d6f2c3ee361489016f327fb5bc517eb50470bffa1afa5f4ce9aa0ce5b8ee19bf5501b958"); + + + public String getName() + { + return "PSSTest"; + } + + private void testSig( + int id, + RSAKeyParameters pub, + RSAKeyParameters prv, + byte[] slt, + byte[] msg, + byte[] sig) + throws Exception + { + PSSSigner eng = new PSSSigner(new RSAEngine(), new SHA1Digest(), 20); + + eng.init(true, new ParametersWithRandom(prv, new FixedRandom(slt))); + + eng.update(msg, 0, msg.length); + + byte[] s = eng.generateSignature(); + + if (!areEqual(s, sig)) + { + fail("test " + id + " failed generation"); + } + + eng.init(false, pub); + + eng.update(msg, 0, msg.length); + + if (!eng.verifySignature(s)) + { + fail("test " + id + " failed verification"); + } + } + + public void performTest() + throws Exception + { + testSig(1, pub1, prv1, slt1a, msg1a, sig1a); + testSig(2, pub1, prv1, slt1b, msg1b, sig1b); + testSig(3, pub2, prv2, slt2a, msg2a, sig2a); + testSig(4, pub2, prv2, slt2b, msg2b, sig2b); + testSig(5, pub4, prv4, slt4a, msg4a, sig4a); + testSig(6, pub4, prv4, slt4b, msg4b, sig4b); + testSig(7, pub8, prv8, slt8a, msg8a, sig8a); + testSig(8, pub8, prv8, slt8b, msg8b, sig8b); + testSig(9, pub9, prv9, slt9a, msg9a, sig9a); + testSig(10, pub9, prv9, slt9b, msg9b, sig9b); + + // + // loop test - sha-1 only + // + PSSSigner eng = new PSSSigner(new RSAEngine(), new SHA1Digest(), 20); + int failed = 0; + byte[] data = new byte[DATA_LENGTH]; + + SecureRandom random = new SecureRandom(); + random.nextBytes(data); + + for (int j = 0; j < NUM_TESTS; j++) + { + eng.init(true, new ParametersWithRandom(prv8, random)); + + eng.update(data, 0, data.length); + + byte[] s = eng.generateSignature(); + + eng.init(false, pub8); + + eng.update(data, 0, data.length); + + if (!eng.verifySignature(s)) + { + failed++; + } + } + + if (failed != 0) + { + fail("loop test failed - failures: " + failed); + } + + // + // loop test - sha-256 and sha-1 + // + eng = new PSSSigner(new RSAEngine(), new SHA256Digest(), new SHA1Digest(), 20); + failed = 0; + data = new byte[DATA_LENGTH]; + + random.nextBytes(data); + + for (int j = 0; j < NUM_TESTS; j++) + { + eng.init(true, new ParametersWithRandom(prv8, random)); + + eng.update(data, 0, data.length); + + byte[] s = eng.generateSignature(); + + eng.init(false, pub8); + + eng.update(data, 0, data.length); + + if (!eng.verifySignature(s)) + { + failed++; + } + } + + if (failed != 0) + { + fail("loop test failed - failures: " + failed); + } + + fixedSaltTest(); + } + + private void fixedSaltTest() + throws Exception + { + byte[] data = Hex.decode("010203040506070809101112131415"); + + PSSSigner eng = new PSSSigner(new RSAEngine(), new SHA256Digest(), new SHA1Digest(), Hex.decode("deadbeef")); + + eng.init(true, prv8); + + eng.update(data, 0, data.length); + + byte[] s = eng.generateSignature(); + + eng.init(false, pub8); + + eng.update(data, 0, data.length); + + if (!eng.verifySignature(s)) + { + fail("fixed salt failed"); + } + + // test failure + eng = new PSSSigner(new RSAEngine(), new SHA256Digest(), new SHA1Digest(), Hex.decode("beefbeef")); + + eng.init(false, pub8); + + eng.update(data, 0, data.length); + + if (eng.verifySignature(s)) + { + fail("fixed salt failure verfied"); + } + } + + public static void main( + String[] args) + { + runTest(new PSSTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PaddingTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PaddingTest.java new file mode 100644 index 000000000..ed25c98c2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/PaddingTest.java @@ -0,0 +1,200 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.paddings.BlockCipherPadding; +import com.fr.third.org.bouncycastle.crypto.paddings.ISO10126d2Padding; +import com.fr.third.org.bouncycastle.crypto.paddings.ISO7816d4Padding; +import com.fr.third.org.bouncycastle.crypto.paddings.PKCS7Padding; +import com.fr.third.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.paddings.TBCPadding; +import com.fr.third.org.bouncycastle.crypto.paddings.X923Padding; +import com.fr.third.org.bouncycastle.crypto.paddings.ZeroBytePadding; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * General Padding tests. + */ +public class PaddingTest + extends SimpleTest +{ + public PaddingTest() + { + } + + private void blockCheck( + PaddedBufferedBlockCipher cipher, + BlockCipherPadding padding, + KeyParameter key, + byte[] data) + { + byte[] out = new byte[data.length + 8]; + byte[] dec = new byte[data.length]; + + try + { + cipher.init(true, key); + + int len = cipher.processBytes(data, 0, data.length, out, 0); + + len += cipher.doFinal(out, len); + + cipher.init(false, key); + + int decLen = cipher.processBytes(out, 0, len, dec, 0); + + decLen += cipher.doFinal(dec, decLen); + + if (!areEqual(data, dec)) + { + fail("failed to decrypt - i = " + data.length + ", padding = " + padding.getPaddingName()); + } + } + catch (Exception e) + { + fail("Exception - " + e.toString(), e); + } + } + + public void testPadding( + BlockCipherPadding padding, + SecureRandom rand, + byte[] ffVector, + byte[] ZeroVector) + { + PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new DESEngine(), padding); + KeyParameter key = new KeyParameter(Hex.decode("0011223344556677")); + + // + // ff test + // + byte[] data = { (byte)0xff, (byte)0xff, (byte)0xff, (byte)0, (byte)0, (byte)0, (byte)0, (byte)0 }; + + if (ffVector != null) + { + padding.addPadding(data, 3); + + if (!areEqual(data, ffVector)) + { + fail("failed ff test for " + padding.getPaddingName()); + } + } + + // + // zero test + // + if (ZeroVector != null) + { + data = new byte[8]; + padding.addPadding(data, 4); + + if (!areEqual(data, ZeroVector)) + { + fail("failed zero test for " + padding.getPaddingName()); + } + } + + for (int i = 1; i != 200; i++) + { + data = new byte[i]; + + rand.nextBytes(data); + + blockCheck(cipher, padding, key, data); + } + } + + private void testOutputSizes() + { + PaddedBufferedBlockCipher bc = new PaddedBufferedBlockCipher(new DESEngine(), new PKCS7Padding()); + KeyParameter key = new KeyParameter(Hex.decode("0011223344556677")); + + for (int i = 0; i < bc.getBlockSize() * 2; i++) + { + bc.init(true, key); + if (bc.getUpdateOutputSize(i) < 0) + { + fail("Padded cipher encrypt negative update output size for input size " + i); + } + if (bc.getOutputSize(i) < 0) + { + fail("Padded cipher encrypt negative output size for input size " + i); + } + + bc.init(false, key); + if (bc.getUpdateOutputSize(i) < 0) + { + fail("Padded cipher decrypt negative update output size for input size " + i); + } + if (bc.getOutputSize(i) < 0) + { + fail("Padded cipher decrypt negative output size for input size " + i); + } + + } + } + + public void performTest() + { + SecureRandom rand = new SecureRandom(new byte[20]); + + rand.setSeed(System.currentTimeMillis()); + + testPadding(new PKCS7Padding(), rand, + Hex.decode("ffffff0505050505"), + Hex.decode("0000000004040404")); + + PKCS7Padding padder = new PKCS7Padding(); + try + { + padder.padCount(new byte[8]); + + fail("invalid padding not detected"); + } + catch (InvalidCipherTextException e) + { + if (!"pad block corrupted".equals(e.getMessage())) + { + fail("wrong exception for corrupt padding: " + e); + } + } + + testPadding(new ISO10126d2Padding(), rand, + null, + null); + + testPadding(new X923Padding(), rand, + null, + null); + + testPadding(new TBCPadding(), rand, + Hex.decode("ffffff0000000000"), + Hex.decode("00000000ffffffff")); + + testPadding(new ZeroBytePadding(), rand, + Hex.decode("ffffff0000000000"), + null); + + testPadding(new ISO7816d4Padding(), rand, + Hex.decode("ffffff8000000000"), + Hex.decode("0000000080000000")); + + testOutputSizes(); + + } + + public String getName() + { + return "PaddingTest"; + } + + public static void main( + String[] args) + { + runTest(new PaddingTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Poly1305Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Poly1305Test.java new file mode 100644 index 000000000..5e8d75558 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Poly1305Test.java @@ -0,0 +1,512 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.CipherKeyGenerator; +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.generators.Poly1305KeyGenerator; +import com.fr.third.org.bouncycastle.crypto.macs.Poly1305; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/* + */ +public class Poly1305Test + extends SimpleTest +{ + private static final int MAXLEN = 1000; + + private static class TestCase + { + private final byte[] key; + private final byte[] nonce; + private final byte[] message; + private final byte[] expectedMac; + + public TestCase(String key, String nonce, String message, String expectedMac) + { + this.key = Hex.decode(key); + // nacl test case keys are not pre-clamped + Poly1305KeyGenerator.clamp(this.key); + this.nonce = (nonce == null) ? null : Hex.decode(nonce); + this.message = Hex.decode(message); + this.expectedMac = Hex.decode(expectedMac); + } + } + + private static TestCase[] CASES = { + // Raw Poly1305 + // onetimeauth.c from nacl-20110221 + new TestCase("eea6a7251c1e72916d11c2cb214d3c25" + "2539121d8e234e652d651fa4c8cff880", null, + "8e993b9f48681273c29650ba32fc76ce48332ea7164d96a4476fb8c531a1186a" + + "c0dfc17c98dce87b4da7f011ec48c97271d2c20f9b928fe2270d6fb863d51738" + + "b48eeee314a7cc8ab932164548e526ae90224368517acfeabd6bb3732bc0e9da" + + "99832b61ca01b6de56244a9e88d5f9b37973f622a43d14a6599b1f654cb45a74e355a5", + "f3ffc7703f9400e52a7dfb4b3d3305d9"), + // Poly1305-AES + // Loop 1 of test-poly1305aes from poly1305aes-20050218 + new TestCase("0000000000000000000000000000000000000000000000000000000000000000", + "00000000000000000000000000000000", "", "66e94bd4ef8a2c3b884cfa59ca342b2e"), + new TestCase("f795bd0a50e29e0710d3130a20e98d0c" + "f795bd4a52e29ed713d313fa20e98dbc", + "917cf69ebd68b2ec9b9fe9a3eadda692", "66f7", "5ca585c75e8f8f025e710cabc9a1508b"), + new TestCase("3ef49901c8e11c000430d90ad45e7603" + "e69dae0aab9f91c03a325dcc9436fa90", + "166450152e2394835606a9d1dd2cdc8b", "66f75c0e0c7a406586", "2924f51b9c2eff5df09db61dd03a9ca1"), + new TestCase("da4afc035087d90e503f8f0ea08c3e0d" + "85a4ea91a7de0b0d96eed0d4bf6ecf1c", + "0b6ef7a0b8f8c738b0f8d5995415271f", + "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea", + "3c5a13adb18d31c64cc29972030c917d"), + new TestCase( + "ca3c6a0da0a864024ca3090628c28e0d" + "25eb69bac5cdf7d6bfcee4d9d5507b82", + "046772a4f0a8de92e4f0d628cdb04484", + "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de", + "fc5fb58dc65daf19b14d1d05da1064e8"), + // Specific test cases generated from test-poly1305aes from poly1305aes-20050218 that + // expose Java unsigned integer problems + new TestCase( + "01bcb20bfc8b6e03609ddd09f44b060f" + "95cc0e44d0b79a8856afcae1bec4fe3c", + null, + "66f75c0e0c7a40658629e3392f7f8e3349a02191ffd49f39879a8d9d1d0e23ea3caa4d240bd2ab8a8c4a6bb8d3288d9de4b793f05e97646dd4d98055de" + + "fc3e0677d956b4c62664bac15962ab15d93ccbbc03aafdbde779162ed93b55361f0f8acaa41d50ef5175927fe79ea316186516eef15001cd04d3524a55" + + "e4fa3c5ca479d3aaa8a897c21807f721b6270ffc68b6889d81a116799f6aaa35d8e04c7a7dd5e6da2519e8759f54e906696f5772fee093283bcef7b930" + + "aed50323bcbc8c820c67422c1e16bdc022a9c0277c9d95fef0ea4ee11e2b27276da811523c5acb80154989f8a67ee9e3fa30b73b0c1c34bf46e3464d97" + + "7cd7fcd0ac3b82721080bb0d9b982ee2c77feee983d7ba35da88ce86955002940652ab63bc56fb16f994da2b01d74356509d7d1b6d7956b0e5a557757b" + + "d1ced2eef8650bc5b6d426108c1518abcbd0befb6a0d5fd57a3e2dbf31458eab63df66613653d4beae73f5c40eb438fbcfdcf4a4ba46320184b9ca0da4" + + "dfae77de7ccc910356caea3243f33a3c81b064b3b7cedc7435c223f664227215715980e6e0bb570d459ba80d7512dbe458c8f0f3f52d659b6e8eef19ee" + + "71aea2ced85c7a42ffca6522a62db49a2a46eff72bd7f7e0883acd087183f0627f3537a4d558754ed63358e8182bee196735b361dc9bd64d5e34e1074a" + + "855655d2974cc6fa1653754cf40f561d8c7dc526aab2908ec2d2b977cde1a1fb1071e32f40e049ea20f30368ba1592b4fe57fb51595d23acbdace324cd" + + "d78060a17187c662368854e915402d9b52fb21e984663e41c26a109437e162cfaf071b53f77e50000a5388ff183b82ce7a1af476c416d7d204157b3633" + + "b2f4ec077b699b032816997e37bceded8d4a04976fd7d0c0b029f290794c3be504c5242287ea2f831f11ed5690d92775cd6e863d7731fd4da687ebfb13" + + "df4c41dc0fb8", "ae345d555eb04d6947bb95c0965237e2"), + new TestCase( + "cd07fd0ef8c0be0afcbdb30af4af0009" + "76fb3635a2dc92a1f768163ab12f2187", + null, + "f05204a74f0f88a7fa1a95b84ec3d8ffb36fcdc7723ea65dfe7cd464e86e0abf6b9d51db3220cfd8496ad6e6d36ebee8d990f9ce0d3bb7f72b7ab5b3ab0a73240d11efe772c857021ae859db4933cdde4387b471d2ce700fef4b81087f8f47c307881fd83017afcd15b8d21edf9b704677f46df97b07e5b83f87c8abd90af9b1d0f9e2710e8ebd0d4d1c6a055abea861f42368bed94d9373e909c1d3715b221c16bc524c55c31ec3eab204850bb2474a84f9917038eff9d921130951391b5c54f09b5e1de833ea2cd7d3b306740abb7096d1e173da83427da2adddd3631eda30b54dbf487f2b082e8646f07d6e0a87e97522ca38d4ace4954bf3db6dd3a93b06fa18eb56856627ed6cffcd7ae26374554ca18ab8905f26331d323fe10e6e70624c7bc07a70f06ecd804b48f8f7e75e910165e1beb554f1f0ec7949c9c8d429a206b4d5c0653102249b6098e6b45fac2a07ff0220b0b8ae8f4c6bcc0c813a7cd141fa8b398b42575fc395747c5a0257ac41d6c1f434cfbf5dfe8349f5347ef6b60e611f5d6c3cbc20ca2555274d1934325824cef4809da293ea13f181929e2af025bbd1c9abdc3af93afd4c50a2854ade3887f4d2c8c225168052c16e74d76d2dd3e9467a2c5b8e15c06ffbffa42b8536384139f07e195a8c9f70f514f31dca4eb2cf262c0dcbde53654b6250a29efe21d54e83c80e005a1cad36d5934ff01c32e4bc5fe06d03064ff4a268517df4a94c759289f323734318cfa5d859d4ce9c16e63d02dff0896976f521607638535d2ee8dd3312e1ddc80a55d34fe829ab954c1ebd54d929954770f1be9d32b4c05003c5c9e97943b6431e2afe820b1e967b19843e5985a131b1100517cdc363799104af91e2cf3f53cb8fd003653a6dd8a31a3f9d566a7124b0ffe9695bcb87c482eb60106f88198f766a40bc0f4873c23653c5f9e7a8e446f770beb8034cf01d21028ba15ccee21a8db918c4829d61c88bfa927bc5def831501796c5b401a60a6b1b433c9fb905c8cd40412fffee81ab", + "045be28cc52009f506bdbfabedacf0b4"), + // Test case from JIRA issue BJA-620 + new TestCase( + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff", + null, + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffffff" + "ffffffffffffffffffffffffffffff", + "c80cb43844f387946e5aa6085bdf67da") + + + }; + + public String getName() + { + return "Poly1305"; + } + + public void performTest() + throws Exception + { + testKeyGenerator(); + testInit(); + for (int i = 0; i < CASES.length; i++) + { + testCase(i); + } + testSequential(); + testReset(); + rfc7539Test(); + } + + private void testCase(int i) + { + byte[] out = new byte[16]; + TestCase tc = CASES[i]; + + final Mac mac; + if (tc.nonce == null) + { + // Raw Poly1305 test - don't do any transform on AES key part + mac = new Poly1305(); + mac.init(new KeyParameter(tc.key)); + } + else + { + mac = new Poly1305(new AESEngine()); + mac.init(new ParametersWithIV(new KeyParameter(tc.key), tc.nonce)); + } + mac.update(tc.message, 0, tc.message.length); + mac.doFinal(out, 0); + + if (!Arrays.areEqual(out, tc.expectedMac)) + { + fail("Mismatched output " + i, new String(Hex.encode(tc.expectedMac)), new String(Hex.encode(out))); + } + } + + private void testSequential() + { + // Sequential test, adapted from test-poly1305aes + int len; + byte[] kr = new byte[32]; + byte[] m = new byte[MAXLEN]; + byte[] n = new byte[16]; + byte[] out = new byte[16]; + + int c = 0; + final Mac mac = new Poly1305(new AESEngine()); + for (int loop = 0; loop < 13; loop++) + { + len = 0; + for (; ; ) + { + c++; + mac.init(new ParametersWithIV(new KeyParameter(kr), n)); + mac.update(m, 0, len); + mac.doFinal(out, 0); + + // if (c == 678) + // { + // TestCase tc = CASES[0]; + // + // if (!Arrays.areEqual(tc.key, kr)) + // { + // System.err.println("Key bad"); + // System.err.println(new String(Hex.encode(tc.key))); + // System.err.println(new String(Hex.encode(kr))); + // System.exit(1); + // } + // if (!Arrays.areEqual(tc.nonce, n)) + // { + // System.err.println("Nonce bad"); + // System.exit(1); + // } + // System.out.printf("[%d] m: %s\n", c, new String(Hex.encode(m, 0, len))); + // System.out.printf("[%d] K: %s\n", c, new String(Hex.encodje(kr))); + // System.out.printf("[%d] N: %s\n", c, new String(Hex.encode(n))); + // System.out.printf("[%d] M: ", c); + // } + // System.out.printf("%d/%s\n", c, new String(Hex.encode(out))); + + if (len >= MAXLEN) + { + break; + } + n[0] ^= loop; + for (int i = 0; i < 16; ++i) + { + n[i] ^= out[i]; + } + if (len % 2 != 0) + { + for (int i = 0; i < 16; ++i) + { + kr[i] ^= out[i]; + } + } + if (len % 3 != 0) + { + for (int i = 0; i < 16; ++i) + { + kr[i + 16] ^= out[i]; + } + } + Poly1305KeyGenerator.clamp(kr); + m[len++] ^= out[0]; + } + } + // Output after 13 loops as generated by poly1305 ref + if (c != 13013 || !Arrays.areEqual(out, Hex.decode("89824ddf0816481051f4a82731cd56d5"))) + { + fail("Sequential Poly1305 " + c, "89824ddf0816481051f4a82731cd56d5", new String(Hex.encode(out))); + } + } + + private void testReset() + { + CipherKeyGenerator gen = new Poly1305KeyGenerator(); + gen.init(new KeyGenerationParameters(new SecureRandom(), 256)); + byte[] k = gen.generateKey(); + + byte[] m = new byte[10000]; + byte[] check = new byte[16]; + byte[] out = new byte[16]; + + // Generate baseline + Mac poly = new Poly1305(new AESEngine()); + poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); + + poly.update(m, 0, m.length); + poly.doFinal(check, 0); + + // Check reset after doFinal + poly.update(m, 0, m.length); + poly.doFinal(out, 0); + + if (!Arrays.areEqual(check, out)) + { + fail("Mac not reset after doFinal"); + } + + // Check reset + poly.update((byte)1); + poly.update((byte)2); + poly.reset(); + poly.update(m, 0, m.length); + poly.doFinal(out, 0); + + if (!Arrays.areEqual(check, out)) + { + fail("Mac not reset after doFinal"); + } + + // Check init resets + poly.update((byte)1); + poly.update((byte)2); + poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); + poly.update(m, 0, m.length); + poly.doFinal(out, 0); + + if (!Arrays.areEqual(check, out)) + { + fail("Mac not reset after doFinal"); + } + } + + private void testInit() + { + CipherKeyGenerator gen = new Poly1305KeyGenerator(); + gen.init(new KeyGenerationParameters(new SecureRandom(), 256)); + byte[] k = gen.generateKey(); + + Mac poly = new Poly1305(new AESEngine()); + poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); + + try + { + poly.init(new ParametersWithIV(new KeyParameter(k), new byte[15])); + fail("16 byte nonce required"); + } + catch (IllegalArgumentException e) + { + // Expected + } + + try + { + byte[] k2 = new byte[k.length - 1]; + System.arraycopy(k, 0, k2, 0, k2.length); + poly.init(new ParametersWithIV(new KeyParameter(k2), new byte[16])); + fail("32 byte key required"); + } + catch (IllegalArgumentException e) + { + // Expected + } + /* + try + { + k[19] = (byte)0xFF; + poly.init(new ParametersWithIV(new KeyParameter(k), new byte[16])); + fail("Unclamped key should not be accepted."); + } catch (IllegalArgumentException e) + { + // Expected + } + */ + } + + private void testKeyGenerator() + { + CipherKeyGenerator gen = new Poly1305KeyGenerator(); + gen.init(new KeyGenerationParameters(new SecureRandom(), 256)); + byte[] k = gen.generateKey(); + + if (k.length != 32) + { + fail("Poly1305 key should be 256 bits."); + } + + try + { + Poly1305KeyGenerator.checkKey(k); + } + catch (IllegalArgumentException e) + { + fail("Poly1305 key should be clamped on generation."); + } + + byte[] k2 = new byte[k.length]; + System.arraycopy(k, 0, k2, 0, k2.length); + Poly1305KeyGenerator.clamp(k); + if (!Arrays.areEqual(k, k2)) + { + fail("Poly1305 key should be clamped on generation."); + } + /* + try + { + k2[19] = (byte)0xff; + Poly1305KeyGenerator.checkKey(k2); + fail("Unclamped key should fail check."); + } catch (IllegalArgumentException e) + { + // Expected + } + */ + } + + public void rfc7539Test() + { + // From RFC 7539 + byte[] keyMaterial = Hex.decode("85d6be7857556d337f4452fe42d506a80103808afb0db2fd4abff6af4149f51b"); + byte[] data = Hex.decode("43727970746f677261706869 63 20 46 6f 72 75 6d 20 52 65 73 65 61 72 63 68 20 47 72 6f7570"); + byte[] expected = Hex.decode("a8061dc1305136c6c22b8baf0c0127a9"); + + checkVector(keyMaterial, data, expected); + + data = Hex.decode("48656c6c6f20776f726c6421"); + keyMaterial = Hex.decode( + "746869732069732033322d6279746520" + + "6b657920666f7220506f6c7931333035"); + + checkVector(keyMaterial, data, Hex.decode("a6f745008f81c916a20dcc74eef2b2f0")); + + // A.3 #1 + keyMaterial = Hex.decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + + data = Hex.decode( + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + + checkVector(keyMaterial, data, Hex.decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")); + + // A.3 #2 + keyMaterial = Hex.decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0036 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e"); + + data = Hex.decode( + "41 6e 79 20 73 75 62 6d 69 73 73 69 6f 6e 20 74" + + "6f 20 74 68 65 20 49 45 54 46 20 69 6e 74 65 6e" + + "64 65 64 20 62 79 20 74 68 65 20 43 6f 6e 74 72" + + "69 62 75 74 6f 72 20 66 6f 72 20 70 75 62 6c 69" + + "63 61 74 69 6f 6e 20 61 73 20 61 6c 6c 20 6f 72" + + "20 70 61 72 74 20 6f 66 20 61 6e 20 49 45 54 46" + + "20 49 6e 74 65 72 6e 65 74 2d 44 72 61 66 74 20" + + "6f 72 20 52 46 43 20 61 6e 64 20 61 6e 79 20 73" + + "74 61 74 65 6d 65 6e 74 20 6d 61 64 65 20 77 69" + + "74 68 69 6e 20 74 68 65 20 63 6f 6e 74 65 78 74" + + "20 6f 66 20 61 6e 20 49 45 54 46 20 61 63 74 69" + + "76 69 74 79 20 69 73 20 63 6f 6e 73 69 64 65 72" + + "65 64 20 61 6e 20 22 49 45 54 46 20 43 6f 6e 74" + + "72 69 62 75 74 69 6f 6e 22 2e 20 53 75 63 68 20" + + "73 74 61 74 65 6d 65 6e 74 73 20 69 6e 63 6c 75" + + "64 65 20 6f 72 61 6c 20 73 74 61 74 65 6d 65 6e" + + "74 73 20 69 6e 20 49 45 54 46 20 73 65 73 73 69" + + "6f 6e 73 2c 20 61 73 20 77 65 6c 6c 20 61 73 20" + + "77 72 69 74 74 65 6e 20 61 6e 64 20 65 6c 65 63" + + "74 72 6f 6e 69 63 20 63 6f 6d 6d 75 6e 69 63 61" + + "74 69 6f 6e 73 20 6d 61 64 65 20 61 74 20 61 6e" + + "79 20 74 69 6d 65 20 6f 72 20 70 6c 61 63 65 2c" + + "20 77 68 69 63 68 20 61 72 65 20 61 64 64 72 65" + + "73 73 65 64 20 74 6f"); + + checkVector(keyMaterial, data, Hex.decode("36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e")); + + // A.3 #3 + keyMaterial = Hex.decode("36 e5 f6 b5 c5 e0 60 70 f0 ef ca 96 22 7a 86 3e00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + + checkVector(keyMaterial, data, Hex.decode("f3 47 7e 7c d9 54 17 af 89 a6 b8 79 4c 31 0c f0")); + + // A.3 #4 + + keyMaterial = Hex.decode("1c 92 40 a5 eb 55 d3 8a f3 33 88 86 04 f6 b5 f0 47 39 17 c1 40 2b 80 09 9d ca 5c bc 20 70 75 c0"); + + data = Hex.decode( + "27 54 77 61 73 20 62 72 69 6c 6c 69 67 2c 20 61" + + "6e 64 20 74 68 65 20 73 6c 69 74 68 79 20 74 6f" + + "76 65 73 0a 44 69 64 20 67 79 72 65 20 61 6e 64" + + "20 67 69 6d 62 6c 65 20 69 6e 20 74 68 65 20 77" + + "61 62 65 3a 0a 41 6c 6c 20 6d 69 6d 73 79 20 77" + + "65 72 65 20 74 68 65 20 62 6f 72 6f 67 6f 76 65" + + "73 2c 0a 41 6e 64 20 74 68 65 20 6d 6f 6d 65 20" + + "72 61 74 68 73 20 6f 75 74 67 72 61 62 65 2e"); + + checkVector(keyMaterial, data, Hex.decode("45 41 66 9a 7e aa ee 61 e7 08 dc 7c bc c5 eb 62")); + + // A.3 #5 + keyMaterial = Hex.decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + data = Hex.decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF"); + + checkVector(keyMaterial, data, Hex.decode("03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")); + + // A.3 #6 + keyMaterial = Hex.decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF"); + data = Hex.decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + + checkVector(keyMaterial, data, Hex.decode("03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")); + + // A.3 #7 + keyMaterial = Hex.decode("01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + data = Hex.decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FFF0 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF11 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + + checkVector(keyMaterial, data, Hex.decode("05 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")); + + // A.3 #8 + keyMaterial = Hex.decode("01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + data = Hex.decode("FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FFFB FE FE FE FE FE FE FE FE FE FE FE FE FE FE FE01 01 01 01 01 01 01 01 01 01 01 01 01 01 01 01"); + + checkVector(keyMaterial, data, Hex.decode("00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")); + + // A.3 #9 + keyMaterial = Hex.decode("02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + data = Hex.decode("FD FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF"); + + checkVector(keyMaterial, data, Hex.decode("FA FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF")); + + // A.3 #10 + keyMaterial = Hex.decode("01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + data = Hex.decode( + "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00" + + "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00" + + "01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + + checkVector(keyMaterial, data, Hex.decode("14 00 00 00 00 00 00 00 55 00 00 00 00 00 00 00")); + + // A.3 #11 + keyMaterial = Hex.decode("01 00 00 00 00 00 00 00 04 00 00 00 00 00 00 0000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + data = Hex.decode( + "E3 35 94 D7 50 5E 43 B9 00 00 00 00 00 00 00 00" + + "33 94 D7 50 5E 43 79 CD 01 00 00 00 00 00 00 00" + + "00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00"); + + checkVector(keyMaterial, data, Hex.decode("13 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00")); + } + + private void checkVector(byte[] keyMaterial, byte[] input, byte[] tag) + { + Poly1305 poly1305 = new Poly1305(); + + poly1305.init(new KeyParameter(keyMaterial)); + + poly1305.update(input, 0, input.length); + + byte[] mac = new byte[poly1305.getMacSize()]; + + poly1305.doFinal(mac, 0); + + if (!Arrays.areEqual(tag, mac)) + { + fail("rfc7539", Hex.toHexString(tag), Hex.toHexString(mac)); + } + } + + public static void main(String[] args) + throws Exception + { + runTest(new Poly1305Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC2Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC2Test.java new file mode 100644 index 000000000..d99946e0f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC2Test.java @@ -0,0 +1,66 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.RC2Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.RC2Parameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +/** + * RC2 tester - vectors from ftp://ftp.isi.edu/in-notes/rfc2268.txt + * + * RFC 2268 "A Description of the RC2(r) Encryption Algorithm" + */ +public class RC2Test + extends CipherTest +{ + static BlockCipherVectorTest[] tests = + { + new BlockCipherVectorTest(0, new RC2Engine(), + new RC2Parameters(Hex.decode("0000000000000000"), 63), + "0000000000000000", "ebb773f993278eff"), + + new BlockCipherVectorTest(1, new RC2Engine(), + new RC2Parameters(Hex.decode("ffffffffffffffff"), 64), + "ffffffffffffffff", "278b27e42e2f0d49"), + + new BlockCipherVectorTest(2, new RC2Engine(), + new RC2Parameters(Hex.decode("3000000000000000"), 64), + "1000000000000001", "30649edf9be7d2c2"), + + new BlockCipherVectorTest(3, new RC2Engine(), + new RC2Parameters(Hex.decode("88"), 64), + "0000000000000000", "61a8a244adacccf0"), + + new BlockCipherVectorTest(4, new RC2Engine(), + new RC2Parameters(Hex.decode("88bca90e90875a"), 64), + "0000000000000000", "6ccf4308974c267f"), + + new BlockCipherVectorTest(5, new RC2Engine(), + new RC2Parameters(Hex.decode("88bca90e90875a7f0f79c384627bafb2"), 64), + "0000000000000000", "1a807d272bbe5db1"), + + new BlockCipherVectorTest(6, new RC2Engine(), + new RC2Parameters(Hex.decode("88bca90e90875a7f0f79c384627bafb2"), 128), + "0000000000000000", "2269552ab0f85ca6"), + + new BlockCipherVectorTest(7, new RC2Engine(), + new RC2Parameters(Hex.decode("88bca90e90875a7f0f79c384627bafb216f80a6f85920584c42fceb0be255daf1e"), 129), + "0000000000000000", "5b78d3a43dfff1f1") + }; + + RC2Test() + { + super(tests, new RC2Engine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "RC2"; + } + + public static void main( + String[] args) + { + runTest(new RC2Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC2WrapTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC2WrapTest.java new file mode 100644 index 000000000..86fcbfc4a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC2WrapTest.java @@ -0,0 +1,111 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.Wrapper; +import com.fr.third.org.bouncycastle.crypto.engines.RC2WrapEngine; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.params.RC2Parameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * RC2 wrap tester + */ +public class RC2WrapTest + implements Test +{ + private class RFCRandom + extends SecureRandom + { + public void nextBytes( + byte[] nextBytes) + { + System.arraycopy(Hex.decode("4845cce7fd1250"), 0, nextBytes, 0, nextBytes.length); + } + } + + private TestResult wrapTest( + int id, + CipherParameters paramsWrap, + CipherParameters paramsUnwrap, + byte[] in, + byte[] out) + { + Wrapper wrapper = new RC2WrapEngine(); + + wrapper.init(true, paramsWrap); + + try + { + byte[] cText = wrapper.wrap(in, 0, in.length); + if (!Arrays.areEqual(cText, out)) + { + return new SimpleTestResult(false, getName() + ": failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed wrap test exception " + e.toString(), e); + } + + wrapper.init(false, paramsUnwrap); + + try + { + byte[] pText = wrapper.unwrap(out, 0, out.length); + if (!Arrays.areEqual(pText, in)) + { + return new SimpleTestResult(false, getName() + ": failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": failed unwrap test exception " + e.toString(), e); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public TestResult perform() + { + byte[] kek1 = Hex.decode("fd04fd08060707fb0003fefffd02fe05"); + byte[] iv1 = Hex.decode("c7d90059b29e97f7"); + byte[] in1 = Hex.decode("b70a25fbc9d86a86050ce0d711ead4d9"); + byte[] out1 = Hex.decode("70e699fb5701f7833330fb71e87c85a420bdc99af05d22af5a0e48d35f3138986cbaafb4b28d4f35"); + // + // note the RFC 3217 test specifies a key to be used with an effective key size of + // 40 bits which is why it is done here - in practice nothing less than 128 bits should be used. + // + CipherParameters paramWrap = new ParametersWithRandom(new ParametersWithIV(new RC2Parameters(kek1, 40), iv1), new RFCRandom()); + CipherParameters paramUnwrap = new RC2Parameters(kek1, 40); + + TestResult result = wrapTest(1, paramWrap, paramUnwrap, in1, out1); + + if (!result.isSuccessful()) + { + return result; + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public String getName() + { + return "RC2Wrap"; + } + + public static void main( + String[] args) + { + RC2WrapTest test = new RC2WrapTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC4Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC4Test.java new file mode 100644 index 000000000..b874a0b81 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC4Test.java @@ -0,0 +1,45 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.RC4Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * RC4 Test + */ +public class RC4Test + extends SimpleTest +{ + StreamCipherVectorTest[] tests = + { + new StreamCipherVectorTest(0, new RC4Engine(), + new KeyParameter(Hex.decode("0123456789ABCDEF")), + "4e6f772069732074", "3afbb5c77938280d"), + new StreamCipherVectorTest(0, new RC4Engine(), + new KeyParameter(Hex.decode("0123456789ABCDEF")), + "68652074696d6520", "1cf1e29379266d59"), + new StreamCipherVectorTest(0, new RC4Engine(), + new KeyParameter(Hex.decode("0123456789ABCDEF")), + "666f7220616c6c20", "12fbb0c771276459") + }; + + public String getName() + { + return "RC4"; + } + + public void performTest() + { + for (int i = 0; i != tests.length; i++) + { + tests[i].performTest(); + } + } + + public static void main( + String[] args) + { + runTest(new RC4Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC5Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC5Test.java new file mode 100644 index 000000000..f530d48fe --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC5Test.java @@ -0,0 +1,188 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.RC532Engine; +import com.fr.third.org.bouncycastle.crypto.engines.RC564Engine; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.crypto.params.RC5Parameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * RC5 tester - vectors from ftp://ftp.nordu.net/rfc/rfc2040.txt + * + * RFC 2040 "The RC5, RC5-CBC, RC5-CBC-Pad, and RC5-CTS Algorithms" + */ +public class RC5Test + implements Test +{ + BlockCipherVectorTest[] tests = + { + new BlockCipherVectorTest(0, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("0000000000000000")), + "0000000000000000", "7a7bba4d79111d1e"), + new BlockCipherVectorTest(1, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "797bba4d78111d1e"), + new BlockCipherVectorTest(2, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("0000000000000001")), + "0000000000000000", "7a7bba4d79111d1f"), + new BlockCipherVectorTest(3, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("0000000000000000")), + "0000000000000001", "7a7bba4d79111d1f"), + new BlockCipherVectorTest(4, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("0102030405060708")), + "1020304050607080", "8b9ded91ce7794a6"), + new BlockCipherVectorTest(5, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("11"), 1), + Hex.decode("0000000000000000")), + "0000000000000000", "2f759fe7ad86a378"), + new BlockCipherVectorTest(6, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 2), + Hex.decode("0000000000000000")), + "0000000000000000", "dca2694bf40e0788"), + new BlockCipherVectorTest(7, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00000000"), 2), + Hex.decode("0000000000000000")), + "0000000000000000", "dca2694bf40e0788"), + new BlockCipherVectorTest(8, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00000000"), 8), + Hex.decode("0000000000000000")), + "0000000000000000", "dcfe098577eca5ff"), + new BlockCipherVectorTest(9, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 8), + Hex.decode("0102030405060708")), + "1020304050607080", "9646fb77638f9ca8"), + new BlockCipherVectorTest(10, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 12), + Hex.decode("0102030405060708")), + "1020304050607080", "b2b3209db6594da4"), + new BlockCipherVectorTest(11, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 16), + Hex.decode("0102030405060708")), + "1020304050607080", "545f7f32a5fc3836"), + new BlockCipherVectorTest(12, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304"), 8), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "8285e7c1b5bc7402"), + new BlockCipherVectorTest(13, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304"), 12), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "fc586f92f7080934"), + new BlockCipherVectorTest(14, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304"), 16), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "cf270ef9717ff7c4"), + new BlockCipherVectorTest(15, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405060708"), 12), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "e493f1c1bb4d6e8c"), + new BlockCipherVectorTest(16, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405060708"), 8), + Hex.decode("0102030405060708")), + "1020304050607080", "5c4c041e0f217ac3"), + new BlockCipherVectorTest(17, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405060708"), 12), + Hex.decode("0102030405060708")), + "1020304050607080", "921f12485373b4f7"), + new BlockCipherVectorTest(18, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405060708"), 16), + Hex.decode("0102030405060708")), + "1020304050607080", "5ba0ca6bbe7f5fad"), + new BlockCipherVectorTest(19, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304050607081020304050607080"), 8), + Hex.decode("0102030405060708")), + "1020304050607080", "c533771cd0110e63"), + new BlockCipherVectorTest(20, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304050607081020304050607080"), 12), + Hex.decode("0102030405060708")), + "1020304050607080", "294ddb46b3278d60"), + new BlockCipherVectorTest(21, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("01020304050607081020304050607080"), 16), + Hex.decode("0102030405060708")), + "1020304050607080", "dad6bda9dfe8f7e8"), + new BlockCipherVectorTest(22, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405"), 12), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "97e0787837ed317f"), + new BlockCipherVectorTest(23, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405"), 8), + Hex.decode("0000000000000000")), + "ffffffffffffffff", "7875dbf6738c6478"), + new BlockCipherVectorTest(23, new CBCBlockCipher(new RC532Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("0102030405"), 8), + Hex.decode("7875dbf6738c6478")), + "0808080808080808", "8f34c3c681c99695"), + new BlockCipherVectorTest(640, new CBCBlockCipher(new RC564Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "9f09b98d3f6062d9d4d59973d00e0e63"), + new BlockCipherVectorTest(641, new CBCBlockCipher(new RC564Engine()), + new ParametersWithIV( + new RC5Parameters(Hex.decode("00"), 0), + Hex.decode("00000000000000000000000000000000")), + "ffffffffffffffffffffffffffffffff", "9e09b98d3f6062d9d3d59973d00e0e63") + }; + + public String getName() + { + return "RC5"; + } + + public TestResult perform() + { + for (int i = 0; i != tests.length; i++) + { + TestResult res = tests[i].perform(); + + if (!res.isSuccessful()) + { + return res; + } + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + RC5Test test = new RC5Test(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC6Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC6Test.java new file mode 100644 index 000000000..d2df503c8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RC6Test.java @@ -0,0 +1,64 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.RC6Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * RC6 Test - test vectors from AES Submitted RSA Reference implementation. + * ftp://ftp.funet.fi/pub/crypt/cryptography/symmetric/aes/rc6-unix-refc.tar + */ +public class RC6Test + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new RC6Engine(), + new KeyParameter( + Hex.decode("00000000000000000000000000000000")), + "80000000000000000000000000000000", + "f71f65e7b80c0c6966fee607984b5cdf"), + new BlockCipherVectorTest(1, new RC6Engine(), + new KeyParameter( + Hex.decode("000000000000000000000000000000008000000000000000")), + "00000000000000000000000000000000", + "dd04c176440bbc6686c90aee775bd368"), + new BlockCipherVectorTest(2, new RC6Engine(), + new KeyParameter( + Hex.decode("000000000000000000000000000000000000001000000000")), + "00000000000000000000000000000000", + "937fe02d20fcb72f0f57201012b88ba4"), + new BlockCipherVectorTest(3, new RC6Engine(), + new KeyParameter( + Hex.decode("00000001000000000000000000000000")), + "00000000000000000000000000000000", + "8a380594d7396453771a1dfbe2914c8e"), + new BlockCipherVectorTest(4, new RC6Engine(), + new KeyParameter( + Hex.decode("1000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000000000000000000", + "11395d4bfe4c8258979ee2bf2d24dff4"), + new BlockCipherVectorTest(5, new RC6Engine(), + new KeyParameter( + Hex.decode("0000000000000000000000000000000000080000000000000000000000000000")), + "00000000000000000000000000000000", + "3d6f7e99f6512553bb983e8f75672b97") + }; + + RC6Test() + { + super(tests, new RC6Engine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "RC6"; + } + + public static void main( + String[] args) + { + runTest(new RC6Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RFC3211WrapTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RFC3211WrapTest.java new file mode 100644 index 000000000..42397d19f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RFC3211WrapTest.java @@ -0,0 +1,203 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.Wrapper; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.engines.RFC3211WrapEngine; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.prng.FixedSecureRandom; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Wrap Test based on RFC3211 test vectors + */ +public class RFC3211WrapTest + extends SimpleTest +{ + SecureRandom r1 = new FixedSecureRandom(Hex.decode("C436F541")); + + SecureRandom r2 = new FixedSecureRandom(Hex.decode("FA060A45")); + + public String getName() + { + return "RFC3211Wrap"; + } + + private void wrapTest( + int id, + BlockCipher engine, + byte[] kek, + byte[] iv, + SecureRandom rand, + byte[] in, + byte[] out) + throws Exception + { + Wrapper wrapper = new RFC3211WrapEngine(engine); + + wrapper.init(true, new ParametersWithRandom(new ParametersWithIV(new KeyParameter(kek), iv), rand)); + + byte[] cText = wrapper.wrap(in, 0, in.length); + if (!Arrays.areEqual(cText, out)) + { + fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + + wrapper.init(false, new ParametersWithIV(new KeyParameter(kek), iv)); + + byte[] pText = wrapper.unwrap(out, 0, out.length); + if (!Arrays.areEqual(pText, in)) + { + fail("rfailed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText))); + } + } + + private void testCorruption() + throws InvalidCipherTextException + { + byte[] kek = Hex.decode("D1DAA78615F287E6"); + byte[] iv = Hex.decode("EFE598EF21B33D6D"); + + Wrapper wrapper = new RFC3211WrapEngine(new DESEngine()); + + wrapper.init(false, new ParametersWithIV(new KeyParameter(kek), iv)); + + byte[] block = Hex.decode("ff739D838C627C897323A2F8C436F541"); + encryptBlock(kek, iv, block); + + try + { + wrapper.unwrap(block, 0, block.length); + + fail("bad length not detected"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals("wrapped key corrupted")) + { + fail("wrong exception on length"); + } + } + + block = Hex.decode("08639D838C627C897323A2F8C436F541"); + testChecksum(kek, iv, block, wrapper); + + block = Hex.decode("08736D838C627C897323A2F8C436F541"); + testChecksum(kek, iv, block, wrapper); + + block = Hex.decode("08739D638C627C897323A2F8C436F541"); + testChecksum(kek, iv, block, wrapper); + } + + private void testChecksum(byte[] kek, byte[] iv, byte[] block, Wrapper wrapper) + { + encryptBlock(kek, iv, block); + + try + { + wrapper.unwrap(block, 0, block.length); + + fail("bad checksum not detected"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals("wrapped key corrupted")) + { + fail("wrong exception"); + } + } + } + + private void encryptBlock(byte[] key, byte[] iv, byte[] cekBlock) + { + BlockCipher engine = new CBCBlockCipher(new DESEngine()); + + engine.init(true, new ParametersWithIV(new KeyParameter(key), iv)); + + for (int i = 0; i < cekBlock.length; i += 8) + { + engine.processBlock(cekBlock, i, cekBlock, i); + } + + for (int i = 0; i < cekBlock.length; i += 8) + { + engine.processBlock(cekBlock, i, cekBlock, i); + } + } + + public void performTest() + throws Exception + { + wrapTest(1, new DESEngine(), Hex.decode("D1DAA78615F287E6"), Hex.decode("EFE598EF21B33D6D"), r1, Hex.decode("8C627C897323A2F8"), Hex.decode("B81B2565EE373CA6DEDCA26A178B0C10")); + wrapTest(2, new DESedeEngine(), Hex.decode("6A8970BF68C92CAEA84A8DF28510858607126380CC47AB2D"), Hex.decode("BAF1CA7931213C4E"), r2, + Hex.decode("8C637D887223A2F965B566EB014B0FA5D52300A3F7EA40FFFC577203C71BAF3B"), + Hex.decode("C03C514ABDB9E2C5AAC038572B5E24553876B377AAFB82ECA5A9D73F8AB143D9EC74E6CAD7DB260C")); + + testCorruption(); + + Wrapper wrapper = new RFC3211WrapEngine(new DESEngine()); + ParametersWithIV params = new ParametersWithIV(new KeyParameter(new byte[16]), new byte[16]); + byte[] buf = new byte[16]; + + try + { + wrapper.init(true, params); + + wrapper.unwrap(buf, 0, buf.length); + + fail("failed unwrap state test."); + } + catch (IllegalStateException e) + { + // expected + } + catch (InvalidCipherTextException e) + { + fail("unexpected exception: " + e, e); + } + + try + { + wrapper.init(false, params); + + wrapper.wrap(buf, 0, buf.length); + + fail("failed unwrap state test."); + } + catch (IllegalStateException e) + { + // expected + } + + // + // short test + // + try + { + wrapper.init(false, params); + + wrapper.unwrap(buf, 0, buf.length / 2); + + fail("failed unwrap short test."); + } + catch (InvalidCipherTextException e) + { + // expected + } + } + + public static void main( + String[] args) + { + runTest(new RFC3211WrapTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD128DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD128DigestTest.java new file mode 100644 index 000000000..d9a0c0861 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD128DigestTest.java @@ -0,0 +1,58 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD128Digest; + +/** + * RIPEMD128 Digest Test + */ +public class RIPEMD128DigestTest + extends DigestTest +{ + final static String[] messages = { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + final static String[] digests = { + "cdf26213a150dc3ecb610f18f6b38b46", + "86be7afa339d0fc7cfc785e72f578d33", + "c14a12199c66e4ba84636b0f69144c77", + "9e327b3d6e523062afc1132d7df9d1b8", + "fd2aa607f71dc8f510714922b371834e", + "a1aa0689d0fafa2ddc22e88b49133a06", + "d1e959eb179c911faea4624c60c5c702", + "3f45ef194732c2dbb2c4a2c769795fa3" + }; + + final static String million_a_digest = "4a7f5723f954eba1216c9d8f6320431f"; + + RIPEMD128DigestTest() + { + super(new RIPEMD128Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new RIPEMD128Digest((RIPEMD128Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new RIPEMD128DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD128HMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD128HMacTest.java new file mode 100644 index 000000000..d6cc0d9c9 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD128HMacTest.java @@ -0,0 +1,86 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD128Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * RIPEMD128 HMac Test, test vectors from RFC 2286 + */ +public class RIPEMD128HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "fbf61f9492aa4bbf81c172e84e0734db", + "875f828862b6b334b427c55f9f7ff09b", + "09f0b2846d2f543da363cbec8d62a38d", + "bdbbd7cf03e44b5aa60af815be4d2294", + "e79808f24b25fd031c155f0d551d9a3a", + "dc732928de98104a1f59d373c150acbb", + "5c6bec96793e16d40690c237635f30c5" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" + }; + + public String getName() + { + return "RIPEMD128HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new RIPEMD128Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed"); + } + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + RIPEMD128HMacTest test = new RIPEMD128HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD160DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD160DigestTest.java new file mode 100644 index 000000000..881057e98 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD160DigestTest.java @@ -0,0 +1,58 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD160Digest; + +/** + * RIPEMD160 Digest Test + */ +public class RIPEMD160DigestTest + extends DigestTest +{ + final static String[] messages = { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + final static String[] digests = { + "9c1185a5c5e9fc54612808977ee8f548b2258d31", + "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe", + "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc", + "5d0689ef49d2fae572b881b123a85ffa21595f36", + "f71c27109c692c1b56bbdceb5b9d2865b3708dbc", + "12a053384a9c0c88e405a06c27dcf49ada62eb2b", + "b0e20b6e3116640286ed3a87a5713079b21f5189", + "9b752e45573d4b39f4dbd3323cab82bf63326bfb" + }; + + final static String million_a_digest = "52783243c1697bdbe16d37f97f68f08325dc1528"; + + RIPEMD160DigestTest() + { + super(new RIPEMD160Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new RIPEMD160Digest((RIPEMD160Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new RIPEMD160DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD160HMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD160HMacTest.java new file mode 100644 index 000000000..3863a0342 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD160HMacTest.java @@ -0,0 +1,86 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD160Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * RIPEMD160 HMac Test, test vectors from RFC 2286 + */ +public class RIPEMD160HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668", + "dda6c0213a485a9e24f4742064a7f033b43c4069", + "b0b105360de759960ab4f35298e116e295d8e7c1", + "d5ca862f4d21d5e610e18b4cf1beb97a4365ecf4", + "7619693978f91d90539ae786500ff3d8e0518e39", + "6466ca07ac5eac29e1bd523e5ada7605b791fd8b", + "69ea60798d71616cce5fd0871e23754cd75d5a0a" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data" + }; + + public String getName() + { + return "RIPEMD160HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new RIPEMD160Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed"); + } + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + RIPEMD160HMacTest test = new RIPEMD160HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD256DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD256DigestTest.java new file mode 100644 index 000000000..303e7220c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD256DigestTest.java @@ -0,0 +1,58 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD256Digest; + +/** + * RIPEMD128 Digest Test + */ +public class RIPEMD256DigestTest + extends DigestTest +{ + final static String[] messages = { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + final static String[] digests = { + "02ba4c4e5f8ecd1877fc52d64d30e37a2d9774fb1e5d026380ae0168e3c5522d", + "f9333e45d857f5d90a91bab70a1eba0cfb1be4b0783c9acfcd883a9134692925", + "afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65", + "87e971759a1ce47a514d5c914c392c9018c7c46bc14465554afcdf54a5070c0e", + "649d3034751ea216776bf9a18acc81bc7896118a5197968782dd1fd97d8d5133", + "3843045583aac6c8c8d9128573e7a9809afb2a0f34ccc36ea9e72f16f6368e3f", + "5740a408ac16b720b84424ae931cbb1fe363d1d0bf4017f1a89f7ea6de77a0b8", + "06fdcc7a409548aaf91368c06a6275b553e3f099bf0ea4edfd6778df89a890dd" + }; + + final static String million_a_digest = "ac953744e10e31514c150d4d8d7b677342e33399788296e43ae4850ce4f97978"; + + RIPEMD256DigestTest() + { + super(new RIPEMD256Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new RIPEMD256Digest((RIPEMD256Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new RIPEMD256DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD320DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD320DigestTest.java new file mode 100644 index 000000000..232140b52 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RIPEMD320DigestTest.java @@ -0,0 +1,58 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD320Digest; + +/** + * RIPEMD320 Digest Test + */ +public class RIPEMD320DigestTest + extends DigestTest +{ + final static String[] messages = { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890" + }; + + final static String[] digests = { + "22d65d5661536cdc75c1fdf5c6de7b41b9f27325ebc61e8557177d705a0ec880151c3a32a00899b8", + "ce78850638f92658a5a585097579926dda667a5716562cfcf6fbe77f63542f99b04705d6970dff5d", + "de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d", + "3a8e28502ed45d422f68844f9dd316e7b98533fa3f2a91d29f84d425c88d6b4eff727df66a7c0197", + "cabdb1810b92470a2093aa6bce05952c28348cf43ff60841975166bb40ed234004b8824463e6b009", + "d034a7950cf722021ba4b84df769a5de2060e259df4c9bb4a4268c0e935bbc7470a969c9d072a1ac", + "ed544940c86d67f250d232c30b7b3e5770e0c60c8cb9a4cafe3b11388af9920e1b99230b843c86a4", + "557888af5f6d8ed62ab66945c6d2a0a47ecd5341e915eb8fea1d0524955f825dc717e4a008ab2d42" + }; + + final static String million_a_digest = "bdee37f4371e20646b8b0d862dda16292ae36f40965e8c8509e63d1dbddecc503e2b63eb9245bb66"; + + RIPEMD320DigestTest() + { + super(new RIPEMD320Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new RIPEMD320Digest((RIPEMD320Digest)digest); + } + + public static void main( + String[] args) + { + runTest(new RIPEMD320DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RNGUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RNGUtils.java new file mode 100644 index 000000000..e664c025d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RNGUtils.java @@ -0,0 +1,11 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.util.Random; + +class RNGUtils +{ + public static int nextInt(Random rng, int n) + { + return rng.nextInt(n); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSABlindedTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSABlindedTest.java new file mode 100644 index 000000000..bbb56ee0a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSABlindedTest.java @@ -0,0 +1,437 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricBlockCipher; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.encodings.OAEPEncoding; +import com.fr.third.org.bouncycastle.crypto.encodings.PKCS1Encoding; +import com.fr.third.org.bouncycastle.crypto.engines.RSABlindedEngine; +import com.fr.third.org.bouncycastle.crypto.generators.RSAKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +import java.math.BigInteger; +import java.security.SecureRandom; + +public class RSABlindedTest + extends SimpleTest +{ + static BigInteger mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16); + static BigInteger pubExp = new BigInteger("11", 16); + static BigInteger privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16); + static BigInteger p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16); + static BigInteger q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16); + static BigInteger pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16); + static BigInteger qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16); + static BigInteger crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16); + + static String input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + // + // to check that we handling byte extension by big number correctly. + // + static String edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + static byte[] oversizedSig = Hex.decode("01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] dudBlock = Hex.decode("000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] truncatedDataBlock = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] incorrectPadding = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] missingDataBlock = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + + public String getName() + { + return "RSABlinded"; + } + + private void testStrictPKCS1Length(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + AsymmetricBlockCipher eng = new RSABlindedEngine(); + + eng.init(true, privParameters); + + byte[] data = null; + + try + { + data = eng.processBlock(oversizedSig, 0, oversizedSig.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng = new PKCS1Encoding(eng); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + + fail("oversized signature block not recognised"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals("block incorrect size")) + { + fail("RSA: failed - exception " + e.toString(), e); + } + } + + //System.setProperty(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false"); + + System.getProperties().put(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false"); + eng = new PKCS1Encoding(new RSABlindedEngine()); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (InvalidCipherTextException e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + System.getProperties().remove(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY); + } + + private void testTruncatedPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block incorrect"); + } + + private void testDudPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "block incorrect"); + } + + private void testWrongPaddingPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block incorrect"); + } + + private void testMissingDataPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "block incorrect"); + } + + private void checkForPKCS1Exception(RSAKeyParameters pubParameters, RSAKeyParameters privParameters, byte[] inputData, String expectedMessage) + { + AsymmetricBlockCipher eng = new RSABlindedEngine(); + + eng.init(true, privParameters); + + byte[] data = null; + + try + { + data = eng.processBlock(inputData, 0, inputData.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng = new PKCS1Encoding(eng); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + + fail("missing data block not recognised"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals(expectedMessage)) + { + fail("RSA: failed - exception " + e.toString(), e); + } + } + } + + private void testOAEP(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + // + // OAEP - public encrypt, private decrypt + // + AsymmetricBlockCipher eng = new OAEPEncoding(new RSABlindedEngine()); + byte[] data = Hex.decode(input); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed OAEP Test"); + } + } + + public void performTest() + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef); + byte[] data = Hex.decode(edgeInput); + + // + // RAW + // + AsymmetricBlockCipher eng = new RSABlindedEngine(); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!edgeInput.equals(new String(Hex.encode(data)))) + { + fail("failed RAW edge Test"); + } + + data = Hex.decode(input); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed RAW Test"); + } + + // + // PKCS1 - public encrypt, private decrypt + // + eng = new PKCS1Encoding(eng); + + eng.init(true, pubParameters); + + if (eng.getOutputBlockSize() != ((PKCS1Encoding)eng).getUnderlyingCipher().getOutputBlockSize()) + { + fail("PKCS1 output block size incorrect"); + } + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed PKCS1 public/private Test"); + } + + // + // PKCS1 - private encrypt, public decrypt + // + eng = new PKCS1Encoding(((PKCS1Encoding)eng).getUnderlyingCipher()); + + eng.init(true, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed PKCS1 private/public Test"); + } + + // + // key generation test + // + RSAKeyPairGenerator pGen = new RSAKeyPairGenerator(); + RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters( + BigInteger.valueOf(0x11), new SecureRandom(), 768, 25); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + eng = new RSABlindedEngine(); + + if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 768) + { + fail("failed key generation (768) length test"); + } + + eng.init(true, pair.getPublic()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pair.getPrivate()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed key generation (768) Test"); + } + + genParam = new RSAKeyGenerationParameters(BigInteger.valueOf(0x11), new SecureRandom(), 1024, 25); + + pGen.init(genParam); + pair = pGen.generateKeyPair(); + + eng.init(true, pair.getPublic()); + + if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 1024) + { + fail("failed key generation (1024) length test"); + } + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pair.getPrivate()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed key generation (1024) test"); + } + + testOAEP(pubParameters, privParameters); + testStrictPKCS1Length(pubParameters, privParameters); + testDudPKCS1Block(pubParameters, privParameters); + testMissingDataPKCS1Block(pubParameters, privParameters); + testTruncatedPKCS1Block(pubParameters, privParameters); + testWrongPaddingPKCS1Block(pubParameters, privParameters); + + try + { + new RSABlindedEngine().processBlock(new byte[]{ 1 }, 0, 1); + fail("failed initialisation check"); + } + catch (IllegalStateException e) + { + // expected + } + } + + + public static void main( + String[] args) + { + runTest(new RSABlindedTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSADigestSignerTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSADigestSignerTest.java new file mode 100644 index 000000000..644612c50 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSADigestSignerTest.java @@ -0,0 +1,143 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.DigestInfo; +import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.CryptoException; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.NullDigest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA224Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA384Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA3Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512tDigest; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.crypto.signers.RSADigestSigner; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class RSADigestSignerTest + extends SimpleTest +{ + public String getName() + { + return "RSADigestSigner"; + } + + public void performTest() throws Exception + { + BigInteger rsaPubMod = new BigInteger(Base64.decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt")); + BigInteger rsaPubExp = new BigInteger(Base64.decode("EQ==")); + BigInteger rsaPrivMod = new BigInteger(Base64.decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt")); + BigInteger rsaPrivDP = new BigInteger(Base64.decode("JXzfzG5v+HtLJIZqYMUefJfFLu8DPuJGaLD6lI3cZ0babWZ/oPGoJa5iHpX4Ul/7l3s1PFsuy1GhzCdOdlfRcQ==")); + BigInteger rsaPrivDQ = new BigInteger(Base64.decode("YNdJhw3cn0gBoVmMIFRZzflPDNthBiWy/dUMSRfJCxoZjSnr1gysZHK01HteV1YYNGcwPdr3j4FbOfri5c6DUQ==")); + BigInteger rsaPrivExp = new BigInteger(Base64.decode("DxFAOhDajr00rBjqX+7nyZ/9sHWRCCp9WEN5wCsFiWVRPtdB+NeLcou7mWXwf1Y+8xNgmmh//fPV45G2dsyBeZbXeJwB7bzx9NMEAfedchyOwjR8PYdjK3NpTLKtZlEJ6Jkh4QihrXpZMO4fKZWUm9bid3+lmiq43FwW+Hof8/E=")); + BigInteger rsaPrivP = new BigInteger(Base64.decode("AJ9StyTVW+AL/1s7RBtFwZGFBgd3zctBqzzwKPda6LbtIFDznmwDCqAlIQH9X14X7UPLokCDhuAa76OnDXb1OiE=")); + BigInteger rsaPrivQ = new BigInteger(Base64.decode("AM3JfD79dNJ5A3beScSzPtWxx/tSLi0QHFtkuhtSizeXdkv5FSba7lVzwEOGKHmW829bRoNxThDy4ds1IihW1w0=")); + BigInteger rsaPrivQinv = new BigInteger(Base64.decode("Lt0g7wrsNsQxuDdB8q/rH8fSFeBXMGLtCIqfOec1j7FEIuYA/ACiRDgXkHa0WgN7nLXSjHoy630wC5Toq8vvUg==")); + RSAKeyParameters rsaPublic = new RSAKeyParameters(false, rsaPubMod, rsaPubExp); + RSAPrivateCrtKeyParameters rsaPrivate = new RSAPrivateCrtKeyParameters(rsaPrivMod, rsaPubExp, rsaPrivExp, rsaPrivP, rsaPrivQ, rsaPrivDP, rsaPrivDQ, rsaPrivQinv); + + checkDigest(rsaPublic, rsaPrivate, new SHA1Digest(), X509ObjectIdentifiers.id_SHA1); + checkNullDigest(rsaPublic, rsaPrivate, new SHA1Digest(), X509ObjectIdentifiers.id_SHA1); + + checkDigest(rsaPublic, rsaPrivate, new SHA224Digest(), NISTObjectIdentifiers.id_sha224); + checkDigest(rsaPublic, rsaPrivate, new SHA256Digest(), NISTObjectIdentifiers.id_sha256); + checkNullDigest(rsaPublic, rsaPrivate, new SHA256Digest(), NISTObjectIdentifiers.id_sha256); + checkDigest(rsaPublic, rsaPrivate, new SHA384Digest(), NISTObjectIdentifiers.id_sha384); + checkDigest(rsaPublic, rsaPrivate, new SHA512Digest(), NISTObjectIdentifiers.id_sha512); + checkDigest(rsaPublic, rsaPrivate, new SHA512tDigest(224), NISTObjectIdentifiers.id_sha512_224); + checkDigest(rsaPublic, rsaPrivate, new SHA512tDigest(256), NISTObjectIdentifiers.id_sha512_256); + + checkDigest(rsaPublic, rsaPrivate, new SHA3Digest(224), NISTObjectIdentifiers.id_sha3_224); + checkDigest(rsaPublic, rsaPrivate, new SHA3Digest(256), NISTObjectIdentifiers.id_sha3_256); + checkDigest(rsaPublic, rsaPrivate, new SHA3Digest(384), NISTObjectIdentifiers.id_sha3_384); + checkDigest(rsaPublic, rsaPrivate, new SHA3Digest(512), NISTObjectIdentifiers.id_sha3_512); + + // Null format test + RSADigestSigner signer = new RSADigestSigner(new NullDigest()); + + signer.init(true, rsaPrivate); + + signer.update(new byte[16], 0, 16); + + try + { + signer.generateSignature(); + fail("no exception"); + } + catch (CryptoException e) + { + isTrue(e.getMessage().startsWith("unable to encode signature: malformed DigestInfo")); + } + } + + private void checkDigest(RSAKeyParameters rsaPublic, RSAPrivateCrtKeyParameters rsaPrivate, Digest digest, ASN1ObjectIdentifier digOid) + throws Exception + { + byte[] msg = new byte[] { 1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23 }; + + RSADigestSigner signer = new RSADigestSigner(digest); + signer.init(true, rsaPrivate); + signer.update(msg, 0, msg.length); + byte[] sig = signer.generateSignature(); + + signer = new RSADigestSigner(digest, digOid); + signer.init(false, rsaPublic); + signer.update(msg, 0, msg.length); + if (!signer.verifySignature(sig)) + { + fail("RSA Digest Signer failed."); + } + } + + private void checkNullDigest(RSAKeyParameters rsaPublic, RSAPrivateCrtKeyParameters rsaPrivate, Digest digest, ASN1ObjectIdentifier digOid) + throws Exception + { + byte[] msg = new byte[] { 1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23 }; + + RSADigestSigner signer = new RSADigestSigner(new NullDigest()); + + byte[] hash = new byte[digest.getDigestSize()]; + digest.update(msg, 0, msg.length); + digest.doFinal(hash, 0); + + DigestInfo digInfo = new DigestInfo(new AlgorithmIdentifier(digOid, DERNull.INSTANCE), hash); + byte[] infoEnc = digInfo.getEncoded(); + + signer.init(true, rsaPrivate); + + signer.update(infoEnc, 0, infoEnc.length); + + byte[] sig = signer.generateSignature(); + + signer = new RSADigestSigner(digest, digOid); + signer.init(false, rsaPublic); + signer.update(msg, 0, msg.length); + if (!signer.verifySignature(sig)) + { + fail("NONE - RSA Digest Signer failed."); + } + + signer = new RSADigestSigner(new NullDigest()); + signer.init(false, rsaPublic); + signer.update(infoEnc, 0, infoEnc.length); + if (!signer.verifySignature(sig)) + { + fail("NONE - RSA Digest Signer failed."); + } + } + + public static void main(String[] args) + { + runTest(new RSADigestSignerTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSAKeyEncapsulationTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSAKeyEncapsulationTest.java new file mode 100644 index 000000000..ec72dbd06 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSAKeyEncapsulationTest.java @@ -0,0 +1,61 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.generators.KDF2BytesGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.RSAKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.kems.RSAKeyEncapsulation; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyGenerationParameters; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Tests for the RSA Key Encapsulation Mechanism + */ +public class RSAKeyEncapsulationTest + extends SimpleTest +{ + public String getName() + { + return "RSAKeyEncapsulation"; + } + + public void performTest() + throws Exception + { + // Generate RSA key pair + RSAKeyPairGenerator rsaGen = new RSAKeyPairGenerator(); + rsaGen.init(new RSAKeyGenerationParameters(BigInteger.valueOf(65537), new SecureRandom(), 1024, 5)); + AsymmetricCipherKeyPair keys = rsaGen.generateKeyPair(); + + // Set RSA-KEM parameters + RSAKeyEncapsulation kem; + KDF2BytesGenerator kdf = new KDF2BytesGenerator(new SHA1Digest()); + SecureRandom rnd = new SecureRandom(); + byte[] out = new byte[128]; + KeyParameter key1, key2; + + // Test RSA-KEM + kem = new RSAKeyEncapsulation(kdf, rnd); + + kem.init(keys.getPublic()); + key1 = (KeyParameter)kem.encrypt(out, 128); + + kem.init(keys.getPrivate()); + key2 = (KeyParameter)kem.decrypt(out, 128); + + if (!areEqual(key1.getKey(), key2.getKey())) + { + fail("failed test"); + } + } + + public static void main( + String[] args) + { + runTest(new RSAKeyEncapsulationTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSATest.java new file mode 100644 index 000000000..501002114 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RSATest.java @@ -0,0 +1,719 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricBlockCipher; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.encodings.OAEPEncoding; +import com.fr.third.org.bouncycastle.crypto.encodings.PKCS1Encoding; +import com.fr.third.org.bouncycastle.crypto.engines.RSAEngine; +import com.fr.third.org.bouncycastle.crypto.generators.RSAKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class RSATest + extends SimpleTest +{ + /* + * Based on https://github.com/crocs-muni/roca/blob/master/java/BrokenKey.java + * Credits: ported to Java by Martin Paljak + */ + static class BrokenKey_CVE_2017_15361 + { + private static final int[] prims = new int[]{ 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, + 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167 }; + private static final BigInteger[] primes = new BigInteger[prims.length]; + + static + { + for (int i = 0; i < prims.length; i++) + { + primes[i] = BigInteger.valueOf(prims[i]); + } + } + + private static final BigInteger[] markers = new BigInteger[] + { + new BigInteger("6"), + new BigInteger("30"), + new BigInteger("126"), + new BigInteger("1026"), + new BigInteger("5658"), + new BigInteger("107286"), + new BigInteger("199410"), + new BigInteger("8388606"), + new BigInteger("536870910"), + new BigInteger("2147483646"), + new BigInteger("67109890"), + new BigInteger("2199023255550"), + new BigInteger("8796093022206"), + new BigInteger("140737488355326"), + new BigInteger("5310023542746834"), + new BigInteger("576460752303423486"), + new BigInteger("1455791217086302986"), + new BigInteger("147573952589676412926"), + new BigInteger("20052041432995567486"), + new BigInteger("6041388139249378920330"), + new BigInteger("207530445072488465666"), + new BigInteger("9671406556917033397649406"), + new BigInteger("618970019642690137449562110"), + new BigInteger("79228162521181866724264247298"), + new BigInteger("2535301200456458802993406410750"), + new BigInteger("1760368345969468176824550810518"), + new BigInteger("50079290986288516948354744811034"), + new BigInteger("473022961816146413042658758988474"), + new BigInteger("10384593717069655257060992658440190"), + new BigInteger("144390480366845522447407333004847678774"), + new BigInteger("2722258935367507707706996859454145691646"), + new BigInteger("174224571863520493293247799005065324265470"), + new BigInteger("696898287454081973172991196020261297061886"), + new BigInteger("713623846352979940529142984724747568191373310"), + new BigInteger("1800793591454480341970779146165214289059119882"), + new BigInteger("126304807362733370595828809000324029340048915994"), + new BigInteger("11692013098647223345629478661730264157247460343806"), + new BigInteger("187072209578355573530071658587684226515959365500926") + }; + + public static boolean isAffected(RSAKeyParameters publicKey) + { + BigInteger modulus = publicKey.getModulus(); + + for (int i = 0; i < primes.length; i++) + { + int remainder = modulus.remainder(primes[i]).intValue(); + if (!markers[i].testBit(remainder)) + { + return false; + } + } + + return true; + } + } + + static BigInteger mod = new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16); + static BigInteger pubExp = new BigInteger("11", 16); + static BigInteger privExp = new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16); + static BigInteger p = new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16); + static BigInteger q = new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16); + static BigInteger pExp = new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16); + static BigInteger qExp = new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16); + static BigInteger crtCoef = new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16); + + static String input = "4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + // + // to check that we handling byte extension by big number correctly. + // + static String edgeInput = "ff6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"; + + static byte[] oversizedSig = Hex.decode("01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] dudBlock = Hex.decode("000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] truncatedDataBlock = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff004e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] incorrectPadding = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4e6f77206973207468652074696d6520666f7220616c6c20676f6f64206d656e"); + static byte[] missingDataBlock = Hex.decode("0001ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); + + public String getName() + { + return "RSA"; + } + + private void testStrictPKCS1Length(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + AsymmetricBlockCipher eng = new RSAEngine(); + + eng.init(true, privParameters); + + byte[] data = null; + byte[] overSized = null; + + try + { + overSized = data = eng.processBlock(oversizedSig, 0, oversizedSig.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng = new PKCS1Encoding(eng); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(overSized, 0, overSized.length); + + fail("oversized signature block not recognised"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals("block incorrect size")) + { + fail("RSA: failed - exception " + e.toString(), e); + } + } + + eng = new PKCS1Encoding(new RSAEngine(), Hex.decode("feedbeeffeedbeeffeedbeef")); + eng.init(false, new ParametersWithRandom(privParameters, new SecureRandom())); + + try + { + data = eng.processBlock(overSized, 0, overSized.length); + isTrue("not fallback", Arrays.areEqual(Hex.decode("feedbeeffeedbeeffeedbeef"), data)); + } + catch (InvalidCipherTextException e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + //System.setProperty(PKCS1Encoding.STRICT_LENGTH_ENABLED_PROPERTY, "false"); + + System.getProperties().put(PKCS1Encoding.NOT_STRICT_LENGTH_ENABLED_PROPERTY, "true"); + eng = new PKCS1Encoding(new RSAEngine()); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(overSized, 0, overSized.length); + } + catch (InvalidCipherTextException e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + System.getProperties().remove(PKCS1Encoding.NOT_STRICT_LENGTH_ENABLED_PROPERTY); + } + + private void testUnsafeModulusAndWrongExp() + { + try + { + try + { + new RSAKeyParameters(false, mod, pubExp.multiply(BigInteger.valueOf(2))); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isTrue("RSA publicExponent is even".equals(e.getMessage())); + } + + try + { + new RSAKeyParameters(false, mod.multiply(BigInteger.valueOf(2)), pubExp); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isTrue("RSA modulus is even".equals(e.getMessage())); + } + + try + { + new RSAKeyParameters(false, mod.multiply(BigInteger.valueOf(3)), pubExp); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isTrue("RSA modulus has a small prime factor".equals(e.getMessage())); + } + + System.getProperties().put("com.fr.third.org.bouncycastle.rsa.allow_unsafe_mod", "true"); + + // this should now work (sigh...) + new RSAKeyParameters(false, mod.multiply(BigInteger.valueOf(3)), pubExp); + } + finally + { + System.getProperties().remove("com.fr.third.org.bouncycastle.rsa.allow_unsafe_mod"); + } + } + + private void testTruncatedPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, truncatedDataBlock, "block incorrect"); + } + + private void testDudPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, dudBlock, "block incorrect"); + } + + private void testWrongPaddingPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, incorrectPadding, "block incorrect"); + } + + private void testMissingDataPKCS1Block(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + checkForPKCS1Exception(pubParameters, privParameters, missingDataBlock, "block incorrect"); + } + + private void checkForPKCS1Exception(RSAKeyParameters pubParameters, RSAKeyParameters privParameters, byte[] inputData, String expectedMessage) + { + AsymmetricBlockCipher eng = new RSAEngine(); + + eng.init(true, privParameters); + + byte[] data = null; + + try + { + data = eng.processBlock(inputData, 0, inputData.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng = new PKCS1Encoding(eng); + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + + fail("missing data block not recognised"); + } + catch (InvalidCipherTextException e) + { + if (!e.getMessage().equals(expectedMessage)) + { + fail("RSA: failed - exception " + e.toString(), e); + } + } + } + + private void testOAEP(RSAKeyParameters pubParameters, RSAKeyParameters privParameters) + { + // + // OAEP - public encrypt, private decrypt + // + AsymmetricBlockCipher eng = new OAEPEncoding(new RSAEngine()); + byte[] data = Hex.decode(input); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed OAEP Test"); + } + + // check for oversized input + byte[] message = new byte[87]; + RSAEngine rsaEngine = new RSAEngine(); + AsymmetricBlockCipher cipher = new OAEPEncoding(rsaEngine, new SHA1Digest(), new SHA1Digest(), message); + cipher.init(true, new ParametersWithRandom(pubParameters, new SecureRandom())); + + try + { + cipher.processBlock(message, 0, message.length); + + fail("no exception thrown"); + } + catch (DataLengthException e) + { + isTrue("message mismatch", "input data too long".equals(e.getMessage())); + } + catch (InvalidCipherTextException e) + { + fail("failed - exception " + e.toString(), e); + } + + } + + private void zeroBlockTest(CipherParameters encParameters, CipherParameters decParameters) + { + AsymmetricBlockCipher eng = new PKCS1Encoding(new RSAEngine()); + + eng.init(true, encParameters); + + if (eng.getOutputBlockSize() != ((PKCS1Encoding)eng).getUnderlyingCipher().getOutputBlockSize()) + { + fail("PKCS1 output block size incorrect"); + } + + byte[] zero = new byte[0]; + byte[] data = null; + + try + { + data = eng.processBlock(zero, 0, zero.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, decParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!Arrays.areEqual(zero, data)) + { + fail("failed PKCS1 zero Test"); + } + } + + private void test_CVE_2017_15361() + { + SecureRandom random = new SecureRandom(); + RSAKeyPairGenerator pGen = new RSAKeyPairGenerator(); + BigInteger e = BigInteger.valueOf(0x11); + + for (int strength = 512; strength <= 2048; strength += 32) + { + pGen.init(new RSAKeyGenerationParameters( + e, random, strength, 100)); + + RSAKeyParameters pubKey = (RSAKeyParameters)pGen.generateKeyPair().getPublic(); + + if (BrokenKey_CVE_2017_15361.isAffected(pubKey)) + { + fail("failed CVE-2017-15361 vulnerability test for generated RSA key"); + } + } + } + + public void performTest() + { + RSAKeyParameters pubParameters = new RSAKeyParameters(false, mod, pubExp); + RSAKeyParameters privParameters = new RSAPrivateCrtKeyParameters(mod, pubExp, privExp, p, q, pExp, qExp, crtCoef); + byte[] data = Hex.decode(edgeInput); + + // + // RAW + // + AsymmetricBlockCipher eng = new RSAEngine(); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("RSA: failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!edgeInput.equals(new String(Hex.encode(data)))) + { + fail("failed RAW edge Test"); + } + + data = Hex.decode(input); + + eng.init(true, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed RAW Test"); + } + + // + // PKCS1 - public encrypt, private decrypt + // + eng = new PKCS1Encoding(eng); + + eng.init(true, pubParameters); + + if (eng.getOutputBlockSize() != ((PKCS1Encoding)eng).getUnderlyingCipher().getOutputBlockSize()) + { + fail("PKCS1 output block size incorrect"); + } + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, privParameters); + + byte[] plainData = null; + try + { + plainData = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(Hex.toHexString(plainData))) + { + fail("failed PKCS1 public/private Test"); + } + + PKCS1Encoding fEng = new PKCS1Encoding(new RSAEngine(), input.length() / 2); + fEng.init(false, new ParametersWithRandom(privParameters, new SecureRandom())); + try + { + plainData = fEng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(Hex.toHexString(plainData))) + { + fail("failed PKCS1 public/private fixed Test"); + } + + fEng = new PKCS1Encoding(new RSAEngine(), input.length()); + fEng.init(false, new ParametersWithRandom(privParameters, new SecureRandom())); + try + { + data = fEng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (input.equals(Hex.toHexString(data))) + { + fail("failed to recognise incorrect plaint text length"); + } + + data = plainData; + + // + // PKCS1 - private encrypt, public decrypt + // + eng = new PKCS1Encoding(((PKCS1Encoding)eng).getUnderlyingCipher()); + + eng.init(true, privParameters); + + try + { + data = eng.processBlock(plainData, 0, plainData.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pubParameters); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(Hex.toHexString(data))) + { + fail("failed PKCS1 private/public Test"); + } + + zeroBlockTest(pubParameters, privParameters); + zeroBlockTest(privParameters, pubParameters); + + // + // key generation test + // + RSAKeyPairGenerator pGen = new RSAKeyPairGenerator(); + RSAKeyGenerationParameters genParam = new RSAKeyGenerationParameters( + BigInteger.valueOf(0x11), new SecureRandom(), 768, 25); + + pGen.init(genParam); + + AsymmetricCipherKeyPair pair = pGen.generateKeyPair(); + + eng = new RSAEngine(); + + if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 768) + { + fail("failed key generation (768) length test"); + } + + eng.init(true, pair.getPublic()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pair.getPrivate()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed key generation (768) Test"); + } + + genParam = new RSAKeyGenerationParameters(BigInteger.valueOf(0x11), new SecureRandom(), 1024, 25); + + pGen.init(genParam); + pair = pGen.generateKeyPair(); + + eng.init(true, pair.getPublic()); + + if (((RSAKeyParameters)pair.getPublic()).getModulus().bitLength() < 1024) + { + fail("failed key generation (1024) length test"); + } + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + eng.init(false, pair.getPrivate()); + + try + { + data = eng.processBlock(data, 0, data.length); + } + catch (Exception e) + { + fail("failed - exception " + e.toString(), e); + } + + if (!input.equals(new String(Hex.encode(data)))) + { + fail("failed key generation (1024) test"); + } + + genParam = new RSAKeyGenerationParameters( + BigInteger.valueOf(0x11), new SecureRandom(), 128, 25); + pGen.init(genParam); + + for (int i = 0; i < 100; ++i) + { + pair = pGen.generateKeyPair(); + RSAPrivateCrtKeyParameters privKey = (RSAPrivateCrtKeyParameters)pair.getPrivate(); + BigInteger pqDiff = privKey.getP().subtract(privKey.getQ()).abs(); + + if (pqDiff.bitLength() < 42) + { + fail("P and Q too close in RSA key pair"); + } + } + + testOAEP(pubParameters, privParameters); + testStrictPKCS1Length(pubParameters, privParameters); + testDudPKCS1Block(pubParameters, privParameters); + testMissingDataPKCS1Block(pubParameters, privParameters); + testTruncatedPKCS1Block(pubParameters, privParameters); + testWrongPaddingPKCS1Block(pubParameters, privParameters); + test_CVE_2017_15361(); + testUnsafeModulusAndWrongExp(); + + try + { + new RSAEngine().processBlock(new byte[]{1}, 0, 1); + fail("failed initialisation check"); + } + catch (IllegalStateException e) + { + // expected + } + } + + + public static void main( + String[] args) + { + runTest(new RSATest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RegressionTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RegressionTest.java new file mode 100644 index 000000000..6ee5a4b5d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RegressionTest.java @@ -0,0 +1,182 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.Test; + +public class RegressionTest +{ + public static Test[] tests = + { + new AESTest(), + new AESLightTest(), + new AESFastTest(), + new AESWrapTest(), + new AESWrapPadTest(), + new ARIATest(), + new DESTest(), + new DESedeTest(), + new ModeTest(), + new PaddingTest(), + new DHTest(), + new ElGamalTest(), + new DSATest(), + new ECTest(), + new DeterministicDSATest(), + new GOST3410Test(), + new ECGOST3410Test(), + new ECIESTest(), + new ECNRTest(), + new MacTest(), + new GOST28147MacTest(), + new RC2Test(), + new RC2WrapTest(), + new RC4Test(), + new RC5Test(), + new RC6Test(), + new RijndaelTest(), + new SerpentTest(), + new TnepresTest(), + new CamelliaTest(), + new CamelliaLightTest(), + new DigestRandomNumberTest(), + new SkipjackTest(), + new BlowfishTest(), + new TwofishTest(), + new Threefish256Test(), + new Threefish512Test(), + new Threefish1024Test(), + new SkeinDigestTest(), + new SkeinMacTest(), + new CAST5Test(), + new CAST6Test(), + new GOST28147Test(), + new IDEATest(), + new RSATest(), + new RSABlindedTest(), + new RSADigestSignerTest(), + new PSSBlindTest(), + new ISO9796Test(), + new ISO9797Alg3MacTest(), + new MD2DigestTest(), + new MD4DigestTest(), + new MD5DigestTest(), + new SHA1DigestTest(), + new SHA224DigestTest(), + new SHA256DigestTest(), + new SHA384DigestTest(), + new SHA512DigestTest(), + new SHA512t224DigestTest(), + new SHA512t256DigestTest(), + new SHA3DigestTest(), + new RIPEMD128DigestTest(), + new RIPEMD160DigestTest(), + new RIPEMD256DigestTest(), + new RIPEMD320DigestTest(), + new TigerDigestTest(), + new GOST3411DigestTest(), + new GOST3411_2012_256DigestTest(), + new GOST3411_2012_512DigestTest(), + new WhirlpoolDigestTest(), + new MD5HMacTest(), + new SHA1HMacTest(), + new SHA224HMacTest(), + new SHA256HMacTest(), + new SHA384HMacTest(), + new SHA512HMacTest(), + new RIPEMD128HMacTest(), + new RIPEMD160HMacTest(), + new OAEPTest(), + new PSSTest(), + new CTSTest(), + new NISTCTSTest(), + new CCMTest(), + new PKCS5Test(), + new PKCS12Test(), + new KDF1GeneratorTest(), + new KDF2GeneratorTest(), + new MGF1GeneratorTest(), + new HKDFGeneratorTest(), + new DHKEKGeneratorTest(), + new ECDHKEKGeneratorTest(), + new ShortenedDigestTest(), + new EqualsHashCodeTest(), + new TEATest(), + new XTEATest(), + new RFC3211WrapTest(), + new SEEDTest(), + new Salsa20Test(), + new XSalsa20Test(), + new ChaChaTest(), + new ChaCha20Poly1305Test(), + new CMacTest(), + new EAXTest(), + new GCMTest(), + new GMacTest(), + new HCFamilyTest(), + new HCFamilyVecTest(), + new ISAACTest(), + new NoekeonTest(), + new VMPCKSA3Test(), + new VMPCMacTest(), + new VMPCTest(), + new Grainv1Test(), + new Grain128Test(), + //new NaccacheSternTest(), + new SRP6Test(), + new SCryptTest(), + new ResetTest(), + new NullTest(), + new DSTU4145Test(), + new SipHashTest(), + new Poly1305Test(), + new OCBTest(), + new NonMemoableDigestTest(), + new RSAKeyEncapsulationTest(), + new ECIESKeyEncapsulationTest(), + new HashCommitmentTest(), + new CipherStreamTest(), + new BlockCipherResetTest(), + new StreamCipherResetTest(), + new SM3DigestTest(), + new Shacal2Test(), + new KDFCounterGeneratorTest(), + new KDFDoublePipelineIteratorGeneratorTest(), + new KDFFeedbackGeneratorTest(), + new CramerShoupTest(), + new BCryptTest(), + new OpenBSDBCryptTest(), + new X931SignerTest(), + new Blake2bDigestTest(), + new Blake2sDigestTest(), + new Blake2xsDigestTest(), + new KeccakDigestTest(), + new SHAKEDigestTest(), + new SM2EngineTest(), + new SM2KeyExchangeTest(), + new SM2SignerTest(), + new SM4Test(), + new DSTU7624Test(), + new DSTU7564Test(), + new IsoTrailerTest(), + new GOST3412Test(), + new GOST3412MacTest(), + new GSKKDFTest(), + new X25519Test(), + new X448Test(), + new Ed25519Test(), + new Ed448Test(), + new CSHAKETest(), + new Argon2Test(), + new OpenSSHKeyParsingTests(), + new EthereumIESTest(), + new BigIntegersTest(), + new ZucTest(), + new Haraka256DigestTest(), + new Haraka512DigestTest() + }; + + public static void main(String[] args) + { + SimpleTest.runTests(tests); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ResetTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ResetTest.java new file mode 100644 index 000000000..8efbfcf2f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ResetTest.java @@ -0,0 +1,99 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.DataLengthException; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ResetTest + extends SimpleTest +{ + private static final byte[] input = Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20"); + private static final byte[] output = Hex.decode("3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53"); + public String getName() + { + return "Reset"; + } + + public void performTest() + throws Exception + { + BufferedBlockCipher cipher = new BufferedBlockCipher(new DESEngine()); + + KeyParameter param = new KeyParameter(Hex.decode("0123456789abcdef")); + + basicTrial(cipher, param); + + cipher.init(false, param); + + byte[] out = new byte[input.length]; + + int len2 = cipher.processBytes(output, 0, output.length - 1, out, 0); + + try + { + cipher.doFinal(out, len2); + fail("no DataLengthException - short input"); + } + catch (DataLengthException e) + { + // ignore + } + + len2 = cipher.processBytes(output, 0, output.length, out, 0); + + cipher.doFinal(out, len2); + + if (!areEqual(input, out)) + { + fail("failed reversal one got " + new String(Hex.encode(out))); + } + + len2 = cipher.processBytes(output, 0, output.length - 1, out, 0); + + try + { + cipher.doFinal(out, len2); + fail("no DataLengthException - short output"); + } + catch (DataLengthException e) + { + // ignore + } + + len2 = cipher.processBytes(output, 0, output.length, out, 0); + + cipher.doFinal(out, len2); + + if (!areEqual(input, out)) + { + fail("failed reversal two got " + new String(Hex.encode(out))); + } + } + + private void basicTrial(BufferedBlockCipher cipher, KeyParameter param) + throws InvalidCipherTextException + { + cipher.init(true, param); + + byte[] out = new byte[input.length]; + + int len1 = cipher.processBytes(input, 0, input.length, out, 0); + + cipher.doFinal(out, len1); + + if (!areEqual(out, output)) + { + fail("failed - " + "expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + public static void main( + String[] args) + { + runTest(new ResetTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RijndaelTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RijndaelTest.java new file mode 100644 index 000000000..af2225aae --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/RijndaelTest.java @@ -0,0 +1,116 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.RijndaelEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test vectors from the NIST standard tests and Brian Gladman's vector set + * + * http://fp.gladman.plus.com/cryptography_technology/rijndael/ + */ +public class RijndaelTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new RijndaelEngine(128), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "0EDD33D3C621E546455BD8BA1418BEC8"), + new BlockCipherVectorTest(1, new RijndaelEngine(128), + new KeyParameter(Hex.decode("00000000000000000000000000000080")), + "00000000000000000000000000000000", "172AEAB3D507678ECAF455C12587ADB7"), + new BlockCipherMonteCarloTest(2, 10000, new RijndaelEngine(128), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "C34C052CC0DA8D73451AFE5F03BE297F"), + new BlockCipherMonteCarloTest(3, 10000, new RijndaelEngine(128), + new KeyParameter(Hex.decode("5F060D3716B345C253F6749ABAC10917")), + "355F697E8B868B65B25A04E18D782AFA", "ACC863637868E3E068D2FD6E3508454A"), + new BlockCipherVectorTest(4, new RijndaelEngine(128), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "6CD02513E8D4DC986B4AFE087A60BD0C"), + new BlockCipherMonteCarloTest(5, 10000, new RijndaelEngine(128), + new KeyParameter(Hex.decode("AAFE47EE82411A2BF3F6752AE8D7831138F041560631B114")), + "F3F6752AE8D7831138F041560631B114", "77BA00ED5412DFF27C8ED91F3C376172"), + new BlockCipherVectorTest(6, new RijndaelEngine(128), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "80000000000000000000000000000000", "DDC6BF790C15760D8D9AEB6F9A75FD4E"), + new BlockCipherMonteCarloTest(7, 10000, new RijndaelEngine(128), + new KeyParameter(Hex.decode("28E79E2AFC5F7745FCCABE2F6257C2EF4C4EDFB37324814ED4137C288711A386")), + "C737317FE0846F132B23C8C2A672CE22", "E58B82BFBA53C0040DC610C642121168"), + new BlockCipherVectorTest(8, new RijndaelEngine(160), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c")), + "3243f6a8885a308d313198a2e03707344a409382", "16e73aec921314c29df905432bc8968ab64b1f51"), + new BlockCipherVectorTest(8, new RijndaelEngine(160), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160")), + "3243f6a8885a308d313198a2e03707344a409382", "0553eb691670dd8a5a5b5addf1aa7450f7a0e587"), + new BlockCipherVectorTest(8, new RijndaelEngine(160), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")), + "3243f6a8885a308d313198a2e03707344a409382", "73cd6f3423036790463aa9e19cfcde894ea16623"), + new BlockCipherVectorTest(8, new RijndaelEngine(160), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")), + "3243f6a8885a308d313198a2e03707344a409382", "601b5dcd1cf4ece954c740445340bf0afdc048df"), + new BlockCipherVectorTest(8, new RijndaelEngine(160), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")), + "3243f6a8885a308d313198a2e03707344a409382", "579e930b36c1529aa3e86628bacfe146942882cf"), + new BlockCipherVectorTest(8, new RijndaelEngine(192), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d", "b24d275489e82bb8f7375e0d5fcdb1f481757c538b65148a"), + new BlockCipherVectorTest(9, new RijndaelEngine(192), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d", "725ae43b5f3161de806a7c93e0bca93c967ec1ae1b71e1cf"), + new BlockCipherVectorTest(10, new RijndaelEngine(192), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d", "bbfc14180afbf6a36382a061843f0b63e769acdc98769130"), + new BlockCipherVectorTest(11, new RijndaelEngine(192), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d", "0ebacf199e3315c2e34b24fcc7c46ef4388aa475d66c194c"), + new BlockCipherVectorTest(12, new RijndaelEngine(224), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "b0a8f78f6b3c66213f792ffd2a61631f79331407a5e5c8d3793aceb1"), + new BlockCipherVectorTest(13, new RijndaelEngine(224), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "08b99944edfce33a2acb131183ab0168446b2d15e958480010f545e3"), + new BlockCipherVectorTest(14, new RijndaelEngine(224), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "be4c597d8f7efe22a2f7e5b1938e2564d452a5bfe72399c7af1101e2"), + new BlockCipherVectorTest(15, new RijndaelEngine(224), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "ef529598ecbce297811b49bbed2c33bbe1241d6e1a833dbe119569e8"), + new BlockCipherVectorTest(16, new RijndaelEngine(224), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa9", "02fafc200176ed05deb8edb82a3555b0b10d47a388dfd59cab2f6c11"), + new BlockCipherVectorTest(17, new RijndaelEngine(256), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "7d15479076b69a46ffb3b3beae97ad8313f622f67fedb487de9f06b9ed9c8f19"), + new BlockCipherVectorTest(18, new RijndaelEngine(256), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "514f93fb296b5ad16aa7df8b577abcbd484decacccc7fb1f18dc567309ceeffd"), + new BlockCipherVectorTest(19, new RijndaelEngine(256), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da5")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "5d7101727bb25781bf6715b0e6955282b9610e23a43c2eb062699f0ebf5887b2"), + new BlockCipherVectorTest(20, new RijndaelEngine(256), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d90")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "d56c5a63627432579e1dd308b2c8f157b40a4bfb56fea1377b25d3ed3d6dbf80"), + new BlockCipherVectorTest(21, new RijndaelEngine(256), + new KeyParameter(Hex.decode("2b7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfe")), + "3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c8", "a49406115dfb30a40418aafa4869b7c6a886ff31602a7dd19c889dc64f7e4e7a") + }; + + RijndaelTest() + { + super(tests, new RijndaelEngine(128), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "Rijndael"; + } + + public static void main( + String[] args) + { + runTest(new RijndaelTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SCryptTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SCryptTest.java new file mode 100644 index 000000000..b940d5f8e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SCryptTest.java @@ -0,0 +1,146 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.BufferedReader; +import java.io.InputStreamReader; + +import com.fr.third.org.bouncycastle.crypto.generators.SCrypt; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/* + * scrypt test vectors from "Stronger Key Derivation Via Sequential Memory-hard Functions" Appendix B. + * (http://www.tarsnap.com/scrypt/scrypt.pdf) + */ +public class SCryptTest + extends SimpleTest +{ + public String getName() + { + return "SCrypt"; + } + + public void performTest() + throws Exception + { + testParameters(); + testVectors(); + } + + public void testParameters() + { + checkOK("Minimal values", new byte[0], new byte[0], 2, 1, 1, 1); + checkIllegal("Cost parameter must be > 1", new byte[0], new byte[0], 1, 1, 1, 1); + checkOK("Cost parameter 32768 OK for r == 1", new byte[0], new byte[0], 32768, 1, 1, 1); + checkIllegal("Cost parameter must < 65536 for r == 1", new byte[0], new byte[0], 65536, 1, 1, 1); + checkIllegal("Block size must be >= 1", new byte[0], new byte[0], 2, 0, 2, 1); + checkIllegal("Parallelisation parameter must be >= 1", new byte[0], new byte[0], 2, 1, 0, 1); + // checkOK("Parallelisation parameter 65535 OK for r = 4", new byte[0], new byte[0], 2, 32, + // 65535, 1); + checkIllegal("Parallelisation parameter must be < 65535 for r = 4", new byte[0], new byte[0], 2, 32, 65536, 1); + + checkIllegal("Len parameter must be > 1", new byte[0], new byte[0], 2, 1, 1, 0); + } + + private void checkOK(String msg, byte[] pass, byte[] salt, int N, int r, int p, int len) + { + try + { + SCrypt.generate(pass, salt, N, r, p, len); + } + catch (IllegalArgumentException e) + { + e.printStackTrace(); + fail(msg); + } + } + + private void checkIllegal(String msg, byte[] pass, byte[] salt, int N, int r, int p, int len) + { + try + { + SCrypt.generate(pass, salt, N, r, p, len); + fail(msg); + } + catch (IllegalArgumentException e) + { + // e.printStackTrace(); + } + } + + public void testVectors() + throws Exception + { + BufferedReader br = new BufferedReader(new InputStreamReader( + getClass().getResourceAsStream("SCryptTestVectors.txt"))); + + int count = 0; + String line = br.readLine(); + + while (line != null) + { + ++count; + String header = line; + StringBuffer data = new StringBuffer(); + + while (!isEndData(line = br.readLine())) + { + for (int i = 0; i != line.length(); i++) + { + if (line.charAt(i) != ' ') + { + data.append(line.charAt(i)); + } + } + } + + int start = header.indexOf('(') + 1; + int limit = header.lastIndexOf(')'); + String argStr = header.substring(start, limit); + String[] args = Strings.split(argStr, ','); + + byte[] P = extractQuotedString(args[0]); + byte[] S = extractQuotedString(args[1]); + int N = extractInteger(args[2]); + int r = extractInteger(args[3]); + int p = extractInteger(args[4]); + int dkLen = extractInteger(args[5]); + byte[] expected = Hex.decode(data.toString()); + + // This skips very expensive test case(s), remove check to re-enable + if (N <= 16384) + { + byte[] result = SCrypt.generate(P, S, N, r, p, dkLen); + + if (!areEqual(expected, result)) + { + fail("Result does not match expected value in test case " + count); + } + } + } + + br.close(); + } + + private static boolean isEndData(String line) + { + return line == null || line.startsWith("scrypt"); + } + + private static byte[] extractQuotedString(String arg) + { + arg = arg.trim(); + arg = arg.substring(1, arg.length() - 1); + return Strings.toByteArray(arg); + } + + private static int extractInteger(String arg) + { + return Integer.parseInt(arg.trim()); + } + + public static void main(String[] args) + { + runTest(new SCryptTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SEEDTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SEEDTest.java new file mode 100644 index 000000000..bab0325ef --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SEEDTest.java @@ -0,0 +1,53 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.SEEDEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * SEED tester - vectors http://www.ietf.org/rfc/rfc4009.txt + */ +public class SEEDTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new SEEDEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "000102030405060708090a0b0c0d0e0f", + "5EBAC6E0054E166819AFF1CC6D346CDB"), + new BlockCipherVectorTest(0, new SEEDEngine(), + new KeyParameter(Hex.decode("000102030405060708090a0b0c0d0e0f")), + "00000000000000000000000000000000", + "c11f22f20140505084483597e4370f43"), + new BlockCipherVectorTest(0, new SEEDEngine(), + new KeyParameter(Hex.decode("4706480851E61BE85D74BFB3FD956185")), + "83A2F8A288641FB9A4E9A5CC2F131C7D", + "EE54D13EBCAE706D226BC3142CD40D4A"), + new BlockCipherVectorTest(0, new SEEDEngine(), + new KeyParameter(Hex.decode("28DBC3BC49FFD87DCFA509B11D422BE7")), + "B41E6BE2EBA84A148E2EED84593C5EC7", + "9B9B7BFCD1813CB95D0B3618F40F5122"), + new BlockCipherVectorTest(0, new SEEDEngine(), + new KeyParameter(Hex.decode("0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E")), + "0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E0E", + "8296F2F1B007AB9D533FDEE35A9AD850"), + }; + + SEEDTest() + { + super(tests, new SEEDEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "SEED"; + } + + public static void main( + String[] args) + { + runTest(new SEEDTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA1DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA1DigestTest.java new file mode 100644 index 000000000..1c1da2a53 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA1DigestTest.java @@ -0,0 +1,48 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; + +/** + * standard vector test for SHA-1 from "Handbook of Applied Cryptography", page 345. + */ +public class SHA1DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghijklmnopqrstuvwxyz" + }; + + private static String[] digests = + { + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", + "a9993e364706816aba3e25717850c26c9cd0d89d", + "32d10c7b8cf96570ca04ce37f2a19d84240d3a89" + }; + + SHA1DigestTest() + { + super(new SHA1Digest(), messages, digests); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA1Digest((SHA1Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA1Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA1DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA1HMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA1HMacTest.java new file mode 100644 index 000000000..59a79da84 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA1HMacTest.java @@ -0,0 +1,111 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * SHA1 HMac Test, test vectors from RFC 2202 + */ +public class SHA1HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F" + }; + + final static String[] digests = { + "b617318655057264e28bc0b6fb378c8ef146be00", + "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79", + "125d7342b9ac11cd91a39af48aa17b4f63f175d3", + "4c9007f4026250c6bc8414f9bf50c86c2d7235da", + "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04", + "aa4ae5e15272d00e95705637ce8a3b55ed402112", + "e8e99d0f45237d786d6bbaa7965c7808bbff1a91", + "5FD596EE78D5553C8FF4E72D266DFD192366DA29" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data", + "Sample message for keylen=blocklen" + }; + + public String getName() + { + return "SHA1HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new SHA1Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed"); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + SHA1HMacTest test = new SHA1HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA224DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA224DigestTest.java new file mode 100644 index 000000000..141b701fc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA224DigestTest.java @@ -0,0 +1,59 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA224Digest; + +/** + * standard vector test for SHA-224 from RFC 3874 - only the last three are in + * the RFC. + */ +public class SHA224DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + }; + + private static String[] digests = + { + "d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", + "abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", + "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", + "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525" + }; + + // 1 million 'a' + static private String million_a_digest = "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67"; + + SHA224DigestTest() + { + super(new SHA224Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA224Digest((SHA224Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA224Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA224DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA224HMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA224HMacTest.java new file mode 100644 index 000000000..75eb9f06e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA224HMacTest.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA224Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * SHA224 HMac Test + */ +public class SHA224HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22", + "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44", + "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea", + "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a", + "0e2aea68a90c8d37c988bcdb9fca6fa8099cd857c7ec4a1815cac54c", + "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e", + "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." + }; + + public String getName() + { + return "SHA224HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new SHA224Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed got -" + new String(Hex.encode(resBuf))); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + SHA224HMacTest test = new SHA224HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA256DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA256DigestTest.java new file mode 100644 index 000000000..eb4d97c7b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA256DigestTest.java @@ -0,0 +1,60 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; + +/** + * standard vector test for SHA-256 from FIPS Draft 180-2. + * + * Note, the first two vectors are _not_ from the draft, the last three are. + */ +public class SHA256DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" + }; + + private static String[] digests = + { + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", + "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1" + }; + + // 1 million 'a' + static private String million_a_digest = "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"; + + SHA256DigestTest() + { + super(new SHA256Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA256Digest((SHA256Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA256Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA256DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA256HMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA256HMacTest.java new file mode 100644 index 000000000..3618450af --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA256HMacTest.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * SHA256 HMac Test + */ +public class SHA256HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7", + "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843", + "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe", + "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b", + "a3b6167473100ee06e0c796c2955552bfa6f7c0a6a8aef8b93f860aab0cd20c5", + "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54", + "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." + }; + + public String getName() + { + return "SHA256HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new SHA256Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed got -" + new String(Hex.encode(resBuf))); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + SHA256HMacTest test = new SHA256HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA384DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA384DigestTest.java new file mode 100644 index 000000000..d61bf3c03 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA384DigestTest.java @@ -0,0 +1,59 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA384Digest; + +/** + * standard vector test for SHA-384 from FIPS Draft 180-2. + * + * Note, the first two vectors are _not_ from the draft, the last three are. + */ +public class SHA384DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + }; + + private static String[] digests = + { + "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b", + "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31", + "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7", + "09330c33f71147e83d192fc782cd1b4753111b173b3b05d22fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039" + }; + + static private String million_a_digest = "9d0e1809716474cb086e834e310a4a1ced149e9c00f248527972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985"; + + SHA384DigestTest() + { + super(new SHA384Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA384Digest((SHA384Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA384Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA384DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA384HMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA384HMacTest.java new file mode 100644 index 000000000..976efd3b6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA384HMacTest.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA384Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * SHA384 HMac Test + */ +public class SHA384HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6", + "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649", + "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27", + "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb", + "3abf34c3503b2a23a46efc619baef897f4c8e42c934ce55ccbae9740fcbc1af4ca62269e2a37cd88ba926341efe4aeea", + "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952", + "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." + }; + + public String getName() + { + return "SHA384HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new SHA384Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed got -" + new String(Hex.encode(resBuf))); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + SHA384HMacTest test = new SHA384HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA3DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA3DigestTest.java new file mode 100644 index 000000000..219add444 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA3DigestTest.java @@ -0,0 +1,301 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA3Digest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * SHA3 Digest Test + */ +public class SHA3DigestTest + extends SimpleTest +{ + static class MySHA3Digest extends SHA3Digest + { + MySHA3Digest(int bitLength) + { + super(bitLength); + } + + int myDoFinal(byte[] out, int outOff, byte partialByte, int partialBits) + { + return doFinal(out, outOff, partialByte, partialBits); + } + } + + SHA3DigestTest() + { + } + + public String getName() + { + return "SHA-3"; + } + + public void performTest() throws Exception + { + testVectors(); + } + + public void testVectors() throws Exception + { + BufferedReader r = new BufferedReader(new InputStreamReader( + getClass().getResourceAsStream("SHA3TestVectors.txt"))); + + String line; + while (null != (line = readLine(r))) + { + if (line.length() != 0) + { + TestVector v = readTestVector(r, line); + runTestVector(v); + } + } + + r.close(); + } + + private MySHA3Digest createDigest(String algorithm) throws Exception + { + if (algorithm.startsWith("SHA3-")) + { + int bits = parseDecimal(algorithm.substring("SHA3-".length())); + return new MySHA3Digest(bits); + } + throw new IllegalArgumentException("Unknown algorithm: " + algorithm); + } + + private byte[] decodeBinary(String block) + { + int bits = block.length(); + int fullBytes = bits / 8; + int totalBytes = (bits + 7) / 8; + byte[] result = new byte[totalBytes]; + + for (int i = 0; i < fullBytes; ++i) + { + String byteStr = reverse(block.substring(i * 8, (i + 1) * 8)); + result[i] = (byte)parseBinary(byteStr); + } + + if (totalBytes > fullBytes) + { + String byteStr = reverse(block.substring(fullBytes * 8)); + result[fullBytes] = (byte)parseBinary(byteStr); + } + + return result; + } + + private int parseBinary(String s) + { + return Integer.parseInt(s, 2); + } + + private int parseDecimal(String s) + { + return Integer.parseInt(s); + } + + private String readBlock(BufferedReader r) throws IOException + { + StringBuffer b = new StringBuffer(); + String line; + while ((line = readBlockLine(r)) != null) + { + b.append(line); + } + return b.toString(); + } + + private String readBlockLine(BufferedReader r) throws IOException + { + String line = readLine(r); + if (line == null || line.length() == 0) + { + return null; + } + + char[] chars = line.toCharArray(); + + int pos = 0; + for (int i = 0; i != chars.length; i++) + { + if (chars[i] != ' ') + { + chars[pos++] = chars[i]; + } + } + + return new String(chars, 0, pos); + } + + private TestVector readTestVector(BufferedReader r, String header) throws IOException + { + String[] parts = splitAround(header, TestVector.SAMPLE_OF); + + String algorithm = parts[0]; + int bits = parseDecimal(stripFromChar(parts[1], '-')); + + skipUntil(r, TestVector.MSG_HEADER); + String messageBlock = readBlock(r); + if (messageBlock.length() != bits) + { + throw new IllegalStateException("Test vector length mismatch"); + } + byte[] message = decodeBinary(messageBlock); + + skipUntil(r, TestVector.HASH_HEADER); + byte[] hash = Hex.decode(readBlock(r)); + + return new TestVector(algorithm, bits, message, hash); + } + + private String readLine(BufferedReader r) throws IOException + { + String line = r.readLine(); + return line == null ? null : stripFromChar(line, '#').trim(); + } + + private String requireLine(BufferedReader r) throws IOException + { + String line = readLine(r); + if (line == null) + { + throw new EOFException(); + } + return line; + } + + private String reverse(String s) + { + return new StringBuffer(s).reverse().toString(); + } + + private void runTestVector(TestVector v) throws Exception + { + int bits = v.getBits(); + int partialBits = bits % 8; + +// System.out.println(v.getAlgorithm() + " " + bits + "-bit"); +// System.out.println(Hex.toHexString(v.getMessage()).toUpperCase()); +// System.out.println(Hex.toHexString(v.getHash()).toUpperCase()); + + MySHA3Digest d = createDigest(v.getAlgorithm()); + byte[] output = new byte[d.getDigestSize()]; + + byte[] m = v.getMessage(); + if (partialBits == 0) + { + d.update(m, 0, m.length); + d.doFinal(output, 0); + } + else + { + d.update(m, 0, m.length - 1); + d.myDoFinal(output, 0, m[m.length - 1], partialBits); + } + + if (!Arrays.areEqual(v.getHash(), output)) + { + fail(v.getAlgorithm() + " " + v.getBits() + "-bit test vector hash mismatch"); +// System.err.println(v.getAlgorithm() + " " + v.getBits() + "-bit test vector hash mismatch"); +// System.err.println(Hex.toHexString(output).toUpperCase()); + } + } + + private void skipUntil(BufferedReader r, String header) throws IOException + { + String line; + do + { + line = requireLine(r); + } + while (line.length() == 0); + if (!line.equals(header)) + { + throw new IOException("Expected: " + header); + } + } + + private String[] splitAround(String s, String separator) + { + List strings = new ArrayList(); + + String remaining = s; + int index; + + while ((index = remaining.indexOf(separator)) > 0) + { + strings.add(remaining.substring(0, index)); + remaining = remaining.substring(index + separator.length()); + } + strings.add(remaining); + + return (String[])strings.toArray(new String[strings.size()]); + } + + private String stripFromChar(String s, char c) + { + int i = s.indexOf(c); + if (i >= 0) + { + s = s.substring(0, i); + } + return s; + } + + public static void main( + String[] args) + { + runTest(new SHA3DigestTest()); + } + + private static class TestVector + { + private static String SAMPLE_OF = " sample of "; + private static String MSG_HEADER = "Msg as bit string"; + private static String HASH_HEADER = "Hash val is"; + + private String algorithm; + private int bits; + private byte[] message; + private byte[] hash; + + private TestVector(String algorithm, int bits, byte[] message, byte[] hash) + { + this.algorithm = algorithm; + this.bits = bits; + this.message = message; + this.hash = hash; + } + + public String getAlgorithm() + { + return algorithm; + } + + public int getBits() + { + return bits; + } + + public byte[] getMessage() + { + return message; + } + + public byte[] getHash() + { + return hash; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA3HMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA3HMacTest.java new file mode 100644 index 000000000..a8f09aaa5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA3HMacTest.java @@ -0,0 +1,335 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA3Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * SHA224 HMac Test + */ +public class SHA3HMacTest + extends SimpleTest +{ + final static String[][] sha3_224 = + { + { + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b", + "53616d706c65206d65737361676520666f72206b65796c656e3c626c6f636b6c656e", + "332cfd59347fdb8e576e77260be4aba2d6dc53117b3bfb52c6d18c04" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f" + + "30313233 34353637 38393a3b 3c3d3e3f" + + "40414243 44454647 48494a4b 4c4d4e4f" + + "50515253 54555657 58595a5b 5c5d5e5f" + + "60616263 64656667 68696a6b 6c6d6e6f" + + "70717273 74757677 78797a7b 7c7d7e7f" + + "80818283 84858687 88898a8b 8c8d8e8f", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3d626c 6f636b6c" + + "656e", + "d8b733bc f66c644a 12323d56 4e24dcf3" + + "fc75f231 f3b67968 359100c7" + + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f" + + "30313233 34353637 38393a3b 3c3d3e3f" + + "40414243 44454647 48494a4b 4c4d4e4f" + + "50515253 54555657 58595a5b 5c5d5e5f" + + "60616263 64656667 68696a6b 6c6d6e6f" + + "70717273 74757677 78797a7b 7c7d7e7f" + + "80818283 84858687 88898a8b 8c8d8e8f" + + "90919293 94959697 98999a9b 9c9d9e9f" + + "a0a1a2a3 a4a5a6a7 a8a9aaab", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3e626c 6f636b6c" + + "656e", + "078695ee cc227c63 6ad31d06 3a15dd05" + + "a7e819a6 6ec6d8de 1e193e59" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3c626c 6f636b6c" + + "656e2c20 77697468 20747275 6e636174" + + "65642074 6167", + "8569c54c bb00a9b7 8ff1b391 b0e5" + }, + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4869205468657265", + "3b16546bbc7be2706a031dcafd56373d9884367641d8c59af3c860f7" + } + }; + + final static String[][] sha3_256 = + { + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3c626c 6f636b6c" + + "656e", + "4fe8e202 c4f058e8 dddc23d8 c34e4673" + + "43e23555 e24fc2f0 25d598f5 58f67205" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f" + + "30313233 34353637 38393a3b 3c3d3e3f" + + "40414243 44454647 48494a4b 4c4d4e4f" + + "50515253 54555657 58595a5b 5c5d5e5f" + + "60616263 64656667 68696a6b 6c6d6e6f" + + "70717273 74757677 78797a7b 7c7d7e7f" + + "80818283 84858687", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3d626c 6f636b6c" + + "656e", + "68b94e2e 538a9be4 103bebb5 aa016d47" + + "961d4d1a a9060613 13b557f8 af2c3faa" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f" + + "30313233 34353637 38393a3b 3c3d3e3f" + + "40414243 44454647 48494a4b 4c4d4e4f" + + "50515253 54555657 58595a5b 5c5d5e5f" + + "60616263 64656667 68696a6b 6c6d6e6f" + + "70717273 74757677 78797a7b 7c7d7e7f" + + "80818283 84858687 88898a8b 8c8d8e8f" + + "90919293 94959697 98999a9b 9c9d9e9f" + + "a0a1a2a3 a4a5a6a7", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3e626c 6f636b6c" + + "656e", + "9bcf2c23 8e235c3c e88404e8 13bd2f3a" + + "97185ac6 f238c63d 6229a00b 07974258" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3c626c 6f636b6c" + + "656e2c20 77697468 20747275 6e636174" + + "65642074 6167", + "c8dc7148 d8c1423a a549105d afdf9cad" + }, + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4869205468657265", + "ba85192310dffa96e2a3a40e69774351140bb7185e1202cdcc917589f95e16bb" + } + }; + + final static String[][] sha3_384 = { + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3c626c 6f636b6c" + + "656e", + "d588a3c5 1f3f2d90 6e8298c1 199aa8ff" + + "62962181 27f6b38a 90b6afe2 c5617725" + + "bc99987f 79b22a55 7b6520db 710b7f42" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f" + + "30313233 34353637 38393a3b 3c3d3e3f" + + "40414243 44454647 48494a4b 4c4d4e4f" + + "50515253 54555657 58595a5b 5c5d5e5f" + + "60616263 64656667", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3d626c 6f636b6c" + + "656e", + "a27d24b5 92e8c8cb f6d4ce6f c5bf62d8" + + "fc98bf2d 486640d9 eb8099e2 4047837f" + + "5f3bffbe 92dcce90 b4ed5b1e 7e44fa90" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f" + + "30313233 34353637 38393a3b 3c3d3e3f" + + "40414243 44454647 48494a4b 4c4d4e4f" + + "50515253 54555657 58595a5b 5c5d5e5f" + + "60616263 64656667 68696a6b 6c6d6e6f" + + "70717273 74757677 78797a7b 7c7d7e7f" + + "80818283 84858687 88898a8b 8c8d8e8f" + + "90919293 94959697", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3e626c 6f636b6c" + + "656e", + "e5ae4c73 9f455279 368ebf36 d4f5354c" + + "95aa184c 899d3870 e460ebc2 88ef1f94" + + "70053f73 f7c6da2a 71bcaec3 8ce7d6ac" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3c626c 6f636b6c" + + "656e2c20 77697468 20747275 6e636174" + + "65642074 6167", + "25f4bf53 606e91af 79d24a4b b1fd6aec" + + "d44414a3 0c8ebb0a" + }, + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4869205468657265", + "68d2dcf7fd4ddd0a2240c8a437305f61fb7334cfb5d0226e1bc27dc10a2e723a20d370b47743130e26ac7e3d532886bd" + } + }; + + final static String[][] sha3_512 = { + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f" + + "30313233 34353637 38393a3b 3c3d3e3f", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3c626c 6f636b6c" + + "656e", + "4efd629d 6c71bf86 162658f2 9943b1c3" + + "08ce27cd fa6db0d9 c3ce8176 3f9cbce5" + + "f7ebe986 8031db1a 8f8eb7b6 b95e5c5e" + + "3f657a89 96c86a2f 6527e307 f0213196" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f" + + "30313233 34353637 38393a3b 3c3d3e3f" + + "40414243 44454647", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3d626c 6f636b6c" + + "656e", + "544e257e a2a3e5ea 19a590e6 a24b724c" + + "e6327757 723fe275 1b75bf00 7d80f6b3" + + "60744bf1 b7a88ea5 85f9765b 47911976" + + "d3191cf8 3c039f5f fab0d29c c9d9b6da" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f" + + "30313233 34353637 38393a3b 3c3d3e3f" + + "40414243 44454647 48494a4b 4c4d4e4f" + + "50515253 54555657 58595a5b 5c5d5e5f" + + "60616263 64656667 68696a6b 6c6d6e6f" + + "70717273 74757677 78797a7b 7c7d7e7f" + + "80818283 84858687", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3e626c 6f636b6c" + + "656e", + "5f464f5e 5b7848e3 885e49b2 c385f069" + + "4985d0e3 8966242d c4a5fe3f ea4b37d4" + + "6b65cece d5dcf594 38dd840b ab22269f" + + "0ba7febd b9fcf746 02a35666 b2a32915" + }, + { + "00010203 04050607 08090a0b 0c0d0e0f" + + "10111213 14151617 18191a1b 1c1d1e1f" + + "20212223 24252627 28292a2b 2c2d2e2f" + + "30313233 34353637 38393a3b 3c3d3e3f", + "53616d70 6c65206d 65737361 67652066" + + "6f72206b 65796c65 6e3c626c 6f636b6c" + + "656e2c20 77697468 20747275 6e636174" + + "65642074 6167", + "7bb06d85 9257b25c e73ca700 df34c5cb" + + "ef5c898b ac91029e 0b27975d 4e526a08" + }, + { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4869205468657265", + "eb3fbd4b2eaab8f5c504bd3a41465aacec15770a7cabac531e482f860b5ec7ba47ccb2c6f2afce8f88d22b6dc61380f23a668fd3888bb80537c0a0b86407689e" + } + }; + + public String getName() + { + return "SHA3HMac"; + } + + public void performTest() + throws Exception + { + doTest(new HMac(new SHA3Digest(224)), sha3_224); + doTest(new HMac(new SHA3Digest(256)), sha3_256); + doTest(new HMac(new SHA3Digest(384)), sha3_384); + doTest(new HMac(new SHA3Digest(512)), sha3_512); + } + + public void doTest(HMac hmac, String[][] data) + { + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < data.length; i++) + { + byte[] m = Hex.decode(data[i][1]); + + hmac.init(new KeyParameter(Hex.decode(data[i][0]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + isTrue(hmac.getAlgorithmName() + " vector " + i + " failed got " + new String(Hex.encode(resBuf)), startsWith(resBuf, Hex.decode(data[i][2]))); + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = Hex.decode(data[vector][1]); + + hmac.init(new KeyParameter(Hex.decode(data[vector][0]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + isTrue(hmac.getAlgorithmName() + " reset with vector " + vector + " failed", Arrays.areEqual(resBuf, Hex.decode(data[vector][2]))); + } + + private static boolean startsWith(byte[] a, byte[] b) + { + if (a.length == b.length) + { + return Arrays.areEqual(a, b); + } + + for (int i = 0; i != b.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + public static void main( + String[] args) + { + SHA3HMacTest test = new SHA3HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512DigestTest.java new file mode 100644 index 000000000..7f2a4de6d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512DigestTest.java @@ -0,0 +1,60 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; + +/** + * standard vector test for SHA-512 from FIPS Draft 180-2. + * + * Note, the first two vectors are _not_ from the draft, the last three are. + */ +public class SHA512DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + }; + + private static String[] digests = + { + "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e", + "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75", + "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f", + "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909" + }; + + // 1 million 'a' + static private String million_a_digest = "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b"; + + SHA512DigestTest() + { + super(new SHA512Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA512Digest((SHA512Digest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA512Digest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA512DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512HMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512HMacTest.java new file mode 100644 index 000000000..16cf70ffd --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512HMacTest.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * SHA512 HMac Test + */ +public class SHA512HMacTest + implements Test +{ + final static String[] keys = { + "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b", + "4a656665", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "0102030405060708090a0b0c0d0e0f10111213141516171819", + "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }; + + final static String[] digests = { + "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854", + "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737", + "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb", + "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd", + "415fad6271580a531d4179bc891d87a650188707922a4fbb36663a1eb16da008711c5b50ddd0fc235084eb9d3364a1454fb2ef67cd1d29fe6773068ea266e96b", + "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598", + "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58" + }; + + final static String[] messages = { + "Hi There", + "what do ya want for nothing?", + "0xdddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd", + "0xcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd", + "Test With Truncation", + "Test Using Larger Than Block-Size Key - Hash Key First", + "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm." + }; + + public String getName() + { + return "SHA512HMac"; + } + + public TestResult perform() + { + HMac hmac = new HMac(new SHA512Digest()); + byte[] resBuf = new byte[hmac.getMacSize()]; + + for (int i = 0; i < messages.length; i++) + { + byte[] m = messages[i].getBytes(); + if (messages[i].startsWith("0x")) + { + m = Hex.decode(messages[i].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[i]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[i]))) + { + return new SimpleTestResult(false, getName() + ": Vector " + i + " failed got -" + new String(Hex.encode(resBuf))); + } + } + + // + // test reset + // + int vector = 0; // vector used for test + byte[] m = messages[vector].getBytes(); + if (messages[vector].startsWith("0x")) + { + m = Hex.decode(messages[vector].substring(2)); + } + hmac.init(new KeyParameter(Hex.decode(keys[vector]))); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + hmac.reset(); + hmac.update(m, 0, m.length); + hmac.doFinal(resBuf, 0); + + if (!Arrays.areEqual(resBuf, Hex.decode(digests[vector]))) + { + return new SimpleTestResult(false, getName() + + "Reset with vector " + vector + " failed"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + { + SHA512HMacTest test = new SHA512HMacTest(); + TestResult result = test.perform(); + + System.out.println(result); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512t224DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512t224DigestTest.java new file mode 100644 index 000000000..fa5376950 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512t224DigestTest.java @@ -0,0 +1,60 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512tDigest; + +/** + * standard vector test for SHA-512/224 from FIPS 180-4. + * + * Note, only the last 2 message entries are FIPS originated.. + */ +public class SHA512t224DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + }; + + private static String[] digests = + { + "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4", + "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327", + "4634270F707B6A54DAAE7530460842E20E37ED265CEEE9A43E8924AA", + "23FEC5BB94D60B23308192640B0C453335D664734FE40E7268674AF9" + }; + + // 1 million 'a' + static private String million_a_digest = "37ab331d76f0d36de422bd0edeb22a28accd487b7a8453ae965dd287"; + + SHA512t224DigestTest() + { + super(new SHA512tDigest(224), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA512tDigest((SHA512tDigest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA512tDigest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA512t224DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512t256DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512t256DigestTest.java new file mode 100644 index 000000000..abc2a8d33 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHA512t256DigestTest.java @@ -0,0 +1,60 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512tDigest; + +/** + * standard vector test for SHA-512/256 from FIPS 180-4. + * + * Note, only the last 2 message entries are FIPS originated.. + */ +public class SHA512t256DigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu" + }; + + private static String[] digests = + { + "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a", + "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8", + "53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23", + "3928E184FB8690F840DA3988121D31BE65CB9D3EF83EE6146FEAC861E19B563A" + }; + + // 1 million 'a' + static private String million_a_digest = "9a59a052930187a97038cae692f30708aa6491923ef5194394dc68d56c74fb21"; + + SHA512t256DigestTest() + { + super(new SHA512tDigest(256), messages, digests); + } + + public void performTest() + { + super.performTest(); + + millionATest(million_a_digest); + } + + protected Digest cloneDigest(Digest digest) + { + return new SHA512tDigest((SHA512tDigest)digest); + } + + protected Digest cloneDigest(byte[] encodedState) + { + return new SHA512tDigest(encodedState); + } + + public static void main( + String[] args) + { + runTest(new SHA512t256DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHAKEDigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHAKEDigestTest.java new file mode 100644 index 000000000..da167612b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SHAKEDigestTest.java @@ -0,0 +1,346 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.BufferedReader; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; + +import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * SHAKE Digest Test + */ +public class SHAKEDigestTest + extends SimpleTest +{ + static class MySHAKEDigest extends SHAKEDigest + { + MySHAKEDigest(int bitLength) + { + super(bitLength); + } + + int myDoFinal(byte[] out, int outOff, int outLen, byte partialByte, int partialBits) + { + return doFinal(out, outOff, outLen, partialByte, partialBits); + } + } + + SHAKEDigestTest() + { + } + + public String getName() + { + return "SHAKE"; + } + + public void performTest() throws Exception + { + testVectors(); + } + + public void testVectors() throws Exception + { + BufferedReader r = new BufferedReader(new InputStreamReader( + getClass().getResourceAsStream("SHAKETestVectors.txt"))); + + String line; + while (null != (line = readLine(r))) + { + if (line.length() != 0) + { + TestVector v = readTestVector(r, line); + runTestVector(v); + } + } + + r.close(); + } + + private MySHAKEDigest createDigest(String algorithm) throws Exception + { + if (algorithm.startsWith("SHAKE-")) + { + int bits = parseDecimal(algorithm.substring("SHAKE-".length())); + return new MySHAKEDigest(bits); + } + throw new IllegalArgumentException("Unknown algorithm: " + algorithm); + } + + private byte[] decodeBinary(String block) + { + int bits = block.length(); + int fullBytes = bits / 8; + int totalBytes = (bits + 7) / 8; + byte[] result = new byte[totalBytes]; + + for (int i = 0; i < fullBytes; ++i) + { + String byteStr = reverse(block.substring(i * 8, (i + 1) * 8)); + result[i] = (byte)parseBinary(byteStr); + } + + if (totalBytes > fullBytes) + { + String byteStr = reverse(block.substring(fullBytes * 8)); + result[fullBytes] = (byte)parseBinary(byteStr); + } + + return result; + } + + private int parseBinary(String s) + { + return Integer.parseInt(s, 2); + } + + private int parseDecimal(String s) + { + return Integer.parseInt(s); + } + + private String readBlock(BufferedReader r) throws IOException + { + StringBuffer b = new StringBuffer(); + String line; + while ((line = readBlockLine(r)) != null) + { + b.append(line); + } + return b.toString(); + } + + private String readBlockLine(BufferedReader r) throws IOException + { + String line = readLine(r); + if (line == null || line.length() == 0) + { + return null; + } + + char[] chars = line.toCharArray(); + + int pos = 0; + for (int i = 0; i != chars.length; i++) + { + if (chars[i] != ' ') + { + chars[pos++] = chars[i]; + } + } + + return new String(chars, 0, pos); + } + + private TestVector readTestVector(BufferedReader r, String header) throws IOException + { + String[] parts = splitAround(header, TestVector.SAMPLE_OF); + + String algorithm = parts[0]; + int bits = parseDecimal(stripFromChar(parts[1], '-')); + + skipUntil(r, TestVector.MSG_HEADER); + String messageBlock = readBlock(r); + if (messageBlock.length() != bits) + { + throw new IllegalStateException("Test vector length mismatch"); + } + byte[] message = decodeBinary(messageBlock); + + skipUntil(r, TestVector.OUTPUT_HEADER); + byte[] output = Hex.decode(readBlock(r)); + + return new TestVector(algorithm, bits, message, output); + } + + private String readLine(BufferedReader r) throws IOException + { + String line = r.readLine(); + return line == null ? null : stripFromChar(line, '#').trim(); + } + + private String requireLine(BufferedReader r) throws IOException + { + String line = readLine(r); + if (line == null) + { + throw new EOFException(); + } + return line; + } + + private String reverse(String s) + { + return new StringBuffer(s).reverse().toString(); + } + + private void runTestVector(TestVector v) throws Exception + { + int bits = v.getBits(); + int partialBits = bits % 8; + + byte[] expected = v.getOutput(); + +// System.out.println(v.getAlgorithm() + " " + bits + "-bit"); +// System.out.println(Hex.toHexString(v.getMessage()).toUpperCase()); +// System.out.println(Hex.toHexString(expected).toUpperCase()); + + int outLen = expected.length; + + MySHAKEDigest d = createDigest(v.getAlgorithm()); + byte[] output = new byte[outLen]; + + byte[] m = v.getMessage(); + if (partialBits == 0) + { + d.update(m, 0, m.length); + d.doFinal(output, 0, outLen); + } + else + { + d.update(m, 0, m.length - 1); + d.myDoFinal(output, 0, outLen, m[m.length - 1], partialBits); + } + + if (!Arrays.areEqual(expected, output)) + { + fail(v.getAlgorithm() + " " + v.getBits() + "-bit test vector hash mismatch"); +// System.err.println(v.getAlgorithm() + " " + v.getBits() + "-bit test vector hash mismatch"); +// System.err.println(Hex.toHexString(output).toUpperCase()); + } + + if (partialBits == 0) + { + d = createDigest(v.getAlgorithm()); + + m = v.getMessage(); + + d.update(m, 0, m.length); + d.doOutput(output, 0, outLen / 2); + d.doOutput(output, outLen / 2, output.length - outLen / 2); + + if (!Arrays.areEqual(expected, output)) + { + fail(v.getAlgorithm() + " " + v.getBits() + "-bit test vector extended hash mismatch"); + } + + try + { + d.update((byte)0x01); + fail("no exception"); + } + catch (IllegalStateException e) + { + isTrue("wrong exception", "attempt to absorb while squeezing".equals(e.getMessage())); + } + + d = createDigest(v.getAlgorithm()); + + m = v.getMessage(); + + d.update(m, 0, m.length); + d.doOutput(output, 0, outLen / 2); + d.doFinal(output, outLen / 2, output.length - outLen / 2); + + if (!Arrays.areEqual(expected, output)) + { + fail(v.getAlgorithm() + " " + v.getBits() + "-bit test vector extended doFinal hash mismatch"); + } + + d.update((byte)0x01); // this should be okay as we've reset on doFinal() + } + } + + private void skipUntil(BufferedReader r, String header) throws IOException + { + String line; + do + { + line = requireLine(r); + } + while (line.length() == 0); + if (!line.equals(header)) + { + throw new IOException("Expected: " + header); + } + } + + private String[] splitAround(String s, String separator) + { + List strings = new ArrayList(); + + String remaining = s; + int index; + + while ((index = remaining.indexOf(separator)) > 0) + { + strings.add(remaining.substring(0, index)); + remaining = remaining.substring(index + separator.length()); + } + strings.add(remaining); + + return (String[])strings.toArray(new String[strings.size()]); + } + + private String stripFromChar(String s, char c) + { + int i = s.indexOf(c); + if (i >= 0) + { + s = s.substring(0, i); + } + return s; + } + + public static void main( + String[] args) + { + runTest(new SHAKEDigestTest()); + } + + private static class TestVector + { + private static String SAMPLE_OF = " sample of "; + private static String MSG_HEADER = "Msg as bit string"; + private static String OUTPUT_HEADER = "Output val is"; + + private String algorithm; + private int bits; + private byte[] message; + private byte[] output; + + private TestVector(String algorithm, int bits, byte[] message, byte[] output) + { + this.algorithm = algorithm; + this.bits = bits; + this.message = message; + this.output = output; + } + + public String getAlgorithm() + { + return algorithm; + } + + public int getBits() + { + return bits; + } + + public byte[] getMessage() + { + return message; + } + + public byte[] getOutput() + { + return output; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM2EngineTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM2EngineTest.java new file mode 100644 index 000000000..880f861ca --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM2EngineTest.java @@ -0,0 +1,248 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.SM2Engine; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; + +public class SM2EngineTest + extends SimpleTest +{ + public String getName() + { + return "SM2Engine"; + } + + private void doEngineTestFp() + throws Exception + { + BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); + BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); + BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); + BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_H = ECConstants.ONE; + BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); + BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); + + ECCurve curve = new ECCurve.Fp(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); + + ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0", 16)); + + keyPairGenerator.init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.getPublic(); + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.getPrivate(); + + SM2Engine sm2Engine = new SM2Engine(); + + byte[] m = Strings.toByteArray("encryption standard"); + + sm2Engine.init(true, new ParametersWithRandom(aPub, new TestRandomBigInteger("4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", 16))); + + byte[] enc = sm2Engine.processBlock(m, 0, m.length); + + isTrue("enc wrong", Arrays.areEqual(Hex.decode( + "04245C26 FB68B1DD DDB12C4B 6BF9F2B6 D5FE60A3 83B0D18D 1C4144AB F17F6252" + + "E776CB92 64C2A7E8 8E52B199 03FDC473 78F605E3 6811F5C0 7423A24B 84400F01" + + "B8650053 A89B41C4 18B0C3AA D00D886C 00286467 9C3D7360 C30156FA B7C80A02" + + "76712DA9 D8094A63 4B766D3A 285E0748 0653426D"), enc)); + + sm2Engine.init(false, aPriv); + + byte[] dec = sm2Engine.processBlock(enc, 0, enc.length); + + isTrue("dec wrong", Arrays.areEqual(m, dec)); + + enc[80] = (byte)(enc[80] + 1); + + try + { + sm2Engine.processBlock(enc, 0, enc.length); + fail("no exception"); + } + catch (InvalidCipherTextException e) + { + isTrue("wrong exception", "invalid cipher text".equals(e.getMessage())); + } + + // long message + sm2Engine = new SM2Engine(); + + m = new byte[4097]; + for (int i = 0; i != m.length; i++) + { + m[i] = (byte)i; + } + + sm2Engine.init(true, new ParametersWithRandom(aPub, new TestRandomBigInteger("4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", 16))); + + enc = sm2Engine.processBlock(m, 0, m.length); + + sm2Engine.init(false, aPriv); + + dec = sm2Engine.processBlock(enc, 0, enc.length); + + isTrue("dec wrong", Arrays.areEqual(m, dec)); + } + + private void doEngineTestFpC1C3C2() + throws Exception + { + BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); + BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); + BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); + BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_H = ECConstants.ONE; + BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); + BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); + + ECCurve curve = new ECCurve.Fp(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); + + ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0", 16)); + + keyPairGenerator.init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.getPublic(); + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.getPrivate(); + + SM2Engine sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2); + + byte[] m = Strings.toByteArray("encryption standard"); + + sm2Engine.init(true, new ParametersWithRandom(aPub, new TestRandomBigInteger("4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", 16))); + + byte[] enc = sm2Engine.processBlock(m, 0, m.length); + + isTrue("enc wrong", Arrays.areEqual(Hex.decode( + "04245C26 FB68B1DD DDB12C4B 6BF9F2B6 D5FE60A3 83B0D18D 1C4144AB F17F6252" + + "E776CB92 64C2A7E8 8E52B199 03FDC473 78F605E3 6811F5C0 7423A24B 84400F01" + + "B8 9C3D7360 C30156FA B7C80A02" + + "76712DA9 D8094A63 4B766D3A 285E0748 0653426D 650053 A89B41C4 18B0C3AA D00D886C 00286467"), enc)); + + sm2Engine.init(false, aPriv); + + byte[] dec = sm2Engine.processBlock(enc, 0, enc.length); + + isTrue("dec wrong", Arrays.areEqual(m, dec)); + + enc[80] = (byte)(enc[80] + 1); + + try + { + sm2Engine.processBlock(enc, 0, enc.length); + fail("no exception"); + } + catch (InvalidCipherTextException e) + { + isTrue("wrong exception", "invalid cipher text".equals(e.getMessage())); + } + + // long message + sm2Engine = new SM2Engine(SM2Engine.Mode.C1C3C2); + + m = new byte[4097]; + for (int i = 0; i != m.length; i++) + { + m[i] = (byte)i; + } + + sm2Engine.init(true, new ParametersWithRandom(aPub, new TestRandomBigInteger("4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", 16))); + + enc = sm2Engine.processBlock(m, 0, m.length); + + sm2Engine.init(false, aPriv); + + dec = sm2Engine.processBlock(enc, 0, enc.length); + + isTrue("dec wrong", Arrays.areEqual(m, dec)); + } + + private void doEngineTestF2m() + throws Exception + { + BigInteger SM2_ECC_A = new BigInteger("00", 16); + BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); + BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_H = BigInteger.valueOf(4); + BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); + BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); + + ECCurve curve = new ECCurve.F2m(257, 12, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); + + ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("56A270D17377AA9A367CFA82E46FA5267713A9B91101D0777B07FCE018C757EB", 16)); + + keyPairGenerator.init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.getPublic(); + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.getPrivate(); + + SM2Engine sm2Engine = new SM2Engine(); + + byte[] m = Strings.toByteArray("encryption standard"); + + sm2Engine.init(true, new ParametersWithRandom(aPub, new TestRandomBigInteger("6D3B497153E3E92524E5C122682DBDC8705062E20B917A5F8FCDB8EE4C66663D", 16))); + + byte[] enc = sm2Engine.processBlock(m, 0, m.length); + + isTrue("f2m enc wrong", Arrays.areEqual(Hex.decode( + "04019D23 6DDB3050 09AD52C5 1BB93270 9BD534D4 76FBB7B0 DF9542A8 A4D890A3" + + "F2E100B2 3B938DC0 A94D1DF8 F42CF45D 2D6601BF 638C3D7D E75A29F0 2AFB7E45" + + "E91771FD 55AC6213 C2A8A040 E4CAB5B2 6A9CFCDA 737373A4 8625D375 8FA37B3E" + + "AB80E9CF CABA665E 3199EA15 A1FA8189 D96F5791 25E4"), enc)); + + sm2Engine.init(false, aPriv); + + byte[] dec = sm2Engine.processBlock(enc, 0, enc.length); + + isTrue("f2m dec wrong", Arrays.areEqual(m, dec)); + } + + public void performTest() + throws Exception + { + doEngineTestFp(); + doEngineTestF2m(); + doEngineTestFpC1C3C2(); + } + + public static void main(String[] args) + { + runTest(new SM2EngineTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM2KeyExchangeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM2KeyExchangeTest.java new file mode 100644 index 000000000..34b54f173 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM2KeyExchangeTest.java @@ -0,0 +1,229 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.agreement.SM2KeyExchange; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithID; +import com.fr.third.org.bouncycastle.crypto.params.SM2KeyExchangePrivateParameters; +import com.fr.third.org.bouncycastle.crypto.params.SM2KeyExchangePublicParameters; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; + +public class SM2KeyExchangeTest + extends SimpleTest +{ + public String getName() + { + return "SM2KeyExchange"; + } + + private void doKeyExchangeTestFp() + throws Exception + { + BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); + BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); + BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); + BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_H = ECConstants.ONE; + BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); + BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); + + ECCurve curve = new ECCurve.Fp(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); + + ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("6FCBA2EF9AE0AB902BC3BDE3FF915D44BA4CC78F88E2F8E7F8996D3B8CCEEDEE", 16)); + + keyPairGenerator.init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.getPublic(); + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.getPrivate(); + + ECKeyGenerationParameters aeKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("83A2C9C8B96E5AF70BD480B472409A9A327257F1EBB73F5B073354B248668563", 16)); + + keyPairGenerator.init(aeKeyGenParams); + + AsymmetricCipherKeyPair aeKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters aePub = (ECPublicKeyParameters)aeKp.getPublic(); + ECPrivateKeyParameters aePriv = (ECPrivateKeyParameters)aeKp.getPrivate(); + + ECKeyGenerationParameters bKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("5E35D7D3F3C54DBAC72E61819E730B019A84208CA3A35E4C2E353DFCCB2A3B53", 16)); + + keyPairGenerator.init(bKeyGenParams); + + AsymmetricCipherKeyPair bKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters bPub = (ECPublicKeyParameters)bKp.getPublic(); + ECPrivateKeyParameters bPriv = (ECPrivateKeyParameters)bKp.getPrivate(); + + ECKeyGenerationParameters beKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("33FE21940342161C55619C4A0C060293D543C80AF19748CE176D83477DE71C80", 16)); + + keyPairGenerator.init(beKeyGenParams); + + AsymmetricCipherKeyPair beKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters bePub = (ECPublicKeyParameters)beKp.getPublic(); + ECPrivateKeyParameters bePriv = (ECPrivateKeyParameters)beKp.getPrivate(); + + SM2KeyExchange exch = new SM2KeyExchange(); + + exch.init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.toByteArray("ALICE123@YAHOO.COM"))); + + byte[] k1 = exch.calculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.toByteArray("BILL456@YAHOO.COM"))); + + isTrue("key 1 wrong", Arrays.areEqual(Hex.decode("55b0ac62a6b927ba23703832c853ded4"), k1)); + + exch = new SM2KeyExchange(); + + exch.init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.toByteArray("BILL456@YAHOO.COM"))); + + byte[] k2 = exch.calculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.toByteArray("ALICE123@YAHOO.COM"))); + + isTrue("key 2 wrong", Arrays.areEqual(Hex.decode("55b0ac62a6b927ba23703832c853ded4"), k2)); + + // with key confirmation + exch = new SM2KeyExchange(); + + exch.init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.toByteArray("BILL456@YAHOO.COM"))); + + byte[][] vals2 = exch.calculateKeyWithConfirmation(128, null, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.toByteArray("ALICE123@YAHOO.COM"))); + + isTrue("key 2 wrong", Arrays.areEqual(Hex.decode("55b0ac62a6b927ba23703832c853ded4"), k2)); + + isTrue("conf a tag 2 wrong", Arrays.areEqual(Hex.decode("284C8F198F141B502E81250F1581C7E9EEB4CA6990F9E02DF388B45471F5BC5C"), vals2[1])); + isTrue("conf b tag 2 wrong", Arrays.areEqual(Hex.decode("23444DAF8ED7534366CB901C84B3BDBB63504F4065C1116C91A4C00697E6CF7A"), vals2[2])); + + exch = new SM2KeyExchange(); + + exch.init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.toByteArray("ALICE123@YAHOO.COM"))); + + byte[][] vals1 = exch.calculateKeyWithConfirmation(128, vals2[1], new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.toByteArray("BILL456@YAHOO.COM"))); + + isTrue("conf key 1 wrong", Arrays.areEqual(Hex.decode("55b0ac62a6b927ba23703832c853ded4"), vals1[0])); + isTrue("conf tag 1 wrong", Arrays.areEqual(Hex.decode("23444DAF8ED7534366CB901C84B3BDBB63504F4065C1116C91A4C00697E6CF7A"), vals1[1])); + } + + private void doKeyExchangeTestF2m() + throws Exception + { + BigInteger SM2_ECC_A = new BigInteger("00", 16); + BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); + BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_H = BigInteger.valueOf(4); + BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); + BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); + + ECCurve curve = new ECCurve.F2m(257, 12, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); + + ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H); + + ECKeyPairGenerator keyPairGenerator = new ECKeyPairGenerator(); + + ECKeyGenerationParameters aKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("4813903D254F2C20A94BC5704238496954BB5279F861952EF2C5298E84D2CEAA", 16)); + + keyPairGenerator.init(aKeyGenParams); + + AsymmetricCipherKeyPair aKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters aPub = (ECPublicKeyParameters)aKp.getPublic(); + ECPrivateKeyParameters aPriv = (ECPrivateKeyParameters)aKp.getPrivate(); + + ECKeyGenerationParameters aeKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("54A3D6673FF3A6BD6B02EBB164C2A3AF6D4A4906229D9BFCE68CC366A2E64BA4", 16)); + + keyPairGenerator.init(aeKeyGenParams); + + AsymmetricCipherKeyPair aeKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters aePub = (ECPublicKeyParameters)aeKp.getPublic(); + ECPrivateKeyParameters aePriv = (ECPrivateKeyParameters)aeKp.getPrivate(); + + ECKeyGenerationParameters bKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("08F41BAE0922F47C212803FE681AD52B9BF28A35E1CD0EC273A2CF813E8FD1DC", 16)); + + keyPairGenerator.init(bKeyGenParams); + + AsymmetricCipherKeyPair bKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters bPub = (ECPublicKeyParameters)bKp.getPublic(); + ECPrivateKeyParameters bPriv = (ECPrivateKeyParameters)bKp.getPrivate(); + + ECKeyGenerationParameters beKeyGenParams = new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger("1F21933387BEF781D0A8F7FD708C5AE0A56EE3F423DBC2FE5BDF6F068C53F7AD", 16)); + + keyPairGenerator.init(beKeyGenParams); + + AsymmetricCipherKeyPair beKp = keyPairGenerator.generateKeyPair(); + + ECPublicKeyParameters bePub = (ECPublicKeyParameters)beKp.getPublic(); + ECPrivateKeyParameters bePriv = (ECPrivateKeyParameters)beKp.getPrivate(); + + SM2KeyExchange exch = new SM2KeyExchange(); + + exch.init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.toByteArray("ALICE123@YAHOO.COM"))); + + byte[] k1 = exch.calculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.toByteArray("BILL456@YAHOO.COM"))); + + // there appears to be typo for ZA in the draft + //isTrue("F2m key 1 wrong", Arrays.areEqual(Hex.decode("4E587E5C66634F22D973A7D98BF8BE23"), k1)); + isTrue("F2m key 1 wrong", Arrays.areEqual(Hex.decode("8c2b03289aa7126555dc660cfc29fd74"), k1)); + + exch = new SM2KeyExchange(); + + exch.init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.toByteArray("BILL456@YAHOO.COM"))); + + byte[] k2 = exch.calculateKey(128, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.toByteArray("ALICE123@YAHOO.COM"))); + + //isTrue("F2m key 2 wrong", Arrays.areEqual(Hex.decode("4E587E5C66634F22D973A7D98BF8BE23"), k2)); + isTrue("F2m key 2 wrong", Arrays.areEqual(Hex.decode("8c2b03289aa7126555dc660cfc29fd74"), k2)); + + // with key confirmation + exch = new SM2KeyExchange(); + + exch.init(new ParametersWithID(new SM2KeyExchangePrivateParameters(false, bPriv, bePriv), Strings.toByteArray("BILL456@YAHOO.COM"))); + + byte[][] vals2 = exch.calculateKeyWithConfirmation(128, null, new ParametersWithID(new SM2KeyExchangePublicParameters(aPub, aePub), Strings.toByteArray("ALICE123@YAHOO.COM"))); + + isTrue("key 2 wrong", Arrays.areEqual(Hex.decode("8c2b03289aa7126555dc660cfc29fd74"), k2)); + + isTrue("conf a tag 2 wrong", Arrays.areEqual(Hex.decode("d8294c4c0f0ac180feac95e8a0d786638c9e915b9a684b2348809af03a0de2a5"), vals2[1])); + isTrue("conf b tag 2 wrong", Arrays.areEqual(Hex.decode("52089e706911b58fd5e7c7b2ab5cf32bb61e481ef1e114a1e33d99eec84b5a4f"), vals2[2])); + + exch = new SM2KeyExchange(); + + exch.init(new ParametersWithID(new SM2KeyExchangePrivateParameters(true, aPriv, aePriv), Strings.toByteArray("ALICE123@YAHOO.COM"))); + + byte[][] vals1 = exch.calculateKeyWithConfirmation(128, vals2[1], new ParametersWithID(new SM2KeyExchangePublicParameters(bPub, bePub), Strings.toByteArray("BILL456@YAHOO.COM"))); + + isTrue("conf key 1 wrong", Arrays.areEqual(Hex.decode("8c2b03289aa7126555dc660cfc29fd74"), vals1[0])); + isTrue("conf tag 1 wrong", Arrays.areEqual(Hex.decode("52089e706911b58fd5e7c7b2ab5cf32bb61e481ef1e114a1e33d99eec84b5a4f"), vals1[1])); + } + + public void performTest() + throws Exception + { + doKeyExchangeTestFp(); + doKeyExchangeTestF2m(); + } + + public static void main(String[] args) + { + runTest(new SM2KeyExchangeTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM2SignerTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM2SignerTest.java new file mode 100644 index 000000000..89db8596a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM2SignerTest.java @@ -0,0 +1,280 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.IOException; +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SM3Digest; +import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithID; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.signers.SM2Signer; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; + +public class SM2SignerTest + extends SimpleTest +{ + private static final ECDomainParameters PARAMS_FP_DRAFT = createParamsFpDraft(); + private static final ECDomainParameters PARAMS_F2M = createParamsF2m(); + + public String getName() + { + return "SM2Signer"; + } + + private void doSignerTestFpDraftSM3() + throws Exception + { + doSignerTest( + PARAMS_FP_DRAFT, + new SM3Digest(), + "ALICE123@YAHOO.COM", + "message digest", + "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263", + "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F", + "40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1", + "6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7" + ); + } + + private void doSignerTestFpDraftSha256() + throws Exception + { + doSignerTest( + PARAMS_FP_DRAFT, + new SHA256Digest(), + "ALICE123@YAHOO.COM", + "message digest", + "128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263", + "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F", + "7D62A5EDBDDC8AF4D69C9E37A60D31F5CEFE8727709117E0869648D0A9AE4F57", + "1E5E89718B716AAFC6253443168E4F7CF7E1B7B3934307686CE5947C1BD55EDA" + ); + } + + private void doSignerTestFpStandardSM3() + throws Exception + { + doSignerTest( + "sm2p256v1", + new SM3Digest(), + "sm2test@example.com", + "hi chappy", + "110E7973206F68C19EE5F7328C036F26911C8C73B4E4F36AE3291097F8984FFC", + "3174C6FFC3C279D2422F3FC0A9F3E574674A4490FE45A5325CAF7D3EC4C8F96C", + "05890B9077B92E47B17A1FF42A814280E556AFD92B4A98B9670BF8B1A274C2FA", + "E3ABBB8DB2B6ECD9B24ECCEA7F679FB9A4B1DB52F4AA985E443AD73237FA1993" + ); + } + + private void doSignerTestFpStandardSha256() + throws Exception + { + doSignerTest( + "sm2p256v1", + new SHA256Digest(), + "sm2test@example.com", + "hi chappy", + "110E7973206F68C19EE5F7328C036F26911C8C73B4E4F36AE3291097F8984FFC", + "3174C6FFC3C279D2422F3FC0A9F3E574674A4490FE45A5325CAF7D3EC4C8F96C", + "94DA20EA69E4FC70692158BF3D30F87682A4B2F84DF4A4829A1EFC5D9C979D3F", + "EE15AF8D455B728AB80E592FCB654BF5B05620B2F4D25749D263D5C01FAD365F" + ); + } + + private void doSignerTestFpP256SM3() + throws Exception + { + doSignerTest( + "P-256", + new SM3Digest(), + "sm2_p256_test@example.com", + "no backdoors here", + "110E7973206F68C19EE5F7328C036F26911C8C73B4E4F36AE3291097F8984FFC", + "3174C6FFC3C279D2422F3FC0A9F3E574674A4490FE45A5325CAF7D3EC4C8F96C", + "96AA39A0C4A5C454653F394E86386F2E38BE14C57D0E555F3A27A5CEF30E51BD", + "62372BE4AC97DBE725AC0B279BB8FD15883858D814FD792DDB0A401DCC988E70" + ); + } + + private void doSignerTestFpP256Sha256() + throws Exception + { + doSignerTest( + "P-256", + new SHA256Digest(), + "sm2_p256_test@example.com", + "no backdoors here", + "110E7973206F68C19EE5F7328C036F26911C8C73B4E4F36AE3291097F8984FFC", + "3174C6FFC3C279D2422F3FC0A9F3E574674A4490FE45A5325CAF7D3EC4C8F96C", + "503D234A22123D7029271EB9E0D763619A69868DE8296C13EDD4CA32D280CFDE", + "0BDE97699B77268584DDD238DA120095F01130AD2DB37184270F37C02FB2E86B" + ); + } + + private void doSignerTestF2m() + throws Exception + { + doSignerTest( + PARAMS_F2M, + new SM3Digest(), + "ALICE123@YAHOO.COM", + "message digest", + "771EF3DBFF5F1CDC32B9C572930476191998B2BF7CB981D7F5B39202645F0931", + "36CD79FC8E24B7357A8A7B4A46D454C397703D6498158C605399B341ADA186D6", + "6D3FBA26EAB2A1054F5D198332E335817C8AC453ED26D3391CD4439D825BF25B", + "3124C5688D95F0A10252A9BED033BEC84439DA384621B6D6FAD77F94B74A9556" + ); + } + + private void doSignerTest(String curveName, Digest d, String ident, String msg, String x, String nonce, String r, String s) + throws Exception + { + X9ECParameters x9 = ECNamedCurveTable.getByName(curveName); + ECDomainParameters domainParams = new ECDomainParameters(x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); + + doSignerTest(domainParams, d, ident, msg, x, nonce, r, s); + } + + private void doSignerTest(ECDomainParameters domainParams, Digest d, String ident, String msg, String x, String nonce, String r, String s) + throws Exception + { + byte[] idBytes = Strings.toByteArray(ident); + byte[] msgBytes = Strings.toByteArray(msg); + AsymmetricCipherKeyPair kp = generateKeyPair(domainParams, x); + + SM2Signer signer = new SM2Signer(d); + + signer.init(true, new ParametersWithID( + new ParametersWithRandom(kp.getPrivate(), new TestRandomBigInteger(nonce, 16)), + idBytes)); + + signer.update(msgBytes, 0, msgBytes.length); + + byte[] sig = signer.generateSignature(); + + BigInteger[] rs = decode(sig); + + isTrue("r wrong", rs[0].equals(new BigInteger(r, 16))); + isTrue("s wrong", rs[1].equals(new BigInteger(s, 16))); + + signer.init(false, new ParametersWithID(kp.getPublic(), idBytes)); + + signer.update(msgBytes, 0, msgBytes.length); + + isTrue("verification failed", signer.verifySignature(sig)); + } + + private void doVerifyBoundsCheck() + throws IOException + { + ECDomainParameters domainParams = PARAMS_F2M; + + AsymmetricCipherKeyPair kp = generateKeyPair(domainParams, "771EF3DBFF5F1CDC32B9C572930476191998B2BF7CB981D7F5B39202645F0931"); + + SM2Signer signer = new SM2Signer(); + + signer.init(false, kp.getPublic()); + + signer.update(new byte[20], 0, 20); + isTrue(!signer.verifySignature(encode(ECConstants.ZERO, ECConstants.EIGHT))); + + signer.update(new byte[20], 0, 20); + isTrue(!signer.verifySignature(encode(ECConstants.EIGHT, ECConstants.ZERO))); + + signer.update(new byte[20], 0, 20); + isTrue(!signer.verifySignature(encode(domainParams.getN(), ECConstants.EIGHT))); + + signer.update(new byte[20], 0, 20); + isTrue(!signer.verifySignature(encode(ECConstants.EIGHT, domainParams.getN()))); + } + + public void performTest() + throws Exception + { + doSignerTestFpDraftSM3(); + doSignerTestFpDraftSha256(); + doSignerTestFpStandardSM3(); + doSignerTestFpStandardSha256(); + doSignerTestFpP256SM3(); + doSignerTestFpP256Sha256(); + doSignerTestF2m(); + doVerifyBoundsCheck(); + } + + private static ECDomainParameters createParamsFpDraft() + { + BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); + BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); + BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); + BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_H = ECConstants.ONE; + BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); + BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); + + ECCurve curve = new ECCurve.Fp(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); + ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY); + return new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H); + } + + private static ECDomainParameters createParamsF2m() + { + BigInteger SM2_ECC_A = new BigInteger("00", 16); + BigInteger SM2_ECC_B = new BigInteger("E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B", 16); + BigInteger SM2_ECC_N = new BigInteger("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFBC972CF7E6B6F900945B3C6A0CF6161D", 16); + BigInteger SM2_ECC_H = BigInteger.valueOf(4); + BigInteger SM2_ECC_GX = new BigInteger("00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD", 16); + BigInteger SM2_ECC_GY = new BigInteger("013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E", 16); + + ECCurve curve = new ECCurve.F2m(257, 12, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); + ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY); + return new ECDomainParameters(curve, g, SM2_ECC_N, SM2_ECC_H); + } + + private static BigInteger[] decode(byte[] sig) + { + ASN1Sequence s = ASN1Sequence.getInstance(sig); + + return new BigInteger[] { + decodeValue(s.getObjectAt(0)), + decodeValue(s.getObjectAt(1)) }; + } + + private static BigInteger decodeValue(ASN1Encodable e) + { + return ASN1Integer.getInstance(e).getValue(); + } + + private static byte[] encode(BigInteger r, BigInteger s) + throws IOException + { + return new DERSequence(new ASN1Encodable[] { new ASN1Integer(r), new ASN1Integer(s)}).getEncoded(); + } + + private static AsymmetricCipherKeyPair generateKeyPair(ECDomainParameters domainParams, String x) + { + ECKeyPairGenerator kpg = new ECKeyPairGenerator(); + kpg.init(new ECKeyGenerationParameters(domainParams, new TestRandomBigInteger(x, 16))); + return kpg.generateKeyPair(); + } + + public static void main(String[] args) + { + runTest(new SM2SignerTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM3DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM3DigestTest.java new file mode 100644 index 000000000..df788378b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM3DigestTest.java @@ -0,0 +1,197 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SM3Digest; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +/** + * standard vector test for SM3 digest from chinese specification + */ +public class SM3DigestTest + extends DigestTest +{ + private static String[] messages = { + // Standard test vectors + "abc", + "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd", + // Non-standard test vectors + "", + "a", + "abcdefghijklmnopqrstuvwxyz", + }; + + private static String[] hexMessages = { + /* 2 p.57 ZA */ + "0090" + + "414C494345313233405941484F4F2E434F4D" + + "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498" + + "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A" + + "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D" + + "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2" + + "0AE4C7798AA0F119471BEE11825BE46202BB79E2A5844495E97C04FF4DF2548A" + + "7C0240F88F1CD4E16352A73C17B7F16F07353E53A176D684A9FE0C6BB798E857", + /* 3 p.59 ZA */ + "0090" + + "414C494345313233405941484F4F2E434F4D" + + "000000000000000000000000000000000000000000000000000000000000000000" + + "00E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B" + + "00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD" + + "013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E" + + "0165961645281A8626607B917F657D7E9382F1EA5CD931F40F6627F357542653B2" + + "01686522130D590FB8DE635D8FCA715CC6BF3D05BEF3F75DA5D543454448166612", + /* 4 p.72 ZA */ + "0090" + + "414C494345313233405941484F4F2E434F4D" + + "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498" + + "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A" + + "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D" + + "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2" + + "3099093BF3C137D8FCBBCDF4A2AE50F3B0F216C3122D79425FE03A45DBFE1655" + + "3DF79E8DAC1CF0ECBAA2F2B49D51A4B387F2EFAF482339086A27A8E05BAED98B", + /* 5 p.72 ZB */ + "0088" + + "42494C4C343536405941484F4F2E434F4D" + + "787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498" + + "63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A" + + "421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D" + + "0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2" + + "245493D446C38D8CC0F118374690E7DF633A8A4BFB3329B5ECE604B2B4F37F43" + + "53C0869F4B9E17773DE68FEC45E14904E0DEA45BF6CECF9918C85EA047C60A4C", + /* 6 p.75 ZA */ + "0090" + + "414C494345313233405941484F4F2E434F4D" + + "000000000000000000000000000000000000000000000000000000000000000000" + + "00E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B" + + "00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD" + + "013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E" + + "008E3BDB2E11F9193388F1F901CCC857BF49CFC065FB38B9069CAAE6D5AFC3592F" + + "004555122AAC0075F42E0A8BBD2C0665C789120DF19D77B4E3EE4712F598040415", + /* 7 p.76 ZB */ + "0088" + + "42494C4C343536405941484F4F2E434F4D" + + "000000000000000000000000000000000000000000000000000000000000000000" + + "00E78BCD09746C202378A7E72B12BCE00266B9627ECB0B5A25367AD1AD4CC6242B" + + "00CDB9CA7F1E6B0441F658343F4B10297C0EF9B6491082400A62E7A7485735FADD" + + "013DE74DA65951C4D76DC89220D5F7777A611B1C38BAE260B175951DC8060C2B3E" + + "0034297DD83AB14D5B393B6712F32B2F2E938D4690B095424B89DA880C52D4A7D9" + + "0199BBF11AC95A0EA34BBD00CA50B93EC24ACB68335D20BA5DCFE3B33BDBD2B62D", + /* 8 TopsecCA cert ZA */ + "0080" + + "31323334353637383132333435363738" + + "FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC" + + "28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93" + + "32C4AE2C1F1981195F9904466A39C9948FE30BBFF2660BE1715A4589334C74C7" + + "BC3736A2F4F6779C59BDCEE36B692153D0A9877CC62A474002DF32E52139F0A0" + + "D69C2F1EEC3BFB6B95B30C28085C77B125D77A9C39525D8190768F37D6B205B5" + + "89DCD316BBE7D89A9DC21917F17799E698531F5E6E3E10BD31370B259C3F81C3", + /* 9 */ + "4D38D2958CA7FD2CFAE3AF04486959CF92C8EF48E8B83A05C112E739D5F181D0" + + "3082020CA003020102020900" + + "AF28725D98D33143300C06082A811CCF" + + "550183750500307D310B300906035504" + + "060C02636E310B300906035504080C02" + + "626A310B300906035504070C02626A31" + + "0F300D060355040A0C06746F70736563" + + "310F300D060355040B0C06746F707365" + + "633111300F06035504030C08546F7073" + + "65634341311F301D06092A864886F70D" + + "0109010C10626A40746F707365632E63" + + "6F6D2E636E301E170D31323036323430" + + "37353433395A170D3332303632303037" + + "353433395A307D310B30090603550406" + + "0C02636E310B300906035504080C0262" + + "6A310B300906035504070C02626A310F" + + "300D060355040A0C06746F7073656331" + + "0F300D060355040B0C06746F70736563" + + "3111300F06035504030C08546F707365" + + "634341311F301D06092A864886F70D01" + + "09010C10626A40746F707365632E636F" + + "6D2E636E3059301306072A8648CE3D02" + + "0106082A811CCF5501822D03420004D6" + + "9C2F1EEC3BFB6B95B30C28085C77B125" + + "D77A9C39525D8190768F37D6B205B589" + + "DCD316BBE7D89A9DC21917F17799E698" + + "531F5E6E3E10BD31370B259C3F81C3A3" + + "733071300F0603551D130101FF040530" + + "030101FF301D0603551D0E041604148E" + + "5D90347858BAAAD870D8BDFBA6A85E7B" + + "563B64301F0603551D23041830168014" + + "8E5D90347858BAAAD870D8BDFBA6A85E" + + "7B563B64300B0603551D0F0404030201" + + "06301106096086480186F84201010404" + + "03020057", + }; + + private static String[] digests = { + // Standard test vectors + "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0", + "debe9ff92275b8a138604889c18e5a4d6fdb70e5387e5765293dcba39c0c5732", + // Non-standard test vectors + "1ab21d8355cfa17f8e61194831e81a8f22bec8c728fefb747ed035eb5082aa2b", + "623476ac18f65a2909e43c7fec61b49c7e764a91a18ccb82f1917a29c86c5e88", + "b80fe97a4da24afc277564f66a359ef440462ad28dcc6d63adb24d5c20a61595", + // Additional vectors for GMSSL + "F4A38489E32B45B6F876E3AC2168CA392362DC8F23459C1D1146FC3DBFB7BC9A", + "26352AF82EC19F207BBC6F9474E11E90CE0F7DDACE03B27F801817E897A81FD5", + "E4D1D0C3CA4C7F11BC8FF8CB3F4C02A78F108FA098E51A668487240F75E20F31", + "6B4B6D0E276691BD4A11BF72F4FB501AE309FDACB72FA6CC336E6656119ABD67", + "329c2f6030cc7e0ca3af6c97b76243ca250338ad3d3dc3a8b322d1cfdf98c2b7", // original appears wrong -> "ECF0080215977B2E5D6D61B98A99442F03E8803DC39E349F8DCA5621A9ACDF2B", + "557BAD30E183559AEEC3B2256E1C7C11F870D22B165D015ACF9465B09B87B527", + "4D38D2958CA7FD2CFAE3AF04486959CF92C8EF48E8B83A05C112E739D5F181D0", + "C3B02E500A8B60B77DEDCF6F4C11BEF8D56E5CDE708C72065654FD7B2167915A", + }; + + final static String sixtyFourKdigest = "97049bdc8f0736bc7300eafa9980aeb9cf00f24f7ec3a8f1f8884954d7655c1d"; + final static String million_a_digest = "c8aaf89429554029e231941a2acc0ad61ff2a5acd8fadd25847a3a732b3b02c3"; + + SM3DigestTest() + { + super(new SM3Digest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + SM3Digest dig = new SM3Digest(); + byte[] resBuf = new byte[dig.getDigestSize()]; + + vectorTest(dig, 10, resBuf, Hex.decode(hexMessages[0]), Hex.decode(digests[messages.length])); + vectorTest(dig, 11, resBuf, Hex.decode(hexMessages[1]), Hex.decode(digests[messages.length + 1])); + vectorTest(dig, 12, resBuf, Hex.decode(hexMessages[2]), Hex.decode(digests[messages.length + 2])); + vectorTest(dig, 13, resBuf, Hex.decode(hexMessages[3]), Hex.decode(digests[messages.length + 3])); + vectorTest(dig, 14, resBuf, Hex.decode(hexMessages[4]), Hex.decode(digests[messages.length + 4])); + vectorTest(dig, 15, resBuf, Hex.decode(hexMessages[5]), Hex.decode(digests[messages.length + 5])); + vectorTest(dig, 16, resBuf, Hex.decode(hexMessages[6]), Hex.decode(digests[messages.length + 6])); + vectorTest(dig, 17, resBuf, Hex.decode(hexMessages[7]), Hex.decode(digests[messages.length + 7])); + + sixtyFourKTest(sixtyFourKdigest); + millionATest(million_a_digest); + } + + private void vectorTest( + Digest digest, + int count, + byte[] resBuf, + byte[] input, + byte[] expected) + { + digest.update(input, 0, input.length); + digest.doFinal(resBuf, 0); + + if (!areEqual(resBuf, expected)) + { + fail("Vector " + count + " failed got " + new String(Hex.encode(resBuf))); + } + } + + protected Digest cloneDigest(Digest digest) + { + return new SM3Digest((SM3Digest)digest); + } + + public static void main(String[] args) + { + runTest(new SM3DigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM4Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM4Test.java new file mode 100644 index 000000000..2661c56fc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SM4Test.java @@ -0,0 +1,81 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.engines.SM4Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * SM4 tester, vectors from http://eprint.iacr.org/2008/329.pdf + */ +public class SM4Test + extends CipherTest +{ + static SimpleTest[] tests = { + new BlockCipherVectorTest(0, new SM4Engine(), + new KeyParameter(Hex.decode("0123456789abcdeffedcba9876543210")), + "0123456789abcdeffedcba9876543210", + "681edf34d206965e86b3e94f536e4246") + }; + + SM4Test() + { + super(tests, new SM4Engine(), new KeyParameter(new byte[16])); + } + + public void performTest() + throws Exception + { + super.performTest(); + + test1000000(); + } + + private void test1000000() + { + byte[] plain = Hex.decode("0123456789abcdeffedcba9876543210"); + byte[] key = Hex.decode("0123456789abcdeffedcba9876543210"); + byte[] cipher = Hex.decode("595298c7c6fd271f0402f804c33d3f66"); + byte[] buf = new byte[16]; + + BlockCipher engine = new SM4Engine(); + + engine.init(true, new KeyParameter(key)); + + System.arraycopy(plain, 0, buf, 0, buf.length); + + for (int i = 0; i != 1000000; i++) + { + engine.processBlock(buf, 0, buf, 0); + } + + if (!areEqual(cipher, buf)) + { + fail("1000000 encryption test failed"); + } + + engine.init(false, new KeyParameter(key)); + + for (int i = 0; i != 1000000; i++) + { + engine.processBlock(buf, 0, buf, 0); + } + + if (!areEqual(plain, buf)) + { + fail("1000000 decryption test failed"); + } + } + + public String getName() + { + return "SM4"; + } + + public static void main( + String[] args) + { + runTest(new SM4Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SRP6Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SRP6Test.java new file mode 100644 index 000000000..20274fc47 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SRP6Test.java @@ -0,0 +1,267 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.CryptoException; +import com.fr.third.org.bouncycastle.crypto.agreement.srp.SRP6Client; +import com.fr.third.org.bouncycastle.crypto.agreement.srp.SRP6Server; +import com.fr.third.org.bouncycastle.crypto.agreement.srp.SRP6StandardGroups; +import com.fr.third.org.bouncycastle.crypto.agreement.srp.SRP6Util; +import com.fr.third.org.bouncycastle.crypto.agreement.srp.SRP6VerifierGenerator; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.generators.DHParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.params.DHParameters; +import com.fr.third.org.bouncycastle.crypto.params.SRP6GroupParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SRP6Test extends SimpleTest +{ + private static final BigInteger ZERO = BigInteger.valueOf(0); + + private static BigInteger fromHex(String hex) + { + return new BigInteger(1, Hex.decode(hex)); + } + + private final SecureRandom random = new SecureRandom(); + + public String getName() + { + return "SRP6"; + } + + public void performTest() throws Exception + { + rfc5054AppendixBTestVectors(); + + testMutualVerification(SRP6StandardGroups.rfc5054_1024); + testClientCatchesBadB(SRP6StandardGroups.rfc5054_1024); + testServerCatchesBadA(SRP6StandardGroups.rfc5054_1024); + + testWithRandomParams(256); + testWithRandomParams(384); + testWithRandomParams(512); + } + + private void rfc5054AppendixBTestVectors() throws Exception + { + byte[] I = "alice".getBytes("UTF8"); + byte[] P = "password123".getBytes("UTF8"); + byte[] s = Hex.decode("BEB25379D1A8581EB5A727673A2441EE"); + BigInteger N = SRP6StandardGroups.rfc5054_1024.getN(); + BigInteger g = SRP6StandardGroups.rfc5054_1024.getG(); + BigInteger a = fromHex("60975527035CF2AD1989806F0407210BC81EDC04E2762A56AFD529DDDA2D4393"); + BigInteger b = fromHex("E487CB59D31AC550471E81F00F6928E01DDA08E974A004F49E61F5D105284D20"); + + BigInteger expect_k = fromHex("7556AA045AEF2CDD07ABAF0F665C3E818913186F"); + BigInteger expect_x = fromHex("94B7555AABE9127CC58CCF4993DB6CF84D16C124"); + BigInteger expect_v = fromHex("7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D812" + + "9BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5" + + "C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5" + + "EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78" + + "E955A5E29E7AB245DB2BE315E2099AFB"); + BigInteger expect_A = fromHex("61D5E490F6F1B79547B0704C436F523DD0E560F0C64115BB72557EC4" + + "4352E8903211C04692272D8B2D1A5358A2CF1B6E0BFCF99F921530EC" + + "8E39356179EAE45E42BA92AEACED825171E1E8B9AF6D9C03E1327F44" + + "BE087EF06530E69F66615261EEF54073CA11CF5858F0EDFDFE15EFEA" + + "B349EF5D76988A3672FAC47B0769447B"); + BigInteger expect_B = fromHex("BD0C61512C692C0CB6D041FA01BB152D4916A1E77AF46AE105393011" + + "BAF38964DC46A0670DD125B95A981652236F99D9B681CBF87837EC99" + + "6C6DA04453728610D0C6DDB58B318885D7D82C7F8DEB75CE7BD4FBAA" + + "37089E6F9C6059F388838E7A00030B331EB76840910440B1B27AAEAE" + + "EB4012B7D7665238A8E3FB004B117B58"); + BigInteger expect_u = fromHex("CE38B9593487DA98554ED47D70A7AE5F462EF019"); + BigInteger expect_S = fromHex("B0DC82BABCF30674AE450C0287745E7990A3381F63B387AAF271A10D" + + "233861E359B48220F7C4693C9AE12B0A6F67809F0876E2D013800D6C" + + "41BB59B6D5979B5C00A172B4A2A5903A0BDCAF8A709585EB2AFAFA8F" + + "3499B200210DCC1F10EB33943CD67FC88A2F39A4BE5BEC4EC0A3212D" + + "C346D7E474B29EDE8A469FFECA686E5A"); + + BigInteger k = SRP6Util.calculateK(new SHA1Digest(), N, g); + if (!k.equals(expect_k)) + { + fail("wrong value of 'k'"); + } + + BigInteger x = SRP6Util.calculateX(new SHA1Digest(), N, s, I, P); + if (!x.equals(expect_x)) + { + fail("wrong value of 'x'"); + } + + SRP6VerifierGenerator gen = new SRP6VerifierGenerator(); + gen.init(N, g, new SHA1Digest()); + BigInteger v = gen.generateVerifier(s, I, P); + if (!v.equals(expect_v)) + { + fail("wrong value of 'v'"); + } + + final BigInteger aVal = a; + SRP6Client client = new SRP6Client() + { + protected BigInteger selectPrivateValue() + { + return aVal; + } + }; + client.init(N, g, new SHA1Digest(), random); + + BigInteger A = client.generateClientCredentials(s, I, P); + if (!A.equals(expect_A)) + { + fail("wrong value of 'A'"); + } + + final BigInteger bVal = b; + SRP6Server server = new SRP6Server() + { + protected BigInteger selectPrivateValue() + { + return bVal; + } + }; + server.init(N, g, v, new SHA1Digest(), random); + + BigInteger B = server.generateServerCredentials(); + if (!B.equals(expect_B)) + { + fail("wrong value of 'B'"); + } + + BigInteger u = SRP6Util.calculateU(new SHA1Digest(), N, A, B); + if (!u.equals(expect_u)) + { + fail("wrong value of 'u'"); + } + + BigInteger clientS = client.calculateSecret(B); + if (!clientS.equals(expect_S)) + { + fail("wrong value of 'S' (client)"); + } + + BigInteger serverS = server.calculateSecret(A); + if (!serverS.equals(expect_S)) + { + fail("wrong value of 'S' (server)"); + } + } + + private void testWithRandomParams(int bits) throws CryptoException + { + DHParametersGenerator paramGen = new DHParametersGenerator(); + paramGen.init(bits, 25, random); + DHParameters parameters = paramGen.generateParameters(); + + testMutualVerification(new SRP6GroupParameters(parameters.getP(), parameters.getG())); + } + + private void testMutualVerification(SRP6GroupParameters group) throws CryptoException + { + byte[] I = "username".getBytes(); + byte[] P = "password".getBytes(); + byte[] s = new byte[16]; + random.nextBytes(s); + + SRP6VerifierGenerator gen = new SRP6VerifierGenerator(); + gen.init(group, new SHA256Digest()); + BigInteger v = gen.generateVerifier(s, I, P); + + SRP6Client client = new SRP6Client(); + client.init(group, new SHA256Digest(), random); + + SRP6Server server = new SRP6Server(); + server.init(group, v, new SHA256Digest(), random); + + BigInteger A = client.generateClientCredentials(s, I, P); + BigInteger B = server.generateServerCredentials(); + + BigInteger clientS = client.calculateSecret(B); + BigInteger serverS = server.calculateSecret(A); + + if (!clientS.equals(serverS)) + { + fail("SRP agreement failed - client/server calculated different secrets"); + } + } + + private void testClientCatchesBadB(SRP6GroupParameters group) + { + byte[] I = "username".getBytes(); + byte[] P = "password".getBytes(); + byte[] s = new byte[16]; + random.nextBytes(s); + + SRP6Client client = new SRP6Client(); + client.init(group, new SHA256Digest(), random); + + client.generateClientCredentials(s, I, P); + + try + { + client.calculateSecret(ZERO); + fail("Client failed to detect invalid value for 'B'"); + } + catch (CryptoException e) + { + // Expected + } + + try + { + client.calculateSecret(group.getN()); + fail("Client failed to detect invalid value for 'B'"); + } + catch (CryptoException e) + { + // Expected + } + } + + private void testServerCatchesBadA(SRP6GroupParameters group) + { + byte[] I = "username".getBytes(); + byte[] P = "password".getBytes(); + byte[] s = new byte[16]; + random.nextBytes(s); + + SRP6VerifierGenerator gen = new SRP6VerifierGenerator(); + gen.init(group, new SHA256Digest()); + BigInteger v = gen.generateVerifier(s, I, P); + + SRP6Server server = new SRP6Server(); + server.init(group, v, new SHA256Digest(), random); + + server.generateServerCredentials(); + + try + { + server.calculateSecret(ZERO); + fail("Client failed to detect invalid value for 'A'"); + } + catch (CryptoException e) + { + // Expected + } + + try + { + server.calculateSecret(group.getN()); + fail("Client failed to detect invalid value for 'A'"); + } + catch (CryptoException e) + { + // Expected + } + } + + public static void main(String[] args) + { + runTest(new SRP6Test()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Salsa20Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Salsa20Test.java new file mode 100644 index 000000000..13caa146b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Salsa20Test.java @@ -0,0 +1,400 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.engines.Salsa20Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Salsa20 Test + */ +public class Salsa20Test + extends SimpleTest +{ + byte[] zeroes = Hex.decode( + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"); + + String set1v0_0 = "4DFA5E481DA23EA09A31022050859936" + + "DA52FCEE218005164F267CB65F5CFD7F" + + "2B4F97E0FF16924A52DF269515110A07" + + "F9E460BC65EF95DA58F740B7D1DBB0AA"; + + String set1v0_192 = "DA9C1581F429E0A00F7D67E23B730676" + + "783B262E8EB43A25F55FB90B3E753AEF" + + "8C6713EC66C51881111593CCB3E8CB8F" + + "8DE124080501EEEB389C4BCB6977CF95"; + + String set1v0_256 = "7D5789631EB4554400E1E025935DFA7B" + + "3E9039D61BDC58A8697D36815BF1985C" + + "EFDF7AE112E5BB81E37ECF0616CE7147" + + "FC08A93A367E08631F23C03B00A8DA2F"; + + String set1v0_448 = "B375703739DACED4DD4059FD71C3C47F" + + "C2F9939670FAD4A46066ADCC6A564578" + + "3308B90FFB72BE04A6B147CBE38CC0C3" + + "B9267C296A92A7C69873F9F263BE9703"; + + String set1v9_0 = "0471076057830FB99202291177FBFE5D" + + "38C888944DF8917CAB82788B91B53D1C" + + "FB06D07A304B18BB763F888A61BB6B75" + + "5CD58BEC9C4CFB7569CB91862E79C459"; + + String set1v9_192 = "D1D7E97556426E6CFC21312AE3811425" + + "9E5A6FB10DACBD88E4354B0472556935" + + "2B6DA5ACAFACD5E266F9575C2ED8E6F2" + + "EFE4B4D36114C3A623DD49F4794F865B"; + + String set1v9_256 = "AF06FAA82C73291231E1BD916A773DE1" + + "52FD2126C40A10C3A6EB40F22834B8CC" + + "68BD5C6DBD7FC1EC8F34165C517C0B63" + + "9DB0C60506D3606906B8463AA0D0EC2F"; + + String set1v9_448 = "AB3216F1216379EFD5EC589510B8FD35" + + "014D0AA0B613040BAE63ECAB90A9AF79" + + "661F8DA2F853A5204B0F8E72E9D9EB4D" + + "BA5A4690E73A4D25F61EE7295215140C"; + + String set6v0_0 = "F5FAD53F79F9DF58C4AEA0D0ED9A9601" + + "F278112CA7180D565B420A48019670EA" + + "F24CE493A86263F677B46ACE1924773D" + + "2BB25571E1AA8593758FC382B1280B71"; + + String set6v0_65472 = "B70C50139C63332EF6E77AC54338A407" + + "9B82BEC9F9A403DFEA821B83F7860791" + + "650EF1B2489D0590B1DE772EEDA4E3BC" + + "D60FA7CE9CD623D9D2FD5758B8653E70"; + + String set6v0_65536 = "81582C65D7562B80AEC2F1A673A9D01C" + + "9F892A23D4919F6AB47B9154E08E699B" + + "4117D7C666477B60F8391481682F5D95" + + "D96623DBC489D88DAA6956B9F0646B6E"; + + String set6v1_0 = "3944F6DC9F85B128083879FDF190F7DE" + + "E4053A07BC09896D51D0690BD4DA4AC1" + + "062F1E47D3D0716F80A9B4D85E6D6085" + + "EE06947601C85F1A27A2F76E45A6AA87"; + + String set6v1_65472 = "36E03B4B54B0B2E04D069E690082C8C5" + + "92DF56E633F5D8C7682A02A65ECD1371" + + "8CA4352AACCB0DA20ED6BBBA62E177F2" + + "10E3560E63BB822C4158CAA806A88C82"; + + String set6v1_65536 = "1B779E7A917C8C26039FFB23CF0EF8E0" + + "8A1A13B43ACDD9402CF5DF38501098DF" + + "C945A6CC69A6A17367BC03431A86B3ED" + + "04B0245B56379BF997E25800AD837D7D"; + + // Salsa20/12 + String salsa12_set1v0_0 = "FC207DBFC76C5E1774961E7A5AAD0906" + + "9B2225AC1CE0FE7A0CE77003E7E5BDF8" + + "B31AF821000813E6C56B8C1771D6EE70" + + "39B2FBD0A68E8AD70A3944B677937897"; + + String salsa12_set1v0_192 = "4B62A4881FA1AF9560586510D5527ED4" + + "8A51ECAFA4DECEEBBDDC10E9918D44AB" + + "26B10C0A31ED242F146C72940C6E9C37" + + "53F641DA84E9F68B4F9E76B6C48CA5AC"; + + String salsa12_set1v0_256 = "F52383D9DEFB20810325F7AEC9EADE34" + + "D9D883FEE37E05F74BF40875B2D0BE79" + + "ED8886E5BFF556CEA8D1D9E86B1F68A9" + + "64598C34F177F8163E271B8D2FEB5996"; + + String salsa12_set1v0_448 = "A52ED8C37014B10EC0AA8E05B5CEEE12" + + "3A1017557FB3B15C53E6C5EA8300BF74" + + "264A73B5315DC821AD2CAB0F3BB2F152" + + "BDAEA3AEE97BA04B8E72A7B40DCC6BA4"; + + // Salsa20/8 + String salsa8_set1v0_0 = "A9C9F888AB552A2D1BBFF9F36BEBEB33" + + "7A8B4B107C75B63BAE26CB9A235BBA9D" + + "784F38BEFC3ADF4CD3E266687EA7B9F0" + + "9BA650AE81EAC6063AE31FF12218DDC5"; + + String salsa8_set1v0_192 = "BB5B6BB2CC8B8A0222DCCC1753ED4AEB" + + "23377ACCBD5D4C0B69A8A03BB115EF71" + + "871BC10559080ACA7C68F0DEF32A80DD" + + "BAF497259BB76A3853A7183B51CC4B9F"; + + String salsa8_set1v0_256 = "4436CDC0BE39559F5E5A6B79FBDB2CAE" + + "4782910F27FFC2391E05CFC78D601AD8" + + "CD7D87B074169361D997D1BED9729C0D" + + "EB23418E0646B7997C06AA84E7640CE3"; + + String salsa8_set1v0_448 = "BEE85903BEA506B05FC04795836FAAAC" + + "7F93F785D473EB762576D96B4A65FFE4" + + "63B34AAE696777FC6351B67C3753B89B" + + "A6B197BD655D1D9CA86E067F4D770220"; + + + public String getName() + { + return "Salsa20"; + } + + public void performTest() + { + salsa20Test1(20, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + set1v0_0, set1v0_192, set1v0_256, set1v0_448); + salsa20Test1(20, new ParametersWithIV(new KeyParameter(Hex.decode("00400000000000000000000000000000")), Hex.decode("0000000000000000")), + set1v9_0, set1v9_192, set1v9_256, set1v9_448); + salsa20Test1(12, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + salsa12_set1v0_0, salsa12_set1v0_192, salsa12_set1v0_256, salsa12_set1v0_448); + salsa20Test1(8, new ParametersWithIV(new KeyParameter(Hex.decode("80000000000000000000000000000000")), Hex.decode("0000000000000000")), + salsa8_set1v0_0, salsa8_set1v0_192, salsa8_set1v0_256, salsa8_set1v0_448); + salsa20Test2(new ParametersWithIV(new KeyParameter(Hex.decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.decode("0D74DB42A91077DE")), + set6v0_0, set6v0_65472, set6v0_65536); + salsa20Test2(new ParametersWithIV(new KeyParameter(Hex.decode("0558ABFE51A4F74A9DF04396E93C8FE23588DB2E81D4277ACD2073C6196CBF12")), Hex.decode("167DE44BB21980E7")), + set6v1_0, set6v1_65472, set6v1_65536); + reinitBug(); + skipTest(); + } + + private void salsa20Test1(int rounds, CipherParameters params, String v0, String v192, String v256, String v448) + { + StreamCipher salsa = new Salsa20Engine(rounds); + byte[] buf = new byte[64]; + + salsa.init(true, params); + + for (int i = 0; i != 7; i++) + { + salsa.processBytes(zeroes, 0, 64, buf, 0); + switch (i) + { + case 0: + if (!areEqual(buf, Hex.decode(v0))) + { + mismatch("v0/" + rounds, v0, buf); + } + break; + case 3: + if (!areEqual(buf, Hex.decode(v192))) + { + mismatch("v192/" + rounds, v192, buf); + } + break; + case 4: + if (!areEqual(buf, Hex.decode(v256))) + { + mismatch("v256/" + rounds, v256, buf); + } + break; + default: + // ignore + } + } + + for (int i = 0; i != 64; i++) + { + buf[i] = salsa.returnByte(zeroes[i]); + } + + if (!areEqual(buf, Hex.decode(v448))) + { + mismatch("v448", v448, buf); + } + } + + private void salsa20Test2(CipherParameters params, String v0, String v65472, String v65536) + { + StreamCipher salsa = new Salsa20Engine(); + byte[] buf = new byte[64]; + + salsa.init(true, params); + + for (int i = 0; i != 1025; i++) + { + salsa.processBytes(zeroes, 0, 64, buf, 0); + switch (i) + { + case 0: + if (!areEqual(buf, Hex.decode(v0))) + { + mismatch("v0", v0, buf); + } + break; + case 1023: + if (!areEqual(buf, Hex.decode(v65472))) + { + mismatch("v65472", v65472, buf); + } + break; + case 1024: + if (!areEqual(buf, Hex.decode(v65536))) + { + mismatch("v65536", v65536, buf); + } + break; + default: + // ignore + } + } + } + + private void mismatch(String name, String expected, byte[] found) + { + fail("mismatch on " + name, expected, new String(Hex.encode(found))); + } + + + private void reinitBug() + { + KeyParameter key = new KeyParameter(Hex.decode("80000000000000000000000000000000")); + ParametersWithIV parameters = new ParametersWithIV(key, Hex.decode("0000000000000000")); + + StreamCipher salsa = new Salsa20Engine(); + + salsa.init(true, parameters); + + try + { + salsa.init(true, key); + fail("Salsa20 should throw exception if no IV in Init"); + } + catch (IllegalArgumentException e) + { + } + } + + private boolean areEqual(byte[] a, int aOff, byte[] b, int bOff) + { + for (int i = bOff; i != b.length; i++) + { + if (a[aOff + i - bOff] != b[i]) + { + return false; + } + } + + return true; + } + + private void skipTest() + { + SecureRandom rand = new SecureRandom(); + byte[] plain = new byte[50000]; + byte[] cipher = new byte[50000]; + + rand.nextBytes(plain); + + CipherParameters params = new ParametersWithIV(new KeyParameter(Hex.decode("0053A6F94C9FF24598EB3E91E4378ADD3083D6297CCF2275C81B6EC11467BA0D")), Hex.decode("0D74DB42A91077DE")); + Salsa20Engine engine = new Salsa20Engine(); + + engine.init(true, params); + + engine.processBytes(plain, 0, plain.length, cipher, 0); + + byte[] fragment = new byte[20]; + + engine.init(true, params); + + engine.skip(10); + + engine.processBytes(plain, 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 10, fragment, 0)) + { + fail("skip forward 10 failed"); + } + + engine.skip(1000); + + engine.processBytes(plain, 1010 + fragment.length, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + fragment.length, fragment, 0)) + { + fail("skip forward 1000 failed"); + } + + engine.skip(-10); + + engine.processBytes(plain, 1010 + 2 * fragment.length - 10, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010 + 2 * fragment.length - 10, fragment, 0)) + { + fail("skip back 10 failed"); + } + + engine.skip(-1000); + + if (engine.getPosition() != 60) + { + fail("skip position incorrect - " + 60 + " got " + engine.getPosition()); + } + + engine.processBytes(plain, 60, fragment.length, fragment, 0); + + if (!areEqual(cipher, 60, fragment, 0)) + { + fail("skip back 1000 failed"); + } + + long pos = engine.seekTo(1010); + if (pos != 1010) + { + fail("position wrong"); + } + + engine.processBytes(plain, 1010, fragment.length, fragment, 0); + + if (!areEqual(cipher, 1010, fragment, 0)) + { + fail("seek to 1010 failed"); + } + + engine.reset(); + + for (int i = 0; i != 5000; i++) + { + engine.skip(i); + + if (engine.getPosition() != i) + { + fail("skip forward at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip forward i failed: " + i); + } + + if (engine.getPosition() != i + fragment.length) + { + fail("cipher at wrong position: " + engine.getPosition() + " [" + i + "]"); + } + + engine.skip(-fragment.length); + + if (engine.getPosition() != i) + { + fail("skip back at wrong position"); + } + + engine.processBytes(plain, i, fragment.length, fragment, 0); + + if (!areEqual(cipher, i, fragment, 0)) + { + fail("skip back i failed: " + i); + } + + engine.reset(); + } + } + + public static void main( + String[] args) + { + runTest(new Salsa20Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SerpentTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SerpentTest.java new file mode 100644 index 000000000..e1cd92f50 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SerpentTest.java @@ -0,0 +1,140 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.engines.SerpentEngine; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.EAXBlockCipher; +import com.fr.third.org.bouncycastle.crypto.paddings.PKCS7Padding; +import com.fr.third.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test vectors based on the NESSIE submission + */ +public class SerpentTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new SerpentEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000000000000000", "3620b17ae6a993d09618b8768266bae9"), + new BlockCipherVectorTest(1, new SerpentEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "264E5481EFF42A4606ABDA06C0BFDA3D"), + new BlockCipherVectorTest(2, new SerpentEngine(), + new KeyParameter(Hex.decode("D9D9D9D9D9D9D9D9D9D9D9D9D9D9D9D9")), + "D9D9D9D9D9D9D9D9D9D9D9D9D9D9D9D9", "20EA07F19C8E93FDA30F6B822AD5D486"), + new BlockCipherVectorTest(3, new SerpentEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000008000")), + "00000000000000000000000000000000", "40520018C4AC2BBA285AEEB9BCB58755"), + new BlockCipherVectorTest(4, new SerpentEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000000000000000001", "AD86DE83231C3203A86AE33B721EAA9F"), + new BlockCipherVectorTest(5, new SerpentEngine(), + new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F")), + "3DA46FFA6F4D6F30CD258333E5A61369", "00112233445566778899AABBCCDDEEFF"), + new BlockCipherVectorTest(6, new SerpentEngine(), + new KeyParameter(Hex.decode("2BD6459F82C5B300952C49104881FF482BD6459F82C5B300952C49104881FF48")), + "677C8DFAA08071743FD2B415D1B28AF2", "EA024714AD5C4D84EA024714AD5C4D84"), + new BlockCipherVectorTest(7, new SerpentEngine(), + new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F1011121314151617")), + "4528CACCB954D450655E8CFD71CBFAC7", "00112233445566778899AABBCCDDEEFF"), + new BlockCipherVectorTest(8, new SerpentEngine(), + new KeyParameter(Hex.decode("2BD6459F82C5B300952C49104881FF482BD6459F82C5B300")), + "E0208BE278E21420C4B1B9747788A954", "EA024714AD5C4D84EA024714AD5C4D84"), + new BlockCipherVectorTest(9, new SerpentEngine(), + new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F")), + "33B3DC87EDDD9B0F6A1F407D14919365", "00112233445566778899AABBCCDDEEFF"), + new BlockCipherVectorTest(10, new SerpentEngine(), + new KeyParameter(Hex.decode("2BD6459F82C5B300952C49104881FF48")), + "BEB6C069393822D3BE73FF30525EC43E", "EA024714AD5C4D84EA024714AD5C4D84"), + new BlockCipherMonteCarloTest(20, 100, new SerpentEngine(), + new KeyParameter(Hex.decode("F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3")), + "F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3F3", "8FD0E58DB7A54B929FCA6A12F96F20AF"), + new BlockCipherMonteCarloTest(21, 100, new SerpentEngine(), + new KeyParameter(Hex.decode("0004000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000000000000000000", "E7B681E8871FD05FEAE5FB64DA891EA2"), + new BlockCipherMonteCarloTest(22, 100, new SerpentEngine(), + new KeyParameter(Hex.decode("0000000020000000000000000000000000000000000000000000000000000000")), + "00000000000000000000000000000000", "C5545D516EEC73BFA3622A8194F95620"), + new BlockCipherMonteCarloTest(23, 100, new SerpentEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000002000000")), + "00000000000000000000000000000000", "11FF5C9BE006F82C98BD4FAC1A19920E"), + new BlockCipherMonteCarloTest(24, 100, new SerpentEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000000000000010000", "47CA1CA404B6481CAD4C21C8A0415A0E"), + new BlockCipherMonteCarloTest(25, 100, new SerpentEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000008000000000000000", "A0A2D5B07E27D539CA5BEE9DE1EAB3E6") + }; + + SerpentTest() + { + super(tests, new SerpentEngine(), new KeyParameter(new byte[32])); + } + + public void performTest() + throws Exception + { + super.performTest(); + + doCbc(Hex.decode("BE4295539F6BD1752FD0A80229EF8847"), Hex.decode("00963F59224794D5AD4252094358FBC3"), Strings.toByteArray("CBC Mode Test"), Hex.decode("CF2CF2547E02F6D34D97246E8042ED89")); + doEax(Hex.decode("7494A57648FB420043BFBFC5639EB82D"), Hex.decode("6DF94638B83E01458F3E30C9A1D6AF1C"), Strings.toByteArray("EAX Mode Test"), new byte[0], 128, Hex.decode("96C521F32DC5E9BBC369DDE4914CB13B710EEBBAB7D706D3ABE06A99DC")); + } + + private void doEax(byte[] key, byte[] iv, byte[] pt, byte[] aad, int tagLength, byte[] expected) + throws InvalidCipherTextException + { + EAXBlockCipher c = new EAXBlockCipher(new SerpentEngine()); + + c.init(true, new AEADParameters(new KeyParameter(key), tagLength, iv, aad)); + + byte[] out = new byte[expected.length]; + + int len = c.processBytes(pt, 0, pt.length, out, 0); + + c.doFinal(out, len); + + if (!Arrays.areEqual(expected, out)) + { + fail("EAX test failed"); + } + } + + private void doCbc(byte[] key, byte[] iv, byte[] pt, byte[] expected) + throws Exception + { + PaddedBufferedBlockCipher c = new PaddedBufferedBlockCipher(new CBCBlockCipher(new SerpentEngine()), new PKCS7Padding()); + + byte[] ct = new byte[expected.length]; + + c.init(true, new ParametersWithIV(new KeyParameter(key), iv)); + + int l = c.processBytes(pt, 0, pt.length, ct, 0); + + c.doFinal(ct, l); + + if (!Arrays.areEqual(expected, ct)) + { + fail("CBC test failed"); + } + } + + public String getName() + { + return "Serpent"; + } + + public static void main( + String[] args) + { + runTest(new SerpentTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Shacal2Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Shacal2Test.java new file mode 100644 index 000000000..45f4a5bc4 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Shacal2Test.java @@ -0,0 +1,200 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.engines.Shacal2Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Shacal2 tester - vectors from https://www.cosic.esat.kuleuven.be/nessie/testvectors/ + */ +public class Shacal2Test + extends CipherTest +{ + static SimpleTest[] tests = + { + // set 8.0 + new BlockCipherVectorTest(0, new Shacal2Engine(), + new KeyParameter(Hex.decode("000102030405060708090A0B0C0D0E0F" + + "101112131415161718191A1B1C1D1E1F" + + "202122232425262728292A2B2C2D2E2F" + + "303132333435363738393A3B3C3D3E3F")), + "98BCC10405AB0BFC686BECECAAD01AC1" + + "9B452511BCEB9CB094F905C51CA45430", + "00112233445566778899AABBCCDDEEFF" + + "102132435465768798A9BACBDCEDFE0F"), + // set 8.1 + new BlockCipherVectorTest(1, new Shacal2Engine(), + new KeyParameter(Hex.decode("2BD6459F82C5B300952C49104881FF48" + + "2BD6459F82C5B300952C49104881FF48" + + "2BD6459F82C5B300952C49104881FF48" + + "2BD6459F82C5B300952C49104881FF48")), + "481F122A75F2C4C3395140B5A951EBBA" + + "06D96BDFD9D8FF4FB59CBD1287808D5A", + "EA024714AD5C4D84EA024714AD5C4D84" + + "EA024714AD5C4D84EA024714AD5C4D84"), + // 7.255 + new BlockCipherVectorTest(2, new Shacal2Engine(), + new KeyParameter(Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")), + "94FEDFF2A0CFE3C983D340C88D73F8CF" + + "4B79FC581797EC10B27D4DA1B51E1BC7", + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"), + // 7.100 + new BlockCipherVectorTest(3, new Shacal2Engine(), + new KeyParameter(Hex.decode("64646464646464646464646464646464" + + "64646464646464646464646464646464" + + "64646464646464646464646464646464" + + "64646464646464646464646464646464")), + "6643CB84B3B3F126F5E50959EF4CE73D" + + "B8500918ABE1056368DB06CA8C1C0D45", + "64646464646464646464646464646464" + + "64646464646464646464646464646464"), + // 7.50 + new BlockCipherVectorTest(4, new Shacal2Engine(), + new KeyParameter(Hex.decode("32323232323232323232323232323232" + + "32323232323232323232323232323232" + + "32323232323232323232323232323232" + + "32323232323232323232323232323232")), + "92E937285AB11FE3561542C43C918966" + + "971DE722E9B9D38BD69EAC77899DCF81", + "32323232323232323232323232323232" + + "32323232323232323232323232323232"), + // 7.0 + new BlockCipherVectorTest(5, new Shacal2Engine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000")), + "F8C9259FA4F5D787B570AFA9219166A6" + + "3636FC5C30AC289155D0CC4FFCB4B03D", + "00000000000000000000000000000000" + + "00000000000000000000000000000000"), + // 6.255 + new BlockCipherVectorTest(6, new Shacal2Engine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000")), + "F4E976DF0172CD961D4C8D466A12F676" + + "5B9089046E747CD2A41BF43C18A8328E", + "00000000000000000000000000000000" + + "00000000000000000000000000000001"), + // 6.100 + new BlockCipherVectorTest(7, new Shacal2Engine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000")), + "3B929F0597E21D0076EC399D21B67713" + + "B40E3AD559704219A26A3380212D5AD6", + "00000000000000000000000008000000" + + "00000000000000000000000000000000"), + + // 6.0 + new BlockCipherVectorTest(8, new Shacal2Engine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000")), + "43A0DAD8307F19FBBCF166FE20BAC075" + + "C56FF14042550E472094B042BE5963EE", + "80000000000000000000000000000000" + + "00000000000000000000000000000000"), + }; + + Shacal2Test() + { + super(tests, new Shacal2Engine(), new KeyParameter(new byte[16])); + } + + public void performTest() + throws Exception + { + super.performTest(); + + // 1.0 + iteratedTest(0, + Hex.decode("80000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"), + Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000"), + Hex.decode("361AB6322FA9E7A7BB23818D839E01BD" + + "DAFDF47305426EDD297AEDB9F6202BAE"), + Hex.decode("226A582DE04383D0F3E7DE655DD848AC" + + "3E14CCFB4E76F7B7069879F67C4D5420"), + Hex.decode("B05D5A18C0712082CFF5BA9DBBCD7269" + + "114FC3DF83B42DAC306D95BBC473D839")); + + // 1.100 + iteratedTest(1, + Hex.decode("00000000000000000000000008000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"), + Hex.decode("00000000000000000000000000000000" + + "00000000000000000000000000000000"), + Hex.decode("F703282E54592A5617E10618027BB67F" + + "639E43A90767150D8B7F5E83054B3CBD"), + Hex.decode("3B442692B579485B8BA2F92CE3B90DE7" + + "D2EA03D8B3C8E7BE7BF6415F798EED90"), + Hex.decode("331B9B65F06230380BBEECFBFBA94BCF" + + "92AF6341F815D7651F996144A5377263")); + } + + private void iteratedTest(int index, byte[] key, byte[] plain, byte[] cipher, byte[] cipher100, byte[] cipher1000) + { + BlockCipher engine = new Shacal2Engine(); + + engine.init(true, new KeyParameter(key)); + + byte[] buf = new byte[plain.length]; + + System.arraycopy(plain, 0, buf, 0, plain.length); + + engine.processBlock(buf, 0, buf, 0); + + if (!Arrays.areEqual(cipher, buf)) + { + fail(index + " single count failed"); + } + + for (int i = 1; i != 100; i++) + { + engine.processBlock(buf, 0, buf, 0); + } + + if (!Arrays.areEqual(cipher100, buf)) + { + fail(index + " 100 count failed"); + } + + for (int i = 100; i != 1000; i++) + { + engine.processBlock(buf, 0, buf, 0); + } + + if (!Arrays.areEqual(cipher1000, buf)) + { + fail(index + " 1000 count failed"); + } + } + + public String getName() + { + return "Shacal2"; + } + + public static void main( + String[] args) + { + runTest(new Shacal2Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ShortenedDigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ShortenedDigestTest.java new file mode 100644 index 000000000..0cca27603 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ShortenedDigestTest.java @@ -0,0 +1,89 @@ +/* + * Created on 6/05/2006 + * + * To change the template for this generated file go to + * Window>Preferences>Java>Code Generation>Code and Comments + */ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.ExtendedDigest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.digests.ShortenedDigest; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ShortenedDigestTest + extends SimpleTest +{ + public void performTest() + { + ExtendedDigest d = new SHA1Digest(); + ShortenedDigest sd = new ShortenedDigest(new SHA1Digest(), 10); + + if (sd.getDigestSize() != 10) + { + fail("size check wrong for SHA-1"); + } + + if (sd.getByteLength() != d.getByteLength()) + { + fail("byte length check wrong for SHA-1"); + } + + // + // check output fits + // + sd.doFinal(new byte[10], 0); + + d = new SHA512Digest(); + sd = new ShortenedDigest(new SHA512Digest(), 20); + + if (sd.getDigestSize() != 20) + { + fail("size check wrong for SHA-512"); + } + + if (sd.getByteLength() != d.getByteLength()) + { + fail("byte length check wrong for SHA-512"); + } + + // + // check output fits + // + sd.doFinal(new byte[20], 0); + + try + { + new ShortenedDigest(null, 20); + + fail("null parameter not caught"); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + new ShortenedDigest(new SHA1Digest(), 50); + + fail("short digest not caught"); + } + catch (IllegalArgumentException e) + { + // expected + } + } + + public String getName() + { + return "ShortenedDigest"; + } + + public static void main( + String[] args) + { + runTest(new ShortenedDigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SipHashTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SipHashTest.java new file mode 100644 index 000000000..a7e0524da --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SipHashTest.java @@ -0,0 +1,143 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.macs.SipHash; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Pack; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/* + * SipHash test values from "SipHash: a fast short-input PRF", by Jean-Philippe + * Aumasson and Daniel J. Bernstein (https://131002.net/siphash/siphash.pdf), Appendix A. + */ +public class SipHashTest + extends SimpleTest +{ + private static final int UPDATE_BYTES = 0; + private static final int UPDATE_FULL = 1; + private static final int UPDATE_MIX = 2; + + public String getName() + { + return "SipHash"; + } + + public void performTest() + throws Exception + { + byte[] key = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] input = Hex.decode("000102030405060708090a0b0c0d0e"); + + runMAC(key, input, UPDATE_BYTES); + runMAC(key, input, UPDATE_FULL); + runMAC(key, input, UPDATE_MIX); + + SecureRandom random = new SecureRandom(); + for (int i = 0; i < 100; ++i) + { + randomTest(random); + } + } + + private void runMAC(byte[] key, byte[] input, int updateType) + throws Exception + { + long expected = 0xa129ca6149be45e5L; + + SipHash mac = new SipHash(); + mac.init(new KeyParameter(key)); + + updateMAC(mac, input, updateType); + + long result = mac.doFinal(); + if (expected != result) + { + fail("Result does not match expected value for doFinal()"); + } + + byte[] expectedBytes = new byte[8]; + Pack.longToLittleEndian(expected, expectedBytes, 0); + + updateMAC(mac, input, updateType); + + byte[] output = new byte[mac.getMacSize()]; + int len = mac.doFinal(output, 0); + if (len != output.length) + { + fail("Result length does not equal getMacSize() for doFinal(byte[],int)"); + } + if (!areEqual(expectedBytes, output)) + { + fail("Result does not match expected value for doFinal(byte[],int)"); + } + } + + private void randomTest(SecureRandom random) + { + byte[] key = new byte[16]; + random.nextBytes(key); + + int length = 1 + RNGUtils.nextInt(random, 1024); + byte[] input = new byte[length]; + random.nextBytes(input); + + SipHash mac = new SipHash(); + mac.init(new KeyParameter(key)); + + updateMAC(mac, input, UPDATE_BYTES); + long result1 = mac.doFinal(); + + updateMAC(mac, input, UPDATE_FULL); + long result2 = mac.doFinal(); + + updateMAC(mac, input, UPDATE_MIX); + long result3 = mac.doFinal(); + + if (result1 != result2 || result1 != result3) + { + fail("Inconsistent results in random test"); + } + } + + private void updateMAC(SipHash mac, byte[] input, int updateType) + { + switch (updateType) + { + case UPDATE_BYTES: + { + for (int i = 0; i < input.length; ++i) + { + mac.update(input[i]); + } + break; + } + case UPDATE_FULL: + { + mac.update(input, 0, input.length); + break; + } + case UPDATE_MIX: + { + int step = Math.max(1, input.length / 3); + int pos = 0; + while (pos < input.length) + { + mac.update(input[pos++]); + int len = Math.min(input.length - pos, step); + mac.update(input, pos, len); + pos += len; + } + break; + } + default: + throw new IllegalStateException(); + } + } + + public static void main(String[] args) + { + runTest(new SipHashTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SkeinDigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SkeinDigestTest.java new file mode 100644 index 000000000..3836ef7b6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SkeinDigestTest.java @@ -0,0 +1,294 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SkeinDigest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Memoable; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SkeinDigestTest + extends SimpleTest +{ + private static class Case + { + private byte[] message; + private byte[] digest; + private int blockSize; + private int outputSize; + + public Case(int blockSize, int outputSize, String message, String digest) + { + this.blockSize = blockSize; + this.outputSize = outputSize; + this.message = Hex.decode(message); + this.digest = Hex.decode(digest); + } + + public int getOutputSize() + { + return outputSize; + } + + public int getBlockSize() + { + return blockSize; + } + + public byte[] getMessage() + { + return message; + } + + public byte[] getDigest() + { + return digest; + } + + } + + // Test cases from skein_golden_kat.txt and skein_golden_kat_short.txt in Skein 1.3 NIST CD + private static final Case[] TEST_CASES = { + new Case(256, 256, "", "c8877087da56e072870daa843f176e9453115929094c3a40c463a196c29bf7ba"), + new Case(256, 256, "fb", "088eb23cc2bccfb8171aa64e966d4af937325167dfcd170700ffd21f8a4cbdac"), + new Case(256, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8", + "5c3002ff57a627089ea2f97a5000d5678416389019e80e45a3bbcab118315d26"), + new Case(256, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a129233", + "640c894a4bba6574c83e920ddf7dd2982fc634881bbbcb9d774eae0a285e89ce"), + new Case(256, 160, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "0cd491b7715704c3a15a45a1ca8d93f8f646d3a1"), + new Case(256, 224, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "afd1e2d0f5b6cd4e1f8b3935fa2497d27ee97e72060adac099543487"), + new Case(256, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "4de6fe2bfdaa3717a4261030ef0e044ced9225d066354610842a24a3eafd1dcf"), + new Case(256, 384, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "954620fb31e8b782a2794c6542827026fe069d715df04261629fcbe81d7d529b" + + "95ba021fa4239fb00afaa75f5fd8e78b"), + new Case(256, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "51347e27c7eabba514959f899a6715ef6ad5cf01c23170590e6a8af399470bf9" + + "0ea7409960a708c1dbaa90e86389df254abc763639bb8cdf7fb663b29d9557c3"), + new Case(256, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "6c9b6facbaf116b538aa655e0be0168084aa9f1be445f7e06714585e5999a6c9" + + "84fffa9d41a316028692d4aad18f573fbf27cf78e84de26da1928382b023987d" + + "cfe002b6201ea33713c54a8a5d9eb346f0365e04330d2faaf7bc8aba92a5d7fb" + + "6345c6fb26750bce65ab2045c233627679ac6e9acb33602e26fe3526063ecc8b"), + + new Case(512, 512, "", "bc5b4c50925519c290cc634277ae3d6257212395cba733bbad37a4af0fa06af4" + + "1fca7903d06564fea7a2d3730dbdb80c1f85562dfcc070334ea4d1d9e72cba7a"), + new Case(512, 512, "fb", "c49e03d50b4b2cc46bd3b7ef7014c8a45b016399fd1714467b7596c86de98240" + + "e35bf7f9772b7d65465cd4cffab14e6bc154c54fc67b8bc340abf08eff572b9e"), + new Case(512, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8", + "abefb179d52f68f86941acbbe014cc67ec66ad78b7ba9508eb1400ee2cbdb06f" + + "9fe7c2a260a0272d0d80e8ef5e8737c0c6a5f1c02ceb00fb2746f664b85fcef5"), + new Case(512, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a129233", + "5c5b7956f9d973c0989aa40a71aa9c48a65af2757590e9a758343c7e23ea2df4" + + "057ce0b49f9514987feff97f648e1dd065926e2c371a0211ca977c213f14149f"), + new Case(512, 160, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "ef03079d61b57c6047e15fa2b35b46fa24279539"), + new Case(512, 224, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "d9e3219b214e15246a2038f76a573e018ef69b385b3bd0576b558231"), + new Case(512, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "809dd3f763a11af90912bbb92bc0d94361cbadab10142992000c88b4ceb88648"), + new Case(512, 384, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "825f5cbd5da8807a7b4d3e7bd9cd089ca3a256bcc064cd73a9355bf3ae67f2bf" + + "93ac7074b3b19907a0665ba3a878b262"), + new Case(512, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "1a0d5abf4432e7c612d658f8dcfa35b0d1ab68b8d6bd4dd115c23cc57b5c5bcd" + + "de9bff0ece4208596e499f211bc07594d0cb6f3c12b0e110174b2a9b4b2cb6a9"), + + new Case(1024, 1024, "", "0fff9563bb3279289227ac77d319b6fff8d7e9f09da1247b72a0a265cd6d2a62" + + "645ad547ed8193db48cff847c06494a03f55666d3b47eb4c20456c9373c86297" + + "d630d5578ebd34cb40991578f9f52b18003efa35d3da6553ff35db91b81ab890" + + "bec1b189b7f52cb2a783ebb7d823d725b0b4a71f6824e88f68f982eefc6d19c6"), + new Case(1024, 1024, "fb", "6426bdc57b2771a6ef1b0dd39f8096a9a07554565743ac3de851d28258fcff22" + + "9993e11c4e6bebc8b6ecb0ad1b140276081aa390ec3875960336119427827473" + + "4770671b79f076771e2cfdaaf5adc9b10cbae43d8e6cd2b1c1f5d6c82dc96618" + + "00ddc476f25865b8748253173187d81da971c027d91d32fb390301c2110d2db2"), + new Case(1024, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8", + "140e93726ab0b0467c0b8a834ad8cda4d1769d273661902b70db0dcb5ee692ac" + + "b3f852d03b11f857850f2428432811309c1dcbe5724f00267ea3667e89fadb4e" + + "4911da6b0ba8a7eddf87c1c67152ef0f07b7fead3557318478bdef5ad1e5926d" + + "7071fdd4bfa5076d4b3253f8de479ebdf5357676f1641b2f097e9b785e9e528e"), + new Case(1024, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a129233", + "31105e1ef042c30b95b16e0f6e6a1a19172bb7d54a0597dd0c711194888efe1d" + + "bce82d47416df9577ca387219f06e45cd10964ff36f6711edbbea0e9595b0f66" + + "f72b755d70a46857e0aec98561a743d49370d8e572e212811273125f66cc30bf" + + "117d3221894c48012bf6e2219de91e064b01523517420a1e00f71c4cc04bab62"), + new Case(1024, 160, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "2e6a4cbf2ef05ea9c24b93e8d1de732ddf2739eb"), + new Case(1024, 224, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "1d6de19f37f7a3c265440eecb4b9fbd3300bb5ac60895cfc0d4d3c72"), + new Case(1024, 256, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "986a4d472b123e8148731a8eac9db23325f0058c4ccbc44a5bb6fe3a8db672d7"), + new Case(1024, 384, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "9c3d0648c11f31c18395d5e6c8ebd73f43d189843fc45235e2c35e345e12d62b" + + "c21a41f65896ddc6a04969654c2e2ce9"), + new Case(1024, 512, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "5d0416f49c2d08dfd40a1446169dc6a1d516e23b8b853be4933513051de8d5c2" + + "6baccffb08d3b16516ba3c6ccf3e9a6c78fff6ef955f2dbc56e1459a7cdba9a5"), + new Case(1024, 1024, "fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410", + "96ca81f586c825d0360aef5acaec49ad55289e1797072eee198b64f349ce65b6" + + "e6ed804fe38f05135fe769cc56240ddda5098f620865ce4a4278c77fa2ec6bc3" + + "1c0f354ca78c7ca81665bfcc5dc54258c3b8310ed421d9157f36c093814d9b25" + + "103d83e0ddd89c52d0050e13a64c6140e6388431961685734b1f138fe2243086"), + + }; + + public String getName() + { + return "SkeinDigest"; + } + + public void performTest() + throws Exception + { + runTest(TEST_CASES[7]); + for (int i = 0; i < TEST_CASES.length; i++) + { + Case test = TEST_CASES[i]; + runTest(test); + } + } + + private void runTest(Case dc) + { + SkeinDigest digest = new SkeinDigest(dc.getBlockSize(), dc.getOutputSize()); + + byte[] message = dc.getMessage(); + digest.update(message, 0, message.length); + + byte[] output = new byte[digest.getDigestSize()]; + digest.doFinal(output, 0); + + if (!Arrays.areEqual(output, dc.getDigest())) + { + fail(digest.getAlgorithmName() + " message mismatch.\n Message " + new String(Hex.encode(dc.getMessage())), + new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + + // Clone test + digest.update(message, 0, message.length / 2); + + // clone the Digest + Digest d = new SkeinDigest(digest); + + digest.update(message, message.length / 2, message.length - message.length / 2); + digest.doFinal(output, 0); + + if (!areEqual(dc.getDigest(), output)) + { + fail("failing clone vector test", new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + + d.update(message, message.length / 2, message.length - message.length / 2); + d.doFinal(output, 0); + + if (!areEqual(dc.getDigest(), output)) + { + fail("failing second clone vector test", new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + + // + // memo test + // + Memoable m = (Memoable)digest; + + digest.update(message, 0, message.length / 2); + + // copy the Digest + Memoable copy1 = m.copy(); + Memoable copy2 = copy1.copy(); + + digest.update(message, message.length / 2, message.length - message.length / 2); + digest.doFinal(output, 0); + + if (!areEqual(dc.getDigest(), output)) + { + fail("failing memo vector test", new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + + m.reset(copy1); + + digest.update(message, message.length / 2, message.length - message.length / 2); + digest.doFinal(output, 0); + + if (!areEqual(dc.getDigest(), output)) + { + fail("failing memo reset vector test", new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + + Digest md = (Digest)copy2; + + md.update(message, message.length / 2, message.length - message.length / 2); + md.doFinal(output, 0); + + if (!areEqual(dc.getDigest(), output)) + { + fail("failing memo copy vector test", new String(Hex.encode(dc.getDigest())), new String(Hex.encode(output))); + } + } + + public static void main(String[] args) + throws IOException + { + // generateTests(); + runTest(new SkeinDigestTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SkeinMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SkeinMacTest.java new file mode 100644 index 000000000..7d7443914 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SkeinMacTest.java @@ -0,0 +1,162 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.io.IOException; + +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.macs.SkeinMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SkeinMacTest + extends SimpleTest +{ + private static class Case + { + private byte[] message; + private byte[] digest; + private byte[] key; + private int blockSize; + private int outputSize; + + public Case(int blockSize, int outputSize, String message, String key, String digest) + { + this.blockSize = blockSize; + this.outputSize = outputSize; + this.message = Hex.decode(message); + this.key = Hex.decode(key); + this.digest = Hex.decode(digest); + } + + public int getOutputSize() + { + return outputSize; + } + + public int getBlockSize() + { + return blockSize; + } + + public byte[] getMessage() + { + return message; + } + + public byte[] getKey() + { + return key; + } + + public byte[] getDigest() + { + return digest; + } + + public String toString() + { + return "new Case(" + blockSize + ", " + outputSize + ", \"" + new String(Hex.encode(message)) + "\", \"" + + new String(Hex.encode(key)) + "\", \"" + new String(Hex.encode(digest)) + "\""; + } + + } + + // Test cases from skein_golden_kat.txt in Skein 1.3 NIST CD + // Excludes empty '(none)' key 'random+MAC' tests, which are in effect digest + private static final Case[] TEST_CASES = { + new Case(256, 256, "", "cb41f1706cde09651203c2d0efbaddf8", "886e4efefc15f06aa298963971d7a25398fffe5681c84db39bd00851f64ae29d"), + new Case(256, 256, "d3", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "979422a94e3afaa46664124d4e5e8b9422b1d8baf11c6ae6725992ac72a112ca"), + new Case(256, 256, "d3090c72", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "1d658372cbea2f9928493cc47599d6f4ad8ce33536bedfa20b739f07516519d5"), + new Case(256, 256, "d3090c72167517f7", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "41ef6b0f0fad81c040284f3b1a91e9c44e4c26a6d7207f3aac4362856ef12aca"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "ca8208119b9e4e4057631ab31015cfd256f6763a0a34381633d97f640899b84f"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "9e9980fcc16ee082cf164a5147d0e0692aeffe3dcb8d620e2bb542091162e2e9"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc235", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "c353a316558ec34f8245dd2f9c2c4961fbc7decc3b69053c103e4b8aaaf20394"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdf", "cb41f1706cde09651203c2d0efbaddf8", "b1b8c18188e69a6ecae0b6018e6b638c6a91e6de6881e32a60858468c17b520d"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "1dfd2515a412e78852cd81a7f2167711b4ca19b2891c2ea36ba94f8451944793"), + new Case(256, 224, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf8", "a097340709b443ed2c0a921f5dcefef3ead65c4f0bcd5f13da54d7ed"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "ac1b4fab6561c92d0c487e082daec53e0db4f505e08bf51cae4fd5375e37fc04"), + new Case(256, 384, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "96e6cebb23573d0a70ce36a67aa05d2403148093f25c695e1254887cc97f9771d2518413af4286bf2a06b61a53f7fcec"), + new Case(256, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "0e95e597e71d6350f20b99c4179f54f43a4722705c06ba765a82cb0a314fe2fe87ef8090063b757e53182706ed18737dadc0da1e1c66518f08334052702c5ed7"), + new Case(256, 264, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf8", "064abd4896f460b1953f5a357e7f7c5256e29cdb62b8740d0b52295cfa2ef4c7a2"), + new Case(256, 520, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "edf220e43e048603bd16197d59b673b9974de5b8bcf7cb1558a4799f6fd3743eb5fb400cd6129afc0c60e7b741b7e5806f0e0b93eb8429fbc7efa222175a9c80fd"), + new Case(256, 1032, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e92", "f3f59fb07399c7b73aae02a8590883cb2fdfde75c55654e71846522301bde48d267169adcc559e038e8c2f28faa552b550d51874055384adea93c036c71a1f0af0c7bcc3bc923738d5307b9da7cb423d4e615c629c4aba71f70d4c9d1fa008176825e51bfa0203445a4083947ec19f6a0fbd082b5b970f2396fb67420639410447"), + new Case(256, 2056, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "80eb80d9b8836b32fa576fc84ba08edfbdfd6979123d61914e610a70a372b37f560a10909484f9f4a377c93e29ba681dfe522c41dc83b5ee0567e5370007c7bbe4df0b2b4a25e088f80d72fc30734cdcd76d817b42fbd44dca881019afb25306f19d4e91848778af306517d2072cef72caa327e877c5b6554f83cec3d00877131b47c4d3b557f5a13541c4d5080ee3ce7a658993d083efd0db3496a8752060c3c8552f44b290cabdcc867f691ad605836c08dbd59c9528d885b600b85fdfc8a9d0e636ac3ad8b4295bcb0169e78dc358e77eacc8c4b61bddfa9e5f32d2268a006cfe05c57150fe8e68cabd21cf6cf6035aa1fe4db36c922b765aad0b64e82a2c37"), + new Case(256, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed696e6c9db1e6abea026288954a9c2d5758d7c5db7c9e48aa3d21cae3d977a7c3926066aa393dbd538dd0c30da8916c8757f24c18488014668a2627163a37b261833dc2f8c3c56b1b2e0be21fd3fbdb507b2950b77a6cc02efb393e57419383a920767bca2c972107aa61384542d47cbfb82cfe5c415389d1b0a2d74e2c5da851", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "8f88de68f03cd2f396ccdd49c3a0f4ff15bcda7eb357da9753f6116b124de91d"), + new Case(512, 512, "", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "9bd43d2a2fcfa92becb9f69faab3936978f1b865b7e44338fc9c8f16aba949ba340291082834a1fc5aa81649e13d50cd98641a1d0883062bfe2c16d1faa7e3aa"), + new Case(512, 512, "d3", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "f0c0a10f031c8fc69cfabcd54154c318b5d6cd95d06b12cf20264402492211ee010d5cecc2dc37fd772afac0596b2bf71e6020ef2dee7c860628b6e643ed9ff6"), + new Case(512, 512, "d3090c72167517f7", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "0c1f1921253dd8e5c2d4c5f4099f851042d91147892705829161f5fc64d89785226eb6e187068493ee4c78a4b7c0f55a8cbbb1a5982c2daf638fc6a74b16b0d7"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "478d7b6c0cc6e35d9ebbdedf39128e5a36585db6222891692d1747d401de34ce3db6fcbab6c968b7f2620f4a844a2903b547775579993736d2493a75ff6752a1"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e59", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "13c170bac1de35e5fb843f65fabecf214a54a6e0458a4ff6ea5df91915468f4efcd371effa8965a9e82c5388d84730490dcf3976af157b8baf550655a5a6ab78"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc235", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "a947812529a72fd3b8967ec391b298bee891babc8487a1ec4ea3d88f6b2b5be09ac6a780f30f8e8c3bbb4f18bc302a28f3e87d170ba0f858a8fefe3487478cca"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdf", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "7690ba61f10e0bba312980b0212e6a9a51b0e9aadfde7ca535754a706e042335b29172aae29d8bad18efaf92d43e6406f3098e253f41f2931eda5911dc740352"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "d10e3ba81855ac087fbf5a3bc1f99b27d05f98ba22441138026225d34a418b93fd9e8dfaf5120757451adabe050d0eb59d271b0fe1bbf04badbcf9ba25a8791b"), + new Case(512, 160, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "5670b226156570dff3efe16661ab86eb24982cdf"), + new Case(512, 224, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "c41b9ff9753e6c0f8ed88866e320535e927fe4da552c289841a920db"), + new Case(512, 384, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "dfbf5c1319a1d9d70efb2f1600fbcf694f935907f31d24a16d6cd2fb2d7855a769681766c0a29da778eed346cd1d740f"), + new Case(512, 512, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "04d8cddb0ad931d54d195899a094684344e902286037272890bce98a41813edc37a3cee190a693fcca613ee30049ce7ec2bdff9613f56778a13f8c28a21d167a"), + new Case(512, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c193", "08fca368b3b14ac406676adf37ac9be2dbb8704e694055a0c6331184d4f0070098f23f0963ee29002495771bf56fb4d3d9ff3506abcd80be927379f7880d5d7703919fbf92184f498ac44f47f015ce676eded9165d47d53733f5a27abbc05f45acd98b97cc15ffdced641defd1a5119ef841b452a1b8f94ee69004466ccdc143"), + new Case(512, 264, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "669e770ebe7eacc2b64caaf049923ad297a5b37cfa61c283392d81ccfcb9bbbc09"), + new Case(512, 1032, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e", "acc2e03f07f33e9820a6038421089429adcd6a7a83f733beec048c05bf37531a170a5537fcb565c348a70a83217f8be768ff6f95fd2b3d89cb7d8a3dc849505e3710eb4e65a8e7134bbf580d92fe18c9aa987563669b1f014aa5e092519089355534eaa9f0bdc99f6839f54080ffe74623254c906ecb8896b4346c3178a0bc2898"), + new Case(512, 2056, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "9f3e082223c43090a4a3ffbdcd469cbabfe0c1399d1edf45a5dfc18f4db5428928a76e979b8d0d5dffec0e6a59ada448c1ffbc06cc80a2006f002adc0c6dbf458563762228dce4381944e460ebebfe06f1237093634625107469a22a189a47f8b025899265d8890a1b39df64552394377e88ba2ad44a8c8d174f884ac8c3ae24ddb0affca5fceb6aa76e09706881e8371774b9b050a69b96ef5e97e81043f8b7e9479e287ab441bacd62caf768a82c8c3e3107be70eb8799a39856fe29842a04e25de0ef9de1b7e65bd0f1f7306835287fc957388e2035b7d22d3aa9c06a9fefbca16f3f60e1c4def89038d918942152a069aa2e0be8ae7475d859031adec84583"), + new Case(1024, 1024, "", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "bcf37b3459c88959d6b6b58b2bfe142cef60c6f4ec56b0702480d7893a2b0595aa354e87102a788b61996b9cbc1eade7dafbf6581135572c09666d844c90f066b800fc4f5fd1737644894ef7d588afc5c38f5d920bdbd3b738aea3a3267d161ed65284d1f57da73b68817e17e381ca169115152b869c66b812bb9a84275303f0"), + new Case(1024, 1024, "d3090c72", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "df0596e5808835a3e304aa27923db05f61dac57c0696a1d19abf188e70aa9dbcc659e9510f7c9a37fbc025bd4e5ea293e78ed7838dd0b08864e8ad40ddb3a88031ebefc21572a89960d1916107a7da7ac0c067e34ec46a86a29ca63fa250bd398eb32ec1ed0f8ac8329f26da018b029e41e2e58d1dfc44de81615e6c987ed9c9"), + new Case(1024, 1024, "d3090c72167517f7", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "3cfbb79cd88af8ee09c7670bcbab6907a31f80fa31d9d7c9d50826c9568f307a78bd254961398c76b6e338fd9ca5f351059350d30963c3320659b223b991fc46d1307686fe2b4763d9f593c57ad5adbc45caf2ea3dc6090f5a74fa5fa6d9e9838964ea0a2aa216831ab069b00629a1a9b037083403bdb25d3d06a21c430c87dd"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e59", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "0a1b960099fc9d653b0fd1f5b6b972fb366907b772cbce5a59b6171d7935506f70c212bd169d68c5cfd8618343611b7eb2e686ff1dc7c03a57e1a55ed10726848161eea903d53b58459be42d95df989c66c2eea4e51cde272c2d8be67bf3bca2aee633777eb8486781eaa060d0f538abd6c93dbd2d1bf66e6f50bfdcac3725a4"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "3e0cd7938d71c39ffbb08a6ba7995ade3ad140e2c0c45cdbafb099247e08e4c20b61c1f885ced5ed2f816680925034918236e5807f0eecf3f27e9cfca36675eb75873efa1fb41f17541dc2f7c2469eaecb35cc7ca58e489804caf56f09fb97c9f689c64ad49c6888f86c483e901bd3d25798b394ef93faf9154900f92f31f433"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdf", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "7266752f7e9aa04bd7d8a1b16030677de6021301f6a62473c76bae2b98bbf8aad73bd00a4b5035f741caf2317ab80e4e97f5c5bbe8acc0e8b424bcb13c7c6740a985801fba54addde8d4f13f69d2bfc98ae104d46a211145217e51d510ea846cec9581d14fda079f775c8b18d66cb31bf7060996ee8a69eee7f107909ce59a97"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "71f40bf2aa635125ef83c8df0d4e9ea18b73b56be4f45e89b910a7c68d396b65b09d18abc7d1b6de3f53fd5de583e6f22e612dd17b292068af6027daaf8b4cd60acf5bc85044741e9f7a1f423f5827f5e360930a2e71912239af9fc6343604fdcf3f3569854f2bb8d25a81e3b3f5261a02fe8292aaaa50c324101ab2c7a2f349"), + new Case(1024, 160, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "17c3c533b27d666da556ae586e641b7a3a0bcc45"), + new Case(1024, 224, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "6625df9801581009125ea4e5c94ad6f1a2d692c278822ccb6eb67235"), + new Case(1024, 256, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "6c5b671c1766f6eecea6d24b641d4a6bf84bba13a1976f8f80b3f30ee2f93de6"), + new Case(1024, 384, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "98af454d7fa3706dfaafbf58c3f9944868b57f68f493987347a69fce19865febba0407a16b4e82065035651f0b1e0327"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1", "211ac479e9961141da3aac19d320a1dbbbfad55d2dce87e6a345fcd58e36827597378432b482d89bad44dddb13e6ad86e0ee1e0882b4eb0cd6a181e9685e18dd302ebb3aa74502c06254dcadfb2bd45d288f82366b7afc3bc0f6b1a3c2e8f84d37fbedd07a3f8fcff84faf24c53c11da600aaa118e76cfdcb366d0b3f7729dce"), + new Case(1024, 264, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc81463134", "dc1d253b7cadbdaef18503b1809a7f1d4f8c323b7f6f8ca50b76d3864649ce1c7d"), + new Case(1024, 520, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "decd79578d12bf6806530c382230a2c7836429c70cac941179e1dd982938bab91fb6f3638df1cc1ef615ecfc4249e5aca8a73c4c1eebef662a836d0be903b00146"), + new Case(1024, 1032, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c042eb4187aa1c015a4767032c0bb28f076b66485f51531c12e948f47dbc2cb904a4b75d1e8a6d931dab4a07e0a54d1bb5b55e602141746bd09fb15e8f01a8d74e9e63959cb37336bc1b896ec78da734c15e362db04368fbba280f20a043e0d0941e9f5193e1b360a33c43b266524880125222e648f05f28be34ba3cabfc9c544", "440fe691e04f1fed8c253d6c4670646156f33fffaea702de9445df5739eb960cecf85d56e2e6860a610211a5c909932ab774b978aa0b0d5bbce82775172ab12dceddd51d1eb030057ce61bea6c18f6bb368d26ae76a9e44a962eb132e6c42c25d9fecc4f13348300ca55c78e0990de96c1ae24eb3ee3324782c93dd628260a2c8d"), + new Case(1024, 1024, "d3090c72167517f7c7ad82a70c2fd3f6443f608301591e598eadb195e8357135ba26fede2ee187417f816048d00fc23512737a2113709a77e4170c49a94b7fdff45ff579a72287743102e7766c35ca5abc5dfe2f63a1e726ce5fbd2926db03a2dd18b03fc1508a9aac45eb362440203a323e09edee6324ee2e37b4432c1867ed696e6c9db1e6abea026288954a9c2d5758d7c5db7c9e48aa3d21cae3d977a7c3926066aa393dbd538dd0c30da8916c8757f24c18488014668a2627163a37b261833dc2f8c3c56b1b2e0be21fd3fbdb507b2950b77a6cc02efb393e57419383a920767bca2c972107aa61384542d47cbfb82cfe5c415389d1b0a2d74e2c5da851", "cb41f1706cde09651203c2d0efbaddf847a0d315cb2e53ff8bac41da0002672e920244c66e02d5f0dad3e94c42bb65f0d14157decf4105ef5609d5b0984457c1935df3061ff06e9f204192ba11e5bb2cac0430c1c370cb3d113fea5ec1021eb875e5946d7a96ac69a1626c6206b7252736f24253c9ee9b85eb852dfc814631346c", "46a42b0d7b8679f8fcea156c072cf9833c468a7d59ac5e5d326957d60dfe1cdfb27eb54c760b9e049fda47f0b847ac68d6b340c02c39d4a18c1bdfece3f405fae8aa848bdbefe3a4c277a095e921228618d3be8bd1999a071682810de748440ad416a97742cc9e8a9b85455b1d76472cf562f525116698d5cd0a35ddf86e7f8a"), + + }; + + public String getName() + { + return "SkeinMac"; + } + + public void performTest() + throws Exception + { + for (int i = 0; i < TEST_CASES.length; i++) + { + Case test = TEST_CASES[i]; + runTest(test); + } + } + + private void runTest(Case dc) + { + Mac digest = new SkeinMac(dc.getBlockSize(), dc.getOutputSize()); + digest.init(new KeyParameter(dc.getKey())); + + byte[] message = dc.getMessage(); + digest.update(message, 0, message.length); + + byte[] output = new byte[digest.getMacSize()]; + digest.doFinal(output, 0); + + if (!Arrays.areEqual(output, dc.getDigest())) + { + fail(digest.getAlgorithmName() + " message " + (dc.getMessage().length * 8) + " mismatch.\n Message " + new String(Hex.encode(dc.getMessage())) + + "\n Key " + new String(Hex.encode(dc.getKey())) + "\n Expected " + + new String(Hex.encode(dc.getDigest())) + "\n Actual " + new String(Hex.encode(output))); + } + + } + + public static void main(String[] args) + throws IOException + { + runTest(new SkeinMacTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SkipjackTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SkipjackTest.java new file mode 100644 index 000000000..ff0b64def --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/SkipjackTest.java @@ -0,0 +1,35 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.SkipjackEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + */ +public class SkipjackTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new SkipjackEngine(), + new KeyParameter(Hex.decode("00998877665544332211")), + "33221100ddccbbaa", "2587cae27a12d300") + }; + + SkipjackTest() + { + super(tests, new SkipjackEngine(), new KeyParameter(Hex.decode("00998877665544332211"))); + } + + public String getName() + { + return "SKIPJACK"; + } + + public static void main( + String[] args) + { + runTest(new SkipjackTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/StreamCipherResetTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/StreamCipherResetTest.java new file mode 100644 index 000000000..c2f88904e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/StreamCipherResetTest.java @@ -0,0 +1,133 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.engines.ChaChaEngine; +import com.fr.third.org.bouncycastle.crypto.engines.Grain128Engine; +import com.fr.third.org.bouncycastle.crypto.engines.Grainv1Engine; +import com.fr.third.org.bouncycastle.crypto.engines.HC128Engine; +import com.fr.third.org.bouncycastle.crypto.engines.HC256Engine; +import com.fr.third.org.bouncycastle.crypto.engines.ISAACEngine; +import com.fr.third.org.bouncycastle.crypto.engines.RC4Engine; +import com.fr.third.org.bouncycastle.crypto.engines.Salsa20Engine; +import com.fr.third.org.bouncycastle.crypto.engines.XSalsa20Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test whether block ciphers implement reset contract on init, encrypt/decrypt and reset. + */ +public class StreamCipherResetTest + extends SimpleTest +{ + public String getName() + { + return "Stream Cipher Reset"; + } + + public void performTest() + throws Exception + { + testReset(new Salsa20Engine(), new Salsa20Engine(), new ParametersWithIV(new KeyParameter(random(32)), + random(8))); + testReset(new Salsa20Engine(), new Salsa20Engine(), new ParametersWithIV(new KeyParameter(random(16)), + random(8))); + testReset(new XSalsa20Engine(), new XSalsa20Engine(), new ParametersWithIV(new KeyParameter(random(32)), + random(24))); + testReset(new ChaChaEngine(), new ChaChaEngine(), new ParametersWithIV(new KeyParameter(random(32)), random(8))); + testReset(new ChaChaEngine(), new ChaChaEngine(), new ParametersWithIV(new KeyParameter(random(16)), random(8))); + testReset(new RC4Engine(), new RC4Engine(), new KeyParameter(random(16))); + testReset(new ISAACEngine(), new ISAACEngine(), new KeyParameter(random(16))); + testReset(new HC128Engine(), new HC128Engine(), new ParametersWithIV(new KeyParameter(random(16)), random(16))); + testReset(new HC256Engine(), new HC256Engine(), new ParametersWithIV(new KeyParameter(random(16)), random(16))); + testReset(new Grainv1Engine(), new Grainv1Engine(), new ParametersWithIV(new KeyParameter(random(16)), + random(8))); + testReset(new Grain128Engine(), new Grain128Engine(), new ParametersWithIV(new KeyParameter(random(16)), + random(12))); + } + + private static final SecureRandom RAND = new SecureRandom(); + + private byte[] random(int size) + { + final byte[] data = new byte[size]; + RAND.nextBytes(data); + return data; + } + + private void testReset(StreamCipher cipher1, StreamCipher cipher2, CipherParameters params) + throws InvalidCipherTextException + { + cipher1.init(true, params); + + byte[] plaintext = new byte[1023]; + byte[] ciphertext = new byte[plaintext.length]; + + // Establish baseline answer + cipher1.processBytes(plaintext, 0, plaintext.length, ciphertext, 0); + + // Test encryption resets + checkReset(cipher1, params, true, plaintext, ciphertext); + + // Test decryption resets with fresh instance + cipher2.init(false, params); + checkReset(cipher2, params, false, ciphertext, plaintext); + } + + private void checkReset(StreamCipher cipher, + CipherParameters params, + boolean encrypt, + byte[] pretext, + byte[] posttext) + throws InvalidCipherTextException + { + // Do initial run + byte[] output = new byte[posttext.length]; + cipher.processBytes(pretext, 0, pretext.length, output, 0); + + // Check encrypt resets cipher + cipher.init(encrypt, params); + + try + { + cipher.processBytes(pretext, 0, pretext.length, output, 0); + } + catch (Exception e) + { + fail(cipher.getAlgorithmName() + " init did not reset: " + e.getMessage()); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(cipher.getAlgorithmName() + " init did not reset.", new String(Hex.encode(posttext)), + new String(Hex.encode(output))); + } + + // Check reset resets data + cipher.reset(); + + try + { + cipher.processBytes(pretext, 0, pretext.length, output, 0); + } + catch (Exception e) + { + fail(cipher.getAlgorithmName() + " reset did not reset: " + e.getMessage()); + } + if (!Arrays.areEqual(output, posttext)) + { + fail(cipher.getAlgorithmName() + " reset did not reset."); + } + } + + public static void main(String[] args) + { + runTest(new StreamCipherResetTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/StreamCipherVectorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/StreamCipherVectorTest.java new file mode 100644 index 000000000..bfe2c9817 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/StreamCipherVectorTest.java @@ -0,0 +1,62 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * a basic test that takes a stream cipher, key parameter, and an input + * and output string. + */ +public class StreamCipherVectorTest + extends SimpleTest +{ + int id; + StreamCipher cipher; + CipherParameters param; + byte[] input; + byte[] output; + + public StreamCipherVectorTest( + int id, + StreamCipher cipher, + CipherParameters param, + String input, + String output) + { + this.id = id; + this.cipher = cipher; + this.param = param; + this.input = Hex.decode(input); + this.output = Hex.decode(output); + } + + public String getName() + { + return cipher.getAlgorithmName() + " Vector Test " + id; + } + + public void performTest() + { + cipher.init(true, param); + + byte[] out = new byte[input.length]; + + cipher.processBytes(input, 0, input.length, out, 0); + + if (!areEqual(out, output)) + { + fail("failed.", new String(Hex.encode(output)) , new String(Hex.encode(out))); + } + + cipher.init(false, param); + + cipher.processBytes(output, 0, output.length, out, 0); + + if (!areEqual(input, out)) + { + fail("failed reversal"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TEATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TEATest.java new file mode 100644 index 000000000..a80fa7509 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TEATest.java @@ -0,0 +1,48 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.TEAEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * TEA tester - based on C implementation results from http://www.simonshepherd.supanet.com/tea.htm + */ +public class TEATest + extends CipherTest +{ + static SimpleTest[] tests = { + new BlockCipherVectorTest(0, new TEAEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "0000000000000000", + "41ea3a0a94baa940"), + new BlockCipherVectorTest(1, new TEAEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "0102030405060708", + "6a2f9cf3fccf3c55"), + new BlockCipherVectorTest(2, new TEAEngine(), + new KeyParameter(Hex.decode("0123456712345678234567893456789A")), + "0000000000000000", + "34e943b0900f5dcb"), + new BlockCipherVectorTest(3, new TEAEngine(), + new KeyParameter(Hex.decode("0123456712345678234567893456789A")), + "0102030405060708", + "773dc179878a81c0"), + }; + + TEATest() + { + super(tests, new TEAEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "TEA"; + } + + public static void main( + String[] args) + { + runTest(new TEATest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Threefish1024Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Threefish1024Test.java new file mode 100644 index 000000000..ffed05962 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Threefish1024Test.java @@ -0,0 +1,60 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.ThreefishEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.TweakableBlockCipherParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Threefish1024Test + extends CipherTest +{ + // Test cases from skein_golden_kat_internals.txt in Skein 1.3 NIST CD + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024), + new TweakableBlockCipherParameters( + new KeyParameter(new byte[128]), + new byte[16]), + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000", + "f05c3d0a3d05b304f785ddc7d1e036015c8aa76e2f217b06c6e1544c0bc1a90d" + + "f0accb9473c24e0fd54fea68057f43329cb454761d6df5cf7b2e9b3614fbd5a2" + + "0b2e4760b40603540d82eabc5482c171c832afbe68406bc39500367a592943fa" + + "9a5b4a43286ca3c4cf46104b443143d560a4b230488311df4feef7e1dfe8391e"), + new BlockCipherVectorTest(1, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024), + new TweakableBlockCipherParameters( + new KeyParameter(Hex.decode( + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f" + + "505152535455565758595a5b5c5d5e5f606162636465666768696a6b6c6d6e6f" + + "707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f")), + Hex.decode("000102030405060708090a0b0c0d0e0f")), + "fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0" + + "dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0" + + "bfbebdbcbbbab9b8b7b6b5b4b3b2b1b0afaeadacabaaa9a8a7a6a5a4a3a2a1a0" + + "9f9e9d9c9b9a999897969594939291908f8e8d8c8b8a89888786858483828180", + "a6654ddbd73cc3b05dd777105aa849bce49372eaaffc5568d254771bab85531c" + + "94f780e7ffaae430d5d8af8c70eebbe1760f3b42b737a89cb363490d670314bd" + + "8aa41ee63c2e1f45fbd477922f8360b388d6125ea6c7af0ad7056d01796e90c8" + + "3313f4150a5716b30ed5f569288ae974ce2b4347926fce57de44512177dd7cde") + }; + + Threefish1024Test() + { + super(tests, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_1024), new KeyParameter(new byte[128])); + } + + public String getName() + { + return "Threefish-1024"; + } + + public static void main( + String[] args) + { + runTest(new Threefish1024Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Threefish256Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Threefish256Test.java new file mode 100644 index 000000000..929919d1d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Threefish256Test.java @@ -0,0 +1,45 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.ThreefishEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.TweakableBlockCipherParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Threefish256Test + extends CipherTest +{ + // Test cases from skein_golden_kat_internals.txt in Skein 1.3 NIST CD + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256), + new TweakableBlockCipherParameters( + new KeyParameter(new byte[32]), + new byte[16]), + "0000000000000000000000000000000000000000000000000000000000000000", + "84da2a1f8beaee947066ae3e3103f1ad536db1f4a1192495116b9f3ce6133fd8"), + new BlockCipherVectorTest(1, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256), + new TweakableBlockCipherParameters( + new KeyParameter(Hex.decode( + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f")), + Hex.decode("000102030405060708090a0b0c0d0e0f")), + "FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0", + "e0d091ff0eea8fdfc98192e62ed80ad59d865d08588df476657056b5955e97df") + }; + + Threefish256Test() + { + super(tests, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_256), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "Threefish-256"; + } + + public static void main( + String[] args) + { + runTest(new Threefish256Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Threefish512Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Threefish512Test.java new file mode 100644 index 000000000..0656b8a3c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/Threefish512Test.java @@ -0,0 +1,50 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.ThreefishEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.TweakableBlockCipherParameters; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class Threefish512Test + extends CipherTest +{ + // Test cases from skein_golden_kat_internals.txt in Skein 1.3 NIST CD + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), + new TweakableBlockCipherParameters( + new KeyParameter(new byte[64]), + new byte[16]), + "0000000000000000000000000000000000000000000000000000000000000000" + + "0000000000000000000000000000000000000000000000000000000000000000", + "b1a2bbc6ef6025bc40eb3822161f36e375d1bb0aee3186fbd19e47c5d479947b" + + "7bc2f8586e35f0cff7e7f03084b0b7b1f1ab3961a580a3e97eb41ea14a6d7bbe"), + new BlockCipherVectorTest(1, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), + new TweakableBlockCipherParameters( + new KeyParameter(Hex.decode( + "101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f" + + "303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f")), + Hex.decode("000102030405060708090a0b0c0d0e0f")), + "fffefdfcfbfaf9f8f7f6f5f4f3f2f1f0efeeedecebeae9e8e7e6e5e4e3e2e1e0" + + "dfdedddcdbdad9d8d7d6d5d4d3d2d1d0cfcecdcccbcac9c8c7c6c5c4c3c2c1c0", + "e304439626d45a2cb401cad8d636249a6338330eb06d45dd8b36b90e97254779" + + "272a0a8d99463504784420ea18c9a725af11dffea10162348927673d5c1caf3d") + }; + + Threefish512Test() + { + super(tests, new ThreefishEngine(ThreefishEngine.BLOCKSIZE_512), new KeyParameter(new byte[64])); + } + + public String getName() + { + return "Threefish-512"; + } + + public static void main( + String[] args) + { + runTest(new Threefish512Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TigerDigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TigerDigestTest.java new file mode 100644 index 000000000..61afe6516 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TigerDigestTest.java @@ -0,0 +1,59 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.TigerDigest; + +/** + * Tiger Digest Test + */ +public class TigerDigestTest + extends DigestTest +{ + final static String[] messages = { + "", + "abc", + "Tiger", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvw", + "ABCDEFGHIJKLMNOPQRSTUVWXYZ=abcdefghijklmnopqrstuvwxyz+0123456789", + "Tiger - A Fast New Hash Function, by Ross Anderson and Eli Biham, proceedings of Fast Software Encryption 3, Cambridge, 1996.", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-" + }; + + final static String[] digests = { + "3293AC630C13F0245F92BBB1766E16167A4E58492DDE73F3", + "2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93", + "DD00230799F5009FEC6DEBC838BB6A27DF2B9D6F110C7937", + "F71C8583902AFB879EDFE610F82C0D4786A3A534504486B5", + "38F41D9D9A710A10C3727AC0DEEAA270727D9F926EC10139", + "48CEEB6308B87D46E95D656112CDF18D97915F9765658957", + "631ABDD103EB9A3D245B6DFD4D77B257FC7439501D1568DD", + "C54034E5B43EB8005848A7E0AE6AAC76E4FF590AE715FD25", + "C54034E5B43EB8005848A7E0AE6AAC76E4FF590AE715FD25" + }; + + final static String hash64k = "FDF4F5B35139F48E710E421BE5AF411DE1A8AAC333F26204"; + + TigerDigestTest() + { + super(new TigerDigest(), messages, digests); + } + + public void performTest() + { + super.performTest(); + + sixtyFourKTest(hash64k); + } + + protected Digest cloneDigest(Digest digest) + { + return new TigerDigest((TigerDigest)digest); + } + + public static void main( + String[] args) + { + runTest(new TigerDigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TnepresTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TnepresTest.java new file mode 100644 index 000000000..357502ee5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TnepresTest.java @@ -0,0 +1,144 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.engines.TnepresEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test vectors based on Floppy 4 of the Serpent AES submission. + */ +public class TnepresTest + extends CipherTest +{ + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new TnepresEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000000000000000000", "8910494504181950f98dd998a82b6749"), + new BlockCipherVectorTest(1, new TnepresEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "80000000000000000000000000000000", "10b5ffb720b8cb9002a1142b0ba2e94a"), + new BlockCipherVectorTest(2, new TnepresEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000008000000000000000000000", "4f057a42d8d5bd9746e434680ddcd5e5"), + new BlockCipherVectorTest(3, new TnepresEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "00000000000000000000400000000000", "99407bf8582ef12550886ef5b6f169b9"), + new BlockCipherVectorTest(4, new TnepresEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "40000000000000000000000000000000", "d522a3b8d6d89d4d2a124fdd88f36896"), + new BlockCipherVectorTest(5, new TnepresEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "00000000000200000000000000000000", "189b8ec3470085b3da97e82ca8964e32"), + new BlockCipherVectorTest(6, new TnepresEngine(), + new KeyParameter(Hex.decode("000000000000000000000000000000000000000000000000")), + "00000000000000000000008000000000", "f77d868cf760b9143a89809510ccb099"), + new BlockCipherVectorTest(7, new TnepresEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "08000000000000000000000000000000", "d43b7b981b829342fce0e3ec6f5f4c82"), + new BlockCipherVectorTest(8, new TnepresEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000100000000000000", "0bf30e1a0c33ccf6d5293177886912a7"), + new BlockCipherVectorTest(9, new TnepresEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000000000000")), + "00000000000000000000000000000001", "6a7f3b805d2ddcba49b89770ade5e507"), + new BlockCipherVectorTest(10, new TnepresEngine(), + new KeyParameter(Hex.decode("80000000000000000000000000000000")), + "00000000000000000000000000000000", "49afbfad9d5a34052cd8ffa5986bd2dd"), + new BlockCipherVectorTest(11, new TnepresEngine(), + new KeyParameter(Hex.decode("000000000000000000000000004000000000000000000000")), + "00000000000000000000000000000000", "ba8829b1de058c4b48615d851fc74f17"), + new BlockCipherVectorTest(12, new TnepresEngine(), + new KeyParameter(Hex.decode("0000000000000000000000000000000000000000000000000000000100000000")), + "00000000000000000000000000000000", "89f64377bf1e8a46c8247044e8056a98"), +/* + new BlockCipherMonteCarloTest(13, 10000, new TnepresEngine(), + new KeyParameter(Hex.decode("47f5f881daab9b67b43bd1342e339c19")), + "7a4f7db38c52a8b711b778a38d203b6b", "003380e19f10065740394f48e2fe80b7"), +*/ + new BlockCipherMonteCarloTest(13, 100, new TnepresEngine(), + new KeyParameter(Hex.decode("47f5f881daab9b67b43bd1342e339c19")), + "7a4f7db38c52a8b711b778a38d203b6b", "4db75303d815c2f7cc6ca935d1c5a046"), +/* + new BlockCipherMonteCarloTest(14, 10000, new TnepresEngine(), + new KeyParameter(Hex.decode("31fba879ebc5e80df35e6fa33eaf92d6")), + "70a05e12f74589009692a337f53ff614", "afb5425426906db26b70bdf842ac5400"), +*/ + new BlockCipherMonteCarloTest(14, 100, new TnepresEngine(), + new KeyParameter(Hex.decode("31fba879ebc5e80df35e6fa33eaf92d6")), + "70a05e12f74589009692a337f53ff614", "fc53a50f4d3bc9836001893d2f41742d"), +/* + new BlockCipherMonteCarloTest(15, 10000, new TnepresEngine(), + new KeyParameter(Hex.decode("bde6dd392307984695aee80e574f9977caae9aa78eda53e8")), + "9cc523d034a93740a0aa4e2054bb34d8", "1949d506ada7de1f1344986e8ea049b2"), +*/ + new BlockCipherMonteCarloTest(15, 100, new TnepresEngine(), + new KeyParameter(Hex.decode("bde6dd392307984695aee80e574f9977caae9aa78eda53e8")), + "9cc523d034a93740a0aa4e2054bb34d8", "77117e6a9e80f40b2a36b7d755573c2d"), +/* + new BlockCipherMonteCarloTest(16, 10000, new TnepresEngine(), + new KeyParameter(Hex.decode("60f6f8ad4290699dc50921a1bbcca92da914e7d9cf01a9317c79c0af8f2487a1")), + "ee1a61106fae2d381d686cbf854bab65", "e57f45559027cb1f2ed9603d814e1c34"), +*/ + new BlockCipherMonteCarloTest(16, 100, new TnepresEngine(), + new KeyParameter(Hex.decode("60f6f8ad4290699dc50921a1bbcca92da914e7d9cf01a9317c79c0af8f2487a1")), + "ee1a61106fae2d381d686cbf854bab65", "dcd7f13ea0dcdfd0139d1a42e2ffb84b") + }; + + TnepresTest() + { + super(tests, new TnepresEngine(), new KeyParameter(new byte[32])); + } + + public void performTest() + throws Exception + { + super.performTest(); + + doCbcMonte(new byte[16], new byte[16], new byte[16], Hex.decode("9ea101ecebaa41c712bcb0d9bab3e2e4")); + doCbcMonte(Hex.decode("9ea101ecebaa41c712bcb0d9bab3e2e4"), Hex.decode("9ea101ecebaa41c712bcb0d9bab3e2e4"), Hex.decode("b4813d8a66244188b9e92c75913fa2f4"), Hex.decode("f86b2c265b9c75869f31e2c684c13e9f")); + } + + private void doCbcMonte(byte[] key, byte[] iv, byte[] pt, byte[] expected) + { + BlockCipher c = new TnepresEngine(); + + byte[] ct = new byte[16]; + + System.arraycopy(iv, 0, ct, 0, 16); + + for (int i = 0; i < 10000; i++) + { + for (int k = 0; k != iv.length; k++) + { + iv[k] ^= pt[k]; + } + System.arraycopy(ct, 0, pt, 0, 16); + + c.init(true, new KeyParameter(key)); + + c.processBlock(iv, 0, ct, 0); + + System.arraycopy(ct, 0, iv, 0, 16); + } + + if (!Arrays.areEqual(expected, ct)) + { + fail("CBC monte test failed"); + } + } + + public String getName() + { + return "Tnepres"; + } + + public static void main( + String[] args) + { + runTest(new TnepresTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TwofishTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TwofishTest.java new file mode 100644 index 000000000..f2a4e3ddb --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/TwofishTest.java @@ -0,0 +1,45 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.TwofishEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class TwofishTest + extends CipherTest +{ + static String key1 = "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"; + static String key2 = "000102030405060708090a0b0c0d0e0f1011121314151617"; + static String key3 = "000102030405060708090a0b0c0d0e0f"; + + static String input = "000102030405060708090A0B0C0D0E0F"; + + static SimpleTest[] tests = + { + new BlockCipherVectorTest(0, new TwofishEngine(), + new KeyParameter(Hex.decode(key1)), + input, "8ef0272c42db838bcf7b07af0ec30f38"), + new BlockCipherVectorTest(1, new TwofishEngine(), + new KeyParameter(Hex.decode(key2)), + input, "95accc625366547617f8be4373d10cd7"), + new BlockCipherVectorTest(2, new TwofishEngine(), + new KeyParameter(Hex.decode(key3)), + input, "9fb63337151be9c71306d159ea7afaa4") + }; + + TwofishTest() + { + super(tests, new TwofishEngine(), new KeyParameter(new byte[32])); + } + + public String getName() + { + return "Twofish"; + } + + public static void main( + String[] args) + { + runTest(new TwofishTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/VMPCKSA3Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/VMPCKSA3Test.java new file mode 100644 index 000000000..27b05e298 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/VMPCKSA3Test.java @@ -0,0 +1,97 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.engines.VMPCKSA3Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * VMPC Test + */ +public class VMPCKSA3Test extends SimpleTest +{ + private static final byte[] input = new byte[1000000]; + + public String getName() + { + return "VMPC-KSA3"; + } + + private void checkByte(byte[] array, int position, byte b) + { + if (array[position] != b) + { + fail("Fail on position " + position, + new String(Hex.encode(new byte[] { b })), + new String(Hex.encode(new byte[] { array[position] }))); + } + } + + public void performTest() + { + byte[] key = Hex.decode("9661410AB797D8A9EB767C21172DF6C7"); + byte[] iv = Hex.decode("4B5C2F003E67F39557A8D26F3DA2B155"); + CipherParameters kp = new KeyParameter(key); + CipherParameters kpwiv = new ParametersWithIV(kp, iv); + + VMPCKSA3Engine engine = new VMPCKSA3Engine(); + + try + { + engine.init(true, kp); + fail("init failed to throw expected exception"); + } + catch (IllegalArgumentException e) + { + // Expected + } + + engine.init(true, kpwiv); + checkEngine(engine); + + engine.reset(); + byte[] output = checkEngine(engine); + + engine.init(false, kpwiv); + byte[] recovered = new byte[output.length]; + engine.processBytes(output, 0, output.length, recovered, 0); + + if (!Arrays.areEqual(input, recovered)) + { + fail("decrypted bytes differ from original bytes"); + } + } + + private byte[] checkEngine(VMPCKSA3Engine engine) + { + byte[] output = new byte[input.length]; + engine.processBytes(input, 0, output.length, output, 0); + + checkByte(output, 0, (byte) 0xB6); + checkByte(output, 1, (byte) 0xEB); + checkByte(output, 2, (byte) 0xAE); + checkByte(output, 3, (byte) 0xFE); + checkByte(output, 252, (byte) 0x48); + checkByte(output, 253, (byte) 0x17); + checkByte(output, 254, (byte) 0x24); + checkByte(output, 255, (byte) 0x73); + checkByte(output, 1020, (byte) 0x1D); + checkByte(output, 1021, (byte) 0xAE); + checkByte(output, 1022, (byte) 0xC3); + checkByte(output, 1023, (byte) 0x5A); + checkByte(output, 102396, (byte) 0x1D); + checkByte(output, 102397, (byte) 0xA7); + checkByte(output, 102398, (byte) 0xE1); + checkByte(output, 102399, (byte) 0xDC); + + return output; + } + + public static void main(String[] args) + { + runTest(new VMPCKSA3Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/VMPCMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/VMPCMacTest.java new file mode 100644 index 000000000..368f535db --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/VMPCMacTest.java @@ -0,0 +1,53 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.macs.VMPCMac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class VMPCMacTest extends SimpleTest +{ + public String getName() + { + return "VMPC-MAC"; + } + + public static void main(String[] args) + { + runTest(new VMPCMacTest()); + } + + static byte[] output1 = Hex.decode("9BDA16E2AD0E284774A3ACBC8835A8326C11FAAD"); + + public void performTest() throws Exception + { + CipherParameters kp = new KeyParameter( + Hex.decode("9661410AB797D8A9EB767C21172DF6C7")); + CipherParameters kpwiv = new ParametersWithIV(kp, + Hex.decode("4B5C2F003E67F39557A8D26F3DA2B155")); + + byte[] m = new byte[512]; + + int offset = 117; + for (int i = 0; i < 256; i++) + { + m[offset + i] = (byte) i; + } + + VMPCMac mac = new VMPCMac(); + mac.init(kpwiv); + + mac.update(m, offset, 256); + + byte[] out = new byte[20]; + mac.doFinal(out, 0); + + if (!Arrays.areEqual(out, output1)) + { + fail("Fail", new String(Hex.encode(output1)), new String(Hex.encode(out))); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/VMPCTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/VMPCTest.java new file mode 100644 index 000000000..a9344920b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/VMPCTest.java @@ -0,0 +1,97 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.engines.VMPCEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * VMPC Test + */ +public class VMPCTest extends SimpleTest +{ + private static final byte[] input = new byte[1000000]; + + public String getName() + { + return "VMPC"; + } + + private void checkByte(byte[] array, int position, byte b) + { + if (array[position] != b) + { + fail("Fail on position " + position, + new String(Hex.encode(new byte[] { b })), + new String(Hex.encode(new byte[] { array[position] }))); + } + } + + public void performTest() + { + byte[] key = Hex.decode("9661410AB797D8A9EB767C21172DF6C7"); + byte[] iv = Hex.decode("4B5C2F003E67F39557A8D26F3DA2B155"); + CipherParameters kp = new KeyParameter(key); + CipherParameters kpwiv = new ParametersWithIV(kp, iv); + + VMPCEngine engine = new VMPCEngine(); + + try + { + engine.init(true, kp); + fail("init failed to throw expected exception"); + } + catch (IllegalArgumentException e) + { + // Expected + } + + engine.init(true, kpwiv); + checkEngine(engine); + + engine.reset(); + byte[] output = checkEngine(engine); + + engine.init(false, kpwiv); + byte[] recovered = new byte[output.length]; + engine.processBytes(output, 0, output.length, recovered, 0); + + if (!Arrays.areEqual(input, recovered)) + { + fail("decrypted bytes differ from original bytes"); + } + } + + private byte[] checkEngine(VMPCEngine engine) + { + byte[] output = new byte[input.length]; + engine.processBytes(input, 0, output.length, output, 0); + + checkByte(output, 0, (byte) 0xA8); + checkByte(output, 1, (byte) 0x24); + checkByte(output, 2, (byte) 0x79); + checkByte(output, 3, (byte) 0xF5); + checkByte(output, 252, (byte) 0xB8); + checkByte(output, 253, (byte) 0xFC); + checkByte(output, 254, (byte) 0x66); + checkByte(output, 255, (byte) 0xA4); + checkByte(output, 1020, (byte) 0xE0); + checkByte(output, 1021, (byte) 0x56); + checkByte(output, 1022, (byte) 0x40); + checkByte(output, 1023, (byte) 0xA5); + checkByte(output, 102396, (byte) 0x81); + checkByte(output, 102397, (byte) 0xCA); + checkByte(output, 102398, (byte) 0x49); + checkByte(output, 102399, (byte) 0x9A); + + return output; + } + + public static void main(String[] args) + { + runTest(new VMPCTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/WhirlpoolDigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/WhirlpoolDigestTest.java new file mode 100644 index 000000000..d1b7d59d6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/WhirlpoolDigestTest.java @@ -0,0 +1,105 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.WhirlpoolDigest; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * ISO vector test for Whirlpool + * + */ +public class WhirlpoolDigestTest + extends DigestTest +{ + private static String[] messages = + { + "", + "a", + "abc", + "message digest", + "abcdefghijklmnopqrstuvwxyz", + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", + "12345678901234567890123456789012345678901234567890123456789012345678901234567890", + "abcdbcdecdefdefgefghfghighijhijk" + }; + + private static String[] digests = + { + "19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A73E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3", + "8ACA2602792AEC6F11A67206531FB7D7F0DFF59413145E6973C45001D0087B42D11BC645413AEFF63A42391A39145A591A92200D560195E53B478584FDAE231A", + "4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5", + "378C84A4126E2DC6E56DCC7458377AAC838D00032230F53CE1F5700C0FFB4D3B8421557659EF55C106B4B52AC5A4AAA692ED920052838F3362E86DBD37A8903E", + "F1D754662636FFE92C82EBB9212A484A8D38631EAD4238F5442EE13B8054E41B08BF2A9251C30B6A0B8AAE86177AB4A6F68F673E7207865D5D9819A3DBA4EB3B", + "DC37E008CF9EE69BF11F00ED9ABA26901DD7C28CDEC066CC6AF42E40F82F3A1E08EBA26629129D8FB7CB57211B9281A65517CC879D7B962142C65F5A7AF01467", + "466EF18BABB0154D25B9D38A6414F5C08784372BCCB204D6549C4AFADB6014294D5BD8DF2A6C44E538CD047B2681A51A2C60481E88C5A20B2C2A80CF3A9A083B", + "2A987EA40F917061F5D6F0A0E4644F488A7A5A52DEEE656207C562F988E95C6916BDC8031BC5BE1B7B947639FE050B56939BAAA0ADFF9AE6745B7B181C3BE3FD" + }; + + WhirlpoolDigestTest() + { + super(new WhirlpoolDigest(), messages, digests); + } + + protected Digest cloneDigest(Digest digest) + { + return new WhirlpoolDigest((WhirlpoolDigest)digest); + } + + private static String _millionAResultVector = "0C99005BEB57EFF50A7CF005560DDF5D29057FD86B20BFD62DECA0F1CCEA4AF51FC15490EDDC47AF32BB2B66C34FF9AD8C6008AD677F77126953B226E4ED8B01"; + + private static String _thirtyOneZeros = "3E3F188F8FEBBEB17A933FEAF7FE53A4858D80C915AD6A1418F0318E68D49B4E459223CD414E0FBC8A57578FD755D86E827ABEF4070FC1503E25D99E382F72BA"; + + public String getName() + { + return "Whirlpool"; + } + + public void performTest() + { + super.performTest(); + + byte[] thirtyOneZeros = new byte[31]; + performStandardVectorTest("31 zeroes test", + thirtyOneZeros, _thirtyOneZeros); + + byte[] millionAInByteArray = new byte[1000000]; + Arrays.fill(millionAInByteArray, (byte)'a'); + + performStandardVectorTest("Million 'a' test", + millionAInByteArray, _millionAResultVector); + } + + private void performStandardVectorTest(String testTitle, byte[] inputBytes, + String resultsAsHex) + { + doPerformTest(testTitle, inputBytes, resultsAsHex); + } + + private void doPerformTest(String testTitle, byte[] inputBytes, String resultsAsHex) + { + String resStr = createHexOutputFromDigest(inputBytes); + if (!resultsAsHex.equals(resStr.toUpperCase())) + { + fail(testTitle, resultsAsHex, resStr); + } + } + + private String createHexOutputFromDigest(byte[] digestBytes) + { + String resStr; + Digest digest = new WhirlpoolDigest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + digest.update(digestBytes, 0, digestBytes.length); + digest.doFinal(resBuf, 0); + resStr = new String(Hex.encode(resBuf)); + return resStr; + } + + public static void main(String[] args) + { + runTest(new WhirlpoolDigestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/X25519Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/X25519Test.java new file mode 100644 index 000000000..2b6c5447f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/X25519Test.java @@ -0,0 +1,58 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.agreement.X25519Agreement; +import com.fr.third.org.bouncycastle.crypto.generators.X25519KeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.X25519KeyGenerationParameters; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class X25519Test + extends SimpleTest +{ + private static final SecureRandom RANDOM = new SecureRandom(); + + public String getName() + { + return "X25519"; + } + + public static void main(String[] args) + { + runTest(new X25519Test()); + } + + public void performTest() + { + for (int i = 0; i < 10; ++i) + { + testAgreement(); + } + } + + private void testAgreement() + { + AsymmetricCipherKeyPairGenerator kpGen = new X25519KeyPairGenerator(); + kpGen.init(new X25519KeyGenerationParameters(RANDOM)); + + AsymmetricCipherKeyPair kpA = kpGen.generateKeyPair(); + AsymmetricCipherKeyPair kpB = kpGen.generateKeyPair(); + + X25519Agreement agreeA = new X25519Agreement(); + agreeA.init(kpA.getPrivate()); + byte[] secretA = new byte[agreeA.getAgreementSize()]; + agreeA.calculateAgreement(kpB.getPublic(), secretA, 0); + + X25519Agreement agreeB = new X25519Agreement(); + agreeB.init(kpB.getPrivate()); + byte[] secretB = new byte[agreeB.getAgreementSize()]; + agreeB.calculateAgreement(kpA.getPublic(), secretB, 0); + + if (!areEqual(secretA, secretB)) + { + fail("X25519 agreement failed"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/X448Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/X448Test.java new file mode 100644 index 000000000..8f96e2dab --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/X448Test.java @@ -0,0 +1,58 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.agreement.X448Agreement; +import com.fr.third.org.bouncycastle.crypto.generators.X448KeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.X448KeyGenerationParameters; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class X448Test + extends SimpleTest +{ + private static final SecureRandom RANDOM = new SecureRandom(); + + public String getName() + { + return "X448"; + } + + public static void main(String[] args) + { + runTest(new X448Test()); + } + + public void performTest() + { + for (int i = 0; i < 10; ++i) + { + testAgreement(); + } + } + + private void testAgreement() + { + AsymmetricCipherKeyPairGenerator kpGen = new X448KeyPairGenerator(); + kpGen.init(new X448KeyGenerationParameters(RANDOM)); + + AsymmetricCipherKeyPair kpA = kpGen.generateKeyPair(); + AsymmetricCipherKeyPair kpB = kpGen.generateKeyPair(); + + X448Agreement agreeA = new X448Agreement(); + agreeA.init(kpA.getPrivate()); + byte[] secretA = new byte[agreeA.getAgreementSize()]; + agreeA.calculateAgreement(kpB.getPublic(), secretA, 0); + + X448Agreement agreeB = new X448Agreement(); + agreeB.init(kpB.getPrivate()); + byte[] secretB = new byte[agreeB.getAgreementSize()]; + agreeB.calculateAgreement(kpA.getPublic(), secretB, 0); + + if (!areEqual(secretA, secretB)) + { + fail("X448 agreement failed"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/X931SignerTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/X931SignerTest.java new file mode 100644 index 000000000..98a44d9d3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/X931SignerTest.java @@ -0,0 +1,138 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA224Digest; +import com.fr.third.org.bouncycastle.crypto.engines.RSAEngine; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.crypto.signers.X931Signer; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class X931SignerTest + extends SimpleTest +{ + public String getName() + { + return "X931Signer"; + } + + public void performTest() throws Exception + { + BigInteger rsaPubMod = new BigInteger(Base64.decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt")); + BigInteger rsaPubExp = new BigInteger(Base64.decode("EQ==")); + BigInteger rsaPrivMod = new BigInteger(Base64.decode("AIASoe2PQb1IP7bTyC9usjHP7FvnUMVpKW49iuFtrw/dMpYlsMMoIU2jupfifDpdFxIktSB4P+6Ymg5WjvHKTIrvQ7SR4zV4jaPTu56Ys0pZ9EDA6gb3HLjtU+8Bb1mfWM+yjKxcPDuFjwEtjGlPHg1Vq+CA9HNcMSKNn2+tW6qt")); + BigInteger rsaPrivDP = new BigInteger(Base64.decode("JXzfzG5v+HtLJIZqYMUefJfFLu8DPuJGaLD6lI3cZ0babWZ/oPGoJa5iHpX4Ul/7l3s1PFsuy1GhzCdOdlfRcQ==")); + BigInteger rsaPrivDQ = new BigInteger(Base64.decode("YNdJhw3cn0gBoVmMIFRZzflPDNthBiWy/dUMSRfJCxoZjSnr1gysZHK01HteV1YYNGcwPdr3j4FbOfri5c6DUQ==")); + BigInteger rsaPrivExp = new BigInteger(Base64.decode("DxFAOhDajr00rBjqX+7nyZ/9sHWRCCp9WEN5wCsFiWVRPtdB+NeLcou7mWXwf1Y+8xNgmmh//fPV45G2dsyBeZbXeJwB7bzx9NMEAfedchyOwjR8PYdjK3NpTLKtZlEJ6Jkh4QihrXpZMO4fKZWUm9bid3+lmiq43FwW+Hof8/E=")); + BigInteger rsaPrivP = new BigInteger(Base64.decode("AJ9StyTVW+AL/1s7RBtFwZGFBgd3zctBqzzwKPda6LbtIFDznmwDCqAlIQH9X14X7UPLokCDhuAa76OnDXb1OiE=")); + BigInteger rsaPrivQ = new BigInteger(Base64.decode("AM3JfD79dNJ5A3beScSzPtWxx/tSLi0QHFtkuhtSizeXdkv5FSba7lVzwEOGKHmW829bRoNxThDy4ds1IihW1w0=")); + BigInteger rsaPrivQinv = new BigInteger(Base64.decode("Lt0g7wrsNsQxuDdB8q/rH8fSFeBXMGLtCIqfOec1j7FEIuYA/ACiRDgXkHa0WgN7nLXSjHoy630wC5Toq8vvUg==")); + RSAKeyParameters rsaPublic = new RSAKeyParameters(false, rsaPubMod, rsaPubExp); + RSAPrivateCrtKeyParameters rsaPrivate = new RSAPrivateCrtKeyParameters(rsaPrivMod, rsaPubExp, rsaPrivExp, rsaPrivP, rsaPrivQ, rsaPrivDP, rsaPrivDQ, rsaPrivQinv); + + byte[] msg = new byte[] { 1, 6, 3, 32, 7, 43, 2, 5, 7, 78, 4, 23 }; + + X931Signer signer = new X931Signer(new RSAEngine(), new SHA1Digest()); + signer.init(true, rsaPrivate); + signer.update(msg, 0, msg.length); + byte[] sig = signer.generateSignature(); + + signer = new X931Signer(new RSAEngine(), new SHA1Digest()); + signer.init(false, rsaPublic); + signer.update(msg, 0, msg.length); + if (!signer.verifySignature(sig)) + { + fail("X9.31 Signer failed."); + } + + shouldPassSignatureTest1(); + shouldPassSignatureTest2(); + shouldPassSignatureTest3(); + } + + private void shouldPassSignatureTest1() + throws Exception + { + BigInteger n = new BigInteger("c9be1b28f8caccca65d86cc3c9bbcc13eccc059df3b80bd2292b811eff3aa0dd75e1e85c333b8e3fa9bed53bb20f5359ff4e6900c5e9a388e3a4772a583a79e2299c76582c2b27694b65e9ba22e66bfb817f8b70b22206d7d8ae488c86dbb7137c26d5eff9b33c90e6cee640630313b7a715802e15142fef498c404a8de19674974785f0f852e2d470fe85a2e54ffca9f5851f672b71df691785a5cdabe8f14aa628942147de7593b2cf962414a5b59c632c4e14f1768c0ab2e9250824beea60a3529f11bf5e070ce90a47686eb0be1086fb21f0827f55295b4a48307db0b048c05a4aec3f488c576ca6f1879d354224c7e84cbcd8e76dd217a3de54dba73c35", 16); + BigInteger e = new BigInteger("e75b1b", 16); + byte[] msg = Hex.decode("5bb0d1c0ef9b5c7af2477fe08d45523d3842a4b2db943f7033126c2a7829bacb3d2cfc6497ec91688189e81b7f8742488224ba320ce983ce9480722f2cc5bc42611f00bb6311884f660ccc244788378673532edb05284fd92e83f6f6dab406209032e6af9a33c998677933e32d6fb95fd27408940d7728f9c9c40267ca1d20ce"); + byte[] sig = Hex.decode("0fe8bb8e3109a1eb7489ef35bf4c1a0780071da789c8bd226a4170538eafefdd30b732d628f0e87a0b9450051feae9754d4fb61f57862d10f0bacc4f660d13281d0cd1141c006ade5186ff7d961a4c6cd0a4b352fc1295c5afd088f80ac1f8e192ef116a010a442655fe8ff5eeacea15807906fb0f0dfa86e680d4c005872357f7ece9aa4e20b15d5f709b30f08648ecaa34f2fbf54eb6b414fa2ff6f87561f70163235e69ccb4ac82a2e46d3be214cc2ef5263b569b2d8fd839b21a9e102665105ea762bda25bb446cfd831487a6b846100dee113ae95ae64f4af22c428c87bab809541c962bb3a56d4c86588e0af4ebc7fcc66dadced311051356d3ea745f7"); + + RSAKeyParameters rsaPublic = new RSAKeyParameters(false, n, e); + X931Signer signer = new X931Signer(new RSAEngine(), new SHA1Digest()); + + signer.init(false, rsaPublic); + + signer.update(msg, 0, msg.length); + + if (!signer.verifySignature(sig)) + { + fail("RSA X931 verify test 1 failed."); + } + } + + private void shouldPassSignatureTest2() + throws Exception + { + BigInteger n = new BigInteger("b746ba6c3c0be64bbe33aa55b2929b0af4e86d773d44bfe5914db9287788c4663984b61a418d2eecca30d752ff6b620a07ec72eeb2b422d2429da352407b99982800b9dd7697be6a7b1baa98ca5f4fc2fe33400f20b9dba337ac25c987804165d4a6e0ee4d18eabd6de5abdfe578cae6713ff91d16c80a5bb20217fe614d9509e75a43e1825327b9da8f0a9f6eeaa1c04b69fb4bacc073569fff4ab491becbe6d0441d437fc3fa823239c4a0f75321666b68dd3f66e2dd394089a15bcc288a68a4eb0a48e17d639743b9dea0a91cc35820544732aff253f8ca9967c609dc01c2f8cd0313a7a91cfa94ff74289a1d2b6f19d1811f4b9a65f4cce9e5759b4cc64f", 16); + BigInteger e = new BigInteger("dcbbdb", 16); + byte[] msg = Hex.decode("a5d3c8a060f897bbbc20ae0955052f37fbc70986b6e11c65075c9f457142bfa93856897c69020aa81a91b5e4f39e05cdeecc63395ab849c8262ca8bc5c96870aecb8edb0aba0024a9bdb71e06de6100344e5c318bc979ef32b8a49a8278ba99d4861bce42ebbc5c8c666aaa6cac39aff8779f2cae367620f9edd4cb1d80b6c8c"); + byte[] sig = Hex.decode("39fbbd1804c689a533b0043f84da0f06081038c0fbf31e443e46a05e58f50de5198bbca40522afefaba3aed7082a6cb93b1da39f1f5a42246bf64930781948d300549bef0f8d554ecfca60a1b1ecba95a7014ee4545ad4f0c4e3a31942c6738b4ccd6244b6a21267dadf0826a5f713f13b1f5a9ab8501d957a26d4948278ac67851071a315674bdab173bfef2c2690c8373da6bf3d69f30c0e5da8883de872f59521b40793854085641adf98d13db991c5d0a8aaa0222934fa33332e90ef0b954e195cb267d6ffb36c96e14d1ec7b915a87598b4461a3146566354dc2ae748c84ee0cd46543b53ebff8cdf47725b280a1f799fb6ebb4a31ad2bdd5178250f83a"); + + RSAKeyParameters rsaPublic = new RSAKeyParameters(false, n, e); + X931Signer signer = new X931Signer(new RSAEngine(), new SHA224Digest()); + + signer.init(false, rsaPublic); + + signer.update(msg, 0, msg.length); + + if (!signer.verifySignature(sig)) + { + fail("RSA X931 verify test 2 failed."); + } + } + + private void shouldPassSignatureTest3() + throws Exception + { + BigInteger n = new BigInteger("dcb5686a3d2063a3f9cf7b9b32d2d3765b4c449b09b4960245a9111cd3b0cbd3260496885b8e1fa5db33b03efcc759d9c1afe29d93c6faebc7e0efada334b5b9a29655e2da2c8f11103d8203be311feab7ae88e9f1b2ec7d8fc655d77202b1681dd9717ec0f525b35584987e19539635a1ed23ca482a00149c609a23dc1645fd", 16); + BigInteger e = new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dc9f7", 16); + BigInteger d = new BigInteger("189d6345099098992e0c9ca5f281e1338092342fa0acc85cc2a111f30f9bd2fb4753cd1a48ef0ddca9bf1af33ec76fb2e23a9fb4896c26f2235b516f7c05ef7ae81e70f4b491a5fedba9b935e9c76d761a813ce7776ff8a1e5efe1166ff2eca26aa900da88c908d51af9de26977fe39719cc781df32216fa41b838f0c63803c3", 16); + + byte[] msg = Hex.decode("911475c6e210ef4ac65b6fe8d2bfe5e01b959771b137c4ef69b88716e0d2ff9ebc1fad0f358c1dd7d50cc99a7b893ac9a6207076f08d8467d9e48c69c683bfe64a44dabaa3f7c243880f6ab7229bf7bb587822314fc5de5131983bfb2eef8b4bc1eac36f353724b567cd1ae8cddd64ddb7057549d5c81ad5fa3b5e751f00abf5"); + byte[] sig = Hex.decode("02c50ec0ac8a7f38ef5630c396964d6a6daaa7e3083ab5b57fa2a2632f3b70e2e85c8456cd774d45d7e44fcb063f0f04fff9f1e3adfda11272535a92cb59320b190b5ee4261f23d6ceaa925df3a7bfa42e26bf61ea9645d9d64b3c90a820802768a6e209c9f83705375a3867afccc037e8242a98fa4c3db6b2d9877754d47289"); + + RSAKeyParameters rsaPublic = new RSAKeyParameters(false, n, e); + X931Signer signer = new X931Signer(new RSAEngine(), new SHA1Digest()); + + signer.init(true, new RSAKeyParameters(true, n, d)); + + signer.update(msg, 0, msg.length); + + byte[] s = signer.generateSignature(); + + if (!Arrays.areEqual(sig, s)) + { + fail("RSA X931 sig test 3 failed."); + } + + signer.init(false, rsaPublic); + + signer.update(msg, 0, msg.length); + + if (!signer.verifySignature(sig)) + { + fail("RSA X931 verify test 3 failed."); + } + } + + public static void main(String[] args) + { + runTest(new X931SignerTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/XSalsa20Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/XSalsa20Test.java new file mode 100644 index 000000000..47cfcd139 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/XSalsa20Test.java @@ -0,0 +1,166 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.XSalsa20Engine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class XSalsa20Test extends SimpleTest +{ + private static class TestCase + { + + private byte[] key; + private byte[] iv; + private byte[] plaintext; + private byte[] ciphertext; + + public TestCase(String key, String iv, String plaintext, String ciphertext) + { + this.key = Hex.decode(key); + this.iv = Hex.decode(iv); + this.plaintext = Hex.decode(plaintext); + this.ciphertext = Hex.decode(ciphertext); + } + + public byte[] getKey() + { + return key; + } + + public byte[] getIv() + { + return iv; + } + + public byte[] getPlaintext() + { + return plaintext; + } + + public byte[] getCiphertext() + { + return ciphertext; + } + } + + // Test cases generated by naclcrypto-20090308, as used by cryptopp + private static final TestCase[] TEST_CASES = new TestCase[] { + new TestCase( + "a6a7251c1e72916d11c2cb214d3c252539121d8e234e652d651fa4c8cff88030", + "9e645a74e9e0a60d8243acd9177ab51a1beb8d5a2f5d700c", + "093c5e5585579625337bd3ab619d615760d8c5b224a85b1d0efe0eb8a7ee163abb0376529fcc09bab506c618e13ce777d82c3ae9d1a6f972d4160287cbfe60bf2130fc0a6ff6049d0a5c8a82f429231f008082e845d7e189d37f9ed2b464e6b919e6523a8c1210bd52a02a4c3fe406d3085f5068d1909eeeca6369abc981a42e87fe665583f0ab85ae71f6f84f528e6b397af86f6917d9754b7320dbdc2fea81496f2732f532ac78c4e9c6cfb18f8e9bdf74622eb126141416776971a84f94d156beaf67aecbf2ad412e76e66e8fad7633f5b6d7f3d64b5c6c69ce29003c6024465ae3b89be78e915d88b4b5621d", + "b2af688e7d8fc4b508c05cc39dd583d6714322c64d7f3e63147aede2d9534934b04ff6f337b031815cd094bdbc6d7a92077dce709412286822ef0737ee47f6b7ffa22f9d53f11dd2b0a3bb9fc01d9a88f9d53c26e9365c2c3c063bc4840bfc812e4b80463e69d179530b25c158f543191cff993106511aa036043bbc75866ab7e34afc57e2cce4934a5faae6eabe4f221770183dd060467827c27a354159a081275a291f69d946d6fe28ed0b9ce08206cf484925a51b9498dbde178ddd3ae91a8581b91682d860f840782f6eea49dbb9bd721501d2c67122dea3b7283848c5f13e0c0de876bd227a856e4de593a3"), + new TestCase( + "9e1da239d155f52ad37f75c7368a536668b051952923ad44f57e75ab588e475a", + "af06f17859dffa799891c4288f6635b5c5a45eee9017fd72", + "feac9d54fc8c115ae247d9a7e919dd76cfcbc72d32cae4944860817cbdfb8c04e6b1df76a16517cd33ccf1acda9206389e9e318f5966c093cfb3ec2d9ee2de856437ed581f552f26ac2907609df8c613b9e33d44bfc21ff79153e9ef81a9d66cc317857f752cc175fd8891fefebb7d041e6517c3162d197e2112837d3bc4104312ad35b75ea686e7c70d4ec04746b52ff09c421451459fb59f", + "2c261a2f4e61a62e1b27689916bf03453fcbc97bb2af6f329391ef063b5a219bf984d07d70f602d85f6db61474e9d9f5a2deecb4fcd90184d16f3b5b5e168ee03ea8c93f3933a22bc3d1a5ae8c2d8b02757c87c073409052a2a8a41e7f487e041f9a49a0997b540e18621cad3a24f0a56d9b19227929057ab3ba950f6274b121f193e32e06e5388781a1cb57317c0ba6305e910961d01002f0"), + new TestCase("d5c7f6797b7e7e9c1d7fd2610b2abf2bc5a7885fb3ff78092fb3abe8986d35e2", + "744e17312b27969d826444640e9c4a378ae334f185369c95", + "7758298c628eb3a4b6963c5445ef66971222be5d1a4ad839715d1188071739b77cc6e05d5410f963a64167629757", + "27b8cfe81416a76301fd1eec6a4d99675069b2da2776c360db1bdfea7c0aa613913e10f7a60fec04d11e65f2d64e"), + new TestCase( + "737d7811ce96472efed12258b78122f11deaec8759ccbd71eac6bbefa627785c", + "6fb2ee3dda6dbd12f1274f126701ec75c35c86607adb3edd", + "501325fb2645264864df11faa17bbd58312b77cad3d94ac8fb8542f0eb653ad73d7fce932bb874cb89ac39fc47f8267cf0f0c209f204b2d8578a3bdf461cb6a271a468bebaccd9685014ccbc9a73618c6a5e778a21cc8416c60ad24ddc417a130d53eda6dfbfe47d09170a7be1a708b7b5f3ad464310be36d9a2a95dc39e83d38667e842eb6411e8a23712297b165f690c2d7ca1b1346e3c1fccf5cafd4f8be0", + "6724c372d2e9074da5e27a6c54b2d703dc1d4c9b1f8d90f00c122e692ace7700eadca942544507f1375b6581d5a8fb39981c1c0e6e1ff2140b082e9ec016fce141d5199647d43b0b68bfd0fea5e00f468962c7384dd6129aea6a3fdfe75abb210ed5607cef8fa0e152833d5ac37d52e557b91098a322e76a45bbbcf4899e790618aa3f4c2e5e0fc3de93269a577d77a5502e8ea02f717b1dd2df1ec69d8b61ca"), + new TestCase( + "760158da09f89bbab2c99e6997f9523a95fcef10239bcca2573b7105f6898d34", + "43636b2cc346fc8b7c85a19bf507bdc3dafe953b88c69dba", + "d30a6d42dff49f0ed039a306bae9dec8d9e88366cc19e8c3642fd58fa0794ebf8029d949730339b0823a51f0f49f0d2c71f1051c1e0e2c86941f172789cdb1b0107413e70f982ff9761877bb526ef1c3eb1106a948d60ef21bd35d32cfd64f89b79ed63ecc5cca56246af736766f285d8e6b0da9cb1cd21020223ffacc5a32", + "c815b6b79b64f9369aec8dce8c753df8a50f2bc97c70ce2f014db33a65ac5816bac9e30ac08bdded308c65cb87e28e2e71b677dc25c5a6499c1553555daf1f55270a56959dffa0c66f24e0af00951ec4bb59ccc3a6c5f52e0981647e53e439313a52c40fa7004c855b6e6eb25b212a138e843a9ba46edb2a039ee82a263abe"), + new TestCase( + "27ba7e81e7edd4e71be53c07ce8e633138f287e155c7fa9e84c4ad804b7fa1b9", + "ea05f4ebcd2fb6b000da0612861ba54ff5c176fb601391aa", + "e09ff5d2cb050d69b2d42494bde5825238c756d6991d99d7a20d1ef0b83c371c89872690b2fc11d5369f4fc4971b6d3d6c078aef9b0f05c0e61ab89c025168054defeb03fef633858700c58b1262ce011300012673e893e44901dc18eee3105699c44c805897bdaf776af1833162a21a", + "a23e7ef93c5d0667c96d9e404dcbe6be62026fa98f7a3ff9ba5d458643a16a1cef7272dc6097a9b52f35983557c77a11b314b4f7d5dc2cca15ee47616f861873cbfed1d32372171a61e38e447f3cf362b3abbb2ed4170d89dcb28187b7bfd206a3e026f084a7e0ed63d319de6bc9afc0"), + new TestCase("6799d76e5ffb5b4920bc2768bafd3f8c16554e65efcf9a16f4683a7a06927c11", + "61ab951921e54ff06d9b77f313a4e49df7a057d5fd627989", "472766", "8fd7df"), + new TestCase( + "f68238c08365bb293d26980a606488d09c2f109edafa0bbae9937b5cc219a49c", + "5190b51e9b708624820b5abdf4e40fad1fb950ad1adc2d26", + "47ec6b1f73c4b7ff5274a0bfd7f45f864812c85a12fbcb3c2cf8a3e90cf66ccf2eacb521e748363c77f52eb426ae57a0c6c78f75af71284569e79d1a92f949a9d69c4efc0b69902f1e36d7562765543e2d3942d9f6ff5948d8a312cff72c1afd9ea3088aff7640bfd265f7a9946e606abc77bcedae6bddc75a0dba0bd917d73e3bd1268f727e0096345da1ed25cf553ea7a98fea6b6f285732de37431561ee1b3064887fbcbd71935e02", + "36160e88d3500529ba4edba17bc24d8cfaca9a0680b3b1fc97cf03f3675b7ac301c883a68c071bc54acdd3b63af4a2d72f985e51f9d60a4c7fd481af10b2fc75e252fdee7ea6b6453190617dcc6e2fe1cd56585fc2f0b0e97c5c3f8ad7eb4f31bc4890c03882aac24cc53acc1982296526690a220271c2f6e326750d3fbda5d5b63512c831f67830f59ac49aae330b3e0e02c9ea0091d19841f1b0e13d69c9fbfe8a12d6f30bb734d9d2"), + new TestCase( + "45b2bd0de4ed9293ec3e26c4840faaf64b7d619d51e9d7a2c7e36c83d584c3df", + "546c8c5d6be8f90952cab3f36d7c1957baaa7a59abe3d7e5", + "5007c8cd5b3c40e17d7fe423a87ae0ced86bec1c39dc07a25772f3e96dabd56cd3fd7319f6c9654925f2d87087a700e1b130da796895d1c9b9acd62b266144067d373ed51e787498b03c52faad16bb3826fa511b0ed2a19a8663f5ba2d6ea7c38e7212e9697d91486c49d8a000b9a1935d6a7ff7ef23e720a45855481440463b4ac8c4f6e7062adc1f1e1e25d3d65a31812f58a71160", + "8eacfba568898b10c0957a7d44100685e8763a71a69a8d16bc7b3f88085bb9a2f09642e4d09a9f0ad09d0aad66b22610c8bd02ff6679bb92c2c026a216bf425c6be35fb8dae7ff0c72b0efd6a18037c70eed0ca90062a49a3c97fdc90a8f9c2ea536bfdc41918a7582c9927fae47efaa3dc87967b7887dee1bf071734c7665901d9105dae2fdf66b4918e51d8f4a48c60d19fbfbbcba"), + new TestCase( + "fe559c9a282beb40814d016d6bfcb2c0c0d8bf077b1110b8703a3ce39d70e0e1", + "b076200cc7011259805e18b304092754002723ebec5d6200", + "6db65b9ec8b114a944137c821fd606be75478d928366d5284096cdef782fcff7e8f59cb8ffcda979757902c5ffa6bc477ceaa4cb5d5ea76f94d91e833f823a6bc78f1055dfa6a97bea8965c1cde67a668e001257334a585727d9e0f7c1a06e88d3d25a4e6d9096c968bf138e116a3ebeffd4bb4808adb1fd698164ba0a35c709a47f16f1f4435a2345a9194a00b95abd51851d505809a6077da9baca5831afff31578c487ee68f2767974a98a7e803aac788da98319c4ea8eaa3d394855651f484cef543f537e35158ee29", + "4dce9c8f97a028051b0727f34e1b9ef21f06f0760f36e71713204027902090ba2bb6b13436ee778d9f50530efbd7a32b0d41443f58ccaee781c7b716d3a96fdec0e3764ed7959f34c3941278591ea033b5cbadc0f1916032e9bebbd1a8395b83fb63b1454bd775bd20b3a2a96f951246ac14daf68166ba62f6cbff8bd121ac9498ff8852fd2be975df52b5daef3829d18eda42e715022dcbf930d0a789ee6a146c2c7088c35773c63c06b4af4559856ac199ced86863e4294707825337c5857970eb7fddeb263781309011"), + new TestCase( + "0ae10012d7e56614b03dcc89b14bae9242ffe630f3d7e35ce8bbb97bbc2c92c3", + "f96b025d6cf46a8a12ac2af1e2aef1fb83590adadaa5c5ea", + "ea0f354e96f12bc72bbaa3d12b4a8ed879b042f0689878f46b651cc4116d6f78409b11430b3aaa30b2076891e8e1fa528f2fd169ed93dc9f84e24409eec2101daf4d057be2492d11de640cbd7b355ad29fb70400fffd7cd6d425abeeb732a0eaa4330af4c656252c4173deab653eb85c58462d7ab0f35fd12b613d29d473d330310dc323d3c66348bbdbb68a326324657cae7b77a9e34358f2cec50c85609e73056856796e3be8d62b6e2fe9f953", + "e8abd48924b54e5b80866be7d4ebe5cf4274cafff08b39cb2d40a8f0b472398aedc776e0793812fbf1f60078635d2ed86b15efcdba60411ee23b07233592a44ec31b1013ce8964236675f8f183aef885e864f2a72edf4215b5338fa2b54653dfa1a8c55ce5d95cc605b9b311527f2e3463ffbec78a9d1d65dabad2f338769c9f43f133a791a11c7eca9af0b771a4ac32963dc8f631a2c11217ac6e1b9430c1aae1ceebe22703f429998a8fb8c641"), + new TestCase( + "082c539bc5b20f97d767cd3f229eda80b2adc4fe49c86329b5cd6250a9877450", + "845543502e8b64912d8f2c8d9fffb3c69365686587c08d0c", + "a96bb7e910281a6dfad7c8a9c370674f0ceec1ad8d4f0de32f9ae4a23ed329e3d6bc708f876640a229153ac0e7281a8188dd77695138f01cda5f41d5215fd5c6bdd46d982cb73b1efe2997970a9fdbdb1e768d7e5db712068d8ba1af6067b5753495e23e6e1963af012f9c7ce450bf2de619d3d59542fb55f3", + "835da74fc6de08cbda277a7966a07c8dcd627e7b17adde6d930b6581e3124b8baad096f693991fedb1572930601fc7709541839b8e3ffd5f033d2060d999c6c6e3048276613e648000acb5212cc632a916afce290e20ebdf612d08a6aa4c79a74b070d3f872a861f8dc6bb07614db515d363349d3a8e3336a3"), + new TestCase("3d02bff3375d403027356b94f514203737ee9a85d2052db3e4e5a217c259d18a", + "74216c95031895f48c1dba651555ebfa3ca326a755237025", + "0d4b0f54fd09ae39baa5fa4baccf2e6682e61b257e01f42b8f", + "16c4006c28365190411eb1593814cf15e74c22238f210afc3d"), + new TestCase( + "ad1a5c47688874e6663a0f3fa16fa7efb7ecadc175c468e5432914bdb480ffc6", + "e489eed440f1aae1fac8fb7a9825635454f8f8f1f52e2fcc", + "aa6c1e53580f03a9abb73bfdadedfecada4c6b0ebe020ef10db745e54ba861caf65f0e40dfc520203bb54d29e0a8f78f16b3f1aa525d6bfa33c54726e59988cfbec78056", + "02fe84ce81e178e7aabdd3ba925a766c3c24756eefae33942af75e8b464556b5997e616f3f2dfc7fce91848afd79912d9fb55201b5813a5a074d2c0d4292c1fd441807c5"), + new TestCase( + "053a02bedd6368c1fb8afc7a1b199f7f7ea2220c9a4b642a6850091c9d20ab9c", + "c713eea5c26dad75ad3f52451e003a9cb0d649f917c89dde", + "8f0a8a164760426567e388840276de3f95cb5e3fadc6ed3f3e4fe8bc169d9388804dcb94b6587dbb66cb0bd5f87b8e98b52af37ba290629b858e0e2aa7378047a26602", + "516710e59843e6fbd4f25d0d8ca0ec0d47d39d125e9dad987e0518d49107014cb0ae405e30c2eb3794750bca142ce95e290cf95abe15e822823e2e7d3ab21bc8fbd445"), + new TestCase( + "5b14ab0fbed4c58952548a6cb1e0000cf4481421f41288ea0aa84add9f7deb96", + "54bf52b911231b952ba1a6af8e45b1c5a29d97e2abad7c83", + "37fb44a675978b560ff9a4a87011d6f3ad2d37a2c3815b45a3c0e6d1b1d8b1784cd468927c2ee39e1dccd4765e1c3d676a335be1ccd6900a45f5d41a317648315d8a8c24adc64eb285f6aeba05b9029586353d303f17a807658b9ff790474e1737bd5fdc604aeff8dfcaf1427dcc3aacbb0256badcd183ed75a2dc52452f87d3c1ed2aa583472b0ab91cda20614e9b6fdbda3b49b098c95823cc72d8e5b717f2314b0324e9ce", + "ae6deb5d6ce43d4b09d0e6b1c0e9f46157bcd8ab50eaa3197ff9fa2bf7af649eb52c68544fd3adfe6b1eb316f1f23538d470c30dbfec7e57b60cbcd096c782e7736b669199c8253e70214cf2a098fda8eac5da79a9496a3aae754d03b17c6d70d1027f42bf7f95ce3d1d9c338854e158fcc803e4d6262fb639521e47116ef78a7a437ca9427ba645cd646832feab822a208278e45e93e118d780b988d65397eddfd7a819526e"), + new TestCase( + "d74636e3413a88d85f322ca80fb0bd650bd0bf0134e2329160b69609cd58a4b0", + "efb606aa1d9d9f0f465eaa7f8165f1ac09f5cb46fecf2a57", + "f85471b75f6ec81abac2799ec09e98e280b2ffd64ca285e5a0109cfb31ffab2d617b2c2952a2a8a788fc0da2af7f530758f74f1ab56391ab5ff2adbcc5be2d6c7f49fbe8118104c6ff9a23c6dfe52f57954e6a69dcee5db06f514f4a0a572a9a8525d961dae72269b987189d465df6107119c7fa790853e063cba0fab7800ca932e258880fd74c33c784675bedad0e7c09e9cc4d63dd5e9713d5d4a0196e6b562226ac31b4f57c04f90a181973737ddc7e80f364112a9fbb435ebdbcabf7d490ce52", + "b2b795fe6c1d4c83c1327e015a67d4465fd8e32813575cbab263e20ef05864d2dc17e0e4eb81436adfe9f638dcc1c8d78f6b0306baf938e5d2ab0b3e05e735cc6fff2d6e02e3d60484bea7c7a8e13e23197fea7b04d47d48f4a4e5944174539492800d3ef51e2ee5e4c8a0bdf050c2dd3dd74fce5e7e5c37364f7547a11480a3063b9a0a157b15b10a5a954de2731ced055aa2e2767f0891d4329c426f3808ee867bed0dc75b5922b7cfb895700fda016105a4c7b7f0bb90f029f6bbcb04ac36ac16") }; + + public String getName() + { + return "XSalsa20"; + } + + public void performTest() throws Exception + { + for (int i = 0; i < TEST_CASES.length; i++) + { + performTest(i, TEST_CASES[i]); + } + } + + private void performTest(int number, TestCase testCase) + { + final byte[] plaintext = testCase.getPlaintext(); + byte[] output = new byte[plaintext.length]; + + XSalsa20Engine engine = new XSalsa20Engine(); + engine.init(false, new ParametersWithIV(new KeyParameter(testCase.getKey()), testCase.getIv())); + + engine.processBytes(testCase.getPlaintext(), 0, testCase.getPlaintext().length, output, 0); + + if (!Arrays.areEqual(testCase.getCiphertext(), output)) + { + fail("mismatch on " + number, new String(Hex.encode(testCase.getCiphertext())), + new String(Hex.encode(output))); + } + } + + public static void main(String[] args) + { + runTest(new XSalsa20Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/XTEATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/XTEATest.java new file mode 100644 index 000000000..7f3ba4019 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/XTEATest.java @@ -0,0 +1,48 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.engines.XTEAEngine; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * TEA tester - based on C implementation results from http://www.simonshepherd.supanet.com/tea.htm + */ +public class XTEATest + extends CipherTest +{ + static SimpleTest[] tests = { + new BlockCipherVectorTest(0, new XTEAEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "0000000000000000", + "dee9d4d8f7131ed9"), + new BlockCipherVectorTest(1, new XTEAEngine(), + new KeyParameter(Hex.decode("00000000000000000000000000000000")), + "0102030405060708", + "065c1b8975c6a816"), + new BlockCipherVectorTest(2, new XTEAEngine(), + new KeyParameter(Hex.decode("0123456712345678234567893456789A")), + "0000000000000000", + "1ff9a0261ac64264"), + new BlockCipherVectorTest(3, new XTEAEngine(), + new KeyParameter(Hex.decode("0123456712345678234567893456789A")), + "0102030405060708", + "8c67155b2ef91ead"), + }; + + XTEATest() + { + super(tests, new XTEAEngine(), new KeyParameter(new byte[16])); + } + + public String getName() + { + return "XTEA"; + } + + public static void main( + String[] args) + { + runTest(new XTEATest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ZucTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ZucTest.java new file mode 100644 index 000000000..4bfedf758 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/ZucTest.java @@ -0,0 +1,497 @@ +package com.fr.third.org.bouncycastle.crypto.test; + +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.engines.Zuc128CoreEngine; +import com.fr.third.org.bouncycastle.crypto.engines.Zuc128Engine; +import com.fr.third.org.bouncycastle.crypto.engines.Zuc256CoreEngine; +import com.fr.third.org.bouncycastle.crypto.engines.Zuc256Engine; +import com.fr.third.org.bouncycastle.crypto.macs.Zuc128Mac; +import com.fr.third.org.bouncycastle.crypto.macs.Zuc256Mac; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test Cases for Zuc128 and Zuc256. + * Test Vectors taken from https://www.gsma.com/aboutus/wp-content/uploads/2014/12/eea3eia3zucv16.pdf for Zuc128 + * and http://www.is.cas.cn/ztzl2016/zouchongzhi/201801/W020180126529970733243.pdf for Zuc256. + */ +public class ZucTest + extends SimpleTest +{ + private static final int INT_SIZE = 32; + private static final int BYTE_SIZE = 8; + + /** + * Test Keys and IV. + */ + private static final String KEY128_1 = + "00000000000000000000000000000000"; + private static final String KEY128_2 = + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + private static final String KEY256_1 = + "00000000000000000000000000000000" + + "00000000000000000000000000000000"; + private static final String KEY256_2 = + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + private static final String IV128_1 = "00000000000000000000000000000000"; + private static final String IV128_2 = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + private static final String IV200_1 = "00000000000000000000000000000000000000000000000000"; + private static final String IV200_2 = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3F3F3F3F3F3F3F"; + + /** + * Define the bit limits for engines. + */ + private static final int ZUC256LIMIT = 20000; + private static final int ZUC128LIMIT = 65504; + + public String getName() + { + return "Zuc"; + } + + public void performTest() + throws Exception + { + new Zuc128Test().testTheCipher(); + new Zuc256Test().testTheCipher(); + new Zuc128MacTest().testTheMac(); + new Zuc256Mac32Test().testTheMac(); + new Zuc256Mac64Test().testTheMac(); + new Zuc256Mac128Test().testTheMac(); + } + + /** + * The TestCase. + */ + private static class TestCase + { + /** + * The testCase. + */ + private final String theKey; + private final String theIV; + private final String thePlainText; + private final String theExpected; + + /** + * Constructor. + * + * @param pKey the key + * @param pIV the IV + * @param pExpected the expected results. + */ + TestCase(final String pKey, + final String pIV, + final String pExpected) + { + this(pKey, pIV, null, pExpected); + } + + /** + * Constructor. + * + * @param pKey the key + * @param pIV the IV + * @param pPlain the plainText + * @param pExpected the expected results. + */ + TestCase(final String pKey, + final String pIV, + final String pPlain, + final String pExpected) + { + theKey = pKey; + theIV = pIV; + thePlainText = pPlain; + theExpected = pExpected; + } + } + + /** + * Zuc128. + */ + class Zuc128Test + { + /** + * TestCases. + */ + private final TestCase TEST4 = new TestCase(KEY128_1, IV128_1, + "27bede74018082da87d4e5b69f18bf6632070e0f39b7b692b4673edc3184a48e27636f4414510d62cc15cfe194ec4f6d4b8c8fcc630648badf41b6f9d16a36ca" + ); + private final TestCase TEST5 = new TestCase(KEY128_2, IV128_2, + "0657cfa07096398b734b6cb4883eedf4257a76eb97595208d884adcdb1cbffb8e0f9d15846a0eed015328503351138f740d079af17296c232c4f022d6e4acac6" + ); + + /** + * Test cipher. + */ + void testTheCipher() + { + final Zuc128CoreEngine myEngine = new Zuc128Engine(); + testCipher(myEngine, TEST4); + testCipher(myEngine, TEST5); + testStreamLimit(myEngine, TEST5, ZUC128LIMIT); + } + } + + /** + * Zuc256. + */ + class Zuc256Test + { + /** + * TestCases. + */ + private final TestCase TEST4 = new TestCase(KEY256_1, IV200_1, + "58d03ad62e032ce2dafc683a39bdcb0352a2bc67f1b7de74163ce3a101ef55589639d75b95fa681b7f090df756391ccc903b7612744d544c17bc3fad8b163b08" + ); + private final TestCase TEST5 = new TestCase(KEY256_2, IV200_2, + "3356cbaed1a1c18b6baa4ffe343f777c9e15128f251ab65b949f7b26ef7157f296dd2fa9df95e3ee7a5be02ec32ba585505af316c2f9ded27cdbd935e441ce11" + ); + + /** + * Test cipher. + */ + void testTheCipher() + { + final Zuc256CoreEngine myEngine = new Zuc256Engine(); + testCipher(myEngine, TEST4); + testCipher(myEngine, TEST5); + testStreamLimit(myEngine, TEST5, ZUC256LIMIT); + } + } + + /** + * Zuc128Mac. + */ + class Zuc128MacTest + { + + /** + * TestCases. + */ + private final TestCase TEST1 = new TestCase(KEY128_1, IV128_1, + "508dd5ff" + ); + private final TestCase TEST2 = new TestCase(KEY128_1, IV128_1, + "fbed4c12" + ); + private final TestCase TEST3 = new TestCase(KEY128_2, IV128_2, + "55e01504" + ); + private final TestCase TEST4 = new TestCase(KEY128_2, IV128_2, + "9ce9a0c4" + ); + + /** + * Test Mac. + */ + void testTheMac() + { + final Zuc128Mac myMac = new Zuc128Mac(); + testMac(myMac, false, TEST1); + testMac(myMac, true, TEST2); + testMac(myMac, false, TEST3); + testMac(myMac, true, TEST4); + testMacLimit(myMac, TEST4, ZUC128LIMIT - (2 * INT_SIZE)); + + // reset without init(). + Zuc128Mac xMac = new Zuc128Mac(); + + xMac.reset(); + } + } + + /** + * Zuc256Mac32. + */ + class Zuc256Mac32Test + { + /** + * TestCases. + */ + private final TestCase TEST1 = new TestCase(KEY256_1, IV200_1, + "9b972a74" + ); + private final TestCase TEST2 = new TestCase(KEY256_1, IV200_1, + "8754f5cf" + ); + private final TestCase TEST3 = new TestCase(KEY256_2, IV200_2, + "1f3079b4" + ); + private final TestCase TEST4 = new TestCase(KEY256_2, IV200_2, + "5c7c8b88" + ); + + /** + * Test Mac. + */ + void testTheMac() + { + final Zuc256Mac myMac = new Zuc256Mac(32); + testMac(myMac, false, TEST1); + testMac(myMac, true, TEST2); + testMac(myMac, false, TEST3); + testMac(myMac, true, TEST4); + testMacLimit(myMac, TEST4, ZUC256LIMIT - (2 * myMac.getMacSize() * BYTE_SIZE)); + + // reset without init(). + Zuc256Mac xMac = new Zuc256Mac(32); + + xMac.reset(); + } + } + + /** + * Zuc256Mac64. + */ + class Zuc256Mac64Test + { + /** + * TestCases. + */ + private final TestCase TEST1 = new TestCase(KEY256_1, IV200_1, + "673e54990034d38c" + ); + private final TestCase TEST2 = new TestCase(KEY256_1, IV200_1, + "130dc225e72240cc" + ); + private final TestCase TEST3 = new TestCase(KEY256_2, IV200_2, + "8c71394d39957725" + ); + private final TestCase TEST4 = new TestCase(KEY256_2, IV200_2, + "ea1dee544bb6223b" + ); + + /** + * Test Mac. + */ + void testTheMac() + { + final Zuc256Mac myMac = new Zuc256Mac(64); + testMac(myMac, false, TEST1); + testMac(myMac, true, TEST2); + testMac(myMac, false, TEST3); + testMac(myMac, true, TEST4); + testMacLimit(myMac, TEST4, ZUC256LIMIT - (2 * myMac.getMacSize() * BYTE_SIZE)); + } + } + + /** + * Zuc256Mac128. + */ + class Zuc256Mac128Test + { + /** + * TestCases. + */ + private final TestCase TEST1 = new TestCase(KEY256_1, IV200_1, + "d85e54bbcb9600967084c952a1654b26" + ); + private final TestCase TEST2 = new TestCase(KEY256_1, IV200_1, + "df1e8307b31cc62beca1ac6f8190c22f" + ); + private final TestCase TEST3 = new TestCase(KEY256_2, IV200_2, + "a35bb274b567c48b28319f111af34fbd" + ); + private final TestCase TEST4 = new TestCase(KEY256_2, IV200_2, + "3a83b554be408ca5494124ed9d473205" + ); + + /** + * Test Mac. + */ + void testTheMac() + { + final Zuc256Mac myMac = new Zuc256Mac(128); + testMac(myMac, false, TEST1); + testMac(myMac, true, TEST2); + testMac(myMac, false, TEST3); + testMac(myMac, true, TEST4); + testMacLimit(myMac, TEST4, ZUC256LIMIT - (2 * myMac.getMacSize() * BYTE_SIZE)); + } + } + + /** + * Test the Cipher against the results. + * + * @param pCipher the cipher to test. + * @param pTestCase the testCase + */ + void testCipher(final StreamCipher pCipher, + final TestCase pTestCase) + { + /* Access the expected bytes */ + final byte[] myExpected = Hex.decode(pTestCase.theExpected); + + /* Create the output buffer */ + final byte[] myOutput = new byte[myExpected.length]; + + /* Access plainText or nulls */ + final byte[] myData = pTestCase.thePlainText != null + ? Hex.decode(pTestCase.thePlainText) + : new byte[myExpected.length]; + + /* Access the key and the iv */ + final KeyParameter myKey = new KeyParameter(Hex.decode(pTestCase.theKey)); + final byte[] myIV = Hex.decode(pTestCase.theIV); + final ParametersWithIV myParms = new ParametersWithIV(myKey, myIV); + + /* Initialise the cipher and create the keyStream */ + pCipher.init(true, myParms); + pCipher.processBytes(myData, 0, myData.length, myOutput, 0); + + /* Check the encryption */ + isTrue("Encryption mismatch", Arrays.areEqual(myExpected, myOutput)); + } + + /** + * Test the Mac against the results. + * + * @param pMac the mac to test. + * @param pOnes use all ones as data? + * @param pTestCase the testCase + */ + void testMac(final Mac pMac, + final boolean pOnes, + final TestCase pTestCase) + { + /* Access the expected bytes */ + final byte[] myExpected = Hex.decode(pTestCase.theExpected); + + /* Create the output buffer and the data */ + final byte[] myOutput = new byte[pMac.getMacSize()]; + final byte[] myData = new byte[(pOnes ? 4000 : 400) / 8]; + Arrays.fill(myData, (byte)(pOnes ? 0x11 : 0)); + + /* Access the key and the iv */ + final KeyParameter myKey = new KeyParameter(Hex.decode(pTestCase.theKey)); + final byte[] myIV = Hex.decode(pTestCase.theIV); + final ParametersWithIV myParms = new ParametersWithIV(myKey, myIV); + + /* Initialise the cipher and create the keyStream */ + pMac.init(myParms); + pMac.update(myData, 0, myData.length); + pMac.doFinal(myOutput, 0); + + /* Check the mac */ + isTrue("Mac mismatch", Arrays.areEqual(myExpected, myOutput)); + + /* Check doFinal reset */ + pMac.update(myData, 0, myData.length); + pMac.doFinal(myOutput, 0); + + isTrue("DoFinal Mac mismatch", Arrays.areEqual(myExpected, myOutput)); + + /* Check reset() */ + pMac.update(myData, 0, myData.length); + + pMac.reset(); + + pMac.update(myData, 0, myData.length); + pMac.doFinal(myOutput, 0); + + isTrue("Reset Mac mismatch", Arrays.areEqual(myExpected, myOutput)); + } + + /** + * Test the Stream Cipher against the limit. + * + * @param pCipher the cipher to test. + * @param pTestCase the testCase + * @param pLimit the limit in bits. + */ + void testStreamLimit(final StreamCipher pCipher, + final TestCase pTestCase, + final int pLimit) + { + /* Check the limit is a whole number of integers */ + isTrue("Invalid limit", (pLimit % INT_SIZE == 0)); + final int myNumBytes = pLimit / BYTE_SIZE; + + /* Create the maximum # of bytes */ + final byte[] myData = new byte[myNumBytes]; + final byte[] myOutput = new byte[myNumBytes]; + + /* Access the key and the iv */ + final KeyParameter myKey = new KeyParameter(Hex.decode(pTestCase.theKey)); + final byte[] myIV = Hex.decode(pTestCase.theIV); + final ParametersWithIV myParms = new ParametersWithIV(myKey, myIV); + + /* Initialise the cipher and create the keyStream */ + pCipher.init(true, myParms); + pCipher.processBytes(myData, 0, myData.length, myOutput, 0); + + /* Check that next encryption throws exception */ + try + { + pCipher.processBytes(myData, 0, 1, myOutput, 0); + fail("Limit Failure"); + } + catch (IllegalStateException e) + { + /* OK */ + } + } + + /** + * Test the Mac against the limit. + * + * @param pMac the mac to test. + * @param pTestCase the testCase + * @param pLimit the limit in bits. + */ + void testMacLimit(final Mac pMac, + final TestCase pTestCase, + final int pLimit) + { + /* Check the limit is a whole numbet of integers */ + isTrue("Invalid limit", (pLimit % INT_SIZE == 0)); + final int myNumBytes = pLimit / BYTE_SIZE; + + /* Create the maximum # of bytes */ + final byte[] myData = new byte[myNumBytes]; + final byte[] myOutput = new byte[myNumBytes]; + + /* Access the key and the iv */ + final KeyParameter myKey = new KeyParameter(Hex.decode(pTestCase.theKey)); + final byte[] myIV = Hex.decode(pTestCase.theIV); + final ParametersWithIV myParms = new ParametersWithIV(myKey, myIV); + + /* Initialise the mac and create the result */ + pMac.init(myParms); + pMac.update(myData, 0, myData.length); + pMac.doFinal(myOutput, 0); + + /* Initialise the mac and process as much data as possible */ + pMac.init(myParms); + pMac.update(myData, 0, myData.length); + + /* We expect a failure on processing a further byte */ + try + { + pMac.update(myData, 0, 1); + pMac.doFinal(myOutput, 0); + fail("Limit Failure"); + } + catch (IllegalStateException e) + { + /* OK */ + } + } + + /** + * Main entry point. + * + * @param args the argyments + */ + public static void main(String[] args) + { + runTest(new ZucTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/CAVPListener.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/CAVPListener.java new file mode 100644 index 000000000..d9a4c60d0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/CAVPListener.java @@ -0,0 +1,18 @@ +package com.fr.third.org.bouncycastle.crypto.test.cavp; + +import java.util.Properties; + +public interface CAVPListener +{ + public void setup(); + + public void receiveStart(String name); + + public void receiveCAVPVectors(String name, Properties config, Properties vectors); + + public void receiveCommentLine(String commentLine); + + public void receiveEnd(); + + public void tearDown(); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/CAVPReader.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/CAVPReader.java new file mode 100644 index 000000000..ae7947e9c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/CAVPReader.java @@ -0,0 +1,152 @@ +package com.fr.third.org.bouncycastle.crypto.test.cavp; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Reader; +import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA224Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA384Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.macs.CMac; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; + +public class CAVPReader +{ + + private static final Pattern COMMENT_PATTERN = Pattern.compile("^\\s*\\#\\s*(.*)$"); + private static final Pattern CONFIG_PATTERN = Pattern.compile("^\\s*+\\[\\s*+(.*?)\\s*+=\\s*+(.*?)\\s*+\\]\\s*+$"); + private static final Pattern VECTOR_PATTERN = Pattern.compile("^\\s*+(.*?)\\s*+=\\s*+(.*?)\\s*+$"); + private static final Pattern EMPTY_PATTERN = Pattern.compile("^\\s*+$"); + static final Pattern PATTERN_FOR_R = Pattern.compile("(\\d+)_BITS"); + private final CAVPListener listener; + private String name; + private BufferedReader lineReader; + + + public CAVPReader(CAVPListener listener) + { + this.listener = listener; + } + + public void setInput(String name, Reader reader) + { + this.name = name; + this.lineReader = new BufferedReader(reader); + } + + public void readAll() + throws IOException + { + + listener.setup(); + + Properties config = new Properties(); + + boolean startNewVector = true; + + Properties vectors = new Properties(); + + while (true) + { + final String line = lineReader.readLine(); + if (line == null) + { + listener.receiveEnd(); + break; + } + + final Matcher commentMatcher = COMMENT_PATTERN.matcher(line); + if (commentMatcher.matches()) + { + listener.receiveCommentLine(commentMatcher.group(1)); + continue; + } + + final Matcher configMatcher = CONFIG_PATTERN.matcher(line); + if (configMatcher.matches()) + { + config.put(configMatcher.group(1), configMatcher.group(2)); + continue; + } + + final Matcher vectorMatcher = VECTOR_PATTERN.matcher(line); + if (vectorMatcher.matches()) + { + vectors.put(vectorMatcher.group(1), vectorMatcher.group(2)); + startNewVector = false; + continue; + } + + final Matcher emptyMatcher = EMPTY_PATTERN.matcher(line); + if (emptyMatcher.matches()) + { + if (startNewVector) + { + continue; + } + + listener.receiveCAVPVectors(name, config, vectors); + vectors = new Properties(); + startNewVector = true; + } + } + + listener.tearDown(); + } + + static Mac createPRF(Properties config) + { + final Mac prf; + if (config.getProperty("PRF").matches("CMAC_AES\\d\\d\\d")) + { + BlockCipher blockCipher = new AESEngine(); + prf = new CMac(blockCipher); + } + else if (config.getProperty("PRF").matches("CMAC_TDES\\d")) + { + BlockCipher blockCipher = new DESedeEngine(); + prf = new CMac(blockCipher); + } + else if (config.getProperty("PRF").matches("HMAC_SHA1")) + { + Digest digest = new SHA1Digest(); + prf = new HMac(digest); + } + else if (config.getProperty("PRF").matches("HMAC_SHA224")) + { + Digest digest = new SHA224Digest(); + prf = new HMac(digest); + } + else if (config.getProperty("PRF").matches("HMAC_SHA256")) + { + Digest digest = new SHA256Digest(); + prf = new HMac(digest); + } + else if (config.getProperty("PRF").matches("HMAC_SHA384")) + { + Digest digest = new SHA384Digest(); + prf = new HMac(digest); + } + else if (config.getProperty("PRF").matches("HMAC_SHA512")) + { + Digest digest = new SHA512Digest(); + prf = new HMac(digest); + } + else + { + throw new IllegalStateException("Unknown Mac for PRF"); + } + return prf; + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFCounterTests.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFCounterTests.java new file mode 100644 index 000000000..34e284e77 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFCounterTests.java @@ -0,0 +1,119 @@ +package com.fr.third.org.bouncycastle.crypto.test.cavp; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; +import java.util.regex.Matcher; + +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.generators.KDFCounterBytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.KDFCounterParameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +public final class KDFCounterTests + implements CAVPListener +{ + private PrintWriter out; + + public void receiveCAVPVectors(String name, Properties config, + Properties vectors) + { + + // create Mac based PRF from PRF property, create the KDF + final Mac prf = CAVPReader.createPRF(config); + final KDFCounterBytesGenerator gen = new KDFCounterBytesGenerator(prf); + + + Matcher matcherForR = CAVPReader.PATTERN_FOR_R.matcher(config.getProperty("RLEN")); + if (!matcherForR.matches()) + { + throw new IllegalStateException("RLEN value should always match"); + } + final int r = Integer.parseInt(matcherForR.group(1)); + + final int count = Integer.parseInt(vectors.getProperty("COUNT")); + final int l = Integer.parseInt(vectors.getProperty("L")); + final byte[] ki = Hex.decode(vectors.getProperty("KI")); + + //Three variants of this KDF are possible, with the counter before the fixed data, after the fixed data, or in the middle of the fixed data. + if (config.getProperty("CTRLOCATION").matches("BEFORE_FIXED")) + { + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFCounterParameters params = new KDFCounterParameters(ki, null, fixedInputData, r); + gen.init(params); + } + else if (config.getProperty("CTRLOCATION").matches("AFTER_FIXED")) + { + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFCounterParameters params = new KDFCounterParameters(ki, fixedInputData, null, r); + gen.init(params); + } + else if (config.getProperty("CTRLOCATION").matches("MIDDLE_FIXED")) + { + final byte[] DataBeforeCtrData = Hex.decode(vectors.getProperty("DataBeforeCtrData")); + final byte[] DataAfterCtrData = Hex.decode(vectors.getProperty("DataAfterCtrData")); + final KDFCounterParameters params = new KDFCounterParameters(ki, DataBeforeCtrData, DataAfterCtrData, r); + gen.init(params); + } + else + { + return; // Unknown CTRLOCATION + } + + + final byte[] koGenerated = new byte[l / 8]; + gen.generateBytes(koGenerated, 0, koGenerated.length); + + final byte[] koVectors = Hex.decode(vectors.getProperty("KO")); + + compareKO(name, config, count, koGenerated, koVectors); + } + + private static void compareKO( + String name, Properties config, int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!Arrays.areEqual(calculatedOKM, testOKM)) + { + throw new TestFailedException(new SimpleTestResult( + false, name + " using " + config + " test " + test + " failed")); + + } + } + + public void receiveCommentLine(String commentLine) + { + // out.println("# " + commentLine); + } + + public void receiveStart(String name) + { + // do nothing + } + + public void receiveEnd() + { + out.println(" *** *** *** "); + } + + public void setup() + { + try + { + out = new PrintWriter(new FileWriter("KDFCTR.gen")); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + + public void tearDown() + { + out.close(); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFDoublePipelineCounterTests.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFDoublePipelineCounterTests.java new file mode 100644 index 000000000..e7fa9f6fa --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFDoublePipelineCounterTests.java @@ -0,0 +1,107 @@ +package com.fr.third.org.bouncycastle.crypto.test.cavp; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; +import java.util.regex.Matcher; + +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.generators.KDFDoublePipelineIterationBytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.KDFDoublePipelineIterationParameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +public final class KDFDoublePipelineCounterTests + implements CAVPListener +{ + private PrintWriter out; + + public void receiveCAVPVectors(String name, Properties config, + Properties vectors) + { + // out.println(" === " + name + " === "); + // out.println(" --- config --- "); + // out.println(config); + // out.println(" --- vectors --- "); + // out.println(vectors); + + // always skip AFTER_FIXED + if (!config.getProperty("CTRLOCATION").matches("AFTER_ITER")) + { + return; + } + + // create Mac based PRF from PRF property, create the KDF + final Mac prf = CAVPReader.createPRF(config); + final KDFDoublePipelineIterationBytesGenerator gen = new KDFDoublePipelineIterationBytesGenerator(prf); + + + Matcher matcherForR = CAVPReader.PATTERN_FOR_R.matcher(config.getProperty("RLEN")); + if (!matcherForR.matches()) + { + throw new IllegalStateException("RLEN value should always match"); + } + final int r = Integer.parseInt(matcherForR.group(1)); + + final int count = Integer.parseInt(vectors.getProperty("COUNT")); + final int l = Integer.parseInt(vectors.getProperty("L")); + final byte[] ki = Hex.decode(vectors.getProperty("KI")); + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFDoublePipelineIterationParameters params = KDFDoublePipelineIterationParameters.createWithCounter(ki, fixedInputData, r); + gen.init(params); + + final byte[] koGenerated = new byte[l / 8]; + gen.generateBytes(koGenerated, 0, koGenerated.length); + + final byte[] koVectors = Hex.decode(vectors.getProperty("KO")); + + compareKO(name, config, count, koGenerated, koVectors); + } + + private static void compareKO( + String name, Properties config, int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!Arrays.areEqual(calculatedOKM, testOKM)) + { + throw new TestFailedException(new SimpleTestResult( + false, name + " using " + config + " test " + test + " failed")); + + } + } + + public void receiveCommentLine(String commentLine) + { + // out.println("# " + commentLine); + } + + public void receiveStart(String name) + { + // do nothing + } + + public void receiveEnd() + { + out.println(" *** *** *** "); + } + + public void setup() + { + try + { + out = new PrintWriter(new FileWriter("KDFDblPipelineCounter.gen")); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + + public void tearDown() + { + out.close(); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFDoublePipelineIterationNoCounterTests.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFDoublePipelineIterationNoCounterTests.java new file mode 100644 index 000000000..36ead842b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFDoublePipelineIterationNoCounterTests.java @@ -0,0 +1,88 @@ +package com.fr.third.org.bouncycastle.crypto.test.cavp; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; + +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.generators.KDFDoublePipelineIterationBytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.KDFDoublePipelineIterationParameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +public final class KDFDoublePipelineIterationNoCounterTests + implements CAVPListener +{ + private PrintWriter out; + + public void receiveCAVPVectors(String name, Properties config, + Properties vectors) + { + + + // create Mac based PRF from PRF property, create the KDF + final Mac prf = CAVPReader.createPRF(config); + final KDFDoublePipelineIterationBytesGenerator gen = new KDFDoublePipelineIterationBytesGenerator(prf); + + final int count = Integer.parseInt(vectors.getProperty("COUNT")); + final int l = Integer.parseInt(vectors.getProperty("L")); + final byte[] ki = Hex.decode(vectors.getProperty("KI")); + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFDoublePipelineIterationParameters params = KDFDoublePipelineIterationParameters.createWithoutCounter(ki, fixedInputData); + gen.init(params); + + final byte[] koGenerated = new byte[l / 8]; + gen.generateBytes(koGenerated, 0, koGenerated.length); + + final byte[] koVectors = Hex.decode(vectors.getProperty("KO")); + + compareKO(name, config, count, koGenerated, koVectors); + } + + private static void compareKO( + String name, Properties config, int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!Arrays.areEqual(calculatedOKM, testOKM)) + { + throw new TestFailedException(new SimpleTestResult( + false, name + " using " + config + " test " + test + " failed")); + + } + } + + public void receiveCommentLine(String commentLine) + { + // out.println("# " + commentLine); + } + + public void receiveStart(String name) + { + // do nothing + } + + public void receiveEnd() + { + out.println(" *** *** *** "); + } + + public void setup() + { + try + { + out = new PrintWriter(new FileWriter("KDFDblPipelineNoCounter.gen")); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + + public void tearDown() + { + out.close(); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFFeedbackCounterTests.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFFeedbackCounterTests.java new file mode 100644 index 000000000..ad7165837 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFFeedbackCounterTests.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.crypto.test.cavp; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; +import java.util.regex.Matcher; + +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.generators.KDFFeedbackBytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.KDFFeedbackParameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +public final class KDFFeedbackCounterTests + implements CAVPListener +{ + private PrintWriter out; + + public void receiveCAVPVectors(String name, Properties config, + Properties vectors) + { + // out.println(" === " + name + " === "); + // out.println(" --- config --- "); + // out.println(config); + // out.println(" --- vectors --- "); + // out.println(vectors); + + // always skip AFTER_FIXED + if (!config.getProperty("CTRLOCATION").matches("AFTER_ITER")) + { + return; + } + + // create Mac based PRF from PRF property, create the KDF + final Mac prf = CAVPReader.createPRF(config); + final KDFFeedbackBytesGenerator gen = new KDFFeedbackBytesGenerator(prf); + + + Matcher matcherForR = CAVPReader.PATTERN_FOR_R.matcher(config.getProperty("RLEN")); + if (!matcherForR.matches()) + { + throw new IllegalStateException("RLEN value should always match"); + } + final int r = Integer.parseInt(matcherForR.group(1)); + + final int count = Integer.parseInt(vectors.getProperty("COUNT")); + final int l = Integer.parseInt(vectors.getProperty("L")); + final byte[] ki = Hex.decode(vectors.getProperty("KI")); + final byte[] iv = Hex.decode(vectors.getProperty("IV")); + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFFeedbackParameters params = KDFFeedbackParameters.createWithCounter(ki, iv, fixedInputData, r); + gen.init(params); + + final byte[] koGenerated = new byte[l / 8]; + gen.generateBytes(koGenerated, 0, koGenerated.length); + + final byte[] koVectors = Hex.decode(vectors.getProperty("KO")); + + compareKO(name, config, count, koGenerated, koVectors); + } + + private static void compareKO( + String name, Properties config, int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!Arrays.areEqual(calculatedOKM, testOKM)) + { + throw new TestFailedException(new SimpleTestResult( + false, name + " using " + config + " test " + test + " failed")); + + } + } + + public void receiveCommentLine(String commentLine) + { + // out.println("# " + commentLine); + } + + public void receiveStart(String name) + { + // do nothing + } + + public void receiveEnd() + { + out.println(" *** *** *** "); + } + + public void setup() + { + try + { + out = new PrintWriter(new FileWriter("KDFFeedbackCounter.gen")); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + + public void tearDown() + { + out.close(); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFFeedbackNoCounterTests.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFFeedbackNoCounterTests.java new file mode 100644 index 000000000..946adb49d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/cavp/KDFFeedbackNoCounterTests.java @@ -0,0 +1,89 @@ +package com.fr.third.org.bouncycastle.crypto.test.cavp; + +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Properties; + +import com.fr.third.org.bouncycastle.crypto.Mac; +import com.fr.third.org.bouncycastle.crypto.generators.KDFFeedbackBytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.KDFFeedbackParameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +public final class KDFFeedbackNoCounterTests + implements CAVPListener +{ + private PrintWriter out; + + public void receiveCAVPVectors(String name, Properties config, + Properties vectors) + { + + + // create Mac based PRF from PRF property, create the KDF + final Mac prf = CAVPReader.createPRF(config); + final KDFFeedbackBytesGenerator gen = new KDFFeedbackBytesGenerator(prf); + + final int count = Integer.parseInt(vectors.getProperty("COUNT")); + final int l = Integer.parseInt(vectors.getProperty("L")); + final byte[] ki = Hex.decode(vectors.getProperty("KI")); + final byte[] iv = Hex.decode(vectors.getProperty("IV")); + final byte[] fixedInputData = Hex.decode(vectors.getProperty("FixedInputData")); + final KDFFeedbackParameters params = KDFFeedbackParameters.createWithoutCounter(ki, iv, fixedInputData); + gen.init(params); + + final byte[] koGenerated = new byte[l / 8]; + gen.generateBytes(koGenerated, 0, koGenerated.length); + + final byte[] koVectors = Hex.decode(vectors.getProperty("KO")); + + compareKO(name, config, count, koGenerated, koVectors); + } + + private static void compareKO( + String name, Properties config, int test, byte[] calculatedOKM, byte[] testOKM) + { + + if (!Arrays.areEqual(calculatedOKM, testOKM)) + { + throw new TestFailedException(new SimpleTestResult( + false, name + " using " + config + " test " + test + " failed")); + + } + } + + public void receiveCommentLine(String commentLine) + { +// out.println("# " + commentLine); + } + + public void receiveStart(String name) + { + // do nothing + } + + public void receiveEnd() + { + out.println(" *** *** *** "); + } + + public void setup() + { + try + { + out = new PrintWriter(new FileWriter("KDFFeedbackNoCounter.gen")); + } + catch (IOException e) + { + throw new IllegalStateException(e); + } + } + + public void tearDown() + { + out.close(); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/package.html b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/package.html new file mode 100644 index 000000000..7bb5e6b1a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/test/package.html @@ -0,0 +1,5 @@ + + +Example code and test classes for the lightweight API. + + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsAgreementCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsAgreementCredentials.java index 9c10bfd16..26953b5c1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsAgreementCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsAgreementCredentials.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class AbstractTlsAgreementCredentials extends AbstractTlsCredentials implements TlsAgreementCredentials diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsCipherFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsCipherFactory.java index 3a119106d..2718b8919 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsCipherFactory.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsCipherFactory.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class AbstractTlsCipherFactory implements TlsCipherFactory { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsClient.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsClient.java index 9a5c14195..323bb3460 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsClient.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsClient.java @@ -4,6 +4,9 @@ import java.io.IOException; import java.util.Hashtable; import java.util.Vector; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class AbstractTlsClient extends AbstractTlsPeer implements TlsClient diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsContext.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsContext.java index e17993c9a..92b46d03f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsContext.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsContext.java @@ -98,21 +98,23 @@ abstract class AbstractTlsContext public byte[] exportKeyingMaterial(String asciiLabel, byte[] context_value, int length) { - /* - * TODO[session-hash] - * - * draft-ietf-tls-session-hash-04 5.4. If a client or server chooses to continue with a full - * handshake without the extended master secret extension, [..] the client or server MUST - * NOT export any key material based on the new master secret for any subsequent - * application-level authentication. In particular, it MUST disable [RFC5705] [..]. - */ - if (context_value != null && !TlsUtils.isValidUint16(context_value.length)) { throw new IllegalArgumentException("'context_value' must have length less than 2^16 (or be null)"); } SecurityParameters sp = getSecurityParameters(); + if (!sp.isExtendedMasterSecret()) + { + /* + * RFC 7627 5.4. If a client or server chooses to continue with a full handshake without + * the extended master secret extension, [..] the client or server MUST NOT export any + * key material based on the new master secret for any subsequent application-level + * authentication. In particular, it MUST disable [RFC5705] [..]. + */ + throw new IllegalStateException("cannot export keying material without extended_master_secret"); + } + byte[] cr = sp.getClientRandom(), sr = sp.getServerRandom(); int seedLength = cr.length + sr.length; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsCredentials.java index 36fdea7e4..040bcb88c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsCredentials.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class AbstractTlsCredentials implements TlsCredentials { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsEncryptionCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsEncryptionCredentials.java index 6902e7e00..d5250301d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsEncryptionCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsEncryptionCredentials.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class AbstractTlsEncryptionCredentials extends AbstractTlsCredentials implements TlsEncryptionCredentials diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsKeyExchange.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsKeyExchange.java index 52695c659..2147196b3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsKeyExchange.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsKeyExchange.java @@ -4,6 +4,9 @@ import java.io.IOException; import java.io.InputStream; import java.util.Vector; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class AbstractTlsKeyExchange implements TlsKeyExchange { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsPeer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsPeer.java index 459824f0f..cae77e1ea 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsPeer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsPeer.java @@ -2,9 +2,33 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class AbstractTlsPeer implements TlsPeer { + private volatile TlsCloseable closeHandle; + + public void cancel() throws IOException + { + TlsCloseable closeHandle = this.closeHandle; + if (null != closeHandle) + { + closeHandle.close(); + } + } + + public void notifyCloseHandle(TlsCloseable closeHandle) + { + this.closeHandle = closeHandle; + } + + public boolean requiresExtendedMasterSecret() + { + return false; + } + public boolean shouldUseGMTUnixTime() { /* diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsServer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsServer.java index 581b98a54..9b7dc0b30 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsServer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsServer.java @@ -6,6 +6,9 @@ import java.util.Vector; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class AbstractTlsServer extends AbstractTlsPeer implements TlsServer diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsSigner.java index d49daa0f1..872169516 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsSigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsSigner.java @@ -4,6 +4,9 @@ import com.fr.third.org.bouncycastle.crypto.CryptoException; import com.fr.third.org.bouncycastle.crypto.Signer; import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class AbstractTlsSigner implements TlsSigner { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsSignerCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsSignerCredentials.java index 06bfe09cb..d397d1868 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsSignerCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AbstractTlsSignerCredentials.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class AbstractTlsSignerCredentials extends AbstractTlsCredentials implements TlsSignerCredentials diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AlertDescription.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AlertDescription.java index 41b13caa7..89b1be0d9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AlertDescription.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AlertDescription.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 5246 7.2. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class AlertDescription { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AlertLevel.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AlertLevel.java index 023548ae4..29744cb26 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AlertLevel.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/AlertLevel.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 5246 7.2 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class AlertLevel { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/BasicTlsPSKIdentity.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/BasicTlsPSKIdentity.java index 722350fcc..c8f6590ec 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/BasicTlsPSKIdentity.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/BasicTlsPSKIdentity.java @@ -3,6 +3,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.Strings; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class BasicTlsPSKIdentity implements TlsPSKIdentity { @@ -36,7 +39,6 @@ public class BasicTlsPSKIdentity public byte[] getPSK() { - return psk; + return Arrays.clone(psk); } - } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/BulkCipherAlgorithm.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/BulkCipherAlgorithm.java index 953aa716c..87eef0ab1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/BulkCipherAlgorithm.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/BulkCipherAlgorithm.java @@ -5,6 +5,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; *

* Note that the values here are implementation-specific and arbitrary. It is recommended not to * depend on the particular values (e.g. serialization). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class BulkCipherAlgorithm { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueue.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueue.java index 6ef32cb18..974d00309 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueue.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueue.java @@ -6,6 +6,8 @@ import java.io.OutputStream; /** * A queue for bytes. This file could be more optimized. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class ByteQueue { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueueInputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueueInputStream.java index 0e2db4241..5aa37cf30 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueueInputStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueueInputStream.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.InputStream; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class ByteQueueInputStream extends InputStream { @@ -12,9 +15,14 @@ public class ByteQueueInputStream buffer = new ByteQueue(); } - public void addBytes(byte[] bytes) + public void addBytes(byte[] buf) { - buffer.addData(bytes, 0, bytes.length); + buffer.addData(buf, 0, buf.length); + } + + public void addBytes(byte[] buf, int bufOff, int bufLen) + { + buffer.addData(buf, bufOff, bufLen); } public int peek(byte[] buf) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueueOutputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueueOutputStream.java index 91cb8be8a..6ca18b5f5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueueOutputStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ByteQueueOutputStream.java @@ -3,6 +3,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; import java.io.OutputStream; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class ByteQueueOutputStream extends OutputStream { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertChainType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertChainType.java index 60486eb16..5eaa84c4c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertChainType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertChainType.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /* * RFC 3546 3.3. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class CertChainType { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/Certificate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/Certificate.java index 2e5103122..f4d913a1f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/Certificate.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/Certificate.java @@ -20,6 +20,8 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; *

* * @see com.fr.third.org.bouncycastle.asn1.x509.Certificate + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class Certificate { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateRequest.java index d9ec981a2..b22d2b37a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateRequest.java @@ -21,6 +21,8 @@ import com.fr.third.org.bouncycastle.asn1.x500.X500Name; * * @see ClientCertificateType * @see X500Name + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class CertificateRequest { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatus.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatus.java index 468bb3193..e20563850 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatus.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatus.java @@ -7,6 +7,9 @@ import java.io.OutputStream; import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; import com.fr.third.org.bouncycastle.asn1.ocsp.OCSPResponse; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class CertificateStatus { protected short statusType; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatusRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatusRequest.java index 05ba6fe7b..2f527a5ce 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatusRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatusRequest.java @@ -4,6 +4,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class CertificateStatusRequest { protected short statusType; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatusType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatusType.java index d2b86ed4f..18ac5e1ad 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatusType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateStatusType.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class CertificateStatusType { /* diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateType.java index 507b914ad..8fa4fd187 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateType.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 6091 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class CertificateType { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateURL.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateURL.java index afa783e14..ca99a24f2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateURL.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CertificateURL.java @@ -9,6 +9,8 @@ import java.util.Vector; /* * RFC 3546 3.3 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class CertificateURL { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/Chacha20Poly1305.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/Chacha20Poly1305.java index 57ca673f6..a9790d710 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/Chacha20Poly1305.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/Chacha20Poly1305.java @@ -13,6 +13,8 @@ import com.fr.third.org.bouncycastle.util.Pack; /** * draft-ietf-tls-chacha20-poly1305-04 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class Chacha20Poly1305 implements TlsCipher { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ChangeCipherSpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ChangeCipherSpec.java index ca6c0d184..9ab727056 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ChangeCipherSpec.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ChangeCipherSpec.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class ChangeCipherSpec { public static final short change_cipher_spec = 1; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CipherSuite.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CipherSuite.java index 458706afc..0e8007724 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CipherSuite.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CipherSuite.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 2246 A.5 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class CipherSuite { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CipherType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CipherType.java index 26a144dd6..06f8fd9ed 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CipherType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CipherType.java @@ -5,6 +5,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; *

* Note that the values here are implementation-specific and arbitrary. It is recommended not to * depend on the particular values (e.g. serialization). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class CipherType { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ClientAuthenticationType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ClientAuthenticationType.java index 0c9b7f2ae..0ed738bd4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ClientAuthenticationType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ClientAuthenticationType.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class ClientAuthenticationType { /* diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ClientCertificateType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ClientCertificateType.java index 76ab43313..4b093dc42 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ClientCertificateType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ClientCertificateType.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class ClientCertificateType { /* diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CompressionMethod.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CompressionMethod.java index 188d304fb..8b72717ad 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CompressionMethod.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/CompressionMethod.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 2246 6.1 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class CompressionMethod { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ConnectionEnd.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ConnectionEnd.java index 02760ca02..708c78522 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ConnectionEnd.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ConnectionEnd.java @@ -5,6 +5,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; *

* Note that the values here are implementation-specific and arbitrary. It is recommended not to * depend on the particular values (e.g. serialization). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class ConnectionEnd { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ContentType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ContentType.java index 10cfeb161..441629505 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ContentType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ContentType.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 2246 6.2.1 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class ContentType { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSClientProtocol.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSClientProtocol.java index b56345203..7e29ea1a7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSClientProtocol.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSClientProtocol.java @@ -10,6 +10,9 @@ import java.util.Vector; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class DTLSClientProtocol extends DTLSProtocol { @@ -43,12 +46,13 @@ public class DTLSClientProtocol client.init(state.clientContext); DTLSRecordLayer recordLayer = new DTLSRecordLayer(transport, state.clientContext, client, ContentType.handshake); + client.notifyCloseHandle(recordLayer); TlsSession sessionToResume = state.client.getSessionToResume(); if (sessionToResume != null && sessionToResume.isResumable()) { SessionParameters sessionParameters = sessionToResume.exportSessionParameters(); - if (sessionParameters != null) + if (sessionParameters != null && sessionParameters.isExtendedMasterSecret()) { state.tlsSession = sessionToResume; state.sessionParameters = sessionParameters; @@ -367,6 +371,7 @@ public class DTLSClientProtocol state.sessionParameters = new SessionParameters.Builder() .setCipherSuite(securityParameters.getCipherSuite()) .setCompressionAlgorithm(securityParameters.getCompressionAlgorithm()) + .setExtendedMasterSecret(securityParameters.isExtendedMasterSecret()) .setMasterSecret(securityParameters.getMasterSecret()) .setPeerCertificate(serverCertificate) .setPSKIdentity(securityParameters.getPSKIdentity()) @@ -396,8 +401,6 @@ public class DTLSClientProtocol protected byte[] generateClientHello(ClientHandshakeState state, TlsClient client) throws IOException { - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - ProtocolVersion client_version = client.getClientVersion(); if (!client_version.isDTLS()) { @@ -407,10 +410,8 @@ public class DTLSClientProtocol TlsClientContextImpl context = state.clientContext; context.setClientVersion(client_version); - TlsUtils.writeVersion(client_version, buf); SecurityParameters securityParameters = context.getSecurityParameters(); - buf.write(securityParameters.getClientRandom()); // Session ID byte[] session_id = TlsUtils.EMPTY_BYTES; @@ -422,20 +423,35 @@ public class DTLSClientProtocol session_id = TlsUtils.EMPTY_BYTES; } } - TlsUtils.writeOpaque8(session_id, buf); - - // Cookie - TlsUtils.writeOpaque8(TlsUtils.EMPTY_BYTES, buf); boolean fallback = client.isFallback(); - /* - * Cipher suites - */ state.offeredCipherSuites = client.getCipherSuites(); - // Integer -> byte[] - state.clientExtensions = client.getClientExtensions(); + if (session_id.length > 0 && state.sessionParameters != null) + { + if (!state.sessionParameters.isExtendedMasterSecret() + || !Arrays.contains(state.offeredCipherSuites, state.sessionParameters.getCipherSuite()) + || CompressionMethod._null != state.sessionParameters.getCompressionAlgorithm()) + { + session_id = TlsUtils.EMPTY_BYTES; + } + } + + state.clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(client.getClientExtensions()); + + TlsExtensionsUtils.addExtendedMasterSecretExtension(state.clientExtensions); + + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + + TlsUtils.writeVersion(client_version, buf); + + buf.write(securityParameters.getClientRandom()); + + TlsUtils.writeOpaque8(session_id, buf); + + // Cookie + TlsUtils.writeOpaque8(TlsUtils.EMPTY_BYTES, buf); // Cipher Suites (and SCSV) { @@ -470,18 +486,10 @@ public class DTLSClientProtocol TlsUtils.writeUint16ArrayWithUint16Length(state.offeredCipherSuites, buf); } - // TODO Add support for compression - // Compression methods - // state.offeredCompressionMethods = client.getCompressionMethods(); - state.offeredCompressionMethods = new short[]{ CompressionMethod._null }; - - TlsUtils.writeUint8ArrayWithUint8Length(state.offeredCompressionMethods, buf); + TlsUtils.writeUint8ArrayWithUint8Length(new short[]{ CompressionMethod._null }, buf); // Extensions - if (state.clientExtensions != null) - { - TlsProtocol.writeExtensions(buf, state.clientExtensions); - } + TlsProtocol.writeExtensions(buf, state.clientExtensions); return buf.toByteArray(); } @@ -644,7 +652,7 @@ public class DTLSClientProtocol state.client.notifySelectedCipherSuite(selectedCipherSuite); short selectedCompressionMethod = TlsUtils.readUint8(buf); - if (!Arrays.contains(state.offeredCompressionMethods, selectedCompressionMethod)) + if (CompressionMethod._null != selectedCompressionMethod) { throw new TlsFatalAlert(AlertDescription.illegal_parameter); } @@ -668,6 +676,18 @@ public class DTLSClientProtocol // Integer -> byte[] state.serverExtensions = TlsProtocol.readExtensions(buf); + /* + * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended + * master secret [..]. (and see 5.2, 5.3) + */ + securityParameters.extendedMasterSecret = TlsExtensionsUtils.hasExtendedMasterSecretExtension(state.serverExtensions); + + if (!securityParameters.isExtendedMasterSecret() + && (state.resumedSession || state.client.requiresExtendedMasterSecret())) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + /* * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an * extended client hello message. However, see RFC 5746 exception below. We always include @@ -765,7 +785,7 @@ public class DTLSClientProtocol securityParameters.cipherSuite = selectedCipherSuite; securityParameters.compressionAlgorithm = selectedCompressionMethod; - if (sessionServerExtensions != null) + if (sessionServerExtensions != null && !sessionServerExtensions.isEmpty()) { { /* @@ -782,8 +802,6 @@ public class DTLSClientProtocol securityParameters.encryptThenMAC = serverSentEncryptThenMAC; } - securityParameters.extendedMasterSecret = TlsExtensionsUtils.hasExtendedMasterSecretExtension(sessionServerExtensions); - securityParameters.maxFragmentLength = evaluateMaxFragmentLengthExtension(state.resumedSession, sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter); @@ -802,13 +820,6 @@ public class DTLSClientProtocol AlertDescription.illegal_parameter); } - /* - * TODO[session-hash] - * - * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes - * that do not use the extended master secret [..]. (and see 5.2, 5.3) - */ - if (sessionClientExtensions != null) { state.client.processServerExtensions(sessionServerExtensions); @@ -886,7 +897,6 @@ public class DTLSClientProtocol SessionParameters sessionParameters = null; SessionParameters.Builder sessionParametersBuilder = null; int[] offeredCipherSuites = null; - short[] offeredCompressionMethods = null; Hashtable clientExtensions = null; Hashtable serverExtensions = null; byte[] selectedSessionID = null; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSEpoch.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSEpoch.java index 0450eed54..2e0cd6531 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSEpoch.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSEpoch.java @@ -1,5 +1,7 @@ package com.fr.third.org.bouncycastle.crypto.tls; +import java.io.IOException; + class DTLSEpoch { private final DTLSReplayWindow replayWindow = new DTLSReplayWindow(); @@ -24,9 +26,13 @@ class DTLSEpoch this.cipher = cipher; } - long allocateSequenceNumber() + synchronized long allocateSequenceNumber() throws IOException { - // TODO Check for overflow + if (sequenceNumber >= (1L << 48)) + { + throw new TlsFatalAlert(AlertDescription.internal_error); + } + return sequenceNumber++; } @@ -45,7 +51,7 @@ class DTLSEpoch return replayWindow; } - long getSequenceNumber() + synchronized long getSequenceNumber() { return sequenceNumber; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSProtocol.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSProtocol.java index 6481326b8..3bec6508d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSProtocol.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSProtocol.java @@ -9,6 +9,9 @@ import java.util.Vector; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class DTLSProtocol { protected final SecureRandom secureRandom; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSRecordLayer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSRecordLayer.java index 931f6ad32..f5faf82f6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSRecordLayer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSRecordLayer.java @@ -44,6 +44,11 @@ class DTLSRecordLayer setPlaintextLimit(MAX_FRAGMENT_LENGTH); } + boolean isClosed() + { + return closed; + } + void setPlaintextLimit(int plaintextLimit) { this.plaintextLimit = plaintextLimit; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java index 53e17eb4e..5a386cab3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSReliableHandshake.java @@ -103,6 +103,11 @@ class DTLSReliableHandshake { for (;;) { + if (recordLayer.isClosed()) + { + throw new TlsFatalAlert(AlertDescription.user_canceled); + } + Message pending = getPendingMessage(); if (pending != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSServerProtocol.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSServerProtocol.java index f7a8b5356..ef3435b09 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSServerProtocol.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSServerProtocol.java @@ -12,6 +12,9 @@ import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; import com.fr.third.org.bouncycastle.crypto.util.PublicKeyFactory; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class DTLSServerProtocol extends DTLSProtocol { @@ -57,6 +60,7 @@ public class DTLSServerProtocol server.init(state.serverContext); DTLSRecordLayer recordLayer = new DTLSRecordLayer(transport, state.serverContext, server, ContentType.handshake); + server.notifyCloseHandle(recordLayer); // TODO Need to handle sending of HelloVerifyRequest without entering a full connection @@ -283,6 +287,24 @@ public class DTLSServerProtocol handshake.finish(); +// { +// state.sessionParameters = new SessionParameters.Builder() +// .setCipherSuite(securityParameters.getCipherSuite()) +// .setCompressionAlgorithm(securityParameters.getCompressionAlgorithm()) +// .setExtendedMasterSecret(securityParameters.isExtendedMasterSecret()) +// .setMasterSecret(securityParameters.getMasterSecret()) +// .setPeerCertificate(state.clientCertificate) +// .setPSKIdentity(securityParameters.getPSKIdentity()) +// .setSRPIdentity(securityParameters.getSRPIdentity()) +// // TODO Consider filtering extensions that aren't relevant to resumed sessions +// .setServerExtensions(state.serverExtensions) +// .build(); +// +// state.tlsSession = TlsUtils.importSession(state.tlsSession.getSessionID(), state.sessionParameters); +// +// state.serverContext.setResumableSession(state.tlsSession); +// } + state.server.notifyHandshakeComplete(); return new DTLSTransport(recordLayer); @@ -364,7 +386,7 @@ public class DTLSServerProtocol TlsUtils.writeUint16(selectedCipherSuite, buf); TlsUtils.writeUint8(selectedCompressionMethod, buf); - state.serverExtensions = state.server.getServerExtensions(); + state.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(state.server.getServerExtensions()); /* * RFC 5746 3.6. Server Behavior: Initial Handshake @@ -388,15 +410,13 @@ public class DTLSServerProtocol * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty * "renegotiation_info" extension in the ServerHello message. */ - state.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(state.serverExtensions); state.serverExtensions.put(TlsProtocol.EXT_RenegotiationInfo, TlsProtocol.createRenegotiationInfo(TlsUtils.EMPTY_BYTES)); } } - if (securityParameters.extendedMasterSecret) + if (securityParameters.isExtendedMasterSecret()) { - state.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(state.serverExtensions); TlsExtensionsUtils.addExtendedMasterSecretExtension(state.serverExtensions); } @@ -406,7 +426,7 @@ public class DTLSServerProtocol * extensions. */ - if (state.serverExtensions != null) + if (!state.serverExtensions.isEmpty()) { securityParameters.encryptThenMAC = TlsExtensionsUtils.hasEncryptThenMACExtension(state.serverExtensions); @@ -623,12 +643,18 @@ public class DTLSServerProtocol SecurityParameters securityParameters = context.getSecurityParameters(); /* - * TODO[session-hash] - * - * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes - * that do not use the extended master secret [..]. (and see 5.2, 5.3) + * TODO[resumption] Check RFC 7627 5.4. for required behaviour + */ + + /* + * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended + * master secret [..]. (and see 5.2, 5.3) */ securityParameters.extendedMasterSecret = TlsExtensionsUtils.hasExtendedMasterSecretExtension(state.clientExtensions); + if (!securityParameters.isExtendedMasterSecret() && state.server.requiresExtendedMasterSecret()) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } context.setClientVersion(client_version); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSTransport.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSTransport.java index d36784544..75285a74c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSTransport.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DTLSTransport.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class DTLSTransport implements DatagramTransport { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DatagramTransport.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DatagramTransport.java index a962296fc..d1e66625c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DatagramTransport.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DatagramTransport.java @@ -4,8 +4,11 @@ import java.io.IOException; /** * Base interface for an object sending and receiving DTLS data. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public interface DatagramTransport + extends TlsCloseable { int getReceiveLimit() throws IOException; @@ -18,7 +21,4 @@ public interface DatagramTransport void send(byte[] buf, int off, int len) throws IOException; - - void close() - throws IOException; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsAgreementCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsAgreementCredentials.java index a8559b1c0..06f165e0c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsAgreementCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsAgreementCredentials.java @@ -10,6 +10,9 @@ import com.fr.third.org.bouncycastle.crypto.params.DHPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; import com.fr.third.org.bouncycastle.util.BigIntegers; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class DefaultTlsAgreementCredentials extends AbstractTlsAgreementCredentials { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsCipherFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsCipherFactory.java index 61fca8cd0..2e57c4ac5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsCipherFactory.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsCipherFactory.java @@ -17,6 +17,9 @@ import com.fr.third.org.bouncycastle.crypto.modes.CCMBlockCipher; import com.fr.third.org.bouncycastle.crypto.modes.GCMBlockCipher; import com.fr.third.org.bouncycastle.crypto.modes.OCBBlockCipher; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class DefaultTlsCipherFactory extends AbstractTlsCipherFactory { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsClient.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsClient.java index 084d7baf2..4f2ab0153 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsClient.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsClient.java @@ -2,17 +2,29 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class DefaultTlsClient extends AbstractTlsClient { + protected TlsDHVerifier dhVerifier; + public DefaultTlsClient() { - super(); + this(new DefaultTlsCipherFactory()); } public DefaultTlsClient(TlsCipherFactory cipherFactory) + { + this(cipherFactory, new DefaultTlsDHVerifier()); + } + + public DefaultTlsClient(TlsCipherFactory cipherFactory, TlsDHVerifier dhVerifier) { super(cipherFactory); + + this.dhVerifier = dhVerifier; } public int[] getCipherSuites() @@ -25,12 +37,6 @@ public abstract class DefaultTlsClient CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_DHE_DSS_WITH_AES_128_GCM_SHA256, - CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA256, - CipherSuite.TLS_DHE_DSS_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256, - CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA256, - CipherSuite.TLS_DHE_RSA_WITH_AES_128_CBC_SHA, CipherSuite.TLS_RSA_WITH_AES_128_GCM_SHA256, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_RSA_WITH_AES_128_CBC_SHA, @@ -77,12 +83,12 @@ public abstract class DefaultTlsClient protected TlsKeyExchange createDHKeyExchange(int keyExchange) { - return new TlsDHKeyExchange(keyExchange, supportedSignatureAlgorithms, null); + return new TlsDHKeyExchange(keyExchange, supportedSignatureAlgorithms, dhVerifier, null); } protected TlsKeyExchange createDHEKeyExchange(int keyExchange) { - return new TlsDHEKeyExchange(keyExchange, supportedSignatureAlgorithms, null); + return new TlsDHEKeyExchange(keyExchange, supportedSignatureAlgorithms, dhVerifier, null); } protected TlsKeyExchange createECDHKeyExchange(int keyExchange) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsDHVerifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsDHVerifier.java new file mode 100644 index 000000000..057c18519 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsDHVerifier.java @@ -0,0 +1,107 @@ +package com.fr.third.org.bouncycastle.crypto.tls; + +import java.math.BigInteger; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.crypto.agreement.DHStandardGroups; +import com.fr.third.org.bouncycastle.crypto.params.DHParameters; + +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ +public class DefaultTlsDHVerifier + implements TlsDHVerifier +{ + public static final int DEFAULT_MINIMUM_PRIME_BITS = 2048; + + protected static final Vector DEFAULT_GROUPS = new Vector(); + + private static void addDefaultGroup(DHParameters dhParameters) + { + DEFAULT_GROUPS.addElement(dhParameters); + } + + static + { + addDefaultGroup(DHStandardGroups.rfc7919_ffdhe2048); + addDefaultGroup(DHStandardGroups.rfc7919_ffdhe3072); + addDefaultGroup(DHStandardGroups.rfc7919_ffdhe4096); + addDefaultGroup(DHStandardGroups.rfc7919_ffdhe6144); + addDefaultGroup(DHStandardGroups.rfc7919_ffdhe8192); + + addDefaultGroup(DHStandardGroups.rfc3526_1536); + addDefaultGroup(DHStandardGroups.rfc3526_2048); + addDefaultGroup(DHStandardGroups.rfc3526_3072); + addDefaultGroup(DHStandardGroups.rfc3526_4096); + addDefaultGroup(DHStandardGroups.rfc3526_6144); + addDefaultGroup(DHStandardGroups.rfc3526_8192); + } + + // Vector is (DHParameters) + protected Vector groups; + protected int minimumPrimeBits; + + /** + * Accept various standard DH groups with 'P' at least {@link #DEFAULT_MINIMUM_PRIME_BITS} bits. + */ + public DefaultTlsDHVerifier() + { + this(DEFAULT_MINIMUM_PRIME_BITS); + } + + /** + * Accept various standard DH groups with 'P' at least the specified number of bits. + */ + public DefaultTlsDHVerifier(int minimumPrimeBits) + { + this(DEFAULT_GROUPS, minimumPrimeBits); + } + + /** + * Accept a custom set of group parameters, subject to a minimum bitlength for 'P'. + * + * @param groups a {@link Vector} of acceptable {@link DHParameters}. + */ + public DefaultTlsDHVerifier(Vector groups, int minimumPrimeBits) + { + this.groups = groups; + this.minimumPrimeBits = minimumPrimeBits; + } + + public boolean accept(DHParameters dhParameters) + { + return checkMinimumPrimeBits(dhParameters) && checkGroup(dhParameters); + } + + public int getMinimumPrimeBits() + { + return minimumPrimeBits; + } + + protected boolean areGroupsEqual(DHParameters a, DHParameters b) + { + return a == b || (areParametersEqual(a.getP(), b.getP()) && areParametersEqual(a.getG(), b.getG())); + } + + protected boolean areParametersEqual(BigInteger a, BigInteger b) + { + return a == b || a.equals(b); + } + + protected boolean checkGroup(DHParameters dhParameters) + { + for (int i = 0; i < groups.size(); ++i) + { + if (areGroupsEqual(dhParameters, (DHParameters)groups.elementAt(i))) + { + return true; + } + } + return false; + } + + protected boolean checkMinimumPrimeBits(DHParameters dhParameters) + { + return dhParameters.getP().bitLength() >= getMinimumPrimeBits(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsEncryptionCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsEncryptionCredentials.java index 5c7a0c345..7715840c4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsEncryptionCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsEncryptionCredentials.java @@ -5,6 +5,9 @@ import java.io.IOException; import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class DefaultTlsEncryptionCredentials extends AbstractTlsEncryptionCredentials { protected TlsContext context; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsSRPGroupVerifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsSRPGroupVerifier.java index 8a9656eb3..ea31e9c3d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsSRPGroupVerifier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsSRPGroupVerifier.java @@ -6,6 +6,9 @@ import java.util.Vector; import com.fr.third.org.bouncycastle.crypto.agreement.srp.SRP6StandardGroups; import com.fr.third.org.bouncycastle.crypto.params.SRP6GroupParameters; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class DefaultTlsSRPGroupVerifier implements TlsSRPGroupVerifier { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsServer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsServer.java index ebfc4d091..371aa8eeb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsServer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsServer.java @@ -5,6 +5,9 @@ import java.io.IOException; import com.fr.third.org.bouncycastle.crypto.agreement.DHStandardGroups; import com.fr.third.org.bouncycastle.crypto.params.DHParameters; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class DefaultTlsServer extends AbstractTlsServer { @@ -142,12 +145,12 @@ public abstract class DefaultTlsServer protected TlsKeyExchange createDHKeyExchange(int keyExchange) { - return new TlsDHKeyExchange(keyExchange, supportedSignatureAlgorithms, getDHParameters()); + return new TlsDHKeyExchange(keyExchange, supportedSignatureAlgorithms, null, getDHParameters()); } protected TlsKeyExchange createDHEKeyExchange(int keyExchange) { - return new TlsDHEKeyExchange(keyExchange, supportedSignatureAlgorithms, getDHParameters()); + return new TlsDHEKeyExchange(keyExchange, supportedSignatureAlgorithms, null, getDHParameters()); } protected TlsKeyExchange createECDHKeyExchange(int keyExchange) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsSignerCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsSignerCredentials.java index 96fb1026a..1ee7fdf37 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsSignerCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DefaultTlsSignerCredentials.java @@ -8,6 +8,9 @@ import com.fr.third.org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class DefaultTlsSignerCredentials extends AbstractTlsSignerCredentials { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DigitallySigned.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DigitallySigned.java index 6e0c96215..37dd76440 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DigitallySigned.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/DigitallySigned.java @@ -4,6 +4,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class DigitallySigned { protected SignatureAndHashAlgorithm algorithm; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECBasisType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECBasisType.java index 709967827..9d0dcd55b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECBasisType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECBasisType.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 4492 5.4. (Errata ID: 2389) + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class ECBasisType { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECCurveType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECCurveType.java index 88359fa54..bb78f8871 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECCurveType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECCurveType.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 4492 5.4 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class ECCurveType { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECPointFormat.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECPointFormat.java index d4b50b086..f1470d763 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECPointFormat.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ECPointFormat.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 4492 5.1.2 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class ECPointFormat { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/EncryptionAlgorithm.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/EncryptionAlgorithm.java index ad29b7078..15f663cd5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/EncryptionAlgorithm.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/EncryptionAlgorithm.java @@ -5,6 +5,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; *

* Note that the values here are implementation-specific and arbitrary. It is recommended not to * depend on the particular values (e.g. serialization). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class EncryptionAlgorithm { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ExporterLabel.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ExporterLabel.java index c83b9e3b5..09e1eaa9e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ExporterLabel.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ExporterLabel.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 5705 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class ExporterLabel { @@ -30,7 +32,7 @@ public class ExporterLabel public static final String dtls_srtp = "EXTRACTOR-dtls_srtp"; /* - * draft-ietf-tls-session-hash-04 + * RFC 7627 */ public static final String extended_master_secret = "extended master secret"; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ExtensionType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ExtensionType.java index 2de83ff62..40d132e2e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ExtensionType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ExtensionType.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class ExtensionType { /* diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/FiniteFieldDHEGroup.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/FiniteFieldDHEGroup.java index c7ad42bee..a2e6f101e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/FiniteFieldDHEGroup.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/FiniteFieldDHEGroup.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /* * draft-ietf-tls-negotiated-ff-dhe-01 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class FiniteFieldDHEGroup { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HandshakeType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HandshakeType.java index 1edf7e7d9..59505d39a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HandshakeType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HandshakeType.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class HandshakeType { /* diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HashAlgorithm.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HashAlgorithm.java index 40bc08495..a8f3f12ae 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HashAlgorithm.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HashAlgorithm.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 5246 7.4.1.4.1 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class HashAlgorithm { @@ -43,6 +45,22 @@ public class HashAlgorithm public static boolean isPrivate(short hashAlgorithm) { - return 224 <= hashAlgorithm && hashAlgorithm <= 255; + return 224 <= hashAlgorithm && hashAlgorithm <= 255; + } + + public static boolean isRecognized(short hashAlgorithm) + { + switch (hashAlgorithm) + { + case md5: + case sha1: + case sha224: + case sha256: + case sha384: + case sha512: + return true; + default: + return false; + } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatExtension.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatExtension.java index f218f1434..34776f319 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatExtension.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatExtension.java @@ -4,6 +4,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class HeartbeatExtension { protected short mode; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMessage.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMessage.java index 690ef0642..e3dd3f831 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMessage.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMessage.java @@ -8,6 +8,9 @@ import java.io.OutputStream; import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.io.Streams; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class HeartbeatMessage { protected short type; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMessageType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMessageType.java index 0c5424055..c7dc2bc6c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMessageType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMessageType.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /* * RFC 6520 3. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class HeartbeatMessageType { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMode.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMode.java index a532bfc95..7d0d04b37 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMode.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/HeartbeatMode.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /* * RFC 6520 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class HeartbeatMode { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/KeyExchangeAlgorithm.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/KeyExchangeAlgorithm.java index 871a2c1c1..f977b9c35 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/KeyExchangeAlgorithm.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/KeyExchangeAlgorithm.java @@ -5,6 +5,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; *

* Note that the values here are implementation-specific and arbitrary. It is recommended not to * depend on the particular values (e.g. serialization). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class KeyExchangeAlgorithm { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/MACAlgorithm.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/MACAlgorithm.java index 42fc05d44..e9156178c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/MACAlgorithm.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/MACAlgorithm.java @@ -5,6 +5,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; *

* Note that the values here are implementation-specific and arbitrary. It is recommended not to * depend on the particular values (e.g. serialization). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class MACAlgorithm { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/MaxFragmentLength.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/MaxFragmentLength.java index 989c20e1b..65de041ec 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/MaxFragmentLength.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/MaxFragmentLength.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class MaxFragmentLength { /* diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NameType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NameType.java index cfcca2ed2..286a5f7ad 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NameType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NameType.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class NameType { /* diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NamedCurve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NamedCurve.java index fb880d181..bcdd4981b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NamedCurve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NamedCurve.java @@ -8,6 +8,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; * reserved for private use. Values 0xFF01 and 0xFF02 indicate that the client supports arbitrary * prime and characteristic-2 curves, respectively (the curve parameters must be encoded explicitly * in ECParameters). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class NamedCurve { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NewSessionTicket.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NewSessionTicket.java index 0ee6d6758..5610a8b80 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NewSessionTicket.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/NewSessionTicket.java @@ -4,6 +4,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class NewSessionTicket { protected long ticketLifetimeHint; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/OCSPStatusRequest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/OCSPStatusRequest.java index 2169c3aa1..c129a85ca 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/OCSPStatusRequest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/OCSPStatusRequest.java @@ -14,6 +14,8 @@ import com.fr.third.org.bouncycastle.util.io.Streams; /** * RFC 3546 3.6 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class OCSPStatusRequest { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PRFAlgorithm.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PRFAlgorithm.java index a37c3170b..7d6e38ab5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PRFAlgorithm.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PRFAlgorithm.java @@ -5,6 +5,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; *

* Note that the values here are implementation-specific and arbitrary. It is recommended not to * depend on the particular values (e.g. serialization). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class PRFAlgorithm { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PSKTlsClient.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PSKTlsClient.java index 30f199a49..c36c305bc 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PSKTlsClient.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PSKTlsClient.java @@ -2,9 +2,13 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class PSKTlsClient extends AbstractTlsClient { + protected TlsDHVerifier dhVerifier; protected TlsPSKIdentity pskIdentity; public PSKTlsClient(TlsPSKIdentity pskIdentity) @@ -13,8 +17,15 @@ public class PSKTlsClient } public PSKTlsClient(TlsCipherFactory cipherFactory, TlsPSKIdentity pskIdentity) + { + this(cipherFactory, new DefaultTlsDHVerifier(), pskIdentity); + } + + public PSKTlsClient(TlsCipherFactory cipherFactory, TlsDHVerifier dhVerifier, TlsPSKIdentity pskIdentity) { super(cipherFactory); + + this.dhVerifier = dhVerifier; this.pskIdentity = pskIdentity; } @@ -24,8 +35,6 @@ public class PSKTlsClient { CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA256, CipherSuite.TLS_ECDHE_PSK_WITH_AES_128_CBC_SHA, - CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA256, - CipherSuite.TLS_DHE_PSK_WITH_AES_128_CBC_SHA }; } @@ -62,7 +71,7 @@ public class PSKTlsClient protected TlsKeyExchange createPSKKeyExchange(int keyExchange) { - return new TlsPSKKeyExchange(keyExchange, supportedSignatureAlgorithms, pskIdentity, null, null, namedCurves, - clientECPointFormats, serverECPointFormats); + return new TlsPSKKeyExchange(keyExchange, supportedSignatureAlgorithms, pskIdentity, null, dhVerifier, null, + namedCurves, clientECPointFormats, serverECPointFormats); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PSKTlsServer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PSKTlsServer.java index 9c397c657..62d2ec80e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PSKTlsServer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/PSKTlsServer.java @@ -5,6 +5,9 @@ import java.io.IOException; import com.fr.third.org.bouncycastle.crypto.agreement.DHStandardGroups; import com.fr.third.org.bouncycastle.crypto.params.DHParameters; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class PSKTlsServer extends AbstractTlsServer { @@ -87,6 +90,6 @@ public class PSKTlsServer protected TlsKeyExchange createPSKKeyExchange(int keyExchange) { return new TlsPSKKeyExchange(keyExchange, supportedSignatureAlgorithms, null, pskIdentityManager, - getDHParameters(), namedCurves, clientECPointFormats, serverECPointFormats); + null, getDHParameters(), namedCurves, clientECPointFormats, serverECPointFormats); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ProtocolVersion.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ProtocolVersion.java index 4d494b802..596c27729 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ProtocolVersion.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ProtocolVersion.java @@ -4,6 +4,9 @@ import java.io.IOException; import com.fr.third.org.bouncycastle.util.Strings; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public final class ProtocolVersion { public static final ProtocolVersion SSLv3 = new ProtocolVersion(0x0300, "SSL 3.0"); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRPTlsClient.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRPTlsClient.java index 2802ea470..b16ec7c22 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRPTlsClient.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRPTlsClient.java @@ -5,6 +5,9 @@ import java.util.Hashtable; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class SRPTlsClient extends AbstractTlsClient { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRPTlsServer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRPTlsServer.java index 67e109f3f..25b77dbb1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRPTlsServer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRPTlsServer.java @@ -3,6 +3,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; import java.util.Hashtable; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class SRPTlsServer extends AbstractTlsServer { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRTPProtectionProfile.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRTPProtectionProfile.java index 1dbc5d470..831bfa55c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRTPProtectionProfile.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SRTPProtectionProfile.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class SRTPProtectionProfile { /* diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SSL3Mac.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SSL3Mac.java index c7fed94c8..58140fa8f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SSL3Mac.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SSL3Mac.java @@ -12,6 +12,8 @@ import com.fr.third.org.bouncycastle.util.Arrays; * The difference is that padding is concatenated versus XORed with the key *

* H(K + opad, H(K + ipad, text)) + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class SSL3Mac implements Mac diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SecurityParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SecurityParameters.java index 1985fbd32..438191d36 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SecurityParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SecurityParameters.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class SecurityParameters { int entity = -1; @@ -105,4 +108,9 @@ public class SecurityParameters { return srpIdentity; } + + public boolean isExtendedMasterSecret() + { + return extendedMasterSecret; + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerDHParams.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerDHParams.java deleted file mode 100644 index 7f27a6f19..000000000 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerDHParams.java +++ /dev/null @@ -1,63 +0,0 @@ -package com.fr.third.org.bouncycastle.crypto.tls; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.math.BigInteger; - -import com.fr.third.org.bouncycastle.crypto.params.DHParameters; -import com.fr.third.org.bouncycastle.crypto.params.DHPublicKeyParameters; - -public class ServerDHParams -{ - protected DHPublicKeyParameters publicKey; - - public ServerDHParams(DHPublicKeyParameters publicKey) - { - if (publicKey == null) - { - throw new IllegalArgumentException("'publicKey' cannot be null"); - } - - this.publicKey = publicKey; - } - - public DHPublicKeyParameters getPublicKey() - { - return publicKey; - } - - /** - * Encode this {@link ServerDHParams} to an {@link OutputStream}. - * - * @param output - * the {@link OutputStream} to encode to. - * @throws IOException - */ - public void encode(OutputStream output) throws IOException - { - DHParameters dhParameters = publicKey.getParameters(); - BigInteger Ys = publicKey.getY(); - - TlsDHUtils.writeDHParameter(dhParameters.getP(), output); - TlsDHUtils.writeDHParameter(dhParameters.getG(), output); - TlsDHUtils.writeDHParameter(Ys, output); - } - - /** - * Parse a {@link ServerDHParams} from an {@link InputStream}. - * - * @param input - * the {@link InputStream} to parse from. - * @return a {@link ServerDHParams} object. - * @throws IOException - */ - public static ServerDHParams parse(InputStream input) throws IOException - { - BigInteger p = TlsDHUtils.readDHParameter(input); - BigInteger g = TlsDHUtils.readDHParameter(input); - BigInteger Ys = TlsDHUtils.readDHParameter(input); - - return new ServerDHParams(TlsDHUtils.validateDHPublicKey(new DHPublicKeyParameters(Ys, new DHParameters(p, g)))); - } -} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerName.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerName.java index 34bb664c8..92d1134f6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerName.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerName.java @@ -4,6 +4,9 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class ServerName { protected short nameType; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerNameList.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerNameList.java index 8d0b9232f..6456bc8b2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerNameList.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerNameList.java @@ -10,6 +10,9 @@ import java.util.Vector; import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.io.Streams; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class ServerNameList { protected Vector serverNameList; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerOnlyTlsAuthentication.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerOnlyTlsAuthentication.java index 7f6680c13..4860aa609 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerOnlyTlsAuthentication.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerOnlyTlsAuthentication.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class ServerOnlyTlsAuthentication implements TlsAuthentication { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerSRPParams.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerSRPParams.java index f3000b868..b7bdf2dd8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerSRPParams.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/ServerSRPParams.java @@ -7,6 +7,9 @@ import java.math.BigInteger; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class ServerSRPParams { protected BigInteger N, g, B; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SessionParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SessionParameters.java index e0e1eb3ce..091ad2ce6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SessionParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SessionParameters.java @@ -7,6 +7,9 @@ import java.util.Hashtable; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public final class SessionParameters { public static final class Builder @@ -18,6 +21,7 @@ public final class SessionParameters private byte[] pskIdentity = null; private byte[] srpIdentity = null; private byte[] encodedServerExtensions = null; + private boolean extendedMasterSecret = false; public Builder() { @@ -29,7 +33,7 @@ public final class SessionParameters validate(this.compressionAlgorithm >= 0, "compressionAlgorithm"); validate(this.masterSecret != null, "masterSecret"); return new SessionParameters(cipherSuite, compressionAlgorithm, masterSecret, peerCertificate, pskIdentity, - srpIdentity, encodedServerExtensions); + srpIdentity, encodedServerExtensions, extendedMasterSecret); } public Builder setCipherSuite(int cipherSuite) @@ -44,6 +48,12 @@ public final class SessionParameters return this; } + public Builder setExtendedMasterSecret(boolean extendedMasterSecret) + { + this.extendedMasterSecret = extendedMasterSecret; + return this; + } + public Builder setMasterSecret(byte[] masterSecret) { this.masterSecret = masterSecret; @@ -108,9 +118,11 @@ public final class SessionParameters private byte[] pskIdentity = null; private byte[] srpIdentity = null; private byte[] encodedServerExtensions; + private boolean extendedMasterSecret; private SessionParameters(int cipherSuite, short compressionAlgorithm, byte[] masterSecret, - Certificate peerCertificate, byte[] pskIdentity, byte[] srpIdentity, byte[] encodedServerExtensions) + Certificate peerCertificate, byte[] pskIdentity, byte[] srpIdentity, byte[] encodedServerExtensions, + boolean extendedMasterSecret) { this.cipherSuite = cipherSuite; this.compressionAlgorithm = compressionAlgorithm; @@ -119,6 +131,7 @@ public final class SessionParameters this.pskIdentity = Arrays.clone(pskIdentity); this.srpIdentity = Arrays.clone(srpIdentity); this.encodedServerExtensions = encodedServerExtensions; + this.extendedMasterSecret = extendedMasterSecret; } public void clear() @@ -132,7 +145,7 @@ public final class SessionParameters public SessionParameters copy() { return new SessionParameters(cipherSuite, compressionAlgorithm, masterSecret, peerCertificate, pskIdentity, - srpIdentity, encodedServerExtensions); + srpIdentity, encodedServerExtensions, extendedMasterSecret); } public int getCipherSuite() @@ -173,6 +186,11 @@ public final class SessionParameters return srpIdentity; } + public boolean isExtendedMasterSecret() + { + return extendedMasterSecret; + } + public Hashtable readServerExtensions() throws IOException { if (encodedServerExtensions == null) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SignatureAlgorithm.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SignatureAlgorithm.java index 417a14193..05d0cd1f8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SignatureAlgorithm.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SignatureAlgorithm.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 5246 7.4.1.4.1 (in RFC 2246, there were no specific values assigned) + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class SignatureAlgorithm { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SignatureAndHashAlgorithm.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SignatureAndHashAlgorithm.java index 06ce15193..ee320a505 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SignatureAndHashAlgorithm.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SignatureAndHashAlgorithm.java @@ -6,6 +6,8 @@ import java.io.OutputStream; /** * RFC 5246 7.4.1.4.1 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class SignatureAndHashAlgorithm { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SimulatedTlsSRPIdentityManager.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SimulatedTlsSRPIdentityManager.java index 1a8f2ae69..8db102f1e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SimulatedTlsSRPIdentityManager.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SimulatedTlsSRPIdentityManager.java @@ -12,6 +12,8 @@ import com.fr.third.org.bouncycastle.util.Strings; /** * An implementation of {@link TlsSRPIdentityManager} that simulates the existence of "unknown" identities * to obscure the fact that there is no verifier for them. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class SimulatedTlsSRPIdentityManager implements TlsSRPIdentityManager diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SupplementalDataEntry.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SupplementalDataEntry.java index 58b742796..0c5666f67 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SupplementalDataEntry.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SupplementalDataEntry.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class SupplementalDataEntry { protected int dataType; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SupplementalDataType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SupplementalDataType.java index d662b2937..fea0aff8e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SupplementalDataType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/SupplementalDataType.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 4680 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class SupplementalDataType { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAEADCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAEADCipher.java index 65dd0e5ba..c8128f3ca 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAEADCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAEADCipher.java @@ -7,6 +7,9 @@ import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsAEADCipher implements TlsCipher { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAgreementCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAgreementCredentials.java index bfbc7bccd..ac55c9c26 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAgreementCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAgreementCredentials.java @@ -4,6 +4,9 @@ import java.io.IOException; import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsAgreementCredentials extends TlsCredentials { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAuthentication.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAuthentication.java index fca105ae7..25e83355b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAuthentication.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsAuthentication.java @@ -4,6 +4,8 @@ import java.io.IOException; /** * Base interface to provide TLS authentication credentials. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public interface TlsAuthentication { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsBlockCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsBlockCipher.java index 6c4ff7437..7d2e4f729 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsBlockCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsBlockCipher.java @@ -12,6 +12,8 @@ import com.fr.third.org.bouncycastle.util.Arrays; /** * A generic TLS 1.0-1.2 / SSLv3 block cipher. This can be used for AES or 3DES for example. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsBlockCipher implements TlsCipher diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCipher.java index 690346f6b..432e30d8a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCipher.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsCipher { int getPlaintextLimit(int ciphertextLimit); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCipherFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCipherFactory.java index cbb201fd8..181b16a63 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCipherFactory.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCipherFactory.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsCipherFactory { /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClient.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClient.java index 0d4a3da35..2ff4c442e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClient.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClient.java @@ -6,6 +6,8 @@ import java.util.Vector; /** * Interface describing a TLS client endpoint. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public interface TlsClient extends TlsPeer diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClientContext.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClientContext.java index fb2a7c53f..548d7239d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClientContext.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClientContext.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * Marker interface to distinguish a TLS client context. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public interface TlsClientContext extends TlsContext diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClientProtocol.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClientProtocol.java index b702d901e..3cb4aa9c4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClientProtocol.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsClientProtocol.java @@ -11,6 +11,9 @@ import java.util.Vector; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsClientProtocol extends TlsProtocol { @@ -88,11 +91,13 @@ public class TlsClientProtocol this.tlsClient.init(tlsClientContext); this.recordStream.init(tlsClientContext); + tlsClient.notifyCloseHandle(this); + TlsSession sessionToResume = tlsClient.getSessionToResume(); if (sessionToResume != null && sessionToResume.isResumable()) { SessionParameters sessionParameters = sessionToResume.exportSessionParameters(); - if (sessionParameters != null) + if (sessionParameters != null && sessionParameters.isExtendedMasterSecret()) { this.tlsSession = sessionToResume; this.sessionParameters = sessionParameters; @@ -652,7 +657,7 @@ public class TlsClientProtocol this.tlsClient.notifySelectedCompressionMethod(selectedCompressionMethod); /* - * RFC3546 2.2 The extended server hello message format MAY be sent in place of the server + * RFC 3546 2.2 The extended server hello message format MAY be sent in place of the server * hello message when the client has requested extended functionality via the extended * client hello message specified in Section 2.1. ... Note that the extended server hello * message is only sent in response to an extended client hello message. This prevents the @@ -661,6 +666,19 @@ public class TlsClientProtocol */ this.serverExtensions = readExtensions(buf); + /* + * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended + * master secret [..]. (and see 5.2, 5.3) + */ + this.securityParameters.extendedMasterSecret = !TlsUtils.isSSL(tlsClientContext) + && TlsExtensionsUtils.hasExtendedMasterSecretExtension(serverExtensions); + + if (!securityParameters.isExtendedMasterSecret() + && (resumedSession || tlsClient.requiresExtendedMasterSecret())) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + /* * RFC 3546 2.2 Note that the extended server hello message is only sent in response to an * extended client hello message. @@ -759,7 +777,7 @@ public class TlsClientProtocol this.securityParameters.cipherSuite = selectedCipherSuite; this.securityParameters.compressionAlgorithm = selectedCompressionMethod; - if (sessionServerExtensions != null) + if (sessionServerExtensions != null && !sessionServerExtensions.isEmpty()) { { /* @@ -776,8 +794,6 @@ public class TlsClientProtocol this.securityParameters.encryptThenMAC = serverSentEncryptThenMAC; } - this.securityParameters.extendedMasterSecret = TlsExtensionsUtils.hasExtendedMasterSecretExtension(sessionServerExtensions); - this.securityParameters.maxFragmentLength = processMaxFragmentLengthExtension(sessionClientExtensions, sessionServerExtensions, AlertDescription.illegal_parameter); @@ -796,13 +812,6 @@ public class TlsClientProtocol AlertDescription.illegal_parameter); } - /* - * TODO[session-hash] - * - * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes - * that do not use the extended master secret [..]. (and see 5.2, 5.3) - */ - if (sessionClientExtensions != null) { this.tlsClient.processServerExtensions(sessionServerExtensions); @@ -864,14 +873,20 @@ public class TlsClientProtocol if (session_id.length > 0 && this.sessionParameters != null) { - if (!Arrays.contains(this.offeredCipherSuites, sessionParameters.getCipherSuite()) + if (!sessionParameters.isExtendedMasterSecret() + || !Arrays.contains(this.offeredCipherSuites, sessionParameters.getCipherSuite()) || !Arrays.contains(this.offeredCompressionMethods, sessionParameters.getCompressionAlgorithm())) { session_id = TlsUtils.EMPTY_BYTES; } } - this.clientExtensions = this.tlsClient.getClientExtensions(); + this.clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(this.tlsClient.getClientExtensions()); + + if (!client_version.isSSL()) + { + TlsExtensionsUtils.addExtendedMasterSecretExtension(this.clientExtensions); + } HandshakeMessage message = new HandshakeMessage(HandshakeType.client_hello); @@ -896,8 +911,6 @@ public class TlsClientProtocol if (noRenegExt && noRenegSCSV) { // TODO Consider whether to default to a client extension instead -// this.clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(this.clientExtensions); -// this.clientExtensions.put(EXT_RenegotiationInfo, createRenegotiationInfo(TlsUtils.EMPTY_BYTES)); this.offeredCipherSuites = Arrays.append(offeredCipherSuites, CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV); } @@ -918,10 +931,7 @@ public class TlsClientProtocol TlsUtils.writeUint8ArrayWithUint8Length(offeredCompressionMethods, message); - if (clientExtensions != null) - { - writeExtensions(message, clientExtensions); - } + writeExtensions(message, clientExtensions); message.writeToRecordStream(); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCloseable.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCloseable.java new file mode 100644 index 000000000..de8d874e4 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCloseable.java @@ -0,0 +1,11 @@ +package com.fr.third.org.bouncycastle.crypto.tls; + +import java.io.IOException; + +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ +public interface TlsCloseable +{ + public void close() throws IOException; +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCompression.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCompression.java index 53b7e8aaf..b04b84bfc 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCompression.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCompression.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.OutputStream; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsCompression { OutputStream compress(OutputStream output); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsContext.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsContext.java index b2066006b..6b7d5ea3c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsContext.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsContext.java @@ -4,6 +4,9 @@ import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.prng.RandomGenerator; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsContext { RandomGenerator getNonceRandomGenerator(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCredentials.java index cda7d0a5d..52927c863 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsCredentials.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsCredentials { Certificate getCertificate(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHEKeyExchange.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHEKeyExchange.java index 12a5482fa..017b5c241 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHEKeyExchange.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHEKeyExchange.java @@ -7,16 +7,28 @@ import java.util.Vector; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.Signer; import com.fr.third.org.bouncycastle.crypto.params.DHParameters; +import com.fr.third.org.bouncycastle.crypto.params.DHPublicKeyParameters; import com.fr.third.org.bouncycastle.util.io.TeeInputStream; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsDHEKeyExchange extends TlsDHKeyExchange { protected TlsSignerCredentials serverCredentials = null; + /** + * @deprecated Use constructor that takes a TlsDHVerifier + */ public TlsDHEKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, DHParameters dhParameters) { - super(keyExchange, supportedSignatureAlgorithms, dhParameters); + this(keyExchange, supportedSignatureAlgorithms, new DefaultTlsDHVerifier(), dhParameters); + } + + public TlsDHEKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsDHVerifier dhVerifier, DHParameters dhParameters) + { + super(keyExchange, supportedSignatureAlgorithms, dhVerifier, dhParameters); } public void processServerCredentials(TlsCredentials serverCredentials) @@ -77,7 +89,8 @@ public class TlsDHEKeyExchange SignerInputBuffer buf = new SignerInputBuffer(); InputStream teeIn = new TeeInputStream(input, buf); - ServerDHParams dhParams = ServerDHParams.parse(teeIn); + this.dhParameters = TlsDHUtils.receiveDHParameters(dhVerifier, teeIn); + this.dhAgreePublicKey = new DHPublicKeyParameters(TlsDHUtils.readDHParameter(teeIn), dhParameters); DigitallySigned signed_params = parseSignature(input); @@ -87,9 +100,6 @@ public class TlsDHEKeyExchange { throw new TlsFatalAlert(AlertDescription.decrypt_error); } - - this.dhAgreePublicKey = TlsDHUtils.validateDHPublicKey(dhParams.getPublicKey()); - this.dhParameters = validateDHParameters(dhAgreePublicKey.getParameters()); } protected Signer initVerifyer(TlsSigner tlsSigner, SignatureAndHashAlgorithm algorithm, SecurityParameters securityParameters) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHKeyExchange.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHKeyExchange.java index 790647021..3ded82874 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHKeyExchange.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHKeyExchange.java @@ -4,7 +4,6 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.math.BigInteger; import java.util.Vector; import com.fr.third.org.bouncycastle.asn1.x509.KeyUsage; @@ -17,11 +16,14 @@ import com.fr.third.org.bouncycastle.crypto.util.PublicKeyFactory; /** * (D)TLS DH key exchange. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsDHKeyExchange extends AbstractTlsKeyExchange { protected TlsSigner tlsSigner; + protected TlsDHVerifier dhVerifier; protected DHParameters dhParameters; protected AsymmetricKeyParameter serverPublicKey; @@ -30,7 +32,15 @@ public class TlsDHKeyExchange protected DHPrivateKeyParameters dhAgreePrivateKey; protected DHPublicKeyParameters dhAgreePublicKey; + /** + * @deprecated Use constructor that takes a TlsDHVerifier + */ public TlsDHKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, DHParameters dhParameters) + { + this(keyExchange, supportedSignatureAlgorithms, new DefaultTlsDHVerifier(), dhParameters); + } + + public TlsDHKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsDHVerifier dhVerifier, DHParameters dhParameters) { super(keyExchange, supportedSignatureAlgorithms); @@ -51,6 +61,7 @@ public class TlsDHKeyExchange throw new IllegalArgumentException("unsupported key exchange algorithm"); } + this.dhVerifier = dhVerifier; this.dhParameters = dhParameters; } @@ -101,8 +112,8 @@ public class TlsDHKeyExchange { try { - this.dhAgreePublicKey = TlsDHUtils.validateDHPublicKey((DHPublicKeyParameters)this.serverPublicKey); - this.dhParameters = validateDHParameters(dhAgreePublicKey.getParameters()); + this.dhAgreePublicKey = (DHPublicKeyParameters)this.serverPublicKey; + this.dhParameters = dhAgreePublicKey.getParameters(); } catch (ClassCastException e) { @@ -161,10 +172,8 @@ public class TlsDHKeyExchange // DH_anon is handled here, DHE_* in a subclass - ServerDHParams dhParams = ServerDHParams.parse(input); - - this.dhAgreePublicKey = TlsDHUtils.validateDHPublicKey(dhParams.getPublicKey()); - this.dhParameters = validateDHParameters(dhAgreePublicKey.getParameters()); + this.dhParameters = TlsDHUtils.receiveDHParameters(dhVerifier, input); + this.dhAgreePublicKey = new DHPublicKeyParameters(TlsDHUtils.readDHParameter(input), dhParameters); } public void validateCertificateRequest(CertificateRequest certificateRequest) @@ -250,9 +259,7 @@ public class TlsDHKeyExchange return; } - BigInteger Yc = TlsDHUtils.readDHParameter(input); - - this.dhAgreePublicKey = TlsDHUtils.validateDHPublicKey(new DHPublicKeyParameters(Yc, dhParameters)); + this.dhAgreePublicKey = new DHPublicKeyParameters(TlsDHUtils.readDHParameter(input), dhParameters); } public byte[] generatePremasterSecret() @@ -270,19 +277,4 @@ public class TlsDHKeyExchange throw new TlsFatalAlert(AlertDescription.internal_error); } - - protected int getMinimumPrimeBits() - { - return 1024; - } - - protected DHParameters validateDHParameters(DHParameters params) throws IOException - { - if (params.getP().bitLength() < getMinimumPrimeBits()) - { - throw new TlsFatalAlert(AlertDescription.insufficient_security); - } - - return TlsDHUtils.validateDHParameters(params); - } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHUtils.java index 7052e9022..9e477300c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHUtils.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHUtils.java @@ -19,6 +19,9 @@ import com.fr.third.org.bouncycastle.util.BigIntegers; import com.fr.third.org.bouncycastle.util.Integers; import com.fr.third.org.bouncycastle.util.encoders.Hex; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsDHUtils { static final BigInteger TWO = BigInteger.valueOf(2); @@ -30,7 +33,7 @@ public class TlsDHUtils */ private static BigInteger fromHex(String hex) { - return new BigInteger(1, Hex.decode(hex)); + return new BigInteger(1, Hex.decodeStrict(hex)); } private static DHParameters fromSafeP(String hexP) @@ -409,6 +412,25 @@ public class TlsDHUtils case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_128_OCB: case CipherSuite.DRAFT_TLS_DHE_PSK_WITH_AES_256_OCB: + /* + * DH_anon cipher suites are consider ephemeral DH + */ + case CipherSuite.TLS_DH_anon_WITH_3DES_EDE_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_AES_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_AES_256_GCM_SHA384: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256: + case CipherSuite.TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384: + case CipherSuite.TLS_DH_anon_WITH_RC4_128_MD5: + case CipherSuite.TLS_DH_anon_WITH_SEED_CBC_SHA: + return true; default: @@ -459,50 +481,43 @@ public class TlsDHUtils AsymmetricCipherKeyPair kp = generateDHKeyPair(random, dhParams); DHPublicKeyParameters dhPublic = (DHPublicKeyParameters)kp.getPublic(); - new ServerDHParams(dhPublic).encode(output); + writeDHParameters(dhParams, output); + writeDHParameter(dhPublic.getY(), output); return (DHPrivateKeyParameters)kp.getPrivate(); } - public static DHParameters validateDHParameters(DHParameters params) throws IOException + public static BigInteger readDHParameter(InputStream input) throws IOException { - BigInteger p = params.getP(); - BigInteger g = params.getG(); + return new BigInteger(1, TlsUtils.readOpaque16(input)); + } - if (!p.isProbablePrime(2)) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } - if (g.compareTo(TWO) < 0 || g.compareTo(p.subtract(TWO)) > 0) - { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); - } + public static DHParameters readDHParameters(InputStream input) throws IOException + { + BigInteger p = readDHParameter(input); + BigInteger g = readDHParameter(input); - return params; + return new DHParameters(p, g); } - public static DHPublicKeyParameters validateDHPublicKey(DHPublicKeyParameters key) throws IOException + public static DHParameters receiveDHParameters(TlsDHVerifier dhVerifier, InputStream input) throws IOException { - DHParameters params = validateDHParameters(key.getParameters()); - - BigInteger Y = key.getY(); - if (Y.compareTo(TWO) < 0 || Y.compareTo(params.getP().subtract(TWO)) > 0) + DHParameters dhParameters = readDHParameters(input); + if (!dhVerifier.accept(dhParameters)) { - throw new TlsFatalAlert(AlertDescription.illegal_parameter); + throw new TlsFatalAlert(AlertDescription.insufficient_security); } - - // TODO See RFC 2631 for more discussion of Diffie-Hellman validation - - return key; + return dhParameters; } - public static BigInteger readDHParameter(InputStream input) throws IOException + public static void writeDHParameter(BigInteger x, OutputStream output) throws IOException { - return new BigInteger(1, TlsUtils.readOpaque16(input)); + TlsUtils.writeOpaque16(BigIntegers.asUnsignedByteArray(x), output); } - public static void writeDHParameter(BigInteger x, OutputStream output) throws IOException + public static void writeDHParameters(DHParameters dhParameters, OutputStream output) throws IOException { - TlsUtils.writeOpaque16(BigIntegers.asUnsignedByteArray(x), output); + writeDHParameter(dhParameters.getP(), output); + writeDHParameter(dhParameters.getG(), output); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHVerifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHVerifier.java new file mode 100644 index 000000000..9429073c0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDHVerifier.java @@ -0,0 +1,19 @@ +package com.fr.third.org.bouncycastle.crypto.tls; + +import com.fr.third.org.bouncycastle.crypto.params.DHParameters; + +/** + * Interface a class for verifying Diffie-Hellman parameters needs to conform to. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ +public interface TlsDHVerifier +{ + /** + * Check whether the given DH parameters are acceptable for use. + * + * @param dhParameters the {@link DHParameters} to check + * @return true if (and only if) the specified parameters are acceptable + */ + boolean accept(DHParameters dhParameters); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDSASigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDSASigner.java index c2b04cd2f..bc65716df 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDSASigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDSASigner.java @@ -10,6 +10,9 @@ import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; import com.fr.third.org.bouncycastle.crypto.signers.DSADigestSigner; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class TlsDSASigner extends AbstractTlsSigner { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDSSSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDSSSigner.java index 56f656356..8c1baa8f3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDSSSigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsDSSSigner.java @@ -6,6 +6,9 @@ import com.fr.third.org.bouncycastle.crypto.params.DSAPublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.signers.DSASigner; import com.fr.third.org.bouncycastle.crypto.signers.HMacDSAKCalculator; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsDSSSigner extends TlsDSASigner { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECCUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECCUtils.java index 16078a213..76299b7a4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECCUtils.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECCUtils.java @@ -27,6 +27,9 @@ import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.BigIntegers; import com.fr.third.org.bouncycastle.util.Integers; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsECCUtils { public static final Integer EXT_elliptic_curves = Integers.valueOf(ExtensionType.elliptic_curves); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDHEKeyExchange.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDHEKeyExchange.java index 7327ae3d8..b6306fe32 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDHEKeyExchange.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDHEKeyExchange.java @@ -11,6 +11,8 @@ import com.fr.third.org.bouncycastle.util.io.TeeInputStream; /** * (D)TLS ECDHE key exchange (see RFC 4492). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsECDHEKeyExchange extends TlsECDHKeyExchange diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDHKeyExchange.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDHKeyExchange.java index ec4cf6b3d..eeb491cf9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDHKeyExchange.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDHKeyExchange.java @@ -16,6 +16,8 @@ import com.fr.third.org.bouncycastle.crypto.util.PublicKeyFactory; /** * (D)TLS ECDH key exchange (see RFC 4492). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsECDHKeyExchange extends AbstractTlsKeyExchange { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDSASigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDSASigner.java index 2973cc0e6..66a5feff2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDSASigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsECDSASigner.java @@ -6,6 +6,9 @@ import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.signers.ECDSASigner; import com.fr.third.org.bouncycastle.crypto.signers.HMacDSAKCalculator; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsECDSASigner extends TlsDSASigner { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsEncryptionCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsEncryptionCredentials.java index 3b6d1ad7b..3105946cd 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsEncryptionCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsEncryptionCredentials.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsEncryptionCredentials extends TlsCredentials { byte[] decryptPreMasterSecret(byte[] encryptedPreMasterSecret) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsException.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsException.java index ae381227b..4939ed9df 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsException.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsException.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsException extends IOException { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsExtensionsUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsExtensionsUtils.java index ad9b00f9e..79b3d253d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsExtensionsUtils.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsExtensionsUtils.java @@ -7,6 +7,9 @@ import java.util.Hashtable; import com.fr.third.org.bouncycastle.util.Integers; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsExtensionsUtils { public static final Integer EXT_encrypt_then_mac = Integers.valueOf(ExtensionType.encrypt_then_mac); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsFatalAlert.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsFatalAlert.java index 05d963dcf..8cdd673a4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsFatalAlert.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsFatalAlert.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsFatalAlert extends TlsException { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsFatalAlertReceived.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsFatalAlertReceived.java index 9f4f47778..e3bdbc8ea 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsFatalAlertReceived.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsFatalAlertReceived.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsFatalAlertReceived extends TlsException { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsHandshakeHash.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsHandshakeHash.java index 6218c6cb8..b18b0ea03 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsHandshakeHash.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsHandshakeHash.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import com.fr.third.org.bouncycastle.crypto.Digest; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsHandshakeHash extends Digest { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsKeyExchange.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsKeyExchange.java index 4857ce01c..6db8f0438 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsKeyExchange.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsKeyExchange.java @@ -6,6 +6,8 @@ import java.io.OutputStream; /** * A generic interface for key exchange implementations in (D)TLS. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public interface TlsKeyExchange { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsMac.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsMac.java index b934c4e24..01d1d0455 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsMac.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsMac.java @@ -9,6 +9,8 @@ import com.fr.third.org.bouncycastle.util.Arrays; /** * A generic TLS MAC implementation, acting as an HMAC based on some underlying Digest. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsMac { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java index ef1b5455f..731431d96 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNoCloseNotifyException.java @@ -8,6 +8,8 @@ import java.io.EOFException; * protocol cannot rule out truncation of the connection data (potentially malicious). It may be * possible to check for truncation via some property of a higher level protocol built upon TLS, * e.g. the Content-Length header for HTTPS. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsNoCloseNotifyException extends EOFException diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNullCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNullCipher.java index 6d564e102..ecb4634f7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNullCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNullCipher.java @@ -7,6 +7,8 @@ import com.fr.third.org.bouncycastle.util.Arrays; /** * A NULL CipherSuite with optional MAC + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsNullCipher implements TlsCipher diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNullCompression.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNullCompression.java index 18a6c4707..3392f19ef 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNullCompression.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsNullCompression.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.OutputStream; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsNullCompression implements TlsCompression { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKIdentity.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKIdentity.java index 4e13af25d..a4c6db896 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKIdentity.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKIdentity.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsPSKIdentity { void skipIdentityHint(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKIdentityManager.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKIdentityManager.java index 0e13613f1..c38d69b62 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKIdentityManager.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKIdentityManager.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsPSKIdentityManager { byte[] getHint(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKKeyExchange.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKKeyExchange.java index e7cc95d0b..186573826 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKKeyExchange.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPSKKeyExchange.java @@ -23,6 +23,8 @@ import com.fr.third.org.bouncycastle.util.io.Streams; /** * (D)TLS PSK key exchange (RFC 4279). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsPSKKeyExchange extends AbstractTlsKeyExchange @@ -30,6 +32,7 @@ public class TlsPSKKeyExchange protected TlsPSKIdentity pskIdentity; protected TlsPSKIdentityManager pskIdentityManager; + protected TlsDHVerifier dhVerifier; protected DHParameters dhParameters; protected int[] namedCurves; protected short[] clientECPointFormats, serverECPointFormats; @@ -48,9 +51,20 @@ public class TlsPSKKeyExchange protected TlsEncryptionCredentials serverCredentials = null; protected byte[] premasterSecret; + /** + * @deprecated Use constructor that takes a TlsDHVerifier + */ public TlsPSKKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsPSKIdentity pskIdentity, TlsPSKIdentityManager pskIdentityManager, DHParameters dhParameters, int[] namedCurves, short[] clientECPointFormats, short[] serverECPointFormats) + { + this(keyExchange, supportedSignatureAlgorithms, pskIdentity, pskIdentityManager, new DefaultTlsDHVerifier(), + dhParameters, namedCurves, clientECPointFormats, serverECPointFormats); + } + + public TlsPSKKeyExchange(int keyExchange, Vector supportedSignatureAlgorithms, TlsPSKIdentity pskIdentity, + TlsPSKIdentityManager pskIdentityManager, TlsDHVerifier dhVerifier, DHParameters dhParameters, int[] namedCurves, + short[] clientECPointFormats, short[] serverECPointFormats) { super(keyExchange, supportedSignatureAlgorithms); @@ -67,6 +81,7 @@ public class TlsPSKKeyExchange this.pskIdentity = pskIdentity; this.pskIdentityManager = pskIdentityManager; + this.dhVerifier = dhVerifier; this.dhParameters = dhParameters; this.namedCurves = namedCurves; this.clientECPointFormats = clientECPointFormats; @@ -186,10 +201,8 @@ public class TlsPSKKeyExchange if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) { - ServerDHParams serverDHParams = ServerDHParams.parse(input); - - this.dhAgreePublicKey = TlsDHUtils.validateDHPublicKey(serverDHParams.getPublicKey()); - this.dhParameters = dhAgreePublicKey.getParameters(); + this.dhParameters = TlsDHUtils.receiveDHParameters(dhVerifier, input); + this.dhAgreePublicKey = new DHPublicKeyParameters(TlsDHUtils.readDHParameter(input), dhParameters); } else if (this.keyExchange == KeyExchangeAlgorithm.ECDHE_PSK) { @@ -270,9 +283,7 @@ public class TlsPSKKeyExchange if (this.keyExchange == KeyExchangeAlgorithm.DHE_PSK) { - BigInteger Yc = TlsDHUtils.readDHParameter(input); - - this.dhAgreePublicKey = TlsDHUtils.validateDHPublicKey(new DHPublicKeyParameters(Yc, dhParameters)); + this.dhAgreePublicKey = new DHPublicKeyParameters(TlsDHUtils.readDHParameter(input), dhParameters); } else if (this.keyExchange == KeyExchangeAlgorithm.ECDHE_PSK) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPeer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPeer.java index 2f9e24a81..ddea87ab4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPeer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsPeer.java @@ -2,8 +2,28 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsPeer { + void notifyCloseHandle(TlsCloseable closehandle); + + void cancel() throws IOException; + + /** + * This implementation supports RFC 7627 and will always negotiate the extended_master_secret + * extension where possible. When connecting to a peer that does not offer/accept this + * extension, it is recommended to abort the handshake. This option is provided for + * interoperability with legacy peers, although some TLS features will be disabled in that case + * (see RFC 7627 5.4). + * + * @return true if the handshake should be aborted when the peer does not negotiate + * the extended_master_secret extension, or false to support legacy + * interoperability. + */ + boolean requiresExtendedMasterSecret(); + /** * draft-mathewson-no-gmtunixtime-00 2. "If existing users of a TLS implementation may rely on * gmt_unix_time containing the current time, we recommend that implementors MAY provide the diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsProtocol.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsProtocol.java index 6d5e109ee..5ede6d39c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsProtocol.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsProtocol.java @@ -16,7 +16,11 @@ import com.fr.third.org.bouncycastle.crypto.prng.RandomGenerator; import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.Integers; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public abstract class TlsProtocol + implements TlsCloseable { protected static final Integer EXT_RenegotiationInfo = Integers.valueOf(ExtensionType.renegotiation_info); protected static final Integer EXT_SessionTicket = Integers.valueOf(ExtensionType.session_ticket); @@ -310,6 +314,7 @@ public abstract class TlsProtocol this.sessionParameters = new SessionParameters.Builder() .setCipherSuite(this.securityParameters.getCipherSuite()) .setCompressionAlgorithm(this.securityParameters.getCompressionAlgorithm()) + .setExtendedMasterSecret(securityParameters.isExtendedMasterSecret()) .setMasterSecret(this.securityParameters.getMasterSecret()) .setPeerCertificate(this.peerCertificate) .setPSKIdentity(this.securityParameters.getPSKIdentity()) @@ -419,31 +424,30 @@ public abstract class TlsProtocol break; } - checkReceivedChangeCipherSpec(connection_state == CS_END || type == HandshakeType.finished); - /* * RFC 2246 7.4.9. The value handshake_messages includes all handshake messages * starting at client hello up to, but not including, this finished message. * [..] Note: [Also,] Hello Request messages are omitted from handshake hashes. */ - switch (type) - { - case HandshakeType.hello_request: - break; - case HandshakeType.finished: + if (HandshakeType.hello_request != type) { - TlsContext ctx = getContext(); - if (this.expected_verify_data == null - && ctx.getSecurityParameters().getMasterSecret() != null) + if (HandshakeType.finished == type) { - this.expected_verify_data = createVerifyData(!ctx.isServer()); + checkReceivedChangeCipherSpec(true); + + TlsContext ctx = getContext(); + if (this.expected_verify_data == null + && ctx.getSecurityParameters().getMasterSecret() != null) + { + this.expected_verify_data = createVerifyData(!ctx.isServer()); + } + } + else + { + checkReceivedChangeCipherSpec(connection_state == CS_END); } - // NB: Fall through to next case label - } - default: queue.copyTo(recordStream.getHandshakeHashUpdater(), totalLength); - break; } queue.removeData(4); @@ -797,12 +801,20 @@ public abstract class TlsProtocol throw new TlsNoCloseNotifyException(); } + /** + * Equivalent to offerInput(input, 0, input.length) + * @see TlsProtocol#offerInput(byte[], int, int) + * @param input The input buffer to offer + * @throws IOException If an error occurs while decrypting or processing a record + */ + public void offerInput(byte[] input) throws IOException + { + offerInput(input, 0, input.length); + } + /** * Offer input from an arbitrary source. Only allowed in non-blocking mode.
*
- * After this method returns, the input buffer is "owned" by this object. Other code - * must not attempt to do anything with it.
- *
* This method will decrypt and process all records that are fully available. * If only part of a record is available, the buffer will be retained until the * remainder of the record is offered.
@@ -813,21 +825,23 @@ public abstract class TlsProtocol * You should always check to see if there is any available output after calling * this method by calling {@link #getAvailableOutputBytes()}. * @param input The input buffer to offer + * @param inputOff The offset within the input buffer that input begins + * @param inputLen The number of bytes of input being offered * @throws IOException If an error occurs while decrypting or processing a record */ - public void offerInput(byte[] input) throws IOException + public void offerInput(byte[] input, int inputOff, int inputLen) throws IOException { if (blocking) { throw new IllegalStateException("Cannot use offerInput() in blocking mode! Use getInputStream() instead."); } - + if (closed) { throw new IOException("Connection is closed, cannot accept any more input"); } - - inputBuffers.addBytes(input); + + inputBuffers.addBytes(input, inputOff, inputLen); // loop while there are enough bytes to read the length of the next record while (inputBuffers.available() >= RecordStream.TLS_HEADER_SIZE) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSAKeyExchange.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSAKeyExchange.java index a9d967999..5b701d273 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSAKeyExchange.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSAKeyExchange.java @@ -14,6 +14,8 @@ import com.fr.third.org.bouncycastle.util.io.Streams; /** * (D)TLS and SSLv3 RSA key exchange. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsRSAKeyExchange extends AbstractTlsKeyExchange diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSASigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSASigner.java index 23d71a8b7..b58c45d13 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSASigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSASigner.java @@ -14,6 +14,9 @@ import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; import com.fr.third.org.bouncycastle.crypto.signers.GenericSigner; import com.fr.third.org.bouncycastle.crypto.signers.RSADigestSigner; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsRSASigner extends AbstractTlsSigner { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSAUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSAUtils.java index 328cc2e40..78ed90545 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSAUtils.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsRSAUtils.java @@ -10,6 +10,9 @@ import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsRSAUtils { public static byte[] generateEncryptedPreMasterSecret(TlsContext context, RSAKeyParameters rsaServerPublicKey, diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPGroupVerifier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPGroupVerifier.java index 369d97da7..242a026ca 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPGroupVerifier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPGroupVerifier.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import com.fr.third.org.bouncycastle.crypto.params.SRP6GroupParameters; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsSRPGroupVerifier { /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPIdentityManager.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPIdentityManager.java index a22b91998..f65ef86b3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPIdentityManager.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPIdentityManager.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsSRPIdentityManager { /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPKeyExchange.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPKeyExchange.java index 7952a0a7e..734e0e512 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPKeyExchange.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPKeyExchange.java @@ -23,6 +23,8 @@ import com.fr.third.org.bouncycastle.util.io.TeeInputStream; /** * (D)TLS SRP key exchange (RFC 5054). + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsSRPKeyExchange extends AbstractTlsKeyExchange { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPLoginParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPLoginParameters.java index 1e9774b8b..4083d97f1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPLoginParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPLoginParameters.java @@ -4,6 +4,9 @@ import java.math.BigInteger; import com.fr.third.org.bouncycastle.crypto.params.SRP6GroupParameters; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsSRPLoginParameters { protected SRP6GroupParameters group; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPUtils.java index 997173943..26d7deffa 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPUtils.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRPUtils.java @@ -10,6 +10,9 @@ import java.util.Hashtable; import com.fr.third.org.bouncycastle.util.BigIntegers; import com.fr.third.org.bouncycastle.util.Integers; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsSRPUtils { public static final Integer EXT_SRP = Integers.valueOf(ExtensionType.srp); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRTPUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRTPUtils.java index 28268f4fa..4252a4cc4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRTPUtils.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSRTPUtils.java @@ -9,6 +9,8 @@ import com.fr.third.org.bouncycastle.util.Integers; /** * RFC 5764 DTLS Extension to Establish Keys for SRTP. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsSRTPUtils { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServer.java index f7844ad5a..5017481fc 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServer.java @@ -6,6 +6,8 @@ import java.util.Vector; /** * Interface describing a TLS server endpoint. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public interface TlsServer extends TlsPeer diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServerContext.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServerContext.java index a08b5e4a2..4f011aa35 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServerContext.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServerContext.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * Marker interface to distinguish a TLS server context. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public interface TlsServerContext extends TlsContext diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServerProtocol.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServerProtocol.java index 926092be5..9a426fa2e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServerProtocol.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsServerProtocol.java @@ -12,6 +12,9 @@ import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; import com.fr.third.org.bouncycastle.crypto.util.PublicKeyFactory; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsServerProtocol extends TlsProtocol { @@ -89,6 +92,8 @@ public class TlsServerProtocol this.tlsServer.init(tlsServerContext); this.recordStream.init(tlsServerContext); + tlsServer.notifyCloseHandle(this); + this.recordStream.setRestrictReadVersion(false); blockForHandshake(); @@ -583,12 +588,18 @@ public class TlsServerProtocol this.clientExtensions = readExtensions(buf); /* - * TODO[session-hash] - * - * draft-ietf-tls-session-hash-04 4. Clients and servers SHOULD NOT accept handshakes - * that do not use the extended master secret [..]. (and see 5.2, 5.3) + * TODO[resumption] Check RFC 7627 5.4. for required behaviour + */ + + /* + * RFC 7627 4. Clients and servers SHOULD NOT accept handshakes that do not use the extended + * master secret [..]. (and see 5.2, 5.3) */ this.securityParameters.extendedMasterSecret = TlsExtensionsUtils.hasExtendedMasterSecretExtension(clientExtensions); + if (!securityParameters.isExtendedMasterSecret() && tlsServer.requiresExtendedMasterSecret()) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } getContextAdmin().setClientVersion(client_version); @@ -758,7 +769,7 @@ public class TlsServerProtocol TlsUtils.writeUint16(selectedCipherSuite, message); TlsUtils.writeUint8(selectedCompressionMethod, message); - this.serverExtensions = tlsServer.getServerExtensions(); + this.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(tlsServer.getServerExtensions()); /* * RFC 5746 3.6. Server Behavior: Initial Handshake @@ -782,14 +793,16 @@ public class TlsServerProtocol * If the secure_renegotiation flag is set to TRUE, the server MUST include an empty * "renegotiation_info" extension in the ServerHello message. */ - this.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(serverExtensions); this.serverExtensions.put(EXT_RenegotiationInfo, createRenegotiationInfo(TlsUtils.EMPTY_BYTES)); } } - if (securityParameters.extendedMasterSecret) + if (TlsUtils.isSSL(tlsServerContext)) + { + securityParameters.extendedMasterSecret = false; + } + else if (securityParameters.isExtendedMasterSecret()) { - this.serverExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(serverExtensions); TlsExtensionsUtils.addExtendedMasterSecretExtension(serverExtensions); } @@ -799,7 +812,7 @@ public class TlsServerProtocol * extensions. */ - if (this.serverExtensions != null) + if (!this.serverExtensions.isEmpty()) { this.securityParameters.encryptThenMAC = TlsExtensionsUtils.hasEncryptThenMACExtension(serverExtensions); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSession.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSession.java index 4551bf9eb..a9a7bbe7c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSession.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSession.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsSession { SessionParameters exportSessionParameters(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSessionImpl.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSessionImpl.java index e77000b0e..417c1a4da 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSessionImpl.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSessionImpl.java @@ -5,7 +5,8 @@ import com.fr.third.org.bouncycastle.util.Arrays; class TlsSessionImpl implements TlsSession { final byte[] sessionID; - SessionParameters sessionParameters; + final SessionParameters sessionParameters; + boolean resumable; TlsSessionImpl(byte[] sessionID, SessionParameters sessionParameters) { @@ -13,13 +14,16 @@ class TlsSessionImpl implements TlsSession { throw new IllegalArgumentException("'sessionID' cannot be null"); } - if (sessionID.length < 1 || sessionID.length > 32) + if (sessionID.length > 32) { - throw new IllegalArgumentException("'sessionID' must have length between 1 and 32 bytes, inclusive"); + throw new IllegalArgumentException("'sessionID' cannot be longer than 32 bytes"); } this.sessionID = Arrays.clone(sessionID); this.sessionParameters = sessionParameters; + this.resumable = sessionID.length > 0 + && null != sessionParameters + && sessionParameters.isExtendedMasterSecret(); } public synchronized SessionParameters exportSessionParameters() @@ -34,15 +38,11 @@ class TlsSessionImpl implements TlsSession public synchronized void invalidate() { - if (this.sessionParameters != null) - { - this.sessionParameters.clear(); - this.sessionParameters = null; - } + this.resumable = false; } public synchronized boolean isResumable() { - return this.sessionParameters != null; + return resumable; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSigner.java index 4e430c87e..950454011 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSigner.java @@ -4,6 +4,9 @@ import com.fr.third.org.bouncycastle.crypto.CryptoException; import com.fr.third.org.bouncycastle.crypto.Signer; import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsSigner { void init(TlsContext context); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSignerCredentials.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSignerCredentials.java index 5d8689d63..381608d89 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSignerCredentials.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsSignerCredentials.java @@ -2,6 +2,9 @@ package com.fr.third.org.bouncycastle.crypto.tls; import java.io.IOException; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public interface TlsSignerCredentials extends TlsCredentials { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsStreamCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsStreamCipher.java index e55359e0c..8ad63e04f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsStreamCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsStreamCipher.java @@ -9,6 +9,9 @@ import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; import com.fr.third.org.bouncycastle.util.Arrays; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class TlsStreamCipher implements TlsCipher { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsUtils.java index a08257672..5cb3f5624 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsUtils.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/TlsUtils.java @@ -41,6 +41,8 @@ import com.fr.third.org.bouncycastle.util.io.Streams; /** * Some helper functions for MicroTLS. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class TlsUtils { @@ -1100,7 +1102,7 @@ public class TlsUtils SecurityParameters securityParameters = context.getSecurityParameters(); byte[] seed; - if (securityParameters.extendedMasterSecret) + if (securityParameters.isExtendedMasterSecret()) { seed = securityParameters.getSessionHash(); } @@ -1114,7 +1116,7 @@ public class TlsUtils return calculateMasterSecret_SSL(pre_master_secret, seed); } - String asciiLabel = securityParameters.extendedMasterSecret + String asciiLabel = securityParameters.isExtendedMasterSecret() ? ExporterLabel.extended_master_secret : ExporterLabel.master_secret; @@ -1352,11 +1354,14 @@ public class TlsUtils supportedSignatureAlgorithms.elementAt(i); short hashAlgorithm = signatureAndHashAlgorithm.getHash(); - // TODO Support values in the "Reserved for Private Use" range - if (!HashAlgorithm.isPrivate(hashAlgorithm)) + if (HashAlgorithm.isRecognized(hashAlgorithm)) { handshakeHash.trackHashAlgorithm(hashAlgorithm); } + else //if (HashAlgorithm.isPrivate(hashAlgorithm)) + { + // TODO Support values in the "Reserved for Private Use" range + } } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UDPTransport.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UDPTransport.java index 4f21c187e..c6ae2fdac 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UDPTransport.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UDPTransport.java @@ -4,6 +4,9 @@ import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSocket; +/** + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). + */ public class UDPTransport implements DatagramTransport { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/URLAndHash.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/URLAndHash.java index fb8f60b29..071b9b6b3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/URLAndHash.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/URLAndHash.java @@ -8,6 +8,8 @@ import com.fr.third.org.bouncycastle.util.Strings; /** * RFC 6066 5. + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class URLAndHash { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UseSRTPData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UseSRTPData.java index a7755c05f..d9e9da849 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UseSRTPData.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UseSRTPData.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 5764 4.1.1 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class UseSRTPData { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UserMappingType.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UserMappingType.java index 76f6d510d..ab9323268 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UserMappingType.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/UserMappingType.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.crypto.tls; /** * RFC 4681 + * + * @deprecated Migrate to the (D)TLS API in com.fr.third.org.bouncycastle.tls (bctls jar). */ public class UserMappingType { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSClientTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSClientTest.java new file mode 100644 index 000000000..b1b36af83 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSClientTest.java @@ -0,0 +1,81 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.net.DatagramSocket; +import java.net.InetAddress; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.tls.DTLSClientProtocol; +import com.fr.third.org.bouncycastle.crypto.tls.DTLSTransport; +import com.fr.third.org.bouncycastle.crypto.tls.DatagramTransport; +import com.fr.third.org.bouncycastle.crypto.tls.TlsClient; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSession; +import com.fr.third.org.bouncycastle.crypto.tls.UDPTransport; + +/** + * A simple test designed to conduct a DTLS handshake with an external DTLS server. + *

+ * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external DTLS server. + *

+ */ +public class DTLSClientTest +{ + private static final SecureRandom secureRandom = new SecureRandom(); + + public static void main(String[] args) + throws Exception + { + InetAddress address = InetAddress.getLocalHost(); + int port = 5556; + + TlsSession session = createSession(address, port); + + MockDTLSClient client = new MockDTLSClient(session); + + DTLSTransport dtls = openDTLSConnection(address, port, client); + + System.out.println("Receive limit: " + dtls.getReceiveLimit()); + System.out.println("Send limit: " + dtls.getSendLimit()); + + // Send and hopefully receive a packet back + + byte[] request = "Hello World!\n".getBytes("UTF-8"); + dtls.send(request, 0, request.length); + + byte[] response = new byte[dtls.getReceiveLimit()]; + int received = dtls.receive(response, 0, response.length, 30000); + if (received >= 0) + { + System.out.println(new String(response, 0, received, "UTF-8")); + } + + dtls.close(); + } + + private static TlsSession createSession(InetAddress address, int port) + throws IOException + { + MockDTLSClient client = new MockDTLSClient(null); + DTLSTransport dtls = openDTLSConnection(address, port, client); + TlsSession session = client.getSessionToResume(); + dtls.close(); + return session; + } + + private static DTLSTransport openDTLSConnection(InetAddress address, int port, TlsClient client) + throws IOException + { + DatagramSocket socket = new DatagramSocket(); + socket.connect(address, port); + + int mtu = 1500; + DatagramTransport transport = new UDPTransport(socket, mtu); + transport = new UnreliableDatagramTransport(transport, secureRandom, 0, 0); + transport = new LoggingDatagramTransport(transport, System.out); + + DTLSClientProtocol protocol = new DTLSClientProtocol(secureRandom); + + return protocol.connect(client, transport); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSServerTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSServerTest.java new file mode 100644 index 000000000..8ba6576ab --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSServerTest.java @@ -0,0 +1,75 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.net.DatagramPacket; +import java.net.DatagramSocket; +import java.net.SocketTimeoutException; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.tls.DTLSServerProtocol; +import com.fr.third.org.bouncycastle.crypto.tls.DTLSTransport; +import com.fr.third.org.bouncycastle.crypto.tls.DatagramTransport; +import com.fr.third.org.bouncycastle.crypto.tls.UDPTransport; + +/** + * A simple test designed to conduct a DTLS handshake with an external DTLS client. + *

+ * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external DTLS client. + *

+ */ +public class DTLSServerTest +{ + public static void main(String[] args) + throws Exception + { + int port = 5556; + + int mtu = 1500; + + SecureRandom secureRandom = new SecureRandom(); + + DTLSServerProtocol serverProtocol = new DTLSServerProtocol(secureRandom); + + byte[] data = new byte[mtu]; + DatagramPacket packet = new DatagramPacket(data, mtu); + + DatagramSocket socket = new DatagramSocket(port); + socket.receive(packet); + + System.out.println("Accepting connection from " + packet.getAddress().getHostAddress() + ":" + port); + socket.connect(packet.getAddress(), packet.getPort()); + + /* + * NOTE: For simplicity, and since we don't yet have HelloVerifyRequest support, we just + * discard the initial packet, which the client should re-send anyway. + */ + + DatagramTransport transport = new UDPTransport(socket, mtu); + + // Uncomment to see packets +// transport = new LoggingDatagramTransport(transport, System.out); + + MockDTLSServer server = new MockDTLSServer(); + DTLSTransport dtlsServer = serverProtocol.accept(server, transport); + + byte[] buf = new byte[dtlsServer.getReceiveLimit()]; + + while (!socket.isClosed()) + { + try + { + int length = dtlsServer.receive(buf, 0, buf.length, 60000); + if (length >= 0) + { + System.out.write(buf, 0, length); + dtlsServer.send(buf, 0, length); + } + } + catch (SocketTimeoutException ste) + { + } + } + + dtlsServer.close(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSTestClientProtocol.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSTestClientProtocol.java new file mode 100644 index 000000000..ee0b62bad --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSTestClientProtocol.java @@ -0,0 +1,30 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.tls.DTLSClientProtocol; +import com.fr.third.org.bouncycastle.crypto.tls.DigitallySigned; + +class DTLSTestClientProtocol extends DTLSClientProtocol +{ + protected final TlsTestConfig config; + + public DTLSTestClientProtocol(SecureRandom secureRandom, TlsTestConfig config) + { + super(secureRandom); + + this.config = config; + } + + protected byte[] generateCertificateVerify(ClientHandshakeState state, DigitallySigned certificateVerify) + throws IOException + { + if (certificateVerify.getAlgorithm() != null && config.clientAuthSigAlgClaimed != null) + { + certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.getSignature()); + } + + return super.generateCertificateVerify(state, certificateVerify); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSTestServerProtocol.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSTestServerProtocol.java new file mode 100644 index 000000000..24ab142e9 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/DTLSTestServerProtocol.java @@ -0,0 +1,17 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.tls.DTLSServerProtocol; + +class DTLSTestServerProtocol extends DTLSServerProtocol +{ + protected final TlsTestConfig config; + + public DTLSTestServerProtocol(SecureRandom secureRandom, TlsTestConfig config) + { + super(secureRandom); + + this.config = config; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/HTTPSServerThread.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/HTTPSServerThread.java new file mode 100644 index 000000000..14af787e8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/HTTPSServerThread.java @@ -0,0 +1,114 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.security.KeyStore; + +import javax.net.ssl.KeyManagerFactory; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; +import javax.net.ssl.SSLServerSocketFactory; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; +import javax.net.ssl.TrustManagerFactory; + +public class HTTPSServerThread + extends Thread +{ + private static final int PORT_NO = 8003; + private static final char[] SERVER_PASSWORD = "serverPassword".toCharArray(); + private static final char[] TRUST_STORE_PASSWORD = "trustPassword".toCharArray(); + + /** + * Read a HTTP request + */ + private void readRequest( + InputStream in) + throws IOException + { + int ch = 0; + int lastCh = 0; + while ((ch = in.read()) >= 0 && (ch != '\n' && lastCh != '\n')) + { + if (ch != '\r') + { + lastCh = ch; + } + } + } + + /** + * Send a response + */ + private void sendResponse( + OutputStream out) + { + PrintWriter pWrt = new PrintWriter(new OutputStreamWriter(out)); + pWrt.print("HTTP/1.1 200 OK\r\n"); + pWrt.print("Content-Type: text/html\r\n"); + pWrt.print("\r\n"); + pWrt.print("\r\n"); + pWrt.print("\r\n"); + pWrt.print("Hello World!\r\n"); + pWrt.print("\r\n"); + pWrt.print("\r\n"); + pWrt.flush(); + } + + SSLContext createSSLContext() + throws Exception + { + KeyManagerFactory mgrFact = KeyManagerFactory.getInstance("SunX509"); + KeyStore serverStore = KeyStore.getInstance("JKS"); + + serverStore.load(new ByteArrayInputStream(KeyStores.server), SERVER_PASSWORD); + + mgrFact.init(serverStore, SERVER_PASSWORD); + + // set up a trust manager so we can recognize the server + TrustManagerFactory trustFact = TrustManagerFactory.getInstance("SunX509"); + KeyStore trustStore = KeyStore.getInstance("JKS"); + + trustStore.load(new ByteArrayInputStream(KeyStores.trustStore), TRUST_STORE_PASSWORD); + + trustFact.init(trustStore); + + // create a context and set up a socket factory + SSLContext sslContext = SSLContext.getInstance("TLS"); + + sslContext.init(mgrFact.getKeyManagers(), trustFact.getTrustManagers(), null); + + return sslContext; + } + + public void run() + { + try + { + SSLContext sslContext = createSSLContext(); + SSLServerSocketFactory fact = sslContext.getServerSocketFactory(); + + SSLServerSocket sSock = (SSLServerSocket)fact.createServerSocket(PORT_NO); + SSLSocket sslSock = (SSLSocket)sSock.accept(); + + sslSock.startHandshake(); + + readRequest(sslSock.getInputStream()); + + SSLSession session = sslSock.getSession(); + + sendResponse(sslSock.getOutputStream()); + + sslSock.close(); + sSock.close(); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/KeyStores.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/KeyStores.java new file mode 100644 index 000000000..2eea83f45 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/KeyStores.java @@ -0,0 +1,113 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import com.fr.third.org.bouncycastle.util.encoders.Base64; + +public class KeyStores +{ + static final byte[] trustStore = Base64.decode( + "/u3+7QAAAAIAAAABAAAAAgAGc2VydmVyAAABD34zDJEABVguNTA5AAABrzCC" + + "AaswggEUAgEBMA0GCSqGSIb3DQEBBQUAMB4xHDAaBgNVBAMTE1Rlc3QgQ0Eg" + + "Q2VydGlmaWNhdGUwHhcNMDYxMjEzMjM0MzI5WhcNMDYxMjIwMjM0MzI5WjAe" + + "MRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEB" + + "AQUAA4GNADCBiQKBgQCmOumCM46ehsdcrZMw6tj0hMl5D0xf21gcyBj/ByIv" + + "pe008ukaN3zCXIUUUlAu0GkbI1sCbTD1V4qVZuaHqtfa/FINJjyZJy5w7KEx" + + "93OOF2/gyPlnEPGs6RPdThAPliSBsWKBKqtOdmKpwYn/NKuUNFRkFXVLLUPn" + + "jyEKjIcNywIDAQABMA0GCSqGSIb3DQEBBQUAA4GBACi8J7raYqDFjXqAXXPJ" + + "ljZHqvzJNVaSWvBtK/oY7g0+sdGIjPR526fhSCxOZRr7G157ERqMnPjuFjcm" + + "cRlUOPsQtTl6KbUnxmKxa04UzDuNXzSx2oyGx5GCWx9u62hpO6vSpK69L9gH" + + "OUtM5dQXcoK4i3olScKaU8qaYb0mBAy8fnx5pen8B0bIg+pz47l5VxQ5NO8="); + + static final byte[] server = Base64.decode( + "/u3+7QAAAAIAAAABAAAAAQAGc2VydmVyAAABD34zDJIAAAK8MIICuDAOBgor" + + "BgEEASoCEQEBBQAEggKk9OXWj3aBr6rV9Grcsm2YL+/2ShVsxbJVGMSWll1f" + + "U8z/mjhv5K/skgleTIMoyE5FzDDxJIGEmSMCkcHsnseXzxyhLpKBaz3N1Tk7" + + "KVPzXfrNh0FJwzw3lPWyC2ayT+ObQfAtzuI9SUWNLBzzpWeolUJ8gkXnLshX" + + "5RqmR735NRZdjgQOtNYBBErX/NOhTyi009/CZDNxgJQzywFmQcXBLhNSA+0i" + + "cE+LwZ4sZV0NXshPZiyNnsfqN/XNOyhpKr8a3VyVtee2nhO9+FY5IDEviHmR" + + "WDvH5TmB6Os3L6xvwE1ZQCPElk/cK2G1q9+zDBe4JDeo8o7lPhiNpVfcivnr" + + "+tyK9m7PqlssR0+ohuZGwrFMyzLugkOWh+qZ3pk8/7AwJosMvvTvIg36nN7R" + + "pdnouQNKqTm1Sr/UUnKyWqfG7zqKIuF72IkDwwafwuQ9YRX5PAOuRfo6bCyb" + + "D4w1OWdfGFciKMc1BrT+8JzhiTkzNe+jWEA5Tw1zeazPGpp1RHPz2np50G2s" + + "v025uiOSUilBe13Qpx0mAyx7z8Gl6eOxai6rQ/eB/Fu++BMx0OX8vO/K4//Q" + + "w43IPVPklGlb/3Qt7eoNf4tichuxrYJjHu4XbwnzB29Vmsan0XZFER7epvFj" + + "cAZCSG+O6G/f6Ib+7d7xYjLdUaPI60tJ4/C+AuYwZn4jJwTnMnMmwIypz4Z8" + + "XPXW5SbHlV5OkkFC+eAuuN4b2YXZmifeWv4fx65Ioir921LMJrorMizH41RJ" + + "/rAO5wGSwjeDJ784QhhLGbEUMygraRtdaz6MRx26InnoHY7V58ET3Z5YGV39" + + "p+9AtVhYw/QQmTZiF7hqnEMf9AMVFfac9qFF2+IN3g9HAMC6QLxJ1VuPn5oo" + + "lS//axPfjckO7iZx9x59/gAAAAEABVguNTA5AAABrzCCAaswggEUAgEBMA0G" + + "CSqGSIb3DQEBBQUAMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGUw" + + "HhcNMDYxMjEzMjM0MzI5WhcNMDYxMjIwMjM0MzI5WjAeMRwwGgYDVQQDExNU" + + "ZXN0IENBIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB" + + "gQCmOumCM46ehsdcrZMw6tj0hMl5D0xf21gcyBj/ByIvpe008ukaN3zCXIUU" + + "UlAu0GkbI1sCbTD1V4qVZuaHqtfa/FINJjyZJy5w7KEx93OOF2/gyPlnEPGs" + + "6RPdThAPliSBsWKBKqtOdmKpwYn/NKuUNFRkFXVLLUPnjyEKjIcNywIDAQAB" + + "MA0GCSqGSIb3DQEBBQUAA4GBACi8J7raYqDFjXqAXXPJljZHqvzJNVaSWvBt" + + "K/oY7g0+sdGIjPR526fhSCxOZRr7G157ERqMnPjuFjcmcRlUOPsQtTl6KbUn" + + "xmKxa04UzDuNXzSx2oyGx5GCWx9u62hpO6vSpK69L9gHOUtM5dQXcoK4i3ol" + + "ScKaU8qaYb0mBAy87VQaPfaiQqqxSgqifbSowlg+0fg="); + + static final byte[] client = Base64.decode( + "MIACAQMwgAYJKoZIhvcNAQcBoIAkgASCA+gwgDCABgkqhkiG9w0BBwGggCSA" + + "BIIDDzCCAwswggMHBgsqhkiG9w0BDAoBAqCCArIwggKuMCgGCiqGSIb3DQEM" + + "AQMwGgQUyeN8U+ViAJCk1WGo8wTnRVOaE1oCAgQABIICgH3yMWB+dfMBNa07" + + "hn3smUSBTF+LUauM+kx+12nZt0QazBYg09yM+aVcTznettlDwE/PTpKZnrFT" + + "22DSQf5GwABwiL6KW+xyM8wV5vZx1xtqrQoNf2oNHnF0lB7ddSYM8jHqennb" + + "bzcVOdrrCqewqAfUU/CDugpwwI8c8Iy9ECri6vBMbfeIIZQTug+1952TCCiA" + + "E1bEDFGqgAoDsqYi6uNtpjmL/DPX/qmkbHAXUKxOtjTtxacfat2HgN97Gb7z" + + "+ZBNI5aaCSRoYwl+K9biWGID3EqsNmg0+2ELmFhE4mQZ78i7vNLTG7e5mj6v" + + "Qt+QuqN+daCbVqVTKxsFpODRRweobUTRxwEun6p0p3w3SUhR6p7ug1Jttgyu" + + "vfZug3PIk2j9fb26wAs2ZreVYut8hXpp/09ulCUudtlsYb/FD+H11v/JyopG" + + "2vYy0hL/gkMr41sGoVdyvzXeZUa7A1wYask+g7torad9sT8CPb3zXBd0kU2r" + + "lbSJIXQ8wTpheeUKe47YF9JVCF8WRc1dokD7fgfn6197pwyZpDEVrVyz1pUq" + + "jyum3ctONU4BSkAUVr9pTyeRFUeOE7SLuVu+c67PzNWXEc/HMVD4Hgs/idVc" + + "mrONk3xe385wFJK1iPe1kfRX5OXk9UWr2/yjgrahbkonWhJHnIlvs+b5rRKN" + + "qauwUZ+agMJV98Eyc2Lz0Lp/pNDRNjmGXeJLzAaAy46STov8sxwAgj3bQ7xu" + + "uEzdhJPDynAY5sWd3WnBY2ZhpawnToEKnD4u+eiH2MjUL2q/R2IPSmoyg9i2" + + "Ictgh4/ylrhm+lJDzcDrLDhC0m/t9EdhytH4erk/uCPcmAK/jpzFn6ltxcsx" + + "QjAbBgkqhkiG9w0BCRQxDh4MAGMAbABpAGUAbgB0MCMGCSqGSIb3DQEJFTEW" + + "BBS2wDxw7yH2OhKIgkDoQrTlavLvxQAAAAAAADCABgkqhkiG9w0BBwaggDCA" + + "AgEAMIAGCSqGSIb3DQEHATAoBgoqhkiG9w0BDAEGMBoEFORdyeTIG2oXDQBl" + + "I3aFNozDAkC2AgIEAKCABIIHICsc3D8rxLiDlegyXFfIejto66RW4u6b+d0C" + + "uAAz0G+dIvhQ9g3s++vUsX7x+icO/vjpgdo09aqtIg7T3suzfcHtU8CGSgtQ" + + "Tvml25LDC3IK3qI6cRqO+sCdvg18aS04IDKvDPYH4ca5btwPBIID6CStk/jY" + + "QFpnSI6VNz9IERi/nwuvuBYk+A0Z7+nQdhF+QkW1rzN+uz0dkNJt6ZbG5lEK" + + "GayV+FDTQcREMihYa716RN9sq3cm0jXXdttj998oS/QrpZDEcPqd4AM6EIL+" + + "PTA1tEQYxXa8msAPp+tLvXOtiD6v/4FO77EA7E5oR36a9en+M1QQasFU3VBf" + + "V9os92QlbtVUTkspJV9gXL6s4CGNptc7lUH+nIw65j9MOoyOU9w1qjPRlN/Z" + + "MTuhFooglE6TPd29Udwufqp+hHkW/7z5tBKkhGlZEClzD3IWhcF9NVraE/IV" + + "S5qVmx2Up7SeLZAXJ+AAznq5IXwE1dOUTkwYLcIrH1FuVA5rtOkB8Xt1LJq0" + + "ERkjJ5MfpxTxbKXp5PejzD98v54+s4INekcrI0jzz4pLsann7ex0r6CPsQsH" + + "+F3rBVaT3oHSKqoIm2Nw57oDjLLp5lP2qcCqps3y2dcVzu5NIzCSkVlxUaBK" + + "IT3xv0gvVJI7wnP0QM35MCywKkToJX5ajQKrDc4iCAAzmxaQzdBycxJPYByq" + + "VHvH7BJldJlMw5NHbTHlNoYKndMdAsHp7sUqERkDEGl80R86TlB4nJaDrfsx" + + "vL+KluiCY9AD7o+MEYZ9VYoNDUzVGH4pTr4wnv1UFoRWix5IZuDnnYkyijKD" + + "VtU5+mc0YtsPQIpKCBJOYt05bgpX5aPQ3s2lviYw3bvP0TrclYs/rx4wKVgW" + + "2GYLzPh0OVMBduCbzW1E58ieBsgRyQ7+2MTl9Nj+nznjCAfLSvrVEcwxVUQA" + + "ofcEbiECEJss2JNQq8erwgo8dP3atwQ1KeqMc8acICcOrI2rNxwVOLzPuCsl" + + "l8gwZOoxLZXuKMQbQu4as1HNS309dfWIWppvc3K4nDWg51HUCPbsIo3wm3rR" + + "igc/W3bf4Ppg0pLAS5c1s0Xau43u9GmIjGiDqYaasfcXnCKy2LNuUpbhoOC1" + + "o/wMC9gT45aJQ5vsVGe5XvfhLV7Y815EdI756s9PIEOnG8HbAtCAjOIVpQfP" + + "eF8+cnZyGGdsbmu7lYzg3whCpZ/L2RrTI86nEn5eePs4m2hDV0Oi9r6e2CIf" + + "nGUa0TB9jf1OMhOSBD+h4jx7b6uT+XLmG8qUxvkoItMDZLrJ0f8czO5MyOZa" + + "nEJoG42Fy2p7zD/qO72OUQISNmt8C1rQFsg9dBDib4DMu69vBsVrIV028sal" + + "+tq1UH3vFMbEYyVfPH3WDgxyHwUQK2qrz3WBdD/BMyuAV4DPI3SPTweROh8n" + + "yWJN1ppY9qybmTyHFCs6TRjPB9cVcdKSc0qYxgzblJiXXb3s9ANOb89aA3Ah" + + "anWnAhcEggLZN2yFCtrRuvJXvDQhj8qmye9UkjB2fEpWXV7H0natE3hSoB+C" + + "2krt3eBV0xJ1tLEco7T4zsbQQJRmeu/essOsfwpRfE5ZPoIeThf+UmWTsfsw" + + "r4fxeePMTy6iCnkF5/ro8k5WKnOsaV+HWy/ulwW2r/DMT3aDBWfHX5Hk8DpU" + + "+PlQhbyGTSTIJ/OFmbcWjMPt469o7+KrrF9IBrzJ42KzMw6xtKwtVb0232AM" + + "pIwnLzCHIiNO2qDBZAIDdF68+GU3RsEkHfR6d5myZVxnH4mhSCFFtHxgqTOz" + + "Ouo/uvgu72miZ0OFAy1zcMtfGMS3Md54MJkhSZq4ZgUo/EyJCeEDLGn8pMF1" + + "jX1WsUj96qMRyc+p2KnKs6ZL95BVa76SdIFz6ts6uoIem3drTXYJHNbw29OW" + + "Y0am+FmXTWFZFnin8Qu5Xct5l7FYIGA9VLOHL9Vtp+SXomcFEZpjMaxvtf4R" + + "xoAI2Bc9Ka+MNiz35O0JXhI9/t5uOdiN6ZOJlfpEWOK7ou5lDkZuDcrHvLvQ" + + "PocP2Yemd36xEgjFssR/tFITlhRBXHDeHwpvmXM4iiwD1wOGMqybXx/1g1m1" + + "0UBbKqDsgSLQC7c0TaRFJjj71T74PBMiapiQgijv9WINfmTgxNUukbK3Kqp/" + + "G3BmThoIDCB8WD1kxXBpaG62dSsih7yhPQJVEV3Y0tdkdChOk+Y3Wf8crV/Q" + + "P08pQH7H9yCi04S5fSJtIDtYARWhr1yl8EQMnu2X8J6r/DWcDmXUK4Bv1vqe" + + "tcnT5EAYFPeOMz21nonM3kJgUMNsxCQjKaEMEcUu8ZRnGUAFdG4lULPJn5NQ" + + "LTvWg8Y3GrHRLjpnd9k+8gWWzRIbBiwCwEbClMZffRd6kcA5ZoOhVngdyvvj" + + "BhkgadB5jC+ZRzExHxoEhzPJx3mxIVTqLuw7QxHz9OTcysvY/cGKCvmgzgk/" + + "TjTJsqcEAAAAAAAAAAAAAAAAAAAAAAAAMD0wITAJBgUrDgMCGgUABBQWfGA6" + + "lI+TXQiuXaa1V+LlHodhXAQUAwMIAAUvBYY+a7sXNlQeVEPAGkMCAgQAAAA="); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/LoggingDatagramTransport.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/LoggingDatagramTransport.java new file mode 100644 index 000000000..5ffa95726 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/LoggingDatagramTransport.java @@ -0,0 +1,92 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; + +import com.fr.third.org.bouncycastle.crypto.tls.DatagramTransport; +import com.fr.third.org.bouncycastle.util.Strings; + +public class LoggingDatagramTransport + implements DatagramTransport +{ + + private static final String HEX_CHARS = "0123456789ABCDEF"; + + private final DatagramTransport transport; + private final PrintStream output; + private final long launchTimestamp; + + public LoggingDatagramTransport(DatagramTransport transport, PrintStream output) + { + this.transport = transport; + this.output = output; + this.launchTimestamp = System.currentTimeMillis(); + } + + public int getReceiveLimit() + throws IOException + { + return transport.getReceiveLimit(); + } + + public int getSendLimit() + throws IOException + { + return transport.getSendLimit(); + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + int length = transport.receive(buf, off, len, waitMillis); + if (length >= 0) + { + dumpDatagram("Received", buf, off, length); + } + return length; + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + dumpDatagram("Sending", buf, off, len); + transport.send(buf, off, len); + } + + public void close() + throws IOException + { + } + + private void dumpDatagram(String verb, byte[] buf, int off, int len) + throws IOException + { + long timestamp = System.currentTimeMillis() - launchTimestamp; + StringBuffer sb = new StringBuffer("(+" + timestamp + "ms) " + verb + " " + len + " byte datagram:"); + for (int pos = 0; pos < len; ++pos) + { + if (pos % 16 == 0) + { + sb.append(Strings.lineSeparator()); + sb.append(" "); + } + else if (pos % 16 == 8) + { + sb.append('-'); + } + else + { + sb.append(' '); + } + int val = buf[off + pos] & 0xFF; + sb.append(HEX_CHARS.charAt(val >> 4)); + sb.append(HEX_CHARS.charAt(val & 0xF)); + } + dump(sb.toString()); + } + + private synchronized void dump(String s) + { + output.println(s); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockDTLSClient.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockDTLSClient.java new file mode 100644 index 000000000..54e229255 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockDTLSClient.java @@ -0,0 +1,157 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.Hashtable; + +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.crypto.tls.AlertDescription; +import com.fr.third.org.bouncycastle.crypto.tls.AlertLevel; +import com.fr.third.org.bouncycastle.crypto.tls.CertificateRequest; +import com.fr.third.org.bouncycastle.crypto.tls.ClientCertificateType; +import com.fr.third.org.bouncycastle.crypto.tls.DefaultTlsClient; +import com.fr.third.org.bouncycastle.crypto.tls.MaxFragmentLength; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.SignatureAlgorithm; +import com.fr.third.org.bouncycastle.crypto.tls.TlsAuthentication; +import com.fr.third.org.bouncycastle.crypto.tls.TlsCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsExtensionsUtils; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSession; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +public class MockDTLSClient + extends DefaultTlsClient +{ + protected TlsSession session; + + public MockDTLSClient(TlsSession session) + { + this.session = session; + } + + public TlsSession getSessionToResume() + { + return this.session; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("DTLS client raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println(message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("DTLS client received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + + public ProtocolVersion getClientVersion() + { + return ProtocolVersion.DTLSv12; + } + + public ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.DTLSv10; + } + +// public int[] getCipherSuites() +// { +// return Arrays.concatenate(super.getCipherSuites(), +// new int[] +// { +// CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +// }); +// } + + public Hashtable getClientExtensions() throws IOException + { + Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); + TlsExtensionsUtils.addEncryptThenMACExtension(clientExtensions); + { + /* + * NOTE: If you are copying test code, do not blindly set these extensions in your own client. + */ + TlsExtensionsUtils.addMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9); + TlsExtensionsUtils.addPaddingExtension(clientExtensions, context.getSecureRandom().nextInt(16)); + TlsExtensionsUtils.addTruncatedHMacExtension(clientExtensions); + } + return clientExtensions; + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + System.out.println("Negotiated " + serverVersion); + } + + public TlsAuthentication getAuthentication() + throws IOException + { + return new TlsAuthentication() + { + public void notifyServerCertificate(com.fr.third.org.bouncycastle.crypto.tls.Certificate serverCertificate) + throws IOException + { + Certificate[] chain = serverCertificate.getCertificateList(); + System.out.println("DTLS client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = chain[i]; + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) + throws IOException + { + short[] certificateTypes = certificateRequest.getCertificateTypes(); + if (certificateTypes == null || !Arrays.contains(certificateTypes, ClientCertificateType.rsa_sign)) + { + return null; + } + + return TlsTestUtils.loadSignerCredentials(context, certificateRequest.getSupportedSignatureAlgorithms(), + SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem"); + } + }; + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + TlsSession newSession = context.getResumableSession(); + if (newSession != null) + { + byte[] newSessionID = newSession.getSessionID(); + String hex = Hex.toHexString(newSessionID); + + if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID)) + { + System.out.println("Resumed session: " + hex); + } + else + { + System.out.println("Established session: " + hex); + } + + this.session = newSession; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockDTLSServer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockDTLSServer.java new file mode 100644 index 000000000..3f2157907 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockDTLSServer.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.crypto.tls.AlertDescription; +import com.fr.third.org.bouncycastle.crypto.tls.AlertLevel; +import com.fr.third.org.bouncycastle.crypto.tls.CertificateRequest; +import com.fr.third.org.bouncycastle.crypto.tls.CipherSuite; +import com.fr.third.org.bouncycastle.crypto.tls.ClientCertificateType; +import com.fr.third.org.bouncycastle.crypto.tls.DefaultTlsServer; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.SignatureAlgorithm; +import com.fr.third.org.bouncycastle.crypto.tls.TlsEncryptionCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSignerCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsUtils; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class MockDTLSServer + extends DefaultTlsServer +{ + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("DTLS server raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println(message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("DTLS server received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + + protected int[] getCipherSuites() + { + return Arrays.concatenate(super.getCipherSuites(), + new int[] + { + CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + }); + } + + public CertificateRequest getCertificateRequest() throws IOException + { + short[] certificateTypes = new short[]{ ClientCertificateType.rsa_sign, + ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign }; + + Vector serverSigAlgs = null; + if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(serverVersion)) + { + serverSigAlgs = TlsUtils.getDefaultSupportedSignatureAlgorithms(); + } + + Vector certificateAuthorities = new Vector(); + certificateAuthorities.addElement(TlsTestUtils.loadCertificateResource("x509-ca.pem").getSubject()); + + return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities); + } + + public void notifyClientCertificate(com.fr.third.org.bouncycastle.crypto.tls.Certificate clientCertificate) + throws IOException + { + Certificate[] chain = clientCertificate.getCertificateList(); + System.out.println("DTLS server received client certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = chain[i]; + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + entry.getSubject() + + ")"); + } + } + + protected ProtocolVersion getMaximumVersion() + { + return ProtocolVersion.DTLSv12; + } + + protected ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.DTLSv10; + } + + protected TlsEncryptionCredentials getRSAEncryptionCredentials() + throws IOException + { + return TlsTestUtils.loadEncryptionCredentials(context, new String[]{"x509-server.pem", "x509-ca.pem"}, + "x509-server-key.pem"); + } + + protected TlsSignerCredentials getRSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, supportedSignatureAlgorithms, SignatureAlgorithm.rsa, + "x509-server.pem", "x509-server-key.pem"); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockDatagramAssociation.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockDatagramAssociation.java new file mode 100644 index 000000000..8eb339d1d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockDatagramAssociation.java @@ -0,0 +1,110 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.net.DatagramPacket; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.crypto.tls.DatagramTransport; + +public class MockDatagramAssociation +{ + private int mtu; + private MockDatagramTransport client, server; + + public MockDatagramAssociation(int mtu) + { + this.mtu = mtu; + + Vector clientQueue = new Vector(); + Vector serverQueue = new Vector(); + + this.client = new MockDatagramTransport(clientQueue, serverQueue); + this.server = new MockDatagramTransport(serverQueue, clientQueue); + } + + public DatagramTransport getClient() + { + return client; + } + + public DatagramTransport getServer() + { + return server; + } + + private class MockDatagramTransport + implements DatagramTransport + { + private Vector receiveQueue, sendQueue; + + MockDatagramTransport(Vector receiveQueue, Vector sendQueue) + { + this.receiveQueue = receiveQueue; + this.sendQueue = sendQueue; + } + + public int getReceiveLimit() + throws IOException + { + return mtu; + } + + public int getSendLimit() + throws IOException + { + return mtu; + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + synchronized (receiveQueue) + { + if (receiveQueue.isEmpty()) + { + try + { + receiveQueue.wait(waitMillis); + } + catch (InterruptedException e) + { + // TODO Keep waiting until full wait expired? + } + if (receiveQueue.isEmpty()) + { + return -1; + } + } + DatagramPacket packet = (DatagramPacket)receiveQueue.remove(0); + int copyLength = Math.min(len, packet.getLength()); + System.arraycopy(packet.getData(), packet.getOffset(), buf, off, copyLength); + return copyLength; + } + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + if (len > mtu) + { + // TODO Simulate rejection? + } + + byte[] copy = new byte[len]; + System.arraycopy(buf, off, copy, 0, len); + DatagramPacket packet = new DatagramPacket(copy, len); + + synchronized (sendQueue) + { + sendQueue.addElement(packet); + sendQueue.notify(); + } + } + + public void close() + throws IOException + { + // TODO? + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockPSKTlsClient.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockPSKTlsClient.java new file mode 100644 index 000000000..da32a9358 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockPSKTlsClient.java @@ -0,0 +1,135 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.Hashtable; + +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.crypto.tls.AlertDescription; +import com.fr.third.org.bouncycastle.crypto.tls.AlertLevel; +import com.fr.third.org.bouncycastle.crypto.tls.BasicTlsPSKIdentity; +import com.fr.third.org.bouncycastle.crypto.tls.CipherSuite; +import com.fr.third.org.bouncycastle.crypto.tls.PSKTlsClient; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.ServerOnlyTlsAuthentication; +import com.fr.third.org.bouncycastle.crypto.tls.TlsAuthentication; +import com.fr.third.org.bouncycastle.crypto.tls.TlsExtensionsUtils; +import com.fr.third.org.bouncycastle.crypto.tls.TlsPSKIdentity; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSession; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +class MockPSKTlsClient + extends PSKTlsClient +{ + TlsSession session; + + MockPSKTlsClient(TlsSession session) + { + this(session, new BasicTlsPSKIdentity("client", Strings.toUTF8ByteArray("TLS_TEST_PSK"))); + } + + MockPSKTlsClient(TlsSession session, TlsPSKIdentity pskIdentity) + { + super(pskIdentity); + + this.session = session; + } + + public TlsSession getSessionToResume() + { + return this.session; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-PSK client raised alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-PSK client received alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + TlsSession newSession = context.getResumableSession(); + if (newSession != null) + { + byte[] newSessionID = newSession.getSessionID(); + String hex = Hex.toHexString(newSessionID); + + if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID)) + { + System.out.println("Resumed session: " + hex); + } + else + { + System.out.println("Established session: " + hex); + } + + this.session = newSession; + } + } + + public int[] getCipherSuites() + { + return new int[]{ CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, + CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, + CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA }; + } + + public ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.TLSv12; + } + + public Hashtable getClientExtensions() throws IOException + { + Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); + TlsExtensionsUtils.addEncryptThenMACExtension(clientExtensions); + return clientExtensions; + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + System.out.println("TLS-PSK client negotiated " + serverVersion); + } + + public TlsAuthentication getAuthentication() throws IOException + { + return new ServerOnlyTlsAuthentication() + { + public void notifyServerCertificate(com.fr.third.org.bouncycastle.crypto.tls.Certificate serverCertificate) + throws IOException + { + Certificate[] chain = serverCertificate.getCertificateList(); + System.out.println("TLS-PSK client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = chain[i]; + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + }; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockPSKTlsServer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockPSKTlsServer.java new file mode 100644 index 000000000..101a2c899 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockPSKTlsServer.java @@ -0,0 +1,110 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; + +import com.fr.third.org.bouncycastle.crypto.tls.AlertDescription; +import com.fr.third.org.bouncycastle.crypto.tls.AlertLevel; +import com.fr.third.org.bouncycastle.crypto.tls.CipherSuite; +import com.fr.third.org.bouncycastle.crypto.tls.PSKTlsServer; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.TlsEncryptionCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsPSKIdentityManager; +import com.fr.third.org.bouncycastle.util.Strings; + +class MockPSKTlsServer + extends PSKTlsServer +{ + MockPSKTlsServer() + { + super(new MyIdentityManager()); + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-PSK server raised alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-PSK server received alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + byte[] pskIdentity = context.getSecurityParameters().getPSKIdentity(); + if (pskIdentity != null) + { + String name = Strings.fromUTF8ByteArray(pskIdentity); + System.out.println("TLS-PSK server completed handshake for PSK identity: " + name); + } + } + + protected int[] getCipherSuites() + { + return new int[]{ CipherSuite.TLS_ECDHE_PSK_WITH_AES_256_CBC_SHA384, + CipherSuite.TLS_DHE_PSK_WITH_AES_256_CBC_SHA384, CipherSuite.TLS_RSA_PSK_WITH_AES_256_CBC_SHA384, + CipherSuite.TLS_PSK_WITH_AES_256_CBC_SHA }; + } + + protected ProtocolVersion getMaximumVersion() + { + return ProtocolVersion.TLSv12; + } + + protected ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.TLSv12; + } + + public ProtocolVersion getServerVersion() throws IOException + { + ProtocolVersion serverVersion = super.getServerVersion(); + + System.out.println("TLS-PSK server negotiated " + serverVersion); + + return serverVersion; + } + + protected TlsEncryptionCredentials getRSAEncryptionCredentials() throws IOException + { + return TlsTestUtils.loadEncryptionCredentials(context, new String[]{ "x509-server.pem", "x509-ca.pem" }, + "x509-server-key.pem"); + } + + static class MyIdentityManager + implements TlsPSKIdentityManager + { + public byte[] getHint() + { + return Strings.toUTF8ByteArray("hint"); + } + + public byte[] getPSK(byte[] identity) + { + if (identity != null) + { + String name = Strings.fromUTF8ByteArray(identity); + if (name.equals("client")) + { + return Strings.toUTF8ByteArray("TLS_TEST_PSK"); + } + } + return null; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockSRPTlsClient.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockSRPTlsClient.java new file mode 100644 index 000000000..2fc2155c4 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockSRPTlsClient.java @@ -0,0 +1,120 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.Hashtable; + +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.crypto.tls.AlertDescription; +import com.fr.third.org.bouncycastle.crypto.tls.AlertLevel; +import com.fr.third.org.bouncycastle.crypto.tls.CipherSuite; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.SRPTlsClient; +import com.fr.third.org.bouncycastle.crypto.tls.ServerOnlyTlsAuthentication; +import com.fr.third.org.bouncycastle.crypto.tls.TlsAuthentication; +import com.fr.third.org.bouncycastle.crypto.tls.TlsExtensionsUtils; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSession; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +class MockSRPTlsClient + extends SRPTlsClient +{ + TlsSession session; + + MockSRPTlsClient(TlsSession session, byte[] identity, byte[] password) + { + super(identity, password); + + this.session = session; + } + + public TlsSession getSessionToResume() + { + return this.session; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-SRP client raised alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-SRP client received alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + TlsSession newSession = context.getResumableSession(); + if (newSession != null) + { + byte[] newSessionID = newSession.getSessionID(); + String hex = Hex.toHexString(newSessionID); + + if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID)) + { + System.out.println("Resumed session: " + hex); + } + else + { + System.out.println("Established session: " + hex); + } + + this.session = newSession; + } + } + + public ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.TLSv12; + } + + public Hashtable getClientExtensions() throws IOException + { + Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); + TlsExtensionsUtils.addEncryptThenMACExtension(clientExtensions); + return clientExtensions; + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + System.out.println("TLS-SRP client negotiated " + serverVersion); + } + + public TlsAuthentication getAuthentication() throws IOException + { + return new ServerOnlyTlsAuthentication() + { + public void notifyServerCertificate(com.fr.third.org.bouncycastle.crypto.tls.Certificate serverCertificate) + throws IOException + { + Certificate[] chain = serverCertificate.getCertificateList(); + System.out.println("TLS-SRP client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = chain[i]; + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + }; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockSRPTlsServer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockSRPTlsServer.java new file mode 100644 index 000000000..ae395f395 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockSRPTlsServer.java @@ -0,0 +1,124 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.crypto.agreement.srp.SRP6StandardGroups; +import com.fr.third.org.bouncycastle.crypto.agreement.srp.SRP6VerifierGenerator; +import com.fr.third.org.bouncycastle.crypto.params.SRP6GroupParameters; +import com.fr.third.org.bouncycastle.crypto.tls.AlertDescription; +import com.fr.third.org.bouncycastle.crypto.tls.AlertLevel; +import com.fr.third.org.bouncycastle.crypto.tls.HashAlgorithm; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.SRPTlsServer; +import com.fr.third.org.bouncycastle.crypto.tls.SignatureAlgorithm; +import com.fr.third.org.bouncycastle.crypto.tls.SimulatedTlsSRPIdentityManager; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSRPIdentityManager; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSRPLoginParameters; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSignerCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsUtils; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; + +class MockSRPTlsServer + extends SRPTlsServer +{ + static final SRP6GroupParameters TEST_GROUP = SRP6StandardGroups.rfc5054_1024; + static final byte[] TEST_IDENTITY = Strings.toUTF8ByteArray("client"); + static final byte[] TEST_PASSWORD = Strings.toUTF8ByteArray("password"); + static final byte[] TEST_SALT = Strings.toUTF8ByteArray("salt"); + static final byte[] TEST_SEED_KEY = Strings.toUTF8ByteArray("seed_key"); + + MockSRPTlsServer() + { + super(new MyIdentityManager()); + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-SRP server raised alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS-SRP server received alert: " + AlertLevel.getText(alertLevel) + ", " + + AlertDescription.getText(alertDescription)); + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + byte[] srpIdentity = context.getSecurityParameters().getSRPIdentity(); + if (srpIdentity != null) + { + String name = Strings.fromUTF8ByteArray(srpIdentity); + System.out.println("TLS-SRP server completed handshake for SRP identity: " + name); + } + } + + protected ProtocolVersion getMaximumVersion() + { + return ProtocolVersion.TLSv12; + } + + protected ProtocolVersion getMinimumVersion() + { + return ProtocolVersion.TLSv12; + } + + public ProtocolVersion getServerVersion() throws IOException + { + ProtocolVersion serverVersion = super.getServerVersion(); + + System.out.println("TLS-SRP server negotiated " + serverVersion); + + return serverVersion; + } + + protected TlsSignerCredentials getDSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, supportedSignatureAlgorithms, SignatureAlgorithm.dsa, + "x509-server-dsa.pem", "x509-server-key-dsa.pem"); + } + + protected TlsSignerCredentials getRSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, supportedSignatureAlgorithms, SignatureAlgorithm.rsa, + "x509-server.pem", "x509-server-key.pem"); + } + + static class MyIdentityManager + implements TlsSRPIdentityManager + { + protected SimulatedTlsSRPIdentityManager unknownIdentityManager = SimulatedTlsSRPIdentityManager.getRFC5054Default( + TEST_GROUP, TEST_SEED_KEY); + + public TlsSRPLoginParameters getLoginParameters(byte[] identity) + { + if (Arrays.areEqual(TEST_IDENTITY, identity)) + { + SRP6VerifierGenerator verifierGenerator = new SRP6VerifierGenerator(); + verifierGenerator.init(TEST_GROUP, TlsUtils.createHash(HashAlgorithm.sha1)); + + BigInteger verifier = verifierGenerator.generateVerifier(TEST_SALT, identity, TEST_PASSWORD); + + return new TlsSRPLoginParameters(TEST_GROUP, verifier, TEST_SALT); + } + + return unknownIdentityManager.getLoginParameters(identity); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockTlsClient.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockTlsClient.java new file mode 100644 index 000000000..26a6dd56d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockTlsClient.java @@ -0,0 +1,148 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.Hashtable; + +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.crypto.tls.AlertDescription; +import com.fr.third.org.bouncycastle.crypto.tls.AlertLevel; +import com.fr.third.org.bouncycastle.crypto.tls.CertificateRequest; +import com.fr.third.org.bouncycastle.crypto.tls.CipherSuite; +import com.fr.third.org.bouncycastle.crypto.tls.ClientCertificateType; +import com.fr.third.org.bouncycastle.crypto.tls.DefaultTlsClient; +import com.fr.third.org.bouncycastle.crypto.tls.MaxFragmentLength; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.SignatureAlgorithm; +import com.fr.third.org.bouncycastle.crypto.tls.TlsAuthentication; +import com.fr.third.org.bouncycastle.crypto.tls.TlsCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsExtensionsUtils; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSession; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +class MockTlsClient + extends DefaultTlsClient +{ + TlsSession session; + + MockTlsClient(TlsSession session) + { + this.session = session; + } + + public TlsSession getSessionToResume() + { + return this.session; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS client raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS client received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + +// public int[] getCipherSuites() +// { +// return Arrays.concatenate(super.getCipherSuites(), +// new int[] +// { +// CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, +// }); +// } + + public Hashtable getClientExtensions() throws IOException + { + Hashtable clientExtensions = TlsExtensionsUtils.ensureExtensionsInitialised(super.getClientExtensions()); + TlsExtensionsUtils.addEncryptThenMACExtension(clientExtensions); + { + /* + * NOTE: If you are copying test code, do not blindly set these extensions in your own client. + */ + TlsExtensionsUtils.addMaxFragmentLengthExtension(clientExtensions, MaxFragmentLength.pow2_9); + TlsExtensionsUtils.addPaddingExtension(clientExtensions, context.getSecureRandom().nextInt(16)); + TlsExtensionsUtils.addTruncatedHMacExtension(clientExtensions); + } + return clientExtensions; + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + System.out.println("TLS client negotiated " + serverVersion); + } + + public TlsAuthentication getAuthentication() + throws IOException + { + return new TlsAuthentication() + { + public void notifyServerCertificate(com.fr.third.org.bouncycastle.crypto.tls.Certificate serverCertificate) + throws IOException + { + Certificate[] chain = serverCertificate.getCertificateList(); + System.out.println("TLS client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = chain[i]; + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) + throws IOException + { + short[] certificateTypes = certificateRequest.getCertificateTypes(); + if (certificateTypes == null || !Arrays.contains(certificateTypes, ClientCertificateType.rsa_sign)) + { + return null; + } + + return TlsTestUtils.loadSignerCredentials(context, certificateRequest.getSupportedSignatureAlgorithms(), + SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem"); + } + }; + } + + public void notifyHandshakeComplete() throws IOException + { + super.notifyHandshakeComplete(); + + TlsSession newSession = context.getResumableSession(); + if (newSession != null) + { + byte[] newSessionID = newSession.getSessionID(); + String hex = Hex.toHexString(newSessionID); + + if (this.session != null && Arrays.areEqual(this.session.getSessionID(), newSessionID)) + { + System.out.println("Resumed session: " + hex); + } + else + { + System.out.println("Established session: " + hex); + } + + this.session = newSession; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockTlsServer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockTlsServer.java new file mode 100644 index 000000000..c17855681 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/MockTlsServer.java @@ -0,0 +1,112 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.crypto.tls.AlertDescription; +import com.fr.third.org.bouncycastle.crypto.tls.AlertLevel; +import com.fr.third.org.bouncycastle.crypto.tls.CertificateRequest; +import com.fr.third.org.bouncycastle.crypto.tls.CipherSuite; +import com.fr.third.org.bouncycastle.crypto.tls.ClientCertificateType; +import com.fr.third.org.bouncycastle.crypto.tls.DefaultTlsServer; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.SignatureAlgorithm; +import com.fr.third.org.bouncycastle.crypto.tls.TlsEncryptionCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSignerCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsUtils; +import com.fr.third.org.bouncycastle.util.Arrays; + +class MockTlsServer + extends DefaultTlsServer +{ + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS server raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS server received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + + protected int[] getCipherSuites() + { + return Arrays.concatenate(super.getCipherSuites(), + new int[] + { + CipherSuite.DRAFT_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, + }); + } + + protected ProtocolVersion getMaximumVersion() + { + return ProtocolVersion.TLSv12; + } + + public ProtocolVersion getServerVersion() throws IOException + { + ProtocolVersion serverVersion = super.getServerVersion(); + + System.out.println("TLS server negotiated " + serverVersion); + + return serverVersion; + } + + public CertificateRequest getCertificateRequest() throws IOException + { + short[] certificateTypes = new short[]{ ClientCertificateType.rsa_sign, + ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign }; + + Vector serverSigAlgs = null; + if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(serverVersion)) + { + serverSigAlgs = TlsUtils.getDefaultSupportedSignatureAlgorithms(); + } + + Vector certificateAuthorities = new Vector(); + certificateAuthorities.addElement(TlsTestUtils.loadCertificateResource("x509-ca.pem").getSubject()); + + return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities); + } + + public void notifyClientCertificate(com.fr.third.org.bouncycastle.crypto.tls.Certificate clientCertificate) + throws IOException + { + Certificate[] chain = clientCertificate.getCertificateList(); + System.out.println("TLS server received client certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = chain[i]; + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + + protected TlsEncryptionCredentials getRSAEncryptionCredentials() + throws IOException + { + return TlsTestUtils.loadEncryptionCredentials(context, new String[]{"x509-server.pem", "x509-ca.pem"}, + "x509-server-key.pem"); + } + + protected TlsSignerCredentials getRSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, supportedSignatureAlgorithms, SignatureAlgorithm.rsa, + "x509-server.pem", "x509-server-key.pem"); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/NetworkInputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/NetworkInputStream.java new file mode 100644 index 000000000..b8186f2f3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/NetworkInputStream.java @@ -0,0 +1,60 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.FilterInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * Tracks and enforces close() calls, without closing the underlying InputStream + */ +class NetworkInputStream extends FilterInputStream +{ + boolean closed = false; + + public NetworkInputStream(InputStream input) + { + super(input); + } + + synchronized boolean isClosed() + { + return closed; + } + + public int available() throws IOException + { + checkNotClosed(); + return in.available(); + } + + public synchronized void close() throws IOException + { + closed = true; + } + + public int read() throws IOException + { + checkNotClosed(); + return in.read(); + } + + public int read(byte[] b) throws IOException + { + checkNotClosed(); + return in.read(b); + } + + public int read(byte[] b, int off, int len) throws IOException + { + checkNotClosed(); + return in.read(b, off, len); + } + + protected synchronized void checkNotClosed() throws IOException + { + if (closed) + { + throw new IOException("NetworkInputStream closed"); + } + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/NetworkOutputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/NetworkOutputStream.java new file mode 100644 index 000000000..a560d560e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/NetworkOutputStream.java @@ -0,0 +1,54 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.FilterOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +/** + * Tracks and enforces close() calls, without closing the underlying OutputStream + */ +class NetworkOutputStream extends FilterOutputStream +{ + boolean closed = false; + + public NetworkOutputStream(OutputStream output) + { + super(output); + } + + synchronized boolean isClosed() + { + return closed; + } + + public synchronized void close() throws IOException + { + closed = true; + } + + public void write(int b) throws IOException + { + checkNotClosed(); + out.write(b); + } + + public void write(byte[] b) throws IOException + { + checkNotClosed(); + out.write(b); + } + + public void write(byte[] b, int off, int len) throws IOException + { + checkNotClosed(); + out.write(b, off, len); + } + + protected synchronized void checkNotClosed() throws IOException + { + if (closed) + { + throw new IOException("NetworkOutputStream closed"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/PSKTlsClientTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/PSKTlsClientTest.java new file mode 100644 index 000000000..d104377df --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/PSKTlsClientTest.java @@ -0,0 +1,87 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.tls.BasicTlsPSKIdentity; +import com.fr.third.org.bouncycastle.crypto.tls.TlsClient; +import com.fr.third.org.bouncycastle.crypto.tls.TlsClientProtocol; +import com.fr.third.org.bouncycastle.util.Strings; + +/** + * A simple test designed to conduct a TLS handshake with an external TLS server. + *

+ * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external TLS server. + *

+ * In both cases, extra options are required to enable PSK ciphersuites and configure identities/keys. + *

+ */ +public class PSKTlsClientTest +{ + private static final SecureRandom secureRandom = new SecureRandom(); + + public static void main(String[] args) throws Exception + { + InetAddress address = InetAddress.getLocalHost(); + int port = 5556; + + long time1 = System.currentTimeMillis(); + + /* + * Note: This is the default PSK identity for 'openssl s_server' testing, the server must be + * started with "-psk 6161616161" to make the keys match, and possibly the "-psk_hint" + * option should be present. + */ +// String psk_identity = "Client_identity"; +// byte[] psk = new byte[]{ 0x61, 0x61, 0x61, 0x61, 0x61 }; + + // These correspond to the configuration of MockPSKTlsServer + String psk_identity = "client"; + byte[] psk = Strings.toUTF8ByteArray("TLS_TEST_PSK"); + + BasicTlsPSKIdentity pskIdentity = new BasicTlsPSKIdentity(psk_identity, psk); + + MockPSKTlsClient client = new MockPSKTlsClient(null, pskIdentity); + TlsClientProtocol protocol = openTlsConnection(address, port, client); + protocol.close(); + + long time2 = System.currentTimeMillis(); + System.out.println("Elapsed 1: " + (time2 - time1) + "ms"); + + client = new MockPSKTlsClient(client.getSessionToResume(), pskIdentity); + protocol = openTlsConnection(address, port, client); + + long time3 = System.currentTimeMillis(); + System.out.println("Elapsed 2: " + (time3 - time2) + "ms"); + + OutputStream output = protocol.getOutputStream(); + output.write("GET / HTTP/1.1\r\n\r\n".getBytes("UTF-8")); + output.flush(); + + InputStream input = protocol.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(input)); + + String line; + while ((line = reader.readLine()) != null) + { + System.out.println(">>> " + line); + } + + protocol.close(); + } + + static TlsClientProtocol openTlsConnection(InetAddress address, int port, TlsClient client) throws IOException + { + Socket s = new Socket(address, port); + TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream(), secureRandom); + protocol.connect(client); + return protocol; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/PSKTlsServerTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/PSKTlsServerTest.java new file mode 100644 index 000000000..a29b57ff9 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/PSKTlsServerTest.java @@ -0,0 +1,89 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.tls.TlsServerProtocol; +import com.fr.third.org.bouncycastle.util.io.Streams; +import com.fr.third.org.bouncycastle.util.io.TeeOutputStream; + +/** + * A simple test designed to conduct a TLS handshake with an external TLS client. + *

+ * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external TLS client. + *

+ */ +public class PSKTlsServerTest +{ + private static final SecureRandom secureRandom = new SecureRandom(); + + public static void main(String[] args) + throws Exception + { + InetAddress address = InetAddress.getLocalHost(); + int port = 5556; + + ServerSocket ss = new ServerSocket(port, 16, address); + try + { + while (true) + { + Socket s = ss.accept(); + System.out.println("--------------------------------------------------------------------------------"); + System.out.println("Accepted " + s); + ServerThread t = new ServerThread(s); + t.start(); + } + } + finally + { + ss.close(); + } + } + + static class ServerThread + extends Thread + { + private final Socket s; + + ServerThread(Socket s) + { + this.s = s; + } + + public void run() + { + try + { + MockPSKTlsServer server = new MockPSKTlsServer(); + TlsServerProtocol serverProtocol = new TlsServerProtocol(s.getInputStream(), s.getOutputStream(), secureRandom); + serverProtocol.accept(server); + OutputStream log = new TeeOutputStream(serverProtocol.getOutputStream(), System.out); + Streams.pipeAll(serverProtocol.getInputStream(), log); + serverProtocol.close(); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + finally + { + try + { + s.close(); + } + catch (IOException e) + { + } + finally + { + } + } + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsClientTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsClientTest.java new file mode 100644 index 000000000..81e0b098f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsClientTest.java @@ -0,0 +1,70 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.Socket; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.tls.TlsClient; +import com.fr.third.org.bouncycastle.crypto.tls.TlsClientProtocol; + +/** + * A simple test designed to conduct a TLS handshake with an external TLS server. + *

+ * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external TLS server. + *

+ */ +public class TlsClientTest +{ + private static final SecureRandom secureRandom = new SecureRandom(); + + public static void main(String[] args) + throws Exception + { + InetAddress address = InetAddress.getLocalHost(); + int port = 5556; + + long time1 = System.currentTimeMillis(); + + MockTlsClient client = new MockTlsClient(null); + TlsClientProtocol protocol = openTlsConnection(address, port, client); + protocol.close(); + + long time2 = System.currentTimeMillis(); + System.out.println("Elapsed 1: " + (time2 - time1) + "ms"); + + client = new MockTlsClient(client.getSessionToResume()); + protocol = openTlsConnection(address, port, client); + + long time3 = System.currentTimeMillis(); + System.out.println("Elapsed 2: " + (time3 - time2) + "ms"); + + OutputStream output = protocol.getOutputStream(); + output.write("GET / HTTP/1.1\r\n\r\n".getBytes("UTF-8")); + output.flush(); + + InputStream input = protocol.getInputStream(); + BufferedReader reader = new BufferedReader(new InputStreamReader(input)); + + String line; + while ((line = reader.readLine()) != null) + { + System.out.println(">>> " + line); + } + + protocol.close(); + } + + static TlsClientProtocol openTlsConnection(InetAddress address, int port, TlsClient client) throws IOException + { + Socket s = new Socket(address, port); + TlsClientProtocol protocol = new TlsClientProtocol(s.getInputStream(), s.getOutputStream(), secureRandom); + protocol.connect(client); + return protocol; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsServerTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsServerTest.java new file mode 100644 index 000000000..4a526eecc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsServerTest.java @@ -0,0 +1,89 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.OutputStream; +import java.net.InetAddress; +import java.net.ServerSocket; +import java.net.Socket; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.tls.TlsServerProtocol; +import com.fr.third.org.bouncycastle.util.io.Streams; +import com.fr.third.org.bouncycastle.util.io.TeeOutputStream; + +/** + * A simple test designed to conduct a TLS handshake with an external TLS client. + *

+ * Please refer to GnuTLSSetup.html or OpenSSLSetup.html (under 'docs'), and x509-*.pem files in + * this package (under 'src/test/resources') for help configuring an external TLS client. + *

+ */ +public class TlsServerTest +{ + private static final SecureRandom secureRandom = new SecureRandom(); + + public static void main(String[] args) + throws Exception + { + InetAddress address = InetAddress.getLocalHost(); + int port = 5556; + + ServerSocket ss = new ServerSocket(port, 16, address); + try + { + while (true) + { + Socket s = ss.accept(); + System.out.println("--------------------------------------------------------------------------------"); + System.out.println("Accepted " + s); + ServerThread t = new ServerThread(s); + t.start(); + } + } + finally + { + ss.close(); + } + } + + static class ServerThread + extends Thread + { + private final Socket s; + + ServerThread(Socket s) + { + this.s = s; + } + + public void run() + { + try + { + MockTlsServer server = new MockTlsServer(); + TlsServerProtocol serverProtocol = new TlsServerProtocol(s.getInputStream(), s.getOutputStream(), secureRandom); + serverProtocol.accept(server); + OutputStream log = new TeeOutputStream(serverProtocol.getOutputStream(), System.out); + Streams.pipeAll(serverProtocol.getInputStream(), log); + serverProtocol.close(); + } + catch (Exception e) + { + throw new RuntimeException(e); + } + finally + { + try + { + s.close(); + } + catch (IOException e) + { + } + finally + { + } + } + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestClientImpl.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestClientImpl.java new file mode 100644 index 000000000..3ea7c53a7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestClientImpl.java @@ -0,0 +1,270 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.Hashtable; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.crypto.tls.AlertDescription; +import com.fr.third.org.bouncycastle.crypto.tls.AlertLevel; +import com.fr.third.org.bouncycastle.crypto.tls.CertificateRequest; +import com.fr.third.org.bouncycastle.crypto.tls.ClientCertificateType; +import com.fr.third.org.bouncycastle.crypto.tls.ConnectionEnd; +import com.fr.third.org.bouncycastle.crypto.tls.DefaultTlsClient; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.SignatureAlgorithm; +import com.fr.third.org.bouncycastle.crypto.tls.SignatureAndHashAlgorithm; +import com.fr.third.org.bouncycastle.crypto.tls.TlsAuthentication; +import com.fr.third.org.bouncycastle.crypto.tls.TlsCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsFatalAlert; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSignerCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsUtils; +import com.fr.third.org.bouncycastle.util.Arrays; + +class TlsTestClientImpl + extends DefaultTlsClient +{ + protected final TlsTestConfig config; + + protected int firstFatalAlertConnectionEnd = -1; + protected short firstFatalAlertDescription = -1; + + TlsTestClientImpl(TlsTestConfig config) + { + this.config = config; + } + + int getFirstFatalAlertConnectionEnd() + { + return firstFatalAlertConnectionEnd; + } + + short getFirstFatalAlertDescription() + { + return firstFatalAlertDescription; + } + + public ProtocolVersion getClientVersion() + { + if (config.clientOfferVersion != null) + { + return config.clientOfferVersion; + } + + return super.getClientVersion(); + } + + public ProtocolVersion getMinimumVersion() + { + if (config.clientMinimumVersion != null) + { + return config.clientMinimumVersion; + } + + return super.getMinimumVersion(); + } + + public Hashtable getClientExtensions() throws IOException + { + Hashtable clientExtensions = super.getClientExtensions(); + if (clientExtensions != null && !config.clientSendSignatureAlgorithms) + { + clientExtensions.remove(TlsUtils.EXT_signature_algorithms); + this.supportedSignatureAlgorithms = null; + } + return clientExtensions; + } + + public boolean isFallback() + { + return config.clientFallback; + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1) + { + firstFatalAlertConnectionEnd = ConnectionEnd.client; + firstFatalAlertDescription = alertDescription; + } + + if (TlsTestConfig.DEBUG) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS client raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1) + { + firstFatalAlertConnectionEnd = ConnectionEnd.server; + firstFatalAlertDescription = alertDescription; + } + + if (TlsTestConfig.DEBUG) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS client received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + } + + public void notifyServerVersion(ProtocolVersion serverVersion) throws IOException + { + super.notifyServerVersion(serverVersion); + + if (TlsTestConfig.DEBUG) + { + System.out.println("TLS client negotiated " + serverVersion); + } + } + + public TlsAuthentication getAuthentication() + throws IOException + { + return new TlsAuthentication() + { + public void notifyServerCertificate(com.fr.third.org.bouncycastle.crypto.tls.Certificate serverCertificate) + throws IOException + { + boolean isEmpty = serverCertificate == null || serverCertificate.isEmpty(); + + Certificate[] chain = serverCertificate.getCertificateList(); + + // TODO Cache test resources? + if (isEmpty || !(chain[0].equals(TlsTestUtils.loadCertificateResource("x509-server.pem")) + || chain[0].equals(TlsTestUtils.loadCertificateResource("x509-server-dsa.pem")) + || chain[0].equals(TlsTestUtils.loadCertificateResource("x509-server-ecdsa.pem")))) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + if (TlsTestConfig.DEBUG) + { + System.out.println("TLS client received server certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = chain[i]; + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + } + + public TlsCredentials getClientCredentials(CertificateRequest certificateRequest) + throws IOException + { + if (config.serverCertReq == TlsTestConfig.SERVER_CERT_REQ_NONE) + { + throw new IllegalStateException(); + } + if (config.clientAuth == TlsTestConfig.CLIENT_AUTH_NONE) + { + return null; + } + + short[] certificateTypes = certificateRequest.getCertificateTypes(); + if (certificateTypes == null || !Arrays.contains(certificateTypes, ClientCertificateType.rsa_sign)) + { + return null; + } + + Vector supportedSigAlgs = certificateRequest.getSupportedSignatureAlgorithms(); + if (supportedSigAlgs != null && config.clientAuthSigAlg != null) + { + supportedSigAlgs = new Vector(1); + supportedSigAlgs.addElement(config.clientAuthSigAlg); + } + + final TlsSignerCredentials signerCredentials = TlsTestUtils.loadSignerCredentials(context, + supportedSigAlgs, SignatureAlgorithm.rsa, "x509-client.pem", "x509-client-key.pem"); + + if (config.clientAuth == TlsTestConfig.CLIENT_AUTH_VALID) + { + return signerCredentials; + } + + return new TlsSignerCredentials() + { + public byte[] generateCertificateSignature(byte[] hash) throws IOException + { + byte[] sig = signerCredentials.generateCertificateSignature(hash); + + if (config.clientAuth == TlsTestConfig.CLIENT_AUTH_INVALID_VERIFY) + { + sig = corruptBit(sig); + } + + return sig; + } + + public com.fr.third.org.bouncycastle.crypto.tls.Certificate getCertificate() + { + com.fr.third.org.bouncycastle.crypto.tls.Certificate cert = signerCredentials.getCertificate(); + + if (config.clientAuth == TlsTestConfig.CLIENT_AUTH_INVALID_CERT) + { + cert = corruptCertificate(cert); + } + + return cert; + } + + public SignatureAndHashAlgorithm getSignatureAndHashAlgorithm() + { + return signerCredentials.getSignatureAndHashAlgorithm(); + } + }; + } + }; + } + + protected com.fr.third.org.bouncycastle.crypto.tls.Certificate corruptCertificate(com.fr.third.org.bouncycastle.crypto.tls.Certificate cert) + { + Certificate[] certList = cert.getCertificateList(); + certList[0] = corruptCertificateSignature(certList[0]); + return new com.fr.third.org.bouncycastle.crypto.tls.Certificate(certList); + } + + protected Certificate corruptCertificateSignature(Certificate cert) + { + ASN1EncodableVector v = new ASN1EncodableVector(); + v.add(cert.getTBSCertificate()); + v.add(cert.getSignatureAlgorithm()); + v.add(corruptSignature(cert.getSignature())); + + return Certificate.getInstance(new DERSequence(v)); + } + + protected DERBitString corruptSignature(DERBitString bs) + { + return new DERBitString(corruptBit(bs.getOctets())); + } + + protected byte[] corruptBit(byte[] bs) + { + bs = Arrays.clone(bs); + + // Flip a random bit + int bit = context.getSecureRandom().nextInt(bs.length << 3); + bs[bit >>> 3] ^= (1 << (bit & 7)); + + return bs; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestClientProtocol.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestClientProtocol.java new file mode 100644 index 000000000..64f1eac41 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestClientProtocol.java @@ -0,0 +1,31 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.tls.DigitallySigned; +import com.fr.third.org.bouncycastle.crypto.tls.TlsClientProtocol; + +class TlsTestClientProtocol extends TlsClientProtocol +{ + protected final TlsTestConfig config; + + public TlsTestClientProtocol(InputStream input, OutputStream output, SecureRandom secureRandom, TlsTestConfig config) + { + super(input, output, secureRandom); + + this.config = config; + } + + protected void sendCertificateVerifyMessage(DigitallySigned certificateVerify) throws IOException + { + if (certificateVerify.getAlgorithm() != null && config.clientAuthSigAlgClaimed != null) + { + certificateVerify = new DigitallySigned(config.clientAuthSigAlgClaimed, certificateVerify.getSignature()); + } + + super.sendCertificateVerifyMessage(certificateVerify); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestConfig.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestConfig.java new file mode 100644 index 000000000..d813fd709 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestConfig.java @@ -0,0 +1,133 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.util.Vector; + +import com.fr.third.org.bouncycastle.crypto.tls.ConnectionEnd; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.SignatureAndHashAlgorithm; + +public class TlsTestConfig +{ + public static final boolean DEBUG = false; + + /** + * Client does not authenticate, ignores any certificate request + */ + public static final int CLIENT_AUTH_NONE = 0; + + /** + * Client will authenticate if it receives a certificate request + */ + public static final int CLIENT_AUTH_VALID = 1; + + /** + * Client will authenticate if it receives a certificate request, with an invalid certificate + */ + public static final int CLIENT_AUTH_INVALID_CERT = 2; + + /** + * Client will authenticate if it receives a certificate request, with an invalid CertificateVerify signature + */ + public static final int CLIENT_AUTH_INVALID_VERIFY = 3; + + /** + * Server will not request a client certificate + */ + public static final int SERVER_CERT_REQ_NONE = 0; + + /** + * Server will request a client certificate but receiving one is optional + */ + public static final int SERVER_CERT_REQ_OPTIONAL = 1; + + /** + * Server will request a client certificate and receiving one is mandatory + */ + public static final int SERVER_CERT_REQ_MANDATORY = 2; + + /** + * Configures the client authentication behaviour of the test client. Use CLIENT_AUTH_* constants. + */ + public int clientAuth = CLIENT_AUTH_VALID; + + /** + * If not null, and TLS 1.2 or higher is negotiated, selects a fixed signature/hash algorithm to + * be used for the CertificateVerify signature (if one is sent). + */ + public SignatureAndHashAlgorithm clientAuthSigAlg = null; + + /** + * If not null, and TLS 1.2 or higher is negotiated, selects a fixed signature/hash algorithm to + * be _claimed_ in the CertificateVerify (if one is sent), independently of what was actually used. + */ + public SignatureAndHashAlgorithm clientAuthSigAlgClaimed = null; + + /** + * Configures the minimum protocol version the client will accept. If null, uses the library's default. + */ + public ProtocolVersion clientMinimumVersion = null; + + /** + * Configures the protocol version the client will offer. If null, uses the library's default. + */ + public ProtocolVersion clientOfferVersion = null; + + /** + * Configures whether the client will indicate version fallback via TLS_FALLBACK_SCSV. + */ + public boolean clientFallback = false; + + /** + * Configures whether a (TLS 1.2+) client will send the signature_algorithms extension in ClientHello. + */ + public boolean clientSendSignatureAlgorithms = true; + + /** + * If not null, and TLS 1.2 or higher is negotiated, selects a fixed signature/hash algorithm to + * be used for the ServerKeyExchange signature (if one is sent). + */ + public SignatureAndHashAlgorithm serverAuthSigAlg = null; + + /** + * Configures whether the test server will send a certificate request. + */ + public int serverCertReq = SERVER_CERT_REQ_OPTIONAL; + + /** + * If TLS 1.2 or higher is negotiated, configures the set of supported signature algorithms in the + * CertificateRequest (if one is sent). If null, uses a default set. + */ + public Vector serverCertReqSigAlgs = null; + + /** + * Configures the maximum protocol version the server will accept. If null, uses the library's default. + */ + public ProtocolVersion serverMaximumVersion = null; + + /** + * Configures the minimum protocol version the server will accept. If null, uses the library's default. + */ + public ProtocolVersion serverMinimumVersion = null; + + /** + * Configures the connection end that a fatal alert is expected to be raised. Use ConnectionEnd.* constants. + */ + public int expectFatalAlertConnectionEnd = -1; + + /** + * Configures the type of fatal alert expected to be raised. Use AlertDescription.* constants. + */ + public short expectFatalAlertDescription = -1; + + public void expectClientFatalAlert(short alertDescription) + { + this.expectFatalAlertConnectionEnd = ConnectionEnd.client; + this.expectFatalAlertDescription = alertDescription; + } + + public void expectServerFatalAlert(short alertDescription) + { + this.expectFatalAlertConnectionEnd = ConnectionEnd.server; + this.expectFatalAlertDescription = alertDescription; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestServerImpl.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestServerImpl.java new file mode 100644 index 000000000..548b518ed --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestServerImpl.java @@ -0,0 +1,214 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.PrintStream; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.crypto.tls.AlertDescription; +import com.fr.third.org.bouncycastle.crypto.tls.AlertLevel; +import com.fr.third.org.bouncycastle.crypto.tls.CertificateRequest; +import com.fr.third.org.bouncycastle.crypto.tls.ClientCertificateType; +import com.fr.third.org.bouncycastle.crypto.tls.ConnectionEnd; +import com.fr.third.org.bouncycastle.crypto.tls.DefaultTlsServer; +import com.fr.third.org.bouncycastle.crypto.tls.ProtocolVersion; +import com.fr.third.org.bouncycastle.crypto.tls.SignatureAlgorithm; +import com.fr.third.org.bouncycastle.crypto.tls.TlsEncryptionCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsFatalAlert; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSignerCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsUtils; + +class TlsTestServerImpl + extends DefaultTlsServer +{ + protected final TlsTestConfig config; + + protected int firstFatalAlertConnectionEnd = -1; + protected short firstFatalAlertDescription = -1; + + TlsTestServerImpl(TlsTestConfig config) + { + this.config = config; + } + + int getFirstFatalAlertConnectionEnd() + { + return firstFatalAlertConnectionEnd; + } + + short getFirstFatalAlertDescription() + { + return firstFatalAlertDescription; + } + + protected ProtocolVersion getMaximumVersion() + { + if (config.serverMaximumVersion != null) + { + return config.serverMaximumVersion; + } + + return super.getMaximumVersion(); + } + + protected ProtocolVersion getMinimumVersion() + { + if (config.serverMinimumVersion != null) + { + return config.serverMinimumVersion; + } + + return super.getMinimumVersion(); + } + + public void notifyAlertRaised(short alertLevel, short alertDescription, String message, Throwable cause) + { + if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1) + { + firstFatalAlertConnectionEnd = ConnectionEnd.server; + firstFatalAlertDescription = alertDescription; + } + + if (TlsTestConfig.DEBUG) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS server raised alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + if (message != null) + { + out.println("> " + message); + } + if (cause != null) + { + cause.printStackTrace(out); + } + } + } + + public void notifyAlertReceived(short alertLevel, short alertDescription) + { + if (alertLevel == AlertLevel.fatal && firstFatalAlertConnectionEnd == -1) + { + firstFatalAlertConnectionEnd = ConnectionEnd.client; + firstFatalAlertDescription = alertDescription; + } + + if (TlsTestConfig.DEBUG) + { + PrintStream out = (alertLevel == AlertLevel.fatal) ? System.err : System.out; + out.println("TLS server received alert: " + AlertLevel.getText(alertLevel) + + ", " + AlertDescription.getText(alertDescription)); + } + } + + public ProtocolVersion getServerVersion() throws IOException + { + ProtocolVersion serverVersion = super.getServerVersion(); + + if (TlsTestConfig.DEBUG) + { + System.out.println("TLS server negotiated " + serverVersion); + } + + return serverVersion; + } + + public CertificateRequest getCertificateRequest() throws IOException + { + if (config.serverCertReq == TlsTestConfig.SERVER_CERT_REQ_NONE) + { + return null; + } + + short[] certificateTypes = new short[]{ ClientCertificateType.rsa_sign, + ClientCertificateType.dss_sign, ClientCertificateType.ecdsa_sign }; + + Vector serverSigAlgs = null; + if (TlsUtils.isSignatureAlgorithmsExtensionAllowed(serverVersion)) + { + serverSigAlgs = config.serverCertReqSigAlgs; + if (serverSigAlgs == null) + { + serverSigAlgs = TlsUtils.getDefaultSupportedSignatureAlgorithms(); + } + } + + Vector certificateAuthorities = new Vector(); + certificateAuthorities.addElement(TlsTestUtils.loadCertificateResource("x509-ca.pem").getSubject()); + + return new CertificateRequest(certificateTypes, serverSigAlgs, certificateAuthorities); + } + + public void notifyClientCertificate(com.fr.third.org.bouncycastle.crypto.tls.Certificate clientCertificate) + throws IOException + { + boolean isEmpty = (clientCertificate == null || clientCertificate.isEmpty()); + + if (isEmpty != (config.clientAuth == TlsTestConfig.CLIENT_AUTH_NONE)) + { + throw new IllegalStateException(); + } + if (isEmpty && (config.serverCertReq == TlsTestConfig.SERVER_CERT_REQ_MANDATORY)) + { + throw new TlsFatalAlert(AlertDescription.handshake_failure); + } + + Certificate[] chain = clientCertificate.getCertificateList(); + + // TODO Cache test resources? + if (!isEmpty && !(chain[0].equals(TlsTestUtils.loadCertificateResource("x509-client.pem")) + || chain[0].equals(TlsTestUtils.loadCertificateResource("x509-client-dsa.pem")) + || chain[0].equals(TlsTestUtils.loadCertificateResource("x509-client-ecdsa.pem")))) + { + throw new TlsFatalAlert(AlertDescription.bad_certificate); + } + + if (TlsTestConfig.DEBUG) + { + System.out.println("TLS server received client certificate chain of length " + chain.length); + for (int i = 0; i != chain.length; i++) + { + Certificate entry = chain[i]; + // TODO Create fingerprint based on certificate signature algorithm digest + System.out.println(" fingerprint:SHA-256 " + TlsTestUtils.fingerprint(entry) + " (" + + entry.getSubject() + ")"); + } + } + } + + protected Vector getSupportedSignatureAlgorithms() + { + if (TlsUtils.isTLSv12(context) && config.serverAuthSigAlg != null) + { + Vector signatureAlgorithms = new Vector(1); + signatureAlgorithms.addElement(config.serverAuthSigAlg); + return signatureAlgorithms; + } + + return supportedSignatureAlgorithms; + } + + protected TlsSignerCredentials getDSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, getSupportedSignatureAlgorithms(), SignatureAlgorithm.dsa, + "x509-server-dsa.pem", "x509-server-key-dsa.pem"); + } + + protected TlsSignerCredentials getECDSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, getSupportedSignatureAlgorithms(), SignatureAlgorithm.ecdsa, + "x509-server-ecdsa.pem", "x509-server-key-ecdsa.pem"); + } + + protected TlsEncryptionCredentials getRSAEncryptionCredentials() throws IOException + { + return TlsTestUtils.loadEncryptionCredentials(context, new String[]{ "x509-server.pem", "x509-ca.pem" }, + "x509-server-key.pem"); + } + + protected TlsSignerCredentials getRSASignerCredentials() throws IOException + { + return TlsTestUtils.loadSignerCredentials(context, getSupportedSignatureAlgorithms(), SignatureAlgorithm.rsa, + "x509-server.pem", "x509-server-key.pem"); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestServerProtocol.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestServerProtocol.java new file mode 100644 index 000000000..0844c310d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestServerProtocol.java @@ -0,0 +1,19 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.InputStream; +import java.io.OutputStream; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.tls.TlsServerProtocol; + +class TlsTestServerProtocol extends TlsServerProtocol +{ + protected final TlsTestConfig config; + + public TlsTestServerProtocol(InputStream input, OutputStream output, SecureRandom secureRandom, TlsTestConfig config) + { + super(input, output, secureRandom); + + this.config = config; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestUtils.java new file mode 100644 index 000000000..2712f8bd6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/TlsTestUtils.java @@ -0,0 +1,191 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.asn1.pkcs.RSAPrivateKey; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.crypto.tls.Certificate; +import com.fr.third.org.bouncycastle.crypto.tls.DefaultTlsAgreementCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.DefaultTlsEncryptionCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.DefaultTlsSignerCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.SignatureAndHashAlgorithm; +import com.fr.third.org.bouncycastle.crypto.tls.TlsAgreementCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsContext; +import com.fr.third.org.bouncycastle.crypto.tls.TlsEncryptionCredentials; +import com.fr.third.org.bouncycastle.crypto.tls.TlsSignerCredentials; +import com.fr.third.org.bouncycastle.crypto.util.PrivateKeyFactory; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.io.pem.PemObject; +import com.fr.third.org.bouncycastle.util.io.pem.PemReader; + +public class TlsTestUtils +{ + static final byte[] rsaCertData = Base64 + .decode("MIICUzCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBjzELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb2" + + "4gb2YgdGhlIEJvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExLzAtBgkq" + + "hkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTEzMDIyNTA2MDIwNVoXDTEzMDIyNT" + + "A2MDM0NVowgY8xCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIw" + + "EAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWVkYmFjay1jcnlwdG" + + "9AYm91bmN5Y2FzdGxlLm9yZzBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr5YtqKmKXmEGb4Shy" + + "pL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERo0QwQjAOBgNVHQ8BAf8EBAMCBSAwEgYDVR" + + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAHU55Ncz" + + "eglREcTg54YLUlGWu2WOYWhit/iM1eeq8Kivro7q98eW52jTuMI3CI5ulqd0hYzshQKQaZ5GDzErMyM="); + + static final byte[] dudRsaCertData = Base64 + .decode("MIICUzCCAf2gAwIBAgIBATANBgkqhkiG9w0BAQQFADCBjzELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb2" + + "4gb2YgdGhlIEJvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExLzAtBgkq" + + "hkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTEzMDIyNTA1NDcyOFoXDTEzMDIyNT" + + "A1NDkwOFowgY8xCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIw" + + "EAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWVkYmFjay1jcnlwdG" + + "9AYm91bmN5Y2FzdGxlLm9yZzBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr5YtqKmKXmEGb4Shy" + + "pL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERo0QwQjAOBgNVHQ8BAf8EBAMCAAEwEgYDVR" + + "0lAQH/BAgwBgYEVR0lADAcBgNVHREBAf8EEjAQgQ50ZXN0QHRlc3QudGVzdDANBgkqhkiG9w0BAQQFAANBAJg55PBS" + + "weg6obRUKF4FF6fCrWFi6oCYSQ99LWcAeupc5BofW5MstFMhCOaEucuGVqunwT5G7/DweazzCIrSzB0="); + + static String fingerprint(com.fr.third.org.bouncycastle.asn1.x509.Certificate c) + throws IOException + { + byte[] der = c.getEncoded(); + byte[] sha1 = sha256DigestOf(der); + byte[] hexBytes = Hex.encode(sha1); + String hex = new String(hexBytes, "ASCII").toUpperCase(); + + StringBuffer fp = new StringBuffer(); + int i = 0; + fp.append(hex.substring(i, i + 2)); + while ((i += 2) < hex.length()) + { + fp.append(':'); + fp.append(hex.substring(i, i + 2)); + } + return fp.toString(); + } + + static byte[] sha256DigestOf(byte[] input) + { + SHA256Digest d = new SHA256Digest(); + d.update(input, 0, input.length); + byte[] result = new byte[d.getDigestSize()]; + d.doFinal(result, 0); + return result; + } + + static TlsAgreementCredentials loadAgreementCredentials(TlsContext context, + String[] certResources, String keyResource) + throws IOException + { + Certificate certificate = loadCertificateChain(certResources); + AsymmetricKeyParameter privateKey = loadPrivateKeyResource(keyResource); + + return new DefaultTlsAgreementCredentials(certificate, privateKey); + } + + static TlsEncryptionCredentials loadEncryptionCredentials(TlsContext context, + String[] certResources, String keyResource) + throws IOException + { + Certificate certificate = loadCertificateChain(certResources); + AsymmetricKeyParameter privateKey = loadPrivateKeyResource(keyResource); + + return new DefaultTlsEncryptionCredentials(context, certificate, privateKey); + } + + static TlsSignerCredentials loadSignerCredentials(TlsContext context, String[] certResources, + String keyResource, SignatureAndHashAlgorithm signatureAndHashAlgorithm) + throws IOException + { + Certificate certificate = loadCertificateChain(certResources); + AsymmetricKeyParameter privateKey = loadPrivateKeyResource(keyResource); + + return new DefaultTlsSignerCredentials(context, certificate, privateKey, signatureAndHashAlgorithm); + } + + static TlsSignerCredentials loadSignerCredentials(TlsContext context, Vector supportedSignatureAlgorithms, + short signatureAlgorithm, String certResource, String keyResource) + throws IOException + { + /* + * TODO Note that this code fails to provide default value for the client supported + * algorithms if it wasn't sent. + */ + + SignatureAndHashAlgorithm signatureAndHashAlgorithm = null; + if (supportedSignatureAlgorithms != null) + { + for (int i = 0; i < supportedSignatureAlgorithms.size(); ++i) + { + SignatureAndHashAlgorithm alg = (SignatureAndHashAlgorithm) + supportedSignatureAlgorithms.elementAt(i); + if (alg.getSignature() == signatureAlgorithm) + { + signatureAndHashAlgorithm = alg; + break; + } + } + + if (signatureAndHashAlgorithm == null) + { + return null; + } + } + + return loadSignerCredentials(context, new String[]{ certResource, "x509-ca.pem" }, + keyResource, signatureAndHashAlgorithm); + } + + static Certificate loadCertificateChain(String[] resources) + throws IOException + { + com.fr.third.org.bouncycastle.asn1.x509.Certificate[] chain = new com.fr.third.org.bouncycastle.asn1.x509.Certificate[resources.length]; + for (int i = 0; i < resources.length; ++i) + { + chain[i] = loadCertificateResource(resources[i]); + } + return new Certificate(chain); + } + + static com.fr.third.org.bouncycastle.asn1.x509.Certificate loadCertificateResource(String resource) + throws IOException + { + PemObject pem = loadPemResource(resource); + if (pem.getType().endsWith("CERTIFICATE")) + { + return com.fr.third.org.bouncycastle.asn1.x509.Certificate.getInstance(pem.getContent()); + } + throw new IllegalArgumentException("'resource' doesn't specify a valid certificate"); + } + + static AsymmetricKeyParameter loadPrivateKeyResource(String resource) + throws IOException + { + PemObject pem = loadPemResource(resource); + if (pem.getType().endsWith("RSA PRIVATE KEY")) + { + RSAPrivateKey rsa = RSAPrivateKey.getInstance(pem.getContent()); + return new RSAPrivateCrtKeyParameters(rsa.getModulus(), rsa.getPublicExponent(), + rsa.getPrivateExponent(), rsa.getPrime1(), rsa.getPrime2(), rsa.getExponent1(), + rsa.getExponent2(), rsa.getCoefficient()); + } + if (pem.getType().endsWith("PRIVATE KEY")) + { + return PrivateKeyFactory.createKey(pem.getContent()); + } + throw new IllegalArgumentException("'resource' doesn't specify a valid private key"); + } + + static PemObject loadPemResource(String resource) + throws IOException + { + InputStream s = TlsTestUtils.class.getResourceAsStream(resource); + PemReader p = new PemReader(new InputStreamReader(s)); + PemObject o = p.readPemObject(); + p.close(); + return o; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/UnreliableDatagramTransport.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/UnreliableDatagramTransport.java new file mode 100644 index 000000000..a7e1f2f1c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/UnreliableDatagramTransport.java @@ -0,0 +1,93 @@ +package com.fr.third.org.bouncycastle.crypto.tls.test; + +import java.io.IOException; +import java.util.Random; + +import com.fr.third.org.bouncycastle.crypto.tls.DatagramTransport; + +public class UnreliableDatagramTransport + implements DatagramTransport +{ + + private final DatagramTransport transport; + private final Random random; + private final int percentPacketLossReceiving, percentPacketLossSending; + + public UnreliableDatagramTransport(DatagramTransport transport, Random random, + int percentPacketLossReceiving, int percentPacketLossSending) + { + if (percentPacketLossReceiving < 0 || percentPacketLossReceiving > 100) + { + throw new IllegalArgumentException("'percentPacketLossReceiving' out of range"); + } + if (percentPacketLossSending < 0 || percentPacketLossSending > 100) + { + throw new IllegalArgumentException("'percentPacketLossSending' out of range"); + } + + this.transport = transport; + this.random = random; + this.percentPacketLossReceiving = percentPacketLossReceiving; + this.percentPacketLossSending = percentPacketLossSending; + } + + public int getReceiveLimit() + throws IOException + { + return transport.getReceiveLimit(); + } + + public int getSendLimit() + throws IOException + { + return transport.getSendLimit(); + } + + public int receive(byte[] buf, int off, int len, int waitMillis) + throws IOException + { + long endMillis = System.currentTimeMillis() + waitMillis; + for (; ; ) + { + int length = transport.receive(buf, off, len, waitMillis); + if (length < 0 || !lostPacket(percentPacketLossReceiving)) + { + return length; + } + + System.out.println("PACKET LOSS (" + length + " byte packet not received)"); + + long now = System.currentTimeMillis(); + if (now >= endMillis) + { + return -1; + } + + waitMillis = (int)(endMillis - now); + } + } + + public void send(byte[] buf, int off, int len) + throws IOException + { + if (lostPacket(percentPacketLossSending)) + { + System.out.println("PACKET LOSS (" + len + " byte packet not sent)"); + } + else + { + transport.send(buf, off, len); + } + } + + public void close() + throws IOException + { + transport.close(); + } + + private boolean lostPacket(int percentPacketLoss) + { + return percentPacketLoss > 0 && random.nextInt(100) < percentPacketLoss; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/package.html b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/package.html new file mode 100644 index 000000000..ec6dbbc86 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/tls/test/package.html @@ -0,0 +1,5 @@ + + +Example code and test classes for the lightweight TLS API. + + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java new file mode 100644 index 000000000..467beec7a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/AlgorithmIdentifierFactory.java @@ -0,0 +1,124 @@ +package com.fr.third.org.bouncycastle.crypto.util; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.cms.GCMParameters; +import com.fr.third.org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.misc.CAST5CBCParameters; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.RC2CBCParameter; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; + +import java.security.SecureRandom; + +/** + * Factory methods for common AlgorithmIdentifiers. + */ +public class AlgorithmIdentifierFactory +{ + private AlgorithmIdentifierFactory() + { + + } + + static final ASN1ObjectIdentifier IDEA_CBC = new ASN1ObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2").intern(); + static final ASN1ObjectIdentifier CAST5_CBC = new ASN1ObjectIdentifier("1.2.840.113533.7.66.10").intern(); + + private static final short[] rc2Table = { + 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0, + 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, + 0x41, 0x9f, 0xe1, 0xd9, 0x4a, 0x4d, 0x9e, 0xda, 0xa0, 0x68, 0x2c, 0xc3, 0x27, 0x5f, 0x80, 0x36, + 0x3e, 0xee, 0xfb, 0x95, 0x1a, 0xfe, 0xce, 0xa8, 0x34, 0xa9, 0x13, 0xf0, 0xa6, 0x3f, 0xd8, 0x0c, + 0x78, 0x24, 0xaf, 0x23, 0x52, 0xc1, 0x67, 0x17, 0xf5, 0x66, 0x90, 0xe7, 0xe8, 0x07, 0xb8, 0x60, + 0x48, 0xe6, 0x1e, 0x53, 0xf3, 0x92, 0xa4, 0x72, 0x8c, 0x08, 0x15, 0x6e, 0x86, 0x00, 0x84, 0xfa, + 0xf4, 0x7f, 0x8a, 0x42, 0x19, 0xf6, 0xdb, 0xcd, 0x14, 0x8d, 0x50, 0x12, 0xba, 0x3c, 0x06, 0x4e, + 0xec, 0xb3, 0x35, 0x11, 0xa1, 0x88, 0x8e, 0x2b, 0x94, 0x99, 0xb7, 0x71, 0x74, 0xd3, 0xe4, 0xbf, + 0x3a, 0xde, 0x96, 0x0e, 0xbc, 0x0a, 0xed, 0x77, 0xfc, 0x37, 0x6b, 0x03, 0x79, 0x89, 0x62, 0xc6, + 0xd7, 0xc0, 0xd2, 0x7c, 0x6a, 0x8b, 0x22, 0xa3, 0x5b, 0x05, 0x5d, 0x02, 0x75, 0xd5, 0x61, 0xe3, + 0x18, 0x8f, 0x55, 0x51, 0xad, 0x1f, 0x0b, 0x5e, 0x85, 0xe5, 0xc2, 0x57, 0x63, 0xca, 0x3d, 0x6c, + 0xb4, 0xc5, 0xcc, 0x70, 0xb2, 0x91, 0x59, 0x0d, 0x47, 0x20, 0xc8, 0x4f, 0x58, 0xe0, 0x01, 0xe2, + 0x16, 0x38, 0xc4, 0x6f, 0x3b, 0x0f, 0x65, 0x46, 0xbe, 0x7e, 0x2d, 0x7b, 0x82, 0xf9, 0x40, 0xb5, + 0x1d, 0x73, 0xf8, 0xeb, 0x26, 0xc7, 0x87, 0x97, 0x25, 0x54, 0xb1, 0x28, 0xaa, 0x98, 0x9d, 0xa5, + 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f, + 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab + }; + + /** + * Create an AlgorithmIdentifier for the passed in encryption algorithm. + * + * @param encryptionOID OID for the encryption algorithm + * @param keySize key size in bits (-1 if unknown) + * @param random SecureRandom to use for parameter generation. + * @return a full AlgorithmIdentifier including parameters + * @throws IllegalArgumentException if encryptionOID cannot be matched + */ + public static AlgorithmIdentifier generateEncryptionAlgID(ASN1ObjectIdentifier encryptionOID, int keySize, SecureRandom random) + throws IllegalArgumentException + { + if (encryptionOID.equals(NISTObjectIdentifiers.id_aes128_CBC) + || encryptionOID.equals(NISTObjectIdentifiers.id_aes192_CBC) + || encryptionOID.equals(NISTObjectIdentifiers.id_aes256_CBC) + || encryptionOID.equals(NTTObjectIdentifiers.id_camellia128_cbc) + || encryptionOID.equals(NTTObjectIdentifiers.id_camellia192_cbc) + || encryptionOID.equals(NTTObjectIdentifiers.id_camellia256_cbc) + || encryptionOID.equals(KISAObjectIdentifiers.id_seedCBC)) + { + byte[] iv = new byte[16]; + + random.nextBytes(iv); + + return new AlgorithmIdentifier(encryptionOID, new DEROctetString(iv)); + } + else if(encryptionOID.equals(NISTObjectIdentifiers.id_aes128_GCM) + || encryptionOID.equals(NISTObjectIdentifiers.id_aes192_GCM) + || encryptionOID.equals(NISTObjectIdentifiers.id_aes256_GCM)){ + byte[] iv =new byte[16]; + + random.nextBytes(iv); + + return new AlgorithmIdentifier(encryptionOID, new GCMParameters(iv, 12)); + } + else if (encryptionOID.equals(PKCSObjectIdentifiers.des_EDE3_CBC) + || encryptionOID.equals(IDEA_CBC) + || encryptionOID.equals(OIWObjectIdentifiers.desCBC)) + { + byte[] iv = new byte[8]; + + random.nextBytes(iv); + + return new AlgorithmIdentifier(encryptionOID, new DEROctetString(iv)); + } + else if (encryptionOID.equals(CAST5_CBC)) + { + byte[] iv = new byte[8]; + + random.nextBytes(iv); + + CAST5CBCParameters cbcParams = new CAST5CBCParameters(iv, keySize); + + return new AlgorithmIdentifier(encryptionOID, cbcParams); + } + else if (encryptionOID.equals(PKCSObjectIdentifiers.rc4)) + { + return new AlgorithmIdentifier(encryptionOID, DERNull.INSTANCE); + } + else if (encryptionOID.equals(PKCSObjectIdentifiers.RC2_CBC)) + { + byte[] iv = new byte[8]; + + random.nextBytes(iv); + + RC2CBCParameter cbcParams = new RC2CBCParameter(rc2Table[128], iv); + + return new AlgorithmIdentifier(encryptionOID, cbcParams); + } + else + { + throw new IllegalArgumentException("unable to match algorithm"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/CipherFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/CipherFactory.java new file mode 100644 index 000000000..aa0642feb --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/CipherFactory.java @@ -0,0 +1,228 @@ +package com.fr.third.org.bouncycastle.crypto.util; + +import com.fr.third.org.bouncycastle.asn1.ASN1Null; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.cms.GCMParameters; +import com.fr.third.org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.misc.CAST5CBCParameters; +import com.fr.third.org.bouncycastle.asn1.misc.MiscObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.RC2CBCParameter; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.crypto.BlockCipher; +import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.StreamCipher; +import com.fr.third.org.bouncycastle.crypto.engines.AESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.CAST5Engine; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.DESedeEngine; +import com.fr.third.org.bouncycastle.crypto.engines.RC2Engine; +import com.fr.third.org.bouncycastle.crypto.engines.RC4Engine; +import com.fr.third.org.bouncycastle.crypto.io.CipherOutputStream; +import com.fr.third.org.bouncycastle.crypto.modes.AEADBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.GCMBlockCipher; +import com.fr.third.org.bouncycastle.crypto.paddings.PKCS7Padding; +import com.fr.third.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import com.fr.third.org.bouncycastle.crypto.params.AEADParameters; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.crypto.params.RC2Parameters; + +import java.io.OutputStream; + +/** + * Factory methods for creating Cipher objects and CipherOutputStreams. + */ +public class CipherFactory +{ + + private static final short[] rc2Ekb = { + 0x5d, 0xbe, 0x9b, 0x8b, 0x11, 0x99, 0x6e, 0x4d, 0x59, 0xf3, 0x85, 0xa6, 0x3f, 0xb7, 0x83, 0xc5, + 0xe4, 0x73, 0x6b, 0x3a, 0x68, 0x5a, 0xc0, 0x47, 0xa0, 0x64, 0x34, 0x0c, 0xf1, 0xd0, 0x52, 0xa5, + 0xb9, 0x1e, 0x96, 0x43, 0x41, 0xd8, 0xd4, 0x2c, 0xdb, 0xf8, 0x07, 0x77, 0x2a, 0xca, 0xeb, 0xef, + 0x10, 0x1c, 0x16, 0x0d, 0x38, 0x72, 0x2f, 0x89, 0xc1, 0xf9, 0x80, 0xc4, 0x6d, 0xae, 0x30, 0x3d, + 0xce, 0x20, 0x63, 0xfe, 0xe6, 0x1a, 0xc7, 0xb8, 0x50, 0xe8, 0x24, 0x17, 0xfc, 0x25, 0x6f, 0xbb, + 0x6a, 0xa3, 0x44, 0x53, 0xd9, 0xa2, 0x01, 0xab, 0xbc, 0xb6, 0x1f, 0x98, 0xee, 0x9a, 0xa7, 0x2d, + 0x4f, 0x9e, 0x8e, 0xac, 0xe0, 0xc6, 0x49, 0x46, 0x29, 0xf4, 0x94, 0x8a, 0xaf, 0xe1, 0x5b, 0xc3, + 0xb3, 0x7b, 0x57, 0xd1, 0x7c, 0x9c, 0xed, 0x87, 0x40, 0x8c, 0xe2, 0xcb, 0x93, 0x14, 0xc9, 0x61, + 0x2e, 0xe5, 0xcc, 0xf6, 0x5e, 0xa8, 0x5c, 0xd6, 0x75, 0x8d, 0x62, 0x95, 0x58, 0x69, 0x76, 0xa1, + 0x4a, 0xb5, 0x55, 0x09, 0x78, 0x33, 0x82, 0xd7, 0xdd, 0x79, 0xf5, 0x1b, 0x0b, 0xde, 0x26, 0x21, + 0x28, 0x74, 0x04, 0x97, 0x56, 0xdf, 0x3c, 0xf0, 0x37, 0x39, 0xdc, 0xff, 0x06, 0xa4, 0xea, 0x42, + 0x08, 0xda, 0xb4, 0x71, 0xb0, 0xcf, 0x12, 0x7a, 0x4e, 0xfa, 0x6c, 0x1d, 0x84, 0x00, 0xc8, 0x7f, + 0x91, 0x45, 0xaa, 0x2b, 0xc2, 0xb1, 0x8f, 0xd5, 0xba, 0xf2, 0xad, 0x19, 0xb2, 0x67, 0x36, 0xf7, + 0x0f, 0x0a, 0x92, 0x7d, 0xe3, 0x9d, 0xe9, 0x90, 0x3e, 0x23, 0x27, 0x66, 0x13, 0xec, 0x81, 0x15, + 0xbd, 0x22, 0xbf, 0x9f, 0x7e, 0xa9, 0x51, 0x4b, 0x4c, 0xfb, 0x02, 0xd3, 0x70, 0x86, 0x31, 0xe7, + 0x3b, 0x05, 0x03, 0x54, 0x60, 0x48, 0x65, 0x18, 0xd2, 0xcd, 0x5f, 0x32, 0x88, 0x0e, 0x35, 0xfd + }; + + /** + * Create a content cipher for encrypting bulk data. + * + * @param forEncryption true if the cipher is for encryption, false otherwise. + * @param encKey the basic key to use. + * @param encryptionAlgID identifying algorithm OID and parameters to use. + * @return a StreamCipher or a BufferedBlockCipher depending on the algorithm. + * @throws IllegalArgumentException + */ + public static Object createContentCipher(boolean forEncryption, CipherParameters encKey, AlgorithmIdentifier encryptionAlgID) + throws IllegalArgumentException + { + ASN1ObjectIdentifier encAlg = encryptionAlgID.getAlgorithm(); + + if (encAlg.equals(PKCSObjectIdentifiers.rc4)) + { + StreamCipher cipher = new RC4Engine(); + + cipher.init(forEncryption, encKey); + + return cipher; + } + else if(encAlg.equals(NISTObjectIdentifiers.id_aes128_GCM) + || encAlg.equals(NISTObjectIdentifiers.id_aes192_GCM) + || encAlg.equals(NISTObjectIdentifiers.id_aes256_GCM)) + { + AEADBlockCipher cipher = createAEADCipher(encryptionAlgID.getAlgorithm()); + GCMParameters gcmParameters = GCMParameters.getInstance(encryptionAlgID.getParameters()); + if(!(encKey instanceof KeyParameter)){ + throw new IllegalArgumentException("key data must be accessible for GCM operation") ; + } + AEADParameters aeadParameters = new AEADParameters((KeyParameter) encKey, gcmParameters.getIcvLen() * 8, gcmParameters.getNonce()); + cipher.init(forEncryption, aeadParameters); + return cipher; + } + else + { + BufferedBlockCipher cipher = createCipher(encryptionAlgID.getAlgorithm()); + ASN1Primitive sParams = encryptionAlgID.getParameters().toASN1Primitive(); + + if (sParams != null && !(sParams instanceof ASN1Null)) + { + if (encAlg.equals(PKCSObjectIdentifiers.des_EDE3_CBC) + || encAlg.equals(AlgorithmIdentifierFactory.IDEA_CBC) + || encAlg.equals(NISTObjectIdentifiers.id_aes128_CBC) + || encAlg.equals(NISTObjectIdentifiers.id_aes192_CBC) + || encAlg.equals(NISTObjectIdentifiers.id_aes256_CBC) + || encAlg.equals(NTTObjectIdentifiers.id_camellia128_cbc) + || encAlg.equals(NTTObjectIdentifiers.id_camellia192_cbc) + || encAlg.equals(NTTObjectIdentifiers.id_camellia256_cbc) + || encAlg.equals(KISAObjectIdentifiers.id_seedCBC) + || encAlg.equals(OIWObjectIdentifiers.desCBC)) + { + cipher.init(forEncryption, new ParametersWithIV(encKey, + ASN1OctetString.getInstance(sParams).getOctets())); + } + else if (encAlg.equals(AlgorithmIdentifierFactory.CAST5_CBC)) + { + CAST5CBCParameters cbcParams = CAST5CBCParameters.getInstance(sParams); + + cipher.init(forEncryption, new ParametersWithIV(encKey, cbcParams.getIV())); + } + else if (encAlg.equals(PKCSObjectIdentifiers.RC2_CBC)) + { + RC2CBCParameter cbcParams = RC2CBCParameter.getInstance(sParams); + + cipher.init(forEncryption, new ParametersWithIV(new RC2Parameters(((KeyParameter)encKey).getKey(), rc2Ekb[cbcParams.getRC2ParameterVersion().intValue()]), cbcParams.getIV())); + } + else + { + throw new IllegalArgumentException("cannot match parameters"); + } + } + else + { + if (encAlg.equals(PKCSObjectIdentifiers.des_EDE3_CBC) + || encAlg.equals(AlgorithmIdentifierFactory.IDEA_CBC) + || encAlg.equals(AlgorithmIdentifierFactory.CAST5_CBC)) + { + cipher.init(forEncryption, new ParametersWithIV(encKey, new byte[8])); + } + else + { + cipher.init(forEncryption, encKey); + } + } + + return cipher; + } + } + + private static AEADBlockCipher createAEADCipher(ASN1ObjectIdentifier algorithm){ + if (NISTObjectIdentifiers.id_aes128_GCM.equals(algorithm) + || NISTObjectIdentifiers.id_aes192_GCM.equals(algorithm) + || NISTObjectIdentifiers.id_aes256_GCM.equals(algorithm)) + { + return new GCMBlockCipher(new AESEngine()); + } + else + { + throw new IllegalArgumentException("cannot recognise cipher: " + algorithm); + } + } + + private static BufferedBlockCipher createCipher(ASN1ObjectIdentifier algorithm) + throws IllegalArgumentException + { + BlockCipher cipher; + + if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm) + || NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm) + || NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm)) + { + cipher = new CBCBlockCipher(new AESEngine()); + } + else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm)) + { + cipher = new CBCBlockCipher(new DESedeEngine()); + } + else if (OIWObjectIdentifiers.desCBC.equals(algorithm)) + { + cipher = new CBCBlockCipher(new DESEngine()); + } + else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm)) + { + cipher = new CBCBlockCipher(new RC2Engine()); + } + else if (MiscObjectIdentifiers.cast5CBC.equals(algorithm)) + { + cipher = new CBCBlockCipher(new CAST5Engine()); + } + else + { + throw new IllegalArgumentException("cannot recognise cipher: " + algorithm); + } + + return new PaddedBufferedBlockCipher(cipher, new PKCS7Padding()); + } + + /** + * Return a new CipherOutputStream based on the passed in cipher. + * + * @param dOut the output stream to write the processed data to. + * @param cipher the cipher to use. + * @return a BC CipherOutputStream using the cipher and writing to dOut. + */ + public static CipherOutputStream createOutputStream(OutputStream dOut, Object cipher) + { + if (cipher instanceof BufferedBlockCipher) + { + return new CipherOutputStream(dOut, (BufferedBlockCipher)cipher); + } + if (cipher instanceof StreamCipher) + { + return new CipherOutputStream(dOut, (StreamCipher)cipher); + } + if (cipher instanceof AEADBlockCipher) + { + return new CipherOutputStream(dOut, (AEADBlockCipher)cipher); + } + throw new IllegalArgumentException("unknown cipher object: " + cipher); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java new file mode 100644 index 000000000..de004b750 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/CipherKeyGeneratorFactory.java @@ -0,0 +1,118 @@ +package com.fr.third.org.bouncycastle.crypto.util; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.CipherKeyGenerator; +import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.generators.DESKeyGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.DESedeKeyGenerator; + +import java.security.SecureRandom; + +/** + * Factory methods for generating secret key generators for symmetric ciphers. + */ +public class CipherKeyGeneratorFactory +{ + private CipherKeyGeneratorFactory() + { + } + + /** + * Create a key generator for the passed in Object Identifier. + * + * @param algorithm the Object Identifier indicating the algorithn the generator is for. + * @param random a source of random to initialise the generator with. + * @return an initialised CipherKeyGenerator. + * @throws IllegalArgumentException if the algorithm cannot be identified. + */ + public static CipherKeyGenerator createKeyGenerator(ASN1ObjectIdentifier algorithm, SecureRandom random) + throws IllegalArgumentException + { + if (NISTObjectIdentifiers.id_aes128_CBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (NISTObjectIdentifiers.id_aes192_CBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 192); + } + else if (NISTObjectIdentifiers.id_aes256_CBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 256); + } + else if (NISTObjectIdentifiers.id_aes128_GCM.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (NISTObjectIdentifiers.id_aes192_GCM.equals(algorithm)) + { + return createCipherKeyGenerator(random, 192); + } + else if (NISTObjectIdentifiers.id_aes256_GCM.equals(algorithm)) + { + return createCipherKeyGenerator(random, 256); + } + else if (PKCSObjectIdentifiers.des_EDE3_CBC.equals(algorithm)) + { + DESedeKeyGenerator keyGen = new DESedeKeyGenerator(); + + keyGen.init(new KeyGenerationParameters(random, 192)); + + return keyGen; + } + else if (NTTObjectIdentifiers.id_camellia128_cbc.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (NTTObjectIdentifiers.id_camellia192_cbc.equals(algorithm)) + { + return createCipherKeyGenerator(random, 192); + } + else if (NTTObjectIdentifiers.id_camellia256_cbc.equals(algorithm)) + { + return createCipherKeyGenerator(random, 256); + } + else if (KISAObjectIdentifiers.id_seedCBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (AlgorithmIdentifierFactory.CAST5_CBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (OIWObjectIdentifiers.desCBC.equals(algorithm)) + { + DESKeyGenerator keyGen = new DESKeyGenerator(); + + keyGen.init(new KeyGenerationParameters(random, 64)); + + return keyGen; + } + else if (PKCSObjectIdentifiers.rc4.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else if (PKCSObjectIdentifiers.RC2_CBC.equals(algorithm)) + { + return createCipherKeyGenerator(random, 128); + } + else + { + throw new IllegalArgumentException("cannot recognise cipher: " + algorithm); + } + } + + private static CipherKeyGenerator createCipherKeyGenerator(SecureRandom random, int keySize) + { + CipherKeyGenerator keyGen = new CipherKeyGenerator(); + + keyGen.init(new KeyGenerationParameters(random, keySize)); + + return keyGen; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/JournaledAlgorithm.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/JournaledAlgorithm.java new file mode 100644 index 000000000..d44ded78a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/JournaledAlgorithm.java @@ -0,0 +1,228 @@ +package com.fr.third.org.bouncycastle.crypto.util; + +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.OutputStream; +import java.io.Serializable; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; +import com.fr.third.org.bouncycastle.util.Encodable; +import com.fr.third.org.bouncycastle.util.io.Streams; + +/** + * JournaledAlgorithm keeps state of the JournalingSecureRandom and the + * AlgorithmIdentifier necessary to fully resume an encryption session. This + * class can be used to retrieve a session even if a process is completely + * stopped. NOTE: This should be used with a shutdown hook to save the state of + * the journaling and the algorithm identifier even in the case of a forced + * shutdown. + *

+ * The raw encoding is in ASN.1 format. + *

+ *

+ * Details: Use serialization of critical parameters of the the + * JournalingSecureRandom and AlgorithmIdentifier. Because these two classes are + * not serializable, create interior class to serialize only the critical + * parameters in the form of byte[] arrays + */ + +public class JournaledAlgorithm + implements Encodable, Serializable +{ + private transient JournalingSecureRandom journaling; + + private transient AlgorithmIdentifier algID; + + public JournaledAlgorithm(AlgorithmIdentifier aid, JournalingSecureRandom journaling) + { + if (aid == null) + { + throw new NullPointerException("AlgorithmIdentifier passed to JournaledAlgorithm is null"); + } + else if (journaling == null) + { + throw new NullPointerException("JournalingSecureRandom passed to JournaledAlgorithm is null"); + } + + this.journaling = journaling; + + this.algID = aid; + } + + /** + * Construct from a previous encoding, using CryptoServicesRegistrar.getSecureRandom() as the backup source of entropy. + * + * @param encoding raw encoding of a previous JournaledAlgorithm. + */ + public JournaledAlgorithm(byte[] encoding) + { + this(encoding, CryptoServicesRegistrar.getSecureRandom()); + } + + /** + * Construct from a previous encoding, using the passed in random as a source for when the existing entropy runs out. + * + * @param encoding raw encoding of a previous JournaledAlgorithm. + * @param random back up source of entropy. + */ + public JournaledAlgorithm(byte[] encoding, SecureRandom random) + { + if (encoding == null) + { + throw new NullPointerException("encoding passed to JournaledAlgorithm is null"); + } + else if (random == null) + { + throw new NullPointerException("random passed to JournaledAlgorithm is null"); + } + + initFromEncoding(encoding, random); + } + + private void initFromEncoding(byte[] encoding, SecureRandom random) + { + ASN1Sequence seq = ASN1Sequence.getInstance(encoding); + + this.algID = AlgorithmIdentifier.getInstance(seq.getObjectAt(0)); + this.journaling = new JournalingSecureRandom(ASN1OctetString.getInstance(seq.getObjectAt(1)).getOctets(), random); + } + + public JournalingSecureRandom getJournalingSecureRandom() + { + return journaling; + } + + public AlgorithmIdentifier getAlgorithmIdentifier() + { + return algID; + } + + /** + * Store state of JournalingSecureRandom and AlgorithmIdentifier in temporary + * file + * + * @param tempfile + * @throws IOException + */ + public void storeState(File tempfile) + throws IOException + { + if (tempfile == null) + { + throw new NullPointerException("file for storage is null in JournaledAlgorithm"); + } + + // Extract key information in byte[] form + FileOutputStream fOut = new FileOutputStream(tempfile); + + try + { + storeState(fOut); + } + finally + { + fOut.close(); + } + } + + public void storeState(OutputStream out) + throws IOException + { + if (out == null) + { + throw new NullPointerException("output stream for storage is null in JournaledAlgorithm"); + } + + out.write(this.getEncoded()); + } + + public static JournaledAlgorithm getState(InputStream stateIn, SecureRandom random) + throws IOException, ClassNotFoundException + { + if (stateIn == null) + { + throw new NullPointerException("stream for loading is null in JournaledAlgorithm"); + } + + InputStream fIn = new BufferedInputStream(stateIn); + + try + { + return new JournaledAlgorithm(Streams.readAll(fIn), random); + } + finally + { + fIn.close(); + } + } + + /** + * Reconstructs JournaledAlgorithm session from file containing it's raw encoding. + * + * @param tempfile temporary file containing serialized state + * @return + * @throws IOException + * @throws ClassNotFoundException + */ + public static JournaledAlgorithm getState(File tempfile, SecureRandom random) + throws IOException, ClassNotFoundException + { + if (tempfile == null) + { + throw new NullPointerException("File for loading is null in JournaledAlgorithm"); + } + + InputStream fIn = new BufferedInputStream(new FileInputStream(tempfile)); + + try + { + return new JournaledAlgorithm(Streams.readAll(fIn), random); + } + finally + { + fIn.close(); + } + } + + public byte[] getEncoded() + throws IOException + { + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(algID); + v.add(new DEROctetString(journaling.getFullTranscript())); + + return new DERSequence(v).getEncoded(); + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + initFromEncoding((byte[])in.readObject(), CryptoServicesRegistrar.getSecureRandom()); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(getEncoded()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/JournalingSecureRandom.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/JournalingSecureRandom.java new file mode 100644 index 000000000..a265639cf --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/JournalingSecureRandom.java @@ -0,0 +1,161 @@ +package com.fr.third.org.bouncycastle.crypto.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; +import com.fr.third.org.bouncycastle.util.Arrays; + +/** +* A SecureRandom that maintains a journal of its output. +* This can be used to recreate an output that was based on randomness +* For the transcript to be reusable, the order of the requests for randomness during recreation must be consistent with the initial requests and no other sources of randomness may be used. + */ +public class JournalingSecureRandom + extends SecureRandom +{ + private static byte[] EMPTY_TRANSCRIPT = new byte[0]; + + private final SecureRandom base; + + private TranscriptStream tOut = new TranscriptStream(); + private byte[] transcript; + + private int index = 0; + + /** + * Default constructor that takes an arbitrary SecureRandom as initial random + */ + public JournalingSecureRandom() + { + this(CryptoServicesRegistrar.getSecureRandom()); + } + + /** + * Base constructor - no prior transcript. + * + * @param random source of randomness we will be journaling. + */ + public JournalingSecureRandom(SecureRandom random) + { + this.base = random; + this.transcript = EMPTY_TRANSCRIPT; + } + + /** + * Constructor with a prior transcript. Both the transcript used and + * any new randomness are journaled. + * + * @param transcript initial transcript of randomness. + * @param random source of randomness we will be journaling when the transcript runs out. + */ + public JournalingSecureRandom(byte[] transcript, SecureRandom random) + { + this.base = random; + this.transcript = Arrays.clone(transcript); + } + + /** + * Fill bytes with random data, journaling the random data before returning or re-use previously used random data, depending on the state of the transcript. + * + * @param bytes a block of bytes to be filled with random data. + */ + public final void nextBytes(byte[] bytes) + { + if (index >= transcript.length) + { + base.nextBytes(bytes); + } + else + { + int i = 0; + + while (i != bytes.length) + { + if (index < transcript.length) + { + bytes[i] = transcript[index++]; + } + else + { + break; + } + i++; + } + + if (i != bytes.length) + { + byte[] extra = new byte[bytes.length - i]; + + base.nextBytes(extra); + + System.arraycopy(extra, 0, bytes, i, extra.length); + } + } + + try + { + tOut.write(bytes); + } + catch (IOException e) + { + throw new IllegalStateException("unable to record transcript: " + e.getMessage()); + } + } + + /** + * Clear the internals + */ + public void clear() + { + Arrays.fill(transcript, (byte)0); + tOut.clear(); + } + + /** + * Resets the index to zero such that the randomness will now be reused + */ + public void reset() + { + index = 0; + if (index == transcript.length) + { + transcript = tOut.toByteArray(); + } + tOut.reset(); + } + + /** + * Return the transcript so far, + * + * @return a copy of the randomness produced so far. + */ + public byte[] getTranscript() + { + return tOut.toByteArray(); + } + + /** + * Return the full transcript, such as would be needed to create a copy of this JournalingSecureRandom, + * + * @return a copy of the original transcript on construction, plus any randomness added since. + */ + public byte[] getFullTranscript() + { + if (index == transcript.length) + { + return tOut.toByteArray(); + } + return Arrays.clone(transcript); + } + + private class TranscriptStream + extends ByteArrayOutputStream + { + public void clear() + { + Arrays.fill(buf, (byte)0); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/OpenSSHPrivateKeyUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/OpenSSHPrivateKeyUtil.java new file mode 100644 index 000000000..28e6f22e1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/OpenSSHPrivateKeyUtil.java @@ -0,0 +1,304 @@ +package com.fr.third.org.bouncycastle.crypto.util; + +import java.io.IOException; +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1TaggedObject; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.RSAPrivateKey; +import com.fr.third.org.bouncycastle.asn1.sec.ECPrivateKey; +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECNamedDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Strings; + + +/** + * A collection of utility methods for parsing OpenSSH private keys. + */ +public class OpenSSHPrivateKeyUtil +{ + private OpenSSHPrivateKeyUtil() + { + + } + + /** + * Magic value for proprietary OpenSSH private key. + **/ + static final byte[] AUTH_MAGIC = Strings.toByteArray("openssh-key-v1\0"); // C string so null terminated + + /** + * Encode a cipher parameters into an OpenSSH private key. + * This does not add headers like ----BEGIN RSA PRIVATE KEY---- + * + * @param params the cipher parameters. + * @return a byte array + */ + public static byte[] encodePrivateKey(AsymmetricKeyParameter params) + throws IOException + { + if (params == null) + { + throw new IllegalArgumentException("param is null"); + } + + if (params instanceof RSAPrivateCrtKeyParameters) + { + PrivateKeyInfo pInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(params); + + return pInfo.parsePrivateKey().toASN1Primitive().getEncoded(); + } + else if (params instanceof ECPrivateKeyParameters) + { + PrivateKeyInfo pInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(params); + + return pInfo.parsePrivateKey().toASN1Primitive().getEncoded(); + } + else if (params instanceof DSAPrivateKeyParameters) + { + DSAPrivateKeyParameters dsaPrivKey = (DSAPrivateKeyParameters)params; + DSAParameters dsaParams = dsaPrivKey.getParameters(); + + ASN1EncodableVector vec = new ASN1EncodableVector(); + vec.add(new ASN1Integer(0)); + vec.add(new ASN1Integer(dsaParams.getP())); + vec.add(new ASN1Integer(dsaParams.getQ())); + vec.add(new ASN1Integer(dsaParams.getG())); + + // public key = g.modPow(x, p); + BigInteger pubKey = dsaParams.getG().modPow(dsaPrivKey.getX(), dsaParams.getP()); + vec.add(new ASN1Integer(pubKey)); + + vec.add(new ASN1Integer(dsaPrivKey.getX())); + try + { + return new DERSequence(vec).getEncoded(); + } + catch (Exception ex) + { + throw new IllegalStateException("unable to encode DSAPrivateKeyParameters " + ex.getMessage()); + } + } + else if (params instanceof Ed25519PrivateKeyParameters) + { + Ed25519PublicKeyParameters publicKeyParameters = ((Ed25519PrivateKeyParameters)params).generatePublicKey(); + + SSHBuilder builder = new SSHBuilder(); + builder.writeBytes(AUTH_MAGIC); + builder.writeString("none"); // cipher name + builder.writeString("none"); // KDF name + builder.writeString(""); // KDF options + + builder.u32(1); // Number of keys + + { + byte[] pkEncoded = OpenSSHPublicKeyUtil.encodePublicKey(publicKeyParameters); + builder.writeBlock(pkEncoded); + } + + { + SSHBuilder pkBuild = new SSHBuilder(); + + int checkint = CryptoServicesRegistrar.getSecureRandom().nextInt(); + pkBuild.u32(checkint); + pkBuild.u32(checkint); + + pkBuild.writeString("ssh-ed25519"); + + // Public key (as part of private key pair) + byte[] pubKeyEncoded = publicKeyParameters.getEncoded(); + pkBuild.writeBlock(pubKeyEncoded); + + // The private key in SSH is 64 bytes long and is the concatenation of the private and the public keys + pkBuild.writeBlock(Arrays.concatenate(((Ed25519PrivateKeyParameters)params).getEncoded(), pubKeyEncoded)); + + pkBuild.writeString(""); // Comment for this private key (empty) + + builder.writeBlock(pkBuild.getPaddedBytes()); + } + + return builder.getBytes(); + } + + throw new IllegalArgumentException("unable to convert " + params.getClass().getName() + " to openssh private key"); + + } + + /** + * Parse a private key. + *

+ * This method accepts the body of the OpenSSH private key. + * The easiest way to extract the body is to use PemReader, for example: + *

+ * byte[] blob = new PemReader([reader]).readPemObject().getContent(); + * CipherParameters params = parsePrivateKeyBlob(blob); + * + * @param blob The key. + * @return A cipher parameters instance. + */ + public static AsymmetricKeyParameter parsePrivateKeyBlob(byte[] blob) + { + AsymmetricKeyParameter result = null; + + if (blob[0] == 0x30) + { + ASN1Sequence sequence = ASN1Sequence.getInstance(blob); + + if (sequence.size() == 6) + { + if (allIntegers(sequence) && ((ASN1Integer)sequence.getObjectAt(0)).getPositiveValue().equals(BigIntegers.ZERO)) + { + // length of 6 and all Integers -- DSA + result = new DSAPrivateKeyParameters( + ((ASN1Integer)sequence.getObjectAt(5)).getPositiveValue(), + new DSAParameters( + ((ASN1Integer)sequence.getObjectAt(1)).getPositiveValue(), + ((ASN1Integer)sequence.getObjectAt(2)).getPositiveValue(), + ((ASN1Integer)sequence.getObjectAt(3)).getPositiveValue()) + ); + } + } + else if (sequence.size() == 9) + { + if (allIntegers(sequence) && ((ASN1Integer)sequence.getObjectAt(0)).getPositiveValue().equals(BigIntegers.ZERO)) + { + // length of 8 and all Integers -- RSA + RSAPrivateKey rsaPrivateKey = RSAPrivateKey.getInstance(sequence); + + result = new RSAPrivateCrtKeyParameters( + rsaPrivateKey.getModulus(), + rsaPrivateKey.getPublicExponent(), + rsaPrivateKey.getPrivateExponent(), + rsaPrivateKey.getPrime1(), + rsaPrivateKey.getPrime2(), + rsaPrivateKey.getExponent1(), + rsaPrivateKey.getExponent2(), + rsaPrivateKey.getCoefficient()); + } + } + else if (sequence.size() == 4) + { + if (sequence.getObjectAt(3) instanceof ASN1TaggedObject + && sequence.getObjectAt(2) instanceof ASN1TaggedObject) + { + ECPrivateKey ecPrivateKey = ECPrivateKey.getInstance(sequence); + ASN1ObjectIdentifier curveOID = (ASN1ObjectIdentifier)ecPrivateKey.getParameters(); + X9ECParameters x9Params = ECNamedCurveTable.getByOID(curveOID); + result = new ECPrivateKeyParameters( + ecPrivateKey.getKey(), + new ECNamedDomainParameters( + curveOID, + x9Params.getCurve(), + x9Params.getG(), + x9Params.getN(), + x9Params.getH(), + x9Params.getSeed())); + } + } + } + else + { + SSHBuffer kIn = new SSHBuffer(AUTH_MAGIC, blob); + + String cipherName = kIn.readString(); + if (!"none".equals(cipherName)) + { + throw new IllegalStateException("encrypted keys not supported"); + } + + // KDF name + kIn.skipBlock(); + + // KDF options + kIn.skipBlock(); + + int publicKeyCount = kIn.readU32(); + if (publicKeyCount != 1) + { + throw new IllegalStateException("multiple keys not supported"); + } + + // Burn off public key. + OpenSSHPublicKeyUtil.parsePublicKey(kIn.readBlock()); + + byte[] privateKeyBlock = kIn.readPaddedBlock(); + + if (kIn.hasRemaining()) + { + throw new IllegalArgumentException("decoded key has trailing data"); + } + + SSHBuffer pkIn = new SSHBuffer(privateKeyBlock); + int check1 = pkIn.readU32(); + int check2 = pkIn.readU32(); + + if (check1 != check2) + { + throw new IllegalStateException("private key check values are not the same"); + } + + String keyType = pkIn.readString(); + if (!"ssh-ed25519".equals(keyType)) + { + throw new IllegalStateException("can not parse private key of type " + keyType); + } + + // Skip public key + pkIn.skipBlock(); + + byte[] edPrivateKey = pkIn.readBlock(); + if (edPrivateKey.length != Ed25519PrivateKeyParameters.KEY_SIZE + Ed25519PublicKeyParameters.KEY_SIZE) + { + throw new IllegalStateException("private key value of wrong length"); + } + + result = new Ed25519PrivateKeyParameters(edPrivateKey, 0); + + // Comment for private key + pkIn.skipBlock(); + + if (pkIn.hasRemaining()) + { + throw new IllegalArgumentException("private key block has trailing data"); + } + } + + if (result == null) + { + throw new IllegalArgumentException("unable to parse key"); + } + + return result; + } + + /** + * allIntegers returns true if the sequence holds only ASN1Integer types. + **/ + private static boolean allIntegers(ASN1Sequence sequence) + { + for (int t = 0; t < sequence.size(); t++) + { + if (!(sequence.getObjectAt(t) instanceof ASN1Integer)) + { + return false; + } + } + return true; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/OpenSSHPublicKeyUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/OpenSSHPublicKeyUtil.java new file mode 100644 index 000000000..9118f2f1b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/OpenSSHPublicKeyUtil.java @@ -0,0 +1,205 @@ +package com.fr.third.org.bouncycastle.crypto.util; + +import java.io.IOException; +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.custom.sec.SecP256R1Curve; + + +/** + * OpenSSHPublicKeyUtil utility classes for parsing OpenSSH public keys. + */ +public class OpenSSHPublicKeyUtil +{ + private OpenSSHPublicKeyUtil() + { + + } + + private static final String RSA = "ssh-rsa"; + private static final String ECDSA = "ecdsa"; + private static final String ED_25519 = "ssh-ed25519"; + private static final String DSS = "ssh-dss"; + + /** + * Parse a public key. + *

+ * This method accepts the bytes that are Base64 encoded in an OpenSSH public key file. + * + * @param encoded The key. + * @return An AsymmetricKeyParameter instance. + */ + public static AsymmetricKeyParameter parsePublicKey(byte[] encoded) + { + SSHBuffer buffer = new SSHBuffer(encoded); + return parsePublicKey(buffer); + } + + /** + * Encode a public key from an AsymmetricKeyParameter instance. + * + * @param cipherParameters The key to encode. + * @return the key OpenSSH encoded. + * @throws IOException + */ + public static byte[] encodePublicKey(AsymmetricKeyParameter cipherParameters) + throws IOException + { + if (cipherParameters == null) + { + throw new IllegalArgumentException("cipherParameters was null."); + } + + if (cipherParameters instanceof RSAKeyParameters) + { + if (cipherParameters.isPrivate()) + { + throw new IllegalArgumentException("RSAKeyParamaters was for encryption"); + } + + RSAKeyParameters rsaPubKey = (RSAKeyParameters)cipherParameters; + + SSHBuilder builder = new SSHBuilder(); + builder.writeString(RSA); + builder.writeBigNum(rsaPubKey.getExponent()); + builder.writeBigNum(rsaPubKey.getModulus()); + + return builder.getBytes(); + + } + else if (cipherParameters instanceof ECPublicKeyParameters) + { + SSHBuilder builder = new SSHBuilder(); + + String name = null; + if (((ECPublicKeyParameters)cipherParameters).getParameters().getCurve() instanceof SecP256R1Curve) + { + name = "nistp256"; + } + else + { + throw new IllegalArgumentException("unable to derive ssh curve name for " + ((ECPublicKeyParameters)cipherParameters).getParameters().getCurve().getClass().getName()); + } + + builder.writeString(ECDSA + "-sha2-" + name); // Magic + builder.writeString(name); + builder.writeBlock(((ECPublicKeyParameters)cipherParameters).getQ().getEncoded(false)); //Uncompressed + return builder.getBytes(); + } + else if (cipherParameters instanceof DSAPublicKeyParameters) + { + DSAPublicKeyParameters dsaPubKey = (DSAPublicKeyParameters)cipherParameters; + DSAParameters dsaParams = dsaPubKey.getParameters(); + + SSHBuilder builder = new SSHBuilder(); + builder.writeString(DSS); + builder.writeBigNum(dsaParams.getP()); + builder.writeBigNum(dsaParams.getQ()); + builder.writeBigNum(dsaParams.getG()); + builder.writeBigNum(dsaPubKey.getY()); + return builder.getBytes(); + } + else if (cipherParameters instanceof Ed25519PublicKeyParameters) + { + SSHBuilder builder = new SSHBuilder(); + builder.writeString(ED_25519); + builder.writeBlock(((Ed25519PublicKeyParameters)cipherParameters).getEncoded()); + return builder.getBytes(); + } + + throw new IllegalArgumentException("unable to convert " + cipherParameters.getClass().getName() + " to private key"); + } + + /** + * Parse a public key from an SSHBuffer instance. + * + * @param buffer containing the SSH public key. + * @return A CipherParameters instance. + */ + public static AsymmetricKeyParameter parsePublicKey(SSHBuffer buffer) + { + AsymmetricKeyParameter result = null; + + String magic = buffer.readString(); + if (RSA.equals(magic)) + { + BigInteger e = buffer.readBigNumPositive(); + BigInteger n = buffer.readBigNumPositive(); + result = new RSAKeyParameters(false, n, e); + } + else if (DSS.equals(magic)) + { + BigInteger p = buffer.readBigNumPositive(); + BigInteger q = buffer.readBigNumPositive(); + BigInteger g = buffer.readBigNumPositive(); + BigInteger pubKey = buffer.readBigNumPositive(); + + result = new DSAPublicKeyParameters(pubKey, new DSAParameters(p, q, g)); + } + else if (magic.startsWith(ECDSA)) + { + String curveName = buffer.readString(); + String nameToFind = curveName; + + if (curveName.startsWith("nist")) + { + // + // NIST names like P-256 are encoded in SSH as nistp256 + // + + nameToFind = curveName.substring(4); + nameToFind = nameToFind.substring(0, 1) + "-" + nameToFind.substring(1); + } + + X9ECParameters x9ECParameters = ECNamedCurveTable.getByName(nameToFind); + + if (x9ECParameters == null) + { + throw new IllegalStateException("unable to find curve for " + magic + " using curve name " + nameToFind); + } + + // + // Extract name of digest from magic string value; + // + //String digest = magic.split("-")[1]; + + ECCurve curve = x9ECParameters.getCurve(); + + byte[] pointRaw = buffer.readBlock(); + + result = new ECPublicKeyParameters(curve.decodePoint(pointRaw), new ECDomainParameters(curve, x9ECParameters.getG(), x9ECParameters.getN(), x9ECParameters.getH(), x9ECParameters.getSeed())); + } + else if (ED_25519.equals(magic)) + { + byte[] pubKeyBytes = buffer.readBlock(); + if (pubKeyBytes.length != Ed25519PublicKeyParameters.KEY_SIZE) + { + throw new IllegalStateException("public key value of wrong length"); + } + + result = new Ed25519PublicKeyParameters(pubKeyBytes, 0); + } + + if (result == null) + { + throw new IllegalArgumentException("unable to parse key"); + } + + if (buffer.hasRemaining()) + { + throw new IllegalArgumentException("decoded key has trailing data"); + } + + return result; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PrivateKeyFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PrivateKeyFactory.java index 54fa096a7..fa31ec720 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PrivateKeyFactory.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PrivateKeyFactory.java @@ -8,16 +8,24 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; +import com.fr.third.org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters; +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.oiw.ElGamalParameter; import com.fr.third.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.pkcs.DHParameter; import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import com.fr.third.org.bouncycastle.asn1.pkcs.RSAPrivateKey; +import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.sec.ECPrivateKey; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.DSAParameter; +import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; @@ -29,11 +37,17 @@ import com.fr.third.org.bouncycastle.crypto.params.DHPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; import com.fr.third.org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECGOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.ECNamedDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ElGamalParameters; import com.fr.third.org.bouncycastle.crypto.params.ElGamalPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.util.Arrays; /** * Factory for creating private key objects from PKCS8 PrivateKeyInfo objects. @@ -42,12 +56,13 @@ public class PrivateKeyFactory { /** * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding. - * + * * @param privateKeyInfoData the PrivateKeyInfo encoding * @return a suitable private key parameter * @throws IOException on an error decoding the key */ - public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) throws IOException + public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) + throws IOException { return createKey(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(privateKeyInfoData))); } @@ -55,28 +70,33 @@ public class PrivateKeyFactory /** * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding read from a * stream. - * + * * @param inStr the stream to read the PrivateKeyInfo encoding from * @return a suitable private key parameter * @throws IOException on an error decoding the key */ - public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException + public static AsymmetricKeyParameter createKey(InputStream inStr) + throws IOException { return createKey(PrivateKeyInfo.getInstance(new ASN1InputStream(inStr).readObject())); } /** * Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object. - * + * * @param keyInfo the PrivateKeyInfo object containing the key material * @return a suitable private key parameter * @throws IOException on an error decoding the key */ - public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) throws IOException + public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) + throws IOException { AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm(); + ASN1ObjectIdentifier algOID = algId.getAlgorithm(); - if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.rsaEncryption)) + if (algOID.equals(PKCSObjectIdentifiers.rsaEncryption) + || algOID.equals(PKCSObjectIdentifiers.id_RSASSA_PSS) + || algOID.equals(X509ObjectIdentifiers.id_ea_rsa)) { RSAPrivateKey keyStructure = RSAPrivateKey.getInstance(keyInfo.parsePrivateKey()); @@ -86,8 +106,8 @@ public class PrivateKeyFactory keyStructure.getExponent2(), keyStructure.getCoefficient()); } // TODO? -// else if (algId.getObjectId().equals(X9ObjectIdentifiers.dhpublicnumber)) - else if (algId.getAlgorithm().equals(PKCSObjectIdentifiers.dhKeyAgreement)) +// else if (algOID.equals(X9ObjectIdentifiers.dhpublicnumber)) + else if (algOID.equals(PKCSObjectIdentifiers.dhKeyAgreement)) { DHParameter params = DHParameter.getInstance(algId.getParameters()); ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey(); @@ -98,7 +118,7 @@ public class PrivateKeyFactory return new DHPrivateKeyParameters(derX.getValue(), dhParams); } - else if (algId.getAlgorithm().equals(OIWObjectIdentifiers.elGamalAlgorithm)) + else if (algOID.equals(OIWObjectIdentifiers.elGamalAlgorithm)) { ElGamalParameter params = ElGamalParameter.getInstance(algId.getParameters()); ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey(); @@ -106,7 +126,7 @@ public class PrivateKeyFactory return new ElGamalPrivateKeyParameters(derX.getValue(), new ElGamalParameters( params.getP(), params.getG())); } - else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_dsa)) + else if (algOID.equals(X9ObjectIdentifiers.id_dsa)) { ASN1Integer derX = (ASN1Integer)keyInfo.parsePrivateKey(); ASN1Encodable de = algId.getParameters(); @@ -120,9 +140,9 @@ public class PrivateKeyFactory return new DSAPrivateKeyParameters(derX.getValue(), parameters); } - else if (algId.getAlgorithm().equals(X9ObjectIdentifiers.id_ecPublicKey)) + else if (algOID.equals(X9ObjectIdentifiers.id_ecPublicKey)) { - X962Parameters params = new X962Parameters((ASN1Primitive)algId.getParameters()); + X962Parameters params = X962Parameters.getInstance(algId.getParameters()); X9ECParameters x9; ECDomainParameters dParams; @@ -151,9 +171,138 @@ public class PrivateKeyFactory return new ECPrivateKeyParameters(d, dParams); } + else if (algOID.equals(EdECObjectIdentifiers.id_X25519)) + { + return new X25519PrivateKeyParameters(getRawKey(keyInfo, X25519PrivateKeyParameters.KEY_SIZE), 0); + } + else if (algOID.equals(EdECObjectIdentifiers.id_X448)) + { + return new X448PrivateKeyParameters(getRawKey(keyInfo, X448PrivateKeyParameters.KEY_SIZE), 0); + } + else if (algOID.equals(EdECObjectIdentifiers.id_Ed25519)) + { + return new Ed25519PrivateKeyParameters(getRawKey(keyInfo, Ed25519PrivateKeyParameters.KEY_SIZE), 0); + } + else if (algOID.equals(EdECObjectIdentifiers.id_Ed448)) + { + return new Ed448PrivateKeyParameters(getRawKey(keyInfo, Ed448PrivateKeyParameters.KEY_SIZE), 0); + } + else if ( + algOID.equals(CryptoProObjectIdentifiers.gostR3410_2001) || + algOID.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512) || + algOID.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256)) + { + GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters()); + ECGOST3410Parameters ecSpec = null; + BigInteger d = null; + ASN1Primitive p = keyInfo.getPrivateKeyAlgorithm().getParameters().toASN1Primitive(); + if (p instanceof ASN1Sequence && (ASN1Sequence.getInstance(p).size() == 2 || ASN1Sequence.getInstance(p).size() == 3)) + { + + ECDomainParameters ecP = ECGOST3410NamedCurves.getByOID(gostParams.getPublicKeyParamSet()); + + ecSpec = new ECGOST3410Parameters( + new ECNamedDomainParameters( + gostParams.getPublicKeyParamSet(), ecP), + gostParams.getPublicKeyParamSet(), + gostParams.getDigestParamSet(), + gostParams.getEncryptionParamSet()); + ASN1Encodable privKey = keyInfo.parsePrivateKey(); + if (privKey instanceof ASN1Integer) + { + d = ASN1Integer.getInstance(privKey).getPositiveValue(); + } + else + { + byte[] dVal = Arrays.reverse(ASN1OctetString.getInstance(privKey).getOctets()); + d = new BigInteger(1, dVal); + } + } + else + { + X962Parameters params = X962Parameters.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters()); + + if (params.isNamedCurve()) + { + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); + X9ECParameters ecP = ECNamedCurveTable.getByOID(oid); + if (ecP == null) + { + ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid); + ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters( + oid, + gParam.getCurve(), + gParam.getG(), + gParam.getN(), + gParam.getH(), + gParam.getSeed()), gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet()); + } + else + { + ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters( + oid, + ecP.getCurve(), + ecP.getG(), + ecP.getN(), + ecP.getH(), + ecP.getSeed()), gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet()); + } + } + else if (params.isImplicitlyCA()) + { + ecSpec = null; + } + else + { + X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); + ecSpec = new ECGOST3410Parameters(new ECNamedDomainParameters( + algOID, + ecP.getCurve(), + ecP.getG(), + ecP.getN(), + ecP.getH(), + ecP.getSeed()), gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet()); + } + + ASN1Encodable privKey = keyInfo.parsePrivateKey(); + if (privKey instanceof ASN1Integer) + { + ASN1Integer derD = ASN1Integer.getInstance(privKey); + + d = derD.getValue(); + } + else + { + com.fr.third.org.bouncycastle.asn1.sec.ECPrivateKey ec = com.fr.third.org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(privKey); + + d = ec.getKey(); + } + + } + + return new ECPrivateKeyParameters( + d, + new ECGOST3410Parameters( + ecSpec, + gostParams.getPublicKeyParamSet(), + gostParams.getDigestParamSet(), + gostParams.getEncryptionParamSet())); + + } else { - throw new RuntimeException("algorithm identifier in key not recognised"); + throw new RuntimeException("algorithm identifier in private key not recognised"); + } + } + + private static byte[] getRawKey(PrivateKeyInfo keyInfo, int expectedSize) + throws IOException + { + byte[] result = ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(); + if (expectedSize != result.length) + { + throw new RuntimeException("private key encoding has incorrect length"); } + return result; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java index db2df5144..e20ef3686 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PrivateKeyInfoFactory.java @@ -1,33 +1,63 @@ package com.fr.third.org.bouncycastle.crypto.util; import java.io.IOException; +import java.math.BigInteger; +import java.util.HashSet; +import java.util.Set; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Set; +import com.fr.third.org.bouncycastle.asn1.DERBitString; import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters; +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import com.fr.third.org.bouncycastle.asn1.pkcs.RSAPrivateKey; +import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.sec.ECPrivateKey; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.DSAParameter; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; import com.fr.third.org.bouncycastle.crypto.params.DSAPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECGOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.ECNamedDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; /** * Factory to create ASN.1 private key info objects from lightweight private keys. */ public class PrivateKeyInfoFactory { + private static Set cryptoProOids = new HashSet(5); + + static + { + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB); + } + private PrivateKeyInfoFactory() { @@ -37,23 +67,42 @@ public class PrivateKeyInfoFactory * Create a PrivateKeyInfo representation of a private key. * * @param privateKey the key to be encoded into the info object. - * @return the appropriate key parameter + * @return the appropriate PrivateKeyInfo + * @throws java.io.IOException on an error encoding the key + */ + public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey) + throws IOException + { + return createPrivateKeyInfo(privateKey, null); + } + + /** + * Create a PrivateKeyInfo representation of a private key with attributes. + * + * @param privateKey the key to be encoded into the info object. + * @param attributes the set of attributes to be included. + * @return the appropriate PrivateKeyInfo * @throws java.io.IOException on an error encoding the key */ - public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey) throws IOException + public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey, ASN1Set attributes) + throws IOException { if (privateKey instanceof RSAKeyParameters) { RSAPrivateCrtKeyParameters priv = (RSAPrivateCrtKeyParameters)privateKey; - return new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new RSAPrivateKey(priv.getModulus(), priv.getPublicExponent(), priv.getExponent(), priv.getP(), priv.getQ(), priv.getDP(), priv.getDQ(), priv.getQInv())); + return new PrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), + new RSAPrivateKey(priv.getModulus(), priv.getPublicExponent(), priv.getExponent(), priv.getP(), priv.getQ(), priv.getDP(), priv.getDQ(), priv.getQInv()), + attributes); } else if (privateKey instanceof DSAPrivateKeyParameters) { DSAPrivateKeyParameters priv = (DSAPrivateKeyParameters)privateKey; DSAParameters params = priv.getParameters(); - return new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, new DSAParameter(params.getP(), params.getQ(), params.getG())), new ASN1Integer(priv.getX())); + return new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa, + new DSAParameter(params.getP(), params.getQ(), params.getG())), new ASN1Integer(priv.getX()), + attributes); } else if (privateKey instanceof ECPrivateKeyParameters) { @@ -67,6 +116,37 @@ public class PrivateKeyInfoFactory params = new X962Parameters(DERNull.INSTANCE); // Implicitly CA orderBitLength = priv.getD().bitLength(); // TODO: this is as good as currently available, must be a better way... } + else if (domainParams instanceof ECGOST3410Parameters) + { + GOST3410PublicKeyAlgParameters gostParams = new GOST3410PublicKeyAlgParameters( + ((ECGOST3410Parameters)domainParams).getPublicKeyParamSet(), + ((ECGOST3410Parameters)domainParams).getDigestParamSet(), + ((ECGOST3410Parameters)domainParams).getEncryptionParamSet()); + + + int size; + ASN1ObjectIdentifier identifier; + + if (cryptoProOids.contains(gostParams.getPublicKeyParamSet())) + { + size = 32; + identifier = CryptoProObjectIdentifiers.gostR3410_2001; + } + else + { + + boolean is512 = priv.getD().bitLength() > 256; + identifier = (is512) ? + RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512 : + RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256; + size = (is512) ? 64 : 32; + } + byte[] encKey = new byte[size]; + + extractBytes(encKey, size, 0, priv.getD()); + + return new PrivateKeyInfo(new AlgorithmIdentifier(identifier, gostParams), new DEROctetString(encKey)); + } else if (domainParams instanceof ECNamedDomainParameters) { params = new X962Parameters(((ECNamedDomainParameters)domainParams).getName()); @@ -76,7 +156,7 @@ public class PrivateKeyInfoFactory { X9ECParameters ecP = new X9ECParameters( domainParams.getCurve(), - domainParams.getG(), + new X9ECPoint(domainParams.getG(), false), domainParams.getN(), domainParams.getH(), domainParams.getSeed()); @@ -85,11 +165,64 @@ public class PrivateKeyInfoFactory orderBitLength = domainParams.getN().bitLength(); } - return new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), new ECPrivateKey(orderBitLength, priv.getD(), params)); + ECPoint q = new FixedPointCombMultiplier().multiply(domainParams.getG(), priv.getD()); + + // TODO Support point compression + DERBitString publicKey = new DERBitString(q.getEncoded(false)); + + return new PrivateKeyInfo( + new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), + new ECPrivateKey(orderBitLength, priv.getD(), publicKey, params), + attributes); + } + else if (privateKey instanceof X448PrivateKeyParameters) + { + X448PrivateKeyParameters key = (X448PrivateKeyParameters)privateKey; + + return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448), + new DEROctetString(key.getEncoded()), attributes, key.generatePublicKey().getEncoded()); + } + else if (privateKey instanceof X25519PrivateKeyParameters) + { + X25519PrivateKeyParameters key = (X25519PrivateKeyParameters)privateKey; + + return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519), + new DEROctetString(key.getEncoded()), attributes, key.generatePublicKey().getEncoded()); + } + else if (privateKey instanceof Ed448PrivateKeyParameters) + { + Ed448PrivateKeyParameters key = (Ed448PrivateKeyParameters)privateKey; + + return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448), + new DEROctetString(key.getEncoded()), attributes, key.generatePublicKey().getEncoded()); + } + else if (privateKey instanceof Ed25519PrivateKeyParameters) + { + Ed25519PrivateKeyParameters key = (Ed25519PrivateKeyParameters)privateKey; + + return new PrivateKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), + new DEROctetString(key.getEncoded()), attributes, key.generatePublicKey().getEncoded()); } else { - throw new IOException("key parameters not recognised."); + throw new IOException("key parameters not recognized"); + } + } + + + private static void extractBytes(byte[] encKey, int size, int offSet, BigInteger bI) + { + byte[] val = bI.toByteArray(); + if (val.length < size) + { + byte[] tmp = new byte[size]; + System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length); + val = tmp; + } + + for (int i = 0; i != size; i++) + { + encKey[offSet + i] = val[val.length - 1 - i]; } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PublicKeyFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PublicKeyFactory.java index bfa9076ac..60c644ebb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PublicKeyFactory.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/PublicKeyFactory.java @@ -17,6 +17,7 @@ import com.fr.third.org.bouncycastle.asn1.DEROctetString; import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; import com.fr.third.org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters; +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.oiw.ElGamalParameter; import com.fr.third.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.pkcs.DHParameter; @@ -50,12 +51,19 @@ import com.fr.third.org.bouncycastle.crypto.params.DHValidationParameters; import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; import com.fr.third.org.bouncycastle.crypto.params.DSAPublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECGOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.ECNamedDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ElGamalParameters; import com.fr.third.org.bouncycastle.crypto.params.ElGamalPublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448PublicKeyParameters; import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.Arrays; /** * Factory to create asymmetric public key parameters for asymmetric ciphers from range of @@ -68,6 +76,7 @@ public class PublicKeyFactory static { converters.put(PKCSObjectIdentifiers.rsaEncryption, new RSAConverter()); + converters.put(PKCSObjectIdentifiers.id_RSASSA_PSS, new RSAConverter()); converters.put(X509ObjectIdentifiers.id_ea_rsa, new RSAConverter()); converters.put(X9ObjectIdentifiers.dhpublicnumber, new DHPublicNumberConverter()); converters.put(PKCSObjectIdentifiers.dhKeyAgreement, new DHAgreementConverter()); @@ -80,6 +89,10 @@ public class PublicKeyFactory converters.put(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512, new GOST3410_2012Converter()); converters.put(UAObjectIdentifiers.dstu4145be, new DSTUConverter()); converters.put(UAObjectIdentifiers.dstu4145le, new DSTUConverter()); + converters.put(EdECObjectIdentifiers.id_X25519, new X25519Converter()); + converters.put(EdECObjectIdentifiers.id_X448, new X448Converter()); + converters.put(EdECObjectIdentifiers.id_Ed25519, new Ed25519Converter()); + converters.put(EdECObjectIdentifiers.id_Ed448, new Ed448Converter()); } /** @@ -124,7 +137,7 @@ public class PublicKeyFactory /** * Create a public key from the passed in SubjectPublicKeyInfo * - * @param keyInfo the SubjectPublicKeyInfo containing the key data + * @param keyInfo the SubjectPublicKeyInfo containing the key data * @param defaultParams default parameters that might be needed. * @return the appropriate key parameter * @throws IOException on an error decoding the key @@ -132,17 +145,15 @@ public class PublicKeyFactory public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo, Object defaultParams) throws IOException { - AlgorithmIdentifier algId = keyInfo.getAlgorithm(); - SubjectPublicKeyInfoConverter converter = (SubjectPublicKeyInfoConverter)converters.get(algId.getAlgorithm()); + AlgorithmIdentifier algID = keyInfo.getAlgorithm(); - if (converter != null) - { - return converter.getPublicKeyParameters(keyInfo, defaultParams); - } - else + SubjectPublicKeyInfoConverter converter = (SubjectPublicKeyInfoConverter)converters.get(algID.getAlgorithm()); + if (null == converter) { - throw new IOException("algorithm identifier in key not recognised: " + algId.getAlgorithm()); + throw new IOException("algorithm identifier in public key not recognised: " + algID.getAlgorithm()); } + + return converter.getPublicKeyParameters(keyInfo, defaultParams); } private static abstract class SubjectPublicKeyInfoConverter @@ -283,8 +294,8 @@ public class PublicKeyFactory x9.getCurve(), x9.getG(), x9.getN(), x9.getH(), x9.getSeed()); } - DERBitString bits = keyInfo.getPublicKeyData(); - byte[] data = bits.getBytes(); + DERBitString bits = keyInfo.getPublicKeyData(); + byte[] data = bits.getBytes(); ASN1OctetString key = new DEROctetString(data); // @@ -319,42 +330,47 @@ public class PublicKeyFactory { AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) { - DERBitString bits = keyInfo.getPublicKeyData(); - ASN1OctetString key; + AlgorithmIdentifier algID = keyInfo.getAlgorithm(); +// ASN1ObjectIdentifier algOid = algID.getAlgorithm(); + GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(algID.getParameters()); + ASN1ObjectIdentifier publicKeyParamSet = gostParams.getPublicKeyParamSet(); + + ECGOST3410Parameters ecDomainParameters = new ECGOST3410Parameters( + new ECNamedDomainParameters(publicKeyParamSet, ECGOST3410NamedCurves.getByOID(publicKeyParamSet)), + publicKeyParamSet, + gostParams.getDigestParamSet(), + gostParams.getEncryptionParamSet()); + ASN1OctetString key; try { - key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes()); + key = (ASN1OctetString)keyInfo.parsePublicKey(); } catch (IOException ex) { - throw new IllegalArgumentException("error recovering public key"); + throw new IllegalArgumentException("error recovering GOST3410_2001 public key"); } - byte[] keyEnc = key.getOctets(); + int fieldSize = 32; + int keySize = 2 * fieldSize; - byte[] x9Encoding = new byte[65]; - x9Encoding[0] = 0x04; - for (int i = 1; i <= 32; ++i) + byte[] keyEnc = key.getOctets(); + if (keyEnc.length != keySize) { - x9Encoding[i] = keyEnc[32 - i]; - x9Encoding[i + 32] = keyEnc[64 - i]; + throw new IllegalArgumentException("invalid length for GOST3410_2001 public key"); } - ASN1ObjectIdentifier paramOID; - - if (keyInfo.getAlgorithm().getParameters() instanceof ASN1ObjectIdentifier) - { - paramOID = ASN1ObjectIdentifier.getInstance(keyInfo.getAlgorithm().getParameters()); - } - else + byte[] x9Encoding = new byte[1 + keySize]; + x9Encoding[0] = 0x04; + for (int i = 1; i <= fieldSize; ++i) { - GOST3410PublicKeyAlgParameters params = GOST3410PublicKeyAlgParameters.getInstance(keyInfo.getAlgorithm().getParameters()); - paramOID = params.getPublicKeyParamSet(); + x9Encoding[i] = keyEnc[fieldSize - i]; + x9Encoding[i + fieldSize] = keyEnc[keySize - i]; } - ECDomainParameters ecDomainParameters = ECGOST3410NamedCurves.getByOID(paramOID); - return new ECPublicKeyParameters(ecDomainParameters.getCurve().decodePoint(x9Encoding), ecDomainParameters); + ECPoint q = ecDomainParameters.getCurve().decodePoint(x9Encoding); + + return new ECPublicKeyParameters(q, ecDomainParameters); } } @@ -363,29 +379,40 @@ public class PublicKeyFactory { AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) { - ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm(); - DERBitString bits = keyInfo.getPublicKeyData(); - ASN1OctetString key; + AlgorithmIdentifier algID = keyInfo.getAlgorithm(); + ASN1ObjectIdentifier algOid = algID.getAlgorithm(); + GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(algID.getParameters()); + ASN1ObjectIdentifier publicKeyParamSet = gostParams.getPublicKeyParamSet(); + + ECGOST3410Parameters ecDomainParameters = new ECGOST3410Parameters( + new ECNamedDomainParameters(publicKeyParamSet, ECGOST3410NamedCurves.getByOID(publicKeyParamSet)), + publicKeyParamSet, + gostParams.getDigestParamSet(), + gostParams.getEncryptionParamSet()); + ASN1OctetString key; try { - key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes()); + key = (ASN1OctetString)keyInfo.parsePublicKey(); } catch (IOException ex) { - throw new IllegalArgumentException("error recovering public key"); + throw new IllegalArgumentException("error recovering GOST3410_2012 public key"); } - byte[] keyEnc = key.getOctets(); - int fieldSize = 32; if (algOid.equals(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512)) { fieldSize = 64; } - int keySize = 2 * fieldSize; + byte[] keyEnc = key.getOctets(); + if (keyEnc.length != keySize) + { + throw new IllegalArgumentException("invalid length for GOST3410_2012 public key"); + } + byte[] x9Encoding = new byte[1 + keySize]; x9Encoding[0] = 0x04; for (int i = 1; i <= fieldSize; ++i) @@ -394,10 +421,9 @@ public class PublicKeyFactory x9Encoding[i + fieldSize] = keyEnc[keySize - i]; } - GOST3410PublicKeyAlgParameters gostParams = GOST3410PublicKeyAlgParameters.getInstance(keyInfo.getAlgorithm().getParameters()); + ECPoint q = ecDomainParameters.getCurve().decodePoint(x9Encoding); - ECDomainParameters ecDomainParameters = ECGOST3410NamedCurves.getByOID(gostParams.getPublicKeyParamSet()); - return new ECPublicKeyParameters(ecDomainParameters.getCurve().decodePoint(x9Encoding), ecDomainParameters); + return new ECPublicKeyParameters(q, ecDomainParameters); } } @@ -407,53 +433,55 @@ public class PublicKeyFactory AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) throws IOException { - DERBitString bits = keyInfo.getPublicKeyData(); - ASN1OctetString key; + AlgorithmIdentifier algID = keyInfo.getAlgorithm(); + ASN1ObjectIdentifier algOid = algID.getAlgorithm(); + DSTU4145Params dstuParams = DSTU4145Params.getInstance(algID.getParameters()); + ASN1OctetString key; try { - key = (ASN1OctetString)ASN1Primitive.fromByteArray(bits.getBytes()); + key = (ASN1OctetString)keyInfo.parsePublicKey(); } catch (IOException ex) { - throw new IllegalArgumentException("error recovering public key"); + throw new IllegalArgumentException("error recovering DSTU public key"); } - byte[] keyEnc = key.getOctets(); + byte[] keyEnc = Arrays.clone(key.getOctets()); - if (keyInfo.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + if (algOid.equals(UAObjectIdentifiers.dstu4145le)) { reverseBytes(keyEnc); } - DSTU4145Params dstuParams = DSTU4145Params.getInstance(keyInfo.getAlgorithm().getParameters()); - ECDomainParameters ecDomain; if (dstuParams.isNamedCurve()) { - ASN1ObjectIdentifier curveOid = dstuParams.getNamedCurve(); - - ecDomain = DSTU4145NamedCurves.getByOID(curveOid); + ecDomain = DSTU4145NamedCurves.getByOID(dstuParams.getNamedCurve()); } else { DSTU4145ECBinary binary = dstuParams.getECBinary(); byte[] b_bytes = binary.getB(); - if (keyInfo.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + if (algOid.equals(UAObjectIdentifiers.dstu4145le)) { reverseBytes(b_bytes); } + BigInteger b = new BigInteger(1, b_bytes); DSTU4145BinaryField field = binary.getField(); - ECCurve curve = new ECCurve.F2m(field.getM(), field.getK1(), field.getK2(), field.getK3(), binary.getA(), new BigInteger(1, b_bytes)); + ECCurve curve = new ECCurve.F2m(field.getM(), field.getK1(), field.getK2(), field.getK3(), binary.getA(), b); byte[] g_bytes = binary.getG(); - if (keyInfo.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + if (algOid.equals(UAObjectIdentifiers.dstu4145le)) { reverseBytes(g_bytes); } - ecDomain = new ECDomainParameters(curve, DSTU4145PointEncoder.decodePoint(curve, g_bytes), binary.getN()); + ECPoint g = DSTU4145PointEncoder.decodePoint(curve, g_bytes); + ecDomain = new ECDomainParameters(curve, g, binary.getN()); } - return new ECPublicKeyParameters(DSTU4145PointEncoder.decodePoint(ecDomain.getCurve(), keyEnc), ecDomain); + ECPoint q = DSTU4145PointEncoder.decodePoint(ecDomain.getCurve(), keyEnc); + + return new ECPublicKeyParameters(q, ecDomain); } private void reverseBytes(byte[] bytes) @@ -468,4 +496,55 @@ public class PublicKeyFactory } } } + + private static class X25519Converter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + return new X25519PublicKeyParameters(getRawKey(keyInfo, defaultParams, X25519PublicKeyParameters.KEY_SIZE), 0); + } + } + + private static class X448Converter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + return new X448PublicKeyParameters(getRawKey(keyInfo, defaultParams, X448PublicKeyParameters.KEY_SIZE), 0); + } + } + + private static class Ed25519Converter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + return new Ed25519PublicKeyParameters(getRawKey(keyInfo, defaultParams, Ed25519PublicKeyParameters.KEY_SIZE), 0); + } + } + + private static class Ed448Converter + extends SubjectPublicKeyInfoConverter + { + AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams) + { + return new Ed448PublicKeyParameters(getRawKey(keyInfo, defaultParams, Ed448PublicKeyParameters.KEY_SIZE), 0); + } + } + + private static byte[] getRawKey(SubjectPublicKeyInfo keyInfo, Object defaultParams, int expectedSize) + { + /* + * TODO[RFC 8422] + * - Require defaultParams == null? + * - Require keyInfo.getAlgorithm().getParameters() == null? + */ + byte[] result = keyInfo.getPublicKeyData().getOctets(); + if (expectedSize != result.length) + { + throw new RuntimeException("public key encoding has incorrect length"); + } + return result; + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/SSHBuffer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/SSHBuffer.java new file mode 100644 index 000000000..ebaa1b428 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/SSHBuffer.java @@ -0,0 +1,154 @@ +package com.fr.third.org.bouncycastle.crypto.util; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; + +/** + * A Buffer for dealing with SSH key products. + */ +class SSHBuffer +{ + private final byte[] buffer; + private int pos = 0; + + public SSHBuffer(byte[] magic, byte[] buffer) + { + this.buffer = buffer; + for (int i = 0; i != magic.length; i++) + { + if (magic[i] != buffer[i]) + { + throw new IllegalArgumentException("magic-number incorrect"); + } + } + + pos += magic.length; + } + + public SSHBuffer(byte[] buffer) + { + this.buffer = buffer; + } + + public int readU32() + { + if (pos > (buffer.length - 4)) + { + throw new IllegalArgumentException("4 bytes for U32 exceeds buffer."); + } + + int i = (buffer[pos++] & 0xFF) << 24; + i |= (buffer[pos++] & 0xFF) << 16; + i |= (buffer[pos++] & 0xFF) << 8; + i |= (buffer[pos++] & 0xFF); + + return i; + } + + public String readString() + { + return Strings.fromByteArray(readBlock()); + } + + public byte[] readBlock() + { + int len = readU32(); + if (len == 0) + { + return new byte[0]; + } + + if (pos > (buffer.length - len)) + { + throw new IllegalArgumentException("not enough data for block"); + } + + int start = pos; pos += len; + return Arrays.copyOfRange(buffer, start, pos); + } + + public void skipBlock() + { + int len = readU32(); + if (pos > (buffer.length - len)) + { + throw new IllegalArgumentException("not enough data for block"); + } + + pos += len; + } + + public byte[] readPaddedBlock() + { + return readPaddedBlock(8); + } + + public byte[] readPaddedBlock(int blockSize) + { + int len = readU32(); + if (len == 0) + { + return new byte[0]; + } + + if (pos > (buffer.length - len)) + { + throw new IllegalArgumentException("not enough data for block"); + } + + int align = len % blockSize; + if (0 != align) + { + throw new IllegalArgumentException("missing padding"); + } + + int start = pos; pos += len; + int end = pos; + + if (len > 0) + { + // TODO If encryption is supported, should be constant-time + int lastByte = buffer[pos - 1] & 0xFF; + if (0 < lastByte && lastByte < blockSize) + { + int padCount = lastByte; + end -= padCount; + + for (int i = 1, padPos = end; i <= padCount; ++i, ++padPos) + { + if (i != (buffer[padPos] & 0xFF)) + { + throw new IllegalArgumentException("incorrect padding"); + } + } + } + } + + return Arrays.copyOfRange(buffer, start, end); + } + + public BigInteger readBigNumPositive() + { + int len = readU32(); + if (pos + len > buffer.length) + { + throw new IllegalArgumentException("not enough data for big num"); + } + + int start = pos; pos += len; + byte[] d = Arrays.copyOfRange(buffer, start, pos); + return new BigInteger(1, d); + } + + public byte[] getBuffer() + { + return Arrays.clone(buffer); + } + + public boolean hasRemaining() + { + return pos < buffer.length; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/SSHBuilder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/SSHBuilder.java new file mode 100644 index 000000000..11892e8e4 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/SSHBuilder.java @@ -0,0 +1,79 @@ +package com.fr.third.org.bouncycastle.crypto.util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.util.Strings; + +class SSHBuilder +{ + private final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + + public void u32(int value) + { + bos.write((value >>> 24) & 0xFF); + bos.write((value >>> 16) & 0xFF); + bos.write((value >>> 8) & 0xFF); + bos.write(value & 0xFF); + } + + public void writeBigNum(BigInteger n) + { + writeBlock(n.toByteArray()); + } + + public void writeBlock(byte[] value) + { + u32(value.length); + try + { + bos.write(value); + } + catch (IOException e) + { + throw new IllegalStateException(e.getMessage(), e); + } + } + + public void writeBytes(byte[] value) + { + try + { + bos.write(value); + } + catch (IOException e) + { + throw new IllegalStateException(e.getMessage(), e); + } + } + + public void writeString(String str) + { + writeBlock(Strings.toByteArray(str)); + } + + public byte[] getBytes() + { + return bos.toByteArray(); + } + + public byte[] getPaddedBytes() + { + return getPaddedBytes(8); + } + + public byte[] getPaddedBytes(int blockSize) + { + int align = bos.size() % blockSize; + if (0 != align) + { + int padCount = blockSize - align; + for (int i = 1; i <= padCount; ++i) + { + bos.write(i); + } + } + return bos.toByteArray(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java index a8df7b76d..cb2504299 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/crypto/util/SubjectPublicKeyInfoFactory.java @@ -1,13 +1,22 @@ package com.fr.third.org.bouncycastle.crypto.util; import java.io.IOException; +import java.math.BigInteger; +import java.util.HashSet; +import java.util.Set; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters; +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.pkcs.RSAPublicKey; +import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.DSAParameter; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; @@ -19,15 +28,31 @@ import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; import com.fr.third.org.bouncycastle.crypto.params.DSAPublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECGOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.ECNamedDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PublicKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448PublicKeyParameters; /** * Factory to create ASN.1 subject public key info objects from lightweight public keys. */ public class SubjectPublicKeyInfoFactory { + private static Set cryptoProOids = new HashSet(5); + + static + { + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_A); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_B); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_C); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchA); + cryptoProOids.add(CryptoProObjectIdentifiers.gostR3410_2001_CryptoPro_XchB); + } + private SubjectPublicKeyInfoFactory() { @@ -40,7 +65,8 @@ public class SubjectPublicKeyInfoFactory * @return a SubjectPublicKeyInfo representing the key. * @throws java.io.IOException on an error encoding the key */ - public static SubjectPublicKeyInfo createSubjectPublicKeyInfo(AsymmetricKeyParameter publicKey) throws IOException + public static SubjectPublicKeyInfo createSubjectPublicKeyInfo(AsymmetricKeyParameter publicKey) + throws IOException { if (publicKey instanceof RSAKeyParameters) { @@ -65,12 +91,62 @@ public class SubjectPublicKeyInfoFactory { ECPublicKeyParameters pub = (ECPublicKeyParameters)publicKey; ECDomainParameters domainParams = pub.getParameters(); - ASN1Encodable params; + ASN1Encodable params; if (domainParams == null) { params = new X962Parameters(DERNull.INSTANCE); // Implicitly CA } + else if (domainParams instanceof ECGOST3410Parameters) + { + ECGOST3410Parameters gostParams = (ECGOST3410Parameters)domainParams; + + BigInteger bX = pub.getQ().getAffineXCoord().toBigInteger(); + BigInteger bY = pub.getQ().getAffineYCoord().toBigInteger(); + + params = new GOST3410PublicKeyAlgParameters(gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet()); + + int encKeySize; + int offset; + ASN1ObjectIdentifier algIdentifier; + + + if (cryptoProOids.contains(gostParams.getPublicKeyParamSet())) + { + encKeySize = 64; + offset = 32; + algIdentifier = CryptoProObjectIdentifiers.gostR3410_2001; + } + else + { + boolean is512 = (bX.bitLength() > 256); + if (is512) + { + encKeySize = 128; + offset = 64; + algIdentifier = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512; + } + else + { + encKeySize = 64; + offset = 32; + algIdentifier = RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256; + } + } + + byte[] encKey = new byte[encKeySize]; + extractBytes(encKey, encKeySize / 2, 0, bX); + extractBytes(encKey, encKeySize / 2, offset, bY); + + try + { + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(algIdentifier, params), new DEROctetString(encKey)); + } + catch (IOException e) + { + return null; + } + } else if (domainParams instanceof ECNamedDomainParameters) { params = new X962Parameters(((ECNamedDomainParameters)domainParams).getName()); @@ -79,7 +155,8 @@ public class SubjectPublicKeyInfoFactory { X9ECParameters ecP = new X9ECParameters( domainParams.getCurve(), - domainParams.getG(), + // TODO Support point compression + new X9ECPoint(domainParams.getG(), false), domainParams.getN(), domainParams.getH(), domainParams.getSeed()); @@ -87,13 +164,54 @@ public class SubjectPublicKeyInfoFactory params = new X962Parameters(ecP); } - ASN1OctetString p = (ASN1OctetString)new X9ECPoint(pub.getQ()).toASN1Primitive(); + // TODO Support point compression + byte[] pubKeyOctets = pub.getQ().getEncoded(false); - return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), pubKeyOctets); + } + else if (publicKey instanceof X448PublicKeyParameters) + { + X448PublicKeyParameters key = (X448PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X448), key.getEncoded()); + } + else if (publicKey instanceof X25519PublicKeyParameters) + { + X25519PublicKeyParameters key = (X25519PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_X25519), key.getEncoded()); + } + else if (publicKey instanceof Ed448PublicKeyParameters) + { + Ed448PublicKeyParameters key = (Ed448PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed448), key.getEncoded()); + } + else if (publicKey instanceof Ed25519PublicKeyParameters) + { + Ed25519PublicKeyParameters key = (Ed25519PublicKeyParameters)publicKey; + + return new SubjectPublicKeyInfo(new AlgorithmIdentifier(EdECObjectIdentifiers.id_Ed25519), key.getEncoded()); } else { - throw new IOException("key parameters not recognised."); + throw new IOException("key parameters not recognized"); + } + } + + private static void extractBytes(byte[] encKey, int size, int offSet, BigInteger bI) + { + byte[] val = bI.toByteArray(); + if (val.length < size) + { + byte[] tmp = new byte[size]; + System.arraycopy(val, 0, tmp, tmp.length - val.length, val.length); + val = tmp; + } + + for (int i = 0; i != size; i++) + { + encKey[offSet + i] = val[val.length - 1 - i]; } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/BCFKSLoadStoreParameter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/BCFKSLoadStoreParameter.java new file mode 100644 index 000000000..bc61675d3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/BCFKSLoadStoreParameter.java @@ -0,0 +1,325 @@ +package com.fr.third.org.bouncycastle.jcajce; + +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Key; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.X509Certificate; + +import com.fr.third.org.bouncycastle.crypto.util.PBKDF2Config; +import com.fr.third.org.bouncycastle.crypto.util.PBKDFConfig; + +/** + * LoadStoreParameter to allow configuring of the PBKDF used to generate encryption keys for + * use in the keystore. + */ +public class BCFKSLoadStoreParameter + extends BCLoadStoreParameter +{ + public enum EncryptionAlgorithm + { + AES256_CCM, + AES256_KWP + } + + public enum MacAlgorithm + { + HmacSHA512, + HmacSHA3_512 + } + + public enum SignatureAlgorithm + { + SHA512withDSA, + SHA3_512withDSA, + SHA512withECDSA, + SHA3_512withECDSA, + SHA512withRSA, + SHA3_512withRSA + } + + public interface CertChainValidator + { + /** + * Return true if the passed in chain is valid, false otherwise. + * + * @param chain the certChain we know about, the end-entity is at position 0. + * @return true if valid, false otherwise. + */ + boolean isValid(X509Certificate[] chain); + } + + public static class Builder + { + private final OutputStream out; + private final InputStream in; + private final KeyStore.ProtectionParameter protectionParameter; + private final Key sigKey; + + private PBKDFConfig storeConfig = new PBKDF2Config.Builder() + .withIterationCount(16384) + .withSaltLength(64).withPRF(PBKDF2Config.PRF_SHA512).build(); + private EncryptionAlgorithm encAlg = EncryptionAlgorithm.AES256_CCM; + private MacAlgorithm macAlg = MacAlgorithm.HmacSHA512; + private SignatureAlgorithm sigAlg = SignatureAlgorithm.SHA512withECDSA; + private X509Certificate[] certs = null; + private CertChainValidator validator; + + + /** + * Base constructor for creating a LoadStoreParameter for initializing a key store. + */ + public Builder() + { + this((OutputStream)null, (KeyStore.ProtectionParameter)null); + } + + /** + * Base constructor for storing to an OutputStream using a password. + * + * @param out OutputStream to write KeyStore to. + * @param password the password to use to protect the KeyStore. + */ + public Builder(OutputStream out, char[] password) + { + this(out, new KeyStore.PasswordProtection(password)); + } + + /** + * Base constructor for storing to an OutputStream using a protection parameter. + * + * @param out OutputStream to write KeyStore to. + * @param protectionParameter the protection parameter to use to protect the KeyStore. + */ + public Builder(OutputStream out, KeyStore.ProtectionParameter protectionParameter) + { + this.in = null; + this.out = out; + this.protectionParameter = protectionParameter; + this.sigKey = null; + } + + /** + * Base constructor for storing to an OutputStream using a protection parameter. + * + * @param out OutputStream to write KeyStore to. + * @param sigKey the key used to protect the integrity of the key store. + */ + public Builder(OutputStream out, PrivateKey sigKey) + { + this.in = null; + this.out = out; + this.protectionParameter = null; + this.sigKey = sigKey; + } + + /** + * Base constructor for reading a KeyStore from an InputStream using a public key for validation. + * + * @param in InputStream to load KeyStore to. + * @param sigKey the public key parameter to used to verify the KeyStore. + */ + public Builder(InputStream in, PublicKey sigKey) + { + this.in = in; + this.out = null; + this.protectionParameter = null; + this.sigKey = sigKey; + } + + /** + * Base constructor for reading a KeyStore from an InputStream using validation based on + * encapsulated certificates in the KeyStore data. + * + * @param in InputStream to load KeyStore to. + * @param validator the certificate chain validator to check the signing certificates. + */ + public Builder(InputStream in, CertChainValidator validator) + { + this.in = in; + this.out = null; + this.protectionParameter = null; + this.validator = validator; + this.sigKey = null; + } + + /** + * Base constructor for reading a KeyStore from an InputStream using a password. + * + * @param in InputStream to read the KeyStore from. + * @param password the password used to protect the KeyStore. + */ + public Builder(InputStream in, char[] password) + { + this(in, new KeyStore.PasswordProtection(password)); + } + + /** + * Base constructor for reading a KeyStore from an InputStream using a password. + * + * @param in InputStream to read the KeyStore from. + * @param protectionParameter the protection parameter used to protect the KeyStore. + */ + public Builder(InputStream in, KeyStore.ProtectionParameter protectionParameter) + { + this.in = in; + this.out = null; + this.protectionParameter = protectionParameter; + this.sigKey = null; + } + + /** + * Configure the PBKDF to use for protecting the KeyStore. + * + * @param storeConfig the PBKDF config to use for protecting the KeyStore. + * @return the current Builder instance. + */ + public Builder withStorePBKDFConfig(PBKDFConfig storeConfig) + { + this.storeConfig = storeConfig; + return this; + } + + /** + * Configure the encryption algorithm to use for protecting the KeyStore and its keys. + * + * @param encAlg the PBKDF config to use for protecting the KeyStore and its keys. + * @return the current Builder instance. + */ + public Builder withStoreEncryptionAlgorithm(EncryptionAlgorithm encAlg) + { + this.encAlg = encAlg; + return this; + } + + /** + * Configure the MAC algorithm to use for protecting the KeyStore. + * + * @param macAlg the PBKDF config to use for protecting the KeyStore. + * @return the current Builder instance. + */ + public Builder withStoreMacAlgorithm(MacAlgorithm macAlg) + { + this.macAlg = macAlg; + return this; + } + + + /** + * Add a valid certificate chain where certs[0] is the end-entity matching the + * private key we are using to sign the key store. + * + * @param certs an array of X509 certificates. + * @return the current Builder instance. + */ + public Builder withCertificates(X509Certificate[] certs) + { + X509Certificate[] tmp = new X509Certificate[certs.length]; + System.arraycopy(certs, 0, tmp, 0, tmp.length); + this.certs = tmp; + + return this; + } + + /** + * Configure the signature algorithm to use for protecting the KeyStore. + * + * @param sigAlg the signature config to use for protecting the KeyStore. + * @return the current Builder instance. + */ + public Builder withStoreSignatureAlgorithm(SignatureAlgorithm sigAlg) + { + this.sigAlg = sigAlg; + + return this; + } + + /** + * Build and return a BCFKSLoadStoreParameter. + * + * @return a new BCFKSLoadStoreParameter. + */ + public BCFKSLoadStoreParameter build() + { + return new BCFKSLoadStoreParameter(this); + } + } + + private final PBKDFConfig storeConfig; + private final EncryptionAlgorithm encAlg; + private final MacAlgorithm macAlg; + private final SignatureAlgorithm sigAlg; + private final Key sigKey; + private final X509Certificate[] certificates; + private final CertChainValidator validator; + + private BCFKSLoadStoreParameter(Builder bldr) + { + super(bldr.in, bldr.out, bldr.protectionParameter); + + this.storeConfig = bldr.storeConfig; + this.encAlg = bldr.encAlg; + this.macAlg = bldr.macAlg; + this.sigAlg = bldr.sigAlg; + this.sigKey = bldr.sigKey; + this.certificates = bldr.certs; + this.validator = bldr.validator; + } + + /** + * Return the PBKDF used for generating the HMAC and store encryption keys. + * + * @return the PBKDF to use for deriving HMAC and store encryption keys. + */ + public PBKDFConfig getStorePBKDFConfig() + { + return storeConfig; + } + + /** + * Return encryption algorithm used to secure the store and its entries. + * + * @return the encryption algorithm to use. + */ + public EncryptionAlgorithm getStoreEncryptionAlgorithm() + { + return encAlg; + } + + /** + * Return mac algorithm used to protect the integrity of the store and its contents. + * + * @return the mac algorithm to use. + */ + public MacAlgorithm getStoreMacAlgorithm() + { + return macAlg; + } + + /** + * Return signature algorithm used to protect the integrity of the store and its contents. + * + * @return the signature algorithm to use. + */ + public SignatureAlgorithm getStoreSignatureAlgorithm() + { + return sigAlg; + } + + public Key getStoreSignatureKey() + { + return sigKey; + } + + public X509Certificate[] getStoreCertificates() + { + return certificates; + } + + public CertChainValidator getCertChainValidator() + { + return validator; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/BCFKSStoreParameter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/BCFKSStoreParameter.java index d539552d6..c82d13e22 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/BCFKSStoreParameter.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/BCFKSStoreParameter.java @@ -8,6 +8,7 @@ import com.fr.third.org.bouncycastle.crypto.util.PBKDFConfig; /** * LoadStoreParameter to allow configuring of the PBKDF used to generate encryption keys for * use in the keystore. + * @deprecated This class does not support configuration on creation, use BCFKSLoadStoreParameter for best results. */ public class BCFKSStoreParameter implements KeyStore.LoadStoreParameter diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/BCLoadStoreParameter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/BCLoadStoreParameter.java new file mode 100644 index 000000000..f9848f72a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/BCLoadStoreParameter.java @@ -0,0 +1,71 @@ +package com.fr.third.org.bouncycastle.jcajce; + +import java.io.InputStream; +import java.io.OutputStream; +import java.security.KeyStore; + +public class BCLoadStoreParameter + implements KeyStore.LoadStoreParameter +{ + private final InputStream in; + private final OutputStream out; + private final KeyStore.ProtectionParameter protectionParameter; + + /** + * Base constructor for + * + * @param out + * @param password + */ + public BCLoadStoreParameter(OutputStream out, char[] password) + { + this(out, new KeyStore.PasswordProtection(password)); + } + + public BCLoadStoreParameter(InputStream in, char[] password) + { + this(in, new KeyStore.PasswordProtection(password)); + } + + public BCLoadStoreParameter(InputStream in, KeyStore.ProtectionParameter protectionParameter) + { + this(in, null, protectionParameter); + } + + public BCLoadStoreParameter(OutputStream out, KeyStore.ProtectionParameter protectionParameter) + { + this(null, out, protectionParameter); + } + + BCLoadStoreParameter(InputStream in, OutputStream out, KeyStore.ProtectionParameter protectionParameter) + { + this.in = in; + this.out = out; + this.protectionParameter = protectionParameter; + } + + public KeyStore.ProtectionParameter getProtectionParameter() + { + return protectionParameter; + } + + public OutputStream getOutputStream() + { + if (out == null) + { + throw new UnsupportedOperationException("parameter not configured for storage - no OutputStream"); + } + + return out; + } + + public InputStream getInputStream() + { + if (out != null) + { + throw new UnsupportedOperationException("parameter configured for storage OutputStream present"); + } + + return in; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/PKIXExtendedParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/PKIXExtendedParameters.java index 1d6e3df54..a5c930f28 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/PKIXExtendedParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/PKIXExtendedParameters.java @@ -337,4 +337,8 @@ public class PKIXExtendedParameters return revocationEnabled; } + public boolean getPolicyQualifiersRejected() + { + return baseParameters.getPolicyQualifiersRejected(); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/interfaces/BCX509Certificate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/interfaces/BCX509Certificate.java new file mode 100644 index 000000000..26fbb45be --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/interfaces/BCX509Certificate.java @@ -0,0 +1,11 @@ +package com.fr.third.org.bouncycastle.jcajce.interfaces; + +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.TBSCertificate; + +public interface BCX509Certificate +{ + X500Name getIssuerX500Name(); + TBSCertificate getTBSCertificateNative(); + X500Name getSubjectX500Name(); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/interfaces/EdDSAKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/interfaces/EdDSAKey.java new file mode 100644 index 000000000..729b9967b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/interfaces/EdDSAKey.java @@ -0,0 +1,8 @@ +package com.fr.third.org.bouncycastle.jcajce.interfaces; + +import java.security.Key; + +public interface EdDSAKey + extends Key +{ +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/interfaces/XDHKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/interfaces/XDHKey.java new file mode 100644 index 000000000..5ef5b2f01 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/interfaces/XDHKey.java @@ -0,0 +1,8 @@ +package com.fr.third.org.bouncycastle.jcajce.interfaces; + +import java.security.Key; + +public interface XDHKey + extends Key +{ +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/CipherInputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/CipherInputStream.java index c3a1cfa75..dc5d44f40 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/CipherInputStream.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/CipherInputStream.java @@ -90,8 +90,12 @@ public class CipherInputStream { try { - finalized = true; - return cipher.doFinal(); + if (!finalized) + { + finalized = true; + return cipher.doFinal(); + } + return null; } catch (GeneralSecurityException e) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/DigestUpdatingOutputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/DigestUpdatingOutputStream.java new file mode 100644 index 000000000..774f65e18 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/DigestUpdatingOutputStream.java @@ -0,0 +1,34 @@ +package com.fr.third.org.bouncycastle.jcajce.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.MessageDigest; + +class DigestUpdatingOutputStream + extends OutputStream +{ + private MessageDigest digest; + + DigestUpdatingOutputStream(MessageDigest digest) + { + this.digest = digest; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + digest.update(bytes, off, len); + } + + public void write(byte[] bytes) + throws IOException + { + digest.update(bytes); + } + + public void write(int b) + throws IOException + { + digest.update((byte)b); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/MacUpdatingOutputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/MacUpdatingOutputStream.java new file mode 100644 index 000000000..592cc71c3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/MacUpdatingOutputStream.java @@ -0,0 +1,35 @@ +package com.fr.third.org.bouncycastle.jcajce.io; + +import java.io.IOException; +import java.io.OutputStream; + +import javax.crypto.Mac; + +class MacUpdatingOutputStream + extends OutputStream +{ + private Mac mac; + + MacUpdatingOutputStream(Mac mac) + { + this.mac = mac; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + mac.update(bytes, off, len); + } + + public void write(byte[] bytes) + throws IOException + { + mac.update(bytes); + } + + public void write(int b) + throws IOException + { + mac.update((byte)b); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/OutputStreamFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/OutputStreamFactory.java new file mode 100644 index 000000000..06cfc5e59 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/OutputStreamFactory.java @@ -0,0 +1,46 @@ +package com.fr.third.org.bouncycastle.jcajce.io; + +import java.io.OutputStream; +import java.security.MessageDigest; +import java.security.Signature; + +import javax.crypto.Mac; + +/** + * Utility class for creating OutputStreams from different JCA/JCE operators. + */ +public class OutputStreamFactory +{ + /** + * Create an OutputStream that wraps a signature. + * + * @param signature the signature to be updated as the stream is written to. + * @return an OutputStream. + */ + public static OutputStream createStream(Signature signature) + { + return new SignatureUpdatingOutputStream(signature); + } + + /** + * Create an OutputStream that wraps a digest. + * + * @param digest the digest to be updated as the stream is written to. + * @return an OutputStream. + */ + public static OutputStream createStream(MessageDigest digest) + { + return new DigestUpdatingOutputStream(digest); + } + + /** + * Create an OutputStream that wraps a mac. + * + * @param mac the signature to be updated as the stream is written to. + * @return an OutputStream. + */ + public static OutputStream createStream(Mac mac) + { + return new MacUpdatingOutputStream(mac); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/SignatureUpdatingOutputStream.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/SignatureUpdatingOutputStream.java new file mode 100644 index 000000000..971bf0458 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/io/SignatureUpdatingOutputStream.java @@ -0,0 +1,56 @@ +package com.fr.third.org.bouncycastle.jcajce.io; + +import java.io.IOException; +import java.io.OutputStream; +import java.security.Signature; +import java.security.SignatureException; + +class SignatureUpdatingOutputStream + extends OutputStream +{ + private Signature sig; + + SignatureUpdatingOutputStream(Signature sig) + { + this.sig = sig; + } + + public void write(byte[] bytes, int off, int len) + throws IOException + { + try + { + sig.update(bytes, off, len); + } + catch (SignatureException e) + { + throw new IOException(e.getMessage()); + } + } + + public void write(byte[] bytes) + throws IOException + { + try + { + sig.update(bytes); + } + catch (SignatureException e) + { + throw new IOException(e.getMessage()); + } + } + + public void write(int b) + throws IOException + { + try + { + sig.update((byte)b); + } + catch (SignatureException e) + { + throw new IOException(e.getMessage()); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java new file mode 100644 index 000000000..c31a3521a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/EdEC.java @@ -0,0 +1,84 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric; + +import java.util.HashMap; +import java.util.Map; + +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.edec.KeyFactorySpi; +import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import com.fr.third.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; + +public class EdEC +{ + private static final String PREFIX = "com.fr.third.org.bouncycastle.jcajce.provider.asymmetric" + ".edec."; + + private static final Map edxAttributes = new HashMap(); + + static + { + edxAttributes.put("SupportedKeyClasses", "java.security.interfaces.ECPublicKey|java.security.interfaces.ECPrivateKey"); + edxAttributes.put("SupportedKeyFormats", "PKCS#8|X.509"); + } + + public static class Mappings + extends AsymmetricAlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("KeyFactory.XDH", PREFIX + "KeyFactorySpi$XDH"); + provider.addAlgorithm("KeyFactory.X448", PREFIX + "KeyFactorySpi$X448"); + provider.addAlgorithm("KeyFactory.X25519", PREFIX + "KeyFactorySpi$X25519"); + + provider.addAlgorithm("KeyFactory.EDDSA", PREFIX + "KeyFactorySpi$EDDSA"); + provider.addAlgorithm("KeyFactory.ED448", PREFIX + "KeyFactorySpi$ED448"); + provider.addAlgorithm("KeyFactory.ED25519", PREFIX + "KeyFactorySpi$ED25519"); + + provider.addAlgorithm("Signature.EDDSA", PREFIX + "SignatureSpi$EdDSA"); + provider.addAlgorithm("Signature.ED448", PREFIX + "SignatureSpi$Ed448"); + provider.addAlgorithm("Signature.ED25519", PREFIX + "SignatureSpi$Ed25519"); + provider.addAlgorithm("Signature", EdECObjectIdentifiers.id_Ed448, PREFIX + "SignatureSpi$Ed448"); + provider.addAlgorithm("Signature", EdECObjectIdentifiers.id_Ed25519, PREFIX + "SignatureSpi$Ed25519"); + + provider.addAlgorithm("KeyPairGenerator.EDDSA", PREFIX + "KeyPairGeneratorSpi$EdDSA"); + provider.addAlgorithm("KeyPairGenerator.ED448", PREFIX + "KeyPairGeneratorSpi$Ed448"); + provider.addAlgorithm("KeyPairGenerator.ED25519", PREFIX + "KeyPairGeneratorSpi$Ed25519"); + provider.addAlgorithm("KeyPairGenerator", EdECObjectIdentifiers.id_Ed448, PREFIX + "KeyPairGeneratorSpi$Ed448"); + provider.addAlgorithm("KeyPairGenerator", EdECObjectIdentifiers.id_Ed25519, PREFIX + "KeyPairGeneratorSpi$Ed25519"); + + provider.addAlgorithm("KeyAgreement.XDH", PREFIX + "KeyAgreementSpi$XDH"); + provider.addAlgorithm("KeyAgreement.X448", PREFIX + "KeyAgreementSpi$X448"); + provider.addAlgorithm("KeyAgreement.X25519", PREFIX + "KeyAgreementSpi$X25519"); + provider.addAlgorithm("KeyAgreement", EdECObjectIdentifiers.id_X448, PREFIX + "KeyAgreementSpi$X448"); + provider.addAlgorithm("KeyAgreement", EdECObjectIdentifiers.id_X25519, PREFIX + "KeyAgreementSpi$X25519"); + + provider.addAlgorithm("KeyAgreement.X25519WITHSHA256CKDF", PREFIX + "KeyAgreementSpi$X25519withSHA256CKDF"); + provider.addAlgorithm("KeyAgreement.X25519WITHSHA384CKDF", PREFIX + "KeyAgreementSpi$X25519withSHA384CKDF"); + provider.addAlgorithm("KeyAgreement.X25519WITHSHA512CKDF", PREFIX + "KeyAgreementSpi$X25519withSHA512CKDF"); + + provider.addAlgorithm("KeyAgreement.X448WITHSHA256CKDF", PREFIX + "KeyAgreementSpi$X448withSHA256CKDF"); + provider.addAlgorithm("KeyAgreement.X448WITHSHA384CKDF", PREFIX + "KeyAgreementSpi$X448withSHA384CKDF"); + provider.addAlgorithm("KeyAgreement.X448WITHSHA512CKDF", PREFIX + "KeyAgreementSpi$X448withSHA512CKDF"); + + provider.addAlgorithm("KeyAgreement.X25519WITHSHA256KDF", PREFIX + "KeyAgreementSpi$X25519withSHA256KDF"); + provider.addAlgorithm("KeyAgreement.X448WITHSHA512KDF", PREFIX + "KeyAgreementSpi$X448withSHA512KDF"); + + provider.addAlgorithm("KeyAgreement.X25519UWITHSHA256KDF", PREFIX + "KeyAgreementSpi$X25519UwithSHA256KDF"); + provider.addAlgorithm("KeyAgreement.X448UWITHSHA512KDF", PREFIX + "KeyAgreementSpi$X448UwithSHA512KDF"); + + provider.addAlgorithm("KeyPairGenerator.XDH", PREFIX + "KeyPairGeneratorSpi$XDH"); + provider.addAlgorithm("KeyPairGenerator.X448", PREFIX + "KeyPairGeneratorSpi$X448"); + provider.addAlgorithm("KeyPairGenerator.X25519", PREFIX + "KeyPairGeneratorSpi$X25519"); + provider.addAlgorithm("KeyPairGenerator", EdECObjectIdentifiers.id_X448, PREFIX + "KeyPairGeneratorSpiSpi$X448"); + provider.addAlgorithm("KeyPairGenerator", EdECObjectIdentifiers.id_X25519, PREFIX + "KeyPairGeneratorSpiSpi$X25519"); + + registerOid(provider, EdECObjectIdentifiers.id_X448, "XDH", new KeyFactorySpi.X448()); + registerOid(provider, EdECObjectIdentifiers.id_X25519, "XDH", new KeyFactorySpi.X25519()); + registerOid(provider, EdECObjectIdentifiers.id_Ed448, "EDDSA", new KeyFactorySpi.ED448()); + registerOid(provider, EdECObjectIdentifiers.id_Ed25519, "EDDSA", new KeyFactorySpi.ED25519()); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/GM.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/GM.java index 61c33c9b1..e58579ef9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/GM.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/GM.java @@ -28,8 +28,50 @@ public class GM public void configure(ConfigurableProvider provider) { +// provider.addAlgorithm("Signature.BLAKE2BWITHSM2", PREFIX + "GMSignatureSpi$blake2b512WithSM2"); +// provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_blake2b512, "BLAKE2BWITHSM2"); +// provider.addAlgorithm("Signature.BLAKE2SWITHSM2", PREFIX + "GMSignatureSpi$blake2s256WithSM2"); +// provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_blake2s256, "BLAKE2SWITHSM2"); +// provider.addAlgorithm("Signature.RIPEMD160WITHSM2", PREFIX + "GMSignatureSpi$ripemd160WithSM2"); +// provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_rmd160, "RIPEMD160WITHSM2"); +// provider.addAlgorithm("Signature.SHA1WITHSM2", PREFIX + "GMSignatureSpi$sha1WithSM2"); +// provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_sha1, "SHA1WITHSM2"); +// provider.addAlgorithm("Signature.SHA224WITHSM2", PREFIX + "GMSignatureSpi$sha224WithSM2"); +// provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_sha224, "SHA224WITHSM2"); + provider.addAlgorithm("Signature.SHA256WITHSM2", PREFIX + "GMSignatureSpi$sha256WithSM2"); + provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_sha256, "SHA256WITHSM2"); +// provider.addAlgorithm("Signature.SHA384WITHSM2", PREFIX + "GMSignatureSpi$sha384WithSM2"); +// provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_sha384, "SHA384WITHSM2"); +// provider.addAlgorithm("Signature.SHA512WITHSM2", PREFIX + "GMSignatureSpi$sha512WithSM2"); +// provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_sha512, "SHA512WITHSM2"); provider.addAlgorithm("Signature.SM3WITHSM2", PREFIX + "GMSignatureSpi$sm3WithSM2"); provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_sm3, "SM3WITHSM2"); +// provider.addAlgorithm("Signature.WHIRLPOOLWITHSM2", PREFIX + "GMSignatureSpi$whirlpoolWithSM2"); +// provider.addAlgorithm("Alg.Alias.Signature." + GMObjectIdentifiers.sm2sign_with_whirlpool, "WHIRLPOOLWITHSM2"); + + provider.addAlgorithm("Cipher.SM2", PREFIX + "GMCipherSpi$SM2"); + provider.addAlgorithm("Alg.Alias.Cipher.SM2WITHSM3", "SM2"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_sm3, "SM2"); + provider.addAlgorithm("Cipher.SM2WITHBLAKE2B", PREFIX + "GMCipherSpi$SM2withBlake2b"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_blake2b512, "SM2WITHBLAKE2B"); + provider.addAlgorithm("Cipher.SM2WITHBLAKE2S", PREFIX + "GMCipherSpi$SM2withBlake2s"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_blake2s256, "SM2WITHBLAKE2S"); + provider.addAlgorithm("Cipher.SM2WITHWHIRLPOOL", PREFIX + "GMCipherSpi$SM2withWhirlpool"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_whirlpool, "SM2WITHWHIRLPOOL"); + provider.addAlgorithm("Cipher.SM2WITHMD5", PREFIX + "GMCipherSpi$SM2withMD5"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_md5, "SM2WITHMD5"); + provider.addAlgorithm("Cipher.SM2WITHRIPEMD160", PREFIX + "GMCipherSpi$SM2withRMD"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_rmd160, "SM2WITHRIPEMD160"); + provider.addAlgorithm("Cipher.SM2WITHSHA1", PREFIX + "GMCipherSpi$SM2withSha1"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_sha1, "SM2WITHSHA1"); + provider.addAlgorithm("Cipher.SM2WITHSHA224", PREFIX + "GMCipherSpi$SM2withSha224"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_sha224, "SM2WITHSHA224"); + provider.addAlgorithm("Cipher.SM2WITHSHA256", PREFIX + "GMCipherSpi$SM2withSha256"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_sha256, "SM2WITHSHA256"); + provider.addAlgorithm("Cipher.SM2WITHSHA384", PREFIX + "GMCipherSpi$SM2withSha384"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_sha384, "SM2WITHSHA384"); + provider.addAlgorithm("Cipher.SM2WITHSHA512", PREFIX + "GMCipherSpi$SM2withSha512"); + provider.addAlgorithm("Alg.Alias.Cipher." + GMObjectIdentifiers.sm2encrypt_with_sha512, "SM2WITHSHA512"); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java index a367ab06b..eff97b7b0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPrivateKey.java @@ -148,7 +148,7 @@ public class BCDHPrivateKey DHParameters params = ((DHDomainParameterSpec)dhSpec).getDomainParameters(); DHValidationParameters validationParameters = params.getValidationParameters(); ValidationParams vParams = null; - if (validationParameters == null) + if (validationParameters != null) { vParams = new ValidationParams(validationParameters.getSeed(), validationParameters.getCounter()); } @@ -161,11 +161,16 @@ public class BCDHPrivateKey return info.getEncoded(ASN1Encoding.DER); } catch (Exception e) - { + { return null; } } + public String toString() + { + return DHUtil.privateKeyToString("DH", x, new DHParameters(dhSpec.getP(), dhSpec.getG())); + } + public DHParameterSpec getParams() { return dhSpec; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java index 981b1db28..b6538c438 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/BCDHPublicKey.java @@ -156,7 +156,7 @@ public class BCDHPublicKey DHParameters params = ((DHDomainParameterSpec)dhSpec).getDomainParameters(); DHValidationParameters validationParameters = params.getValidationParameters(); ValidationParams vParams = null; - if (validationParameters == null) + if (validationParameters != null) { vParams = new ValidationParams(validationParameters.getSeed(), validationParameters.getCounter()); } @@ -165,6 +165,11 @@ public class BCDHPublicKey return KeyUtil.getEncodedSubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.dhKeyAgreement, new DHParameter(dhSpec.getP(), dhSpec.getG(), dhSpec.getL()).toASN1Primitive()), new ASN1Integer(y)); } + public String toString() + { + return DHUtil.publicKeyToString("DH", y, new DHParameters(dhSpec.getP(), dhSpec.getG())); + } + public DHParameterSpec getParams() { return dhSpec; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java new file mode 100644 index 000000000..a1a3954d3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dh/DHUtil.java @@ -0,0 +1,45 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.dh; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.crypto.params.DHParameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Fingerprint; +import com.fr.third.org.bouncycastle.util.Strings; + +class DHUtil +{ + static String privateKeyToString(String algorithm, BigInteger x, DHParameters dhParams) + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + BigInteger y = dhParams.getG().modPow(x, dhParams.getP()); + + buf.append(algorithm); + buf.append(" Private Key [").append(generateKeyFingerprint(y, dhParams)).append("]").append(nl); + buf.append(" Y: ").append(y.toString(16)).append(nl); + + return buf.toString(); + } + + static String publicKeyToString(String algorithm, BigInteger y, DHParameters dhParams) + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + buf.append(algorithm); + buf.append(" Public Key [").append(generateKeyFingerprint(y, dhParams)).append("]").append(nl); + buf.append(" Y: ").append(y.toString(16)).append(nl); + + return buf.toString(); + } + + private static String generateKeyFingerprint(BigInteger y, DHParameters dhParams) + { + return new Fingerprint( + Arrays.concatenate( + y.toByteArray(), + dhParams.getP().toByteArray(), dhParams.getG().toByteArray())).toString(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java index 9dd197d29..3f597ae4c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPrivateKey.java @@ -174,7 +174,7 @@ public class BCDSAPrivateKey BigInteger y = getParams().getG().modPow(x, getParams().getP()); buf.append("DSA Private Key [").append(DSAUtil.generateKeyFingerprint(y, getParams())).append("]").append(nl); - buf.append(" y: ").append(y.toString(16)).append(nl); + buf.append(" Y: ").append(y.toString(16)).append(nl); return buf.toString(); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java index 679ec9b42..2165280fe 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/BCDSAPublicKey.java @@ -138,7 +138,7 @@ public class BCDSAPublicKey String nl = Strings.lineSeparator(); buf.append("DSA Public Key [").append(DSAUtil.generateKeyFingerprint(y, getParams())).append("]").append(nl); - buf.append(" y: ").append(this.getY().toString(16)).append(nl); + buf.append(" Y: ").append(this.getY().toString(16)).append(nl); return buf.toString(); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java index 5046d532b..53b90bd07 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/DSASigner.java @@ -1,6 +1,5 @@ package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.dsa; -import java.io.IOException; import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.PrivateKey; @@ -10,33 +9,30 @@ import java.security.SignatureException; import java.security.SignatureSpi; import java.security.spec.AlgorithmParameterSpec; -import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; -import com.fr.third.org.bouncycastle.asn1.ASN1Integer; -import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; -import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; -import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.digests.NullDigest; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.signers.DSAEncoding; import com.fr.third.org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import com.fr.third.org.bouncycastle.crypto.signers.StandardDSAEncoding; import com.fr.third.org.bouncycastle.crypto.util.DigestFactory; -import com.fr.third.org.bouncycastle.util.Arrays; public class DSASigner extends SignatureSpi implements PKCSObjectIdentifiers, X509ObjectIdentifiers { private Digest digest; - private DSA signer; + private DSAExt signer; + private DSAEncoding encoding = StandardDSAEncoding.INSTANCE; private SecureRandom random; protected DSASigner( Digest digest, - DSA signer) + DSAExt signer) { this.digest = digest; this.signer = signer; @@ -101,9 +97,9 @@ public class DSASigner try { - BigInteger[] sig = signer.generateSignature(hash); + BigInteger[] sig = signer.generateSignature(hash); - return derEncode(sig[0], sig[1]); + return encoding.encode(signer.getOrder(), sig[0], sig[1]); } catch (Exception e) { @@ -119,11 +115,11 @@ public class DSASigner digest.doFinal(hash, 0); - BigInteger[] sig; + BigInteger[] sig; try { - sig = derDecode(sigBytes); + sig = encoding.decode(signer.getOrder(), sigBytes); } catch (Exception e) { @@ -155,36 +151,7 @@ public class DSASigner protected Object engineGetParameter( String param) { - throw new UnsupportedOperationException("engineSetParameter unsupported"); - } - - private byte[] derEncode( - BigInteger r, - BigInteger s) - throws IOException - { - ASN1Integer[] rs = new ASN1Integer[]{ new ASN1Integer(r), new ASN1Integer(s) }; - return new DERSequence(rs).getEncoded(ASN1Encoding.DER); - } - - private BigInteger[] derDecode( - byte[] encoding) - throws IOException - { - ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); - if (s.size() != 2) - { - throw new IOException("malformed signature"); - } - if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER))) - { - throw new IOException("malformed signature"); - } - - return new BigInteger[]{ - ((ASN1Integer)s.getObjectAt(0)).getValue(), - ((ASN1Integer)s.getObjectAt(1)).getValue() - }; + throw new UnsupportedOperationException("engineGetParameter unsupported"); } static public class stdDSA diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java index db20995cf..010019d13 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dsa/KeyFactorySpi.java @@ -15,7 +15,15 @@ import java.security.spec.KeySpec; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAPrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil; +import com.fr.third.org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi; +import com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec; +import com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec; public class KeyFactorySpi extends BaseKeyFactorySpi @@ -41,6 +49,54 @@ public class KeyFactorySpi return new DSAPrivateKeySpec(k.getX(), k.getParams().getP(), k.getParams().getQ(), k.getParams().getG()); } + else if (spec.isAssignableFrom(OpenSSHPublicKeySpec.class) && key instanceof java.security.interfaces.DSAPublicKey) + { + DSAPublicKey k = (DSAPublicKey)key; + try + { + return new OpenSSHPublicKeySpec(OpenSSHPublicKeyUtil.encodePublicKey(new DSAPublicKeyParameters(k.getY(), new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG())))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else if (spec.isAssignableFrom(OpenSSHPrivateKeySpec.class) && key instanceof java.security.interfaces.DSAPrivateKey) + { + DSAPrivateKey k = (DSAPrivateKey)key; + try + { + return new OpenSSHPrivateKeySpec(OpenSSHPrivateKeyUtil.encodePrivateKey(new DSAPrivateKeyParameters(k.getX(), new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG())))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.OpenSSHPublicKeySpec.class) && key instanceof java.security.interfaces.DSAPublicKey) + { + DSAPublicKey k = (DSAPublicKey)key; + try + { + return new com.fr.third.org.bouncycastle.jce.spec.OpenSSHPublicKeySpec(OpenSSHPublicKeyUtil.encodePublicKey(new DSAPublicKeyParameters(k.getY(), new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG())))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec.class) && key instanceof java.security.interfaces.DSAPrivateKey) + { + DSAPrivateKey k = (DSAPrivateKey)key; + try + { + return new com.fr.third.org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec(OpenSSHPrivateKeyUtil.encodePrivateKey(new DSAPrivateKeyParameters(k.getX(), new DSAParameters(k.getParams().getP(), k.getParams().getQ(), k.getParams().getG())))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } return super.engineGetKeySpec(key, spec); } @@ -99,6 +155,24 @@ public class KeyFactorySpi { return new BCDSAPrivateKey((DSAPrivateKeySpec)keySpec); } + else if (keySpec instanceof OpenSSHPrivateKeySpec) + { + CipherParameters params = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(((OpenSSHPrivateKeySpec)keySpec).getEncoded()); + if (params instanceof DSAPrivateKeyParameters) + { + return engineGeneratePrivate( + new DSAPrivateKeySpec( + ((DSAPrivateKeyParameters)params).getX(), + ((DSAPrivateKeyParameters)params).getParameters().getP(), + ((DSAPrivateKeyParameters)params).getParameters().getQ(), + ((DSAPrivateKeyParameters)params).getParameters().getG())); + } + else + { + throw new IllegalArgumentException("openssh private key is not dsa privare key"); + } + + } return super.engineGeneratePrivate(keySpec); } @@ -118,12 +192,28 @@ public class KeyFactorySpi throw new InvalidKeySpecException("invalid KeySpec: " + e.getMessage()) { public Throwable getCause() - { - return e; - } + { + return e; + } }; } } + else if (keySpec instanceof OpenSSHPublicKeySpec) + { + CipherParameters parameters = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded()); + + if (parameters instanceof DSAPublicKeyParameters) + { + return engineGeneratePublic( + new DSAPublicKeySpec(((DSAPublicKeyParameters)parameters).getY(), + ((DSAPublicKeyParameters)parameters).getParameters().getP(), + ((DSAPublicKeyParameters)parameters).getParameters().getQ(), + ((DSAPublicKeyParameters)parameters).getParameters().getG())); + } + + throw new IllegalArgumentException("openssh public key is not dsa public key"); + + } return super.engineGeneratePublic(keySpec); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java index 1ca1b02d2..97f4ddca0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PrivateKey.java @@ -15,15 +15,21 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.DERBitString; import com.fr.third.org.bouncycastle.asn1.DERNull; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.ua.DSTU4145BinaryField; +import com.fr.third.org.bouncycastle.asn1.ua.DSTU4145ECBinary; import com.fr.third.org.bouncycastle.asn1.ua.DSTU4145NamedCurves; +import com.fr.third.org.bouncycastle.asn1.ua.DSTU4145Params; +import com.fr.third.org.bouncycastle.asn1.ua.DSTU4145PointEncoder; import com.fr.third.org.bouncycastle.asn1.ua.UAObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; @@ -33,6 +39,7 @@ import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAt import com.fr.third.org.bouncycastle.jce.interfaces.ECPointEncoder; import com.fr.third.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveSpec; import com.fr.third.org.bouncycastle.math.ec.ECCurve; @@ -182,7 +189,7 @@ public class BCDSTU4145PrivateKey private void populateFromPrivKeyInfo(PrivateKeyInfo info) throws IOException { - X962Parameters params = new X962Parameters((ASN1Primitive)info.getPrivateKeyAlgorithm().getParameters()); + X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters()); if (params.isNamedCurve()) { @@ -219,14 +226,56 @@ public class BCDSTU4145PrivateKey } else { - X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); - EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed()); + ASN1Sequence seq = ASN1Sequence.getInstance(params.getParameters()); - this.ecSpec = new ECParameterSpec( - ellipticCurve, - EC5Util.convertPoint(ecP.getG()), - ecP.getN(), - ecP.getH().intValue()); + if (seq.getObjectAt(0) instanceof ASN1Integer) + { + X9ECParameters ecP = X9ECParameters.getInstance(params.getParameters()); + EllipticCurve ellipticCurve = EC5Util.convertCurve(ecP.getCurve(), ecP.getSeed()); + + this.ecSpec = new ECParameterSpec( + ellipticCurve, + EC5Util.convertPoint(ecP.getG()), + ecP.getN(), + ecP.getH().intValue()); + } + else + { + DSTU4145Params dstuParams = DSTU4145Params.getInstance(seq); + com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec spec; + if (dstuParams.isNamedCurve()) + { + ASN1ObjectIdentifier curveOid = dstuParams.getNamedCurve(); + ECDomainParameters ecP = DSTU4145NamedCurves.getByOID(curveOid); + + spec = new ECNamedCurveParameterSpec(curveOid.getId(), ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); + } + else + { + DSTU4145ECBinary binary = dstuParams.getECBinary(); + byte[] b_bytes = binary.getB(); + if (info.getPrivateKeyAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + { + reverseBytes(b_bytes); + } + DSTU4145BinaryField field = binary.getField(); + ECCurve curve = new ECCurve.F2m(field.getM(), field.getK1(), field.getK2(), field.getK3(), binary.getA(), new BigInteger(1, b_bytes)); + byte[] g_bytes = binary.getG(); + if (info.getPrivateKeyAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + { + reverseBytes(g_bytes); + } + spec = new com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec(curve, DSTU4145PointEncoder.decodePoint(curve, g_bytes), binary.getN()); + } + + EllipticCurve ellipticCurve = EC5Util.convertCurve(spec.getCurve(), spec.getSeed()); + + this.ecSpec = new ECParameterSpec( + ellipticCurve, + EC5Util.convertPoint(spec.getG()), + spec.getN(), + spec.getH().intValue()); + } } ASN1Encodable privKey = info.parsePrivateKey(); @@ -245,6 +294,18 @@ public class BCDSTU4145PrivateKey } } + private void reverseBytes(byte[] bytes) + { + byte tmp; + + for (int i = 0; i < bytes.length / 2; i++) + { + tmp = bytes[i]; + bytes[i] = bytes[bytes.length - 1 - i]; + bytes[bytes.length - 1 - i] = tmp; + } + } + public String getAlgorithm() { return algorithm; @@ -292,7 +353,7 @@ public class BCDSTU4145PrivateKey X9ECParameters ecP = new X9ECParameters( curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); @@ -345,14 +406,14 @@ public class BCDSTU4145PrivateKey return null; } - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() { if (ecSpec != null) { - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java index e60ec063e..44c87cdb6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/BCDSTU4145PublicKey.java @@ -11,6 +11,7 @@ import java.security.spec.ECPublicKeySpec; import java.security.spec.EllipticCurve; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; @@ -27,6 +28,7 @@ import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; @@ -64,7 +66,7 @@ public class BCDSTU4145PublicKey ECPublicKeySpec spec) { this.ecSpec = spec.getParams(); - this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(null, ecSpec)); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW()), EC5Util.getDomainParameters(null, ecSpec)); } public BCDSTU4145PublicKey( @@ -198,54 +200,66 @@ public class BCDSTU4145PublicKey reverseBytes(keyEnc); } - dstuParams = DSTU4145Params.getInstance((ASN1Sequence)info.getAlgorithm().getParameters()); - - //ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet())); + ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithm().getParameters()); com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec spec = null; - if (dstuParams.isNamedCurve()) - { - ASN1ObjectIdentifier curveOid = dstuParams.getNamedCurve(); - ECDomainParameters ecP = DSTU4145NamedCurves.getByOID(curveOid); + X9ECParameters x9Params = null; - spec = new ECNamedCurveParameterSpec(curveOid.getId(), ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); + if (seq.getObjectAt(0) instanceof ASN1Integer) + { + x9Params = X9ECParameters.getInstance(seq); + spec = new com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec(x9Params.getCurve(), x9Params.getG(), x9Params.getN(), x9Params.getH(), x9Params.getSeed()); } else { - DSTU4145ECBinary binary = dstuParams.getECBinary(); - byte[] b_bytes = binary.getB(); - if (info.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + dstuParams = DSTU4145Params.getInstance(seq); + + if (dstuParams.isNamedCurve()) { - reverseBytes(b_bytes); + ASN1ObjectIdentifier curveOid = dstuParams.getNamedCurve(); + ECDomainParameters ecP = DSTU4145NamedCurves.getByOID(curveOid); + + spec = new ECNamedCurveParameterSpec(curveOid.getId(), ecP.getCurve(), ecP.getG(), ecP.getN(), ecP.getH(), ecP.getSeed()); } - DSTU4145BinaryField field = binary.getField(); - ECCurve curve = new ECCurve.F2m(field.getM(), field.getK1(), field.getK2(), field.getK3(), binary.getA(), new BigInteger(1, b_bytes)); - byte[] g_bytes = binary.getG(); - if (info.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + else { - reverseBytes(g_bytes); + DSTU4145ECBinary binary = dstuParams.getECBinary(); + byte[] b_bytes = binary.getB(); + if (info.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + { + reverseBytes(b_bytes); + } + DSTU4145BinaryField field = binary.getField(); + ECCurve curve = new ECCurve.F2m(field.getM(), field.getK1(), field.getK2(), field.getK3(), binary.getA(), new BigInteger(1, b_bytes)); + byte[] g_bytes = binary.getG(); + if (info.getAlgorithm().getAlgorithm().equals(UAObjectIdentifiers.dstu4145le)) + { + reverseBytes(g_bytes); + } + spec = new com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec(curve, DSTU4145PointEncoder.decodePoint(curve, g_bytes), binary.getN()); } - spec = new com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec(curve, DSTU4145PointEncoder.decodePoint(curve, g_bytes), binary.getN()); } ECCurve curve = spec.getCurve(); EllipticCurve ellipticCurve = EC5Util.convertCurve(curve, spec.getSeed()); - if (dstuParams.isNamedCurve()) + if (dstuParams != null) { - ecSpec = new ECNamedCurveSpec( - dstuParams.getNamedCurve().getId(), - ellipticCurve, - EC5Util.convertPoint(spec.getG()), - spec.getN(), - spec.getH()); + ECPoint g = EC5Util.convertPoint(spec.getG()); + + if (dstuParams.isNamedCurve()) + { + String name = dstuParams.getNamedCurve().getId(); + + ecSpec = new ECNamedCurveSpec(name, ellipticCurve, g, spec.getN(), spec.getH()); + } + else + { + ecSpec = new ECParameterSpec(ellipticCurve, g, spec.getN(), spec.getH().intValue()); + } } else { - ecSpec = new ECParameterSpec( - ellipticCurve, - EC5Util.convertPoint(spec.getG()), - spec.getN(), - spec.getH().intValue()); + ecSpec = EC5Util.convertToSpec(x9Params); } //this.q = curve.createPoint(new BigInteger(1, x), new BigInteger(1, y), false); @@ -295,7 +309,7 @@ public class BCDSTU4145PublicKey X9ECParameters ecP = new X9ECParameters( curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); @@ -304,6 +318,7 @@ public class BCDSTU4145PublicKey } } + // NOTE: 'withCompression' is ignored here byte[] encKey = DSTU4145PointEncoder.encodePoint(ecPublicKey.getQ()); try @@ -330,7 +345,7 @@ public class BCDSTU4145PublicKey return null; } - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } public ECPoint getW() @@ -359,7 +374,7 @@ public class BCDSTU4145PublicKey { if (ecSpec != null) { - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java index c5c49e6b8..da01a5295 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyFactorySpi.java @@ -67,13 +67,13 @@ public class KeyFactorySpi ECPublicKey k = (ECPublicKey)key; if (k.getParams() != null) { - return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false)); + return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW()), EC5Util.convertSpec(k.getParams())); } else { ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec); + return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW()), implicitSpec); } } else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey) @@ -82,7 +82,7 @@ public class KeyFactorySpi if (k.getParams() != null) { - return new com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false)); + return new com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams())); } else { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java index 6043a16d9..0b859e12c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/KeyPairGeneratorSpi.java @@ -13,11 +13,13 @@ import com.fr.third.org.bouncycastle.asn1.ua.DSTU4145NamedCurves; import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; import com.fr.third.org.bouncycastle.crypto.generators.DSTU4145KeyPairGenerator; import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.DSTU4145Parameters; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; +import com.fr.third.org.bouncycastle.jcajce.spec.DSTU4145ParameterSpec; import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveSpec; @@ -86,10 +88,19 @@ public class KeyPairGeneratorSpi this.ecParams = params; ECCurve curve = EC5Util.convertCurve(p.getCurve()); - ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false); + ECPoint g = EC5Util.convertPoint(curve, p.getGenerator()); - param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random); + if (p instanceof DSTU4145ParameterSpec) + { + DSTU4145ParameterSpec dstuSpec = (DSTU4145ParameterSpec)p; + param = new ECKeyGenerationParameters(new DSTU4145Parameters( + new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), dstuSpec.getDKE()), random); + } + else + { + param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random); + } engine.init(param); initialised = true; } @@ -124,7 +135,7 @@ public class KeyPairGeneratorSpi java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams; ECCurve curve = EC5Util.convertCurve(p.getCurve()); - ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false); + ECPoint g = EC5Util.convertPoint(curve, p.getGenerator()); param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java index 797654aae..9370b624b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/dstu/SignatureSpi.java @@ -13,7 +13,7 @@ import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.ua.DSTU4145Params; import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.digests.GOST3411Digest; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; @@ -26,7 +26,7 @@ public class SignatureSpi implements PKCSObjectIdentifiers, X509ObjectIdentifiers { private Digest digest; - private DSA signer; + private DSAExt signer; public SignatureSpi() { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java index 643fed593..e517f5cc8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/AlgorithmParametersSpi.java @@ -1,6 +1,7 @@ package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.ec; import java.io.IOException; +import java.math.BigInteger; import java.security.spec.AlgorithmParameterSpec; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECParameterSpec; @@ -11,6 +12,7 @@ import com.fr.third.org.bouncycastle.asn1.DERNull; import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -42,7 +44,9 @@ public class AlgorithmParametersSpi throw new InvalidParameterSpecException("EC curve name not recognized: " + ecGenParameterSpec.getName()); } curveName = ecGenParameterSpec.getName(); - ecParameterSpec = EC5Util.convertToSpec(params); + ECParameterSpec baseSpec = EC5Util.convertToSpec(params); + ecParameterSpec = new ECNamedCurveSpec(curveName, + baseSpec.getCurve(), baseSpec.getGenerator(), baseSpec.getOrder(), BigInteger.valueOf(baseSpec.getCofactor())); } else if (algorithmParameterSpec instanceof ECParameterSpec) { @@ -120,7 +124,7 @@ public class AlgorithmParametersSpi } else { - ASN1ObjectIdentifier namedCurveOid = ECUtil.getNamedCurveOid(EC5Util.convertSpec(ecParameterSpec, false)); + ASN1ObjectIdentifier namedCurveOid = ECUtil.getNamedCurveOid(EC5Util.convertSpec(ecParameterSpec)); if (namedCurveOid != null) { @@ -156,10 +160,10 @@ public class AlgorithmParametersSpi } else { - com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec ecSpec = EC5Util.convertSpec(ecParameterSpec, false); + com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec ecSpec = EC5Util.convertSpec(ecParameterSpec); X9ECParameters ecP = new X9ECParameters( ecSpec.getCurve(), - ecSpec.getG(), + new X9ECPoint(ecSpec.getG(), false), ecSpec.getN(), ecSpec.getH(), ecSpec.getSeed()); @@ -176,6 +180,6 @@ public class AlgorithmParametersSpi @Override protected String engineToString() { - return "EC AlgorithmParameters "; + return "EC Parameters"; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java index e32b8359f..84c209451 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPrivateKey.java @@ -6,7 +6,6 @@ import java.io.ObjectOutputStream; import java.math.BigInteger; import java.security.interfaces.ECPrivateKey; import java.security.spec.ECParameterSpec; -import java.security.spec.ECPoint; import java.security.spec.ECPrivateKeySpec; import java.security.spec.EllipticCurve; import java.util.Enumeration; @@ -298,14 +297,14 @@ public class BCECPrivateKey return null; } - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() { if (ecSpec != null) { - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } return configuration.getEcImplicitlyCa(); @@ -366,11 +365,6 @@ public class BCECPrivateKey return ECUtil.privateKeyToString("EC", d, engineGetSpec()); } - private com.fr.third.org.bouncycastle.math.ec.ECPoint calculateQ(com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec spec) - { - return spec.getG().multiply(d).normalize(); - } - private DERBitString getPublicKeyDetails(BCECPublicKey pub) { try diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java index 9e41f6797..7673b9450 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/BCECPublicKey.java @@ -9,7 +9,6 @@ import java.security.spec.ECPoint; import java.security.spec.ECPublicKeySpec; import java.security.spec.EllipticCurve; -import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.DERBitString; @@ -60,7 +59,7 @@ public class BCECPublicKey { this.algorithm = algorithm; this.ecSpec = spec.getParams(); - this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(configuration, spec.getParams())); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW()), EC5Util.getDomainParameters(configuration, spec.getParams())); this.configuration = configuration; } @@ -164,7 +163,8 @@ public class BCECPublicKey { this.algorithm = key.getAlgorithm(); this.ecSpec = key.getParams(); - this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW(), false), EC5Util.getDomainParameters(configuration, key.getParams())); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW()), EC5Util.getDomainParameters(configuration, key.getParams())); + this.configuration = configuration; } BCECPublicKey( @@ -234,13 +234,14 @@ public class BCECPublicKey public byte[] getEncoded() { - ASN1Encodable params = ECUtils.getDomainParametersFromName(ecSpec, withCompression); - ASN1OctetString p = ASN1OctetString.getInstance(new X9ECPoint(ecPublicKey.getQ(), withCompression).toASN1Primitive()); + AlgorithmIdentifier algId = new AlgorithmIdentifier( + X9ObjectIdentifiers.id_ecPublicKey, + ECUtils.getDomainParametersFromName(ecSpec, withCompression)); - // stored curve is null if ImplicitlyCa - SubjectPublicKeyInfo info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); + byte[] pubKeyOctets = ecPublicKey.getQ().getEncoded(withCompression); - return KeyUtil.getEncodedSubjectPublicKeyInfo(info); + // stored curve is null if ImplicitlyCa + return KeyUtil.getEncodedSubjectPublicKeyInfo(algId, pubKeyOctets); } public ECParameterSpec getParams() @@ -255,7 +256,7 @@ public class BCECPublicKey return null; } - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } public ECPoint getW() @@ -284,7 +285,7 @@ public class BCECPublicKey { if (ecSpec != null) { - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } return configuration.getEcImplicitlyCa(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java index fd64a490d..6d0d5699e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/ECUtils.java @@ -10,6 +10,7 @@ import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.DERNull; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; @@ -83,7 +84,7 @@ class ECUtils X9ECParameters ecP = new X9ECParameters( curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/GMCipherSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/GMCipherSpi.java new file mode 100644 index 000000000..a8772256b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/GMCipherSpi.java @@ -0,0 +1,424 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.ec; + +import java.io.ByteArrayOutputStream; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.CipherSpi; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.ShortBufferException; + +import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; +import com.fr.third.org.bouncycastle.crypto.digests.Blake2bDigest; +import com.fr.third.org.bouncycastle.crypto.digests.Blake2sDigest; +import com.fr.third.org.bouncycastle.crypto.digests.MD5Digest; +import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD160Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA224Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA384Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.digests.WhirlpoolDigest; +import com.fr.third.org.bouncycastle.crypto.engines.SM2Engine; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import com.fr.third.org.bouncycastle.jcajce.provider.util.BadBlockException; +import com.fr.third.org.bouncycastle.jcajce.util.BCJcaJceHelper; +import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; +import com.fr.third.org.bouncycastle.jce.interfaces.ECKey; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; + + +public class GMCipherSpi + extends CipherSpi +{ + private final JcaJceHelper helper = new BCJcaJceHelper(); + + private SM2Engine engine; + private int state = -1; + private ErasableOutputStream buffer = new ErasableOutputStream(); + private AsymmetricKeyParameter key; + private SecureRandom random; + + public GMCipherSpi(SM2Engine engine) + { + this.engine = engine; + } + + public int engineGetBlockSize() + { + return 0; + } + + public int engineGetKeySize(Key key) + { + if (key instanceof ECKey) + { + return ((ECKey)key).getParameters().getCurve().getFieldSize(); + } + else + { + throw new IllegalArgumentException("not an EC key"); + } + } + + + public byte[] engineGetIV() + { + return null; + } + + public AlgorithmParameters engineGetParameters() + { + return null; + } + + public void engineSetMode(String mode) + throws NoSuchAlgorithmException + { + String modeName = Strings.toUpperCase(mode); + + if (!modeName.equals("NONE")) + { + throw new IllegalArgumentException("can't support mode " + mode); + } + } + + public int engineGetOutputSize(int inputLen) + { + if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE) + { + return engine.getOutputSize(inputLen); + } + else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE) + { + return engine.getOutputSize(inputLen); + } + else + { + throw new IllegalStateException("cipher not initialised"); + } + } + + public void engineSetPadding(String padding) + throws NoSuchPaddingException + { + String paddingName = Strings.toUpperCase(padding); + + // TDOD: make this meaningful... + if (!paddingName.equals("NOPADDING")) + { + throw new NoSuchPaddingException("padding not available with IESCipher"); + } + } + + + // Initialisation methods + + public void engineInit( + int opmode, + Key key, + AlgorithmParameters params, + SecureRandom random) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + AlgorithmParameterSpec paramSpec = null; + + if (params != null) + { + throw new InvalidAlgorithmParameterException("cannot recognise parameters: " + params.getClass().getName()); + } + + engineInit(opmode, key, paramSpec, random); + } + + public void engineInit( + int opmode, + Key key, + AlgorithmParameterSpec engineSpec, + SecureRandom random) + throws InvalidAlgorithmParameterException, InvalidKeyException + { + // Parse the recipient's key + if (opmode == Cipher.ENCRYPT_MODE || opmode == Cipher.WRAP_MODE) + { + if (key instanceof PublicKey) + { + this.key = ECUtils.generatePublicKeyParameter((PublicKey)key); + } + else + { + throw new InvalidKeyException("must be passed public EC key for encryption"); + } + } + else if (opmode == Cipher.DECRYPT_MODE || opmode == Cipher.UNWRAP_MODE) + { + if (key instanceof PrivateKey) + { + this.key = ECUtil.generatePrivateKeyParameter((PrivateKey)key); + } + else + { + throw new InvalidKeyException("must be passed private EC key for decryption"); + } + } + else + { + throw new InvalidKeyException("must be passed EC key"); + } + + + if (random != null) + { + this.random = random; + } + else + { + this.random = CryptoServicesRegistrar.getSecureRandom(); + } + + this.state = opmode; + buffer.reset(); + } + + public void engineInit( + int opmode, + Key key, + SecureRandom random) + throws InvalidKeyException + { + try + { + engineInit(opmode, key, (AlgorithmParameterSpec)null, random); + } + catch (InvalidAlgorithmParameterException e) + { + throw new IllegalArgumentException("cannot handle supplied parameter spec: " + e.getMessage()); + } + } + + + // Update methods - buffer the input + + public byte[] engineUpdate( + byte[] input, + int inputOffset, + int inputLen) + { + buffer.write(input, inputOffset, inputLen); + return null; + } + + + public int engineUpdate( + byte[] input, + int inputOffset, + int inputLen, + byte[] output, + int outputOffset) + { + buffer.write(input, inputOffset, inputLen); + return 0; + } + + + // Finalisation methods + + public byte[] engineDoFinal( + byte[] input, + int inputOffset, + int inputLen) + throws IllegalBlockSizeException, BadPaddingException + { + if (inputLen != 0) + { + buffer.write(input, inputOffset, inputLen); + } + + try + { + if (state == Cipher.ENCRYPT_MODE || state == Cipher.WRAP_MODE) + { + // Encrypt the buffer + try + { + engine.init(true, new ParametersWithRandom(key, random)); + + return engine.processBlock(buffer.getBuf(), 0, buffer.size()); + } + catch (final Exception e) + { + throw new BadBlockException("unable to process block", e); + } + } + else if (state == Cipher.DECRYPT_MODE || state == Cipher.UNWRAP_MODE) + { + // Decrypt the buffer + try + { + engine.init(false, key); + + return engine.processBlock(buffer.getBuf(), 0, buffer.size()); + } + catch (final Exception e) + { + throw new BadBlockException("unable to process block", e); + } + } + else + { + throw new IllegalStateException("cipher not initialised"); + } + } + finally + { + buffer.erase(); + } + } + + public int engineDoFinal( + byte[] input, + int inputOffset, + int inputLength, + byte[] output, + int outputOffset) + throws ShortBufferException, IllegalBlockSizeException, BadPaddingException + { + byte[] buf = engineDoFinal(input, inputOffset, inputLength); + System.arraycopy(buf, 0, output, outputOffset, buf.length); + return buf.length; + } + + /** + * Classes that inherit from us + */ + static public class SM2 + extends GMCipherSpi + { + public SM2() + { + super(new SM2Engine()); + } + } + + static public class SM2withBlake2b + extends GMCipherSpi + { + public SM2withBlake2b() + { + super(new SM2Engine(new Blake2bDigest(512))); + } + } + + static public class SM2withBlake2s + extends GMCipherSpi + { + public SM2withBlake2s() + { + super(new SM2Engine(new Blake2sDigest(256))); + } + } + + static public class SM2withWhirlpool + extends GMCipherSpi + { + public SM2withWhirlpool() + { + super(new SM2Engine(new WhirlpoolDigest())); + } + } + + static public class SM2withMD5 + extends GMCipherSpi + { + public SM2withMD5() + { + super(new SM2Engine(new MD5Digest())); + } + } + + static public class SM2withRMD + extends GMCipherSpi + { + public SM2withRMD() + { + super(new SM2Engine(new RIPEMD160Digest())); + } + } + + static public class SM2withSha1 + extends GMCipherSpi + { + public SM2withSha1() + { + super(new SM2Engine(new SHA1Digest())); + } + } + + static public class SM2withSha224 + extends GMCipherSpi + { + public SM2withSha224() + { + super(new SM2Engine(new SHA224Digest())); + } + } + + static public class SM2withSha256 + extends GMCipherSpi + { + public SM2withSha256() + { + super(new SM2Engine(new SHA256Digest())); + } + } + + static public class SM2withSha384 + extends GMCipherSpi + { + public SM2withSha384() + { + super(new SM2Engine(new SHA384Digest())); + } + } + + static public class SM2withSha512 + extends GMCipherSpi + { + public SM2withSha512() + { + super(new SM2Engine(new SHA512Digest())); + } + } + + protected static final class ErasableOutputStream + extends ByteArrayOutputStream + { + public ErasableOutputStream() + { + } + + public byte[] getBuf() + { + return buf; + } + + public void erase() + { + Arrays.fill(this.buf, (byte)0); + reset(); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/GMSignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/GMSignatureSpi.java index 37fb76d02..49f2c6680 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/GMSignatureSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/GMSignatureSpi.java @@ -10,6 +10,7 @@ import java.security.spec.AlgorithmParameterSpec; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.CryptoException; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithID; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; import com.fr.third.org.bouncycastle.crypto.signers.SM2Signer; @@ -146,6 +147,78 @@ public class GMSignatureSpi throw new UnsupportedOperationException("engineGetParameter unsupported"); } +// static public class blake2b512WithSM2 +// extends GMSignatureSpi +// { +// public blake2b512WithSM2() +// { +// super(new SM2Signer(new Blake2bDigest(512))); +// } +// } + +// static public class blake2s256WithSM2 +// extends GMSignatureSpi +// { +// public blake2s256WithSM2() +// { +// super(new SM2Signer(new Blake2sDigest(256))); +// } +// } + +// static public class ripemd160WithSM2 +// extends GMSignatureSpi +// { +// public ripemd160WithSM2() +// { +// super(new SM2Signer(new RIPEMD160Digest())); +// } +// } + +// static public class sha1WithSM2 +// extends GMSignatureSpi +// { +// public sha1WithSM2() +// { +// super(new SM2Signer(new SHA1Digest())); +// } +// } + +// static public class sha224WithSM2 +// extends GMSignatureSpi +// { +// public sha224WithSM2() +// { +// super(new SM2Signer(new SHA224Digest())); +// } +// } + + static public class sha256WithSM2 + extends GMSignatureSpi + { + public sha256WithSM2() + { + super(new SM2Signer(new SHA256Digest())); + } + } + +// static public class sha384WithSM2 +// extends GMSignatureSpi +// { +// public sha384WithSM2() +// { +// super(new SM2Signer(new SHA384Digest())); +// } +// } + +// static public class sha512WithSM2 +// extends GMSignatureSpi +// { +// public sha512WithSM2() +// { +// super(new SM2Signer(new SHA512Digest())); +// } +// } + static public class sm3WithSM2 extends GMSignatureSpi { @@ -154,4 +227,13 @@ public class GMSignatureSpi super(new SM2Signer()); } } -} \ No newline at end of file + +// static public class whirlpoolWithSM2 +// extends GMSignatureSpi +// { +// public whirlpoolWithSM2() +// { +// super(new SM2Signer(new WhirlpoolDigest())); +// } +// } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java index b1e8cd31d..0a4154fee 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyFactorySpi.java @@ -12,12 +12,19 @@ import java.security.spec.KeySpec; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import com.fr.third.org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import com.fr.third.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +import com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec; +import com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec; import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; import com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec; @@ -39,7 +46,7 @@ public class KeyFactorySpi } protected Key engineTranslateKey( - Key key) + Key key) throws InvalidKeyException { if (key instanceof ECPublicKey) @@ -55,70 +62,151 @@ public class KeyFactorySpi } protected KeySpec engineGetKeySpec( - Key key, - Class spec) - throws InvalidKeySpecException + Key key, + Class spec) + throws InvalidKeySpecException { - if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey) - { - ECPublicKey k = (ECPublicKey)key; - if (k.getParams() != null) - { - return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams()); - } - else - { - ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); - } - } - else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey) - { - ECPrivateKey k = (ECPrivateKey)key; - - if (k.getParams() != null) - { - return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams()); - } - else - { - ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); - } - } - else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey) - { - ECPublicKey k = (ECPublicKey)key; - if (k.getParams() != null) - { - return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false)); - } - else - { - ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec); - } - } - else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey) - { - ECPrivateKey k = (ECPrivateKey)key; - - if (k.getParams() != null) - { - return new com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false)); - } - else - { - ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - - return new com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), implicitSpec); - } - } - - return super.engineGetKeySpec(key, spec); + if (spec.isAssignableFrom(java.security.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey) + { + ECPublicKey k = (ECPublicKey)key; + if (k.getParams() != null) + { + return new java.security.spec.ECPublicKeySpec(k.getW(), k.getParams()); + } + else + { + ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + + return new java.security.spec.ECPublicKeySpec(k.getW(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); + } + } + else if (spec.isAssignableFrom(java.security.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey) + { + ECPrivateKey k = (ECPrivateKey)key; + + if (k.getParams() != null) + { + return new java.security.spec.ECPrivateKeySpec(k.getS(), k.getParams()); + } + else + { + ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + + return new java.security.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(EC5Util.convertCurve(implicitSpec.getCurve(), implicitSpec.getSeed()), implicitSpec)); + } + } + else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec.class) && key instanceof ECPublicKey) + { + ECPublicKey k = (ECPublicKey)key; + if (k.getParams() != null) + { + return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW()), EC5Util.convertSpec(k.getParams())); + } + else + { + ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + + return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW()), implicitSpec); + } + } + else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey) + { + ECPrivateKey k = (ECPrivateKey)key; + + if (k.getParams() != null) + { + return new com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams())); + } + else + { + ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); + + return new com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), implicitSpec); + } + } + else if (spec.isAssignableFrom(OpenSSHPublicKeySpec.class) && key instanceof ECPublicKey) + { + if (key instanceof BCECPublicKey) + { + BCECPublicKey bcPk = (BCECPublicKey)key; + ECParameterSpec sc = bcPk.getParameters(); + try + { + return new OpenSSHPublicKeySpec( + OpenSSHPublicKeyUtil.encodePublicKey( + new ECPublicKeyParameters(bcPk.getQ(), new ECDomainParameters(sc.getCurve(), sc.getG(), sc.getN(), sc.getH(), sc.getSeed())))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else + { + throw new IllegalArgumentException("invalid key type: " + key.getClass().getName()); + } + } + else if (spec.isAssignableFrom(OpenSSHPrivateKeySpec.class) && key instanceof ECPrivateKey) + { + if (key instanceof BCECPrivateKey) + { + try + { + return new OpenSSHPrivateKeySpec(PrivateKeyInfo.getInstance(key.getEncoded()).parsePrivateKey().toASN1Primitive().getEncoded()); + } + catch (IOException e) + { + throw new IllegalArgumentException("cannot encoded key: " + e.getMessage()); + } + } + else + { + throw new IllegalArgumentException("invalid key type: " + key.getClass().getName()); + } + + } + else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.OpenSSHPublicKeySpec.class) && key instanceof ECPublicKey) + { + if (key instanceof BCECPublicKey) + { + BCECPublicKey bcPk = (BCECPublicKey)key; + ECParameterSpec sc = bcPk.getParameters(); + try + { + return new com.fr.third.org.bouncycastle.jce.spec.OpenSSHPublicKeySpec( + OpenSSHPublicKeyUtil.encodePublicKey( + new ECPublicKeyParameters(bcPk.getQ(), new ECDomainParameters(sc.getCurve(), sc.getG(), sc.getN(), sc.getH(), sc.getSeed())))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else + { + throw new IllegalArgumentException("invalid key type: " + key.getClass().getName()); + } + } + else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec.class) && key instanceof ECPrivateKey) + { + if (key instanceof BCECPrivateKey) + { + try + { + return new com.fr.third.org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec(PrivateKeyInfo.getInstance(key.getEncoded()).parsePrivateKey().toASN1Primitive().getEncoded()); + } + catch (IOException e) + { + throw new IllegalArgumentException("cannot encoded key: " + e.getMessage()); + } + } + else + { + throw new IllegalArgumentException("invalid key type: " + key.getClass().getName()); + } + } + + return super.engineGetKeySpec(key, spec); } protected PrivateKey engineGeneratePrivate( @@ -133,6 +221,19 @@ public class KeyFactorySpi { return new BCECPrivateKey(algorithm, (java.security.spec.ECPrivateKeySpec)keySpec, configuration); } + else if (keySpec instanceof OpenSSHPrivateKeySpec) + { + com.fr.third.org.bouncycastle.asn1.sec.ECPrivateKey ecKey = com.fr.third.org.bouncycastle.asn1.sec.ECPrivateKey.getInstance(((OpenSSHPrivateKeySpec)keySpec).getEncoded()); + + try + { + return new BCECPrivateKey(algorithm, new PrivateKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, ecKey.getParameters()), ecKey), configuration); + } + catch (IOException e) + { + throw new InvalidKeySpecException("bad encoding: " + e.getMessage()); + } + } return super.engineGeneratePrivate(keySpec); } @@ -151,6 +252,22 @@ public class KeyFactorySpi { return new BCECPublicKey(algorithm, (java.security.spec.ECPublicKeySpec)keySpec, configuration); } + else if (keySpec instanceof OpenSSHPublicKeySpec) + { + CipherParameters params = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded()); + if (params instanceof ECPublicKeyParameters) + { + ECDomainParameters parameters = ((ECPublicKeyParameters)params).getParameters(); + return engineGeneratePublic( + new ECPublicKeySpec(((ECPublicKeyParameters)params).getQ(), + new ECParameterSpec(parameters.getCurve(), parameters.getG(), parameters.getN(), parameters.getH(), parameters.getSeed()) + )); + } + else + { + throw new IllegalArgumentException("openssh key is not ec public key"); + } + } } catch (Exception e) { @@ -217,8 +334,13 @@ public class KeyFactorySpi } } - public static class ECGOST3410_2012 extends KeyFactorySpi{ - public ECGOST3410_2012(){super("ECGOST3410-2012", BouncyCastleProvider.CONFIGURATION);} + public static class ECGOST3410_2012 + extends KeyFactorySpi + { + public ECGOST3410_2012() + { + super("ECGOST3410-2012", BouncyCastleProvider.CONFIGURATION); + } } public static class ECDH diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java index 90e1d7024..4e0401e8f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/KeyPairGeneratorSpi.java @@ -21,6 +21,7 @@ import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import com.fr.third.org.bouncycastle.jcajce.provider.config.ProviderConfiguration; import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; @@ -139,7 +140,16 @@ public abstract class KeyPairGeneratorSpi } else { - throw new InvalidAlgorithmParameterException("parameter object not a ECParameterSpec"); + String name = ECUtil.getNameFrom(params); + + if (name != null) + { + initializeNamedCurve(name, random); + } + else + { + throw new InvalidAlgorithmParameterException("invalid parameterSpec: " + params); + } } engine.init(param); @@ -187,8 +197,20 @@ public abstract class KeyPairGeneratorSpi protected ECKeyGenerationParameters createKeyGenParamsJCE(java.security.spec.ECParameterSpec p, SecureRandom r) { + if (p instanceof ECNamedCurveSpec) + { + X9ECParameters x9P = ECUtils.getDomainParametersFromName(((ECNamedCurveSpec)p).getName()); + + if (x9P != null) + { + ECDomainParameters dp = new ECDomainParameters(x9P.getCurve(), x9P.getG(), x9P.getN(), x9P.getH()); + + return new ECKeyGenerationParameters(dp, r); + } + } + ECCurve curve = EC5Util.convertCurve(p.getCurve()); - ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false); + ECPoint g = EC5Util.convertPoint(curve, p.getGenerator()); BigInteger n = p.getOrder(); BigInteger h = BigInteger.valueOf(p.getCofactor()); ECDomainParameters dp = new ECDomainParameters(curve, g, n, h); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java index 3ef386e1d..ec6c63f8c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ec/SignatureSpi.java @@ -1,38 +1,31 @@ package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.ec; -import java.io.IOException; -import java.math.BigInteger; import java.security.InvalidKeyException; import java.security.PrivateKey; import java.security.PublicKey; -import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; -import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; -import com.fr.third.org.bouncycastle.asn1.ASN1Integer; -import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; -import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; -import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.digests.NullDigest; import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD160Digest; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.signers.DSAEncoding; import com.fr.third.org.bouncycastle.crypto.signers.ECDSASigner; import com.fr.third.org.bouncycastle.crypto.signers.ECNRSigner; import com.fr.third.org.bouncycastle.crypto.signers.HMacDSAKCalculator; +import com.fr.third.org.bouncycastle.crypto.signers.PlainDSAEncoding; +import com.fr.third.org.bouncycastle.crypto.signers.StandardDSAEncoding; import com.fr.third.org.bouncycastle.crypto.util.DigestFactory; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.DSABase; -import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.DSAEncoder; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; -import com.fr.third.org.bouncycastle.util.Arrays; public class SignatureSpi extends DSABase { - SignatureSpi(Digest digest, DSA signer, DSAEncoder encoder) + SignatureSpi(Digest digest, DSAExt signer, DSAEncoding encoding) { - super(digest, signer, encoder); + super(digest, signer, encoding); } protected void engineInitVerify(PublicKey publicKey) @@ -67,7 +60,7 @@ public class SignatureSpi { public ecDSA() { - super(DigestFactory.createSHA1(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA1(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -76,7 +69,7 @@ public class SignatureSpi { public ecDetDSA() { - super(DigestFactory.createSHA1(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1())), new StdDSAEncoder()); + super(DigestFactory.createSHA1(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA1())), StandardDSAEncoding.INSTANCE); } } @@ -85,7 +78,7 @@ public class SignatureSpi { public ecDSAnone() { - super(new NullDigest(), new ECDSASigner(), new StdDSAEncoder()); + super(new NullDigest(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -94,7 +87,7 @@ public class SignatureSpi { public ecDSA224() { - super(DigestFactory.createSHA224(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA224(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -103,7 +96,7 @@ public class SignatureSpi { public ecDetDSA224() { - super(DigestFactory.createSHA224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224())), new StdDSAEncoder()); + super(DigestFactory.createSHA224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA224())), StandardDSAEncoding.INSTANCE); } } @@ -112,7 +105,7 @@ public class SignatureSpi { public ecDSA256() { - super(DigestFactory.createSHA256(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA256(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -121,7 +114,7 @@ public class SignatureSpi { public ecDetDSA256() { - super(DigestFactory.createSHA256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256())), new StdDSAEncoder()); + super(DigestFactory.createSHA256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA256())), StandardDSAEncoding.INSTANCE); } } @@ -130,7 +123,7 @@ public class SignatureSpi { public ecDSA384() { - super(DigestFactory.createSHA384(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA384(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -139,7 +132,7 @@ public class SignatureSpi { public ecDetDSA384() { - super(DigestFactory.createSHA384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384())), new StdDSAEncoder()); + super(DigestFactory.createSHA384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA384())), StandardDSAEncoding.INSTANCE); } } @@ -148,7 +141,7 @@ public class SignatureSpi { public ecDSA512() { - super(DigestFactory.createSHA512(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA512(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -157,7 +150,7 @@ public class SignatureSpi { public ecDetDSA512() { - super(DigestFactory.createSHA512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512())), new StdDSAEncoder()); + super(DigestFactory.createSHA512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA512())), StandardDSAEncoding.INSTANCE); } } @@ -166,7 +159,7 @@ public class SignatureSpi { public ecDSASha3_224() { - super(DigestFactory.createSHA3_224(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_224(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -175,7 +168,7 @@ public class SignatureSpi { public ecDetDSASha3_224() { - super(DigestFactory.createSHA3_224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224())), new StdDSAEncoder()); + super(DigestFactory.createSHA3_224(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_224())), StandardDSAEncoding.INSTANCE); } } @@ -184,7 +177,7 @@ public class SignatureSpi { public ecDSASha3_256() { - super(DigestFactory.createSHA3_256(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_256(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -193,7 +186,7 @@ public class SignatureSpi { public ecDetDSASha3_256() { - super(DigestFactory.createSHA3_256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256())), new StdDSAEncoder()); + super(DigestFactory.createSHA3_256(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_256())), StandardDSAEncoding.INSTANCE); } } @@ -202,7 +195,7 @@ public class SignatureSpi { public ecDSASha3_384() { - super(DigestFactory.createSHA3_384(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_384(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -211,7 +204,7 @@ public class SignatureSpi { public ecDetDSASha3_384() { - super(DigestFactory.createSHA3_384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384())), new StdDSAEncoder()); + super(DigestFactory.createSHA3_384(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_384())), StandardDSAEncoding.INSTANCE); } } @@ -220,7 +213,7 @@ public class SignatureSpi { public ecDSASha3_512() { - super(DigestFactory.createSHA3_512(), new ECDSASigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA3_512(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -229,7 +222,7 @@ public class SignatureSpi { public ecDetDSASha3_512() { - super(DigestFactory.createSHA3_512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512())), new StdDSAEncoder()); + super(DigestFactory.createSHA3_512(), new ECDSASigner(new HMacDSAKCalculator(DigestFactory.createSHA3_512())), StandardDSAEncoding.INSTANCE); } } @@ -238,7 +231,7 @@ public class SignatureSpi { public ecDSARipeMD160() { - super(new RIPEMD160Digest(), new ECDSASigner(), new StdDSAEncoder()); + super(new RIPEMD160Digest(), new ECDSASigner(), StandardDSAEncoding.INSTANCE); } } @@ -247,7 +240,7 @@ public class SignatureSpi { public ecNR() { - super(DigestFactory.createSHA1(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA1(), new ECNRSigner(), StandardDSAEncoding.INSTANCE); } } @@ -256,7 +249,7 @@ public class SignatureSpi { public ecNR224() { - super(DigestFactory.createSHA224(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA224(), new ECNRSigner(), StandardDSAEncoding.INSTANCE); } } @@ -265,7 +258,7 @@ public class SignatureSpi { public ecNR256() { - super(DigestFactory.createSHA256(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA256(), new ECNRSigner(), StandardDSAEncoding.INSTANCE); } } @@ -274,7 +267,7 @@ public class SignatureSpi { public ecNR384() { - super(DigestFactory.createSHA384(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA384(), new ECNRSigner(), StandardDSAEncoding.INSTANCE); } } @@ -283,7 +276,7 @@ public class SignatureSpi { public ecNR512() { - super(DigestFactory.createSHA512(), new ECNRSigner(), new StdDSAEncoder()); + super(DigestFactory.createSHA512(), new ECNRSigner(), StandardDSAEncoding.INSTANCE); } } @@ -292,7 +285,7 @@ public class SignatureSpi { public ecCVCDSA() { - super(DigestFactory.createSHA1(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA1(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } @@ -301,7 +294,7 @@ public class SignatureSpi { public ecCVCDSA224() { - super(DigestFactory.createSHA224(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA224(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } @@ -310,7 +303,7 @@ public class SignatureSpi { public ecCVCDSA256() { - super(DigestFactory.createSHA256(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA256(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } @@ -319,7 +312,7 @@ public class SignatureSpi { public ecCVCDSA384() { - super(DigestFactory.createSHA384(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA384(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } @@ -328,7 +321,7 @@ public class SignatureSpi { public ecCVCDSA512() { - super(DigestFactory.createSHA512(), new ECDSASigner(), new PlainDSAEncoder()); + super(DigestFactory.createSHA512(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } @@ -337,109 +330,7 @@ public class SignatureSpi { public ecPlainDSARP160() { - super(new RIPEMD160Digest(), new ECDSASigner(), new PlainDSAEncoder()); + super(new RIPEMD160Digest(), new ECDSASigner(), PlainDSAEncoding.INSTANCE); } } - - private static class StdDSAEncoder - implements DSAEncoder - { - public byte[] encode( - BigInteger r, - BigInteger s) - throws IOException - { - ASN1EncodableVector v = new ASN1EncodableVector(); - - v.add(new ASN1Integer(r)); - v.add(new ASN1Integer(s)); - - return new DERSequence(v).getEncoded(ASN1Encoding.DER); - } - - public BigInteger[] decode( - byte[] encoding) - throws IOException - { - ASN1Sequence s = (ASN1Sequence)ASN1Primitive.fromByteArray(encoding); - if (s.size() != 2) - { - throw new IOException("malformed signature"); - } - if (!Arrays.areEqual(encoding, s.getEncoded(ASN1Encoding.DER))) - { - throw new IOException("malformed signature"); - } - - BigInteger[] sig = new BigInteger[2]; - - sig[0] = ASN1Integer.getInstance(s.getObjectAt(0)).getValue(); - sig[1] = ASN1Integer.getInstance(s.getObjectAt(1)).getValue(); - - return sig; - } - } - - private static class PlainDSAEncoder - implements DSAEncoder - { - public byte[] encode( - BigInteger r, - BigInteger s) - throws IOException - { - byte[] first = makeUnsigned(r); - byte[] second = makeUnsigned(s); - byte[] res; - - if (first.length > second.length) - { - res = new byte[first.length * 2]; - } - else - { - res = new byte[second.length * 2]; - } - - System.arraycopy(first, 0, res, res.length / 2 - first.length, first.length); - System.arraycopy(second, 0, res, res.length - second.length, second.length); - - return res; - } - - - private byte[] makeUnsigned(BigInteger val) - { - byte[] res = val.toByteArray(); - - if (res[0] == 0) - { - byte[] tmp = new byte[res.length - 1]; - - System.arraycopy(res, 1, tmp, 0, tmp.length); - - return tmp; - } - - return res; - } - - public BigInteger[] decode( - byte[] encoding) - throws IOException - { - BigInteger[] sig = new BigInteger[2]; - - byte[] first = new byte[encoding.length / 2]; - byte[] second = new byte[encoding.length / 2]; - - System.arraycopy(encoding, 0, first, 0, first.length); - System.arraycopy(encoding, first.length, second, 0, second.length); - - sig[0] = new BigInteger(1, first); - sig[1] = new BigInteger(1, second); - - return sig; - } - } -} \ No newline at end of file +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java index 5bc807bea..f6564b3b1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PrivateKey.java @@ -28,6 +28,7 @@ import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; @@ -244,7 +245,9 @@ public class BCECGOST3410PrivateKey if (ecP == null) // GOST Curve { ECDomainParameters gParam = ECGOST3410NamedCurves.getByOID(oid); - ecP = new X9ECParameters(gParam.getCurve(), gParam.getG(), gParam.getN(), gParam.getH(), gParam.getSeed()); + + // Point compression ignored for these temporary parameters + ecP = new X9ECParameters(gParam.getCurve(), new X9ECPoint(gParam.getG(), false), gParam.getN(), gParam.getH(), gParam.getSeed()); curveName = ECGOST3410NamedCurves.getName(oid); } @@ -361,7 +364,7 @@ public class BCECGOST3410PrivateKey X9ECParameters ecP = new X9ECParameters( curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); @@ -423,14 +426,14 @@ public class BCECGOST3410PrivateKey return null; } - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() { if (ecSpec != null) { - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java index a5769affc..df1078d2e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/BCECGOST3410PublicKey.java @@ -23,7 +23,9 @@ import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECGOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; @@ -61,7 +63,7 @@ public class BCECGOST3410PublicKey ECPublicKeySpec spec) { this.ecSpec = spec.getParams(); - this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(null, spec.getParams())); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW()), EC5Util.getDomainParameters(null, spec.getParams())); } public BCECGOST3410PublicKey( @@ -94,6 +96,14 @@ public class BCECGOST3410PublicKey { ECDomainParameters dp = params.getParameters(); + if (dp instanceof ECGOST3410Parameters) + { + ECGOST3410Parameters p = (ECGOST3410Parameters)dp; + + this.gostParams = new GOST3410PublicKeyAlgParameters(p.getPublicKeyParamSet(), + p.getDigestParamSet(), p.getEncryptionParamSet()); + } + this.algorithm = algorithm; this.ecPublicKey = params; @@ -159,7 +169,7 @@ public class BCECGOST3410PublicKey { this.algorithm = key.getAlgorithm(); this.ecSpec = key.getParams(); - this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW(), false), EC5Util.getDomainParameters(null, key.getParams())); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW()), EC5Util.getDomainParameters(null, key.getParams())); } BCECGOST3410PublicKey( @@ -253,7 +263,7 @@ public class BCECGOST3410PublicKey X9ECParameters ecP = new X9ECParameters( curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); @@ -264,8 +274,8 @@ public class BCECGOST3410PublicKey BigInteger bX = this.ecPublicKey.getQ().getAffineXCoord().toBigInteger(); BigInteger bY = this.ecPublicKey.getQ().getAffineYCoord().toBigInteger(); - byte[] encKey = new byte[64]; + byte[] encKey = new byte[64]; extractBytes(encKey, 0, bX); extractBytes(encKey, 32, bY); @@ -309,7 +319,7 @@ public class BCECGOST3410PublicKey return null; } - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } public ECPoint getW() @@ -336,7 +346,7 @@ public class BCECGOST3410PublicKey { if (ecSpec != null) { - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java index 6079234e8..77a5db29e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyFactorySpi.java @@ -67,13 +67,13 @@ public class KeyFactorySpi ECPublicKey k = (ECPublicKey)key; if (k.getParams() != null) { - return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false)); + return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW()), EC5Util.convertSpec(k.getParams())); } else { ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec); + return new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW()), implicitSpec); } } else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec.class) && key instanceof ECPrivateKey) @@ -82,7 +82,7 @@ public class KeyFactorySpi if (k.getParams() != null) { - return new com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false)); + return new com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams())); } else { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java index 70f88e35b..727e48471 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/KeyPairGeneratorSpi.java @@ -12,10 +12,13 @@ import com.fr.third.org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECGOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECNamedDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; +import com.fr.third.org.bouncycastle.jcajce.spec.GOST3410ParameterSpec; import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveSpec; @@ -69,7 +72,13 @@ public class KeyPairGeneratorSpi SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof ECParameterSpec) + if (params instanceof GOST3410ParameterSpec) + { + GOST3410ParameterSpec gostParams = (GOST3410ParameterSpec)params; + + init(gostParams, random); + } + else if (params instanceof ECParameterSpec) { ECParameterSpec p = (ECParameterSpec)params; this.ecParams = params; @@ -85,7 +94,7 @@ public class KeyPairGeneratorSpi this.ecParams = params; ECCurve curve = EC5Util.convertCurve(p.getCurve()); - ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false); + ECPoint g = EC5Util.convertPoint(curve, p.getGenerator()); param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random); @@ -105,29 +114,7 @@ public class KeyPairGeneratorSpi curveName = ((ECNamedCurveGenParameterSpec)params).getName(); } - ECDomainParameters ecP = ECGOST3410NamedCurves.getByName(curveName); - if (ecP == null) - { - throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName); - } - - this.ecParams = new ECNamedCurveSpec( - curveName, - ecP.getCurve(), - ecP.getG(), - ecP.getN(), - ecP.getH(), - ecP.getSeed()); - - java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams; - - ECCurve curve = EC5Util.convertCurve(p.getCurve()); - ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false); - - param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random); - - engine.init(param); - initialised = true; + init(new GOST3410ParameterSpec(curveName), random); } else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() != null) { @@ -149,6 +136,32 @@ public class KeyPairGeneratorSpi } } + private void init(GOST3410ParameterSpec gostParams, SecureRandom random) + throws InvalidAlgorithmParameterException + { + ECDomainParameters ecP = ECGOST3410NamedCurves.getByOID(gostParams.getPublicKeyParamSet()); + if (ecP == null) + { + throw new InvalidAlgorithmParameterException("unknown curve: " + gostParams.getPublicKeyParamSet()); + } + + this.ecParams = new ECNamedCurveSpec( + ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()), + ecP.getCurve(), + ecP.getG(), + ecP.getN(), + ecP.getH(), + ecP.getSeed()); + + param = new ECKeyGenerationParameters( + new ECGOST3410Parameters( + new ECNamedDomainParameters(gostParams.getPublicKeyParamSet(), ecP), + gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet()), random); + + engine.init(param); + initialised = true; + } + public KeyPair generateKeyPair() { if (!initialised) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java index 8a4bcd047..22aaae6fd 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost/SignatureSpi.java @@ -11,7 +11,7 @@ import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.digests.GOST3411Digest; import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; @@ -29,7 +29,7 @@ public class SignatureSpi implements PKCSObjectIdentifiers, X509ObjectIdentifiers { private Digest digest; - private DSA signer; + private DSAExt signer; public SignatureSpi() { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java index 63f7182e7..905c089d8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PrivateKey.java @@ -28,6 +28,7 @@ import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; @@ -371,7 +372,7 @@ public class BCECGOST3410_2012PrivateKey X9ECParameters ecP = new X9ECParameters( curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); @@ -433,14 +434,14 @@ public class BCECGOST3410_2012PrivateKey return null; } - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() { if (ecSpec != null) { - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java index 8ecbe4960..4bdfd0036 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/BCECGOST3410_2012PublicKey.java @@ -23,7 +23,9 @@ import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECGOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; @@ -64,7 +66,7 @@ public class BCECGOST3410_2012PublicKey ECPublicKeySpec spec) { this.ecSpec = spec.getParams(); - this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW(), false), EC5Util.getDomainParameters(null, spec.getParams())); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(ecSpec, spec.getW()), EC5Util.getDomainParameters(null, spec.getParams())); } public BCECGOST3410_2012PublicKey( @@ -100,6 +102,14 @@ public class BCECGOST3410_2012PublicKey this.algorithm = algorithm; this.ecPublicKey = params; + if (dp instanceof ECGOST3410Parameters) + { + ECGOST3410Parameters p = (ECGOST3410Parameters)dp; + + this.gostParams = new GOST3410PublicKeyAlgParameters(p.getPublicKeyParamSet(), + p.getDigestParamSet(), p.getEncryptionParamSet()); + } + if (spec == null) { EllipticCurve ellipticCurve = EC5Util.convertCurve(dp.getCurve(), dp.getSeed()); @@ -164,7 +174,7 @@ public class BCECGOST3410_2012PublicKey { this.algorithm = key.getAlgorithm(); this.ecSpec = key.getParams(); - this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW(), false), EC5Util.getDomainParameters(null, key.getParams())); + this.ecPublicKey = new ECPublicKeyParameters(EC5Util.convertPoint(this.ecSpec, key.getW()), EC5Util.getDomainParameters(null, key.getParams())); } BCECGOST3410_2012PublicKey( @@ -270,7 +280,7 @@ public class BCECGOST3410_2012PublicKey X9ECParameters ecP = new X9ECParameters( curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); @@ -296,7 +306,6 @@ public class BCECGOST3410_2012PublicKey } byte[] encKey = new byte[encKeySize]; - extractBytes(encKey, encKeySize / 2, 0, bX); extractBytes(encKey, encKeySize / 2, offset, bY); @@ -341,7 +350,7 @@ public class BCECGOST3410_2012PublicKey return null; } - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } public ECPoint getW() @@ -368,7 +377,7 @@ public class BCECGOST3410_2012PublicKey { if (ecSpec != null) { - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/ECGOST2012SignatureSpi256.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/ECGOST2012SignatureSpi256.java index 5fe66ceda..e6866f46d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/ECGOST2012SignatureSpi256.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/ECGOST2012SignatureSpi256.java @@ -10,7 +10,7 @@ import java.security.spec.AlgorithmParameterSpec; import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.digests.GOST3411_2012_256Digest; import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; @@ -30,7 +30,7 @@ public class ECGOST2012SignatureSpi256 implements PKCSObjectIdentifiers, X509ObjectIdentifiers { private Digest digest; - private DSA signer; + private DSAExt signer; private int size = 64; private int halfSize = size/2; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/ECGOST2012SignatureSpi512.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/ECGOST2012SignatureSpi512.java index 0db0fbccb..ecd0b6455 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/ECGOST2012SignatureSpi512.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/ECGOST2012SignatureSpi512.java @@ -10,7 +10,7 @@ import java.security.spec.AlgorithmParameterSpec; import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.digests.GOST3411_2012_512Digest; import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; @@ -31,7 +31,7 @@ public class ECGOST2012SignatureSpi512 { private Digest digest; - private DSA signer; + private DSAExt signer; private int size = 128; private int halfSize = 64; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyAgreementSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyAgreementSpi.java index 4c3dd3cf1..8ff6a76de 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyAgreementSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyAgreementSpi.java @@ -163,7 +163,7 @@ public class KeyAgreementSpi { public ECVKO512() { - super("ECGOST3410-2012-512", new ECVKOAgreement(new GOST3411_2012_512Digest()), null); + super("ECGOST3410-2012-512", new ECVKOAgreement(new GOST3411_2012_256Digest()), null); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyFactorySpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyFactorySpi.java index 20ad3ab49..dd7ec8eb8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyFactorySpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyFactorySpi.java @@ -67,13 +67,13 @@ public class KeyFactorySpi ECPublicKey k = (ECPublicKey)key; if (k.getParams() != null) { - return new ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), EC5Util.convertSpec(k.getParams(), false)); + return new ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW()), EC5Util.convertSpec(k.getParams())); } else { ECParameterSpec implicitSpec = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - return new ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW(), false), implicitSpec); + return new ECPublicKeySpec(EC5Util.convertPoint(k.getParams(), k.getW()), implicitSpec); } } else if (spec.isAssignableFrom(ECPrivateKeySpec.class) && key instanceof ECPrivateKey) @@ -82,7 +82,7 @@ public class KeyFactorySpi if (k.getParams() != null) { - return new ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams(), false)); + return new ECPrivateKeySpec(k.getS(), EC5Util.convertSpec(k.getParams())); } else { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyPairGeneratorSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyPairGeneratorSpi.java index 1ba4df661..5fa27b2f7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyPairGeneratorSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ecgost12/KeyPairGeneratorSpi.java @@ -1,13 +1,24 @@ package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.ecgost12; +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECGenParameterSpec; + import com.fr.third.org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; import com.fr.third.org.bouncycastle.crypto.generators.ECKeyPairGenerator; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECGOST3410Parameters; import com.fr.third.org.bouncycastle.crypto.params.ECKeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECNamedDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; +import com.fr.third.org.bouncycastle.jcajce.spec.GOST3410ParameterSpec; import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveSpec; @@ -15,14 +26,6 @@ import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECPoint; -import java.math.BigInteger; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidParameterException; -import java.security.KeyPair; -import java.security.SecureRandom; -import java.security.spec.AlgorithmParameterSpec; -import java.security.spec.ECGenParameterSpec; - /** * KeyPairGenerator for GOST34.10 2012. Algorithm is the same as for GOST34.10 2001 */ @@ -72,7 +75,13 @@ public class KeyPairGeneratorSpi SecureRandom random) throws InvalidAlgorithmParameterException { - if (params instanceof ECParameterSpec) + if (params instanceof GOST3410ParameterSpec) + { + GOST3410ParameterSpec gostParams = (GOST3410ParameterSpec)params; + + init(gostParams, random); + } + else if (params instanceof ECParameterSpec) { ECParameterSpec p = (ECParameterSpec)params; this.ecParams = params; @@ -88,7 +97,7 @@ public class KeyPairGeneratorSpi this.ecParams = params; ECCurve curve = EC5Util.convertCurve(p.getCurve()); - ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false); + ECPoint g = EC5Util.convertPoint(curve, p.getGenerator()); param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random); @@ -108,29 +117,7 @@ public class KeyPairGeneratorSpi curveName = ((ECNamedCurveGenParameterSpec)params).getName(); } - ECDomainParameters ecP = ECGOST3410NamedCurves.getByName(curveName); - if (ecP == null) - { - throw new InvalidAlgorithmParameterException("unknown curve name: " + curveName); - } - - this.ecParams = new ECNamedCurveSpec( - curveName, - ecP.getCurve(), - ecP.getG(), - ecP.getN(), - ecP.getH(), - ecP.getSeed()); - - java.security.spec.ECParameterSpec p = (java.security.spec.ECParameterSpec)ecParams; - - ECCurve curve = EC5Util.convertCurve(p.getCurve()); - ECPoint g = EC5Util.convertPoint(curve, p.getGenerator(), false); - - param = new ECKeyGenerationParameters(new ECDomainParameters(curve, g, p.getOrder(), BigInteger.valueOf(p.getCofactor())), random); - - engine.init(param); - initialised = true; + init(new GOST3410ParameterSpec(curveName), random); } else if (params == null && BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa() != null) { @@ -152,6 +139,32 @@ public class KeyPairGeneratorSpi } } + private void init(GOST3410ParameterSpec gostParams, SecureRandom random) + throws InvalidAlgorithmParameterException + { + ECDomainParameters ecP = ECGOST3410NamedCurves.getByOID(gostParams.getPublicKeyParamSet()); + if (ecP == null) + { + throw new InvalidAlgorithmParameterException("unknown curve: " + gostParams.getPublicKeyParamSet()); + } + + this.ecParams = new ECNamedCurveSpec( + ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet()), + ecP.getCurve(), + ecP.getG(), + ecP.getN(), + ecP.getH(), + ecP.getSeed()); + + param = new ECKeyGenerationParameters( + new ECGOST3410Parameters( + new ECNamedDomainParameters(gostParams.getPublicKeyParamSet(), ecP), + gostParams.getPublicKeyParamSet(), gostParams.getDigestParamSet(), gostParams.getEncryptionParamSet()), random); + + engine.init(param); + initialised = true; + } + public KeyPair generateKeyPair() { if (!initialised) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java new file mode 100644 index 000000000..495185b47 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPrivateKey.java @@ -0,0 +1,152 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.edec; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PrivateKey; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Set; +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.util.PrivateKeyInfoFactory; +import com.fr.third.org.bouncycastle.jcajce.interfaces.EdDSAKey; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class BCEdDSAPrivateKey + implements EdDSAKey, PrivateKey +{ + static final long serialVersionUID = 1L; + + private transient AsymmetricKeyParameter eddsaPrivateKey; + + private final boolean hasPublicKey; + private final byte[] attributes; + + BCEdDSAPrivateKey(AsymmetricKeyParameter privKey) + { + this.hasPublicKey = true; + this.attributes = null; + this.eddsaPrivateKey = privKey; + } + + BCEdDSAPrivateKey(PrivateKeyInfo keyInfo) + throws IOException + { + this.hasPublicKey = keyInfo.hasPublicKey(); + this.attributes = (keyInfo.getAttributes() != null) ? keyInfo.getAttributes().getEncoded() : null; + + populateFromPrivateKeyInfo(keyInfo); + } + + private void populateFromPrivateKeyInfo(PrivateKeyInfo keyInfo) + throws IOException + { + ASN1Encodable keyOcts = keyInfo.parsePrivateKey(); + if (EdECObjectIdentifiers.id_Ed448.equals(keyInfo.getPrivateKeyAlgorithm().getAlgorithm())) + { + eddsaPrivateKey = new Ed448PrivateKeyParameters(ASN1OctetString.getInstance(keyOcts).getOctets(), 0); + } + else + { + eddsaPrivateKey = new Ed25519PrivateKeyParameters(ASN1OctetString.getInstance(keyOcts).getOctets(), 0); + } + } + + public String getAlgorithm() + { + return (eddsaPrivateKey instanceof Ed448PrivateKeyParameters) ? "Ed448" : "Ed25519"; + } + + public String getFormat() + { + return "PKCS#8"; + } + + public byte[] getEncoded() + { + try + { + ASN1Set attrSet = ASN1Set.getInstance(attributes); + PrivateKeyInfo privInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(eddsaPrivateKey, attrSet); + + if (hasPublicKey) + { + return privInfo.getEncoded(); + } + else + { + return new PrivateKeyInfo(privInfo.getPrivateKeyAlgorithm(), privInfo.parsePrivateKey(), attrSet).getEncoded(); + } + } + catch (IOException e) + { + return null; + } + } + + AsymmetricKeyParameter engineGetKeyParameters() + { + return eddsaPrivateKey; + } + + public String toString() + { + AsymmetricKeyParameter pubKey; + if (eddsaPrivateKey instanceof Ed448PrivateKeyParameters) + { + pubKey = ((Ed448PrivateKeyParameters)eddsaPrivateKey).generatePublicKey(); + } + else + { + pubKey = ((Ed25519PrivateKeyParameters)eddsaPrivateKey).generatePublicKey(); + } + return Utils.keyToString("Private Key", getAlgorithm(), pubKey); + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof BCEdDSAPrivateKey)) + { + return false; + } + + BCEdDSAPrivateKey other = (BCEdDSAPrivateKey)o; + + return Arrays.areEqual(other.getEncoded(), this.getEncoded()); + } + + public int hashCode() + { + return Arrays.hashCode(this.getEncoded()); + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + populateFromPrivateKeyInfo(PrivateKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java new file mode 100644 index 000000000..e8ec1540f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCEdDSAPublicKey.java @@ -0,0 +1,157 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.edec; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; + +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PublicKeyParameters; +import com.fr.third.org.bouncycastle.jcajce.interfaces.EdDSAKey; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class BCEdDSAPublicKey + implements EdDSAKey, PublicKey +{ + static final long serialVersionUID = 1L; + + private transient AsymmetricKeyParameter eddsaPublicKey; + + BCEdDSAPublicKey(AsymmetricKeyParameter pubKey) + { + this.eddsaPublicKey = pubKey; + } + + BCEdDSAPublicKey(SubjectPublicKeyInfo keyInfo) + { + populateFromPubKeyInfo(keyInfo); + } + + BCEdDSAPublicKey(byte[] prefix, byte[] rawData) + throws InvalidKeySpecException + { + int prefixLength = prefix.length; + + if (Utils.isValidPrefix(prefix, rawData)) + { + if ((rawData.length - prefixLength) == Ed448PublicKeyParameters.KEY_SIZE) + { + eddsaPublicKey = new Ed448PublicKeyParameters(rawData, prefixLength); + } + else if ((rawData.length - prefixLength) == Ed25519PublicKeyParameters.KEY_SIZE) + { + eddsaPublicKey = new Ed25519PublicKeyParameters(rawData, prefixLength); + } + else + { + throw new InvalidKeySpecException("raw key data not recognised"); + } + } + else + { + throw new InvalidKeySpecException("raw key data not recognised"); + } + } + + private void populateFromPubKeyInfo(SubjectPublicKeyInfo keyInfo) + { + if (EdECObjectIdentifiers.id_Ed448.equals(keyInfo.getAlgorithm().getAlgorithm())) + { + eddsaPublicKey = new Ed448PublicKeyParameters(keyInfo.getPublicKeyData().getOctets(), 0); + } + else + { + eddsaPublicKey = new Ed25519PublicKeyParameters(keyInfo.getPublicKeyData().getOctets(), 0); + } + } + + public String getAlgorithm() + { + return (eddsaPublicKey instanceof Ed448PublicKeyParameters) ? "Ed448" : "Ed25519"; + } + + public String getFormat() + { + return "X.509"; + } + + public byte[] getEncoded() + { + if (eddsaPublicKey instanceof Ed448PublicKeyParameters) + { + byte[] encoding = new byte[KeyFactorySpi.Ed448Prefix.length + Ed448PublicKeyParameters.KEY_SIZE]; + + System.arraycopy(KeyFactorySpi.Ed448Prefix, 0, encoding, 0, KeyFactorySpi.Ed448Prefix.length); + + ((Ed448PublicKeyParameters)eddsaPublicKey).encode(encoding, KeyFactorySpi.Ed448Prefix.length); + + return encoding; + } + else + { + byte[] encoding = new byte[KeyFactorySpi.Ed25519Prefix.length + Ed25519PublicKeyParameters.KEY_SIZE]; + + System.arraycopy(KeyFactorySpi.Ed25519Prefix, 0, encoding, 0, KeyFactorySpi.Ed25519Prefix.length); + + ((Ed25519PublicKeyParameters)eddsaPublicKey).encode(encoding, KeyFactorySpi.Ed25519Prefix.length); + + return encoding; + } + } + + AsymmetricKeyParameter engineGetKeyParameters() + { + return eddsaPublicKey; + } + + public String toString() + { + return Utils.keyToString("Public Key", getAlgorithm(), eddsaPublicKey); + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof BCEdDSAPublicKey)) + { + return false; + } + + BCEdDSAPublicKey other = (BCEdDSAPublicKey)o; + + return Arrays.areEqual(other.getEncoded(), this.getEncoded()); + } + + public int hashCode() + { + return Arrays.hashCode(this.getEncoded()); + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPrivateKey.java new file mode 100644 index 000000000..be33f08c8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPrivateKey.java @@ -0,0 +1,152 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.edec; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PrivateKey; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Set; +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.X25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.util.PrivateKeyInfoFactory; +import com.fr.third.org.bouncycastle.jcajce.interfaces.XDHKey; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class BCXDHPrivateKey + implements XDHKey, PrivateKey +{ + static final long serialVersionUID = 1L; + + private transient AsymmetricKeyParameter xdhPrivateKey; + + private final boolean hasPublicKey; + private final byte[] attributes; + + BCXDHPrivateKey(AsymmetricKeyParameter privKey) + { + this.hasPublicKey = true; + this.attributes = null; + this.xdhPrivateKey = privKey; + } + + BCXDHPrivateKey(PrivateKeyInfo keyInfo) + throws IOException + { + this.hasPublicKey = keyInfo.hasPublicKey(); + this.attributes = (keyInfo.getAttributes() != null) ? keyInfo.getAttributes().getEncoded() : null; + + populateFromPrivateKeyInfo(keyInfo); + } + + private void populateFromPrivateKeyInfo(PrivateKeyInfo keyInfo) + throws IOException + { + ASN1Encodable keyOcts = keyInfo.parsePrivateKey(); + if (EdECObjectIdentifiers.id_X448.equals(keyInfo.getPrivateKeyAlgorithm().getAlgorithm())) + { + xdhPrivateKey = new X448PrivateKeyParameters(ASN1OctetString.getInstance(keyOcts).getOctets(), 0); + } + else + { + xdhPrivateKey = new X25519PrivateKeyParameters(ASN1OctetString.getInstance(keyOcts).getOctets(), 0); + } + } + + public String getAlgorithm() + { + return (xdhPrivateKey instanceof X448PrivateKeyParameters) ? "X448" : "X25519"; + } + + public String getFormat() + { + return "PKCS#8"; + } + + public byte[] getEncoded() + { + try + { + ASN1Set attrSet = ASN1Set.getInstance(attributes); + PrivateKeyInfo privInfo = PrivateKeyInfoFactory.createPrivateKeyInfo(xdhPrivateKey, attrSet); + + if (hasPublicKey) + { + return privInfo.getEncoded(); + } + else + { + return new PrivateKeyInfo(privInfo.getPrivateKeyAlgorithm(), privInfo.parsePrivateKey(), attrSet).getEncoded(); + } + } + catch (IOException e) + { + return null; + } + } + + AsymmetricKeyParameter engineGetKeyParameters() + { + return xdhPrivateKey; + } + + public String toString() + { + AsymmetricKeyParameter pubKey; + if (xdhPrivateKey instanceof X448PrivateKeyParameters) + { + pubKey = ((X448PrivateKeyParameters)xdhPrivateKey).generatePublicKey(); + } + else + { + pubKey = ((X25519PrivateKeyParameters)xdhPrivateKey).generatePublicKey(); + } + return Utils.keyToString("Private Key", getAlgorithm(), pubKey); + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof BCXDHPrivateKey)) + { + return false; + } + + BCXDHPrivateKey other = (BCXDHPrivateKey)o; + + return Arrays.areEqual(other.getEncoded(), this.getEncoded()); + } + + public int hashCode() + { + return Arrays.hashCode(this.getEncoded()); + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + populateFromPrivateKeyInfo(PrivateKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPublicKey.java new file mode 100644 index 000000000..504cd49fa --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/BCXDHPublicKey.java @@ -0,0 +1,157 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.edec; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; + +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.X25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448PublicKeyParameters; +import com.fr.third.org.bouncycastle.jcajce.interfaces.XDHKey; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class BCXDHPublicKey + implements XDHKey, PublicKey +{ + static final long serialVersionUID = 1L; + + private transient AsymmetricKeyParameter xdhPublicKey; + + BCXDHPublicKey(AsymmetricKeyParameter pubKey) + { + this.xdhPublicKey = pubKey; + } + + BCXDHPublicKey(SubjectPublicKeyInfo keyInfo) + { + populateFromPubKeyInfo(keyInfo); + } + + BCXDHPublicKey(byte[] prefix, byte[] rawData) + throws InvalidKeySpecException + { + int prefixLength = prefix.length; + + if (Utils.isValidPrefix(prefix, rawData)) + { + if ((rawData.length - prefixLength) == X448PublicKeyParameters.KEY_SIZE) + { + xdhPublicKey = new X448PublicKeyParameters(rawData, prefixLength); + } + else if ((rawData.length - prefixLength) == X25519PublicKeyParameters.KEY_SIZE) + { + xdhPublicKey = new X25519PublicKeyParameters(rawData, prefixLength); + } + else + { + throw new InvalidKeySpecException("raw key data not recognised"); + } + } + else + { + throw new InvalidKeySpecException("raw key data not recognised"); + } + } + + private void populateFromPubKeyInfo(SubjectPublicKeyInfo keyInfo) + { + if (EdECObjectIdentifiers.id_X448.equals(keyInfo.getAlgorithm().getAlgorithm())) + { + xdhPublicKey = new X448PublicKeyParameters(keyInfo.getPublicKeyData().getOctets(), 0); + } + else + { + xdhPublicKey = new X25519PublicKeyParameters(keyInfo.getPublicKeyData().getOctets(), 0); + } + } + + public String getAlgorithm() + { + return (xdhPublicKey instanceof X448PublicKeyParameters) ? "X448" : "X25519"; + } + + public String getFormat() + { + return "X.509"; + } + + public byte[] getEncoded() + { + if (xdhPublicKey instanceof X448PublicKeyParameters) + { + byte[] encoding = new byte[KeyFactorySpi.x448Prefix.length + X448PublicKeyParameters.KEY_SIZE]; + + System.arraycopy(KeyFactorySpi.x448Prefix, 0, encoding, 0, KeyFactorySpi.x448Prefix.length); + + ((X448PublicKeyParameters)xdhPublicKey).encode(encoding, KeyFactorySpi.x448Prefix.length); + + return encoding; + } + else + { + byte[] encoding = new byte[KeyFactorySpi.x25519Prefix.length + X25519PublicKeyParameters.KEY_SIZE]; + + System.arraycopy(KeyFactorySpi.x25519Prefix, 0, encoding, 0, KeyFactorySpi.x25519Prefix.length); + + ((X25519PublicKeyParameters)xdhPublicKey).encode(encoding, KeyFactorySpi.x25519Prefix.length); + + return encoding; + } + } + + AsymmetricKeyParameter engineGetKeyParameters() + { + return xdhPublicKey; + } + + public String toString() + { + return Utils.keyToString("Public Key", getAlgorithm(), xdhPublicKey); + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof BCXDHPublicKey)) + { + return false; + } + + BCXDHPublicKey other = (BCXDHPublicKey)o; + + return Arrays.areEqual(other.getEncoded(), this.getEncoded()); + } + + public int hashCode() + { + return Arrays.hashCode(this.getEncoded()); + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + populateFromPubKeyInfo(SubjectPublicKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java new file mode 100644 index 000000000..735ef2827 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyAgreementSpi.java @@ -0,0 +1,343 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.edec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +import com.fr.third.org.bouncycastle.crypto.DerivationFunction; +import com.fr.third.org.bouncycastle.crypto.RawAgreement; +import com.fr.third.org.bouncycastle.crypto.agreement.X25519Agreement; +import com.fr.third.org.bouncycastle.crypto.agreement.X448Agreement; +import com.fr.third.org.bouncycastle.crypto.agreement.XDHUnifiedAgreement; +import com.fr.third.org.bouncycastle.crypto.agreement.kdf.ConcatenationKDFGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.KDF2BytesGenerator; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.X448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.XDHUPrivateParameters; +import com.fr.third.org.bouncycastle.crypto.params.XDHUPublicParameters; +import com.fr.third.org.bouncycastle.crypto.util.DigestFactory; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.BaseAgreementSpi; +import com.fr.third.org.bouncycastle.jcajce.spec.DHUParameterSpec; +import com.fr.third.org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec; + +public class KeyAgreementSpi + extends BaseAgreementSpi +{ + private RawAgreement agreement; + private DHUParameterSpec dhuSpec; + private byte[] result; + + KeyAgreementSpi(String algorithm) + { + super(algorithm, null); + } + + KeyAgreementSpi(String algorithm, DerivationFunction kdf) + { + super(algorithm, kdf); + } + + protected byte[] calcSecret() + { + return result; + } + + protected void engineInit(Key key, SecureRandom secureRandom) + throws InvalidKeyException + { + if (key instanceof BCXDHPrivateKey) + { + AsymmetricKeyParameter priv = ((BCXDHPrivateKey)key).engineGetKeyParameters(); + + if (priv instanceof X448PrivateKeyParameters) + { + agreement = getAgreement("X448"); + } + else + { + agreement = getAgreement("X25519"); + } + + agreement.init(priv); + } + else + { + throw new InvalidKeyException("cannot identify XDH private key"); + } + + if (kdf != null) + { + ukmParameters = new byte[0]; + } + else + { + ukmParameters = null; + } + } + + protected void engineInit(Key key, AlgorithmParameterSpec params, SecureRandom secureRandom) + throws InvalidKeyException, InvalidAlgorithmParameterException + { + AsymmetricKeyParameter priv; + + if (key instanceof BCXDHPrivateKey) + { + priv = ((BCXDHPrivateKey)key).engineGetKeyParameters(); + + if (priv instanceof X448PrivateKeyParameters) + { + agreement = getAgreement("X448"); + } + else + { + agreement = getAgreement("X25519"); + } + } + else + { + throw new InvalidKeyException("cannot identify XDH private key"); + } + + ukmParameters = null; + if (params instanceof DHUParameterSpec) + { + if (kaAlgorithm.indexOf('U') < 0) + { + throw new InvalidAlgorithmParameterException("agreement algorithm not DHU based"); + } + + dhuSpec = (DHUParameterSpec)params; + + ukmParameters = dhuSpec.getUserKeyingMaterial(); + + agreement.init(new XDHUPrivateParameters( + priv, ((BCXDHPrivateKey)dhuSpec.getEphemeralPrivateKey()).engineGetKeyParameters(), + ((BCXDHPublicKey)dhuSpec.getEphemeralPublicKey()).engineGetKeyParameters())); + } + else + { + agreement.init(priv); + + if (params instanceof UserKeyingMaterialSpec) + { + if (kdf == null) + { + throw new InvalidAlgorithmParameterException("no KDF specified for UserKeyingMaterialSpec"); + } + this.ukmParameters = ((UserKeyingMaterialSpec)params).getUserKeyingMaterial(); + } + else + { + throw new InvalidAlgorithmParameterException("unknown ParameterSpec"); + } + } + + if (kdf != null && ukmParameters == null) + { + ukmParameters = new byte[0]; + } + } + + protected Key engineDoPhase(Key key, boolean lastPhase) + throws InvalidKeyException, IllegalStateException + { + if (agreement == null) + { + throw new IllegalStateException(kaAlgorithm + " not initialised."); + } + + if (!lastPhase) + { + throw new IllegalStateException(kaAlgorithm + " can only be between two parties."); + } + + if (!(key instanceof BCXDHPublicKey)) + { + throw new InvalidKeyException("cannot identify XDH private key"); + } + + AsymmetricKeyParameter pub = ((BCXDHPublicKey)key).engineGetKeyParameters(); + + result = new byte[agreement.getAgreementSize()]; + + if (dhuSpec != null) + { + agreement.calculateAgreement(new XDHUPublicParameters(pub, ((BCXDHPublicKey)dhuSpec.getOtherPartyEphemeralKey()).engineGetKeyParameters()), result, 0); + } + else + { + agreement.calculateAgreement(pub, result, 0); + } + + return null; + } + + private RawAgreement getAgreement(String alg) + throws InvalidKeyException + { + if (!(kaAlgorithm.equals("XDH") || kaAlgorithm.startsWith(alg))) + { + throw new InvalidKeyException("inappropriate key for " + kaAlgorithm); + } + + if (kaAlgorithm.indexOf('U') > 0) + { + if (alg.startsWith("X448")) + { + return new XDHUnifiedAgreement(new X448Agreement()); + } + else + { + return new XDHUnifiedAgreement(new X25519Agreement()); + } + } + else + { + if (alg.startsWith("X448")) + { + return new X448Agreement(); + } + else + { + return new X25519Agreement(); + } + } + } + + public final static class XDH + extends KeyAgreementSpi + { + public XDH() + { + super("XDH"); + } + } + + public final static class X448 + extends KeyAgreementSpi + { + public X448() + { + super("X448"); + } + } + + public final static class X25519 + extends KeyAgreementSpi + { + public X25519() + { + super("X25519"); + } + } + + public final static class X25519withSHA256CKDF + extends KeyAgreementSpi + { + public X25519withSHA256CKDF() + { + super("X25519withSHA256CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA256())); + } + } + + public static class X25519withSHA384CKDF + extends KeyAgreementSpi + { + public X25519withSHA384CKDF() + { + super("X25519withSHA384CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA384())); + } + } + + public static class X25519withSHA512CKDF + extends KeyAgreementSpi + { + public X25519withSHA512CKDF() + { + super("X25519withSHA512CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA512())); + } + } + + public final static class X448withSHA256CKDF + extends KeyAgreementSpi + { + public X448withSHA256CKDF() + { + super("X448withSHA256CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA256())); + } + } + + public static class X448withSHA384CKDF + extends KeyAgreementSpi + { + public X448withSHA384CKDF() + { + super("X448withSHA384CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA384())); + } + } + + public final static class X448withSHA512CKDF + extends KeyAgreementSpi + { + public X448withSHA512CKDF() + { + super("X448withSHA512CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA512())); + } + } + + public final static class X25519withSHA256KDF + extends KeyAgreementSpi + { + public X25519withSHA256KDF() + { + super("X25519withSHA256KDF", new KDF2BytesGenerator(DigestFactory.createSHA256())); + } + } + + public final static class X448withSHA512KDF + extends KeyAgreementSpi + { + public X448withSHA512KDF() + { + super("X448withSHA512KDF", new KDF2BytesGenerator(DigestFactory.createSHA512())); + } + } + + public static class X25519UwithSHA256CKDF + extends KeyAgreementSpi + { + public X25519UwithSHA256CKDF() + { + super("X25519UwithSHA256CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA256())); + } + } + + public static class X448UwithSHA512CKDF + extends KeyAgreementSpi + { + public X448UwithSHA512CKDF() + { + super("X448UwithSHA512CKDF", new ConcatenationKDFGenerator(DigestFactory.createSHA512())); + } + } + + public static class X25519UwithSHA256KDF + extends KeyAgreementSpi + { + public X25519UwithSHA256KDF() + { + super("X25519UwithSHA256KDF", new KDF2BytesGenerator(DigestFactory.createSHA256())); + } + } + + public static class X448UwithSHA512KDF + extends KeyAgreementSpi + { + public X448UwithSHA512KDF() + { + super("X448UwithSHA512KDF", new KDF2BytesGenerator(DigestFactory.createSHA512())); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java new file mode 100644 index 000000000..de901df83 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyFactorySpi.java @@ -0,0 +1,310 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.edec; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.X509EncodedKeySpec; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil; +import com.fr.third.org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi; +import com.fr.third.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +import com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec; +import com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +public class KeyFactorySpi + extends BaseKeyFactorySpi + implements AsymmetricKeyInfoConverter +{ + static final byte[] x448Prefix = Hex.decode("3042300506032b656f033900"); + static final byte[] x25519Prefix = Hex.decode("302a300506032b656e032100"); + static final byte[] Ed448Prefix = Hex.decode("3043300506032b6571033a00"); + static final byte[] Ed25519Prefix = Hex.decode("302a300506032b6570032100"); + + private static final byte x448_type = 0x6f; + private static final byte x25519_type = 0x6e; + private static final byte Ed448_type = 0x71; + private static final byte Ed25519_type = 0x70; + + String algorithm; + private final boolean isXdh; + private final int specificBase; + + public KeyFactorySpi( + String algorithm, + boolean isXdh, + int specificBase) + { + this.algorithm = algorithm; + this.isXdh = isXdh; + this.specificBase = specificBase; + } + + protected Key engineTranslateKey( + Key key) + throws InvalidKeyException + { + throw new InvalidKeyException("key type unknown"); + } + + protected KeySpec engineGetKeySpec( + Key key, + Class spec) + throws InvalidKeySpecException + { + if (spec.isAssignableFrom(OpenSSHPrivateKeySpec.class) && key instanceof BCEdDSAPrivateKey) + { + try + { + // + // The DEROctetString at element 2 is an encoded DEROctetString with the private key value + // within it. + // + + ASN1Sequence seq = ASN1Sequence.getInstance(key.getEncoded()); + DEROctetString val = (DEROctetString)seq.getObjectAt(2); + ASN1InputStream in = new ASN1InputStream(val.getOctets()); + + return new OpenSSHPrivateKeySpec(OpenSSHPrivateKeyUtil.encodePrivateKey(new Ed25519PrivateKeyParameters(ASN1OctetString.getInstance(in.readObject()).getOctets(), 0))); + } + catch (IOException ex) + { + throw new InvalidKeySpecException(ex.getMessage(), ex.getCause()); + } + + } + else if (spec.isAssignableFrom(OpenSSHPublicKeySpec.class) && key instanceof BCEdDSAPublicKey) + { + try + { + return new OpenSSHPublicKeySpec(OpenSSHPublicKeyUtil.encodePublicKey(new Ed25519PublicKeyParameters(key.getEncoded(), Ed25519Prefix.length))); + } + catch (IOException ex) + { + throw new InvalidKeySpecException(ex.getMessage(), ex.getCause()); + } + } + if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec.class) && key instanceof BCEdDSAPrivateKey) + { + try + { + // + // The DEROctetString at element 2 is an encoded DEROctetString with the private key value + // within it. + // + + ASN1Sequence seq = ASN1Sequence.getInstance(key.getEncoded()); + DEROctetString val = (DEROctetString)seq.getObjectAt(2); + ASN1InputStream in = new ASN1InputStream(val.getOctets()); + + return new com.fr.third.org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec(OpenSSHPrivateKeyUtil.encodePrivateKey(new Ed25519PrivateKeyParameters(ASN1OctetString.getInstance(in.readObject()).getOctets(), 0))); + } + catch (IOException ex) + { + throw new InvalidKeySpecException(ex.getMessage(), ex.getCause()); + } + + } + else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.OpenSSHPublicKeySpec.class) && key instanceof BCEdDSAPublicKey) + { + try + { + return new com.fr.third.org.bouncycastle.jce.spec.OpenSSHPublicKeySpec(OpenSSHPublicKeyUtil.encodePublicKey(new Ed25519PublicKeyParameters(key.getEncoded(), Ed25519Prefix.length))); + } + catch (IOException ex) + { + throw new InvalidKeySpecException(ex.getMessage(), ex.getCause()); + } + } + + return super.engineGetKeySpec(key, spec); + } + + protected PrivateKey engineGeneratePrivate( + KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof OpenSSHPrivateKeySpec) + { + CipherParameters parameters = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(((OpenSSHPrivateKeySpec)keySpec).getEncoded()); + if (parameters instanceof Ed25519PrivateKeyParameters) + { + return new BCEdDSAPrivateKey((Ed25519PrivateKeyParameters)parameters); + } + throw new IllegalStateException("openssh private key not Ed25519 private key"); + } + + return super.engineGeneratePrivate(keySpec); + } + + protected PublicKey engineGeneratePublic( + KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof X509EncodedKeySpec) + { + byte[] enc = ((X509EncodedKeySpec)keySpec).getEncoded(); + // optimise if we can + if (specificBase == 0 || specificBase == enc[8]) + { + switch (enc[8]) + { + case x448_type: + return new BCXDHPublicKey(x448Prefix, enc); + case x25519_type: + return new BCXDHPublicKey(x25519Prefix, enc); + case Ed448_type: + return new BCEdDSAPublicKey(Ed448Prefix, enc); + case Ed25519_type: + return new BCEdDSAPublicKey(Ed25519Prefix, enc); + default: + return super.engineGeneratePublic(keySpec); + } + } + } + else if (keySpec instanceof OpenSSHPublicKeySpec) + { + CipherParameters parameters = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded()); + if (parameters instanceof Ed25519PublicKeyParameters) + { + return new BCEdDSAPublicKey(new byte[0], ((Ed25519PublicKeyParameters)parameters).getEncoded()); + } + + throw new IllegalStateException("openssh public key not Ed25519 public key"); + } + + return super.engineGeneratePublic(keySpec); + } + + public PrivateKey generatePrivate(PrivateKeyInfo keyInfo) + throws IOException + { + ASN1ObjectIdentifier algOid = keyInfo.getPrivateKeyAlgorithm().getAlgorithm(); + + if (isXdh) + { + if ((specificBase == 0 || specificBase == x448_type) && algOid.equals(EdECObjectIdentifiers.id_X448)) + { + return new BCXDHPrivateKey(keyInfo); + } + if ((specificBase == 0 || specificBase == x25519_type) && algOid.equals(EdECObjectIdentifiers.id_X25519)) + { + return new BCXDHPrivateKey(keyInfo); + } + } + else if (algOid.equals(EdECObjectIdentifiers.id_Ed448) || algOid.equals(EdECObjectIdentifiers.id_Ed25519)) + { + if ((specificBase == 0 || specificBase == Ed448_type) && algOid.equals(EdECObjectIdentifiers.id_Ed448)) + { + return new BCEdDSAPrivateKey(keyInfo); + } + if ((specificBase == 0 || specificBase == Ed25519_type) && algOid.equals(EdECObjectIdentifiers.id_Ed25519)) + { + return new BCEdDSAPrivateKey(keyInfo); + } + } + + throw new IOException("algorithm identifier " + algOid + " in key not recognized"); + } + + public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) + throws IOException + { + ASN1ObjectIdentifier algOid = keyInfo.getAlgorithm().getAlgorithm(); + + if (isXdh) + { + if ((specificBase == 0 || specificBase == x448_type) && algOid.equals(EdECObjectIdentifiers.id_X448)) + { + return new BCXDHPublicKey(keyInfo); + } + if ((specificBase == 0 || specificBase == x25519_type) && algOid.equals(EdECObjectIdentifiers.id_X25519)) + { + return new BCXDHPublicKey(keyInfo); + } + } + else if (algOid.equals(EdECObjectIdentifiers.id_Ed448) || algOid.equals(EdECObjectIdentifiers.id_Ed25519)) + { + if ((specificBase == 0 || specificBase == Ed448_type) && algOid.equals(EdECObjectIdentifiers.id_Ed448)) + { + return new BCEdDSAPublicKey(keyInfo); + } + if ((specificBase == 0 || specificBase == Ed25519_type) && algOid.equals(EdECObjectIdentifiers.id_Ed25519)) + { + return new BCEdDSAPublicKey(keyInfo); + } + } + + throw new IOException("algorithm identifier " + algOid + " in key not recognized"); + } + + public static class XDH + extends KeyFactorySpi + { + public XDH() + { + super("XDH", true, 0); + } + } + + public static class X448 + extends KeyFactorySpi + { + public X448() + { + super("X448", true, x448_type); + } + } + + public static class X25519 + extends KeyFactorySpi + { + public X25519() + { + super("X25519", true, x25519_type); + } + } + + public static class EDDSA + extends KeyFactorySpi + { + public EDDSA() + { + super("EdDSA", false, 0); + } + } + + public static class ED448 + extends KeyFactorySpi + { + public ED448() + { + super("Ed448", false, Ed448_type); + } + } + + public static class ED25519 + extends KeyFactorySpi + { + public ED25519() + { + super("Ed25519", false, Ed25519_type); + } + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java new file mode 100644 index 000000000..c30676872 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/KeyPairGeneratorSpi.java @@ -0,0 +1,291 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.edec; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECGenParameterSpec; + +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.Ed25519KeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.Ed448KeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.X25519KeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.X448KeyPairGenerator; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.X25519KeyGenerationParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448KeyGenerationParameters; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import com.fr.third.org.bouncycastle.jcajce.spec.EdDSAParameterSpec; +import com.fr.third.org.bouncycastle.jcajce.spec.XDHParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; + +public class KeyPairGeneratorSpi + extends java.security.KeyPairGeneratorSpi +{ + private static final int EdDSA = -1; + private static final int XDH = -2; + + private static final int Ed448 = 0; + private static final int Ed25519 = 1; + private static final int X448 = 2; + private static final int X25519 = 3; + + private int algorithm; + private AsymmetricCipherKeyPairGenerator generator; + + private boolean initialised; + private SecureRandom secureRandom; + + KeyPairGeneratorSpi(int algorithm, AsymmetricCipherKeyPairGenerator generator) + { + this.algorithm = algorithm; + this.generator = generator; + } + + public void initialize(int strength, SecureRandom secureRandom) + { + this.secureRandom = secureRandom; + + switch (strength) + { + case 255: + case 256: + switch (algorithm) + { + case EdDSA: + case Ed25519: + setupGenerator(Ed25519); + break; + case XDH: + case X25519: + setupGenerator(X25519); + break; + default: + throw new InvalidParameterException("key size not configurable"); + } + break; + case 448: + switch (algorithm) + { + case EdDSA: + case Ed448: + setupGenerator(Ed448); + break; + case XDH: + case X448: + setupGenerator(X448); + break; + default: + throw new InvalidParameterException("key size not configurable"); + } + break; + default: + throw new InvalidParameterException("unknown key size"); + } + } + + public void initialize(AlgorithmParameterSpec paramSpec, SecureRandom secureRandom) + throws InvalidAlgorithmParameterException + { + this.secureRandom = secureRandom; + + if (paramSpec instanceof ECGenParameterSpec) + { + initializeGenerator(((ECGenParameterSpec)paramSpec).getName()); + } + else if (paramSpec instanceof ECNamedCurveGenParameterSpec) + { + initializeGenerator(((ECNamedCurveGenParameterSpec)paramSpec).getName()); + } + else if (paramSpec instanceof EdDSAParameterSpec) + { + initializeGenerator(((EdDSAParameterSpec)paramSpec).getCurveName()); + } + else if (paramSpec instanceof XDHParameterSpec) + { + initializeGenerator(((XDHParameterSpec)paramSpec).getCurveName()); + } + else + { + String name = ECUtil.getNameFrom(paramSpec); + + if (name != null) + { + initializeGenerator(name); + } + else + { + throw new InvalidAlgorithmParameterException("invalid parameterSpec: " + paramSpec); + } + } + } + + private void algorithmCheck(int algorithm) + throws InvalidAlgorithmParameterException + { + if (this.algorithm != algorithm) + { + if (this.algorithm == Ed25519 || this.algorithm == Ed448) + { + throw new InvalidAlgorithmParameterException("parameterSpec for wrong curve type"); + } + if (this.algorithm == EdDSA && (algorithm != Ed25519 && algorithm != Ed448)) + { + throw new InvalidAlgorithmParameterException("parameterSpec for wrong curve type"); + } + if (this.algorithm == X25519 || this.algorithm == X448) + { + throw new InvalidAlgorithmParameterException("parameterSpec for wrong curve type"); + } + if (this.algorithm == XDH && (algorithm != X25519 && algorithm != X448)) + { + throw new InvalidAlgorithmParameterException("parameterSpec for wrong curve type"); + } + this.algorithm = algorithm; + } + } + + private void initializeGenerator(String name) + throws InvalidAlgorithmParameterException + { + if (name.equalsIgnoreCase(EdDSAParameterSpec.Ed448) || name.equals(EdECObjectIdentifiers.id_Ed448.getId())) + { + algorithmCheck(Ed448); + this.generator = new Ed448KeyPairGenerator(); + setupGenerator(Ed448); + } + else if (name.equalsIgnoreCase(EdDSAParameterSpec.Ed25519) || name.equals(EdECObjectIdentifiers.id_Ed25519.getId())) + { + algorithmCheck(Ed25519); + this.generator = new Ed25519KeyPairGenerator(); + setupGenerator(Ed25519); + } + else if (name.equalsIgnoreCase(XDHParameterSpec.X448) || name.equals(EdECObjectIdentifiers.id_X448.getId())) + { + algorithmCheck(X448); + this.generator = new X448KeyPairGenerator(); + setupGenerator(X448); + } + else if (name.equalsIgnoreCase(XDHParameterSpec.X25519) || name.equals(EdECObjectIdentifiers.id_X25519.getId())) + { + algorithmCheck(X25519); + this.generator = new X25519KeyPairGenerator(); + setupGenerator(X25519); + } + } + + public KeyPair generateKeyPair() + { + if (generator == null) + { + throw new IllegalStateException("generator not correctly initialized"); + } + + if (!initialised) + { + setupGenerator(algorithm); + } + + AsymmetricCipherKeyPair kp = generator.generateKeyPair(); + + switch (algorithm) + { + case Ed448: + return new KeyPair(new BCEdDSAPublicKey(kp.getPublic()), new BCEdDSAPrivateKey(kp.getPrivate())); + case Ed25519: + return new KeyPair(new BCEdDSAPublicKey(kp.getPublic()), new BCEdDSAPrivateKey(kp.getPrivate())); + case X448: + return new KeyPair(new BCXDHPublicKey(kp.getPublic()), new BCXDHPrivateKey(kp.getPrivate())); + case X25519: + return new KeyPair(new BCXDHPublicKey(kp.getPublic()), new BCXDHPrivateKey(kp.getPrivate())); + } + + throw new IllegalStateException("generator not correctly initialized"); + } + + private void setupGenerator(int algorithm) + { + initialised = true; + + if (secureRandom == null) + { + secureRandom = new SecureRandom(); + } + + switch (algorithm) + { + case Ed448: + generator.init(new Ed448KeyGenerationParameters(secureRandom)); + break; + case EdDSA: + case Ed25519: + generator.init(new Ed25519KeyGenerationParameters(secureRandom)); + break; + case X448: + generator.init(new X448KeyGenerationParameters(secureRandom)); + break; + case XDH: + case X25519: + generator.init(new X25519KeyGenerationParameters(secureRandom)); + break; + } + } + + public static final class EdDSA + extends KeyPairGeneratorSpi + { + public EdDSA() + { + super(EdDSA, null); + } + } + + public static final class Ed448 + extends KeyPairGeneratorSpi + { + public Ed448() + { + super(Ed448, new Ed448KeyPairGenerator()); + } + } + + public static final class Ed25519 + extends KeyPairGeneratorSpi + { + public Ed25519() + { + super(Ed25519, new Ed25519KeyPairGenerator()); + } + } + + public static final class XDH + extends KeyPairGeneratorSpi + { + public XDH() + { + super(XDH, null); + } + } + + public static final class X448 + extends KeyPairGeneratorSpi + { + public X448() + { + super(X448, new X448KeyPairGenerator()); + } + } + + public static final class X25519 + extends KeyPairGeneratorSpi + { + public X25519() + { + super(X25519, new X25519KeyPairGenerator()); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/SignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/SignatureSpi.java new file mode 100644 index 000000000..388225c97 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/SignatureSpi.java @@ -0,0 +1,166 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.edec; + +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SignatureException; + +import com.fr.third.org.bouncycastle.crypto.CryptoException; +import com.fr.third.org.bouncycastle.crypto.Signer; +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PrivateKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.signers.Ed25519Signer; +import com.fr.third.org.bouncycastle.crypto.signers.Ed448Signer; + +public class SignatureSpi + extends java.security.SignatureSpi +{ + private static final byte[] EMPTY_CONTEXT = new byte[0]; + + private final String algorithm; + + private Signer signer; + + SignatureSpi(String algorithm) + { + this.algorithm = algorithm; + } + + protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException + { + if (publicKey instanceof BCEdDSAPublicKey) + { + AsymmetricKeyParameter pub = ((BCEdDSAPublicKey)publicKey).engineGetKeyParameters(); + + if (pub instanceof Ed448PublicKeyParameters) + { + signer = getSigner("Ed448"); + } + else + { + signer = getSigner("Ed25519"); + } + + signer.init(false, pub); + } + else + { + throw new InvalidKeyException("cannot identify EdDSA public key"); + } + } + + protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException + { + if (privateKey instanceof BCEdDSAPrivateKey) + { + AsymmetricKeyParameter priv = ((BCEdDSAPrivateKey)privateKey).engineGetKeyParameters(); + + if (priv instanceof Ed448PrivateKeyParameters) + { + signer = getSigner("Ed448"); + } + else + { + signer = getSigner("Ed25519"); + } + + signer.init(true, priv); + } + else + { + throw new InvalidKeyException("cannot identify EdDSA private key"); + } + } + + private Signer getSigner(String alg) + throws InvalidKeyException + { + if (algorithm != null && !alg.equals(algorithm)) + { + throw new InvalidKeyException("inappropriate key for " + algorithm); + } + + if (alg.equals("Ed448")) + { + return new Ed448Signer(EMPTY_CONTEXT); + } + else + { + return new Ed25519Signer(); + } + } + + protected void engineUpdate(byte b) + throws SignatureException + { + signer.update(b); + } + + protected void engineUpdate(byte[] bytes, int off, int len) + throws SignatureException + { + signer.update(bytes, off, len); + } + + protected byte[] engineSign() + throws SignatureException + { + try + { + return signer.generateSignature(); + } + catch (CryptoException e) + { + throw new SignatureException(e.getMessage()); + } + } + + protected boolean engineVerify(byte[] signature) + throws SignatureException + { + return signer.verifySignature(signature); + } + + protected void engineSetParameter(String s, Object o) + throws InvalidParameterException + { + throw new UnsupportedOperationException("engineSetParameter unsupported"); + } + + protected Object engineGetParameter(String s) + throws InvalidParameterException + { + throw new UnsupportedOperationException("engineGetParameter unsupported"); + } + + public final static class EdDSA + extends SignatureSpi + { + public EdDSA() + { + super(null); + } + } + + public final static class Ed448 + extends SignatureSpi + { + public Ed448() + { + super("Ed448"); + } + } + + public final static class Ed25519 + extends SignatureSpi + { + public Ed25519() + { + super("Ed25519"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/Utils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/Utils.java new file mode 100644 index 000000000..20990af1c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/edec/Utils.java @@ -0,0 +1,71 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.edec; + +import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.Ed25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.Ed448PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X25519PublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.X448PublicKeyParameters; +import com.fr.third.org.bouncycastle.util.Fingerprint; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +class Utils +{ + static boolean isValidPrefix(byte[] prefix, byte[] encoding) + { + if (encoding.length < prefix.length) + { + return !isValidPrefix(prefix, prefix); + } + + int nonEqual = 0; + + for (int i = 0; i != prefix.length; i++) + { + nonEqual |= (prefix[i] ^ encoding[i]); + } + + return nonEqual == 0; + } + + static String keyToString(String label, String algorithm, AsymmetricKeyParameter pubKey) + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + byte[] keyBytes; + if (pubKey instanceof X448PublicKeyParameters) + { + keyBytes = ((X448PublicKeyParameters)pubKey).getEncoded(); + } + else if (pubKey instanceof Ed448PublicKeyParameters) + { + keyBytes = ((Ed448PublicKeyParameters)pubKey).getEncoded(); + } + else if (pubKey instanceof X25519PublicKeyParameters) + { + keyBytes = ((X25519PublicKeyParameters)pubKey).getEncoded(); + } + else + { + keyBytes = ((Ed25519PublicKeyParameters)pubKey).getEncoded(); + } + + buf.append(algorithm) + .append(" ") + .append(label).append(" [") + .append(Utils.generateKeyFingerprint(keyBytes)) + .append("]") + .append(nl) + .append(" public data: ") + .append(Hex.toHexString(keyBytes)) + .append(nl); + + return buf.toString(); + } + + private static String generateKeyFingerprint(byte[] keyBytes) + { + return new Fingerprint(keyBytes).toString(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/AlgorithmParametersSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/AlgorithmParametersSpi.java index d24c9f437..5c0f7c93e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/AlgorithmParametersSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/AlgorithmParametersSpi.java @@ -102,7 +102,7 @@ public class AlgorithmParametersSpi ASN1Sequence seq = (ASN1Sequence)ASN1Primitive.fromByteArray(params); this.currentSpec = GOST3410ParameterSpec.fromPublicKeyAlg( - new GOST3410PublicKeyAlgParameters(seq)); + GOST3410PublicKeyAlgParameters.getInstance(seq)); } catch (ClassCastException e) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java index 6e6d416b9..28cb66cb9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PrivateKey.java @@ -4,6 +4,7 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigInteger; +import java.security.InvalidKeyException; import java.util.Enumeration; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; @@ -17,6 +18,7 @@ import com.fr.third.org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParamete import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.crypto.params.GOST3410PrivateKeyParameters; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.GOST3410Util; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; import com.fr.third.org.bouncycastle.jce.interfaces.GOST3410Params; import com.fr.third.org.bouncycastle.jce.interfaces.GOST3410PrivateKey; @@ -201,6 +203,19 @@ public class BCGOST3410PrivateKey return this.getX().hashCode() ^ gost3410Spec.hashCode(); } + public String toString() + { + try + { + return GOSTUtil.privateKeyToString("GOST3410", x, + ((GOST3410PrivateKeyParameters)GOST3410Util.generatePrivateKeyParameter(this)).getParameters()); + } + catch (InvalidKeyException e) + { + throw new IllegalStateException(e.getMessage()); // should not be possible + } + } + public void setBagAttribute( ASN1ObjectIdentifier oid, ASN1Encodable attribute) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PublicKey.java index 998ff6611..c4fd5b533 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/BCGOST3410PublicKey.java @@ -4,22 +4,22 @@ import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.math.BigInteger; +import java.security.InvalidKeyException; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; -import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.DEROctetString; import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.crypto.params.GOST3410PublicKeyParameters; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.GOST3410Util; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; import com.fr.third.org.bouncycastle.jce.interfaces.GOST3410Params; import com.fr.third.org.bouncycastle.jce.interfaces.GOST3410PublicKey; import com.fr.third.org.bouncycastle.jce.spec.GOST3410ParameterSpec; import com.fr.third.org.bouncycastle.jce.spec.GOST3410PublicKeyParameterSetSpec; import com.fr.third.org.bouncycastle.jce.spec.GOST3410PublicKeySpec; -import com.fr.third.org.bouncycastle.util.Strings; public class BCGOST3410PublicKey implements GOST3410PublicKey @@ -62,7 +62,7 @@ public class BCGOST3410PublicKey BCGOST3410PublicKey( SubjectPublicKeyInfo info) { - GOST3410PublicKeyAlgParameters params = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters()); + GOST3410PublicKeyAlgParameters params = GOST3410PublicKeyAlgParameters.getInstance(info.getAlgorithm().getParameters()); DEROctetString derY; try @@ -155,13 +155,15 @@ public class BCGOST3410PublicKey public String toString() { - StringBuffer buf = new StringBuffer(); - String nl = Strings.lineSeparator(); - - buf.append("GOST3410 Public Key").append(nl); - buf.append(" y: ").append(this.getY().toString(16)).append(nl); - - return buf.toString(); + try + { + return GOSTUtil.publicKeyToString("GOST3410", y, + ((GOST3410PublicKeyParameters)GOST3410Util.generatePublicKeyParameter(this)).getParameters()); + } + catch (InvalidKeyException e) + { + throw new IllegalStateException(e.getMessage()); // should not be possible + } } public boolean equals(Object o) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/GOSTUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/GOSTUtil.java new file mode 100644 index 000000000..cd23bb71e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/GOSTUtil.java @@ -0,0 +1,45 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.gost; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.crypto.params.GOST3410Parameters; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Fingerprint; +import com.fr.third.org.bouncycastle.util.Strings; + +class GOSTUtil +{ + static String privateKeyToString(String algorithm, BigInteger x, GOST3410Parameters gostParams) + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + BigInteger y = gostParams.getA().modPow(x, gostParams.getP()); + + buf.append(algorithm); + buf.append(" Private Key [").append(generateKeyFingerprint(y, gostParams)).append("]").append(nl); + buf.append(" Y: ").append(y.toString(16)).append(nl); + + return buf.toString(); + } + + static String publicKeyToString(String algorithm, BigInteger y, GOST3410Parameters gostParams) + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + buf.append(algorithm); + buf.append(" Public Key [").append(generateKeyFingerprint(y, gostParams)).append("]").append(nl); + buf.append(" Y: ").append(y.toString(16)).append(nl); + + return buf.toString(); + } + + private static String generateKeyFingerprint(BigInteger y, GOST3410Parameters dhParams) + { + return new Fingerprint( + Arrays.concatenate( + y.toByteArray(), + dhParams.getP().toByteArray(), dhParams.getA().toByteArray())).toString(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java index 03b8b8ed6..0b8048747 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/gost/SignatureSpi.java @@ -12,7 +12,7 @@ import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.digests.GOST3411Digest; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; @@ -29,7 +29,7 @@ public class SignatureSpi implements PKCSObjectIdentifiers, X509ObjectIdentifiers { private Digest digest; - private DSA signer; + private DSAExt signer; private SecureRandom random; public SignatureSpi() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java index 00ea999fd..f383ee1d9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/ies/AlgorithmParametersSpi.java @@ -119,7 +119,7 @@ public class AlgorithmParametersSpi if (s.size() == 1) { - this.currentSpec = new IESParameterSpec(null, null, ASN1Integer.getInstance(s.getObjectAt(0)).getValue().intValue()); + this.currentSpec = new IESParameterSpec(null, null, ASN1Integer.getInstance(s.getObjectAt(0)).intValueExact()); } else if (s.size() == 2) { @@ -127,11 +127,11 @@ public class AlgorithmParametersSpi if (tagged.getTagNo() == 0) { - this.currentSpec = new IESParameterSpec(ASN1OctetString.getInstance(tagged, false).getOctets(), null, ASN1Integer.getInstance(s.getObjectAt(1)).getValue().intValue()); + this.currentSpec = new IESParameterSpec(ASN1OctetString.getInstance(tagged, false).getOctets(), null, ASN1Integer.getInstance(s.getObjectAt(1)).intValueExact()); } else { - this.currentSpec = new IESParameterSpec(null, ASN1OctetString.getInstance(tagged, false).getOctets(), ASN1Integer.getInstance(s.getObjectAt(1)).getValue().intValue()); + this.currentSpec = new IESParameterSpec(null, ASN1OctetString.getInstance(tagged, false).getOctets(), ASN1Integer.getInstance(s.getObjectAt(1)).intValueExact()); } } else if (s.size() == 3) @@ -139,7 +139,10 @@ public class AlgorithmParametersSpi ASN1TaggedObject tagged1 = ASN1TaggedObject.getInstance(s.getObjectAt(0)); ASN1TaggedObject tagged2 = ASN1TaggedObject.getInstance(s.getObjectAt(1)); - this.currentSpec = new IESParameterSpec(ASN1OctetString.getInstance(tagged1, false).getOctets(), ASN1OctetString.getInstance(tagged2, false).getOctets(), ASN1Integer.getInstance(s.getObjectAt(2)).getValue().intValue()); + this.currentSpec = new IESParameterSpec( + ASN1OctetString.getInstance(tagged1, false).getOctets(), + ASN1OctetString.getInstance(tagged2, false).getOctets(), + ASN1Integer.getInstance(s.getObjectAt(2)).intValueExact()); } else if (s.size() == 4) { @@ -147,8 +150,11 @@ public class AlgorithmParametersSpi ASN1TaggedObject tagged2 = ASN1TaggedObject.getInstance(s.getObjectAt(1)); ASN1Sequence cipherDet = ASN1Sequence.getInstance(s.getObjectAt(3)); - this.currentSpec = new IESParameterSpec(ASN1OctetString.getInstance(tagged1, false).getOctets(), ASN1OctetString.getInstance(tagged2, false).getOctets(), ASN1Integer.getInstance(s.getObjectAt(2)).getValue().intValue(), - ASN1Integer.getInstance(cipherDet.getObjectAt(0)).getValue().intValue(), + this.currentSpec = new IESParameterSpec( + ASN1OctetString.getInstance(tagged1, false).getOctets(), + ASN1OctetString.getInstance(tagged2, false).getOctets(), + ASN1Integer.getInstance(s.getObjectAt(2)).intValueExact(), + ASN1Integer.getInstance(cipherDet.getObjectAt(0)).intValueExact(), ASN1OctetString.getInstance(cipherDet.getObjectAt(1)).getOctets()); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java index c234cfb41..10b66814c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/AlgorithmParametersSpi.java @@ -95,7 +95,7 @@ public abstract class AlgorithmParametersSpi { return currentSpec; } - + throw new InvalidParameterSpecException("unknown parameter spec passed to OAEP parameters object."); } @@ -203,11 +203,11 @@ public abstract class AlgorithmParametersSpi Class paramSpec) throws InvalidParameterSpecException { - if (paramSpec == PSSParameterSpec.class && currentSpec != null) + if (paramSpec == PSSParameterSpec.class || paramSpec == AlgorithmParameterSpec.class) { return currentSpec; } - + throw new InvalidParameterSpecException("unknown parameter spec passed to PSS parameters object."); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java index 9705d38bf..4d0b05b6b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateCrtKey.java @@ -1,6 +1,8 @@ package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.rsa; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.math.BigInteger; import java.security.interfaces.RSAPrivateCrtKey; import java.security.spec.RSAPrivateCrtKeySpec; @@ -12,6 +14,7 @@ import com.fr.third.org.bouncycastle.asn1.pkcs.RSAPrivateKey; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; import com.fr.third.org.bouncycastle.util.Strings; /** @@ -56,6 +59,10 @@ public class BCRSAPrivateCrtKey BCRSAPrivateCrtKey( RSAPrivateCrtKeySpec spec) { + super(new RSAPrivateCrtKeyParameters(spec.getModulus(), + spec.getPublicExponent(), spec.getPrivateExponent(), + spec.getPrimeP(), spec.getPrimeQ(), spec.getPrimeExponentP(), spec.getPrimeExponentQ(), spec.getCrtCoefficient())); + this.modulus = spec.getModulus(); this.publicExponent = spec.getPublicExponent(); this.privateExponent = spec.getPrivateExponent(); @@ -74,6 +81,10 @@ public class BCRSAPrivateCrtKey BCRSAPrivateCrtKey( RSAPrivateCrtKey key) { + super(new RSAPrivateCrtKeyParameters(key.getModulus(), + key.getPublicExponent(), key.getPrivateExponent(), + key.getPrimeP(), key.getPrimeQ(), key.getPrimeExponentP(), key.getPrimeExponentQ(), key.getCrtCoefficient())); + this.modulus = key.getModulus(); this.publicExponent = key.getPublicExponent(); this.privateExponent = key.getPrivateExponent(); @@ -100,6 +111,10 @@ public class BCRSAPrivateCrtKey BCRSAPrivateCrtKey( RSAPrivateKey key) { + super(new RSAPrivateCrtKeyParameters(key.getModulus(), + key.getPublicExponent(), key.getPrivateExponent(), + key.getPrime1(), key.getPrime2(), key.getExponent1(), key.getExponent2(), key.getCoefficient())); + this.modulus = key.getModulus(); this.publicExponent = key.getPublicExponent(); this.privateExponent = key.getPrivateExponent(); @@ -222,16 +237,40 @@ public class BCRSAPrivateCrtKey && this.getCrtCoefficient().equals(key.getCrtCoefficient()); } + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + this.attrCarrier = new PKCS12BagAttributeCarrierImpl(); + this.rsaPrivateKey = new RSAPrivateCrtKeyParameters(this.getModulus(), + this.getPublicExponent(), this.getPrivateExponent(), + this.getPrimeP(), this.getPrimeQ(), + this.getPrimeExponentP(), this.getPrimeExponentQ(), this.getCrtCoefficient()); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + } + public String toString() { StringBuffer buf = new StringBuffer(); String nl = Strings.lineSeparator(); buf.append("RSA Private CRT Key [").append( - RSAUtil.generateKeyFingerprint(this.getModulus(), this.getPublicExponent())).append("]").append(nl); - buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); - buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl); - + RSAUtil.generateKeyFingerprint(this.getModulus())).append("]") + .append(",[") + .append(RSAUtil.generateExponentFingerprint(this.getPublicExponent())) + .append("]") + .append(nl); + buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); + buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl); + return buf.toString(); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java index 1bd05c48f..716353ee8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPrivateKey.java @@ -17,6 +17,7 @@ import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.KeyUtil; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; import com.fr.third.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; +import com.fr.third.org.bouncycastle.util.Strings; public class BCRSAPrivateKey implements RSAPrivateKey, PKCS12BagAttributeCarrier @@ -28,17 +29,15 @@ public class BCRSAPrivateKey protected BigInteger modulus; protected BigInteger privateExponent; - private transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl(); - - protected BCRSAPrivateKey() - { - } + protected transient RSAKeyParameters rsaPrivateKey; + protected transient PKCS12BagAttributeCarrierImpl attrCarrier = new PKCS12BagAttributeCarrierImpl(); BCRSAPrivateKey( RSAKeyParameters key) { this.modulus = key.getModulus(); this.privateExponent = key.getExponent(); + this.rsaPrivateKey = key; } BCRSAPrivateKey( @@ -46,6 +45,7 @@ public class BCRSAPrivateKey { this.modulus = spec.getModulus(); this.privateExponent = spec.getPrivateExponent(); + this.rsaPrivateKey = new RSAKeyParameters(true, modulus, privateExponent); } BCRSAPrivateKey( @@ -53,12 +53,14 @@ public class BCRSAPrivateKey { this.modulus = key.getModulus(); this.privateExponent = key.getPrivateExponent(); + this.rsaPrivateKey = new RSAKeyParameters(true, modulus, privateExponent); } BCRSAPrivateKey(com.fr.third.org.bouncycastle.asn1.pkcs.RSAPrivateKey key) { this.modulus = key.getModulus(); this.privateExponent = key.getPrivateExponent(); + this.rsaPrivateKey = new RSAKeyParameters(true, modulus, privateExponent); } public BigInteger getModulus() @@ -81,6 +83,11 @@ public class BCRSAPrivateKey return "PKCS#8"; } + RSAKeyParameters engineGetKeyParameters() + { + return rsaPrivateKey; + } + public byte[] getEncoded() { return KeyUtil.getEncodedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE), new com.fr.third.org.bouncycastle.asn1.pkcs.RSAPrivateKey(getModulus(), ZERO, getPrivateExponent(), ZERO, ZERO, ZERO, ZERO, ZERO)); @@ -134,6 +141,7 @@ public class BCRSAPrivateKey in.defaultReadObject(); this.attrCarrier = new PKCS12BagAttributeCarrierImpl(); + this.rsaPrivateKey = new RSAKeyParameters(true, modulus, privateExponent); } private void writeObject( @@ -142,4 +150,16 @@ public class BCRSAPrivateKey { out.defaultWriteObject(); } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + buf.append("RSA Private Key [").append( + RSAUtil.generateKeyFingerprint(this.getModulus())).append("],[]").append(nl); + buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); + + return buf.toString(); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java index c5f8efeec..0c72a5b0d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/BCRSAPublicKey.java @@ -24,7 +24,9 @@ public class BCRSAPublicKey private BigInteger modulus; private BigInteger publicExponent; + private transient AlgorithmIdentifier algorithmIdentifier; + private transient RSAKeyParameters rsaPublicKey; BCRSAPublicKey( RSAKeyParameters key) @@ -32,6 +34,7 @@ public class BCRSAPublicKey this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; this.modulus = key.getModulus(); this.publicExponent = key.getExponent(); + this.rsaPublicKey = key; } BCRSAPublicKey( @@ -40,6 +43,7 @@ public class BCRSAPublicKey this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; this.modulus = spec.getModulus(); this.publicExponent = spec.getPublicExponent(); + this.rsaPublicKey = new RSAKeyParameters(false, modulus, publicExponent); } BCRSAPublicKey( @@ -48,6 +52,7 @@ public class BCRSAPublicKey this.algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; this.modulus = key.getModulus(); this.publicExponent = key.getPublicExponent(); + this.rsaPublicKey = new RSAKeyParameters(false, modulus, publicExponent); } BCRSAPublicKey( @@ -65,6 +70,7 @@ public class BCRSAPublicKey this.algorithmIdentifier = info.getAlgorithm(); this.modulus = pubKey.getModulus(); this.publicExponent = pubKey.getPublicExponent(); + this.rsaPublicKey = new RSAKeyParameters(false, modulus, publicExponent); } catch (IOException e) { @@ -107,6 +113,11 @@ public class BCRSAPublicKey return KeyUtil.getEncodedSubjectPublicKeyInfo(algorithmIdentifier, new com.fr.third.org.bouncycastle.asn1.pkcs.RSAPublicKey(getModulus(), getPublicExponent())); } + RSAKeyParameters engineGetKeyParameters() + { + return rsaPublicKey; + } + public int hashCode() { return this.getModulus().hashCode() ^ this.getPublicExponent().hashCode(); @@ -135,10 +146,14 @@ public class BCRSAPublicKey StringBuffer buf = new StringBuffer(); String nl = Strings.lineSeparator(); - buf.append("RSA Public Key [").append(RSAUtil.generateKeyFingerprint(this.getModulus(), this.getPublicExponent())).append("]").append(nl); - buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); - buf.append(" public exponent: ").append(this.getPublicExponent().toString(16)).append(nl); - + buf.append("RSA Public Key [").append(RSAUtil.generateKeyFingerprint(this.getModulus())).append("]") + .append(",[") + .append(RSAUtil.generateExponentFingerprint(this.getPublicExponent())) + .append("]") + .append(nl); + buf.append(" modulus: ").append(this.getModulus().toString(16)).append(nl); + buf.append("public exponent: ").append(this.getPublicExponent().toString(16)).append(nl); + return buf.toString(); } @@ -156,6 +171,7 @@ public class BCRSAPublicKey { algorithmIdentifier = DEFAULT_ALGORITHM_IDENTIFIER; } + this.rsaPublicKey = new RSAKeyParameters(false, modulus, publicExponent); } private void writeObject( diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java index b81ba906d..0b64f077a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/KeyFactorySpi.java @@ -18,8 +18,15 @@ import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import com.fr.third.org.bouncycastle.asn1.pkcs.RSAPrivateKey; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; +import com.fr.third.org.bouncycastle.crypto.util.OpenSSHPrivateKeyUtil; +import com.fr.third.org.bouncycastle.crypto.util.OpenSSHPublicKeyUtil; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.BaseKeyFactorySpi; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ExtendedInvalidKeySpecException; +import com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec; +import com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec; public class KeyFactorySpi extends BaseKeyFactorySpi @@ -56,6 +63,82 @@ public class KeyFactorySpi k.getPrimeExponentP(), k.getPrimeExponentQ(), k.getCrtCoefficient()); } + else if (spec.isAssignableFrom(OpenSSHPublicKeySpec.class) && key instanceof RSAPublicKey) + { + try + { + return new OpenSSHPublicKeySpec( + OpenSSHPublicKeyUtil.encodePublicKey( + new RSAKeyParameters( + false, + ((RSAPublicKey)key).getModulus(), + ((RSAPublicKey)key).getPublicExponent()) + ) + ); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else if (spec.isAssignableFrom(OpenSSHPrivateKeySpec.class) && key instanceof RSAPrivateCrtKey) + { + try + { + return new OpenSSHPrivateKeySpec(OpenSSHPrivateKeyUtil.encodePrivateKey(new RSAPrivateCrtKeyParameters( + ((RSAPrivateCrtKey)key).getModulus(), + ((RSAPrivateCrtKey)key).getPublicExponent(), + ((RSAPrivateCrtKey)key).getPrivateExponent(), + ((RSAPrivateCrtKey)key).getPrimeP(), + ((RSAPrivateCrtKey)key).getPrimeQ(), + ((RSAPrivateCrtKey)key).getPrimeExponentP(), + ((RSAPrivateCrtKey)key).getPrimeExponentQ(), + ((RSAPrivateCrtKey)key).getCrtCoefficient() + ))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.OpenSSHPublicKeySpec.class) && key instanceof RSAPublicKey) + { + try + { + return new com.fr.third.org.bouncycastle.jce.spec.OpenSSHPublicKeySpec( + OpenSSHPublicKeyUtil.encodePublicKey( + new RSAKeyParameters( + false, + ((RSAPublicKey)key).getModulus(), + ((RSAPublicKey)key).getPublicExponent()) + ) + ); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } + else if (spec.isAssignableFrom(com.fr.third.org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec.class) && key instanceof RSAPrivateCrtKey) + { + try + { + return new com.fr.third.org.bouncycastle.jce.spec.OpenSSHPrivateKeySpec(OpenSSHPrivateKeyUtil.encodePrivateKey(new RSAPrivateCrtKeyParameters( + ((RSAPrivateCrtKey)key).getModulus(), + ((RSAPrivateCrtKey)key).getPublicExponent(), + ((RSAPrivateCrtKey)key).getPrivateExponent(), + ((RSAPrivateCrtKey)key).getPrimeP(), + ((RSAPrivateCrtKey)key).getPrimeQ(), + ((RSAPrivateCrtKey)key).getPrimeExponentP(), + ((RSAPrivateCrtKey)key).getPrimeExponentQ(), + ((RSAPrivateCrtKey)key).getCrtCoefficient() + ))); + } + catch (IOException e) + { + throw new IllegalArgumentException("unable to produce encoding: " + e.getMessage()); + } + } return super.engineGetKeySpec(key, spec); } @@ -114,8 +197,19 @@ public class KeyFactorySpi { return new BCRSAPrivateKey((RSAPrivateKeySpec)keySpec); } + else if (keySpec instanceof OpenSSHPrivateKeySpec) + { + CipherParameters parameters = OpenSSHPrivateKeyUtil.parsePrivateKeyBlob(((OpenSSHPrivateKeySpec)keySpec).getEncoded()); + + if (parameters instanceof RSAPrivateCrtKeyParameters) + { + return new BCRSAPrivateCrtKey((RSAPrivateCrtKeyParameters)parameters); + } + + throw new InvalidKeySpecException("open SSH public key is not RSA private key"); + } - throw new InvalidKeySpecException("Unknown KeySpec type: " + keySpec.getClass().getName()); + throw new InvalidKeySpecException("unknown KeySpec type: " + keySpec.getClass().getName()); } protected PublicKey engineGeneratePublic( @@ -126,6 +220,18 @@ public class KeyFactorySpi { return new BCRSAPublicKey((RSAPublicKeySpec)keySpec); } + else if (keySpec instanceof OpenSSHPublicKeySpec) + { + + CipherParameters parameters = OpenSSHPublicKeyUtil.parsePublicKey(((OpenSSHPublicKeySpec)keySpec).getEncoded()); + if (parameters instanceof RSAKeyParameters) + { + return new BCRSAPublicKey((RSAKeyParameters)parameters); + } + + throw new InvalidKeySpecException("Open SSH public key is not RSA public key"); + + } return super.engineGeneratePublic(keySpec); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java index 5e342b5ca..0a60a9057 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/PSSSignatureSpi.java @@ -5,6 +5,7 @@ import java.security.AlgorithmParameters; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.PrivateKey; +import java.security.ProviderException; import java.security.PublicKey; import java.security.SecureRandom; import java.security.SignatureException; @@ -21,6 +22,7 @@ import com.fr.third.org.bouncycastle.crypto.CryptoException; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.engines.RSABlindedEngine; import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; import com.fr.third.org.bouncycastle.jcajce.provider.util.DigestFactory; import com.fr.third.org.bouncycastle.jcajce.util.BCJcaJceHelper; import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; @@ -39,8 +41,10 @@ public class PSSSignatureSpi private int saltLength; private byte trailer; private boolean isRaw; + private RSAKeyParameters key; private com.fr.third.org.bouncycastle.crypto.signers.PSSSigner pss; + private boolean isInitState = true; private byte getTrailer( int trailerField) @@ -108,9 +112,10 @@ public class PSSSignatureSpi throw new InvalidKeyException("Supplied key is not a RSAPublicKey instance"); } + key = RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey); pss = new com.fr.third.org.bouncycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength, trailer); - pss.init(false, - RSAUtil.generatePublicKeyParameter((RSAPublicKey)publicKey)); + pss.init(false, key); + isInitState = true; } protected void engineInitSign( @@ -123,8 +128,10 @@ public class PSSSignatureSpi throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance"); } + key = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey); pss = new com.fr.third.org.bouncycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength, trailer); - pss.init(true, new ParametersWithRandom(RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey), random)); + pss.init(true, new ParametersWithRandom(key, random)); + isInitState = true; } protected void engineInitSign( @@ -136,8 +143,10 @@ public class PSSSignatureSpi throw new InvalidKeyException("Supplied key is not a RSAPrivateKey instance"); } + key = RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey); pss = new com.fr.third.org.bouncycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength, trailer); - pss.init(true, RSAUtil.generatePrivateKeyParameter((RSAPrivateKey)privateKey)); + pss.init(true, key); + isInitState = true; } protected void engineUpdate( @@ -145,6 +154,7 @@ public class PSSSignatureSpi throws SignatureException { pss.update(b); + isInitState = false; } protected void engineUpdate( @@ -154,11 +164,13 @@ public class PSSSignatureSpi throws SignatureException { pss.update(b, off, len); + isInitState = false; } protected byte[] engineSign() throws SignatureException { + isInitState = true; try { return pss.generateSignature(); @@ -173,6 +185,7 @@ public class PSSSignatureSpi byte[] sigBytes) throws SignatureException { + isInitState = true; return pss.verifySignature(sigBytes); } @@ -180,6 +193,23 @@ public class PSSSignatureSpi AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { + if (params == null) + { + if (originalSpec != null) + { + params = originalSpec; + } + else + { + return; // Java 11 bug + } + } + + if (!isInitState) + { + throw new ProviderException("cannot call setParameter in the middle of update"); + } + if (params instanceof PSSParameterSpec) { PSSParameterSpec newParamSpec = (PSSParameterSpec)params; @@ -222,6 +252,19 @@ public class PSSSignatureSpi this.trailer = getTrailer(paramSpec.getTrailerField()); setupContentDigest(); + + if (key != null) + { + pss = new com.fr.third.org.bouncycastle.crypto.signers.PSSSigner(signer, contentDigest, mgfDigest, saltLength, trailer); + if (key.isPrivate()) + { + pss.init(true, key); + } + else + { + pss.init(false, key); + } + } } else { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java index 16bcac7d1..3e7140301 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/rsa/RSAUtil.java @@ -10,7 +10,6 @@ import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.params.RSAKeyParameters; import com.fr.third.org.bouncycastle.crypto.params.RSAPrivateCrtKeyParameters; -import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.Fingerprint; /** @@ -44,13 +43,22 @@ public class RSAUtil static RSAKeyParameters generatePublicKeyParameter( RSAPublicKey key) { - return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent()); + if (key instanceof BCRSAPublicKey) + { + return ((BCRSAPublicKey)key).engineGetKeyParameters(); + } + return new RSAKeyParameters(false, key.getModulus(), key.getPublicExponent()); } static RSAKeyParameters generatePrivateKeyParameter( RSAPrivateKey key) { + if (key instanceof BCRSAPrivateKey) + { + return ((BCRSAPrivateKey)key).engineGetKeyParameters(); + } + if (key instanceof RSAPrivateCrtKey) { RSAPrivateCrtKey k = (RSAPrivateCrtKey)key; @@ -67,8 +75,13 @@ public class RSAUtil } } - static String generateKeyFingerprint(BigInteger modulus, BigInteger publicExponent) + static String generateKeyFingerprint(BigInteger modulus) + { + return new Fingerprint(modulus.toByteArray()).toString(); + } + + static String generateExponentFingerprint(BigInteger exponent) { - return new Fingerprint(Arrays.concatenate(modulus.toByteArray(), publicExponent.toByteArray())).toString(); + return new Fingerprint(exponent.toByteArray(), 32).toString(); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java index 033e4aeef..0460be23f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/BaseAgreementSpi.java @@ -223,7 +223,7 @@ public abstract class BaseAgreementSpi byte[] secret = calcSecret(); try { - return getSharedSecretBytes(calcSecret(), null, secret.length * 8); + return getSharedSecretBytes(secret, null, secret.length * 8); } catch (NoSuchAlgorithmException e) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java index 486375fe1..321086501 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/DSABase.java @@ -7,25 +7,26 @@ import java.security.spec.AlgorithmParameterSpec; import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; -import com.fr.third.org.bouncycastle.crypto.DSA; +import com.fr.third.org.bouncycastle.crypto.DSAExt; import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.signers.DSAEncoding; public abstract class DSABase extends SignatureSpi implements PKCSObjectIdentifiers, X509ObjectIdentifiers { - protected Digest digest; - protected DSA signer; - protected DSAEncoder encoder; + protected Digest digest; + protected DSAExt signer; + protected DSAEncoding encoding; protected DSABase( Digest digest, - DSA signer, - DSAEncoder encoder) + DSAExt signer, + DSAEncoding encoding) { this.digest = digest; this.signer = signer; - this.encoder = encoder; + this.encoding = encoding; } protected void engineUpdate( @@ -47,15 +48,14 @@ public abstract class DSABase protected byte[] engineSign() throws SignatureException { - byte[] hash = new byte[digest.getDigestSize()]; - + byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); try { - BigInteger[] sig = signer.generateSignature(hash); + BigInteger[] sig = signer.generateSignature(hash); - return encoder.encode(sig[0], sig[1]); + return encoding.encode(signer.getOrder(), sig[0], sig[1]); } catch (Exception e) { @@ -67,15 +67,13 @@ public abstract class DSABase byte[] sigBytes) throws SignatureException { - byte[] hash = new byte[digest.getDigestSize()]; - + byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); - BigInteger[] sig; - + BigInteger[] sig; try { - sig = encoder.decode(sigBytes); + sig = encoding.decode(signer.getOrder(), sigBytes); } catch (Exception e) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java index efe930267..ab032d5d7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/DSAEncoder.java @@ -3,6 +3,9 @@ package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util; import java.io.IOException; import java.math.BigInteger; +/** + * @deprecated No longer used + */ public interface DSAEncoder { byte[] encode(BigInteger r, BigInteger s) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java index ad513c8b3..de2ab35c5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/EC5Util.java @@ -47,12 +47,16 @@ public class EC5Util } } - X9ECParameters c25519 = CustomNamedCurves.getByName("Curve25519"); + X9ECParameters x9_25519 = CustomNamedCurves.getByName("Curve25519"); + ECCurve c_25519 = x9_25519.getCurve(); customCurves.put(new ECCurve.Fp( - c25519.getCurve().getField().getCharacteristic(), - c25519.getCurve().getA().toBigInteger(), - c25519.getCurve().getB().toBigInteger()), c25519.getCurve()); + c_25519.getField().getCharacteristic(), + c_25519.getA().toBigInteger(), + c_25519.getB().toBigInteger(), + c_25519.getOrder(), + c_25519.getCofactor() + ), c_25519); } public static ECCurve getCurve( @@ -114,7 +118,7 @@ public class EC5Util } else { - domainParameters = ECUtil.getDomainParameters(configuration, convertSpec(params, false)); + domainParameters = ECUtil.getDomainParameters(configuration, convertSpec(params)); } return domainParameters; @@ -189,6 +193,16 @@ public class EC5Util domainParameters.getH().intValue()); } + public static ECParameterSpec convertToSpec( + ECDomainParameters domainParameters) + { + return new ECParameterSpec( + convertCurve(domainParameters.getCurve(), null), // JDK 1.5 has trouble with this if it's not null... + EC5Util.convertPoint(domainParameters.getG()), + domainParameters.getN(), + domainParameters.getH().intValue()); + } + public static EllipticCurve convertCurve( ECCurve curve, byte[] seed) @@ -247,51 +261,46 @@ public class EC5Util EllipticCurve ellipticCurve, com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec spec) { + ECPoint g = convertPoint(spec.getG()); + if (spec instanceof ECNamedCurveParameterSpec) { - return new ECNamedCurveSpec( - ((ECNamedCurveParameterSpec)spec).getName(), - ellipticCurve, - convertPoint(spec.getG()), - spec.getN(), - spec.getH()); + String name = ((ECNamedCurveParameterSpec)spec).getName(); + + return new ECNamedCurveSpec(name, ellipticCurve, g, spec.getN(), spec.getH()); } else { - return new ECParameterSpec( - ellipticCurve, - convertPoint(spec.getG()), - spec.getN(), - spec.getH().intValue()); + return new ECParameterSpec(ellipticCurve, g, spec.getN(), spec.getH().intValue()); } } - public static com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec convertSpec( - ECParameterSpec ecSpec, - boolean withCompression) + public static com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec convertSpec(ECParameterSpec ecSpec) { ECCurve curve = convertCurve(ecSpec.getCurve()); - return new com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec( - curve, - convertPoint(curve, ecSpec.getGenerator(), withCompression), - ecSpec.getOrder(), - BigInteger.valueOf(ecSpec.getCofactor()), - ecSpec.getCurve().getSeed()); + com.fr.third.org.bouncycastle.math.ec.ECPoint g = convertPoint(curve, ecSpec.getGenerator()); + BigInteger n = ecSpec.getOrder(); + BigInteger h = BigInteger.valueOf(ecSpec.getCofactor()); + byte[] seed = ecSpec.getCurve().getSeed(); + + if (ecSpec instanceof ECNamedCurveSpec) + { + return new com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec(((ECNamedCurveSpec)ecSpec).getName(), curve, + g, n, h, seed); + } + else + { + return new com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec(curve, g, n, h, seed); + } } - public static com.fr.third.org.bouncycastle.math.ec.ECPoint convertPoint( - ECParameterSpec ecSpec, - ECPoint point, - boolean withCompression) + public static com.fr.third.org.bouncycastle.math.ec.ECPoint convertPoint(ECParameterSpec ecSpec, ECPoint point) { - return convertPoint(convertCurve(ecSpec.getCurve()), point, withCompression); + return convertPoint(convertCurve(ecSpec.getCurve()), point); } - public static com.fr.third.org.bouncycastle.math.ec.ECPoint convertPoint( - ECCurve curve, - ECPoint point, - boolean withCompression) + public static com.fr.third.org.bouncycastle.math.ec.ECPoint convertPoint(ECCurve curve, ECPoint point) { return curve.createPoint(point.getAffineX(), point.getAffineY()); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java index 827df866b..e4f20f3b5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/ECUtil.java @@ -1,23 +1,20 @@ package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util; +import java.lang.reflect.Method; import java.math.BigInteger; +import java.security.AccessController; import java.security.InvalidKeyException; import java.security.PrivateKey; +import java.security.PrivilegedAction; import java.security.PublicKey; +import java.security.spec.AlgorithmParameterSpec; import java.util.Enumeration; import java.util.Map; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; -import com.fr.third.org.bouncycastle.asn1.anssi.ANSSINamedCurves; -import com.fr.third.org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; -import com.fr.third.org.bouncycastle.asn1.gm.GMNamedCurves; -import com.fr.third.org.bouncycastle.asn1.nist.NISTNamedCurves; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import com.fr.third.org.bouncycastle.asn1.sec.SECNamedCurves; -import com.fr.third.org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; -import com.fr.third.org.bouncycastle.asn1.x9.X962NamedCurves; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; import com.fr.third.org.bouncycastle.crypto.ec.CustomNamedCurves; @@ -34,6 +31,7 @@ import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.ec.FixedPointCombMultiplier; import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.Fingerprint; import com.fr.third.org.bouncycastle.util.Strings; @@ -191,9 +189,9 @@ public class ECUtil else if (key instanceof java.security.interfaces.ECPublicKey) { java.security.interfaces.ECPublicKey pubKey = (java.security.interfaces.ECPublicKey)key; - ECParameterSpec s = EC5Util.convertSpec(pubKey.getParams(), false); + ECParameterSpec s = EC5Util.convertSpec(pubKey.getParams()); return new ECPublicKeyParameters( - EC5Util.convertPoint(pubKey.getParams(), pubKey.getW(), false), + EC5Util.convertPoint(pubKey.getParams(), pubKey.getW()), new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); } else @@ -238,14 +236,25 @@ public class ECUtil s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); } - return new ECPrivateKeyParameters( - k.getD(), - new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); + if (k.getParameters() instanceof ECNamedCurveParameterSpec) + { + String name = ((ECNamedCurveParameterSpec)k.getParameters()).getName(); + return new ECPrivateKeyParameters( + k.getD(), + new ECNamedDomainParameters(ECNamedCurveTable.getOID(name), + s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); + } + else + { + return new ECPrivateKeyParameters( + k.getD(), + new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); + } } else if (key instanceof java.security.interfaces.ECPrivateKey) { java.security.interfaces.ECPrivateKey privKey = (java.security.interfaces.ECPrivateKey)key; - ECParameterSpec s = EC5Util.convertSpec(privKey.getParams(), false); + ECParameterSpec s = EC5Util.convertSpec(privKey.getParams()); return new ECPrivateKeyParameters( privKey.getS(), new ECDomainParameters(s.getCurve(), s.getG(), s.getN(), s.getH(), s.getSeed())); @@ -380,7 +389,7 @@ public class ECUtil StringBuffer buf = new StringBuffer(); String nl = Strings.lineSeparator(); - com.fr.third.org.bouncycastle.math.ec.ECPoint q = calculateQ(d, spec); + com.fr.third.org.bouncycastle.math.ec.ECPoint q = new FixedPointCombMultiplier().multiply(spec.getG(), d).normalize(); buf.append(algorithm); buf.append(" Private Key [").append(ECUtil.generateKeyFingerprint(q, spec)).append("]").append(nl); @@ -390,11 +399,6 @@ public class ECUtil return buf.toString(); } - private static com.fr.third.org.bouncycastle.math.ec.ECPoint calculateQ(BigInteger d, com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec spec) - { - return spec.getG().multiply(d).normalize(); - } - public static String publicKeyToString(String algorithm, com.fr.third.org.bouncycastle.math.ec.ECPoint q, com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec spec) { StringBuffer buf = new StringBuffer(); @@ -420,4 +424,26 @@ public class ECUtil return new Fingerprint(publicPoint.getEncoded(false)).toString(); } + + public static String getNameFrom(final AlgorithmParameterSpec paramSpec) + { + return (String)AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + try + { + Method m = paramSpec.getClass().getMethod("getName"); + + return m.invoke(paramSpec); + } + catch (Exception e) + { + // ignore - maybe log? + } + + return null; + } + }); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java index 31470ce71..42163f43a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/util/PKCS12BagAttributeCarrierImpl.java @@ -83,13 +83,12 @@ public class PKCS12BagAttributeCarrierImpl else { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - - Enumeration e = this.getBagAttributeKeys(); + ASN1OutputStream aOut = ASN1OutputStream.create(bOut); + Enumeration e = this.getBagAttributeKeys(); while (e.hasMoreElements()) { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(e.nextElement()); aOut.writeObject(oid); aOut.writeObject((ASN1Encodable)pkcs12Attributes.get(oid)); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java index c89f897fd..2af60d6d8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/PEMUtil.java @@ -8,43 +8,64 @@ import com.fr.third.org.bouncycastle.util.encoders.Base64; class PEMUtil { - private final String _header1; - private final String _header2; - private final String _header3; - private final String _footer1; - private final String _footer2; - private final String _footer3; - - PEMUtil( - String type) + /** + * Boundary class. Keeps track of the required header/footer pair for the + * current PEM object. + * + */ + private class Boundaries { - _header1 = "-----BEGIN " + type + "-----"; - _header2 = "-----BEGIN X509 " + type + "-----"; - _header3 = "-----BEGIN PKCS7-----"; - _footer1 = "-----END " + type + "-----"; - _footer2 = "-----END X509 " + type + "-----"; - _footer3 = "-----END PKCS7-----"; + private final String _header; + private final String _footer; + + private Boundaries(String type) + { + this._header = "-----BEGIN " + type + "-----"; + this._footer = "-----END " + type + "-----"; + } + + public boolean isTheExpectedHeader(String line) + { + return line.startsWith(_header); + } + + public boolean isTheExpectedFooter(String line) + { + return line.startsWith(_footer); + } } - private String readLine( - InputStream in) - throws IOException + private final Boundaries[] _supportedBoundaries; + + PEMUtil(String type) { - int c; + _supportedBoundaries = new Boundaries[] + { new Boundaries(type), new Boundaries("X509 " + type), + new Boundaries("PKCS7") }; + } + + private String readLine(InputStream in) throws IOException + { + int c; StringBuffer l = new StringBuffer(); do { while (((c = in.read()) != '\r') && c != '\n' && (c >= 0)) { - l.append((char)c); + l.append((char) c); } } while (c >= 0 && l.length() == 0); - + if (c < 0) { - return null; + // make sure to return the read bytes if the end of file is encountered + if (l.length() == 0) + { + return null; + } + return l.toString(); } // make sure we parse to end of line. @@ -66,6 +87,30 @@ class PEMUtil return l.toString(); } + /** + * Returns a {@link Boundaries} object representing the passed in boundary + * string. + * + * @param line the boundary string + * @return the {@link Boundaries} object corresponding to the given boundary + * string or null if the passed in string is not a valid + * boundary. + */ + private Boundaries getBoundaries(String line) + { + for (int i = 0; i != _supportedBoundaries.length; i++) + { + Boundaries boundary = _supportedBoundaries[i]; + + if (boundary.isTheExpectedHeader(line) || boundary.isTheExpectedFooter(line)) + { + return boundary; + } + } + + return null; + } + ASN1Sequence readPEMObject( InputStream in) throws IOException @@ -73,22 +118,43 @@ class PEMUtil String line; StringBuffer pemBuf = new StringBuffer(); - while ((line = readLine(in)) != null) + Boundaries header = null; + + while (header == null && (line = readLine(in)) != null) { - if (line.startsWith(_header1) || line.startsWith(_header2) || line.startsWith(_header3)) + header = getBoundaries(line); + if (header != null && !header.isTheExpectedHeader(line)) { - break; + throw new IOException("malformed PEM data: found footer where header was expected"); } } - while ((line = readLine(in)) != null) + if (header == null) + { + throw new IOException("malformed PEM data: no header found"); + } + + Boundaries footer = null; + + while (footer == null && (line = readLine(in)) != null) { - if (line.startsWith(_footer1) || line.startsWith(_footer2) || line.startsWith(_footer3)) + footer = getBoundaries(line); + if (footer != null) { - break; + if (!header.isTheExpectedFooter(line)) + { + throw new IOException("malformed PEM data: header/footer mismatch"); + } } + else + { + pemBuf.append(line); + } + } - pemBuf.append(line); + if (footer == null) + { + throw new IOException("malformed PEM data: no footer found"); } if (pemBuf.length() != 0) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java index 37ce3b75a..873f7901c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLEntryObject.java @@ -36,8 +36,9 @@ class X509CRLEntryObject extends X509CRLEntry private TBSCertList.CRLEntry c; private X500Name certificateIssuer; - private int hashValue; - private boolean isHashValueSet; + + private volatile boolean hashValueSet; + private volatile int hashValue; protected X509CRLEntryObject(TBSCertList.CRLEntry c) { @@ -202,27 +203,35 @@ class X509CRLEntryObject extends X509CRLEntry */ public int hashCode() { - if (!isHashValueSet) + if (!hashValueSet) { hashValue = super.hashCode(); - isHashValueSet = true; + hashValueSet = true; } return hashValue; } - public boolean equals(Object o) + public boolean equals(Object other) { - if (o == this) + if (other == this) { return true; } - if (o instanceof X509CRLEntryObject) + if (other instanceof X509CRLEntryObject) { - X509CRLEntryObject other = (X509CRLEntryObject)o; + X509CRLEntryObject otherBC = (X509CRLEntryObject)other; + + if (this.hashValueSet && otherBC.hashValueSet) + { + if (this.hashValue != otherBC.hashValue) + { + return false; + } + } - return this.c.equals(other.c); + return this.c.equals(otherBC.c); } return super.equals(this); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java new file mode 100644 index 000000000..8eddb4280 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLImpl.java @@ -0,0 +1,621 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.x509; + +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CRLException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLEntry; +import java.security.cert.X509Certificate; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.util.ASN1Dump; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.CRLDistPoint; +import com.fr.third.org.bouncycastle.asn1.x509.CRLNumber; +import com.fr.third.org.bouncycastle.asn1.x509.CertificateList; +import com.fr.third.org.bouncycastle.asn1.x509.Extension; +import com.fr.third.org.bouncycastle.asn1.x509.Extensions; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames; +import com.fr.third.org.bouncycastle.asn1.x509.IssuingDistributionPoint; +import com.fr.third.org.bouncycastle.asn1.x509.TBSCertList; +import com.fr.third.org.bouncycastle.jcajce.io.OutputStreamFactory; +import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; +import com.fr.third.org.bouncycastle.jce.X509Principal; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +/** + * The following extensions are listed in RFC 2459 as relevant to CRLs + * + * Authority Key Identifier + * Issuer Alternative Name + * CRL Number + * Delta CRL Indicator (critical) + * Issuing Distribution Point (critical) + */ +abstract class X509CRLImpl + extends X509CRL +{ + protected JcaJceHelper bcHelper; + protected CertificateList c; + protected String sigAlgName; + protected byte[] sigAlgParams; + protected boolean isIndirect; + + X509CRLImpl(JcaJceHelper bcHelper, CertificateList c, String sigAlgName, byte[] sigAlgParams, boolean isIndirect) + { + this.bcHelper = bcHelper; + this.c = c; + this.sigAlgName = sigAlgName; + this.sigAlgParams = sigAlgParams; + this.isIndirect = isIndirect; + } + + /** + * Will return true if any extensions are present and marked + * as critical as we currently dont handle any extensions! + */ + public boolean hasUnsupportedCriticalExtension() + { + Set extns = getCriticalExtensionOIDs(); + + if (extns == null) + { + return false; + } + + extns.remove(Extension.issuingDistributionPoint.getId()); + extns.remove(Extension.deltaCRLIndicator.getId()); + + return !extns.isEmpty(); + } + + private Set getExtensionOIDs(boolean critical) + { + if (this.getVersion() == 2) + { + Extensions extensions = c.getTBSCertList().getExtensions(); + + if (extensions != null) + { + Set set = new HashSet(); + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (critical == ext.isCritical()) + { + set.add(oid.getId()); + } + } + + return set; + } + } + + return null; + } + + public Set getCriticalExtensionOIDs() + { + return getExtensionOIDs(true); + } + + public Set getNonCriticalExtensionOIDs() + { + return getExtensionOIDs(false); + } + + public byte[] getExtensionValue(String oid) + { + ASN1OctetString extValue = getExtensionValue(c, oid); + if (null != extValue) + { + try + { + return extValue.getEncoded(); + } + catch (Exception e) + { + throw new IllegalStateException("error parsing " + e.toString()); + } + } + return null; + } + + public byte[] getEncoded() + throws CRLException + { + try + { + return c.getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CRLException(e.toString()); + } + } + + public void verify(PublicKey key) + throws CRLException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + Signature sig; + + try + { + sig = bcHelper.createSignature(getSigAlgName()); + } + catch (Exception e) + { + sig = Signature.getInstance(getSigAlgName()); + } + + doVerify(key, sig); + } + + public void verify(PublicKey key, String sigProvider) + throws CRLException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + Signature sig; + + if (sigProvider != null) + { + sig = Signature.getInstance(getSigAlgName(), sigProvider); + } + else + { + sig = Signature.getInstance(getSigAlgName()); + } + + doVerify(key, sig); + } + + public void verify(PublicKey key, Provider sigProvider) + throws CRLException, NoSuchAlgorithmException, + InvalidKeyException, SignatureException + { + Signature sig; + + if (sigProvider != null) + { + sig = Signature.getInstance(getSigAlgName(), sigProvider); + } + else + { + sig = Signature.getInstance(getSigAlgName()); + } + + doVerify(key, sig); + } + + private void doVerify(PublicKey key, Signature sig) + throws CRLException, NoSuchAlgorithmException, + InvalidKeyException, SignatureException + { + if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature())) + { + throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList."); + } + + if (sigAlgParams != null) + { + try + { + // needs to be called before initVerify(). + X509SignatureUtil.setSignatureParameters(sig, ASN1Primitive.fromByteArray(sigAlgParams)); + } + catch (IOException e) + { + throw new SignatureException("cannot decode signature parameters: " + e.getMessage()); + } + } + + sig.initVerify(key); + + try + { + OutputStream sigOut = new BufferedOutputStream(OutputStreamFactory.createStream(sig), 512); + + c.getTBSCertList().encodeTo(sigOut, ASN1Encoding.DER); + + sigOut.close(); + } + catch (IOException e) + { + throw new CRLException(e.toString()); + } + + if (!sig.verify(this.getSignature())) + { + throw new SignatureException("CRL does not verify with supplied public key."); + } + } + + public int getVersion() + { + return c.getVersionNumber(); + } + + public Principal getIssuerDN() + { + return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive())); + } + + public X500Principal getIssuerX500Principal() + { + try + { + return new X500Principal(c.getIssuer().getEncoded()); + } + catch (IOException e) + { + throw new IllegalStateException("can't encode issuer DN"); + } + } + + public Date getThisUpdate() + { + return c.getThisUpdate().getDate(); + } + + public Date getNextUpdate() + { + if (c.getNextUpdate() != null) + { + return c.getNextUpdate().getDate(); + } + + return null; + } + + private Set loadCRLEntries() + { + Set entrySet = new HashSet(); + Enumeration certs = c.getRevokedCertificateEnumeration(); + + X500Name previousCertificateIssuer = null; // the issuer + while (certs.hasMoreElements()) + { + TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement(); + X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer); + entrySet.add(crlEntry); + if (isIndirect && entry.hasExtensions()) + { + Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); + + if (currentCaName != null) + { + previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); + } + } + } + + return entrySet; + } + + public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) + { + Enumeration certs = c.getRevokedCertificateEnumeration(); + + X500Name previousCertificateIssuer = null; // the issuer + while (certs.hasMoreElements()) + { + TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement(); + + if (entry.getUserCertificate().hasValue(serialNumber)) + { + return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer); + } + + if (isIndirect && entry.hasExtensions()) + { + Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); + + if (currentCaName != null) + { + previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); + } + } + } + + return null; + } + + public Set getRevokedCertificates() + { + Set entrySet = loadCRLEntries(); + + if (!entrySet.isEmpty()) + { + return Collections.unmodifiableSet(entrySet); + } + + return null; + } + + public byte[] getTBSCertList() + throws CRLException + { + try + { + return c.getTBSCertList().getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CRLException(e.toString()); + } + } + + public byte[] getSignature() + { + return c.getSignature().getOctets(); + } + + public String getSigAlgName() + { + return sigAlgName; + } + + public String getSigAlgOID() + { + return c.getSignatureAlgorithm().getAlgorithm().getId(); + } + + public byte[] getSigAlgParams() + { + return Arrays.clone(sigAlgParams); + } + + /** + * Returns a string representation of this CRL. + * + * @return a string representation of this CRL. + */ + public String toString() + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + buf.append(" Version: ").append(this.getVersion()).append( + nl); + buf.append(" IssuerDN: ").append(this.getIssuerDN()) + .append(nl); + buf.append(" This update: ").append(this.getThisUpdate()) + .append(nl); + buf.append(" Next update: ").append(this.getNextUpdate()) + .append(nl); + buf.append(" Signature Algorithm: ").append(this.getSigAlgName()) + .append(nl); + + byte[] sig = this.getSignature(); + + buf.append(" Signature: ").append( + new String(Hex.encode(sig, 0, 20))).append(nl); + for (int i = 20; i < sig.length; i += 20) + { + if (i < sig.length - 20) + { + buf.append(" ").append( + new String(Hex.encode(sig, i, 20))).append(nl); + } + else + { + buf.append(" ").append( + new String(Hex.encode(sig, i, sig.length - i))).append(nl); + } + } + + Extensions extensions = c.getTBSCertList().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + if (e.hasMoreElements()) + { + buf.append(" Extensions: ").append(nl); + } + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (ext.getExtnValue() != null) + { + byte[] octs = ext.getExtnValue().getOctets(); + ASN1InputStream dIn = new ASN1InputStream(octs); + buf.append(" critical(").append( + ext.isCritical()).append(") "); + try + { + if (oid.equals(Extension.cRLNumber)) + { + buf.append( + new CRLNumber(ASN1Integer.getInstance( + dIn.readObject()).getPositiveValue())) + .append(nl); + } + else if (oid.equals(Extension.deltaCRLIndicator)) + { + buf.append( + "Base CRL: " + + new CRLNumber(ASN1Integer.getInstance( + dIn.readObject()).getPositiveValue())) + .append(nl); + } + else if (oid + .equals(Extension.issuingDistributionPoint)) + { + buf.append( + IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl); + } + else if (oid + .equals(Extension.cRLDistributionPoints)) + { + buf.append( + CRLDistPoint.getInstance(dIn.readObject())).append(nl); + } + else if (oid.equals(Extension.freshestCRL)) + { + buf.append( + CRLDistPoint.getInstance(dIn.readObject())).append(nl); + } + else + { + buf.append(oid.getId()); + buf.append(" value = ").append( + ASN1Dump.dumpAsString(dIn.readObject())) + .append(nl); + } + } + catch (Exception ex) + { + buf.append(oid.getId()); + buf.append(" value = ").append("*****").append(nl); + } + } + else + { + buf.append(nl); + } + } + } + Set set = getRevokedCertificates(); + if (set != null) + { + Iterator it = set.iterator(); + while (it.hasNext()) + { + buf.append(it.next()); + buf.append(nl); + } + } + return buf.toString(); + } + + /** + * Checks whether the given certificate is on this CRL. + * + * @param cert the certificate to check for. + * @return true if the given certificate is on this CRL, + * false otherwise. + */ + public boolean isRevoked(Certificate cert) + { + if (!cert.getType().equals("X.509")) + { + throw new IllegalArgumentException("X.509 CRL used with non X.509 Cert"); + } + + Enumeration certs = c.getRevokedCertificateEnumeration(); + + X500Name caName = c.getIssuer(); + + if (certs.hasMoreElements()) + { + BigInteger serial = ((X509Certificate)cert).getSerialNumber(); + + while (certs.hasMoreElements()) + { + TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement()); + + if (isIndirect && entry.hasExtensions()) + { + Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); + + if (currentCaName != null) + { + caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); + } + } + + if (entry.getUserCertificate().hasValue(serial)) + { + X500Name issuer; + + if (cert instanceof X509Certificate) + { + issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded()); + } + else + { + try + { + issuer = com.fr.third.org.bouncycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer(); + } + catch (CertificateEncodingException e) + { + throw new IllegalArgumentException("Cannot process certificate: " + e.getMessage()); + } + } + + if (!caName.equals(issuer)) + { + return false; + } + + return true; + } + } + } + + return false; + } + + protected static byte[] getExtensionOctets(CertificateList c, String oid) + { + ASN1OctetString extValue = getExtensionValue(c, oid); + if (null != extValue) + { + return extValue.getOctets(); + } + return null; + } + + protected static ASN1OctetString getExtensionValue(CertificateList c, String oid) + { + Extensions exts = c.getTBSCertList().getExtensions(); + if (null != exts) + { + Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); + if (null != ext) + { + return ext.getExtnValue(); + } + } + return null; + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLInternal.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLInternal.java new file mode 100644 index 000000000..3b73291d1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLInternal.java @@ -0,0 +1,29 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.x509; + +import java.security.cert.CRLException; + +import com.fr.third.org.bouncycastle.asn1.x509.CertificateList; +import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; + +class X509CRLInternal extends X509CRLImpl +{ + private final byte[] encoding; + + X509CRLInternal(JcaJceHelper bcHelper, CertificateList c, String sigAlgName, byte[] sigAlgParams, boolean isIndirect, + byte[] encoding) + { + super(bcHelper, c, sigAlgName, sigAlgParams, isIndirect); + + this.encoding = encoding; + } + + public byte[] getEncoded() throws CRLException + { + if (null == encoding) + { + throw new CRLException(); + } + + return encoding; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java index f0f7906d3..e9511e49b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CRLObject.java @@ -1,681 +1,149 @@ package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.x509; -import java.io.IOException; -import java.math.BigInteger; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Principal; -import java.security.Provider; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; import java.security.cert.CRLException; -import java.security.cert.Certificate; -import java.security.cert.CertificateEncodingException; -import java.security.cert.X509CRL; -import java.security.cert.X509CRLEntry; -import java.security.cert.X509Certificate; -import java.util.Collections; -import java.util.Date; -import java.util.Enumeration; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; - -import javax.security.auth.x500.X500Principal; +import com.fr.third.org.bouncycastle.asn1.ASN1BitString; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; -import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; -import com.fr.third.org.bouncycastle.asn1.ASN1Integer; -import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; -import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; -import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; -import com.fr.third.org.bouncycastle.asn1.util.ASN1Dump; -import com.fr.third.org.bouncycastle.asn1.x500.X500Name; -import com.fr.third.org.bouncycastle.asn1.x509.CRLDistPoint; -import com.fr.third.org.bouncycastle.asn1.x509.CRLNumber; import com.fr.third.org.bouncycastle.asn1.x509.CertificateList; import com.fr.third.org.bouncycastle.asn1.x509.Extension; -import com.fr.third.org.bouncycastle.asn1.x509.Extensions; -import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames; import com.fr.third.org.bouncycastle.asn1.x509.IssuingDistributionPoint; -import com.fr.third.org.bouncycastle.asn1.x509.TBSCertList; import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; -import com.fr.third.org.bouncycastle.jce.X509Principal; -import com.fr.third.org.bouncycastle.util.Strings; -import com.fr.third.org.bouncycastle.util.encoders.Hex; -/** - * The following extensions are listed in RFC 2459 as relevant to CRLs - * - * Authority Key Identifier - * Issuer Alternative Name - * CRL Number - * Delta CRL Indicator (critical) - * Issuing Distribution Point (critical) - */ class X509CRLObject - extends X509CRL + extends X509CRLImpl { - private JcaJceHelper bcHelper; - private CertificateList c; - private String sigAlgName; - private byte[] sigAlgParams; - private boolean isIndirect; - private boolean isHashCodeSet = false; - private int hashCodeValue; + private final Object cacheLock = new Object(); + private X509CRLInternal internalCRLValue; - static boolean isIndirectCRL(X509CRL crl) - throws CRLException - { - try - { - byte[] idp = crl.getExtensionValue(Extension.issuingDistributionPoint.getId()); - return idp != null - && IssuingDistributionPoint.getInstance(ASN1OctetString.getInstance(idp).getOctets()).isIndirectCRL(); - } - catch (Exception e) - { - throw new ExtCRLException( - "Exception reading IssuingDistributionPoint", e); - } - } + private volatile boolean hashValueSet; + private volatile int hashValue; - protected X509CRLObject( - JcaJceHelper bcHelper, - CertificateList c) - throws CRLException + X509CRLObject(JcaJceHelper bcHelper, CertificateList c) throws CRLException { - this.bcHelper = bcHelper; - this.c = c; - - try - { - this.sigAlgName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); - - if (c.getSignatureAlgorithm().getParameters() != null) - { - this.sigAlgParams = ((ASN1Encodable)c.getSignatureAlgorithm().getParameters()).toASN1Primitive().getEncoded(ASN1Encoding.DER); - } - else - { - this.sigAlgParams = null; - } - - this.isIndirect = isIndirectCRL(this); - } - catch (Exception e) - { - throw new CRLException("CRL contents invalid: " + e); - } + super(bcHelper, c, createSigAlgName(c), createSigAlgParams(c), isIndirectCRL(c)); } - /** - * Will return true if any extensions are present and marked - * as critical as we currently dont handle any extensions! - */ - public boolean hasUnsupportedCriticalExtension() + public boolean equals(Object other) { - Set extns = getCriticalExtensionOIDs(); - - if (extns == null) + if (this == other) { - return false; + return true; } - extns.remove(Extension.issuingDistributionPoint.getId()); - extns.remove(Extension.deltaCRLIndicator.getId()); - - return !extns.isEmpty(); - } - - private Set getExtensionOIDs(boolean critical) - { - if (this.getVersion() == 2) + if (other instanceof X509CRLObject) { - Extensions extensions = c.getTBSCertList().getExtensions(); + X509CRLObject otherBC = (X509CRLObject)other; - if (extensions != null) + if (this.hashValueSet && otherBC.hashValueSet) { - Set set = new HashSet(); - Enumeration e = extensions.oids(); - - while (e.hasMoreElements()) + if (this.hashValue != otherBC.hashValue) { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - Extension ext = extensions.getExtension(oid); - - if (critical == ext.isCritical()) - { - set.add(oid.getId()); - } + return false; } - - return set; } - } - - return null; - } - - public Set getCriticalExtensionOIDs() - { - return getExtensionOIDs(true); - } - - public Set getNonCriticalExtensionOIDs() - { - return getExtensionOIDs(false); - } - - public byte[] getExtensionValue(String oid) - { - Extensions exts = c.getTBSCertList().getExtensions(); - - if (exts != null) - { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) + else if (null == internalCRLValue || null == otherBC.internalCRLValue) { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) + ASN1BitString signature = c.getSignature(); + if (null != signature && !signature.equals(otherBC.c.getSignature())) { - throw new IllegalStateException("error parsing " + e.toString()); + return false; } } } - return null; - } - - public byte[] getEncoded() - throws CRLException - { - try - { - return c.getEncoded(ASN1Encoding.DER); - } - catch (IOException e) - { - throw new CRLException(e.toString()); - } - } - - public void verify(PublicKey key) - throws CRLException, NoSuchAlgorithmException, - InvalidKeyException, NoSuchProviderException, SignatureException - { - Signature sig; - - try - { - sig = bcHelper.createSignature(getSigAlgName()); - } - catch (Exception e) - { - sig = Signature.getInstance(getSigAlgName()); - } - - doVerify(key, sig); - } - - public void verify(PublicKey key, String sigProvider) - throws CRLException, NoSuchAlgorithmException, - InvalidKeyException, NoSuchProviderException, SignatureException - { - Signature sig; - - if (sigProvider != null) - { - sig = Signature.getInstance(getSigAlgName(), sigProvider); - } - else - { - sig = Signature.getInstance(getSigAlgName()); - } - - doVerify(key, sig); + return getInternalCRL().equals(other); } - public void verify(PublicKey key, Provider sigProvider) - throws CRLException, NoSuchAlgorithmException, - InvalidKeyException, SignatureException + public int hashCode() { - Signature sig; - - if (sigProvider != null) + if (!hashValueSet) { - sig = Signature.getInstance(getSigAlgName(), sigProvider); - } - else - { - sig = Signature.getInstance(getSigAlgName()); + hashValue = getInternalCRL().hashCode(); + hashValueSet = true; } - doVerify(key, sig); + return hashValue; } - private void doVerify(PublicKey key, Signature sig) - throws CRLException, NoSuchAlgorithmException, - InvalidKeyException, SignatureException + private X509CRLInternal getInternalCRL() { - if (!c.getSignatureAlgorithm().equals(c.getTBSCertList().getSignature())) + synchronized (cacheLock) { - throw new CRLException("Signature algorithm on CertificateList does not match TBSCertList."); - } - - if (sigAlgParams != null) - { - try - { - // needs to be called before initVerify(). - X509SignatureUtil.setSignatureParameters(sig, ASN1Primitive.fromByteArray(sigAlgParams)); - } - catch (IOException e) + if (null != internalCRLValue) { - throw new SignatureException("cannot decode signature parameters: " + e.getMessage()); + return internalCRLValue; } } - sig.initVerify(key); - sig.update(this.getTBSCertList()); - - if (!sig.verify(this.getSignature())) - { - throw new SignatureException("CRL does not verify with supplied public key."); - } - } - - public int getVersion() - { - return c.getVersionNumber(); - } - - public Principal getIssuerDN() - { - return new X509Principal(X500Name.getInstance(c.getIssuer().toASN1Primitive())); - } - - public X500Principal getIssuerX500Principal() - { + byte[] encoding; try { - return new X500Principal(c.getIssuer().getEncoded()); - } - catch (IOException e) - { - throw new IllegalStateException("can't encode issuer DN"); + encoding = getEncoded(); } - } - - public Date getThisUpdate() - { - return c.getThisUpdate().getDate(); - } - - public Date getNextUpdate() - { - if (c.getNextUpdate() != null) - { - return c.getNextUpdate().getDate(); - } - - return null; - } - - private Set loadCRLEntries() - { - Set entrySet = new HashSet(); - Enumeration certs = c.getRevokedCertificateEnumeration(); - - X500Name previousCertificateIssuer = null; // the issuer - while (certs.hasMoreElements()) + catch (CRLException e) { - TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement(); - X509CRLEntryObject crlEntry = new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer); - entrySet.add(crlEntry); - if (isIndirect && entry.hasExtensions()) - { - Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); - - if (currentCaName != null) - { - previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); - } - } + encoding = null; } - return entrySet; - } - - public X509CRLEntry getRevokedCertificate(BigInteger serialNumber) - { - Enumeration certs = c.getRevokedCertificateEnumeration(); + X509CRLInternal temp = new X509CRLInternal(bcHelper, c, sigAlgName,sigAlgParams, isIndirect, encoding); - X500Name previousCertificateIssuer = null; // the issuer - while (certs.hasMoreElements()) + synchronized (cacheLock) { - TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement(); - - if (serialNumber.equals(entry.getUserCertificate().getValue())) - { - return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer); - } - - if (isIndirect && entry.hasExtensions()) + if (null == internalCRLValue) { - Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); - - if (currentCaName != null) - { - previousCertificateIssuer = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); - } + internalCRLValue = temp; } - } - - return null; - } - - public Set getRevokedCertificates() - { - Set entrySet = loadCRLEntries(); - if (!entrySet.isEmpty()) - { - return Collections.unmodifiableSet(entrySet); + return internalCRLValue; } - - return null; } - public byte[] getTBSCertList() - throws CRLException + private static String createSigAlgName(CertificateList c) throws CRLException { try { - return c.getTBSCertList().getEncoded("DER"); + return X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); } - catch (IOException e) - { - throw new CRLException(e.toString()); - } - } - - public byte[] getSignature() - { - return c.getSignature().getOctets(); - } - - public String getSigAlgName() - { - return sigAlgName; - } - - public String getSigAlgOID() - { - return c.getSignatureAlgorithm().getAlgorithm().getId(); - } - - public byte[] getSigAlgParams() - { - if (sigAlgParams != null) + catch (Exception e) { - byte[] tmp = new byte[sigAlgParams.length]; - - System.arraycopy(sigAlgParams, 0, tmp, 0, tmp.length); - - return tmp; + throw new CRLException("CRL contents invalid: " + e); } - - return null; } - /** - * Returns a string representation of this CRL. - * - * @return a string representation of this CRL. - */ - public String toString() + private static byte[] createSigAlgParams(CertificateList c) throws CRLException { - StringBuffer buf = new StringBuffer(); - String nl = Strings.lineSeparator(); - - buf.append(" Version: ").append(this.getVersion()).append( - nl); - buf.append(" IssuerDN: ").append(this.getIssuerDN()) - .append(nl); - buf.append(" This update: ").append(this.getThisUpdate()) - .append(nl); - buf.append(" Next update: ").append(this.getNextUpdate()) - .append(nl); - buf.append(" Signature Algorithm: ").append(this.getSigAlgName()) - .append(nl); - - byte[] sig = this.getSignature(); - - buf.append(" Signature: ").append( - new String(Hex.encode(sig, 0, 20))).append(nl); - for (int i = 20; i < sig.length; i += 20) - { - if (i < sig.length - 20) - { - buf.append(" ").append( - new String(Hex.encode(sig, i, 20))).append(nl); - } - else - { - buf.append(" ").append( - new String(Hex.encode(sig, i, sig.length - i))).append(nl); - } - } - - Extensions extensions = c.getTBSCertList().getExtensions(); - - if (extensions != null) - { - Enumeration e = extensions.oids(); - - if (e.hasMoreElements()) - { - buf.append(" Extensions: ").append(nl); - } - - while (e.hasMoreElements()) - { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) e.nextElement(); - Extension ext = extensions.getExtension(oid); - - if (ext.getExtnValue() != null) - { - byte[] octs = ext.getExtnValue().getOctets(); - ASN1InputStream dIn = new ASN1InputStream(octs); - buf.append(" critical(").append( - ext.isCritical()).append(") "); - try - { - if (oid.equals(Extension.cRLNumber)) - { - buf.append( - new CRLNumber(ASN1Integer.getInstance( - dIn.readObject()).getPositiveValue())) - .append(nl); - } - else if (oid.equals(Extension.deltaCRLIndicator)) - { - buf.append( - "Base CRL: " - + new CRLNumber(ASN1Integer.getInstance( - dIn.readObject()).getPositiveValue())) - .append(nl); - } - else if (oid - .equals(Extension.issuingDistributionPoint)) - { - buf.append( - IssuingDistributionPoint.getInstance(dIn.readObject())).append(nl); - } - else if (oid - .equals(Extension.cRLDistributionPoints)) - { - buf.append( - CRLDistPoint.getInstance(dIn.readObject())).append(nl); - } - else if (oid.equals(Extension.freshestCRL)) - { - buf.append( - CRLDistPoint.getInstance(dIn.readObject())).append(nl); - } - else - { - buf.append(oid.getId()); - buf.append(" value = ").append( - ASN1Dump.dumpAsString(dIn.readObject())) - .append(nl); - } - } - catch (Exception ex) - { - buf.append(oid.getId()); - buf.append(" value = ").append("*****").append(nl); - } - } - else - { - buf.append(nl); - } - } - } - Set set = getRevokedCertificates(); - if (set != null) + try { - Iterator it = set.iterator(); - while (it.hasNext()) + ASN1Encodable parameters = c.getSignatureAlgorithm().getParameters(); + if (null == parameters) { - buf.append(it.next()); - buf.append(nl); + return null; } - } - return buf.toString(); - } - /** - * Checks whether the given certificate is on this CRL. - * - * @param cert the certificate to check for. - * @return true if the given certificate is on this CRL, - * false otherwise. - */ - public boolean isRevoked(Certificate cert) - { - if (!cert.getType().equals("X.509")) - { - throw new IllegalArgumentException("X.509 CRL used with non X.509 Cert"); + return parameters.toASN1Primitive().getEncoded(ASN1Encoding.DER); } - - Enumeration certs = c.getRevokedCertificateEnumeration(); - - X500Name caName = c.getIssuer(); - - if (certs.hasMoreElements()) + catch (Exception e) { - BigInteger serial = ((X509Certificate)cert).getSerialNumber(); - - while (certs.hasMoreElements()) - { - TBSCertList.CRLEntry entry = TBSCertList.CRLEntry.getInstance(certs.nextElement()); - - if (isIndirect && entry.hasExtensions()) - { - Extension currentCaName = entry.getExtensions().getExtension(Extension.certificateIssuer); - - if (currentCaName != null) - { - caName = X500Name.getInstance(GeneralNames.getInstance(currentCaName.getParsedValue()).getNames()[0].getName()); - } - } - - if (entry.getUserCertificate().getValue().equals(serial)) - { - X500Name issuer; - - if (cert instanceof X509Certificate) - { - issuer = X500Name.getInstance(((X509Certificate)cert).getIssuerX500Principal().getEncoded()); - } - else - { - try - { - issuer = com.fr.third.org.bouncycastle.asn1.x509.Certificate.getInstance(cert.getEncoded()).getIssuer(); - } - catch (CertificateEncodingException e) - { - throw new IllegalArgumentException("Cannot process certificate: " + e.getMessage()); - } - } - - if (!caName.equals(issuer)) - { - return false; - } - - return true; - } - } + throw new CRLException("CRL contents invalid: " + e); } - - return false; } - public boolean equals(Object other) + private static boolean isIndirectCRL(CertificateList c) throws CRLException { - if (this == other) - { - return true; - } - - if (!(other instanceof X509CRL)) - { - return false; - } - - if (other instanceof X509CRLObject) + try { - X509CRLObject crlObject = (X509CRLObject)other; - - if (isHashCodeSet) + byte[] extOctets = getExtensionOctets(c, Extension.issuingDistributionPoint.getId()); + if (null == extOctets) { - boolean otherIsHashCodeSet = crlObject.isHashCodeSet; - if (otherIsHashCodeSet) - { - if (crlObject.hashCodeValue != hashCodeValue) - { - return false; - } - } + return false; } - return this.c.equals(crlObject.c); + return IssuingDistributionPoint.getInstance(extOctets).isIndirectCRL(); } - - return super.equals(other); - } - - public int hashCode() - { - if (!isHashCodeSet) + catch (Exception e) { - isHashCodeSet = true; - hashCodeValue = super.hashCode(); + throw new ExtCRLException("Exception reading IssuingDistributionPoint", e); } - - return hashCodeValue; } } - diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java new file mode 100644 index 000000000..1fb602bb2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateImpl.java @@ -0,0 +1,803 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.x509; + +import java.io.BufferedOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateParsingException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1String; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DERIA5String; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.misc.MiscObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.misc.NetscapeCertType; +import com.fr.third.org.bouncycastle.asn1.misc.NetscapeRevocationURL; +import com.fr.third.org.bouncycastle.asn1.misc.VerisignCzagExtension; +import com.fr.third.org.bouncycastle.asn1.util.ASN1Dump; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.style.RFC4519Style; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.BasicConstraints; +import com.fr.third.org.bouncycastle.asn1.x509.Extension; +import com.fr.third.org.bouncycastle.asn1.x509.Extensions; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.KeyUsage; +import com.fr.third.org.bouncycastle.asn1.x509.TBSCertificate; +import com.fr.third.org.bouncycastle.jcajce.interfaces.BCX509Certificate; +import com.fr.third.org.bouncycastle.jcajce.io.OutputStreamFactory; +import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; +import com.fr.third.org.bouncycastle.jce.X509Principal; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Integers; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +abstract class X509CertificateImpl + extends X509Certificate + implements BCX509Certificate +{ + protected JcaJceHelper bcHelper; + protected com.fr.third.org.bouncycastle.asn1.x509.Certificate c; + protected BasicConstraints basicConstraints; + protected boolean[] keyUsage; + + X509CertificateImpl(JcaJceHelper bcHelper, com.fr.third.org.bouncycastle.asn1.x509.Certificate c, + BasicConstraints basicConstraints, boolean[] keyUsage) + { + this.bcHelper = bcHelper; + this.c = c; + this.basicConstraints = basicConstraints; + this.keyUsage = keyUsage; + } + + public X500Name getIssuerX500Name() + { + return c.getIssuer(); + } + + public TBSCertificate getTBSCertificateNative() + { + return c.getTBSCertificate(); + } + + public X500Name getSubjectX500Name() + { + return c.getSubject(); + } + + public void checkValidity() + throws CertificateExpiredException, CertificateNotYetValidException + { + this.checkValidity(new Date()); + } + + public void checkValidity( + Date date) + throws CertificateExpiredException, CertificateNotYetValidException + { + if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility + { + throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime()); + } + + if (date.getTime() < this.getNotBefore().getTime()) + { + throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime()); + } + } + + public int getVersion() + { + return c.getVersionNumber(); + } + + public BigInteger getSerialNumber() + { + return c.getSerialNumber().getValue(); + } + + public Principal getIssuerDN() + { + return new X509Principal(c.getIssuer()); + } + + public X500Principal getIssuerX500Principal() + { + try + { + byte[] encoding = c.getIssuer().getEncoded(ASN1Encoding.DER); + + return new X500Principal(encoding); + } + catch (IOException e) + { + throw new IllegalStateException("can't encode issuer DN"); + } + } + + public Principal getSubjectDN() + { + return new X509Principal(c.getSubject()); + } + + public X500Principal getSubjectX500Principal() + { + try + { + byte[] encoding = c.getSubject().getEncoded(ASN1Encoding.DER); + + return new X500Principal(encoding); + } + catch (IOException e) + { + throw new IllegalStateException("can't encode subject DN"); + } + } + + public Date getNotBefore() + { + return c.getStartDate().getDate(); + } + + public Date getNotAfter() + { + return c.getEndDate().getDate(); + } + + public byte[] getTBSCertificate() + throws CertificateEncodingException + { + try + { + return c.getTBSCertificate().getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CertificateEncodingException(e.toString()); + } + } + + public byte[] getSignature() + { + return c.getSignature().getOctets(); + } + + /** + * return a more "meaningful" representation for the signature algorithm used in + * the certificate. + */ + public String getSigAlgName() + { + return X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); + } + + /** + * return the object identifier for the signature. + */ + public String getSigAlgOID() + { + return c.getSignatureAlgorithm().getAlgorithm().getId(); + } + + /** + * return the signature parameters, or null if there aren't any. + */ + public byte[] getSigAlgParams() + { + if (c.getSignatureAlgorithm().getParameters() != null) + { + try + { + return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + return null; + } + } + else + { + return null; + } + } + + public boolean[] getIssuerUniqueID() + { + DERBitString id = c.getTBSCertificate().getIssuerUniqueId(); + + if (id != null) + { + byte[] bytes = id.getBytes(); + boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()]; + + for (int i = 0; i != boolId.length; i++) + { + boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + } + + return boolId; + } + + return null; + } + + public boolean[] getSubjectUniqueID() + { + DERBitString id = c.getTBSCertificate().getSubjectUniqueId(); + + if (id != null) + { + byte[] bytes = id.getBytes(); + boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()]; + + for (int i = 0; i != boolId.length; i++) + { + boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + } + + return boolId; + } + + return null; + } + + public boolean[] getKeyUsage() + { + return Arrays.clone(keyUsage); + } + + public List getExtendedKeyUsage() + throws CertificateParsingException + { + byte[] extOctets = getExtensionOctets(c, "2.5.29.37"); + if (null == extOctets) + { + return null; + } + + try + { + ASN1Sequence seq = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(extOctets)); + + List list = new ArrayList(); + for (int i = 0; i != seq.size(); i++) + { + list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId()); + } + return Collections.unmodifiableList(list); + } + catch (Exception e) + { + throw new CertificateParsingException("error processing extended key usage extension"); + } + } + + public int getBasicConstraints() + { + if (basicConstraints != null) + { + if (basicConstraints.isCA()) + { + if (basicConstraints.getPathLenConstraint() == null) + { + return Integer.MAX_VALUE; + } + else + { + return basicConstraints.getPathLenConstraint().intValue(); + } + } + else + { + return -1; + } + } + + return -1; + } + + public Collection getSubjectAlternativeNames() + throws CertificateParsingException + { + return getAlternativeNames(c, Extension.subjectAlternativeName.getId()); + } + + public Collection getIssuerAlternativeNames() + throws CertificateParsingException + { + return getAlternativeNames(c, Extension.issuerAlternativeName.getId()); + } + + public Set getCriticalExtensionOIDs() + { + if (this.getVersion() == 3) + { + Set set = new HashSet(); + Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (ext.isCritical()) + { + set.add(oid.getId()); + } + } + + return set; + } + } + + return null; + } + + public byte[] getExtensionValue(String oid) + { + ASN1OctetString extValue = getExtensionValue(c, oid); + if (null != extValue) + { + try + { + return extValue.getEncoded(); + } + catch (Exception e) + { + throw new IllegalStateException("error parsing " + e.toString()); + } + } + + return null; + } + + public Set getNonCriticalExtensionOIDs() + { + if (this.getVersion() == 3) + { + Set set = new HashSet(); + Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (!ext.isCritical()) + { + set.add(oid.getId()); + } + } + + return set; + } + } + + return null; + } + + public boolean hasUnsupportedCriticalExtension() + { + if (this.getVersion() == 3) + { + Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + + if (oid.equals(Extension.keyUsage) + || oid.equals(Extension.certificatePolicies) + || oid.equals(Extension.policyMappings) + || oid.equals(Extension.inhibitAnyPolicy) + || oid.equals(Extension.cRLDistributionPoints) + || oid.equals(Extension.issuingDistributionPoint) + || oid.equals(Extension.deltaCRLIndicator) + || oid.equals(Extension.policyConstraints) + || oid.equals(Extension.basicConstraints) + || oid.equals(Extension.subjectAlternativeName) + || oid.equals(Extension.nameConstraints)) + { + continue; + } + + Extension ext = extensions.getExtension(oid); + + if (ext.isCritical()) + { + return true; + } + } + } + } + + return false; + } + + public PublicKey getPublicKey() + { + try + { + return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo()); + } + catch (IOException e) + { + return null; // should never happen... + } + } + + public byte[] getEncoded() + throws CertificateEncodingException + { + try + { + return c.getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CertificateEncodingException(e.toString()); + } + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + buf.append(" [0] Version: ").append(this.getVersion()).append(nl); + buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl); + buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl); + buf.append(" Start Date: ").append(this.getNotBefore()).append(nl); + buf.append(" Final Date: ").append(this.getNotAfter()).append(nl); + buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl); + buf.append(" Public Key: ").append(this.getPublicKey()).append(nl); + buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl); + + byte[] sig = this.getSignature(); + + buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl); + for (int i = 20; i < sig.length; i += 20) + { + if (i < sig.length - 20) + { + buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl); + } + else + { + buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl); + } + } + + Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + if (e.hasMoreElements()) + { + buf.append(" Extensions: \n"); + } + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + Extension ext = extensions.getExtension(oid); + + if (ext.getExtnValue() != null) + { + byte[] octs = ext.getExtnValue().getOctets(); + ASN1InputStream dIn = new ASN1InputStream(octs); + buf.append(" critical(").append(ext.isCritical()).append(") "); + try + { + if (oid.equals(Extension.basicConstraints)) + { + buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl); + } + else if (oid.equals(Extension.keyUsage)) + { + buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl); + } + else if (oid.equals(MiscObjectIdentifiers.netscapeCertType)) + { + buf.append(new NetscapeCertType(DERBitString.getInstance(dIn.readObject()))).append(nl); + } + else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL)) + { + buf.append(new NetscapeRevocationURL(DERIA5String.getInstance(dIn.readObject()))).append(nl); + } + else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension)) + { + buf.append(new VerisignCzagExtension(DERIA5String.getInstance(dIn.readObject()))).append(nl); + } + else + { + buf.append(oid.getId()); + buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl); + //buf.append(" value = ").append("*****").append(nl); + } + } + catch (Exception ex) + { + buf.append(oid.getId()); + // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl); + buf.append(" value = ").append("*****").append(nl); + } + } + else + { + buf.append(nl); + } + } + } + + return buf.toString(); + } + + public final void verify( + PublicKey key) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + Signature signature; + String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); + + try + { + signature = bcHelper.createSignature(sigName); + } + catch (Exception e) + { + signature = Signature.getInstance(sigName); + } + + checkSignature(key, signature); + } + + public final void verify( + PublicKey key, + String sigProvider) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); + Signature signature; + + if (sigProvider != null) + { + signature = Signature.getInstance(sigName, sigProvider); + } + else + { + signature = Signature.getInstance(sigName); + } + + checkSignature(key, signature); + } + + public final void verify( + PublicKey key, + Provider sigProvider) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, SignatureException + { + String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); + Signature signature; + + if (sigProvider != null) + { + signature = Signature.getInstance(sigName, sigProvider); + } + else + { + signature = Signature.getInstance(sigName); + } + + checkSignature(key, signature); + } + + private void checkSignature( + PublicKey key, + Signature signature) + throws CertificateException, NoSuchAlgorithmException, + SignatureException, InvalidKeyException + { + if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature())) + { + throw new CertificateException("signature algorithm in TBS cert not same as outer cert"); + } + + ASN1Encodable params = c.getSignatureAlgorithm().getParameters(); + + // TODO This should go after the initVerify? + X509SignatureUtil.setSignatureParameters(signature, params); + + signature.initVerify(key); + + try + { + OutputStream sigOut = new BufferedOutputStream(OutputStreamFactory.createStream(signature), 512); + + c.getTBSCertificate().encodeTo(sigOut, ASN1Encoding.DER); + + sigOut.close(); + } + catch (IOException e) + { + throw new CertificateEncodingException(e.toString()); + } + + if (!signature.verify(this.getSignature())) + { + throw new SignatureException("certificate does not verify with supplied key"); + } + } + + private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) + { + if (!id1.getAlgorithm().equals(id2.getAlgorithm())) + { + return false; + } + + if (id1.getParameters() == null) + { + if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE)) + { + return false; + } + + return true; + } + + if (id2.getParameters() == null) + { + if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE)) + { + return false; + } + + return true; + } + + return id1.getParameters().equals(id2.getParameters()); + } + + private static Collection getAlternativeNames(com.fr.third.org.bouncycastle.asn1.x509.Certificate c, String oid) + throws CertificateParsingException + { + byte[] extOctets = getExtensionOctets(c, oid); + if (extOctets == null) + { + return null; + } + try + { + Collection temp = new ArrayList(); + Enumeration it = ASN1Sequence.getInstance(extOctets).getObjects(); + while (it.hasMoreElements()) + { + GeneralName genName = GeneralName.getInstance(it.nextElement()); + List list = new ArrayList(); + list.add(Integers.valueOf(genName.getTagNo())); + switch (genName.getTagNo()) + { + case GeneralName.ediPartyName: + case GeneralName.x400Address: + case GeneralName.otherName: + list.add(genName.getEncoded()); + break; + case GeneralName.directoryName: + list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString()); + break; + case GeneralName.dNSName: + case GeneralName.rfc822Name: + case GeneralName.uniformResourceIdentifier: + list.add(((ASN1String)genName.getName()).getString()); + break; + case GeneralName.registeredID: + list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId()); + break; + case GeneralName.iPAddress: + byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets(); + final String addr; + try + { + addr = InetAddress.getByAddress(addrBytes).getHostAddress(); + } + catch (UnknownHostException e) + { + continue; + } + list.add(addr); + break; + default: + throw new IOException("Bad tag number: " + genName.getTagNo()); + } + + temp.add(Collections.unmodifiableList(list)); + } + if (temp.size() == 0) + { + return null; + } + return Collections.unmodifiableCollection(temp); + } + catch (Exception e) + { + throw new CertificateParsingException(e.getMessage()); + } + } + + protected static byte[] getExtensionOctets(com.fr.third.org.bouncycastle.asn1.x509.Certificate c, String oid) + { + ASN1OctetString extValue = getExtensionValue(c, oid); + if (null != extValue) + { + return extValue.getOctets(); + } + return null; + } + + protected static ASN1OctetString getExtensionValue(com.fr.third.org.bouncycastle.asn1.x509.Certificate c, String oid) + { + Extensions exts = c.getTBSCertificate().getExtensions(); + if (null != exts) + { + Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); + if (null != ext) + { + return ext.getExtnValue(); + } + } + return null; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateInternal.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateInternal.java new file mode 100644 index 000000000..19f8c4823 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateInternal.java @@ -0,0 +1,29 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.x509; + +import java.security.cert.CertificateEncodingException; + +import com.fr.third.org.bouncycastle.asn1.x509.BasicConstraints; +import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; + +class X509CertificateInternal extends X509CertificateImpl +{ + private final byte[] encoding; + + X509CertificateInternal(JcaJceHelper bcHelper, com.fr.third.org.bouncycastle.asn1.x509.Certificate c, + BasicConstraints basicConstraints, boolean[] keyUsage, byte[] encoding) + { + super(bcHelper, c, basicConstraints, keyUsage); + + this.encoding = encoding; + } + + public byte[] getEncoded() throws CertificateEncodingException + { + if (null == encoding) + { + throw new CertificateEncodingException(); + } + + return encoding; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java index 3cf9f2c15..413cfb1f3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/asymmetric/x509/X509CertificateObject.java @@ -1,588 +1,199 @@ package com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.x509; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.math.BigInteger; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.Principal; -import java.security.Provider; import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; import java.security.cert.CertificateEncodingException; -import java.security.cert.CertificateException; import java.security.cert.CertificateExpiredException; import java.security.cert.CertificateNotYetValidException; import java.security.cert.CertificateParsingException; -import java.security.cert.X509Certificate; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.Date; import java.util.Enumeration; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import javax.security.auth.x500.X500Principal; import com.fr.third.org.bouncycastle.asn1.ASN1BitString; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; -import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; -import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; -import com.fr.third.org.bouncycastle.asn1.ASN1OutputStream; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; -import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; -import com.fr.third.org.bouncycastle.asn1.ASN1String; import com.fr.third.org.bouncycastle.asn1.DERBitString; -import com.fr.third.org.bouncycastle.asn1.DERIA5String; -import com.fr.third.org.bouncycastle.asn1.DERNull; -import com.fr.third.org.bouncycastle.asn1.DEROctetString; -import com.fr.third.org.bouncycastle.asn1.misc.MiscObjectIdentifiers; -import com.fr.third.org.bouncycastle.asn1.misc.NetscapeCertType; -import com.fr.third.org.bouncycastle.asn1.misc.NetscapeRevocationURL; -import com.fr.third.org.bouncycastle.asn1.misc.VerisignCzagExtension; -import com.fr.third.org.bouncycastle.asn1.util.ASN1Dump; -import com.fr.third.org.bouncycastle.asn1.x500.X500Name; -import com.fr.third.org.bouncycastle.asn1.x500.style.RFC4519Style; -import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.BasicConstraints; -import com.fr.third.org.bouncycastle.asn1.x509.Extension; -import com.fr.third.org.bouncycastle.asn1.x509.Extensions; -import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; -import com.fr.third.org.bouncycastle.asn1.x509.KeyUsage; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.PKCS12BagAttributeCarrierImpl; import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; -import com.fr.third.org.bouncycastle.jce.X509Principal; import com.fr.third.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; -import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; -import com.fr.third.org.bouncycastle.util.Integers; -import com.fr.third.org.bouncycastle.util.Strings; -import com.fr.third.org.bouncycastle.util.encoders.Hex; class X509CertificateObject - extends X509Certificate + extends X509CertificateImpl implements PKCS12BagAttributeCarrier { - private JcaJceHelper bcHelper; - private com.fr.third.org.bouncycastle.asn1.x509.Certificate c; - private BasicConstraints basicConstraints; - private boolean[] keyUsage; - private boolean hashValueSet; - private int hashValue; + private final Object cacheLock = new Object(); + private X509CertificateInternal internalCertificateValue; + private X500Principal issuerValue; + private PublicKey publicKeyValue; + private X500Principal subjectValue; + private long[] validityValues; + + private volatile boolean hashValueSet; + private volatile int hashValue; private PKCS12BagAttributeCarrier attrCarrier = new PKCS12BagAttributeCarrierImpl(); - public X509CertificateObject( - JcaJceHelper bcHelper, - com.fr.third.org.bouncycastle.asn1.x509.Certificate c) + X509CertificateObject(JcaJceHelper bcHelper, com.fr.third.org.bouncycastle.asn1.x509.Certificate c) throws CertificateParsingException { - this.bcHelper = bcHelper; - this.c = c; - - try - { - byte[] bytes = this.getExtensionBytes("2.5.29.19"); - - if (bytes != null) - { - basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes)); - } - } - catch (Exception e) - { - throw new CertificateParsingException("cannot construct BasicConstraints: " + e); - } - - try - { - byte[] bytes = this.getExtensionBytes("2.5.29.15"); - if (bytes != null) - { - ASN1BitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes)); - - bytes = bits.getBytes(); - int length = (bytes.length * 8) - bits.getPadBits(); - - keyUsage = new boolean[(length < 9) ? 9 : length]; - - for (int i = 0; i != length; i++) - { - keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; - } - } - else - { - keyUsage = null; - } - } - catch (Exception e) - { - throw new CertificateParsingException("cannot construct KeyUsage: " + e); - } + super(bcHelper, c, createBasicConstraints(c), createKeyUsage(c)); } - public void checkValidity() - throws CertificateExpiredException, CertificateNotYetValidException + public void checkValidity(Date date) throws CertificateExpiredException, CertificateNotYetValidException { - this.checkValidity(new Date()); - } + long checkTime = date.getTime(); + long[] validityValues = getValidityValues(); - public void checkValidity( - Date date) - throws CertificateExpiredException, CertificateNotYetValidException - { - if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility + if (checkTime > validityValues[1]) // for other VM compatibility { throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime()); } - - if (date.getTime() < this.getNotBefore().getTime()) + if (checkTime < validityValues[0]) { throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime()); } } - public int getVersion() - { - return c.getVersionNumber(); - } - - public BigInteger getSerialNumber() - { - return c.getSerialNumber().getValue(); - } - - public Principal getIssuerDN() - { - try - { - return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded())); - } - catch (IOException e) - { - return null; - } - } - public X500Principal getIssuerX500Principal() { - try + synchronized (cacheLock) { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - - aOut.writeObject(c.getIssuer()); - - return new X500Principal(bOut.toByteArray()); - } - catch (IOException e) - { - throw new IllegalStateException("can't encode issuer DN"); - } - } - - public Principal getSubjectDN() - { - return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive())); - } - - public X500Principal getSubjectX500Principal() - { - try - { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - - aOut.writeObject(c.getSubject()); - - return new X500Principal(bOut.toByteArray()); - } - catch (IOException e) - { - throw new IllegalStateException("can't encode issuer DN"); - } - } - - public Date getNotBefore() - { - return c.getStartDate().getDate(); - } - - public Date getNotAfter() - { - return c.getEndDate().getDate(); - } - - public byte[] getTBSCertificate() - throws CertificateEncodingException - { - try - { - return c.getTBSCertificate().getEncoded(ASN1Encoding.DER); - } - catch (IOException e) - { - throw new CertificateEncodingException(e.toString()); - } - } - - public byte[] getSignature() - { - return c.getSignature().getOctets(); - } - - /** - * return a more "meaningful" representation for the signature algorithm used in - * the certificate. - */ - public String getSigAlgName() - { - return X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); - } - - /** - * return the object identifier for the signature. - */ - public String getSigAlgOID() - { - return c.getSignatureAlgorithm().getAlgorithm().getId(); - } - - /** - * return the signature parameters, or null if there aren't any. - */ - public byte[] getSigAlgParams() - { - if (c.getSignatureAlgorithm().getParameters() != null) - { - try - { - return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER); - } - catch (IOException e) + if (null != issuerValue) { - return null; + return issuerValue; } } - else - { - return null; - } - } - public boolean[] getIssuerUniqueID() - { - DERBitString id = c.getTBSCertificate().getIssuerUniqueId(); + X500Principal temp = super.getIssuerX500Principal(); - if (id != null) + synchronized (cacheLock) { - byte[] bytes = id.getBytes(); - boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()]; - - for (int i = 0; i != boolId.length; i++) + if (null == issuerValue) { - boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + issuerValue = temp; } - return boolId; + return issuerValue; } - - return null; } - public boolean[] getSubjectUniqueID() + public PublicKey getPublicKey() { - DERBitString id = c.getTBSCertificate().getSubjectUniqueId(); - - if (id != null) + // Cache the public key to support repeated-use optimizations + synchronized (cacheLock) { - byte[] bytes = id.getBytes(); - boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()]; - - for (int i = 0; i != boolId.length; i++) + if (null != publicKeyValue) { - boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + return publicKeyValue; } - - return boolId; } - - return null; - } - - public boolean[] getKeyUsage() - { - return keyUsage; - } - - public List getExtendedKeyUsage() - throws CertificateParsingException - { - byte[] bytes = this.getExtensionBytes("2.5.29.37"); - if (bytes != null) + PublicKey temp = super.getPublicKey(); + if (null == temp) { - try - { - ASN1InputStream dIn = new ASN1InputStream(bytes); - ASN1Sequence seq = (ASN1Sequence)dIn.readObject(); - List list = new ArrayList(); - - for (int i = 0; i != seq.size(); i++) - { - list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId()); - } - - return Collections.unmodifiableList(list); - } - catch (Exception e) - { - throw new CertificateParsingException("error processing extended key usage extension"); - } + return null; } - return null; - } - - public int getBasicConstraints() - { - if (basicConstraints != null) + synchronized (cacheLock) { - if (basicConstraints.isCA()) + if (null == publicKeyValue) { - if (basicConstraints.getPathLenConstraint() == null) - { - return Integer.MAX_VALUE; - } - else - { - return basicConstraints.getPathLenConstraint().intValue(); - } - } - else - { - return -1; + publicKeyValue = temp; } - } - - return -1; - } - - public Collection getSubjectAlternativeNames() - throws CertificateParsingException - { - return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId())); - } - - public Collection getIssuerAlternativeNames() - throws CertificateParsingException - { - return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId())); - } - - public Set getCriticalExtensionOIDs() - { - if (this.getVersion() == 3) - { - Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); - if (extensions != null) - { - Enumeration e = extensions.oids(); - - while (e.hasMoreElements()) - { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - Extension ext = extensions.getExtension(oid); - - if (ext.isCritical()) - { - set.add(oid.getId()); - } - } - - return set; - } + return publicKeyValue; } - - return null; } - private byte[] getExtensionBytes(String oid) + public X500Principal getSubjectX500Principal() { - Extensions exts = c.getTBSCertificate().getExtensions(); - - if (exts != null) + synchronized (cacheLock) { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - if (ext != null) + if (null != subjectValue) { - return ext.getExtnValue().getOctets(); + return subjectValue; } } - return null; - } + X500Principal temp = super.getSubjectX500Principal(); - public byte[] getExtensionValue(String oid) - { - Extensions exts = c.getTBSCertificate().getExtensions(); - - if (exts != null) + synchronized (cacheLock) { - Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); - - if (ext != null) + if (null == subjectValue) { - try - { - return ext.getExtnValue().getEncoded(); - } - catch (Exception e) - { - throw new IllegalStateException("error parsing " + e.toString()); - } + subjectValue = temp; } - } - return null; + return subjectValue; + } } - public Set getNonCriticalExtensionOIDs() + public long[] getValidityValues() { - if (this.getVersion() == 3) + synchronized (cacheLock) { - Set set = new HashSet(); - Extensions extensions = c.getTBSCertificate().getExtensions(); - - if (extensions != null) + if (null != validityValues) { - Enumeration e = extensions.oids(); - - while (e.hasMoreElements()) - { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - Extension ext = extensions.getExtension(oid); - - if (!ext.isCritical()) - { - set.add(oid.getId()); - } - } - - return set; + return validityValues; } } - return null; - } - - public boolean hasUnsupportedCriticalExtension() - { - if (this.getVersion() == 3) + long[] temp = new long[] { - Extensions extensions = c.getTBSCertificate().getExtensions(); + super.getNotBefore().getTime(), + super.getNotAfter().getTime() + }; - if (extensions != null) + synchronized (cacheLock) + { + if (null == validityValues) { - Enumeration e = extensions.oids(); - - while (e.hasMoreElements()) - { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - - if (oid.equals(Extension.keyUsage) - || oid.equals(Extension.certificatePolicies) - || oid.equals(Extension.policyMappings) - || oid.equals(Extension.inhibitAnyPolicy) - || oid.equals(Extension.cRLDistributionPoints) - || oid.equals(Extension.issuingDistributionPoint) - || oid.equals(Extension.deltaCRLIndicator) - || oid.equals(Extension.policyConstraints) - || oid.equals(Extension.basicConstraints) - || oid.equals(Extension.subjectAlternativeName) - || oid.equals(Extension.nameConstraints)) - { - continue; - } - - Extension ext = extensions.getExtension(oid); - - if (ext.isCritical()) - { - return true; - } - } + validityValues = temp; } - } - - return false; - } - public PublicKey getPublicKey() - { - try - { - return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo()); - } - catch (IOException e) - { - return null; // should never happen... + return validityValues; } } - public byte[] getEncoded() - throws CertificateEncodingException + public boolean equals(Object other) { - try - { - return c.getEncoded(ASN1Encoding.DER); - } - catch (IOException e) - { - throw new CertificateEncodingException(e.toString()); - } - } - - public boolean equals( - Object o) - { - if (o == this) + if (other == this) { return true; } - if (o instanceof X509CertificateObject) + if (other instanceof X509CertificateObject) { - X509CertificateObject other = (X509CertificateObject)o; + X509CertificateObject otherBC = (X509CertificateObject)other; - if (this.hashValueSet && other.hashValueSet) + if (this.hashValueSet && otherBC.hashValueSet) { - if (this.hashValue != other.hashValue) + if (this.hashValue != otherBC.hashValue) + { + return false; + } + } + else if (null == internalCertificateValue || null == otherBC.internalCertificateValue) + { + ASN1BitString signature = c.getSignature(); + if (null != signature && !signature.equals(otherBC.c.getSignature())) { return false; } } - - return this.c.equals(other.c); } - return super.equals(o); + return getInternalCertificate().equals(other); } - public synchronized int hashCode() + public int hashCode() { if (!hashValueSet) { - hashValue = super.hashCode(); + hashValue = getInternalCertificate().hashCode(); hashValueSet = true; } @@ -599,7 +210,7 @@ class X509CertificateObject try { int hashCode = 0; - byte[] certData = this.getEncoded(); + byte[] certData = getInternalCertificate().getEncoded(); for (int i = 1; i < certData.length; i++) { hashCode += certData[i] * i; @@ -612,15 +223,12 @@ class X509CertificateObject } } - public void setBagAttribute( - ASN1ObjectIdentifier oid, - ASN1Encodable attribute) + public void setBagAttribute(ASN1ObjectIdentifier oid, ASN1Encodable attribute) { attrCarrier.setBagAttribute(oid, attribute); } - public ASN1Encodable getBagAttribute( - ASN1ObjectIdentifier oid) + public ASN1Encodable getBagAttribute(ASN1ObjectIdentifier oid) { return attrCarrier.getBagAttribute(oid); } @@ -630,282 +238,85 @@ class X509CertificateObject return attrCarrier.getBagAttributeKeys(); } - public String toString() + private X509CertificateInternal getInternalCertificate() { - StringBuffer buf = new StringBuffer(); - String nl = Strings.lineSeparator(); - - buf.append(" [0] Version: ").append(this.getVersion()).append(nl); - buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl); - buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl); - buf.append(" Start Date: ").append(this.getNotBefore()).append(nl); - buf.append(" Final Date: ").append(this.getNotAfter()).append(nl); - buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl); - buf.append(" Public Key: ").append(this.getPublicKey()).append(nl); - buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl); - - byte[] sig = this.getSignature(); - - buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl); - for (int i = 20; i < sig.length; i += 20) + synchronized (cacheLock) { - if (i < sig.length - 20) - { - buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl); - } - else + if (null != internalCertificateValue) { - buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl); + return internalCertificateValue; } } - Extensions extensions = c.getTBSCertificate().getExtensions(); - - if (extensions != null) - { - Enumeration e = extensions.oids(); - - if (e.hasMoreElements()) - { - buf.append(" Extensions: \n"); - } - - while (e.hasMoreElements()) - { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - Extension ext = extensions.getExtension(oid); - - if (ext.getExtnValue() != null) - { - byte[] octs = ext.getExtnValue().getOctets(); - ASN1InputStream dIn = new ASN1InputStream(octs); - buf.append(" critical(").append(ext.isCritical()).append(") "); - try - { - if (oid.equals(Extension.basicConstraints)) - { - buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl); - } - else if (oid.equals(Extension.keyUsage)) - { - buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl); - } - else if (oid.equals(MiscObjectIdentifiers.netscapeCertType)) - { - buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl); - } - else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL)) - { - buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl); - } - else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension)) - { - buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl); - } - else - { - buf.append(oid.getId()); - buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl); - //buf.append(" value = ").append("*****").append(nl); - } - } - catch (Exception ex) - { - buf.append(oid.getId()); - // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl); - buf.append(" value = ").append("*****").append(nl); - } - } - else - { - buf.append(nl); - } - } - } - - return buf.toString(); - } - - public final void verify( - PublicKey key) - throws CertificateException, NoSuchAlgorithmException, - InvalidKeyException, NoSuchProviderException, SignatureException - { - Signature signature; - String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); - + byte[] encoding; try { - signature = bcHelper.createSignature(sigName); + encoding = getEncoded(); } - catch (Exception e) - { - signature = Signature.getInstance(sigName); - } - - checkSignature(key, signature); - } - - public final void verify( - PublicKey key, - String sigProvider) - throws CertificateException, NoSuchAlgorithmException, - InvalidKeyException, NoSuchProviderException, SignatureException - { - String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); - Signature signature; - - if (sigProvider != null) - { - signature = Signature.getInstance(sigName, sigProvider); - } - else - { - signature = Signature.getInstance(sigName); - } - - checkSignature(key, signature); - } - - public final void verify( - PublicKey key, - Provider sigProvider) - throws CertificateException, NoSuchAlgorithmException, - InvalidKeyException, SignatureException - { - String sigName = X509SignatureUtil.getSignatureName(c.getSignatureAlgorithm()); - Signature signature; - - if (sigProvider != null) - { - signature = Signature.getInstance(sigName, sigProvider); - } - else + catch (CertificateEncodingException e) { - signature = Signature.getInstance(sigName); + encoding = null; } - checkSignature(key, signature); - } + X509CertificateInternal temp = new X509CertificateInternal(bcHelper, c, basicConstraints, keyUsage, encoding); - private void checkSignature( - PublicKey key, - Signature signature) - throws CertificateException, NoSuchAlgorithmException, - SignatureException, InvalidKeyException - { - if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature())) + synchronized (cacheLock) { - throw new CertificateException("signature algorithm in TBS cert not same as outer cert"); - } - - ASN1Encodable params = c.getSignatureAlgorithm().getParameters(); - - // TODO This should go after the initVerify? - X509SignatureUtil.setSignatureParameters(signature, params); - - signature.initVerify(key); - - signature.update(this.getTBSCertificate()); + if (null == internalCertificateValue) + { + internalCertificateValue = temp; + } - if (!signature.verify(this.getSignature())) - { - throw new SignatureException("certificate does not verify with supplied key"); + return internalCertificateValue; } } - private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) + private static BasicConstraints createBasicConstraints(com.fr.third.org.bouncycastle.asn1.x509.Certificate c) + throws CertificateParsingException { - if (!id1.getAlgorithm().equals(id2.getAlgorithm())) - { - return false; - } - - if (id1.getParameters() == null) + try { - if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE)) + byte[] extOctets = getExtensionOctets(c, "2.5.29.19"); + if (null == extOctets) { - return false; + return null; } - return true; + return BasicConstraints.getInstance(ASN1Primitive.fromByteArray(extOctets)); } - - if (id2.getParameters() == null) + catch (Exception e) { - if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE)) - { - return false; - } - - return true; + throw new CertificateParsingException("cannot construct BasicConstraints: " + e); } - - return id1.getParameters().equals(id2.getParameters()); } - private static Collection getAlternativeNames(byte[] extVal) - throws CertificateParsingException + private static boolean[] createKeyUsage(com.fr.third.org.bouncycastle.asn1.x509.Certificate c) throws CertificateParsingException { - if (extVal == null) - { - return null; - } try { - Collection temp = new ArrayList(); - Enumeration it = ASN1Sequence.getInstance(extVal).getObjects(); - while (it.hasMoreElements()) + byte[] extOctets = getExtensionOctets(c, "2.5.29.15"); + if (null == extOctets) { - GeneralName genName = GeneralName.getInstance(it.nextElement()); - List list = new ArrayList(); - list.add(Integers.valueOf(genName.getTagNo())); - switch (genName.getTagNo()) - { - case GeneralName.ediPartyName: - case GeneralName.x400Address: - case GeneralName.otherName: - list.add(genName.getEncoded()); - break; - case GeneralName.directoryName: - list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString()); - break; - case GeneralName.dNSName: - case GeneralName.rfc822Name: - case GeneralName.uniformResourceIdentifier: - list.add(((ASN1String)genName.getName()).getString()); - break; - case GeneralName.registeredID: - list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId()); - break; - case GeneralName.iPAddress: - byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets(); - final String addr; - try - { - addr = InetAddress.getByAddress(addrBytes).getHostAddress(); - } - catch (UnknownHostException e) - { - continue; - } - list.add(addr); - break; - default: - throw new IOException("Bad tag number: " + genName.getTagNo()); - } - - temp.add(Collections.unmodifiableList(list)); + return null; } - if (temp.size() == 0) + + ASN1BitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(extOctets)); + + byte[] bytes = bits.getBytes(); + int length = (bytes.length * 8) - bits.getPadBits(); + + boolean[] keyUsage = new boolean[(length < 9) ? 9 : length]; + + for (int i = 0; i != length; i++) { - return null; + keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; } - return Collections.unmodifiableCollection(temp); + + return keyUsage; } catch (Exception e) { - throw new CertificateParsingException(e.getMessage()); + throw new CertificateParsingException("cannot construct KeyUsage: " + e); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/Haraka.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/Haraka.java new file mode 100644 index 000000000..5e6681a4b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/Haraka.java @@ -0,0 +1,67 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.digest; + +import com.fr.third.org.bouncycastle.crypto.digests.Haraka256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.Haraka512Digest; +import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; + +public class Haraka +{ + private Haraka() + { + + } + + static public class Digest256 + extends BCMessageDigest + implements Cloneable + { + public Digest256() + { + super(new Haraka256Digest()); + } + + public Object clone() + throws CloneNotSupportedException + { + Digest256 d = (Digest256)super.clone(); + d.digest = new Haraka256Digest((Haraka256Digest)digest); + + return d; + } + } + + static public class Digest512 + extends BCMessageDigest + implements Cloneable + { + public Digest512() + { + super(new Haraka512Digest()); + } + + public Object clone() + throws CloneNotSupportedException + { + Digest512 d = (Digest512)super.clone(); + d.digest = new Haraka512Digest((Haraka512Digest)digest); + + return d; + } + } + + public static class Mappings + extends DigestAlgorithmProvider + { + private static final String PREFIX = Haraka.class.getName(); + + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("MessageDigest.HARAKA-256", PREFIX + "$Digest256"); + provider.addAlgorithm("MessageDigest.HARAKA-512", PREFIX + "$Digest512"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/SM3.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/SM3.java index 5414eb5b3..61f8bef5f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/SM3.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/SM3.java @@ -1,5 +1,6 @@ package com.fr.third.org.bouncycastle.jcajce.provider.digest; +import com.fr.third.org.bouncycastle.asn1.gm.GMObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.digests.SM3Digest; import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; @@ -41,7 +42,8 @@ public class SM3 { provider.addAlgorithm("MessageDigest.SM3", PREFIX + "$Digest"); provider.addAlgorithm("Alg.Alias.MessageDigest.SM3", "SM3"); - provider.addAlgorithm("Alg.Alias.MessageDigest.1.2.156.197.1.401", "SM3"); + provider.addAlgorithm("Alg.Alias.MessageDigest.1.2.156.197.1.401", "SM3"); // old draft OID - deprecated + provider.addAlgorithm("Alg.Alias.MessageDigest." + GMObjectIdentifiers.sm3, "SM3"); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/Whirlpool.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/Whirlpool.java index c27e96c90..434a892ef 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/Whirlpool.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/digest/Whirlpool.java @@ -35,7 +35,7 @@ public class Whirlpool } /** - * Tiger HMac + * Whirlpool HMac */ public static class HashMac extends BaseMac diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/drbg/DRBG.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/drbg/DRBG.java index 7fa218bd6..c19c6af25 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/drbg/DRBG.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/drbg/DRBG.java @@ -24,6 +24,7 @@ import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.ClassUtil; import com.fr.third.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.Pack; +import com.fr.third.org.bouncycastle.util.Properties; import com.fr.third.org.bouncycastle.util.Strings; public class DRBG @@ -42,8 +43,6 @@ public class DRBG {"org.conscrypt.OpenSSLProvider", "org.conscrypt.OpenSSLRandom"}, }; - private static final Object[] initialEntropySourceAndSpi = findSource(); - // Cascade through providers looking for match. private final static Object[] findSource() { @@ -68,7 +67,7 @@ public class DRBG private static class CoreSecureRandom extends SecureRandom { - CoreSecureRandom() + CoreSecureRandom(Object[] initialEntropySourceAndSpi) { super((SecureRandomSpi)initialEntropySourceAndSpi[1], (Provider)initialEntropySourceAndSpi[0]); } @@ -120,9 +119,9 @@ public class DRBG private static SecureRandom createCoreSecureRandom() { - if (initialEntropySourceAndSpi != null) + if (Security.getProperty("securerandom.source") == null) { - return new CoreSecureRandom(); + return new CoreSecureRandom(findSource()); } else { @@ -462,9 +461,57 @@ public class DRBG this.numBytes = numBytes; } + private void sleep(long ms) + { + try + { + Thread.sleep(ms); + } + catch (InterruptedException e) + { + Thread.currentThread().interrupt(); + } + } + public void run() { - entropy.set(baseRandom.generateSeed(numBytes)); + long ms; + String pause = Properties.getPropertyValue("com.fr.third.org.bouncycastle.drbg.gather_pause_secs"); + + if (pause != null) + { + try + { + ms = Long.parseLong(pause) * 1000; + } + catch (Exception e) + { + ms = 5000; + } + } + else + { + ms = 5000; + } + + byte[] seed = new byte[numBytes]; + for (int i = 0; i < byteLength / 8; i++) + { + // we need to be mindful that we may not be the only thread/process looking for entropy + sleep(ms); + byte[] rn = baseRandom.generateSeed(8); + System.arraycopy(rn, 0, seed, i * 8, rn.length); + } + + int extra = byteLength - ((byteLength / 8) * 8); + if (extra != 0) + { + sleep(ms); + byte[] rn = baseRandom.generateSeed(extra); + System.arraycopy(rn, 0, seed, seed.length - rn.length, rn.length); + } + + entropy.set(seed); seedAvailable.set(true); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/BCFKS.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/BCFKS.java index c5e573cc3..e460eed9b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/BCFKS.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/BCFKS.java @@ -19,8 +19,8 @@ public class BCFKS provider.addAlgorithm("KeyStore.BCFKS", PREFIX + "BcFKSKeyStoreSpi$Std"); provider.addAlgorithm("KeyStore.BCFKS-DEF", PREFIX + "BcFKSKeyStoreSpi$Def"); - provider.addAlgorithm("KeyStore.BCSFKS", PREFIX + "BcFKSKeyStoreSpi$StdShared"); - provider.addAlgorithm("KeyStore.BCSFKS-DEF", PREFIX + "BcFKSKeyStoreSpi$DefShared"); + provider.addAlgorithm("KeyStore.IBCFKS", PREFIX + "BcFKSKeyStoreSpi$StdShared"); + provider.addAlgorithm("KeyStore.IBCFKS-DEF", PREFIX + "BcFKSKeyStoreSpi$DefShared"); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java index 34084ee0e..033d0e8f6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/bc/BcKeyStoreSpi.java @@ -28,8 +28,6 @@ import java.util.Enumeration; import java.util.Hashtable; import javax.crypto.Cipher; -import javax.crypto.CipherInputStream; -import javax.crypto.CipherOutputStream; import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; @@ -48,6 +46,8 @@ import com.fr.third.org.bouncycastle.crypto.io.DigestOutputStream; import com.fr.third.org.bouncycastle.crypto.io.MacInputStream; import com.fr.third.org.bouncycastle.crypto.io.MacOutputStream; import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.jcajce.io.CipherInputStream; +import com.fr.third.org.bouncycastle.jcajce.io.CipherOutputStream; import com.fr.third.org.bouncycastle.jcajce.util.BCJcaJceHelper; import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; import com.fr.third.org.bouncycastle.jce.interfaces.BCKeyStore; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java index 020585b31..250a9d9cb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/bcfks/BcFKSKeyStoreSpi.java @@ -6,6 +6,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.math.BigInteger; import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; import java.security.InvalidKeyException; import java.security.Key; import java.security.KeyFactory; @@ -13,14 +14,19 @@ import java.security.KeyStore; import java.security.KeyStoreException; import java.security.KeyStoreSpi; import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; import java.security.PrivateKey; +import java.security.PublicKey; import java.security.SecureRandom; +import java.security.Signature; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; +import java.security.interfaces.DSAKey; +import java.security.interfaces.RSAKey; import java.security.spec.PKCS8EncodedKeySpec; import java.text.ParseException; import java.util.Date; @@ -44,6 +50,7 @@ import javax.security.auth.callback.PasswordCallback; import javax.security.auth.callback.UnsupportedCallbackException; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.DERNull; @@ -57,6 +64,7 @@ import com.fr.third.org.bouncycastle.asn1.bc.ObjectStoreData; import com.fr.third.org.bouncycastle.asn1.bc.ObjectStoreIntegrityCheck; import com.fr.third.org.bouncycastle.asn1.bc.PbkdMacIntegrityCheck; import com.fr.third.org.bouncycastle.asn1.bc.SecretKeyData; +import com.fr.third.org.bouncycastle.asn1.bc.SignatureCheck; import com.fr.third.org.bouncycastle.asn1.cms.CCMParameters; import com.fr.third.org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.misc.MiscObjectIdentifiers; @@ -85,8 +93,13 @@ import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; import com.fr.third.org.bouncycastle.crypto.util.PBKDF2Config; import com.fr.third.org.bouncycastle.crypto.util.PBKDFConfig; import com.fr.third.org.bouncycastle.crypto.util.ScryptConfig; +import com.fr.third.org.bouncycastle.jcajce.BCFKSLoadStoreParameter; import com.fr.third.org.bouncycastle.jcajce.BCFKSStoreParameter; -import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jcajce.BCLoadStoreParameter; +import com.fr.third.org.bouncycastle.jcajce.util.BCJcaJceHelper; +import com.fr.third.org.bouncycastle.jcajce.util.DefaultJcaJceHelper; +import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; +import com.fr.third.org.bouncycastle.jce.interfaces.ECKey; import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.Strings; @@ -124,6 +137,9 @@ class BcFKSKeyStoreSpi publicAlgMap.put(X9ObjectIdentifiers.id_dsa, "DSA"); } + private PublicKey verificationKey; + private BCFKSLoadStoreParameter.CertChainValidator validator; + private static String getPublicKeyAlg(ASN1ObjectIdentifier oid) { String algName = (String)publicAlgMap.get(oid); @@ -142,18 +158,20 @@ class BcFKSKeyStoreSpi private final static BigInteger PROTECTED_PRIVATE_KEY = BigInteger.valueOf(3); private final static BigInteger PROTECTED_SECRET_KEY = BigInteger.valueOf(4); - private final BouncyCastleProvider provider; + private final JcaJceHelper helper; private final Map entries = new HashMap(); private final Map privateKeyCache = new HashMap(); private AlgorithmIdentifier hmacAlgorithm; private KeyDerivationFunc hmacPkbdAlgorithm; + private AlgorithmIdentifier signatureAlgorithm; private Date creationDate; private Date lastModifiedDate; + private ASN1ObjectIdentifier storeEncryptionAlgorithm = NISTObjectIdentifiers.id_aes256_CCM; - BcFKSKeyStoreSpi(BouncyCastleProvider provider) + BcFKSKeyStoreSpi(JcaJceHelper helper) { - this.provider = provider; + this.helper = helper; } public Key engineGetKey(String alias, char[] password) @@ -178,15 +196,7 @@ class BcFKSKeyStoreSpi { PrivateKeyInfo pInfo = PrivateKeyInfo.getInstance(decryptData("PRIVATE_KEY_ENCRYPTION", encInfo.getEncryptionAlgorithm(), password, encInfo.getEncryptedData())); - KeyFactory kFact; - if (provider != null) - { - kFact = KeyFactory.getInstance(pInfo.getPrivateKeyAlgorithm().getAlgorithm().getId(), provider); - } - else - { - kFact = KeyFactory.getInstance(getPublicKeyAlg(pInfo.getPrivateKeyAlgorithm().getAlgorithm())); - } + KeyFactory kFact = helper.createKeyFactory(getPublicKeyAlg(pInfo.getPrivateKeyAlgorithm().getAlgorithm())); PrivateKey privateKey = kFact.generatePrivate(new PKCS8EncodedKeySpec(pInfo.getEncoded())); @@ -209,15 +219,7 @@ class BcFKSKeyStoreSpi try { SecretKeyData keyData = SecretKeyData.getInstance(decryptData("SECRET_KEY_ENCRYPTION", encKeyData.getKeyEncryptionAlgorithm(), password, encKeyData.getEncryptedKeyData())); - SecretKeyFactory kFact; - if (provider != null) - { - kFact = SecretKeyFactory.getInstance(keyData.getKeyAlgorithm().getId(), provider); - } - else - { - kFact = SecretKeyFactory.getInstance(keyData.getKeyAlgorithm().getId()); - } + SecretKeyFactory kFact = helper.createSecretKeyFactory(keyData.getKeyAlgorithm().getId()); return kFact.generateSecret(new SecretKeySpec(keyData.getKeyBytes(), keyData.getKeyAlgorithm().getId())); } @@ -283,11 +285,11 @@ class BcFKSKeyStoreSpi private Certificate decodeCertificate(Object cert) { - if (provider != null) + if (helper != null) { try { - CertificateFactory certFact = CertificateFactory.getInstance("X.509", provider); + CertificateFactory certFact = helper.createCertificateFactory("X.509"); return certFact.generateCertificate(new ByteArrayInputStream(com.fr.third.org.bouncycastle.asn1.x509.Certificate.getInstance(cert).getEncoded())); } @@ -362,22 +364,29 @@ class BcFKSKeyStoreSpi KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, 256 / 8); byte[] keyBytes = generateKey(pbkdAlgId, "PRIVATE_KEY_ENCRYPTION", ((password != null) ? password : new char[0]), 32); - Cipher c = createCipher("AES/CCM/NoPadding", keyBytes); + EncryptedPrivateKeyInfo keyInfo; + if (storeEncryptionAlgorithm.equals(NISTObjectIdentifiers.id_aes256_CCM)) + { + Cipher c = createCipher("AES/CCM/NoPadding", keyBytes); - byte[] encryptedKey = c.doFinal(encodedKey); - AlgorithmParameters algParams = c.getParameters(); + byte[] encryptedKey = c.doFinal(encodedKey); - PBES2Parameters pbeParams; - if (algParams != null) - { - pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algParams.getEncoded()))); + AlgorithmParameters algParams = c.getParameters(); + + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algParams.getEncoded()))); + + keyInfo = new EncryptedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey); } - else // AES KWP + else { - pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_wrap_pad, null)); - } + Cipher c = createCipher("AESKWP", keyBytes); + + byte[] encryptedKey = c.doFinal(encodedKey); - EncryptedPrivateKeyInfo keyInfo = new EncryptedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey); + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_wrap_pad)); + + keyInfo = new EncryptedPrivateKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey); + } EncryptedPrivateKeyData keySeq = createPrivateKeySequence(keyInfo, chain); @@ -402,8 +411,6 @@ class BcFKSKeyStoreSpi KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(PKCSObjectIdentifiers.id_PBKDF2, 256 / 8); byte[] keyBytes = generateKey(pbkdAlgId, "SECRET_KEY_ENCRYPTION", ((password != null) ? password : new char[0]), 32); - Cipher c = createCipher("AES/CCM/NoPadding", keyBytes); - String keyAlg = Strings.toUpperCase(key.getAlgorithm()); SecretKeyData secKeyData; @@ -432,21 +439,29 @@ class BcFKSKeyStoreSpi } } - byte[] encryptedKey = c.doFinal(secKeyData.getEncoded()); - AlgorithmParameters algParams = c.getParameters(); - - PBES2Parameters pbeParams; - if (algParams != null) + EncryptedSecretKeyData keyData; + if (storeEncryptionAlgorithm.equals(NISTObjectIdentifiers.id_aes256_CCM)) { - pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algParams.getEncoded()))); + Cipher c = createCipher("AES/CCM/NoPadding", keyBytes); + + byte[] encryptedKey = c.doFinal(secKeyData.getEncoded()); + + AlgorithmParameters algParams = c.getParameters(); + + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algParams.getEncoded()))); + + keyData = new EncryptedSecretKeyData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey); } - else // AES KWP + else { - pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_wrap_pad, null)); - } + Cipher c = createCipher("AESKWP", keyBytes); + + byte[] encryptedKey = c.doFinal(secKeyData.getEncoded()); - EncryptedSecretKeyData keyData = new EncryptedSecretKeyData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey); + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_wrap_pad)); + keyData = new EncryptedSecretKeyData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encryptedKey); + } entries.put(alias, new ObjectData(SECRET_KEY, alias, creationDate, lastEditDate, keyData.getEncoded(), null)); } catch (Exception e) @@ -463,20 +478,12 @@ class BcFKSKeyStoreSpi } private Cipher createCipher(String algorithm, byte[] keyBytes) - throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException + throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, NoSuchProviderException { - Cipher c; - if (provider == null) - { - c = Cipher.getInstance(algorithm); - } - else - { - c = Cipher.getInstance(algorithm, provider); - } + Cipher c = helper.createCipher(algorithm); c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES")); - + return c; } @@ -777,31 +784,38 @@ class BcFKSKeyStoreSpi } } + private void verifySig(ASN1Encodable store, SignatureCheck integrityCheck, PublicKey key) + throws GeneralSecurityException, IOException + { + Signature sig = helper.createSignature(integrityCheck.getSignatureAlgorithm().getAlgorithm().getId()); + + sig.initVerify(key); + + sig.update(store.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + + if (!sig.verify(integrityCheck.getSignature().getOctets())) + { + throw new IOException("BCFKS KeyStore corrupted: signature calculation failed"); + } + } + private void verifyMac(byte[] content, PbkdMacIntegrityCheck integrityCheck, char[] password) - throws NoSuchAlgorithmException, IOException + throws NoSuchAlgorithmException, IOException, NoSuchProviderException { byte[] check = calculateMac(content, integrityCheck.getMacAlgorithm(), integrityCheck.getPbkdAlgorithm(), password); if (!Arrays.constantTimeAreEqual(check, integrityCheck.getMac())) { - throw new IOException("BCFKS KeyStore corrupted: MAC calculation failed."); + throw new IOException("BCFKS KeyStore corrupted: MAC calculation failed"); } } private byte[] calculateMac(byte[] content, AlgorithmIdentifier algorithm, KeyDerivationFunc pbkdAlgorithm, char[] password) - throws NoSuchAlgorithmException, IOException + throws NoSuchAlgorithmException, IOException, NoSuchProviderException { String algorithmId = algorithm.getAlgorithm().getId(); - Mac mac; - if (provider != null) - { - mac = Mac.getInstance(algorithmId, provider); - } - else - { - mac = Mac.getInstance(algorithmId); - } + Mac mac = helper.createMac(algorithmId); try { @@ -816,31 +830,18 @@ class BcFKSKeyStoreSpi return mac.doFinal(content); } - public void engineStore(KeyStore.LoadStoreParameter parameter) - throws CertificateException, NoSuchAlgorithmException, IOException + private char[] extractPassword(KeyStore.LoadStoreParameter bcParam) + throws IOException { - if (parameter == null) - { - throw new IllegalArgumentException("'parameter' arg cannot be null"); - } - - if (!(parameter instanceof BCFKSStoreParameter)) - { - throw new IllegalArgumentException( - "no support for 'parameter' of type " + parameter.getClass().getName()); - } - - BCFKSStoreParameter bcParam = (BCFKSStoreParameter)parameter; - - char[] password; KeyStore.ProtectionParameter protParam = bcParam.getProtectionParameter(); + if (protParam == null) { - password = null; + return null; } else if (protParam instanceof KeyStore.PasswordProtection) { - password = ((KeyStore.PasswordProtection)protParam).getPassword(); + return ((KeyStore.PasswordProtection)protParam).getPassword(); } else if (protParam instanceof KeyStore.CallbackHandlerProtection) { @@ -852,7 +853,7 @@ class BcFKSKeyStoreSpi { handler.handle(new Callback[]{passwordCallback}); - password = passwordCallback.getPassword(); + return passwordCallback.getPassword(); } catch (UnsupportedCallbackException e) { @@ -864,51 +865,208 @@ class BcFKSKeyStoreSpi throw new IllegalArgumentException( "no support for protection parameter of type " + protParam.getClass().getName()); } + } - if (bcParam.getStorePBKDFConfig().getAlgorithm().equals(MiscObjectIdentifiers.id_scrypt)) + public void engineStore(KeyStore.LoadStoreParameter parameter) + throws CertificateException, NoSuchAlgorithmException, IOException + { + if (parameter == null) { + throw new IllegalArgumentException("'parameter' arg cannot be null"); + } + + if (parameter instanceof BCFKSStoreParameter) + { + BCFKSStoreParameter bcParam = (BCFKSStoreParameter)parameter; + + char[] password = extractPassword(parameter); + hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(bcParam.getStorePBKDFConfig(), 512 / 8); + + engineStore(bcParam.getOutputStream(), password); + } + else if (parameter instanceof BCFKSLoadStoreParameter) + { + BCFKSLoadStoreParameter bcParam = (BCFKSLoadStoreParameter)parameter; + + if (bcParam.getStoreSignatureKey() != null) + { + signatureAlgorithm = generateSignatureAlgId(bcParam.getStoreSignatureKey(), bcParam.getStoreSignatureAlgorithm()); + + hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(bcParam.getStorePBKDFConfig(), 512 / 8); + + if (bcParam.getStoreEncryptionAlgorithm() == BCFKSLoadStoreParameter.EncryptionAlgorithm.AES256_CCM) + { + storeEncryptionAlgorithm = NISTObjectIdentifiers.id_aes256_CCM; + } + else + { + storeEncryptionAlgorithm = NISTObjectIdentifiers.id_aes256_wrap_pad; + } + + if (bcParam.getStoreMacAlgorithm() == BCFKSLoadStoreParameter.MacAlgorithm.HmacSHA512) + { + hmacAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE); + } + else + { + hmacAlgorithm = new AlgorithmIdentifier(NISTObjectIdentifiers.id_hmacWithSHA3_512, DERNull.INSTANCE); + } + + char[] password = extractPassword(bcParam); + + EncryptedObjectStoreData encStoreData = getEncryptedObjectStoreData(signatureAlgorithm, password); + + try + { + Signature sig = helper.createSignature(signatureAlgorithm.getAlgorithm().getId()); + + sig.initSign((PrivateKey)bcParam.getStoreSignatureKey()); + + sig.update(encStoreData.getEncoded()); + + SignatureCheck signatureCheck; + X509Certificate[] certs = bcParam.getStoreCertificates(); + + if (certs != null) + { + com.fr.third.org.bouncycastle.asn1.x509.Certificate[] certificates = new com.fr.third.org.bouncycastle.asn1.x509.Certificate[certs.length]; + for (int i = 0; i != certificates.length; i++) + { + certificates[i] = com.fr.third.org.bouncycastle.asn1.x509.Certificate.getInstance(certs[i].getEncoded()); + } + signatureCheck = new SignatureCheck(signatureAlgorithm, certificates, sig.sign()); + } + else + { + signatureCheck = new SignatureCheck(signatureAlgorithm, sig.sign()); + } + ObjectStore store = new ObjectStore(encStoreData, new ObjectStoreIntegrityCheck(signatureCheck)); + + bcParam.getOutputStream().write(store.getEncoded()); + + bcParam.getOutputStream().flush(); + } + catch (GeneralSecurityException e) + { + throw new IOException("error creating signature: " + e.getMessage(), e); + } + } + else + { + char[] password = extractPassword(bcParam); + + hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(bcParam.getStorePBKDFConfig(), 512 / 8); + + if (bcParam.getStoreEncryptionAlgorithm() == BCFKSLoadStoreParameter.EncryptionAlgorithm.AES256_CCM) + { + storeEncryptionAlgorithm = NISTObjectIdentifiers.id_aes256_CCM; + } + else + { + storeEncryptionAlgorithm = NISTObjectIdentifiers.id_aes256_wrap_pad; + } + + if (bcParam.getStoreMacAlgorithm() == BCFKSLoadStoreParameter.MacAlgorithm.HmacSHA512) + { + hmacAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE); + } + else + { + hmacAlgorithm = new AlgorithmIdentifier(NISTObjectIdentifiers.id_hmacWithSHA3_512, DERNull.INSTANCE); + } + + engineStore(bcParam.getOutputStream(), password); + } + } + else if (parameter instanceof BCLoadStoreParameter) + { + BCLoadStoreParameter bcParam = (BCLoadStoreParameter)parameter; + + engineStore(bcParam.getOutputStream(), extractPassword(parameter)); } else { - hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(bcParam.getStorePBKDFConfig(), 512 / 8); + throw new IllegalArgumentException( + "no support for 'parameter' of type " + parameter.getClass().getName()); } - engineStore(bcParam.getOutputStream(), password); } public void engineStore(OutputStream outputStream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException + { + if (creationDate == null) + { + throw new IOException("KeyStore not initialized"); + } + + EncryptedObjectStoreData encStoreData = getEncryptedObjectStoreData(hmacAlgorithm, password); + + // update the salt + if (MiscObjectIdentifiers.id_scrypt.equals(hmacPkbdAlgorithm.getAlgorithm())) + { + ScryptParams sParams = ScryptParams.getInstance(hmacPkbdAlgorithm.getParameters()); + + hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(hmacPkbdAlgorithm, sParams.getKeyLength().intValue()); + } + else + { + PBKDF2Params pbkdf2Params = PBKDF2Params.getInstance(hmacPkbdAlgorithm.getParameters()); + + hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(hmacPkbdAlgorithm, pbkdf2Params.getKeyLength().intValue()); + } + byte[] mac; + try + { + mac = calculateMac(encStoreData.getEncoded(), hmacAlgorithm, hmacPkbdAlgorithm, password); + } + catch (NoSuchProviderException e) + { + throw new IOException("cannot calculate mac: " + e.getMessage()); + } + + ObjectStore store = new ObjectStore(encStoreData, new ObjectStoreIntegrityCheck(new PbkdMacIntegrityCheck(hmacAlgorithm, hmacPkbdAlgorithm, mac))); + + outputStream.write(store.getEncoded()); + + outputStream.flush(); + } + + private EncryptedObjectStoreData getEncryptedObjectStoreData(AlgorithmIdentifier integrityAlgorithm, char[] password) + throws IOException, NoSuchAlgorithmException { ObjectData[] dataArray = (ObjectData[])entries.values().toArray(new ObjectData[entries.size()]); KeyDerivationFunc pbkdAlgId = generatePkbdAlgorithmIdentifier(hmacPkbdAlgorithm, 256 / 8); byte[] keyBytes = generateKey(pbkdAlgId, "STORE_ENCRYPTION", ((password != null) ? password : new char[0]), 256 / 8); - ObjectStoreData storeData = new ObjectStoreData(hmacAlgorithm, creationDate, lastModifiedDate, new ObjectDataSequence(dataArray), null); + ObjectStoreData storeData = new ObjectStoreData(integrityAlgorithm, creationDate, lastModifiedDate, new ObjectDataSequence(dataArray), null); EncryptedObjectStoreData encStoreData; try { - Cipher c; - if (provider == null) - { - c = Cipher.getInstance("AES/CCM/NoPadding"); - } - else + if (storeEncryptionAlgorithm.equals(NISTObjectIdentifiers.id_aes256_CCM)) { - c = Cipher.getInstance("AES/CCM/NoPadding", provider); - } + Cipher c = createCipher("AES/CCM/NoPadding", keyBytes); + + byte[] encOut = c.doFinal(storeData.getEncoded()); - c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(keyBytes, "AES")); + AlgorithmParameters algorithmParameters = c.getParameters(); - byte[] encOut = c.doFinal(storeData.getEncoded()); + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algorithmParameters.getEncoded()))); - AlgorithmParameters algorithmParameters = c.getParameters(); + encStoreData = new EncryptedObjectStoreData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encOut); + } + else + { + Cipher c = createCipher("AESKWP", keyBytes); - PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_CCM, CCMParameters.getInstance(algorithmParameters.getEncoded()))); + byte[] encOut = c.doFinal(storeData.getEncoded()); + PBES2Parameters pbeParams = new PBES2Parameters(pbkdAlgId, new EncryptionScheme(NISTObjectIdentifiers.id_aes256_wrap_pad)); - encStoreData = new EncryptedObjectStoreData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encOut); + encStoreData = new EncryptedObjectStoreData(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_PBES2, pbeParams), encOut); + } } catch (NoSuchPaddingException e) { @@ -926,29 +1084,126 @@ class BcFKSKeyStoreSpi { throw new IOException(e.toString()); } + catch (NoSuchProviderException e) + { + throw new IOException(e.toString()); + } + return encStoreData; + } + + public void engineLoad(KeyStore.LoadStoreParameter parameter) + throws CertificateException, NoSuchAlgorithmException, IOException + { + if (parameter == null) + { + throw new IllegalArgumentException("'parameter' arg cannot be null"); + } + + if (parameter instanceof BCFKSLoadStoreParameter) + { + BCFKSLoadStoreParameter bcParam = (BCFKSLoadStoreParameter)parameter; + + char[] password = extractPassword(bcParam); + + hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(bcParam.getStorePBKDFConfig(), 512 / 8); + + if (bcParam.getStoreEncryptionAlgorithm() == BCFKSLoadStoreParameter.EncryptionAlgorithm.AES256_CCM) + { + storeEncryptionAlgorithm = NISTObjectIdentifiers.id_aes256_CCM; + } + else + { + storeEncryptionAlgorithm = NISTObjectIdentifiers.id_aes256_wrap_pad; + } + + if (bcParam.getStoreMacAlgorithm() == BCFKSLoadStoreParameter.MacAlgorithm.HmacSHA512) + { + hmacAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE); + } + else + { + hmacAlgorithm = new AlgorithmIdentifier(NISTObjectIdentifiers.id_hmacWithSHA3_512, DERNull.INSTANCE); + } + + this.verificationKey = (PublicKey)bcParam.getStoreSignatureKey(); + this.validator = bcParam.getCertChainValidator(); + this.signatureAlgorithm = generateSignatureAlgId(verificationKey, bcParam.getStoreSignatureAlgorithm()); + + AlgorithmIdentifier presetHmacAlgorithm = hmacAlgorithm; + ASN1ObjectIdentifier presetStoreEncryptionAlgorithm = storeEncryptionAlgorithm; + + InputStream inputStream = bcParam.getInputStream(); + + engineLoad(inputStream, password); + + if (inputStream != null) + { + if (//!presetHmacAlgorithm.equals(hmacAlgorithm) + !isSimilarHmacPbkd(bcParam.getStorePBKDFConfig(), hmacPkbdAlgorithm) + || !presetStoreEncryptionAlgorithm.equals(storeEncryptionAlgorithm)) + { + throw new IOException("configuration parameters do not match existing store"); + } + } + } + else if (parameter instanceof BCLoadStoreParameter) + { + BCLoadStoreParameter bcParam = (BCLoadStoreParameter)parameter; + + engineLoad(bcParam.getInputStream(), extractPassword(parameter)); + } + else + { + throw new IllegalArgumentException( + "no support for 'parameter' of type " + parameter.getClass().getName()); + } + } + + private boolean isSimilarHmacPbkd(PBKDFConfig storePBKDFConfig, KeyDerivationFunc hmacPkbdAlgorithm) + { + if (!storePBKDFConfig.getAlgorithm().equals(hmacPkbdAlgorithm.getAlgorithm())) + { + return false; + } - // update the salt if (MiscObjectIdentifiers.id_scrypt.equals(hmacPkbdAlgorithm.getAlgorithm())) { + if (!(storePBKDFConfig instanceof ScryptConfig)) + { + return false; + } + + ScryptConfig scryptConfig = (ScryptConfig)storePBKDFConfig; ScryptParams sParams = ScryptParams.getInstance(hmacPkbdAlgorithm.getParameters()); - hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(hmacPkbdAlgorithm, sParams.getKeyLength().intValue()); + if (scryptConfig.getSaltLength() != sParams.getSalt().length + || scryptConfig.getBlockSize() != sParams.getBlockSize().intValue() + || scryptConfig.getCostParameter() != sParams.getCostParameter().intValue() + || scryptConfig.getParallelizationParameter() != sParams.getParallelizationParameter().intValue()) + { + return false; + } } else { + if (!(storePBKDFConfig instanceof PBKDF2Config)) + { + return false; + } + + PBKDF2Config pbkdf2Config = (PBKDF2Config)storePBKDFConfig; PBKDF2Params pbkdf2Params = PBKDF2Params.getInstance(hmacPkbdAlgorithm.getParameters()); - hmacPkbdAlgorithm = generatePkbdAlgorithmIdentifier(hmacPkbdAlgorithm, pbkdf2Params.getKeyLength().intValue()); + if (pbkdf2Config.getSaltLength() != pbkdf2Params.getSalt().length + || pbkdf2Config.getIterationCount() != pbkdf2Params.getIterationCount().intValue()) + { + return false; + } } - byte[] mac = calculateMac(encStoreData.getEncoded(), hmacAlgorithm, hmacPkbdAlgorithm, password); - - ObjectStore store = new ObjectStore(encStoreData, new ObjectStoreIntegrityCheck(new PbkdMacIntegrityCheck(hmacAlgorithm, hmacPkbdAlgorithm, mac))); - - outputStream.write(store.getEncoded()); - outputStream.flush(); + return true; } - + public void engineLoad(InputStream inputStream, char[] password) throws IOException, NoSuchAlgorithmException, CertificateException { @@ -963,6 +1218,8 @@ class BcFKSKeyStoreSpi { // initialise defaults lastModifiedDate = creationDate = new Date(); + verificationKey = null; + validator = null; // basic initialisation hmacAlgorithm = new AlgorithmIdentifier(PKCSObjectIdentifiers.id_hmacWithSHA512, DERNull.INSTANCE); @@ -985,6 +1242,8 @@ class BcFKSKeyStoreSpi } ObjectStoreIntegrityCheck integrityCheck = store.getIntegrityCheck(); + AlgorithmIdentifier integrityAlg; + if (integrityCheck.getType() == ObjectStoreIntegrityCheck.PBKD_MAC_CHECK) { PbkdMacIntegrityCheck pbkdMacIntegrityCheck = PbkdMacIntegrityCheck.getInstance(integrityCheck.getIntegrityCheck()); @@ -992,7 +1251,59 @@ class BcFKSKeyStoreSpi hmacAlgorithm = pbkdMacIntegrityCheck.getMacAlgorithm(); hmacPkbdAlgorithm = pbkdMacIntegrityCheck.getPbkdAlgorithm(); - verifyMac(store.getStoreData().toASN1Primitive().getEncoded(), pbkdMacIntegrityCheck, password); + integrityAlg = hmacAlgorithm; + + try + { + verifyMac(store.getStoreData().toASN1Primitive().getEncoded(), pbkdMacIntegrityCheck, password); + } + catch (NoSuchProviderException e) + { + throw new IOException(e.getMessage()); + } + } + else if (integrityCheck.getType() == ObjectStoreIntegrityCheck.SIG_CHECK) + { + SignatureCheck sigCheck = SignatureCheck.getInstance(integrityCheck.getIntegrityCheck()); + + integrityAlg = sigCheck.getSignatureAlgorithm(); + + try + { + com.fr.third.org.bouncycastle.asn1.x509.Certificate[] certificates = sigCheck.getCertificates(); + if (validator != null) + { + if (certificates == null) + { + throw new IOException("validator specified but no certifcates in store"); + } + CertificateFactory certFact = helper.createCertificateFactory("X.509"); + X509Certificate[] certs = new X509Certificate[certificates.length]; + + for (int i = 0; i != certs.length; i++) + { + certs[i] = (X509Certificate)certFact.generateCertificate( + new ByteArrayInputStream(certificates[i].getEncoded())); + } + + if (validator.isValid(certs)) + { + verifySig(store.getStoreData(), sigCheck, certs[0].getPublicKey()); + } + else + { + throw new IOException("certificate chain in key store signature not valid"); + } + } + else + { + verifySig(store.getStoreData(), sigCheck, verificationKey); + } + } + catch (GeneralSecurityException e) + { + throw new IOException("error verifying signature: " + e.getMessage(), e); + } } else { @@ -1024,7 +1335,7 @@ class BcFKSKeyStoreSpi throw new IOException("BCFKS KeyStore unable to parse store data information."); } - if (!storeData.getIntegrityAlgorithm().equals(hmacAlgorithm)) + if (!storeData.getIntegrityAlgorithm().equals(integrityAlg)) { throw new IOException("BCFKS KeyStore storeData integrity algorithm does not match store integrity algorithm."); } @@ -1054,16 +1365,8 @@ class BcFKSKeyStoreSpi AlgorithmParameters algParams; if (algId.getAlgorithm().equals(NISTObjectIdentifiers.id_aes256_CCM)) { - if (provider == null) - { - c = Cipher.getInstance("AES/CCM/NoPadding"); - algParams = AlgorithmParameters.getInstance("CCM"); - } - else - { - c = Cipher.getInstance("AES/CCM/NoPadding", provider); - algParams = AlgorithmParameters.getInstance("CCM", provider); - } + c = helper.createCipher("AES/CCM/NoPadding"); + algParams = helper.createAlgorithmParameters("CCM"); CCMParameters ccmParameters = CCMParameters.getInstance(algId.getParameters()); @@ -1071,16 +1374,8 @@ class BcFKSKeyStoreSpi } else if (algId.getAlgorithm().equals(NISTObjectIdentifiers.id_aes256_wrap_pad)) { - if (provider == null) - { - c = Cipher.getInstance("AESKWP"); - algParams = null; - } - else - { - c = Cipher.getInstance("AESKWP", provider); - algParams = null; - } + c = helper.createCipher("AESKWP"); + algParams = null; } else { @@ -1104,6 +1399,50 @@ class BcFKSKeyStoreSpi } } + private AlgorithmIdentifier generateSignatureAlgId(Key key, BCFKSLoadStoreParameter.SignatureAlgorithm sigAlg) + throws IOException + { + if (key== null) + { + return null; + } + + if (key instanceof ECKey) + { + if (sigAlg == BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withECDSA) + { + return new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA512); + } + else if (sigAlg == BCFKSLoadStoreParameter.SignatureAlgorithm.SHA3_512withECDSA) + { + return new AlgorithmIdentifier(NISTObjectIdentifiers.id_ecdsa_with_sha3_512); + } + } + if (key instanceof DSAKey) + { + if (sigAlg == BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withDSA) + { + return new AlgorithmIdentifier(NISTObjectIdentifiers.dsa_with_sha512); + } + else if (sigAlg == BCFKSLoadStoreParameter.SignatureAlgorithm.SHA3_512withDSA) + { + return new AlgorithmIdentifier(NISTObjectIdentifiers.id_dsa_with_sha3_512); + } + } + if (key instanceof RSAKey) + { + if (sigAlg == BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withRSA) + { + return new AlgorithmIdentifier(PKCSObjectIdentifiers.sha512WithRSAEncryption, DERNull.INSTANCE); + } + else if (sigAlg == BCFKSLoadStoreParameter.SignatureAlgorithm.SHA3_512withRSA) + { + return new AlgorithmIdentifier(NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_512, DERNull.INSTANCE); + } + } + throw new IOException("unknown signature algorithm"); + } + private KeyDerivationFunc generatePkbdAlgorithmIdentifier(PBKDFConfig pbkdfConfig, int keySizeInBytes) { if (MiscObjectIdentifiers.id_scrypt.equals(pbkdfConfig.getAlgorithm())) @@ -1148,7 +1487,7 @@ class BcFKSKeyStoreSpi else { PBKDF2Params oldParams = PBKDF2Params.getInstance(baseAlg.getParameters()); - + byte[] pbkdSalt = new byte[oldParams.getSalt().length]; getDefaultSecureRandom().nextBytes(pbkdSalt); @@ -1178,7 +1517,7 @@ class BcFKSKeyStoreSpi { public Std() { - super(new BouncyCastleProvider()); + super(new BCJcaJceHelper()); } } @@ -1187,7 +1526,7 @@ class BcFKSKeyStoreSpi { public Def() { - super(null); + super(new DefaultJcaJceHelper()); } } @@ -1198,26 +1537,18 @@ class BcFKSKeyStoreSpi private final Map cache; private final byte[] seedKey; - public SharedKeyStoreSpi(BouncyCastleProvider provider) + public SharedKeyStoreSpi(JcaJceHelper provider) { super(provider); try { this.seedKey = new byte[32]; - - if (provider != null) - { - SecureRandom.getInstance("DEFAULT", provider).nextBytes(seedKey); - } - else - { - SecureRandom.getInstance("DEFAULT").nextBytes(seedKey); - } + provider.createSecureRandom("DEFAULT").nextBytes(seedKey); } - catch (NoSuchAlgorithmException e) + catch (GeneralSecurityException e) { - throw new IllegalArgumentException("can't create cert factory - " + e.toString()); + throw new IllegalArgumentException("can't create random - " + e.toString()); } this.cache = new HashMap(); @@ -1227,8 +1558,25 @@ class BcFKSKeyStoreSpi String alias) throws KeyStoreException { - cache.remove(alias); - super.engineDeleteEntry(alias); + throw new KeyStoreException("delete operation not supported in shared mode"); + } + + public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain) + throws KeyStoreException + { + throw new KeyStoreException("set operation not supported in shared mode"); + } + + public void engineSetKeyEntry(String alias, byte[] keyEncoding, Certificate[] chain) + throws KeyStoreException + { + throw new KeyStoreException("set operation not supported in shared mode"); + } + + public void engineSetCertificateEntry(String alias, Certificate cert) + throws KeyStoreException + { + throw new KeyStoreException("set operation not supported in shared mode"); } public Key engineGetKey( @@ -1289,7 +1637,7 @@ class BcFKSKeyStoreSpi { public StdShared() { - super(new BouncyCastleProvider()); + super(new BCJcaJceHelper()); } } @@ -1298,7 +1646,7 @@ class BcFKSKeyStoreSpi { public DefShared() { - super(null); + super(new DefaultJcaJceHelper()); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java index e016dc0f3..1026778c6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/keystore/pkcs12/PKCS12KeyStoreSpi.java @@ -2,7 +2,6 @@ package com.fr.third.org.bouncycastle.jcajce.provider.keystore.pkcs12; import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -19,10 +18,8 @@ import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Principal; import java.security.PrivateKey; -import java.security.Provider; import java.security.PublicKey; import java.security.SecureRandom; -import java.security.Security; import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; @@ -59,11 +56,10 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.ASN1Set; import com.fr.third.org.bouncycastle.asn1.BEROctetString; -import com.fr.third.org.bouncycastle.asn1.BEROutputStream; +import com.fr.third.org.bouncycastle.asn1.BERSequence; import com.fr.third.org.bouncycastle.asn1.DERBMPString; import com.fr.third.org.bouncycastle.asn1.DERNull; import com.fr.third.org.bouncycastle.asn1.DEROctetString; -import com.fr.third.org.bouncycastle.asn1.DEROutputStream; import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.asn1.DERSet; import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; @@ -98,6 +94,7 @@ import com.fr.third.org.bouncycastle.jcajce.PKCS12StoreParameter; import com.fr.third.org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; import com.fr.third.org.bouncycastle.jcajce.spec.PBKDF2KeySpec; import com.fr.third.org.bouncycastle.jcajce.util.BCJcaJceHelper; +import com.fr.third.org.bouncycastle.jcajce.util.DefaultJcaJceHelper; import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; import com.fr.third.org.bouncycastle.jce.interfaces.BCKeyStore; import com.fr.third.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; @@ -196,7 +193,7 @@ public class PKCS12KeyStoreSpi } public PKCS12KeyStoreSpi( - Provider provider, + JcaJceHelper helper, ASN1ObjectIdentifier keyAlgorithm, ASN1ObjectIdentifier certAlgorithm) { @@ -205,14 +202,7 @@ public class PKCS12KeyStoreSpi try { - if (provider != null) - { - certFact = CertificateFactory.getInstance("X.509", provider); - } - else - { - certFact = CertificateFactory.getInstance("X.509"); - } + certFact = helper.createCertificateFactory("X.509"); } catch (Exception e) { @@ -410,7 +400,7 @@ public class PKCS12KeyStoreSpi { ASN1InputStream aIn = new ASN1InputStream(bytes); - byte[] authBytes = ((ASN1OctetString)aIn.readObject()).getOctets(); + byte[] authBytes = ASN1OctetString.getInstance(aIn.readObject()).getOctets(); aIn = new ASN1InputStream(authBytes); AuthorityKeyIdentifier id = AuthorityKeyIdentifier.getInstance(aIn.readObject()); @@ -778,11 +768,6 @@ public class PKCS12KeyStoreSpi return; } - if (password == null) - { - throw new NullPointerException("No password supplied for PKCS#12 KeyStore."); - } - BufferedInputStream bufIn = new BufferedInputStream(stream); bufIn.mark(10); @@ -815,6 +800,11 @@ public class PKCS12KeyStoreSpi if (bag.getMacData() != null) // check the mac code { + if (password == null) + { + throw new NullPointerException("no password supplied when one expected"); + } + MacData mData = bag.getMacData(); DigestInfo dInfo = mData.getMac(); macAlgorithm = dInfo.getAlgorithmId(); @@ -856,6 +846,16 @@ public class PKCS12KeyStoreSpi throw new IOException("error constructing MAC: " + e.toString()); } } + else + { + if (!Properties.isOverrideSet("com.fr.third.org.bouncycastle.pkcs12.ignore_useless_passwd")) + { + if (password != null) + { + throw new IOException("password supplied for keystore that does not require one"); + } + } + } keys = new IgnoresCaseHashtable(); localIds = new Hashtable(); @@ -871,8 +871,8 @@ public class PKCS12KeyStoreSpi { if (c[i].getContentType().equals(data)) { - ASN1InputStream dIn = new ASN1InputStream(((ASN1OctetString)c[i].getContent()).getOctets()); - ASN1Sequence seq = (ASN1Sequence)dIn.readObject(); + ASN1InputStream dIn = new ASN1InputStream(ASN1OctetString.getInstance(c[i].getContent()).getOctets()); + ASN1Sequence seq = ASN1Sequence.getInstance(dIn.readObject()); for (int j = 0; j != seq.size(); j++) { @@ -1304,9 +1304,57 @@ public class PKCS12KeyStoreSpi private void doStore(OutputStream stream, char[] password, boolean useDEREncoding) throws IOException { - if (password == null) + if (keys.size() == 0) + { + if (password == null) + { + Enumeration cs = certs.keys(); + + ASN1EncodableVector certSeq = new ASN1EncodableVector(); + + while (cs.hasMoreElements()) + { + try + { + String certId = (String)cs.nextElement(); + Certificate cert = (Certificate)certs.get(certId); + + SafeBag sBag = createSafeBag(certId, cert); + + certSeq.add(sBag); + } + catch (CertificateEncodingException e) + { + throw new IOException("Error encoding certificate: " + e.toString()); + } + } + + if (useDEREncoding) + { + ContentInfo bagInfo = new ContentInfo(PKCSObjectIdentifiers.data, new DEROctetString(new DERSequence(certSeq).getEncoded())); + + Pfx pfx = new Pfx(new ContentInfo(PKCSObjectIdentifiers.data, new DEROctetString(new DERSequence(bagInfo).getEncoded())), null); + + pfx.encodeTo(stream, ASN1Encoding.DER); + } + else + { + ContentInfo bagInfo = new ContentInfo(PKCSObjectIdentifiers.data, new BEROctetString(new BERSequence(certSeq).getEncoded())); + + Pfx pfx = new Pfx(new ContentInfo(PKCSObjectIdentifiers.data, new BEROctetString(new BERSequence(bagInfo).getEncoded())), null); + + pfx.encodeTo(stream, ASN1Encoding.BER); + } + + return; + } + } + else { - throw new NullPointerException("No password supplied for PKCS#12 KeyStore."); + if (password == null) + { + throw new NullPointerException("no password supplied for PKCS#12 KeyStore"); + } } // @@ -1492,66 +1540,13 @@ public class PKCS12KeyStoreSpi { String certId = (String)cs.nextElement(); Certificate cert = (Certificate)certs.get(certId); - boolean cAttrSet = false; if (keys.get(certId) != null) { continue; } - CertBag cBag = new CertBag( - x509Certificate, - new DEROctetString(cert.getEncoded())); - ASN1EncodableVector fName = new ASN1EncodableVector(); - - if (cert instanceof PKCS12BagAttributeCarrier) - { - PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert; - // - // make sure we are using the local alias on store - // - DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName); - if (nm == null || !nm.getString().equals(certId)) - { - bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId)); - } - - Enumeration e = bagAttrs.getBagAttributeKeys(); - - while (e.hasMoreElements()) - { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); - - // a certificate not immediately linked to a key doesn't require - // a localKeyID and will confuse some PKCS12 implementations. - // - // If we find one, we'll prune it out. - if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId)) - { - continue; - } - - ASN1EncodableVector fSeq = new ASN1EncodableVector(); - - fSeq.add(oid); - fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid))); - fName.add(new DERSequence(fSeq)); - - cAttrSet = true; - } - } - - if (!cAttrSet) - { - ASN1EncodableVector fSeq = new ASN1EncodableVector(); - - fSeq.add(pkcs_9_at_friendlyName); - fSeq.add(new DERSet(new DERBMPString(certId))); - - fName.add(new DERSequence(fSeq)); - } - - SafeBag sBag = new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName)); + SafeBag sBag = createSafeBag(certId, cert); certSeq.add(sBag); @@ -1636,20 +1631,7 @@ public class PKCS12KeyStoreSpi AuthenticatedSafe auth = new AuthenticatedSafe(info); - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - DEROutputStream asn1Out; - if (useDEREncoding) - { - asn1Out = new DEROutputStream(bOut); - } - else - { - asn1Out = new BEROutputStream(bOut); - } - - asn1Out.writeObject(auth); - - byte[] pkg = bOut.toByteArray(); + byte[] pkg = auth.getEncoded(useDEREncoding ? ASN1Encoding.DER : ASN1Encoding.BER); ContentInfo mainInfo = new ContentInfo(data, new BEROctetString(pkg)); @@ -1682,16 +1664,69 @@ public class PKCS12KeyStoreSpi // Pfx pfx = new Pfx(mainInfo, mData); - if (useDEREncoding) + pfx.encodeTo(stream, useDEREncoding ? ASN1Encoding.DER : ASN1Encoding.BER); + } + + private SafeBag createSafeBag(String certId, Certificate cert) + throws CertificateEncodingException + { + CertBag cBag = new CertBag( + x509Certificate, + new DEROctetString(cert.getEncoded())); + ASN1EncodableVector fName = new ASN1EncodableVector(); + + boolean cAttrSet = false; + if (cert instanceof PKCS12BagAttributeCarrier) { - asn1Out = new DEROutputStream(stream); + PKCS12BagAttributeCarrier bagAttrs = (PKCS12BagAttributeCarrier)cert; + // + // make sure we are using the local alias on store + // + DERBMPString nm = (DERBMPString)bagAttrs.getBagAttribute(pkcs_9_at_friendlyName); + if (nm == null || !nm.getString().equals(certId)) + { + if (certId != null) + { + bagAttrs.setBagAttribute(pkcs_9_at_friendlyName, new DERBMPString(certId)); + } + } + + Enumeration e = bagAttrs.getBagAttributeKeys(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + + // a certificate not immediately linked to a key doesn't require + // a localKeyID and will confuse some PKCS12 implementations. + // + // If we find one, we'll prune it out. + if (oid.equals(PKCSObjectIdentifiers.pkcs_9_at_localKeyId)) + { + continue; + } + + ASN1EncodableVector fSeq = new ASN1EncodableVector(); + + fSeq.add(oid); + fSeq.add(new DERSet(bagAttrs.getBagAttribute(oid))); + fName.add(new DERSequence(fSeq)); + + cAttrSet = true; + } } - else + + if (!cAttrSet) { - asn1Out = new BEROutputStream(stream); + ASN1EncodableVector fSeq = new ASN1EncodableVector(); + + fSeq.add(pkcs_9_at_friendlyName); + fSeq.add(new DERSet(new DERBMPString(certId))); + + fName.add(new DERSequence(fSeq)); } - asn1Out.writeObject(pfx); + return new SafeBag(certBag, cBag.toASN1Primitive(), new DERSet(fName)); } private Set getUsedCertificateSet() @@ -1745,7 +1780,7 @@ public class PKCS12KeyStoreSpi { public BCPKCS12KeyStore() { - super(PKCS12KeyStoreSpi.getBouncyCastleProvider(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC); + super(new BCJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC); } } @@ -1754,7 +1789,7 @@ public class PKCS12KeyStoreSpi { public BCPKCS12KeyStore3DES() { - super(PKCS12KeyStoreSpi.getBouncyCastleProvider(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC); + super(new BCJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC); } } @@ -1763,7 +1798,7 @@ public class PKCS12KeyStoreSpi { public DefPKCS12KeyStore() { - super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC); + super(new DefaultJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd40BitRC2_CBC); } } @@ -1772,7 +1807,7 @@ public class PKCS12KeyStoreSpi { public DefPKCS12KeyStore3DES() { - super(null, pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC); + super(new DefaultJcaJceHelper(), pbeWithSHAAnd3_KeyTripleDES_CBC, pbeWithSHAAnd3_KeyTripleDES_CBC); } } @@ -1825,6 +1860,11 @@ public class PKCS12KeyStoreSpi { return orig.elements(); } + + public int size() + { + return orig.size(); + } } private static class DefaultSecretKeyProvider @@ -1865,20 +1905,4 @@ public class PKCS12KeyStoreSpi return -1; } } - - private static Provider provider = null; - - private static synchronized Provider getBouncyCastleProvider() - { - if (Security.getProvider("BC") != null) - { - return Security.getProvider("BC"); - } - else if (provider == null) - { - provider = new BouncyCastleProvider(); - } - - return provider; - } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/AES.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/AES.java index ed65804bb..31e29a885 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/AES.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/AES.java @@ -19,6 +19,7 @@ import com.fr.third.org.bouncycastle.crypto.BlockCipher; import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; import com.fr.third.org.bouncycastle.crypto.CipherKeyGenerator; import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; import com.fr.third.org.bouncycastle.crypto.DataLengthException; import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; import com.fr.third.org.bouncycastle.crypto.Mac; @@ -118,7 +119,7 @@ public final class AES { public CCM() { - super(new CCMBlockCipher(new AESEngine()), false, 16); + super(new CCMBlockCipher(new AESEngine()), false, 12); } } @@ -506,7 +507,7 @@ public final class AES if (random == null) { - random = new SecureRandom(); + random = CryptoServicesRegistrar.getSecureRandom(); } random.nextBytes(iv); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/CAST6.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/CAST6.java index e65d220f9..4fc3cb153 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/CAST6.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/CAST6.java @@ -11,6 +11,7 @@ import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCip import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BlockCipherProvider; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters; public final class CAST6 { @@ -69,6 +70,15 @@ public final class CAST6 } } + public static class AlgParams + extends IvAlgorithmParameters + { + protected String engineToString() + { + return "CAST6 IV"; + } + } + public static class Mappings extends SymmetricAlgorithmProvider { @@ -82,7 +92,8 @@ public final class CAST6 { provider.addAlgorithm("Cipher.CAST6", PREFIX + "$ECB"); provider.addAlgorithm("KeyGenerator.CAST6", PREFIX + "$KeyGen"); - + provider.addAlgorithm("AlgorithmParameters.CAST6", PREFIX + "$AlgParams"); + addGMacAlgorithm(provider, "CAST6", PREFIX + "$GMAC", PREFIX + "$KeyGen"); addPoly1305Algorithm(provider, "CAST6", PREFIX + "$Poly1305", PREFIX + "$Poly1305KeyGen"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java index c1a127afb..d00ab8c6d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/ChaCha.java @@ -1,11 +1,15 @@ package com.fr.third.org.bouncycastle.jcajce.provider.symmetric; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.CipherKeyGenerator; import com.fr.third.org.bouncycastle.crypto.engines.ChaCha7539Engine; import com.fr.third.org.bouncycastle.crypto.engines.ChaChaEngine; +import com.fr.third.org.bouncycastle.crypto.modes.ChaCha20Poly1305; import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseBlockCipher; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters; import com.fr.third.org.bouncycastle.jcajce.provider.util.AlgorithmProvider; public final class ChaCha @@ -41,6 +45,15 @@ public final class ChaCha } } + public static class BaseCC20P1305 + extends BaseBlockCipher + { + public BaseCC20P1305() + { + super(new ChaCha20Poly1305(), true, 12); + } + } + public static class KeyGen7539 extends BaseKeyGenerator { @@ -50,6 +63,24 @@ public final class ChaCha } } + public static class AlgParams + extends IvAlgorithmParameters + { + protected String engineToString() + { + return "ChaCha7539 IV"; + } + } + + public static class AlgParamsCC1305 + extends IvAlgorithmParameters + { + protected String engineToString() + { + return "ChaCha20-Poly1305 IV"; + } + } + public static class Mappings extends AlgorithmProvider { @@ -67,6 +98,19 @@ public final class ChaCha provider.addAlgorithm("Cipher.CHACHA7539", PREFIX + "$Base7539"); provider.addAlgorithm("KeyGenerator.CHACHA7539", PREFIX + "$KeyGen7539"); + provider.addAlgorithm("AlgorithmParameters.CHACHA7539", PREFIX + "$AlgParams"); + provider.addAlgorithm("Alg.Alias.Cipher.CHACHA20", "CHACHA7539"); + provider.addAlgorithm("Alg.Alias.KeyGenerator.CHACHA20", "CHACHA7539"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters.CHACHA20", "CHACHA7539"); + + provider.addAlgorithm("Alg.Alias.KeyGenerator.CHACHA20-POLY1305", "CHACHA7539"); + provider.addAlgorithm("Alg.Alias.KeyGenerator." + PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305, "CHACHA7539"); + provider.addAlgorithm("Cipher.CHACHA20-POLY1305", PREFIX + "$BaseCC20P1305"); + provider.addAlgorithm("AlgorithmParameters.CHACHA20-POLY1305", PREFIX + "$AlgParamsCC1305"); + provider.addAlgorithm("Alg.Alias.Cipher." + PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305, "CHACHA20-POLY1305"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters." + PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305, "CHACHA20-POLY1305"); + provider.addAlgorithm("Alg.Alias.Cipher.OID." + PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305, "CHACHA20-POLY1305"); + provider.addAlgorithm("Alg.Alias.AlgorithmParameters.OID." + PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305, "CHACHA20-POLY1305"); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/DESede.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/DESede.java index 78b2cbe12..8f7d2067d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/DESede.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/DESede.java @@ -425,6 +425,7 @@ public final class DESede provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND3-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES3KeyFactory"); provider.addAlgorithm("SecretKeyFactory.PBEWITHSHAAND2-KEYTRIPLEDES-CBC", PREFIX + "$PBEWithSHAAndDES2KeyFactory"); + provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWITHSHA1ANDDESEDE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND3-KEYTRIPLEDES", "PKCS12PBE"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAAND2-KEYTRIPLEDES", "PKCS12PBE"); @@ -433,6 +434,7 @@ public final class DESede provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES3KEY-CBC", "PKCS12PBE"); provider.addAlgorithm("Alg.Alias.AlgorithmParameters.PBEWITHSHAANDDES2KEY-CBC", "PKCS12PBE"); + provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBE", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"); provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.3", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"); provider.addAlgorithm("Alg.Alias.SecretKeyFactory.1.2.840.113549.1.12.1.4", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC"); provider.addAlgorithm("Alg.Alias.SecretKeyFactory.PBEWithSHAAnd3KeyTripleDES", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC"); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/GOST28147.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/GOST28147.java index ff1d9bb34..231dd60d9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/GOST28147.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/GOST28147.java @@ -17,6 +17,7 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.cryptopro.GOST28147Parameters; +import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; import com.fr.third.org.bouncycastle.crypto.CipherKeyGenerator; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; @@ -35,6 +36,7 @@ import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseWrapCipher; import com.fr.third.org.bouncycastle.jcajce.provider.util.AlgorithmProvider; import com.fr.third.org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; +import com.fr.third.org.bouncycastle.util.Strings; public final class GOST28147 { @@ -43,16 +45,18 @@ public final class GOST28147 static { - oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_TestParamSet, "E-TEST"); - oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_A_ParamSet, "E-A"); - oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_B_ParamSet, "E-B"); - oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_C_ParamSet, "E-C"); - oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_D_ParamSet, "E-D"); - - nameMappings.put("E-A", CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_A_ParamSet); - nameMappings.put("E-B", CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_B_ParamSet); - nameMappings.put("E-C", CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_C_ParamSet); - nameMappings.put("E-D", CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_D_ParamSet); + oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_TestParamSet, "E-TEST"); + oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_A_ParamSet, "E-A"); + oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_B_ParamSet, "E-B"); + oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_C_ParamSet, "E-C"); + oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_D_ParamSet, "E-D"); + oidMappings.put(RosstandartObjectIdentifiers.id_tc26_gost_28147_param_Z, "PARAM-Z"); + + nameMappings.put("E-A", CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_A_ParamSet); + nameMappings.put("E-B", CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_B_ParamSet); + nameMappings.put("E-C", CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_C_ParamSet); + nameMappings.put("E-D", CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_D_ParamSet); + nameMappings.put("PARAM-Z", RosstandartObjectIdentifiers.id_tc26_gost_28147_param_Z); } private GOST28147() @@ -288,7 +292,12 @@ public final class GOST28147 protected static ASN1ObjectIdentifier getSBoxOID(String name) { - ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)nameMappings.get(name); + ASN1ObjectIdentifier oid = null; + + if (name != null) + { + oid = (ASN1ObjectIdentifier)nameMappings.get(Strings.toUpperCase(name)); + } if (oid == null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/GOST3412_2015.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/GOST3412_2015.java index 26056461e..9c61f9b3a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/GOST3412_2015.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/GOST3412_2015.java @@ -68,7 +68,7 @@ public class GOST3412_2015 { public CTR() { - super(new BufferedBlockCipher(new G3413CTRBlockCipher(new GOST3412_2015Engine())), 128); + super(new BufferedBlockCipher(new G3413CTRBlockCipher(new GOST3412_2015Engine())), true,64); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Grainv1.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Grainv1.java index 9aa5e6891..c2257dc7b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Grainv1.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Grainv1.java @@ -5,6 +5,7 @@ import com.fr.third.org.bouncycastle.crypto.engines.Grainv1Engine; import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters; import com.fr.third.org.bouncycastle.jcajce.provider.util.AlgorithmProvider; public final class Grainv1 @@ -31,6 +32,15 @@ public final class Grainv1 } } + public static class AlgParams + extends IvAlgorithmParameters + { + protected String engineToString() + { + return "Grainv1 IV"; + } + } + public static class Mappings extends AlgorithmProvider { @@ -44,6 +54,7 @@ public final class Grainv1 { provider.addAlgorithm("Cipher.Grainv1", PREFIX + "$Base"); provider.addAlgorithm("KeyGenerator.Grainv1", PREFIX + "$KeyGen"); + provider.addAlgorithm("AlgorithmParameters.Grainv1", PREFIX + "$AlgParams"); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/HC128.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/HC128.java index 9fcc5fff7..de6ac0b07 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/HC128.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/HC128.java @@ -5,6 +5,7 @@ import com.fr.third.org.bouncycastle.crypto.engines.HC128Engine; import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters; import com.fr.third.org.bouncycastle.jcajce.provider.util.AlgorithmProvider; public final class HC128 @@ -31,6 +32,15 @@ public final class HC128 } } + public static class AlgParams + extends IvAlgorithmParameters + { + protected String engineToString() + { + return "HC128 IV"; + } + } + public static class Mappings extends AlgorithmProvider { @@ -44,6 +54,7 @@ public final class HC128 { provider.addAlgorithm("Cipher.HC128", PREFIX + "$Base"); provider.addAlgorithm("KeyGenerator.HC128", PREFIX + "$KeyGen"); + provider.addAlgorithm("AlgorithmParameters.HC128", PREFIX + "$AlgParams"); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/HC256.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/HC256.java index 3805eec24..c10c0471c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/HC256.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/HC256.java @@ -5,6 +5,7 @@ import com.fr.third.org.bouncycastle.crypto.engines.HC256Engine; import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters; import com.fr.third.org.bouncycastle.jcajce.provider.util.AlgorithmProvider; public final class HC256 @@ -31,6 +32,15 @@ public final class HC256 } } + public static class AlgParams + extends IvAlgorithmParameters + { + protected String engineToString() + { + return "HC256 IV"; + } + } + public static class Mappings extends AlgorithmProvider { @@ -44,6 +54,7 @@ public final class HC256 { provider.addAlgorithm("Cipher.HC256", PREFIX + "$Base"); provider.addAlgorithm("KeyGenerator.HC256", PREFIX + "$KeyGen"); + provider.addAlgorithm("AlgorithmParameters.HC256", PREFIX + "$AlgParams"); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/IDEA.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/IDEA.java index 38f08ad8a..536cfd6d5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/IDEA.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/IDEA.java @@ -9,8 +9,6 @@ import java.security.spec.InvalidParameterSpecException; import javax.crypto.spec.IvParameterSpec; -import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; -import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.misc.IDEACBCPar; import com.fr.third.org.bouncycastle.asn1.misc.MiscObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.CipherKeyGenerator; @@ -193,8 +191,7 @@ public final class IDEA } if (format.equals("ASN.1")) { - ASN1InputStream aIn = new ASN1InputStream(params); - IDEACBCPar oct = new IDEACBCPar((ASN1Sequence)aIn.readObject()); + IDEACBCPar oct = IDEACBCPar.getInstance(params); engineInit(oct.getIV()); return; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java index ce99e3068..7cff146eb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/PBEPBKDF2.java @@ -16,6 +16,7 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.gm.GMObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import com.fr.third.org.bouncycastle.asn1.pkcs.PBKDF2Params; import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; @@ -47,6 +48,7 @@ public class PBEPBKDF2 prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_224, Integers.valueOf(PBE.SHA3_224)); prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_384, Integers.valueOf(PBE.SHA3_384)); prfCodes.put(NISTObjectIdentifiers.id_hmacWithSHA3_512, Integers.valueOf(PBE.SHA3_512)); + prfCodes.put(GMObjectIdentifiers.hmac_sm3, Integers.valueOf(PBE.SM3)); } private PBEPBKDF2() @@ -325,6 +327,14 @@ public class PBEPBKDF2 } } + public static class PBKDF2withSM3 + extends BasePBKDF2 + { + public PBKDF2withSM3() { + super("PBKDF2", PKCS5S2_UTF8, SM3); + } + } + public static class Mappings extends AlgorithmProvider { @@ -354,6 +364,7 @@ public class PBEPBKDF2 provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-384", PREFIX + "$PBKDF2withSHA3_384"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSHA3-512", PREFIX + "$PBKDF2withSHA3_512"); provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACGOST3411", PREFIX + "$PBKDF2withGOST3411"); + provider.addAlgorithm("SecretKeyFactory.PBKDF2WITHHMACSM3", PREFIX + "$PBKDF2withSM3"); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Salsa20.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Salsa20.java index bb31beeca..54af5d763 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Salsa20.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Salsa20.java @@ -5,6 +5,7 @@ import com.fr.third.org.bouncycastle.crypto.engines.Salsa20Engine; import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters; import com.fr.third.org.bouncycastle.jcajce.provider.util.AlgorithmProvider; public final class Salsa20 @@ -31,6 +32,15 @@ public final class Salsa20 } } + public static class AlgParams + extends IvAlgorithmParameters + { + protected String engineToString() + { + return "Salsa20 IV"; + } + } + public static class Mappings extends AlgorithmProvider { @@ -45,7 +55,7 @@ public final class Salsa20 provider.addAlgorithm("Cipher.SALSA20", PREFIX + "$Base"); provider.addAlgorithm("KeyGenerator.SALSA20", PREFIX + "$KeyGen"); - + provider.addAlgorithm("AlgorithmParameters.SALSA20", PREFIX + "$AlgParams"); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Serpent.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Serpent.java index c5e733109..c5e521fa2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Serpent.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Serpent.java @@ -6,7 +6,6 @@ import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; import com.fr.third.org.bouncycastle.crypto.CipherKeyGenerator; import com.fr.third.org.bouncycastle.crypto.engines.SerpentEngine; import com.fr.third.org.bouncycastle.crypto.engines.TnepresEngine; -import com.fr.third.org.bouncycastle.crypto.engines.TwofishEngine; import com.fr.third.org.bouncycastle.crypto.generators.Poly1305KeyGenerator; import com.fr.third.org.bouncycastle.crypto.macs.GMac; import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; @@ -124,7 +123,7 @@ public final class Serpent { public Poly1305() { - super(new com.fr.third.org.bouncycastle.crypto.macs.Poly1305(new TwofishEngine())); + super(new com.fr.third.org.bouncycastle.crypto.macs.Poly1305(new SerpentEngine())); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/XSalsa20.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/XSalsa20.java index 60d295677..1d1fa85b5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/XSalsa20.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/XSalsa20.java @@ -5,6 +5,7 @@ import com.fr.third.org.bouncycastle.crypto.engines.XSalsa20Engine; import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters; import com.fr.third.org.bouncycastle.jcajce.provider.util.AlgorithmProvider; public final class XSalsa20 @@ -31,6 +32,15 @@ public final class XSalsa20 } } + public static class AlgParams + extends IvAlgorithmParameters + { + protected String engineToString() + { + return "XSalsa20 IV"; + } + } + public static class Mappings extends AlgorithmProvider { @@ -45,7 +55,7 @@ public final class XSalsa20 provider.addAlgorithm("Cipher.XSALSA20", PREFIX + "$Base"); provider.addAlgorithm("KeyGenerator.XSALSA20", PREFIX + "$KeyGen"); - + provider.addAlgorithm("AlgorithmParameters.XSALSA20", PREFIX + "$AlgParams"); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/XTEA.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/XTEA.java index 5f89b4eb2..1b0587b37 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/XTEA.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/XTEA.java @@ -52,11 +52,9 @@ public final class XTEA public void configure(ConfigurableProvider provider) { - provider.addAlgorithm("Cipher.XTEA", PREFIX + "$ECB"); provider.addAlgorithm("KeyGenerator.XTEA", PREFIX + "$KeyGen"); provider.addAlgorithm("AlgorithmParameters.XTEA", PREFIX + "$AlgParams"); - } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Zuc.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Zuc.java new file mode 100644 index 000000000..d3ea25c4b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/Zuc.java @@ -0,0 +1,127 @@ +package com.fr.third.org.bouncycastle.jcajce.provider.symmetric; + +import com.fr.third.org.bouncycastle.crypto.CipherKeyGenerator; +import com.fr.third.org.bouncycastle.crypto.engines.Zuc128Engine; +import com.fr.third.org.bouncycastle.crypto.engines.Zuc256Engine; +import com.fr.third.org.bouncycastle.crypto.macs.Zuc128Mac; +import com.fr.third.org.bouncycastle.crypto.macs.Zuc256Mac; +import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseKeyGenerator; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseMac; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BaseStreamCipher; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.IvAlgorithmParameters; + +public class Zuc +{ + private Zuc() + { + } + + public static class Zuc128 + extends BaseStreamCipher + { + public Zuc128() + { + super(new Zuc128Engine(), 16, 128); + } + } + + public static class Zuc256 + extends BaseStreamCipher + { + public Zuc256() + { + super(new Zuc256Engine(), 25, 256); + } + } + + public static class KeyGen128 + extends BaseKeyGenerator + { + public KeyGen128() + { + super("ZUC128", 128, new CipherKeyGenerator()); + } + } + + public static class KeyGen256 + extends BaseKeyGenerator + { + public KeyGen256() + { + super("ZUC256", 256, new CipherKeyGenerator()); + } + } + + public static class AlgParams + extends IvAlgorithmParameters + { + protected String engineToString() + { + return "Zuc IV"; + } + } + + public static class ZucMac128 + extends BaseMac + { + public ZucMac128() + { + super(new Zuc128Mac()); + } + } + + public static class ZucMac256 + extends BaseMac + { + public ZucMac256() + { + super(new Zuc256Mac(128)); + } + } + + public static class ZucMac256_64 + extends BaseMac + { + public ZucMac256_64() + { + super(new Zuc256Mac(64)); + } + } + + public static class ZucMac256_32 + extends BaseMac + { + public ZucMac256_32() + { + super(new Zuc256Mac(32)); + } + } + + public static class Mappings + extends SymmetricAlgorithmProvider + { + private static final String PREFIX = Zuc.class.getName(); + + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("Cipher.ZUC-128", PREFIX + "$Zuc128"); + provider.addAlgorithm("KeyGenerator.ZUC-128", PREFIX + "$KeyGen128"); + provider.addAlgorithm("AlgorithmParameters.ZUC-128", PREFIX + "$AlgParams"); + + provider.addAlgorithm("Cipher.ZUC-256", PREFIX + "$Zuc256"); + provider.addAlgorithm("KeyGenerator.ZUC-256", PREFIX + "$KeyGen256"); + provider.addAlgorithm("AlgorithmParameters.ZUC-256", PREFIX + "$AlgParams"); + + provider.addAlgorithm("Mac.ZUC-128", PREFIX + "$ZucMac128"); + provider.addAlgorithm("Mac.ZUC-256", PREFIX + "$ZucMac256"); + provider.addAlgorithm("Alg.Alias.Mac.ZUC-256-128", "ZUC-256"); + provider.addAlgorithm("Mac.ZUC-256-64", PREFIX + "$ZucMac256_64"); + provider.addAlgorithm("Mac.ZUC-256-32", PREFIX + "$ZucMac256_32"); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java index e0a1527e0..c2fa845c4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseBlockCipher.java @@ -24,7 +24,9 @@ import javax.crypto.spec.PBEParameterSpec; import javax.crypto.spec.RC2ParameterSpec; import javax.crypto.spec.RC5ParameterSpec; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; import com.fr.third.org.bouncycastle.asn1.cms.GCMParameters; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.BlockCipher; import com.fr.third.org.bouncycastle.crypto.BufferedBlockCipher; import com.fr.third.org.bouncycastle.crypto.CipherParameters; @@ -34,6 +36,7 @@ import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException; import com.fr.third.org.bouncycastle.crypto.OutputLengthException; import com.fr.third.org.bouncycastle.crypto.engines.DSTU7624Engine; import com.fr.third.org.bouncycastle.crypto.modes.AEADBlockCipher; +import com.fr.third.org.bouncycastle.crypto.modes.AEADCipher; import com.fr.third.org.bouncycastle.crypto.modes.CBCBlockCipher; import com.fr.third.org.bouncycastle.crypto.modes.CCMBlockCipher; import com.fr.third.org.bouncycastle.crypto.modes.CFBBlockCipher; @@ -71,12 +74,14 @@ import com.fr.third.org.bouncycastle.jcajce.PKCS12KeyWithParameters; import com.fr.third.org.bouncycastle.jcajce.spec.AEADParameterSpec; import com.fr.third.org.bouncycastle.jcajce.spec.GOST28147ParameterSpec; import com.fr.third.org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec; +import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.Strings; public class BaseBlockCipher extends BaseWrapCipher implements PBE { + private static final int BUF_SIZE = 512; private static final Class gcmSpecClass = ClassUtil.loadClass(BaseBlockCipher.class, "javax.crypto.spec.GCMParameterSpec"); // @@ -153,6 +158,17 @@ public class BaseBlockCipher this.cipher = new AEADGenericBlockCipher(engine); } + protected BaseBlockCipher( + AEADCipher engine, + boolean fixedIv, + int ivLength) + { + this.baseEngine = null; + this.fixedIv = fixedIv; + this.ivLength = ivLength; + this.cipher = new AEADGenericBlockCipher(engine); + } + protected BaseBlockCipher( AEADBlockCipher engine, boolean fixedIv, @@ -204,6 +220,10 @@ public class BaseBlockCipher protected int engineGetBlockSize() { + if (baseEngine == null) + { + return -1; + } return baseEngine.getBlockSize(); } @@ -247,14 +267,30 @@ public class BaseBlockCipher } else if (aeadParams != null) { - try + // CHACHA20-Poly1305 + if (baseEngine == null) { - engineParams = createParametersInstance("GCM"); - engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize() / 8).getEncoded()); + try + { + engineParams = createParametersInstance(PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305.getId()); + engineParams.init(new DEROctetString(aeadParams.getNonce()).getEncoded()); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } } - catch (Exception e) + else { - throw new RuntimeException(e.toString()); + try + { + engineParams = createParametersInstance("GCM"); + engineParams.init(new GCMParameters(aeadParams.getNonce(), aeadParams.getMacSize() / 8).getEncoded()); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } } } else if (ivParam != null) @@ -285,6 +321,10 @@ public class BaseBlockCipher String mode) throws NoSuchAlgorithmException { + if (baseEngine == null) + { + throw new NoSuchAlgorithmException("no mode supported for this algorithm"); + } modeName = Strings.toUpperCase(mode); if (modeName.equals("ECB")) @@ -441,6 +481,11 @@ public class BaseBlockCipher String padding) throws NoSuchPaddingException { + if (baseEngine == null) + { + throw new NoSuchPaddingException("no padding supported for this algorithm"); + } + String paddingName = Strings.toUpperCase(padding); if (paddingName.equals("NOPADDING")) @@ -518,7 +563,7 @@ public class BaseBlockCipher // // for RC5-64 we must have some default parameters // - if (params == null && baseEngine.getAlgorithmName().startsWith("RC5-64")) + if (params == null && (baseEngine != null && baseEngine.getAlgorithmName().startsWith("RC5-64"))) { throw new InvalidAlgorithmParameterException("RC5 requires an RC5ParametersSpec to be passed in."); } @@ -872,12 +917,16 @@ public class BaseBlockCipher if (cipher instanceof AEADGenericBlockCipher && aeadParams == null) { - AEADBlockCipher aeadCipher = ((AEADGenericBlockCipher)cipher).cipher; + AEADCipher aeadCipher = ((AEADGenericBlockCipher)cipher).cipher; aeadParams = new AEADParameters((KeyParameter)ivParam.getParameters(), aeadCipher.getMac().length * 8, ivParam.getIV()); } } - catch (final Exception e) + catch (IllegalArgumentException e) + { + throw new InvalidAlgorithmParameterException(e.getMessage(), e); + } + catch (Exception e) { throw new InvalidKeyOrParametersException(e.getMessage(), e); } @@ -997,11 +1046,38 @@ public class BaseBlockCipher cipher.updateAAD(input, offset, length); } - protected void engineUpdateAAD(ByteBuffer bytebuffer) + protected void engineUpdateAAD(ByteBuffer src) { - int offset = bytebuffer.arrayOffset() + bytebuffer.position(); - int length = bytebuffer.limit() - bytebuffer.position(); - engineUpdateAAD(bytebuffer.array(), offset, length); + int remaining = src.remaining(); + if (remaining < 1) + { + // No data to update + } + else if (src.hasArray()) + { + engineUpdateAAD(src.array(), src.arrayOffset() + src.position(), remaining); + src.position(src.limit()); + } + else if (remaining <= BUF_SIZE) + { + byte[] data = new byte[remaining]; + src.get(data); + engineUpdateAAD(data, 0, data.length); + Arrays.fill(data, (byte)0); + } + else + { + byte[] data = new byte[BUF_SIZE]; + do + { + int length = Math.min(data.length, remaining); + src.get(data, 0, length); + engineUpdateAAD(data, 0, length); + remaining -= length; + } + while (remaining > 0); + Arrays.fill(data, (byte)0); + } } protected byte[] engineUpdate( @@ -1277,9 +1353,9 @@ public class BaseBlockCipher } } - private AEADBlockCipher cipher; + private AEADCipher cipher; - AEADGenericBlockCipher(AEADBlockCipher cipher) + AEADGenericBlockCipher(AEADCipher cipher) { this.cipher = cipher; } @@ -1292,7 +1368,12 @@ public class BaseBlockCipher public String getAlgorithmName() { - return cipher.getUnderlyingCipher().getAlgorithmName(); + if (cipher instanceof AEADBlockCipher) + { + return ((AEADBlockCipher)cipher).getUnderlyingCipher().getAlgorithmName(); + } + + return cipher.getAlgorithmName(); } public boolean wrapOnNoPadding() @@ -1302,7 +1383,12 @@ public class BaseBlockCipher public com.fr.third.org.bouncycastle.crypto.BlockCipher getUnderlyingCipher() { - return cipher.getUnderlyingCipher(); + if (cipher instanceof AEADBlockCipher) + { + return ((AEADBlockCipher)cipher).getUnderlyingCipher(); + } + + return null; } public int getOutputSize(int len) @@ -1359,21 +1445,4 @@ public class BaseBlockCipher } } } - - private static class InvalidKeyOrParametersException - extends InvalidKeyException - { - private final Throwable cause; - - InvalidKeyOrParametersException(String msg, Throwable cause) - { - super(msg); - this.cause = cause; - } - - public Throwable getCause() - { - return cause; - } - } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java index 70e735390..dd8e6dad4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseStreamCipher.java @@ -59,6 +59,14 @@ public class BaseStreamCipher this(engine, ivLength, -1, -1); } + protected BaseStreamCipher( + StreamCipher engine, + int ivLength, + int keySizeInBits) + { + this(engine, ivLength, keySizeInBits, -1); + } + protected BaseStreamCipher( StreamCipher engine, int ivLength, @@ -111,6 +119,38 @@ public class BaseStreamCipher return null; } } + else if (ivParam != null) + { + String name = cipher.getAlgorithmName(); + + if (name.indexOf('/') >= 0) + { + name = name.substring(0, name.indexOf('/')); + } + if (name.startsWith("ChaCha7539")) + { + name = "ChaCha7539"; + } + else if (name.startsWith("Grain")) + { + name = "Grainv1"; + } + else if (name.startsWith("HC")) + { + int endIndex = name.indexOf('-'); + name = name.substring(0, endIndex) + name.substring(endIndex + 1); + } + + try + { + engineParams = createParametersInstance(name); + engineParams.init(new IvParameterSpec(ivParam.getIV())); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } + } } return engineParams; @@ -123,7 +163,7 @@ public class BaseStreamCipher String mode) throws NoSuchAlgorithmException { - if (!mode.equalsIgnoreCase("ECB")) + if (!(mode.equalsIgnoreCase("ECB") || mode.equals("NONE"))) { throw new NoSuchAlgorithmException("can't support mode " + mode); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java index 957a4609f..f45096307 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/BaseWrapCipher.java @@ -118,7 +118,30 @@ public abstract class BaseWrapCipher protected AlgorithmParameters engineGetParameters() { - return null; + if (engineParams == null) + { + if (iv != null) + { + String name = wrapEngine.getAlgorithmName(); + + if (name.indexOf('/') >= 0) + { + name = name.substring(0, name.indexOf('/')); + } + + try + { + engineParams = createParametersInstance(name); + engineParams.init(new IvParameterSpec(iv)); + } + catch (Exception e) + { + throw new RuntimeException(e.toString()); + } + } + } + + return engineParams; } protected final AlgorithmParameters createParametersInstance(String algorithm) @@ -174,8 +197,9 @@ public abstract class BaseWrapCipher if (params instanceof IvParameterSpec) { - IvParameterSpec iv = (IvParameterSpec) params; - param = new ParametersWithIV(param, iv.getIV()); + IvParameterSpec ivSpec = (IvParameterSpec)params; + this.iv = ivSpec.getIV(); + param = new ParametersWithIV(param, iv); } if (params instanceof GOST28147WrapParameterSpec) @@ -192,9 +216,12 @@ public abstract class BaseWrapCipher if (param instanceof KeyParameter && ivSize != 0) { - iv = new byte[ivSize]; - random.nextBytes(iv); - param = new ParametersWithIV(param, iv); + if (opmode == Cipher.WRAP_MODE || opmode == Cipher.ENCRYPT_MODE) + { + iv = new byte[ivSize]; + random.nextBytes(iv); + param = new ParametersWithIV(param, iv); + } } if (random != null) @@ -202,30 +229,37 @@ public abstract class BaseWrapCipher param = new ParametersWithRandom(param, random); } - switch (opmode) - { - case Cipher.WRAP_MODE: - wrapEngine.init(true, param); - this.wrapStream = null; - this.forWrapping = true; - break; - case Cipher.UNWRAP_MODE: - wrapEngine.init(false, param); - this.wrapStream = null; - this.forWrapping = false; - break; - case Cipher.ENCRYPT_MODE: - wrapEngine.init(true, param); - this.wrapStream = new ErasableOutputStream(); - this.forWrapping = true; - break; - case Cipher.DECRYPT_MODE: - wrapEngine.init(false, param); - this.wrapStream = new ErasableOutputStream(); - this.forWrapping = false; - break; - default: - throw new InvalidParameterException("Unknown mode parameter passed to init."); + try + { + switch (opmode) + { + case Cipher.WRAP_MODE: + wrapEngine.init(true, param); + this.wrapStream = null; + this.forWrapping = true; + break; + case Cipher.UNWRAP_MODE: + wrapEngine.init(false, param); + this.wrapStream = null; + this.forWrapping = false; + break; + case Cipher.ENCRYPT_MODE: + wrapEngine.init(true, param); + this.wrapStream = new ErasableOutputStream(); + this.forWrapping = true; + break; + case Cipher.DECRYPT_MODE: + wrapEngine.init(false, param); + this.wrapStream = new ErasableOutputStream(); + this.forWrapping = false; + break; + default: + throw new InvalidParameterException("Unknown mode parameter passed to init."); + } + } + catch (Exception e) + { + throw new InvalidKeyOrParametersException(e.getMessage(), e); } } @@ -275,7 +309,7 @@ public abstract class BaseWrapCipher } catch (InvalidAlgorithmParameterException e) { - throw new IllegalArgumentException(e.getMessage()); + throw new InvalidKeyOrParametersException(e.getMessage(), e); } } @@ -323,13 +357,23 @@ public abstract class BaseWrapCipher throw new IllegalStateException("not supported in a wrapping mode"); } - wrapStream.write(input, inputOffset, inputLen); + if (input != null) + { + wrapStream.write(input, inputOffset, inputLen); + } try { if (forWrapping) { - return wrapEngine.wrap(wrapStream.getBuf(), 0, wrapStream.size()); + try + { + return wrapEngine.wrap(wrapStream.getBuf(), 0, wrapStream.size()); + } + catch (Exception e) + { + throw new IllegalBlockSizeException(e.getMessage()); + } } else { @@ -370,7 +414,14 @@ public abstract class BaseWrapCipher if (forWrapping) { - enc = wrapEngine.wrap(wrapStream.getBuf(), 0, wrapStream.size()); + try + { + enc = wrapEngine.wrap(wrapStream.getBuf(), 0, wrapStream.size()); + } + catch (Exception e) + { + throw new IllegalBlockSizeException(e.getMessage()); + } } else { @@ -533,4 +584,21 @@ public abstract class BaseWrapCipher reset(); } } + + protected static class InvalidKeyOrParametersException + extends InvalidKeyException + { + private final Throwable cause; + + InvalidKeyOrParametersException(String msg, Throwable cause) + { + super(msg); + this.cause = cause; + } + + public Throwable getCause() + { + return cause; + } + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java index f3bc0ba9e..003fb0ee5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/symmetric/util/PBE.java @@ -12,6 +12,7 @@ import com.fr.third.org.bouncycastle.crypto.PBEParametersGenerator; import com.fr.third.org.bouncycastle.crypto.digests.GOST3411Digest; import com.fr.third.org.bouncycastle.crypto.digests.MD2Digest; import com.fr.third.org.bouncycastle.crypto.digests.RIPEMD160Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SM3Digest; import com.fr.third.org.bouncycastle.crypto.digests.TigerDigest; import com.fr.third.org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; import com.fr.third.org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; @@ -41,6 +42,7 @@ public interface PBE static final int SHA3_256 = 11; static final int SHA3_384 = 12; static final int SHA3_512 = 13; + static final int SM3 = 14; static final int PKCS5S1 = 0; static final int PKCS5S2 = 1; @@ -123,6 +125,9 @@ public interface PBE case SHA3_512: generator = new PKCS5S2ParametersGenerator(DigestFactory.createSHA3_512()); break; + case SM3: + generator = new PKCS5S2ParametersGenerator(new SM3Digest()); + break; default: throw new IllegalStateException("unknown digest scheme for PBE PKCS5S2 encryption."); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java index 8fd163c28..fccb431ac 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/provider/util/AsymmetricAlgorithmProvider.java @@ -5,7 +5,18 @@ import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider public abstract class AsymmetricAlgorithmProvider extends AlgorithmProvider -{ +{ + protected void addSignatureAlgorithm( + ConfigurableProvider provider, + String algorithm, + String className, + ASN1ObjectIdentifier oid) + { + provider.addAlgorithm("Signature." + algorithm, className); + provider.addAlgorithm("Alg.Alias.Signature." + oid, algorithm); + provider.addAlgorithm("Alg.Alias.Signature.OID." + oid, algorithm); + } + protected void addSignatureAlgorithm( ConfigurableProvider provider, String digest, diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/DSTU4145ParameterSpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/DSTU4145ParameterSpec.java new file mode 100644 index 000000000..548fb482f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/DSTU4145ParameterSpec.java @@ -0,0 +1,54 @@ +package com.fr.third.org.bouncycastle.jcajce.spec; + +import java.security.spec.ECParameterSpec; + +import com.fr.third.org.bouncycastle.asn1.ua.DSTU4145Params; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.EC5Util; +import com.fr.third.org.bouncycastle.util.Arrays; + +/** + * ParameterSpec for a DSTU4145 key. + */ +public class DSTU4145ParameterSpec + extends ECParameterSpec +{ + private final byte[] dke; + private final ECDomainParameters parameters; + + public DSTU4145ParameterSpec( + ECDomainParameters parameters) + { + this(parameters, EC5Util.convertToSpec(parameters), DSTU4145Params.getDefaultDKE()); + } + + private DSTU4145ParameterSpec(ECDomainParameters parameters, ECParameterSpec ecParameterSpec, byte[] dke) + { + super(ecParameterSpec.getCurve(), ecParameterSpec.getGenerator(), ecParameterSpec.getOrder(), ecParameterSpec.getCofactor()); + + this.parameters = parameters; + this.dke = Arrays.clone(dke); + } + + public byte[] getDKE() + { + return Arrays.clone(dke); + } + + public boolean equals(Object o) + { + if (o instanceof DSTU4145ParameterSpec) + { + DSTU4145ParameterSpec other = (DSTU4145ParameterSpec)o; + + return this.parameters.equals(other.parameters); + } + + return false; + } + + public int hashCode() + { + return this.parameters.hashCode(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/EdDSAParameterSpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/EdDSAParameterSpec.java new file mode 100644 index 000000000..425b55823 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/EdDSAParameterSpec.java @@ -0,0 +1,57 @@ +package com.fr.third.org.bouncycastle.jcajce.spec; + +import java.security.spec.AlgorithmParameterSpec; + +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; + +/** + * ParameterSpec for EdDSA signature algorithms. + */ +public class EdDSAParameterSpec + implements AlgorithmParameterSpec +{ + public static final String Ed25519 = "Ed25519"; + public static final String Ed448 = "Ed448"; + + private final String curveName; + + /** + * Base constructor. + * + * @param curveName name of the curve to specify. + */ + public EdDSAParameterSpec(String curveName) + { + if (curveName.equalsIgnoreCase(Ed25519)) + { + this.curveName = Ed25519; + } + else if (curveName.equalsIgnoreCase(Ed448)) + { + this.curveName = Ed448; + } + else if (curveName.equals(EdECObjectIdentifiers.id_Ed25519.getId())) + { + this.curveName = Ed25519; + } + else if (curveName.equals(EdECObjectIdentifiers.id_Ed448.getId())) + { + this.curveName = Ed448; + } + else + { + throw new IllegalArgumentException("unrecognized curve name: " + curveName); + } + + } + + /** + * Return the curve name specified by this parameterSpec. + * + * @return the name of the curve this parameterSpec specifies. + */ + public String getCurveName() + { + return curveName; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/GOST28147ParameterSpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/GOST28147ParameterSpec.java index d7e869616..02e1d021e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/GOST28147ParameterSpec.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/GOST28147ParameterSpec.java @@ -6,6 +6,7 @@ import java.util.Map; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.engines.GOST28147Engine; import com.fr.third.org.bouncycastle.util.Arrays; @@ -91,6 +92,7 @@ public class GOST28147ParameterSpec oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_B_ParamSet, "E-B"); oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_C_ParamSet, "E-C"); oidMappings.put(CryptoProObjectIdentifiers.id_Gost28147_89_CryptoPro_D_ParamSet, "E-D"); + oidMappings.put(RosstandartObjectIdentifiers.id_tc26_gost_28147_param_Z, "Param-Z"); } private static String getName(ASN1ObjectIdentifier sBoxOid) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/GOST3410ParameterSpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/GOST3410ParameterSpec.java new file mode 100644 index 000000000..61a60c0ba --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/GOST3410ParameterSpec.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.jcajce.spec; + +import java.security.spec.AlgorithmParameterSpec; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; +import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; + +/** + * ParameterSpec for a GOST 3410-1994/2001/2012 algorithm parameters. + */ +public class GOST3410ParameterSpec + implements AlgorithmParameterSpec +{ + private final ASN1ObjectIdentifier publicKeyParamSet; + private final ASN1ObjectIdentifier digestParamSet; + private final ASN1ObjectIdentifier encryptionParamSet; + + /** + * Constructor for signing parameters. + * + * @param publicKeyParamSet the curve parameter set name. + */ + public GOST3410ParameterSpec(String publicKeyParamSet) + { + this(getOid(publicKeyParamSet), getDigestOid(publicKeyParamSet), null); + } + + /** + * Constructor for signing parameters. + * + * @param publicKeyParamSet the public key parameter set object identifier. + * @param digestParamSet the object identifier for the digest algorithm to be associated with parameters. + */ + public GOST3410ParameterSpec(ASN1ObjectIdentifier publicKeyParamSet, ASN1ObjectIdentifier digestParamSet) + { + this(publicKeyParamSet, digestParamSet, null); + } + + /** + * Constructor for signing/encryption parameters. + * + * @param publicKeyParamSet the public key parameter set object identifier. + * @param digestParamSet the object identifier for the digest algorithm to be associated with parameters. + * @param encryptionParamSet the object identifier associated with encryption algorithm to use. + */ + public GOST3410ParameterSpec(ASN1ObjectIdentifier publicKeyParamSet, ASN1ObjectIdentifier digestParamSet, ASN1ObjectIdentifier encryptionParamSet) + { + this.publicKeyParamSet = publicKeyParamSet; + this.digestParamSet = digestParamSet; + this.encryptionParamSet = encryptionParamSet; + } + + public String getPublicKeyParamSetName() + { + return ECGOST3410NamedCurves.getName(this.getPublicKeyParamSet()); + } + + /** + * Return the object identifier for the public key parameter set. + * + * @return the OID for the public key parameter set. + */ + public ASN1ObjectIdentifier getPublicKeyParamSet() + { + return publicKeyParamSet; + } + + /** + * Return the object identifier for the digest parameter set. + * + * @return the OID for the digest parameter set. + */ + public ASN1ObjectIdentifier getDigestParamSet() + { + return digestParamSet; + } + + /** + * Return the object identifier for the encryption parameter set. + * + * @return the OID for the encryption parameter set. + */ + public ASN1ObjectIdentifier getEncryptionParamSet() + { + return encryptionParamSet; + } + + private static ASN1ObjectIdentifier getOid(String paramName) + { + return ECGOST3410NamedCurves.getOID(paramName); + } + + private static ASN1ObjectIdentifier getDigestOid(String paramName) + { + if (paramName.indexOf("12-512") > 0) + { + return RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512; + } + if (paramName.indexOf("12-256") > 0) + { + return RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256; + } + + return CryptoProObjectIdentifiers.gostR3411_94_CryptoProParamSet; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/OpenSSHPrivateKeySpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/OpenSSHPrivateKeySpec.java new file mode 100644 index 000000000..dc593cfe0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/OpenSSHPrivateKeySpec.java @@ -0,0 +1,58 @@ +package com.fr.third.org.bouncycastle.jcajce.spec; + +import java.security.spec.EncodedKeySpec; + +/** + * OpenSSHPrivateKeySpec holds and encoded OpenSSH private key. + * The format of the key can be either ASN.1 or OpenSSH. + */ +public class OpenSSHPrivateKeySpec + extends EncodedKeySpec +{ + private final String format; + + /** + * Accept an encoded key and determine the format. + *

+ * The encoded key should be the Base64 decoded blob between the "---BEGIN and ---END" markers. + * This constructor will endeavour to find the OpenSSH format magic value. If it can not then it + * will default to ASN.1. It does not attempt to validate the ASN.1 + *

+ * Example: + * OpenSSHPrivateKeySpec privSpec = new OpenSSHPrivateKeySpec(rawPriv); + *

+ * KeyFactory kpf = KeyFactory.getInstance("RSA", "BC"); + * PrivateKey prk = kpf.generatePrivate(privSpec); + *

+ * OpenSSHPrivateKeySpec rcPrivateSpec = kpf.getKeySpec(prk, OpenSSHPrivateKeySpec.class); + * + * @param encodedKey The encoded key. + */ + public OpenSSHPrivateKeySpec(byte[] encodedKey) + { + super(encodedKey); + + if (encodedKey[0] == 0x30) // DER SEQUENCE + { + format = "ASN.1"; + } + else if (encodedKey[0] == 'o') + { + format = "OpenSSH"; + } + else + { + throw new IllegalArgumentException("unknown byte encoding"); + } + } + + /** + * Return the format, either OpenSSH for the OpenSSH propriety format or ASN.1. + * + * @return the format OpenSSH or ASN.1 + */ + public String getFormat() + { + return format; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/OpenSSHPublicKeySpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/OpenSSHPublicKeySpec.java new file mode 100644 index 000000000..3959bb934 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/OpenSSHPublicKeySpec.java @@ -0,0 +1,77 @@ +package com.fr.third.org.bouncycastle.jcajce.spec; + +import java.security.spec.EncodedKeySpec; + +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; + +/** + * Holds an OpenSSH encoded public key. + */ +public class OpenSSHPublicKeySpec + extends EncodedKeySpec +{ + private static final String[] allowedTypes = new String[]{"ssh-rsa", "ssh-ed25519", "ssh-dss"}; + private final String type; + + + /** + * Construct and instance and determine the OpenSSH public key type. + * The current types are ssh-rsa, ssh-ed25519, ssh-dss and ecdsa-* + *

+ * It does not validate the key beyond identifying the type. + * + * @param encodedKey + */ + public OpenSSHPublicKeySpec(byte[] encodedKey) + { + super(encodedKey); + + // + // The type is encoded at the start of the blob. + // + int pos = 0; + int i = (encodedKey[pos++] & 0xFF) << 24; + i |= (encodedKey[pos++] & 0xFF) << 16; + i |= (encodedKey[pos++] & 0xFF) << 8; + i |= (encodedKey[pos++] & 0xFF); + + if ((pos + i) >= encodedKey.length) + { + throw new IllegalArgumentException("invalid public key blob: type field longer than blob"); + } + + this.type = Strings.fromByteArray(Arrays.copyOfRange(encodedKey, pos, pos + i)); + + if (type.startsWith("ecdsa")) + { + return; // These have a curve name and digest in them and can't be compared exactly. + } + + for (int t = 0; t < allowedTypes.length; t++) + { + if (allowedTypes[t].equals(this.type)) + { + return; + } + } + + throw new IllegalArgumentException("unrecognised public key type " + type); + + } + + public String getFormat() + { + return "OpenSSH"; + } + + /** + * The type of OpenSSH public key. + * + * @return the type. + */ + public String getType() + { + return type; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/XDHParameterSpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/XDHParameterSpec.java new file mode 100644 index 000000000..92f2c7667 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/spec/XDHParameterSpec.java @@ -0,0 +1,56 @@ +package com.fr.third.org.bouncycastle.jcajce.spec; + +import java.security.spec.AlgorithmParameterSpec; + +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; + +/** + * ParameterSpec for XDH key agreement algorithms. + */ +public class XDHParameterSpec + implements AlgorithmParameterSpec +{ + public static final String X25519 = "X25519"; + public static final String X448 = "X448"; + + private final String curveName; + + /** + * Base constructor. + * + * @param curveName name of the curve to specify. + */ + public XDHParameterSpec(String curveName) + { + if (curveName.equalsIgnoreCase(X25519)) + { + this.curveName = X25519; + } + else if (curveName.equalsIgnoreCase(X448)) + { + this.curveName = X448; + } + else if (curveName.equals(EdECObjectIdentifiers.id_X25519.getId())) + { + this.curveName = X25519; + } + else if (curveName.equals(EdECObjectIdentifiers.id_X448.getId())) + { + this.curveName = X448; + } + else + { + throw new IllegalArgumentException("unrecognized curve name: " + curveName); + } + } + + /** + * Return the curve name specified by this parameterSpec. + * + * @return the name of the curve this parameterSpec specifies. + */ + public String getCurveName() + { + return curveName; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/AnnotatedPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/AnnotatedPrivateKey.java new file mode 100644 index 000000000..b8b3e3b09 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/AnnotatedPrivateKey.java @@ -0,0 +1,116 @@ +package com.fr.third.org.bouncycastle.jcajce.util; + +import java.security.PrivateKey; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Wrapper for a private key that carries annotations that can be used + * for tracking or debugging. + */ +public class AnnotatedPrivateKey + implements PrivateKey +{ + public static final String LABEL = "label"; + + private final PrivateKey key; + private final Map annotations; + + AnnotatedPrivateKey(PrivateKey key, String label) + { + this.key = key; + this.annotations = Collections.singletonMap(LABEL, (Object)label); + } + + AnnotatedPrivateKey(PrivateKey key, Map annotations) + { + this.key = key; + this.annotations = annotations; + } + + public PrivateKey getKey() + { + return key; + } + + public Map getAnnotations() + { + return annotations; + } + + public String getAlgorithm() + { + return key.getAlgorithm(); + } + + public Object getAnnotation(String key) + { + return annotations.get(key); + } + + /** + * Return a new annotated key with an additional annotation added to it. + * + * @param name the name of the annotation to add. + * @param annotation the object providing the annotation details. + * @return a new annotated key with the extra annotation. + */ + public AnnotatedPrivateKey addAnnotation(String name, Object annotation) + { + Map newAnnotations = new HashMap(annotations); + + newAnnotations.put(name, annotation); + + return new AnnotatedPrivateKey(this.key, Collections.unmodifiableMap(newAnnotations)); + } + + /** + * Return a new annotated key with the named annotation removed. + * + * @param name the name of the annotation to remove. + * @return a new annotated key with the named annotation removed. + */ + public AnnotatedPrivateKey removeAnnotation(String name) + { + Map newAnnotations = new HashMap(annotations); + + newAnnotations.remove(name); + + return new AnnotatedPrivateKey(this.key, Collections.unmodifiableMap(newAnnotations)); + } + + public String getFormat() + { + return key.getFormat(); + } + + public byte[] getEncoded() + { + return key.getEncoded(); + } + + public int hashCode() + { + return this.key.hashCode(); + } + + public boolean equals(Object o) + { + if (o instanceof AnnotatedPrivateKey) + { + return this.key.equals(((AnnotatedPrivateKey)o).key); + } + return this.key.equals(o); + } + + public String toString() + { + if (annotations.containsKey(LABEL)) + { + return annotations.get(LABEL).toString(); + } + + return key.toString(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/BCJcaJceHelper.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/BCJcaJceHelper.java index 6dd157195..143b33574 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/BCJcaJceHelper.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/BCJcaJceHelper.java @@ -13,7 +13,7 @@ public class BCJcaJceHelper { private static volatile Provider bcProvider; - private static Provider getBouncyCastleProvider() + private static synchronized Provider getBouncyCastleProvider() { if (Security.getProvider("BC") != null) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java index fefacfa4d..b323bdc03 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/DefaultJcaJceHelper.java @@ -2,16 +2,24 @@ package com.fr.third.org.bouncycastle.jcajce.util; import java.security.AlgorithmParameterGenerator; import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; import java.security.KeyFactory; import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import java.security.Signature; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertPathValidator; +import java.security.cert.CertStore; +import java.security.cert.CertStoreParameters; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import javax.crypto.Cipher; +import javax.crypto.ExemptionMechanism; import javax.crypto.KeyAgreement; import javax.crypto.KeyGenerator; import javax.crypto.Mac; @@ -80,12 +88,19 @@ public class DefaultJcaJceHelper return KeyPairGenerator.getInstance(algorithm); } + /** @deprecated Use createMessageDigest instead */ public MessageDigest createDigest(String algorithm) throws NoSuchAlgorithmException { return MessageDigest.getInstance(algorithm); } + public MessageDigest createMessageDigest(String algorithm) + throws NoSuchAlgorithmException + { + return MessageDigest.getInstance(algorithm); + } + public Signature createSignature(String algorithm) throws NoSuchAlgorithmException { @@ -103,4 +118,34 @@ public class DefaultJcaJceHelper { return SecureRandom.getInstance(algorithm); } + + public CertPathBuilder createCertPathBuilder(String algorithm) + throws NoSuchAlgorithmException + { + return CertPathBuilder.getInstance(algorithm); + } + + public CertPathValidator createCertPathValidator(String algorithm) + throws NoSuchAlgorithmException + { + return CertPathValidator.getInstance(algorithm); + } + + public CertStore createCertStore(String type, CertStoreParameters params) + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException + { + return CertStore.getInstance(type, params); + } + + public ExemptionMechanism createExemptionMechanism(String algorithm) + throws NoSuchAlgorithmException + { + return ExemptionMechanism.getInstance(algorithm); + } + + public KeyStore createKeyStore(String type) + throws KeyStoreException + { + return KeyStore.getInstance(type); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/JcaJceHelper.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/JcaJceHelper.java index 94734c453..de7d15888 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/JcaJceHelper.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/JcaJceHelper.java @@ -2,17 +2,25 @@ package com.fr.third.org.bouncycastle.jcajce.util; import java.security.AlgorithmParameterGenerator; import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; import java.security.KeyFactory; import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.Signature; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertPathValidator; +import java.security.cert.CertStore; +import java.security.cert.CertStoreParameters; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import javax.crypto.Cipher; +import javax.crypto.ExemptionMechanism; import javax.crypto.KeyAgreement; import javax.crypto.KeyGenerator; import javax.crypto.Mac; @@ -52,9 +60,13 @@ public interface JcaJceHelper KeyPairGenerator createKeyPairGenerator(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException; + /** @deprecated Use createMessageDigest instead */ MessageDigest createDigest(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException; + MessageDigest createMessageDigest(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException; + Signature createSignature(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException; @@ -63,4 +75,19 @@ public interface JcaJceHelper SecureRandom createSecureRandom(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException; + + CertPathBuilder createCertPathBuilder(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException; + + CertPathValidator createCertPathValidator(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException; + + CertStore createCertStore(String type, CertStoreParameters params) + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException; + + ExemptionMechanism createExemptionMechanism(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException; + + KeyStore createKeyStore(String type) + throws KeyStoreException, NoSuchProviderException; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java index cf1242157..c79fb1e71 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/NamedJcaJceHelper.java @@ -2,17 +2,25 @@ package com.fr.third.org.bouncycastle.jcajce.util; import java.security.AlgorithmParameterGenerator; import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; import java.security.KeyFactory; import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.security.Signature; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertPathValidator; +import java.security.cert.CertStore; +import java.security.cert.CertStoreParameters; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import javax.crypto.Cipher; +import javax.crypto.ExemptionMechanism; import javax.crypto.KeyAgreement; import javax.crypto.KeyGenerator; import javax.crypto.Mac; @@ -87,12 +95,19 @@ public class NamedJcaJceHelper return KeyPairGenerator.getInstance(algorithm, providerName); } + /** @deprecated Use createMessageDigest instead */ public MessageDigest createDigest(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException { return MessageDigest.getInstance(algorithm, providerName); } + public MessageDigest createMessageDigest(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return MessageDigest.getInstance(algorithm, providerName); + } + public Signature createSignature(String algorithm) throws NoSuchAlgorithmException, NoSuchProviderException { @@ -110,4 +125,34 @@ public class NamedJcaJceHelper { return SecureRandom.getInstance(algorithm, providerName); } + + public CertPathBuilder createCertPathBuilder(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return CertPathBuilder.getInstance(algorithm, providerName); + } + + public CertPathValidator createCertPathValidator(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return CertPathValidator.getInstance(algorithm, providerName); + } + + public CertStore createCertStore(String type, CertStoreParameters params) + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException, NoSuchProviderException + { + return CertStore.getInstance(type, params, providerName); + } + + public ExemptionMechanism createExemptionMechanism(String algorithm) + throws NoSuchAlgorithmException, NoSuchProviderException + { + return ExemptionMechanism.getInstance(algorithm, providerName); + } + + public KeyStore createKeyStore(String type) + throws KeyStoreException, NoSuchProviderException + { + return KeyStore.getInstance(type, providerName); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/PrivateKeyAnnotator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/PrivateKeyAnnotator.java new file mode 100644 index 000000000..b7d1d2cdc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/PrivateKeyAnnotator.java @@ -0,0 +1,31 @@ +package com.fr.third.org.bouncycastle.jcajce.util; + +import java.security.PrivateKey; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +/** + * Class for instancing AnnotatedPrivateKeys. + */ +public class PrivateKeyAnnotator +{ + /** + * Create an AnnotatedPrivateKey with a single annotation using AnnotatedPrivateKey.LABEL as a key. + * + * @param privKey the private key to be annotated. + * @param label the label to be associated with the private key. + * @return the newly annotated private key. + */ + public static AnnotatedPrivateKey annotate(PrivateKey privKey, String label) + { + return new AnnotatedPrivateKey(privKey, label); + } + + public static AnnotatedPrivateKey annotate(PrivateKey privKey, Map annotations) + { + Map savedAnnotations = new HashMap(annotations); + + return new AnnotatedPrivateKey(privKey, Collections.unmodifiableMap(savedAnnotations)); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java index b1fa69078..b5b923599 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jcajce/util/ProviderJcaJceHelper.java @@ -2,17 +2,25 @@ package com.fr.third.org.bouncycastle.jcajce.util; import java.security.AlgorithmParameterGenerator; import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; import java.security.KeyFactory; import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.Provider; import java.security.SecureRandom; import java.security.Signature; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertPathValidator; +import java.security.cert.CertStore; +import java.security.cert.CertStoreParameters; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import javax.crypto.Cipher; +import javax.crypto.ExemptionMechanism; import javax.crypto.KeyAgreement; import javax.crypto.KeyGenerator; import javax.crypto.Mac; @@ -87,12 +95,19 @@ public class ProviderJcaJceHelper return KeyPairGenerator.getInstance(algorithm, provider); } + /** @deprecated Use createMessageDigest instead */ public MessageDigest createDigest(String algorithm) throws NoSuchAlgorithmException { return MessageDigest.getInstance(algorithm, provider); } + public MessageDigest createMessageDigest(String algorithm) + throws NoSuchAlgorithmException + { + return MessageDigest.getInstance(algorithm, provider); + } + public Signature createSignature(String algorithm) throws NoSuchAlgorithmException { @@ -110,4 +125,34 @@ public class ProviderJcaJceHelper { return SecureRandom.getInstance(algorithm, provider); } + + public CertPathBuilder createCertPathBuilder(String algorithm) + throws NoSuchAlgorithmException + { + return CertPathBuilder.getInstance(algorithm, provider); + } + + public CertPathValidator createCertPathValidator(String algorithm) + throws NoSuchAlgorithmException + { + return CertPathValidator.getInstance(algorithm, provider); + } + + public CertStore createCertStore(String type, CertStoreParameters params) + throws NoSuchAlgorithmException, InvalidAlgorithmParameterException + { + return CertStore.getInstance(type, params, provider); + } + + public ExemptionMechanism createExemptionMechanism(String algorithm) + throws NoSuchAlgorithmException + { + return ExemptionMechanism.getInstance(algorithm, provider); + } + + public KeyStore createKeyStore(String type) + throws KeyStoreException + { + return KeyStore.getInstance(type, provider); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/ECKeyUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/ECKeyUtil.java index 627741125..4413d858a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/ECKeyUtil.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/ECKeyUtil.java @@ -19,6 +19,7 @@ import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; @@ -70,13 +71,13 @@ public class ECKeyUtil { SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded())); - if (info.getAlgorithmId().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3410_2001)) + if (info.getAlgorithm().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3410_2001)) { throw new IllegalArgumentException("cannot convert GOST key to explicit parameters."); } else { - X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters()); + X962Parameters params = X962Parameters.getInstance(info.getAlgorithm().getParameters()); X9ECParameters curveParams; if (params.isNamedCurve()) @@ -84,12 +85,24 @@ public class ECKeyUtil ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); curveParams = ECUtil.getNamedCurveByOid(oid); - // ignore seed value due to JDK bug - curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH()); + + if (curveParams.hasSeed()) + { + // ignore seed value due to JDK bug + curveParams = new X9ECParameters( + curveParams.getCurve(), + curveParams.getBaseEntry(), + curveParams.getN(), + curveParams.getH()); + } } else if (params.isImplicitlyCA()) { - curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH()); + curveParams = new X9ECParameters( + BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), + new X9ECPoint(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), false), + BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), + BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH()); } else { @@ -160,13 +173,13 @@ public class ECKeyUtil { PrivateKeyInfo info = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(key.getEncoded())); - if (info.getAlgorithmId().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3410_2001)) + if (info.getPrivateKeyAlgorithm().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3410_2001)) { throw new UnsupportedEncodingException("cannot convert GOST key to explicit parameters."); } else { - X962Parameters params = X962Parameters.getInstance(info.getAlgorithmId().getParameters()); + X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters()); X9ECParameters curveParams; if (params.isNamedCurve()) @@ -174,12 +187,24 @@ public class ECKeyUtil ASN1ObjectIdentifier oid = ASN1ObjectIdentifier.getInstance(params.getParameters()); curveParams = ECUtil.getNamedCurveByOid(oid); - // ignore seed value due to JDK bug - curveParams = new X9ECParameters(curveParams.getCurve(), curveParams.getG(), curveParams.getN(), curveParams.getH()); + + if (curveParams.hasSeed()) + { + // ignore seed value due to JDK bug + curveParams = new X9ECParameters( + curveParams.getCurve(), + curveParams.getBaseEntry(), + curveParams.getN(), + curveParams.getH()); + } } else if (params.isImplicitlyCA()) { - curveParams = new X9ECParameters(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH()); + curveParams = new X9ECParameters( + BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getCurve(), + new X9ECPoint(BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getG(), false), + BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getN(), + BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa().getH()); } else { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/PKCS12Util.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/PKCS12Util.java index d0086cc52..bf2f178b4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/PKCS12Util.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/PKCS12Util.java @@ -1,6 +1,5 @@ package com.fr.third.org.bouncycastle.jce; -import java.io.ByteArrayOutputStream; import java.io.IOException; import javax.crypto.Mac; @@ -9,13 +8,12 @@ import javax.crypto.SecretKeyFactory; import javax.crypto.spec.PBEKeySpec; import javax.crypto.spec.PBEParameterSpec; -import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.DERNull; import com.fr.third.org.bouncycastle.asn1.DEROctetString; -import com.fr.third.org.bouncycastle.asn1.DEROutputStream; import com.fr.third.org.bouncycastle.asn1.pkcs.ContentInfo; import com.fr.third.org.bouncycastle.asn1.pkcs.MacData; import com.fr.third.org.bouncycastle.asn1.pkcs.Pfx; @@ -37,16 +35,9 @@ public class PKCS12Util public static byte[] convertToDefiniteLength(byte[] berPKCS12File) throws IOException { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - DEROutputStream dOut = new DEROutputStream(bOut); - Pfx pfx = Pfx.getInstance(berPKCS12File); - bOut.reset(); - - dOut.writeObject(pfx); - - return bOut.toByteArray(); + return pfx.getEncoded(ASN1Encoding.DER); } /** @@ -66,16 +57,11 @@ public class PKCS12Util ContentInfo info = pfx.getAuthSafe(); ASN1OctetString content = ASN1OctetString.getInstance(info.getContent()); + ASN1Primitive obj = ASN1Primitive.fromByteArray(content.getOctets()); - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - DEROutputStream dOut = new DEROutputStream(bOut); + byte[] derEncoding = obj.getEncoded(ASN1Encoding.DER); - ASN1InputStream contentIn = new ASN1InputStream(content.getOctets()); - ASN1Primitive obj = contentIn.readObject(); - - dOut.writeObject(obj); - - info = new ContentInfo(info.getContentType(), new DEROctetString(bOut.toByteArray())); + info = new ContentInfo(info.getContentType(), new DEROctetString(derEncoding)); MacData mData = pfx.getMacData(); try @@ -93,14 +79,10 @@ public class PKCS12Util { throw new IOException("error constructing MAC: " + e.toString()); } - + pfx = new Pfx(info, mData); - bOut.reset(); - - dOut.writeObject(pfx); - - return bOut.toByteArray(); + return pfx.getEncoded(ASN1Encoding.DER); } private static byte[] calculatePbeMac( diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/interfaces/MQVPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/interfaces/MQVPrivateKey.java index b4eb8ac8e..6d0895fe9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/interfaces/MQVPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/interfaces/MQVPrivateKey.java @@ -6,6 +6,7 @@ import java.security.PublicKey; /** * Static/ephemeral private key (pair) for use with ECMQV key agreement * (Optionally provides the ephemeral public key) + * @deprecated use MQVParameterSpec for passing the ephemeral key. */ public interface MQVPrivateKey extends PrivateKey diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/interfaces/MQVPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/interfaces/MQVPublicKey.java index 05fd64ff8..bf03e1bab 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/interfaces/MQVPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/interfaces/MQVPublicKey.java @@ -4,6 +4,7 @@ import java.security.PublicKey; /** * Static/ephemeral public key pair for use with ECMQV key agreement + * @deprecated use MQVParameterSpec for passing the ephemeral key. */ public interface MQVPublicKey extends PublicKey diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/BouncyCastleProvider.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/BouncyCastleProvider.java index e3c2b07d6..085ad1c80 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/BouncyCastleProvider.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/BouncyCastleProvider.java @@ -22,6 +22,7 @@ import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import com.fr.third.org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceCCA2KeyFactorySpi; import com.fr.third.org.bouncycastle.pqc.jcajce.provider.mceliece.McElieceKeyFactorySpi; import com.fr.third.org.bouncycastle.pqc.jcajce.provider.newhope.NHKeyFactorySpi; +import com.fr.third.org.bouncycastle.pqc.jcajce.provider.qtesla.QTESLAKeyFactorySpi; import com.fr.third.org.bouncycastle.pqc.jcajce.provider.rainbow.RainbowKeyFactorySpi; import com.fr.third.org.bouncycastle.pqc.jcajce.provider.sphincs.Sphincs256KeyFactorySpi; import com.fr.third.org.bouncycastle.pqc.jcajce.provider.xmss.XMSSKeyFactorySpi; @@ -54,7 +55,7 @@ import com.fr.third.org.bouncycastle.pqc.jcajce.provider.xmss.XMSSMTKeyFactorySp public final class BouncyCastleProvider extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Security Provider v1.60"; + private static String info = "BouncyCastle Security Provider v1.64"; public static final String PROVIDER_NAME = "BC"; @@ -82,7 +83,7 @@ public final class BouncyCastleProvider extends Provider "AES", "ARC4", "ARIA", "Blowfish", "Camellia", "CAST5", "CAST6", "ChaCha", "DES", "DESede", "GOST28147", "Grainv1", "Grain128", "HC128", "HC256", "IDEA", "Noekeon", "RC2", "RC5", "RC6", "Rijndael", "Salsa20", "SEED", "Serpent", "Shacal2", "Skipjack", "SM4", "TEA", "Twofish", "Threefish", - "VMPC", "VMPCKSA3", "XTEA", "XSalsa20", "OpenSSLPBKDF", "DSTU7624", "GOST3412_2015" + "VMPC", "VMPCKSA3", "XTEA", "XSalsa20", "OpenSSLPBKDF", "DSTU7624", "GOST3412_2015", "Zuc" }; /* @@ -99,7 +100,7 @@ public final class BouncyCastleProvider extends Provider private static final String[] ASYMMETRIC_CIPHERS = { - "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145", "GM" + "DSA", "DH", "EC", "RSA", "GOST", "ECGOST", "ElGamal", "DSTU4145", "GM", "EdEC" }; /* @@ -109,7 +110,8 @@ public final class BouncyCastleProvider extends Provider private static final String[] DIGESTS = { "GOST3411", "Keccak", "MD2", "MD4", "MD5", "SHA1", "RIPEMD128", "RIPEMD160", "RIPEMD256", "RIPEMD320", "SHA224", - "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b", "Blake2s", "DSTU7564" + "SHA256", "SHA384", "SHA512", "SHA3", "Skein", "SM3", "Tiger", "Whirlpool", "Blake2b", "Blake2s", "DSTU7564", + "Haraka" }; /* @@ -137,7 +139,7 @@ public final class BouncyCastleProvider extends Provider */ public BouncyCastleProvider() { - super(PROVIDER_NAME, 1.60, info); + super(PROVIDER_NAME, 1.64, info); AccessController.doPrivileged(new PrivilegedAction() { @@ -180,7 +182,7 @@ public final class BouncyCastleProvider extends Provider put("X509Store.CRL/LDAP", "com.fr.third.org.bouncycastle.jce.provider.X509StoreLDAPCRLs"); put("X509Store.ATTRIBUTECERTIFICATE/LDAP", "com.fr.third.org.bouncycastle.jce.provider.X509StoreLDAPAttrCerts"); put("X509Store.CERTIFICATEPAIR/LDAP", "com.fr.third.org.bouncycastle.jce.provider.X509StoreLDAPCertPairs"); - + // // X509StreamParser // @@ -242,6 +244,8 @@ public final class BouncyCastleProvider extends Provider addKeyInfoConverter(PQCObjectIdentifiers.mcEliece, new McElieceKeyFactorySpi()); addKeyInfoConverter(PQCObjectIdentifiers.mcElieceCca2, new McElieceCCA2KeyFactorySpi()); addKeyInfoConverter(PQCObjectIdentifiers.rainbow, new RainbowKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_p_I, new QTESLAKeyFactorySpi()); + addKeyInfoConverter(PQCObjectIdentifiers.qTESLA_p_III, new QTESLAKeyFactorySpi()); } public void setParameter(String parameterName, Object parameter) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java index a7fd9d03e..20a9a6161 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/BouncyCastleProviderConfiguration.java @@ -63,7 +63,7 @@ class BouncyCastleProviderConfiguration } else // assume java.security.spec { - curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false); + curveSpec = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter); } if (curveSpec == null) @@ -88,7 +88,7 @@ class BouncyCastleProviderConfiguration } else // assume java.security.spec { - ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter, false); + ecImplicitCaParams = EC5Util.convertSpec((java.security.spec.ECParameterSpec)parameter); } } else if (parameterName.equals(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS)) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java index 04e302127..11315e49c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/CertPathValidatorUtilities.java @@ -75,7 +75,6 @@ import com.fr.third.org.bouncycastle.util.Selector; import com.fr.third.org.bouncycastle.util.Store; import com.fr.third.org.bouncycastle.util.StoreException; import com.fr.third.org.bouncycastle.x509.X509AttributeCertificate; -import com.fr.third.org.bouncycastle.x509.extension.X509ExtensionUtil; class CertPathValidatorUtilities { @@ -163,16 +162,11 @@ class CertPathValidatorUtilities Exception invalidKeyEx = null; X509CertSelector certSelectX509 = new X509CertSelector(); - X500Name certIssuer = PrincipalUtils.getEncodedIssuerPrincipal(cert); - try - { - certSelectX509.setSubject(certIssuer.getEncoded()); - } - catch (IOException ex) - { - throw new AnnotatedException("Cannot set subject search criteria for trust anchor.", ex); - } + final X500Principal certIssuerPrincipal = cert.getIssuerX500Principal(); + certSelectX509.setSubject(certIssuerPrincipal); + + X500Name certIssuerName = null; Iterator iter = trustAnchors.iterator(); while (iter.hasNext() && trust == null) @@ -189,13 +183,20 @@ class CertPathValidatorUtilities trust = null; } } - else if (trust.getCAName() != null + else if (trust.getCA() != null + && trust.getCAName() != null && trust.getCAPublicKey() != null) { + if (certIssuerName == null) + { + certIssuerName = X500Name.getInstance(certIssuerPrincipal.getEncoded()); + } + try { - X500Name caName = PrincipalUtils.getCA(trust); - if (certIssuer.equals(caName)) + X500Name caName = X500Name.getInstance(trust.getCA().getEncoded()); + + if (certIssuerName.equals(caName)) { trustPublicKey = trust.getCAPublicKey(); } @@ -334,10 +335,9 @@ class CertPathValidatorUtilities try { ASN1InputStream aIn = new ASN1InputStream(ext); - ASN1OctetString octs = (ASN1OctetString)aIn.readObject(); + ASN1OctetString octs = ASN1OctetString.getInstance(aIn.readObject()); - aIn = new ASN1InputStream(octs.getOctets()); - return aIn.readObject(); + return ASN1Primitive.fromByteArray(octs.getOctets()); } catch (Exception e) { @@ -381,10 +381,9 @@ class CertPathValidatorUtilities } ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); + ASN1OutputStream aOut = ASN1OutputStream.create(bOut); Enumeration e = qualifiers.getObjects(); - while (e.hasMoreElements()) { try @@ -916,7 +915,7 @@ class CertPathValidatorUtilities } else { - certIssuer = X500Name.getInstance(certificateIssuer.getEncoded()); + certIssuer = PrincipalUtils.getX500Name(certificateIssuer); } if (! PrincipalUtils.getEncodedIssuerPrincipal(cert).equals(certIssuer)) @@ -941,6 +940,12 @@ class CertPathValidatorUtilities ASN1Enumerated reasonCode = null; if (crl_entry.hasExtensions()) { + if (crl_entry.hasUnsupportedCriticalExtension()) + { + throw new AnnotatedException( + "CRL entry has unsupported critical extensions."); + } + try { reasonCode = ASN1Enumerated @@ -956,26 +961,19 @@ class CertPathValidatorUtilities } } - // for reason keyCompromise, caCompromise, aACompromise or - // unspecified + int reasonCodeValue = (null == reasonCode) + ? CRLReason.unspecified + : reasonCode.intValueExact(); + + // for reason keyCompromise, caCompromise, aACompromise or unspecified if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime()) - || reasonCode == null - || reasonCode.getValue().intValue() == 0 - || reasonCode.getValue().intValue() == 1 - || reasonCode.getValue().intValue() == 2 - || reasonCode.getValue().intValue() == 8) + || reasonCodeValue == CRLReason.unspecified + || reasonCodeValue == CRLReason.keyCompromise + || reasonCodeValue == CRLReason.cACompromise + || reasonCodeValue == CRLReason.aACompromise) { - - // (i) or (j) (1) - if (reasonCode != null) - { - certStatus.setCertStatus(reasonCode.getValue().intValue()); - } - // (i) or (j) (2) - else - { - certStatus.setCertStatus(CRLReason.unspecified); - } + // (i) or (j) + certStatus.setCertStatus(reasonCodeValue); certStatus.setRevocationDate(crl_entry.getRevocationDate()); } } @@ -1283,10 +1281,10 @@ class CertPathValidatorUtilities { selector.setSubject(PrincipalUtils.getIssuerPrincipal(cert).getEncoded()); } - catch (IOException e) + catch (Exception e) { throw new AnnotatedException( - "Subject criteria for certificate selector to find issuer certificate could not be set.", e); + "Subject criteria for certificate selector to find issuer certificate could not be set.", e); } try diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEDHPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEDHPrivateKey.java index 34e914fce..b7c439cd0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEDHPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEDHPrivateKey.java @@ -59,9 +59,9 @@ public class JCEDHPrivateKey PrivateKeyInfo info) throws IOException { - ASN1Sequence seq = ASN1Sequence.getInstance(info.getAlgorithmId().getParameters()); + ASN1Sequence seq = ASN1Sequence.getInstance(info.getPrivateKeyAlgorithm().getParameters()); ASN1Integer derX = ASN1Integer.getInstance(info.parsePrivateKey()); - ASN1ObjectIdentifier id = info.getAlgorithmId().getAlgorithm(); + ASN1ObjectIdentifier id = info.getPrivateKeyAlgorithm().getAlgorithm(); this.info = info; this.x = derX.getValue(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEECPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEECPrivateKey.java index 69f0d7558..742638552 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEECPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEECPrivateKey.java @@ -27,6 +27,7 @@ import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECPoint; import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; import com.fr.third.org.bouncycastle.crypto.params.ECPrivateKeyParameters; @@ -188,7 +189,7 @@ public class JCEECPrivateKey private void populateFromPrivKeyInfo(PrivateKeyInfo info) throws IOException { - X962Parameters params = new X962Parameters((ASN1Primitive)info.getPrivateKeyAlgorithm().getParameters()); + X962Parameters params = X962Parameters.getInstance(info.getPrivateKeyAlgorithm().getParameters()); if (params.isNamedCurve()) { @@ -295,7 +296,7 @@ public class JCEECPrivateKey X9ECParameters ecP = new X9ECParameters( curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); @@ -347,14 +348,14 @@ public class JCEECPrivateKey return null; } - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec engineGetSpec() { if (ecSpec != null) { - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEECPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEECPublicKey.java index f05cd5c24..66cfe165a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEECPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/JCEECPublicKey.java @@ -14,7 +14,6 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; -import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.DERBitString; import com.fr.third.org.bouncycastle.asn1.DERNull; import com.fr.third.org.bouncycastle.asn1.DEROctetString; @@ -38,8 +37,6 @@ import com.fr.third.org.bouncycastle.jce.interfaces.ECPointEncoder; import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveSpec; import com.fr.third.org.bouncycastle.math.ec.ECCurve; -import com.fr.third.org.bouncycastle.math.ec.custom.sec.SecP256K1Point; -import com.fr.third.org.bouncycastle.math.ec.custom.sec.SecP256R1Point; import com.fr.third.org.bouncycastle.util.Strings; public class JCEECPublicKey @@ -68,7 +65,7 @@ public class JCEECPublicKey { this.algorithm = algorithm; this.ecSpec = spec.getParams(); - this.q = EC5Util.convertPoint(ecSpec, spec.getW(), false); + this.q = EC5Util.convertPoint(ecSpec, spec.getW()); } public JCEECPublicKey( @@ -91,7 +88,7 @@ public class JCEECPublicKey { com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec s = BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); - q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger(), false); + q = s.getCurve().createPoint(q.getAffineXCoord().toBigInteger(), q.getAffineYCoord().toBigInteger()); } this.ecSpec = null; } @@ -169,7 +166,7 @@ public class JCEECPublicKey { this.algorithm = key.getAlgorithm(); this.ecSpec = key.getParams(); - this.q = EC5Util.convertPoint(this.ecSpec, key.getW(), false); + this.q = EC5Util.convertPoint(this.ecSpec, key.getW()); } JCEECPublicKey( @@ -180,7 +177,9 @@ public class JCEECPublicKey private void populateFromPubKeyInfo(SubjectPublicKeyInfo info) { - if (info.getAlgorithmId().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3410_2001)) + AlgorithmIdentifier algID = info.getAlgorithm(); + + if (algID.getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3410_2001)) { DERBitString bits = info.getPublicKeyData(); ASN1OctetString key; @@ -205,7 +204,7 @@ public class JCEECPublicKey x9Encoding[i + 32] = keyEnc[64 - i]; } - gostParams = new GOST3410PublicKeyAlgParameters((ASN1Sequence)info.getAlgorithmId().getParameters()); + gostParams = GOST3410PublicKeyAlgParameters.getInstance(algID.getParameters()); ECNamedCurveParameterSpec spec = ECGOST3410NamedCurveTable.getParameterSpec(ECGOST3410NamedCurves.getName(gostParams.getPublicKeyParamSet())); @@ -223,7 +222,7 @@ public class JCEECPublicKey } else { - X962Parameters params = new X962Parameters((ASN1Primitive)info.getAlgorithmId().getParameters()); + X962Parameters params = X962Parameters.getInstance(algID.getParameters()); ECCurve curve; EllipticCurve ellipticCurve; @@ -326,7 +325,7 @@ public class JCEECPublicKey X9ECParameters ecP = new X9ECParameters( curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); @@ -335,10 +334,10 @@ public class JCEECPublicKey } } - BigInteger bX = this.q.getAffineXCoord().toBigInteger(); - BigInteger bY = this.q.getAffineYCoord().toBigInteger(); - byte[] encKey = new byte[64]; + BigInteger bX = this.q.getAffineXCoord().toBigInteger(); + BigInteger bY = this.q.getAffineYCoord().toBigInteger(); + byte[] encKey = new byte[64]; extractBytes(encKey, 0, bX); extractBytes(encKey, 32, bY); @@ -372,7 +371,7 @@ public class JCEECPublicKey X9ECParameters ecP = new X9ECParameters( curve, - EC5Util.convertPoint(curve, ecSpec.getGenerator(), withCompression), + new X9ECPoint(EC5Util.convertPoint(curve, ecSpec.getGenerator()), withCompression), ecSpec.getOrder(), BigInteger.valueOf(ecSpec.getCofactor()), ecSpec.getCurve().getSeed()); @@ -380,11 +379,9 @@ public class JCEECPublicKey params = new X962Parameters(ecP); } - ECCurve curve = this.engineGetQ().getCurve(); - ASN1OctetString p = (ASN1OctetString) - new X9ECPoint(curve.createPoint(this.getQ().getAffineXCoord().toBigInteger(), this.getQ().getAffineYCoord().toBigInteger(), withCompression)).toASN1Primitive(); + byte[] pubKeyOctets = this.getQ().getEncoded(withCompression); - info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), p.getOctets()); + info = new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_ecPublicKey, params), pubKeyOctets); } return KeyUtil.getEncodedSubjectPublicKeyInfo(info); @@ -418,7 +415,7 @@ public class JCEECPublicKey return null; } - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } public ECPoint getW() @@ -445,7 +442,7 @@ public class JCEECPublicKey { if (ecSpec != null) { - return EC5Util.convertSpec(ecSpec, withCompression); + return EC5Util.convertSpec(ecSpec); } return BouncyCastleProvider.CONFIGURATION.getEcImplicitlyCa(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java index 6977aef03..a2615190c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXCertPathBuilderSpi.java @@ -35,6 +35,18 @@ import com.fr.third.org.bouncycastle.x509.ExtendedPKIXParameters; public class PKIXCertPathBuilderSpi extends CertPathBuilderSpi { + private final boolean isForCRLCheck; + + public PKIXCertPathBuilderSpi() + { + this(false); + } + + PKIXCertPathBuilderSpi(boolean isForCRLCheck) + { + this.isForCRLCheck = isForCRLCheck; + } + /** * Build and validate a CertPath using the given parameter. * @@ -175,7 +187,7 @@ public class PKIXCertPathBuilderSpi try { cFact = new CertificateFactory(); - validator = new PKIXCertPathValidatorSpi(); + validator = new PKIXCertPathValidatorSpi(isForCRLCheck); } catch (Exception e) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java index 018179655..a2ff43806 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXCertPathValidatorSpi.java @@ -1,6 +1,5 @@ package com.fr.third.org.bouncycastle.jce.provider; -import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.PublicKey; import java.security.cert.CertPath; @@ -28,6 +27,7 @@ import com.fr.third.org.bouncycastle.asn1.x509.Extension; import com.fr.third.org.bouncycastle.asn1.x509.TBSCertificate; import com.fr.third.org.bouncycastle.jcajce.PKIXExtendedBuilderParameters; import com.fr.third.org.bouncycastle.jcajce.PKIXExtendedParameters; +import com.fr.third.org.bouncycastle.jcajce.interfaces.BCX509Certificate; import com.fr.third.org.bouncycastle.jcajce.util.BCJcaJceHelper; import com.fr.third.org.bouncycastle.jcajce.util.JcaJceHelper; import com.fr.third.org.bouncycastle.jce.exception.ExtCertPathValidatorException; @@ -41,9 +41,16 @@ public class PKIXCertPathValidatorSpi extends CertPathValidatorSpi { private final JcaJceHelper helper = new BCJcaJceHelper(); + private final boolean isForCRLCheck; public PKIXCertPathValidatorSpi() { + this(false); + } + + public PKIXCertPathValidatorSpi(boolean isForCRLCheck) + { + this.isForCRLCheck = isForCRLCheck; } public CertPathValidatorResult engineValidate( @@ -232,7 +239,7 @@ public class PKIXCertPathValidatorSpi workingPublicKey = trust.getCAPublicKey(); } } - catch (IllegalArgumentException ex) + catch (RuntimeException ex) { throw new ExtCertPathValidatorException("Subject of trust anchor could not be (re)encoded.", ex, certPath, -1); @@ -313,10 +320,10 @@ public class PKIXCertPathValidatorSpi RFC3280CertPathUtilities.processCertA(certPath, paramsPKIX, index, workingPublicKey, verificationAlreadyPerformed, workingIssuerName, sign, helper); - RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator); + RFC3280CertPathUtilities.processCertBC(certPath, index, nameConstraintValidator, isForCRLCheck); validPolicyTree = RFC3280CertPathUtilities.processCertD(certPath, index, acceptablePolicies, - validPolicyTree, policyNodes, inhibitAnyPolicy); + validPolicyTree, policyNodes, inhibitAnyPolicy, isForCRLCheck); validPolicyTree = RFC3280CertPathUtilities.processCertE(certPath, index, validPolicyTree); @@ -475,6 +482,24 @@ public class PKIXCertPathValidatorSpi static void checkCertificate(X509Certificate cert) throws AnnotatedException { + if (cert instanceof BCX509Certificate) + { + RuntimeException cause = null; + try + { + if (null != ((BCX509Certificate)cert).getTBSCertificateNative()) + { + return; + } + } + catch (RuntimeException e) + { + cause = e; + } + + throw new AnnotatedException("unable to process TBSCertificate", cause); + } + try { TBSCertificate.getInstance(cert.getTBSCertificate()); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java index 705166deb..c4d3427a5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXNameConstraintValidator.java @@ -1,1455 +1,58 @@ package com.fr.third.org.bouncycastle.jce.provider; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Set; - -import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; -import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; -import com.fr.third.org.bouncycastle.asn1.DERIA5String; -import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; -import com.fr.third.org.bouncycastle.asn1.x509.GeneralSubtree; -import com.fr.third.org.bouncycastle.util.Arrays; -import com.fr.third.org.bouncycastle.util.Integers; -import com.fr.third.org.bouncycastle.util.Strings; - -public class PKIXNameConstraintValidator -{ - private Set excludedSubtreesDN = new HashSet(); - - private Set excludedSubtreesDNS = new HashSet(); - - private Set excludedSubtreesEmail = new HashSet(); - - private Set excludedSubtreesURI = new HashSet(); - - private Set excludedSubtreesIP = new HashSet(); - - private Set permittedSubtreesDN; - - private Set permittedSubtreesDNS; - - private Set permittedSubtreesEmail; - - private Set permittedSubtreesURI; - - private Set permittedSubtreesIP; - - public PKIXNameConstraintValidator() - { - } - - private static boolean withinDNSubtree( - ASN1Sequence dns, - ASN1Sequence subtree) - { - if (subtree.size() < 1) - { - return false; - } - - if (subtree.size() > dns.size()) - { - return false; - } - - for (int j = subtree.size() - 1; j >= 0; j--) - { - if (!subtree.getObjectAt(j).equals(dns.getObjectAt(j))) - { - return false; - } - } - - return true; - } - - public void checkPermittedDN(ASN1Sequence dns) - throws PKIXNameConstraintValidatorException - { - checkPermittedDN(permittedSubtreesDN, dns); - } - - public void checkExcludedDN(ASN1Sequence dns) - throws PKIXNameConstraintValidatorException - { - checkExcludedDN(excludedSubtreesDN, dns); - } - - private void checkPermittedDN(Set permitted, ASN1Sequence dns) - throws PKIXNameConstraintValidatorException - { - if (permitted == null) - { - return; - } - - if (permitted.isEmpty() && dns.size() == 0) - { - return; - } - Iterator it = permitted.iterator(); - - while (it.hasNext()) - { - ASN1Sequence subtree = (ASN1Sequence)it.next(); - - if (withinDNSubtree(dns, subtree)) - { - return; - } - } - - throw new PKIXNameConstraintValidatorException( - "Subject distinguished name is not from a permitted subtree"); - } - - private void checkExcludedDN(Set excluded, ASN1Sequence dns) - throws PKIXNameConstraintValidatorException - { - if (excluded.isEmpty()) - { - return; - } - - Iterator it = excluded.iterator(); - - while (it.hasNext()) - { - ASN1Sequence subtree = (ASN1Sequence)it.next(); - - if (withinDNSubtree(dns, subtree)) - { - throw new PKIXNameConstraintValidatorException( - "Subject distinguished name is from an excluded subtree"); - } - } - } - - private Set intersectDN(Set permitted, Set dns) - { - Set intersect = new HashSet(); - for (Iterator it = dns.iterator(); it.hasNext();) - { - ASN1Sequence dn = ASN1Sequence.getInstance(((GeneralSubtree)it - .next()).getBase().getName().toASN1Primitive()); - if (permitted == null) - { - if (dn != null) - { - intersect.add(dn); - } - } - else - { - Iterator _iter = permitted.iterator(); - while (_iter.hasNext()) - { - ASN1Sequence subtree = (ASN1Sequence)_iter.next(); - - if (withinDNSubtree(dn, subtree)) - { - intersect.add(dn); - } - else if (withinDNSubtree(subtree, dn)) - { - intersect.add(subtree); - } - } - } - } - return intersect; - } - - private Set unionDN(Set excluded, ASN1Sequence dn) - { - if (excluded.isEmpty()) - { - if (dn == null) - { - return excluded; - } - excluded.add(dn); - - return excluded; - } - else - { - Set intersect = new HashSet(); - - Iterator it = excluded.iterator(); - while (it.hasNext()) - { - ASN1Sequence subtree = (ASN1Sequence)it.next(); - - if (withinDNSubtree(dn, subtree)) - { - intersect.add(subtree); - } - else if (withinDNSubtree(subtree, dn)) - { - intersect.add(dn); - } - else - { - intersect.add(subtree); - intersect.add(dn); - } - } - - return intersect; - } - } - - private Set intersectEmail(Set permitted, Set emails) - { - Set intersect = new HashSet(); - for (Iterator it = emails.iterator(); it.hasNext();) - { - String email = extractNameAsString(((GeneralSubtree)it.next()) - .getBase()); - - if (permitted == null) - { - if (email != null) - { - intersect.add(email); - } - } - else - { - Iterator it2 = permitted.iterator(); - while (it2.hasNext()) - { - String _permitted = (String)it2.next(); - - intersectEmail(email, _permitted, intersect); - } - } - } - return intersect; - } - - private Set unionEmail(Set excluded, String email) - { - if (excluded.isEmpty()) - { - if (email == null) - { - return excluded; - } - excluded.add(email); - return excluded; - } - else - { - Set union = new HashSet(); - - Iterator it = excluded.iterator(); - while (it.hasNext()) - { - String _excluded = (String)it.next(); - - unionEmail(_excluded, email, union); - } - - return union; - } - } - - /** - * Returns the intersection of the permitted IP ranges in - * permitted with ip. - * - * @param permitted A Set of permitted IP addresses with - * their subnet mask as byte arrays. - * @param ips The IP address with its subnet mask. - * @return The Set of permitted IP ranges intersected with - * ip. - */ - private Set intersectIP(Set permitted, Set ips) - { - Set intersect = new HashSet(); - for (Iterator it = ips.iterator(); it.hasNext();) - { - byte[] ip = ASN1OctetString.getInstance( - ((GeneralSubtree)it.next()).getBase().getName()).getOctets(); - if (permitted == null) - { - if (ip != null) - { - intersect.add(ip); - } - } - else - { - Iterator it2 = permitted.iterator(); - while (it2.hasNext()) - { - byte[] _permitted = (byte[])it2.next(); - intersect.addAll(intersectIPRange(_permitted, ip)); - } - } - } - return intersect; - } - - /** - * Returns the union of the excluded IP ranges in excluded - * with ip. - * - * @param excluded A Set of excluded IP addresses with their - * subnet mask as byte arrays. - * @param ip The IP address with its subnet mask. - * @return The Set of excluded IP ranges unified with - * ip as byte arrays. - */ - private Set unionIP(Set excluded, byte[] ip) - { - if (excluded.isEmpty()) - { - if (ip == null) - { - return excluded; - } - excluded.add(ip); - - return excluded; - } - else - { - Set union = new HashSet(); - - Iterator it = excluded.iterator(); - while (it.hasNext()) - { - byte[] _excluded = (byte[])it.next(); - union.addAll(unionIPRange(_excluded, ip)); - } - - return union; - } - } - - /** - * Calculates the union if two IP ranges. - * - * @param ipWithSubmask1 The first IP address with its subnet mask. - * @param ipWithSubmask2 The second IP address with its subnet mask. - * @return A Set with the union of both addresses. - */ - private Set unionIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2) - { - Set set = new HashSet(); - - // difficult, adding always all IPs is not wrong - if (Arrays.areEqual(ipWithSubmask1, ipWithSubmask2)) - { - set.add(ipWithSubmask1); - } - else - { - set.add(ipWithSubmask1); - set.add(ipWithSubmask2); - } - return set; - } - - /** - * Calculates the interesction if two IP ranges. - * - * @param ipWithSubmask1 The first IP address with its subnet mask. - * @param ipWithSubmask2 The second IP address with its subnet mask. - * @return A Set with the single IP address with its subnet - * mask as a byte array or an empty Set. - */ - private Set intersectIPRange(byte[] ipWithSubmask1, byte[] ipWithSubmask2) - { - if (ipWithSubmask1.length != ipWithSubmask2.length) - { - return Collections.EMPTY_SET; - } - byte[][] temp = extractIPsAndSubnetMasks(ipWithSubmask1, ipWithSubmask2); - byte ip1[] = temp[0]; - byte subnetmask1[] = temp[1]; - byte ip2[] = temp[2]; - byte subnetmask2[] = temp[3]; - - byte minMax[][] = minMaxIPs(ip1, subnetmask1, ip2, subnetmask2); - byte[] min; - byte[] max; - max = min(minMax[1], minMax[3]); - min = max(minMax[0], minMax[2]); - - // minimum IP address must be bigger than max - if (compareTo(min, max) == 1) - { - return Collections.EMPTY_SET; - } - // OR keeps all significant bits - byte[] ip = or(minMax[0], minMax[2]); - byte[] subnetmask = or(subnetmask1, subnetmask2); - return Collections.singleton(ipWithSubnetMask(ip, subnetmask)); - } - - /** - * Concatenates the IP address with its subnet mask. - * - * @param ip The IP address. - * @param subnetMask Its subnet mask. - * @return The concatenated IP address with its subnet mask. - */ - private byte[] ipWithSubnetMask(byte[] ip, byte[] subnetMask) - { - int ipLength = ip.length; - byte[] temp = new byte[ipLength * 2]; - System.arraycopy(ip, 0, temp, 0, ipLength); - System.arraycopy(subnetMask, 0, temp, ipLength, ipLength); - return temp; - } - - /** - * Splits the IP addresses and their subnet mask. - * - * @param ipWithSubmask1 The first IP address with the subnet mask. - * @param ipWithSubmask2 The second IP address with the subnet mask. - * @return An array with two elements. Each element contains the IP address - * and the subnet mask in this order. - */ - private byte[][] extractIPsAndSubnetMasks( - byte[] ipWithSubmask1, - byte[] ipWithSubmask2) - { - int ipLength = ipWithSubmask1.length / 2; - byte ip1[] = new byte[ipLength]; - byte subnetmask1[] = new byte[ipLength]; - System.arraycopy(ipWithSubmask1, 0, ip1, 0, ipLength); - System.arraycopy(ipWithSubmask1, ipLength, subnetmask1, 0, ipLength); - - byte ip2[] = new byte[ipLength]; - byte subnetmask2[] = new byte[ipLength]; - System.arraycopy(ipWithSubmask2, 0, ip2, 0, ipLength); - System.arraycopy(ipWithSubmask2, ipLength, subnetmask2, 0, ipLength); - return new byte[][] - {ip1, subnetmask1, ip2, subnetmask2}; - } - - /** - * Based on the two IP addresses and their subnet masks the IP range is - * computed for each IP address - subnet mask pair and returned as the - * minimum IP address and the maximum address of the range. - * - * @param ip1 The first IP address. - * @param subnetmask1 The subnet mask of the first IP address. - * @param ip2 The second IP address. - * @param subnetmask2 The subnet mask of the second IP address. - * @return A array with two elements. The first/second element contains the - * min and max IP address of the first/second IP address and its - * subnet mask. - */ - private byte[][] minMaxIPs( - byte[] ip1, - byte[] subnetmask1, - byte[] ip2, - byte[] subnetmask2) - { - int ipLength = ip1.length; - byte[] min1 = new byte[ipLength]; - byte[] max1 = new byte[ipLength]; - - byte[] min2 = new byte[ipLength]; - byte[] max2 = new byte[ipLength]; - - for (int i = 0; i < ipLength; i++) - { - min1[i] = (byte)(ip1[i] & subnetmask1[i]); - max1[i] = (byte)(ip1[i] & subnetmask1[i] | ~subnetmask1[i]); - - min2[i] = (byte)(ip2[i] & subnetmask2[i]); - max2[i] = (byte)(ip2[i] & subnetmask2[i] | ~subnetmask2[i]); - } - - return new byte[][]{min1, max1, min2, max2}; - } - - private void checkPermittedEmail(Set permitted, String email) - throws PKIXNameConstraintValidatorException - { - if (permitted == null) - { - return; - } - - Iterator it = permitted.iterator(); - - while (it.hasNext()) - { - String str = ((String)it.next()); - - if (emailIsConstrained(email, str)) - { - return; - } - } - - if (email.length() == 0 && permitted.size() == 0) - { - return; - } - - throw new PKIXNameConstraintValidatorException( - "Subject email address is not from a permitted subtree."); - } - - private void checkExcludedEmail(Set excluded, String email) - throws PKIXNameConstraintValidatorException - { - if (excluded.isEmpty()) - { - return; - } - - Iterator it = excluded.iterator(); - - while (it.hasNext()) - { - String str = (String)it.next(); - - if (emailIsConstrained(email, str)) - { - throw new PKIXNameConstraintValidatorException( - "Email address is from an excluded subtree."); - } - } - } - - /** - * Checks if the IP ip is included in the permitted set - * permitted. - * - * @param permitted A Set of permitted IP addresses with - * their subnet mask as byte arrays. - * @param ip The IP address. - * @throws PKIXNameConstraintValidatorException - * if the IP is not permitted. - */ - private void checkPermittedIP(Set permitted, byte[] ip) - throws PKIXNameConstraintValidatorException - { - if (permitted == null) - { - return; - } - - Iterator it = permitted.iterator(); - - while (it.hasNext()) - { - byte[] ipWithSubnet = (byte[])it.next(); - - if (isIPConstrained(ip, ipWithSubnet)) - { - return; - } - } - if (ip.length == 0 && permitted.size() == 0) - { - return; - } - throw new PKIXNameConstraintValidatorException( - "IP is not from a permitted subtree."); - } - - /** - * Checks if the IP ip is included in the excluded set - * excluded. - * - * @param excluded A Set of excluded IP addresses with their - * subnet mask as byte arrays. - * @param ip The IP address. - * @throws PKIXNameConstraintValidatorException - * if the IP is excluded. - */ - private void checkExcludedIP(Set excluded, byte[] ip) - throws PKIXNameConstraintValidatorException - { - if (excluded.isEmpty()) - { - return; - } - - Iterator it = excluded.iterator(); - - while (it.hasNext()) - { - byte[] ipWithSubnet = (byte[])it.next(); - - if (isIPConstrained(ip, ipWithSubnet)) - { - throw new PKIXNameConstraintValidatorException( - "IP is from an excluded subtree."); - } - } - } - - /** - * Checks if the IP address ip is constrained by - * constraint. - * - * @param ip The IP address. - * @param constraint The constraint. This is an IP address concatenated with - * its subnetmask. - * @return true if constrained, false - * otherwise. - */ - private boolean isIPConstrained(byte ip[], byte[] constraint) - { - int ipLength = ip.length; - - if (ipLength != (constraint.length / 2)) - { - return false; - } - - byte[] subnetMask = new byte[ipLength]; - System.arraycopy(constraint, ipLength, subnetMask, 0, ipLength); - - byte[] permittedSubnetAddress = new byte[ipLength]; - - byte[] ipSubnetAddress = new byte[ipLength]; - - // the resulting IP address by applying the subnet mask - for (int i = 0; i < ipLength; i++) - { - permittedSubnetAddress[i] = (byte)(constraint[i] & subnetMask[i]); - ipSubnetAddress[i] = (byte)(ip[i] & subnetMask[i]); - } - - return Arrays.areEqual(permittedSubnetAddress, ipSubnetAddress); - } - - private boolean emailIsConstrained(String email, String constraint) - { - String sub = email.substring(email.indexOf('@') + 1); - // a particular mailbox or @domain - if (constraint.indexOf('@') != -1) - { - if (email.equalsIgnoreCase(constraint)) - { - return true; - } - if (sub.equalsIgnoreCase(constraint.substring(1))) - { - return true; - } - } - // on particular host - else if (!(constraint.charAt(0) == '.')) - { - if (sub.equalsIgnoreCase(constraint)) - { - return true; - } - } - // address in sub domain - else if (withinDomain(sub, constraint)) - { - return true; - } - return false; - } - - private boolean withinDomain(String testDomain, String domain) - { - String tempDomain = domain; - if (tempDomain.startsWith(".")) - { - tempDomain = tempDomain.substring(1); - } - String[] domainParts = Strings.split(tempDomain, '.'); - String[] testDomainParts = Strings.split(testDomain, '.'); - // must have at least one subdomain - if (testDomainParts.length <= domainParts.length) - { - return false; - } - int d = testDomainParts.length - domainParts.length; - for (int i = -1; i < domainParts.length; i++) - { - if (i == -1) - { - if (testDomainParts[i + d].equals("")) - { - return false; - } - } - else if (!domainParts[i].equalsIgnoreCase(testDomainParts[i + d])) - { - return false; - } - } - return true; - } - - private void checkPermittedDNS(Set permitted, String dns) - throws PKIXNameConstraintValidatorException - { - if (permitted == null) - { - return; - } - - Iterator it = permitted.iterator(); - - while (it.hasNext()) - { - String str = ((String)it.next()); - - // is sub domain - if (withinDomain(dns, str) || dns.equalsIgnoreCase(str)) - { - return; - } - } - if (dns.length() == 0 && permitted.size() == 0) - { - return; - } - throw new PKIXNameConstraintValidatorException( - "DNS is not from a permitted subtree."); - } - - private void checkExcludedDNS(Set excluded, String dns) - throws PKIXNameConstraintValidatorException - { - if (excluded.isEmpty()) - { - return; - } - - Iterator it = excluded.iterator(); - - while (it.hasNext()) - { - String str = ((String)it.next()); - - // is sub domain or the same - if (withinDomain(dns, str) || dns.equalsIgnoreCase(str)) - { - throw new PKIXNameConstraintValidatorException( - "DNS is from an excluded subtree."); - } - } - } - - /** - * The common part of email1 and email2 is - * added to the union union. If email1 and - * email2 have nothing in common they are added both. - * - * @param email1 Email address constraint 1. - * @param email2 Email address constraint 2. - * @param union The union. - */ - private void unionEmail(String email1, String email2, Set union) - { - // email1 is a particular address - if (email1.indexOf('@') != -1) - { - String _sub = email1.substring(email1.indexOf('@') + 1); - // both are a particular mailbox - if (email2.indexOf('@') != -1) - { - if (email1.equalsIgnoreCase(email2)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(_sub, email2)) - { - union.add(email2); - } - else - { - union.add(email1); - union.add(email2); - } - } - // email2 specifies a particular host - else - { - if (_sub.equalsIgnoreCase(email2)) - { - union.add(email2); - } - else - { - union.add(email1); - union.add(email2); - } - } - } - // email1 specifies a domain - else if (email1.startsWith(".")) - { - if (email2.indexOf('@') != -1) - { - String _sub = email2.substring(email1.indexOf('@') + 1); - if (withinDomain(_sub, email1)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(email1, email2) - || email1.equalsIgnoreCase(email2)) - { - union.add(email2); - } - else if (withinDomain(email2, email1)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - else - { - if (withinDomain(email2, email1)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - } - // email specifies a host - else - { - if (email2.indexOf('@') != -1) - { - String _sub = email2.substring(email1.indexOf('@') + 1); - if (_sub.equalsIgnoreCase(email1)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(email1, email2)) - { - union.add(email2); - } - else - { - union.add(email1); - union.add(email2); - } - } - // email2 specifies a particular host - else - { - if (email1.equalsIgnoreCase(email2)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - } - } +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralSubtree; +import com.fr.third.org.bouncycastle.asn1.x509.NameConstraintValidatorException; - private void unionURI(String email1, String email2, Set union) - { - // email1 is a particular address - if (email1.indexOf('@') != -1) - { - String _sub = email1.substring(email1.indexOf('@') + 1); - // both are a particular mailbox - if (email2.indexOf('@') != -1) - { - if (email1.equalsIgnoreCase(email2)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(_sub, email2)) - { - union.add(email2); - } - else - { - union.add(email1); - union.add(email2); - } - } - // email2 specifies a particular host - else - { - if (_sub.equalsIgnoreCase(email2)) - { - union.add(email2); - } - else - { - union.add(email1); - union.add(email2); - } - } - } - // email1 specifies a domain - else if (email1.startsWith(".")) - { - if (email2.indexOf('@') != -1) - { - String _sub = email2.substring(email1.indexOf('@') + 1); - if (withinDomain(_sub, email1)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(email1, email2) - || email1.equalsIgnoreCase(email2)) - { - union.add(email2); - } - else if (withinDomain(email2, email1)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - else - { - if (withinDomain(email2, email1)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - } - // email specifies a host - else - { - if (email2.indexOf('@') != -1) - { - String _sub = email2.substring(email1.indexOf('@') + 1); - if (_sub.equalsIgnoreCase(email1)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(email1, email2)) - { - union.add(email2); - } - else - { - union.add(email1); - union.add(email2); - } - } - // email2 specifies a particular host - else - { - if (email1.equalsIgnoreCase(email2)) - { - union.add(email1); - } - else - { - union.add(email1); - union.add(email2); - } - } - } - } +public class PKIXNameConstraintValidator +{ + com.fr.third.org.bouncycastle.asn1.x509.PKIXNameConstraintValidator validator = new com.fr.third.org.bouncycastle.asn1.x509.PKIXNameConstraintValidator(); - private Set intersectDNS(Set permitted, Set dnss) + public PKIXNameConstraintValidator() { - Set intersect = new HashSet(); - for (Iterator it = dnss.iterator(); it.hasNext();) - { - String dns = extractNameAsString(((GeneralSubtree)it.next()) - .getBase()); - if (permitted == null) - { - if (dns != null) - { - intersect.add(dns); - } - } - else - { - Iterator _iter = permitted.iterator(); - while (_iter.hasNext()) - { - String _permitted = (String)_iter.next(); - - if (withinDomain(_permitted, dns)) - { - intersect.add(_permitted); - } - else if (withinDomain(dns, _permitted)) - { - intersect.add(dns); - } - } - } - } - - return intersect; } - protected Set unionDNS(Set excluded, String dns) + public int hashCode() { - if (excluded.isEmpty()) - { - if (dns == null) - { - return excluded; - } - excluded.add(dns); - - return excluded; - } - else - { - Set union = new HashSet(); - - Iterator _iter = excluded.iterator(); - while (_iter.hasNext()) - { - String _permitted = (String)_iter.next(); - - if (withinDomain(_permitted, dns)) - { - union.add(dns); - } - else if (withinDomain(dns, _permitted)) - { - union.add(_permitted); - } - else - { - union.add(_permitted); - union.add(dns); - } - } - - return union; - } + return validator.hashCode(); } - /** - * The most restricting part from email1 and - * email2 is added to the intersection intersect. - * - * @param email1 Email address constraint 1. - * @param email2 Email address constraint 2. - * @param intersect The intersection. - */ - private void intersectEmail(String email1, String email2, Set intersect) + public boolean equals(Object o) { - // email1 is a particular address - if (email1.indexOf('@') != -1) - { - String _sub = email1.substring(email1.indexOf('@') + 1); - // both are a particular mailbox - if (email2.indexOf('@') != -1) - { - if (email1.equalsIgnoreCase(email2)) - { - intersect.add(email1); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(_sub, email2)) - { - intersect.add(email1); - } - } - // email2 specifies a particular host - else - { - if (_sub.equalsIgnoreCase(email2)) - { - intersect.add(email1); - } - } - } - // email specifies a domain - else if (email1.startsWith(".")) - { - if (email2.indexOf('@') != -1) - { - String _sub = email2.substring(email1.indexOf('@') + 1); - if (withinDomain(_sub, email1)) - { - intersect.add(email2); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(email1, email2) - || email1.equalsIgnoreCase(email2)) - { - intersect.add(email1); - } - else if (withinDomain(email2, email1)) - { - intersect.add(email2); - } - } - else - { - if (withinDomain(email2, email1)) - { - intersect.add(email2); - } - } - } - // email1 specifies a host - else + if (!(o instanceof PKIXNameConstraintValidator)) { - if (email2.indexOf('@') != -1) - { - String _sub = email2.substring(email2.indexOf('@') + 1); - if (_sub.equalsIgnoreCase(email1)) - { - intersect.add(email2); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(email1, email2)) - { - intersect.add(email1); - } - } - // email2 specifies a particular host - else - { - if (email1.equalsIgnoreCase(email2)) - { - intersect.add(email1); - } - } + return false; } + PKIXNameConstraintValidator constraintValidator = (PKIXNameConstraintValidator)o; + return this.validator.equals(constraintValidator.validator); } - private void checkExcludedURI(Set excluded, String uri) + public void checkPermittedDN(ASN1Sequence dns) throws PKIXNameConstraintValidatorException { - if (excluded.isEmpty()) + try { - return; + this.validator.checkPermittedDN(X500Name.getInstance(dns)); } - - Iterator it = excluded.iterator(); - - while (it.hasNext()) - { - String str = ((String)it.next()); - - if (isUriConstrained(uri, str)) - { - throw new PKIXNameConstraintValidatorException( - "URI is from an excluded subtree."); - } - } - } - - private Set intersectURI(Set permitted, Set uris) - { - Set intersect = new HashSet(); - for (Iterator it = uris.iterator(); it.hasNext();) - { - String uri = extractNameAsString(((GeneralSubtree)it.next()) - .getBase()); - if (permitted == null) - { - if (uri != null) - { - intersect.add(uri); - } - } - else - { - Iterator _iter = permitted.iterator(); - while (_iter.hasNext()) - { - String _permitted = (String)_iter.next(); - intersectURI(_permitted, uri, intersect); - } - } - } - return intersect; - } - - private Set unionURI(Set excluded, String uri) - { - if (excluded.isEmpty()) - { - if (uri == null) - { - return excluded; - } - excluded.add(uri); - - return excluded; - } - else + catch (NameConstraintValidatorException e) { - Set union = new HashSet(); - - Iterator _iter = excluded.iterator(); - while (_iter.hasNext()) - { - String _excluded = (String)_iter.next(); - - unionURI(_excluded, uri, union); - } - - return union; - } - } - - private void intersectURI(String email1, String email2, Set intersect) - { - // email1 is a particular address - if (email1.indexOf('@') != -1) - { - String _sub = email1.substring(email1.indexOf('@') + 1); - // both are a particular mailbox - if (email2.indexOf('@') != -1) - { - if (email1.equalsIgnoreCase(email2)) - { - intersect.add(email1); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(_sub, email2)) - { - intersect.add(email1); - } - } - // email2 specifies a particular host - else - { - if (_sub.equalsIgnoreCase(email2)) - { - intersect.add(email1); - } - } - } - // email specifies a domain - else if (email1.startsWith(".")) - { - if (email2.indexOf('@') != -1) - { - String _sub = email2.substring(email1.indexOf('@') + 1); - if (withinDomain(_sub, email1)) - { - intersect.add(email2); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(email1, email2) - || email1.equalsIgnoreCase(email2)) - { - intersect.add(email1); - } - else if (withinDomain(email2, email1)) - { - intersect.add(email2); - } - } - else - { - if (withinDomain(email2, email1)) - { - intersect.add(email2); - } - } - } - // email1 specifies a host - else - { - if (email2.indexOf('@') != -1) - { - String _sub = email2.substring(email2.indexOf('@') + 1); - if (_sub.equalsIgnoreCase(email1)) - { - intersect.add(email2); - } - } - // email2 specifies a domain - else if (email2.startsWith(".")) - { - if (withinDomain(email1, email2)) - { - intersect.add(email1); - } - } - // email2 specifies a particular host - else - { - if (email1.equalsIgnoreCase(email2)) - { - intersect.add(email1); - } - } + throw new PKIXNameConstraintValidatorException(e.getMessage(), e); } } - private void checkPermittedURI(Set permitted, String uri) + public void checkExcludedDN(ASN1Sequence dns) throws PKIXNameConstraintValidatorException { - if (permitted == null) - { - return; - } - - Iterator it = permitted.iterator(); - - while (it.hasNext()) - { - String str = ((String)it.next()); - - if (isUriConstrained(uri, str)) - { - return; - } - } - if (uri.length() == 0 && permitted.size() == 0) - { - return; - } - throw new PKIXNameConstraintValidatorException( - "URI is not from a permitted subtree."); - } - - private boolean isUriConstrained(String uri, String constraint) - { - String host = extractHostFromURL(uri); - // a host - if (!constraint.startsWith(".")) - { - if (host.equalsIgnoreCase(constraint)) - { - return true; - } - } - - // in sub domain or domain - else if (withinDomain(host, constraint)) - { - return true; - } - - return false; - } - - private static String extractHostFromURL(String url) - { - // see RFC 1738 - // remove ':' after protocol, e.g. http: - String sub = url.substring(url.indexOf(':') + 1); - // extract host from Common Internet Scheme Syntax, e.g. http:// - if (sub.indexOf("//") != -1) - { - sub = sub.substring(sub.indexOf("//") + 2); - } - // first remove port, e.g. http://test.com:21 - if (sub.lastIndexOf(':') != -1) + try { - sub = sub.substring(0, sub.lastIndexOf(':')); + this.validator.checkExcludedDN(X500Name.getInstance(dns)); } - // remove user and password, e.g. http://john:password@test.com - sub = sub.substring(sub.indexOf(':') + 1); - sub = sub.substring(sub.indexOf('@') + 1); - // remove local parts, e.g. http://test.com/bla - if (sub.indexOf('/') != -1) + catch (NameConstraintValidatorException e) { - sub = sub.substring(0, sub.indexOf('/')); + throw new PKIXNameConstraintValidatorException(e.getMessage(), e); } - return sub; } /** @@ -1462,28 +65,13 @@ public class PKIXNameConstraintValidator public void checkPermitted(GeneralName name) throws PKIXNameConstraintValidatorException { - switch (name.getTagNo()) + try { - case 1: - checkPermittedEmail(permittedSubtreesEmail, - extractNameAsString(name)); - break; - case 2: - checkPermittedDNS(permittedSubtreesDNS, DERIA5String.getInstance( - name.getName()).getString()); - break; - case 4: - checkPermittedDN(ASN1Sequence.getInstance(name.getName() - .toASN1Primitive())); - break; - case 6: - checkPermittedURI(permittedSubtreesURI, DERIA5String.getInstance( - name.getName()).getString()); - break; - case 7: - byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets(); - - checkPermittedIP(permittedSubtreesIP, ip); + validator.checkPermitted(name); + } + catch (NameConstraintValidatorException e) + { + throw new PKIXNameConstraintValidatorException(e.getMessage(), e); } } @@ -1498,33 +86,19 @@ public class PKIXNameConstraintValidator public void checkExcluded(GeneralName name) throws PKIXNameConstraintValidatorException { - switch (name.getTagNo()) + try { - case 1: - checkExcludedEmail(excludedSubtreesEmail, extractNameAsString(name)); - break; - case 2: - checkExcludedDNS(excludedSubtreesDNS, DERIA5String.getInstance( - name.getName()).getString()); - break; - case 4: - checkExcludedDN(ASN1Sequence.getInstance(name.getName() - .toASN1Primitive())); - break; - case 6: - checkExcludedURI(excludedSubtreesURI, DERIA5String.getInstance( - name.getName()).getString()); - break; - case 7: - byte[] ip = ASN1OctetString.getInstance(name.getName()).getOctets(); - - checkExcludedIP(excludedSubtreesIP, ip); + validator.checkExcluded(name); + } + catch (NameConstraintValidatorException e) + { + throw new PKIXNameConstraintValidatorException(e.getMessage(), e); } } public void intersectPermittedSubtree(GeneralSubtree permitted) { - intersectPermittedSubtree(new GeneralSubtree[] { permitted }); + validator.intersectPermittedSubtree(permitted); } /** @@ -1536,396 +110,26 @@ public class PKIXNameConstraintValidator public void intersectPermittedSubtree(GeneralSubtree[] permitted) { - Map subtreesMap = new HashMap(); - - // group in sets in a map ordered by tag no. - for (int i = 0; i != permitted.length; i++) - { - GeneralSubtree subtree = permitted[i]; - Integer tagNo = Integers.valueOf(subtree.getBase().getTagNo()); - if (subtreesMap.get(tagNo) == null) - { - subtreesMap.put(tagNo, new HashSet()); - } - ((Set)subtreesMap.get(tagNo)).add(subtree); - } - - for (Iterator it = subtreesMap.entrySet().iterator(); it.hasNext();) - { - Map.Entry entry = (Map.Entry)it.next(); - - // go through all subtree groups - switch (((Integer)entry.getKey()).intValue()) - { - case 1: - permittedSubtreesEmail = intersectEmail(permittedSubtreesEmail, - (Set)entry.getValue()); - break; - case 2: - permittedSubtreesDNS = intersectDNS(permittedSubtreesDNS, - (Set)entry.getValue()); - break; - case 4: - permittedSubtreesDN = intersectDN(permittedSubtreesDN, - (Set)entry.getValue()); - break; - case 6: - permittedSubtreesURI = intersectURI(permittedSubtreesURI, - (Set)entry.getValue()); - break; - case 7: - permittedSubtreesIP = intersectIP(permittedSubtreesIP, - (Set)entry.getValue()); - } - } - } - - private String extractNameAsString(GeneralName name) - { - return DERIA5String.getInstance(name.getName()).getString(); + validator.intersectPermittedSubtree(permitted); } public void intersectEmptyPermittedSubtree(int nameType) { - switch (nameType) - { - case 1: - permittedSubtreesEmail = new HashSet(); - break; - case 2: - permittedSubtreesDNS = new HashSet(); - break; - case 4: - permittedSubtreesDN = new HashSet(); - break; - case 6: - permittedSubtreesURI = new HashSet(); - break; - case 7: - permittedSubtreesIP = new HashSet(); - } + validator.intersectEmptyPermittedSubtree(nameType); } - - /** + + /** * Adds a subtree to the excluded set of these name constraints. * * @param subtree A subtree with an excluded GeneralName. */ public void addExcludedSubtree(GeneralSubtree subtree) { - GeneralName base = subtree.getBase(); - - switch (base.getTagNo()) - { - case 1: - excludedSubtreesEmail = unionEmail(excludedSubtreesEmail, - extractNameAsString(base)); - break; - case 2: - excludedSubtreesDNS = unionDNS(excludedSubtreesDNS, - extractNameAsString(base)); - break; - case 4: - excludedSubtreesDN = unionDN(excludedSubtreesDN, - (ASN1Sequence)base.getName().toASN1Primitive()); - break; - case 6: - excludedSubtreesURI = unionURI(excludedSubtreesURI, - extractNameAsString(base)); - break; - case 7: - excludedSubtreesIP = unionIP(excludedSubtreesIP, ASN1OctetString - .getInstance(base.getName()).getOctets()); - break; - } - } - - /** - * Returns the maximum IP address. - * - * @param ip1 The first IP address. - * @param ip2 The second IP address. - * @return The maximum IP address. - */ - private static byte[] max(byte[] ip1, byte[] ip2) - { - for (int i = 0; i < ip1.length; i++) - { - if ((ip1[i] & 0xFFFF) > (ip2[i] & 0xFFFF)) - { - return ip1; - } - } - return ip2; - } - - /** - * Returns the minimum IP address. - * - * @param ip1 The first IP address. - * @param ip2 The second IP address. - * @return The minimum IP address. - */ - private static byte[] min(byte[] ip1, byte[] ip2) - { - for (int i = 0; i < ip1.length; i++) - { - if ((ip1[i] & 0xFFFF) < (ip2[i] & 0xFFFF)) - { - return ip1; - } - } - return ip2; - } - - /** - * Compares IP address ip1 with ip2. If ip1 - * is equal to ip2 0 is returned. If ip1 is bigger 1 is returned, -1 - * otherwise. - * - * @param ip1 The first IP address. - * @param ip2 The second IP address. - * @return 0 if ip1 is equal to ip2, 1 if ip1 is bigger, -1 otherwise. - */ - private static int compareTo(byte[] ip1, byte[] ip2) - { - if (Arrays.areEqual(ip1, ip2)) - { - return 0; - } - if (Arrays.areEqual(max(ip1, ip2), ip1)) - { - return 1; - } - return -1; - } - - /** - * Returns the logical OR of the IP addresses ip1 and - * ip2. - * - * @param ip1 The first IP address. - * @param ip2 The second IP address. - * @return The OR of ip1 and ip2. - */ - private static byte[] or(byte[] ip1, byte[] ip2) - { - byte[] temp = new byte[ip1.length]; - for (int i = 0; i < ip1.length; i++) - { - temp[i] = (byte)(ip1[i] | ip2[i]); - } - return temp; - } - - public int hashCode() - { - return hashCollection(excludedSubtreesDN) - + hashCollection(excludedSubtreesDNS) - + hashCollection(excludedSubtreesEmail) - + hashCollection(excludedSubtreesIP) - + hashCollection(excludedSubtreesURI) - + hashCollection(permittedSubtreesDN) - + hashCollection(permittedSubtreesDNS) - + hashCollection(permittedSubtreesEmail) - + hashCollection(permittedSubtreesIP) - + hashCollection(permittedSubtreesURI); - } - - private int hashCollection(Collection coll) - { - if (coll == null) - { - return 0; - } - int hash = 0; - Iterator it1 = coll.iterator(); - while (it1.hasNext()) - { - Object o = it1.next(); - if (o instanceof byte[]) - { - hash += Arrays.hashCode((byte[])o); - } - else - { - hash += o.hashCode(); - } - } - return hash; - } - - public boolean equals(Object o) - { - if (!(o instanceof PKIXNameConstraintValidator)) - { - return false; - } - PKIXNameConstraintValidator constraintValidator = (PKIXNameConstraintValidator)o; - return collectionsAreEqual(constraintValidator.excludedSubtreesDN, excludedSubtreesDN) - && collectionsAreEqual(constraintValidator.excludedSubtreesDNS, excludedSubtreesDNS) - && collectionsAreEqual(constraintValidator.excludedSubtreesEmail, excludedSubtreesEmail) - && collectionsAreEqual(constraintValidator.excludedSubtreesIP, excludedSubtreesIP) - && collectionsAreEqual(constraintValidator.excludedSubtreesURI, excludedSubtreesURI) - && collectionsAreEqual(constraintValidator.permittedSubtreesDN, permittedSubtreesDN) - && collectionsAreEqual(constraintValidator.permittedSubtreesDNS, permittedSubtreesDNS) - && collectionsAreEqual(constraintValidator.permittedSubtreesEmail, permittedSubtreesEmail) - && collectionsAreEqual(constraintValidator.permittedSubtreesIP, permittedSubtreesIP) - && collectionsAreEqual(constraintValidator.permittedSubtreesURI, permittedSubtreesURI); - } - - private boolean collectionsAreEqual(Collection coll1, Collection coll2) - { - if (coll1 == coll2) - { - return true; - } - if (coll1 == null || coll2 == null) - { - return false; - } - if (coll1.size() != coll2.size()) - { - return false; - } - Iterator it1 = coll1.iterator(); - - while (it1.hasNext()) - { - Object a = it1.next(); - Iterator it2 = coll2.iterator(); - boolean found = false; - while (it2.hasNext()) - { - Object b = it2.next(); - if (equals(a, b)) - { - found = true; - break; - } - } - if (!found) - { - return false; - } - } - return true; - } - - private boolean equals(Object o1, Object o2) - { - if (o1 == o2) - { - return true; - } - if (o1 == null || o2 == null) - { - return false; - } - if (o1 instanceof byte[] && o2 instanceof byte[]) - { - return Arrays.areEqual((byte[])o1, (byte[])o2); - } - else - { - return o1.equals(o2); - } - } - - /** - * Stringifies an IPv4 or v6 address with subnet mask. - * - * @param ip The IP with subnet mask. - * @return The stringified IP address. - */ - private String stringifyIP(byte[] ip) - { - String temp = ""; - for (int i = 0; i < ip.length / 2; i++) - { - temp += Integer.toString(ip[i] & 0x00FF) + "."; - } - temp = temp.substring(0, temp.length() - 1); - temp += "/"; - for (int i = ip.length / 2; i < ip.length; i++) - { - temp += Integer.toString(ip[i] & 0x00FF) + "."; - } - temp = temp.substring(0, temp.length() - 1); - return temp; - } - - private String stringifyIPCollection(Set ips) - { - String temp = ""; - temp += "["; - for (Iterator it = ips.iterator(); it.hasNext();) - { - temp += stringifyIP((byte[])it.next()) + ","; - } - if (temp.length() > 1) - { - temp = temp.substring(0, temp.length() - 1); - } - temp += "]"; - return temp; + validator.addExcludedSubtree(subtree); } public String toString() { - String temp = ""; - temp += "permitted:\n"; - if (permittedSubtreesDN != null) - { - temp += "DN:\n"; - temp += permittedSubtreesDN.toString() + "\n"; - } - if (permittedSubtreesDNS != null) - { - temp += "DNS:\n"; - temp += permittedSubtreesDNS.toString() + "\n"; - } - if (permittedSubtreesEmail != null) - { - temp += "Email:\n"; - temp += permittedSubtreesEmail.toString() + "\n"; - } - if (permittedSubtreesURI != null) - { - temp += "URI:\n"; - temp += permittedSubtreesURI.toString() + "\n"; - } - if (permittedSubtreesIP != null) - { - temp += "IP:\n"; - temp += stringifyIPCollection(permittedSubtreesIP) + "\n"; - } - temp += "excluded:\n"; - if (!excludedSubtreesDN.isEmpty()) - { - temp += "DN:\n"; - temp += excludedSubtreesDN.toString() + "\n"; - } - if (!excludedSubtreesDNS.isEmpty()) - { - temp += "DNS:\n"; - temp += excludedSubtreesDNS.toString() + "\n"; - } - if (!excludedSubtreesEmail.isEmpty()) - { - temp += "Email:\n"; - temp += excludedSubtreesEmail.toString() + "\n"; - } - if (!excludedSubtreesURI.isEmpty()) - { - temp += "URI:\n"; - temp += excludedSubtreesURI.toString() + "\n"; - } - if (!excludedSubtreesIP.isEmpty()) - { - temp += "IP:\n"; - temp += stringifyIPCollection(excludedSubtreesIP) + "\n"; - } - return temp; + return validator.toString(); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java index d2f849b6a..8555361f6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PKIXNameConstraintValidatorException.java @@ -3,8 +3,22 @@ package com.fr.third.org.bouncycastle.jce.provider; public class PKIXNameConstraintValidatorException extends Exception { + private Throwable cause; + public PKIXNameConstraintValidatorException(String msg) { super(msg); } + + public PKIXNameConstraintValidatorException(String msg, Throwable e) + { + super(msg); + + this.cause = e; + } + + public Throwable getCause() + { + return cause; + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PrincipalUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PrincipalUtils.java index ba5cb5f3d..51a5fe93b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PrincipalUtils.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/PrincipalUtils.java @@ -2,34 +2,20 @@ package com.fr.third.org.bouncycastle.jce.provider; import java.security.cert.TrustAnchor; import java.security.cert.X509CRL; -import java.security.cert.X509CRLEntry; import java.security.cert.X509Certificate; import javax.security.auth.x500.X500Principal; import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.X500NameStyle; +import com.fr.third.org.bouncycastle.jcajce.interfaces.BCX509Certificate; import com.fr.third.org.bouncycastle.x509.X509AttributeCertificate; class PrincipalUtils { - static X500Name getSubjectPrincipal(X509Certificate cert) - { - return X500Name.getInstance(cert.getSubjectX500Principal().getEncoded()); - } - - static X500Name getIssuerPrincipal(X509CRL crl) - { - return X500Name.getInstance(crl.getIssuerX500Principal().getEncoded()); - } - - static X500Name getIssuerPrincipal(X509Certificate cert) - { - return X500Name.getInstance(cert.getIssuerX500Principal().getEncoded()); - } - static X500Name getCA(TrustAnchor trustAnchor) { - return X500Name.getInstance(trustAnchor.getCA().getEncoded()); + return getX500Name(notNull(trustAnchor).getCA()); } /** @@ -38,8 +24,7 @@ class PrincipalUtils * @param cert The attribute certificate or certificate. * @return The issuer as X500Principal. */ - static X500Name getEncodedIssuerPrincipal( - Object cert) + static X500Name getEncodedIssuerPrincipal(Object cert) { if (cert instanceof X509Certificate) { @@ -47,7 +32,102 @@ class PrincipalUtils } else { - return X500Name.getInstance(((X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0]).getEncoded()); + return getX500Name((X500Principal)((X509AttributeCertificate)cert).getIssuer().getPrincipals()[0]); + } + } + + static X500Name getIssuerPrincipal(X509Certificate certificate) + { + if (certificate instanceof BCX509Certificate) + { + return notNull(((BCX509Certificate)certificate).getIssuerX500Name()); + } + return getX500Name(notNull(certificate).getIssuerX500Principal()); + } + + static X500Name getIssuerPrincipal(X509CRL crl) + { + return getX500Name(notNull(crl).getIssuerX500Principal()); + } + + static X500Name getSubjectPrincipal(X509Certificate certificate) + { + if (certificate instanceof BCX509Certificate) + { + return notNull(((BCX509Certificate)certificate).getSubjectX500Name()); + } + return getX500Name(notNull(certificate).getSubjectX500Principal()); + } + + static X500Name getX500Name(X500Principal principal) + { + X500Name name = X500Name.getInstance(getEncoded(principal)); + return notNull(name); + } + + static X500Name getX500Name(X500NameStyle style, X500Principal principal) + { + X500Name name = X500Name.getInstance(style, getEncoded(principal)); + return notNull(name); + } + + private static byte[] getEncoded(X500Principal principal) + { + byte[] encoding = notNull(principal).getEncoded(); + return notNull(encoding); + } + + private static byte[] notNull(byte[] encoding) + { + if (null == encoding) + { + throw new IllegalStateException(); + } + return encoding; + } + + private static TrustAnchor notNull(TrustAnchor trustAnchor) + { + if (null == trustAnchor) + { + throw new IllegalStateException(); + } + return trustAnchor; + } + + private static X509Certificate notNull(X509Certificate certificate) + { + if (null == certificate) + { + throw new IllegalStateException(); + } + return certificate; + } + + private static X509CRL notNull(X509CRL crl) + { + if (null == crl) + { + throw new IllegalStateException(); + } + return crl; + } + + private static X500Name notNull(X500Name name) + { + if (null == name) + { + throw new IllegalStateException(); + } + return name; + } + + private static X500Principal notNull(X500Principal principal) + { + if (null == principal) + { + throw new IllegalStateException(); } + return principal; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java index d376451df..bf2033b0c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/RFC3280CertPathUtilities.java @@ -30,7 +30,6 @@ import java.util.TimeZone; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; -import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; @@ -504,7 +503,7 @@ class RFC3280CertPathUtilities } try { - PKIXCertPathBuilderSpi builder = new PKIXCertPathBuilderSpi(); + PKIXCertPathBuilderSpi builder = new PKIXCertPathBuilderSpi(true); X509CertSelector tmpCertSelector = new X509CertSelector(); tmpCertSelector.setCertificate(signingCert); @@ -707,7 +706,7 @@ class RFC3280CertPathUtilities { crlselect.addIssuerName(PrincipalUtils.getIssuerPrincipal(crl).getEncoded()); } - catch (IOException e) + catch (Exception e) { throw new AnnotatedException("Cannot extract issuer from CRL." + e, e); } @@ -761,6 +760,12 @@ class RFC3280CertPathUtilities { return; } + + if (deltaCRL.hasUnsupportedCriticalExtension()) + { + throw new AnnotatedException("delta CRL has unsupported critical extensions"); + } + IssuingDistributionPoint completeidp = null; try { @@ -1123,7 +1128,7 @@ class RFC3280CertPathUtilities if (RFC3280CertPathUtilities.ANY_POLICY.equals(subjectDomainPolicy.getId())) { - throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy,", null, certPath, index); + throw new CertPathValidatorException("SubjectDomainPolicy is anyPolicy", null, certPath, index); } } } @@ -1178,7 +1183,8 @@ class RFC3280CertPathUtilities protected static void processCertBC( CertPath certPath, int index, - PKIXNameConstraintValidator nameConstraintValidator) + PKIXNameConstraintValidator nameConstraintValidator, + boolean isForCRLCheck) throws CertPathValidatorException { List certs = certPath.getCertificates(); @@ -1189,7 +1195,12 @@ class RFC3280CertPathUtilities // // (b), (c) permitted and excluded subtree checking. // - if (!(CertPathValidatorUtilities.isSelfIssued(cert) && (i < n))) + // 4.2.1.10 Name constraints are not applied to self-issued certificates (unless + // the certificate is the final certificate in the path) + // as we use the validator for path CRL checking, we need to flag when the + // certificate is self issued, but not really the last one in the path we are actually + // checking. + if (!(CertPathValidatorUtilities.isSelfIssued(cert) && ((i < n) || isForCRLCheck))) { X500Name principal = PrincipalUtils.getSubjectPrincipal(cert); ASN1Sequence dns; @@ -1279,7 +1290,8 @@ class RFC3280CertPathUtilities Set acceptablePolicies, PKIXPolicyNode validPolicyTree, List[] policyNodes, - int inhibitAnyPolicy) + int inhibitAnyPolicy, + boolean isForCRLCheck) throws CertPathValidatorException { List certs = certPath.getCertificates(); @@ -1365,7 +1377,7 @@ class RFC3280CertPathUtilities // // (d) (2) // - if ((inhibitAnyPolicy > 0) || ((i < n) && CertPathValidatorUtilities.isSelfIssued(cert))) + if ((inhibitAnyPolicy > 0) || ((i < n || isForCRLCheck) && CertPathValidatorUtilities.isSelfIssued(cert))) { e = certPolicies.getObjects(); @@ -1591,11 +1603,10 @@ class RFC3280CertPathUtilities { try { - ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement()); if (constraint.getTagNo() == 0) { - tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); + tmpInt = ASN1Integer.getInstance(constraint, false).intValueExact(); if (tmpInt < explicitPolicy) { return tmpInt; @@ -1649,7 +1660,7 @@ class RFC3280CertPathUtilities ASN1TaggedObject constraint = ASN1TaggedObject.getInstance(policyConstraints.nextElement()); if (constraint.getTagNo() == 1) { - tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); + tmpInt = ASN1Integer.getInstance(constraint, false).intValueExact(); if (tmpInt < policyMapping) { return tmpInt; @@ -1852,7 +1863,7 @@ class RFC3280CertPathUtilities throw new AnnotatedException("No valid CRL for current time found."); } } - + RFC3280CertPathUtilities.processCRLB1(dp, cert, crl); // (b) (2) @@ -2015,13 +2026,12 @@ class RFC3280CertPathUtilities * omitted and a distribution point name of the certificate * issuer. */ - ASN1Primitive issuer = null; + X500Name issuer; try { - issuer = new ASN1InputStream(PrincipalUtils.getEncodedIssuerPrincipal(cert).getEncoded()) - .readObject(); + issuer = PrincipalUtils.getEncodedIssuerPrincipal(cert); } - catch (Exception e) + catch (RuntimeException e) { throw new AnnotatedException("Issuer from certificate for CRL could not be reencoded.", e); } @@ -2090,7 +2100,7 @@ class RFC3280CertPathUtilities if (iap != null) { - int _inhibitAnyPolicy = iap.getValue().intValue(); + int _inhibitAnyPolicy = iap.intValueExact(); if (_inhibitAnyPolicy < inhibitAnyPolicy) { @@ -2125,12 +2135,12 @@ class RFC3280CertPathUtilities { if (!(bc.isCA())) { - throw new CertPathValidatorException("Not a CA certificate"); + throw new CertPathValidatorException("Not a CA certificate", null, certPath, index); } } else { - throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints"); + throw new CertPathValidatorException("Intermediate certificate lacks BasicConstraints", null, certPath, index); } } @@ -2382,7 +2392,7 @@ class RFC3280CertPathUtilities case 0: try { - tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); + tmpInt = ASN1Integer.getInstance(constraint, false).intValueExact(); } catch (Exception e) { @@ -2422,6 +2432,10 @@ class RFC3280CertPathUtilities { throw new ExtCertPathValidatorException(e.getMessage(), e, certPath, index); } + catch (Exception e) + { + throw new CertPathValidatorException("Additional certificate path checker failed.", e, certPath, index); + } } if (!criticalExtensions.isEmpty()) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/ReasonsMask.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/ReasonsMask.java index 71fdb515a..1abb7af0a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/ReasonsMask.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/ReasonsMask.java @@ -69,7 +69,7 @@ class ReasonsMask * Intersects this mask with the given reasons mask. * * @param mask The mask to intersect with. - * @return The intersection of this and teh given mask. + * @return The intersection of this and the given mask. */ ReasonsMask intersect(ReasonsMask mask) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509AttrCertParser.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509AttrCertParser.java index 67b97921a..0c9c0b55e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509AttrCertParser.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509AttrCertParser.java @@ -33,7 +33,7 @@ public class X509AttrCertParser throws IOException { ASN1InputStream dIn = new ASN1InputStream(in); - ASN1Sequence seq = (ASN1Sequence)dIn.readObject(); + ASN1Sequence seq = ASN1Sequence.getInstance(dIn.readObject()); if (seq.size() > 1 && seq.getObjectAt(0) instanceof ASN1ObjectIdentifier) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509CRLObject.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509CRLObject.java index 25c9a8bb7..e99690e7e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509CRLObject.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509CRLObject.java @@ -346,7 +346,7 @@ public class X509CRLObject { TBSCertList.CRLEntry entry = (TBSCertList.CRLEntry)certs.nextElement(); - if (serialNumber.equals(entry.getUserCertificate().getValue())) + if (entry.getUserCertificate().hasValue(serialNumber)) { return new X509CRLEntryObject(entry, isIndirect, previousCertificateIssuer); } @@ -583,7 +583,7 @@ public class X509CRLObject } } - if (entry.getUserCertificate().getValue().equals(serial)) + if (entry.getUserCertificate().hasValue(serial)) { X500Name issuer; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509CertificateObject.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509CertificateObject.java index 6b08ed52f..982214070 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509CertificateObject.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/X509CertificateObject.java @@ -1,6 +1,5 @@ package com.fr.third.org.bouncycastle.jce.provider; -import java.io.ByteArrayOutputStream; import java.io.IOException; import java.math.BigInteger; import java.net.InetAddress; @@ -37,7 +36,6 @@ import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; -import com.fr.third.org.bouncycastle.asn1.ASN1OutputStream; import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; import com.fr.third.org.bouncycastle.asn1.ASN1String; @@ -162,26 +160,14 @@ public class X509CertificateObject public Principal getIssuerDN() { - try - { - return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded())); - } - catch (IOException e) - { - return null; - } + return new X509Principal(c.getIssuer()); } public X500Principal getIssuerX500Principal() { try { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - - aOut.writeObject(c.getIssuer()); - - return new X500Principal(bOut.toByteArray()); + return new X500Principal(c.getIssuer().getEncoded()); } catch (IOException e) { @@ -191,19 +177,14 @@ public class X509CertificateObject public Principal getSubjectDN() { - return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive())); + return new X509Principal(c.getSubject()); } public X500Principal getSubjectX500Principal() { try { - ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); - - aOut.writeObject(c.getSubject()); - - return new X500Principal(bOut.toByteArray()); + return new X500Principal(c.getSubject().getEncoded()); } catch (IOException e) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AESSICTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AESSICTest.java new file mode 100644 index 000000000..c75a5a7ef --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AESSICTest.java @@ -0,0 +1,168 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Key; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jcajce.spec.RepeatedSecretKeySpec; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * test vectors based on NIST Special Publication 800-38A, + * "Recommendation for Block Cipher Modes of Operation" + */ +public class AESSICTest + extends SimpleTest +{ + private byte[][] keys = + { + Hex.decode("2b7e151628aed2a6abf7158809cf4f3c"), + Hex.decode("8e73b0f7da0e6452c810f32b809079e562f8ead2522c6b7b"), + Hex.decode("603deb1015ca71be2b73aef0857d77811f352c073b6108d72d9810a30914dff4") + }; + + private byte[][] plain = + { + Hex.decode("6bc1bee22e409f96e93d7e117393172a"), + Hex.decode("ae2d8a571e03ac9c9eb76fac45af8e51"), + Hex.decode("30c81c46a35ce411e5fbc1191a0a52ef"), + Hex.decode("f69f2445df4f9b17ad2b417be66c3710") + }; + + private byte[][][] cipher = + { + { + Hex.decode("874d6191b620e3261bef6864990db6ce"), + Hex.decode("9806f66b7970fdff8617187bb9fffdff"), + Hex.decode("5ae4df3edbd5d35e5b4f09020db03eab"), + Hex.decode("1e031dda2fbe03d1792170a0f3009cee") + }, + { + Hex.decode("1abc932417521ca24f2b0459fe7e6e0b"), + Hex.decode("090339ec0aa6faefd5ccc2c6f4ce8e94"), + Hex.decode("1e36b26bd1ebc670d1bd1d665620abf7"), + Hex.decode("4f78a7f6d29809585a97daec58c6b050") + }, + { + Hex.decode("601ec313775789a5b7a7f504bbf3d228"), + Hex.decode("f443e3ca4d62b59aca84e990cacaf5c5"), + Hex.decode("2b0930daa23de94ce87017ba2d84988d"), + Hex.decode("dfc9c58db67aada613c2dd08457941a6") + } + }; + + public String getName() + { + return "AESSIC"; + } + + public void performTest() + throws Exception + { + Cipher c = Cipher.getInstance("AES/SIC/NoPadding", "BC"); + + // + // NIST vectors + // + for (int i = 0; i != keys.length; i++) + { + Key sk = new SecretKeySpec(keys[i], "AES"); + c.init( + Cipher.ENCRYPT_MODE, sk, + new IvParameterSpec(Hex.decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"))); + + for (int j = 0; j != plain.length; j++) + { + byte[] crypt = c.update(plain[j]); + if (!areEqual(crypt, cipher[i][j])) + { + fail("AESSIC encrypt failed: key " + i + " block " + j); + } + } + + c.init( + Cipher.DECRYPT_MODE, sk, + new IvParameterSpec(Hex.decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"))); + + for (int j = 0; j != plain.length; j++) + { + byte[] crypt = c.update(cipher[i][j]); + if (!areEqual(crypt, plain[j])) + { + fail("AESSIC decrypt failed: key " + i + " block " + j); + } + } + } + + // + // check CTR also recognised. + // + c = Cipher.getInstance("AES/CTR/NoPadding", "BC"); + + Key sk = new SecretKeySpec(Hex.decode("2B7E151628AED2A6ABF7158809CF4F3C"), "AES"); + + c.init( + Cipher.ENCRYPT_MODE, sk, + new IvParameterSpec(Hex.decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFD0001"))); + + byte[] crypt = c.doFinal(Hex.decode("00000000000000000000000000000000")); + + if (!areEqual(crypt, Hex.decode("D23513162B02D0F72A43A2FE4A5F97AB"))) + { + fail("AESSIC failed test 2"); + } + + // + // check partial block processing + // + c = Cipher.getInstance("AES/CTR/NoPadding", "BC"); + + sk = new SecretKeySpec(Hex.decode("2B7E151628AED2A6ABF7158809CF4F3C"), "AES"); + + c.init( + Cipher.ENCRYPT_MODE, sk, + new IvParameterSpec(Hex.decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFD0001"))); + + crypt = c.doFinal(Hex.decode("12345678")); + + c.init( + Cipher.DECRYPT_MODE, sk, + new IvParameterSpec(Hex.decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFD0001"))); + + crypt = c.doFinal(crypt); + + if (!areEqual(crypt, Hex.decode("12345678"))) + { + fail("AESSIC failed partial test"); + } + + // null key test + sk = new RepeatedSecretKeySpec("AES"); + + c.init( + Cipher.ENCRYPT_MODE, sk, + new IvParameterSpec(Hex.decode("F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF"))); + + for (int j = 0; j != plain.length; j++) + { + crypt = c.update(plain[j]); + if (!areEqual(crypt, cipher[0][j])) + { + fail("AESSIC encrypt failed: key " + 0 + " block " + j); + } + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new AESSICTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AESTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AESTest.java new file mode 100644 index 000000000..3ba38644c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AESTest.java @@ -0,0 +1,459 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.Key; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.prng.FixedSecureRandom; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +/** + * basic test class for the AES cipher vectors from FIPS-197 + */ +public class AESTest + extends BaseBlockCipherTest +{ + static String[] cipherTests = + { + "128", + "000102030405060708090a0b0c0d0e0f", + "00112233445566778899aabbccddeeff", + "69c4e0d86a7b0430d8cdb78070b4c55a", + "192", + "000102030405060708090a0b0c0d0e0f1011121314151617", + "00112233445566778899aabbccddeeff", + "dda97ca4864cdfe06eaf70a0ec0d7191", + "256", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "00112233445566778899aabbccddeeff", + "8ea2b7ca516745bfeafc49904b496089", + }; + + public AESTest() + { + super("AES"); + } + + private void test( + int strength, + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "AES"); + + in = Cipher.getInstance("AES/ECB/NoPadding", "BC"); + out = Cipher.getInstance("AES/ECB/NoPadding", "BC"); + + try + { + out.init(Cipher.ENCRYPT_MODE, key); + } + catch (Exception e) + { + fail("AES failed initialisation - " + e.toString(), e); + } + + try + { + in.init(Cipher.DECRYPT_MODE, key); + } + catch (Exception e) + { + fail("AES failed initialisation - " + e.toString(), e); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail("AES failed encryption - " + e.toString(), e); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("AES failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + } + catch (Exception e) + { + fail("AES failed encryption - " + e.toString(), e); + } + + if (!areEqual(bytes, input)) + { + fail("AES failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + private void eaxTest() + throws Exception + { + byte[] K = Hex.decode("233952DEE4D5ED5F9B9C6D6FF80FF478"); + byte[] N = Hex.decode("62EC67F9C3A4A407FCB2A8C49031A8B3"); + byte[] P = Hex.decode("68656c6c6f20776f726c642121"); + byte[] C = Hex.decode("2f9f76cb7659c70e4be11670a3e193ae1bc6b5762a"); + + Key key; + Cipher in, out; + + key = new SecretKeySpec(K, "AES"); + + in = Cipher.getInstance("AES/EAX/NoPadding", "BC"); + out = Cipher.getInstance("AES/EAX/NoPadding", "BC"); + + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] enc = in.doFinal(P); + if (!areEqual(enc, C)) + { + fail("ciphertext doesn't match in EAX"); + } + + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] dec = out.doFinal(C); + if (!areEqual(dec, P)) + { + fail("plaintext doesn't match in EAX"); + } + + try + { + in = Cipher.getInstance("AES/EAX/PKCS5Padding", "BC"); + + fail("bad padding missed in EAX"); + } + catch (NoSuchPaddingException e) + { + // expected + } + } + + private void ccmTest() + throws Exception + { + byte[] K = Hex.decode("404142434445464748494a4b4c4d4e4f"); + byte[] N = Hex.decode("10111213141516"); + byte[] P = Hex.decode("68656c6c6f20776f726c642121"); + byte[] C = Hex.decode("39264f148b54c456035de0a531c8344f46db12b388"); + + Key key; + Cipher in, out; + + key = new SecretKeySpec(K, "AES"); + + in = Cipher.getInstance("AES/CCM/NoPadding", "BC"); + out = Cipher.getInstance("AES/CCM/NoPadding", "BC"); + + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] enc = in.doFinal(P); + if (!areEqual(enc, C)) + { + fail("ciphertext doesn't match in CCM"); + } + + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] dec = out.doFinal(C); + if (!areEqual(dec, P)) + { + fail("plaintext doesn't match in CCM"); + } + + try + { + in = Cipher.getInstance("AES/CCM/PKCS5Padding", "BC"); + + fail("bad padding missed in CCM"); + } + catch (NoSuchPaddingException e) + { + // expected + } + } + + private void gcmTest() + throws Exception + { + // Test Case 15 from McGrew/Viega + byte[] K = Hex.decode( + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308"); + byte[] P = Hex.decode( + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b391aafd255"); + byte[] N = Hex.decode("cafebabefacedbaddecaf888"); + String T = "b094dac5d93471bdec1a502270e3cc6c"; + byte[] C = Hex.decode( + "522dc1f099567d07f47f37a32a84427d" + + "643a8cdcbfe5c0c97598a2bd2555d1aa" + + "8cb08e48590dbb3da7b08b1056828838" + + "c5f61e6393ba7a0abcc9f662898015ad" + + T); + + Key key; + Cipher in, out; + + key = new SecretKeySpec(K, "AES"); + + in = Cipher.getInstance("AES/GCM/NoPadding", "BC"); + out = Cipher.getInstance("AES/GCM/NoPadding", "BC"); + + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] enc = in.doFinal(P); + if (!areEqual(enc, C)) + { + fail("ciphertext doesn't match in GCM"); + } + + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] dec = out.doFinal(C); + if (!areEqual(dec, P)) + { + fail("plaintext doesn't match in GCM"); + } + + try + { + in = Cipher.getInstance("AES/GCM/PKCS5Padding", "BC"); + + fail("bad padding missed in GCM"); + } + catch (NoSuchPaddingException e) + { + // expected + } + + + // reuse test + in = Cipher.getInstance("AES/GCM/NoPadding", "BC"); + + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + + enc = in.doFinal(P); + + try + { + in.doFinal(P); + fail("no exception on reuse"); + } + catch (IllegalStateException e) + { + isTrue("wrong message", e.getMessage().equals("GCM cipher cannot be reused for encryption")); + } + + try + { + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + fail("no exception on reuse"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("wrong message", e.getMessage().equals("cannot reuse nonce for GCM encryption")); + } + } + + private void ocbTest() + throws Exception + { + byte[] K = Hex.decode( + "000102030405060708090A0B0C0D0E0F"); + byte[] P = Hex.decode( + "000102030405060708090A0B0C0D0E0F"); + byte[] N = Hex.decode("000102030405060708090A0B"); + String T = "4CBB3E4BD6B456AF"; + byte[] C = Hex.decode( + "BEA5E8798DBE7110031C144DA0B2612213CC8B747807121A" + T); + + Key key; + Cipher in, out; + + key = new SecretKeySpec(K, "AES"); + + in = Cipher.getInstance("AES/OCB/NoPadding", "BC"); + out = Cipher.getInstance("AES/OCB/NoPadding", "BC"); + + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] enc = in.doFinal(P); + if (!areEqual(enc, C)) + { + fail("ciphertext doesn't match in OCB"); + } + + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] dec = out.doFinal(C); + if (!areEqual(dec, P)) + { + fail("plaintext doesn't match in OCB"); + } + + try + { + in = Cipher.getInstance("AES/OCB/PKCS5Padding", "BC"); + + fail("bad padding missed in OCB"); + } + catch (NoSuchPaddingException e) + { + // expected + } + } + + public void performTest() + throws Exception + { + for (int i = 0; i != cipherTests.length; i += 4) + { + test(Integer.parseInt(cipherTests[i]), + Hex.decode(cipherTests[i + 1]), + Hex.decode(cipherTests[i + 2]), + Hex.decode(cipherTests[i + 3])); + } + + byte[] kek1 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] in1 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out1 = Hex.decode("1fa68b0a8112b447aef34bd8fb5a7b829d3e862371d2cfe5"); + + wrapTest(1, "AESWrap", kek1, in1, out1); + + byte[] kek2 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] in2 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out2 = Hex.decode("7c8798dfc802553b3f00bb4315e3a087322725c92398b9c112c74d0925c63b61"); + + wrapTest(2, "AESRFC3211WRAP", kek2, kek2, new FixedSecureRandom(Hex.decode("9688df2af1b7b1ac9688df2a")), in2, out2); + + byte[] kek3 = Hex.decode("5840df6e29b02af1ab493b705bf16ea1ae8338f4dcc176a8"); + byte[] in3 = Hex.decode("c37b7e6492584340bed12207808941155068f738"); + byte[] out3 = Hex.decode("138bdeaa9b8fa7fc61f97742e72248ee5ae6ae5360d1ae6a5f54f373fa543b6a"); + + wrapTest(3, "AESRFC5649WRAP", kek3, in3, out3); + + String[] oids = { + NISTObjectIdentifiers.id_aes128_ECB.getId(), + NISTObjectIdentifiers.id_aes128_CBC.getId(), + NISTObjectIdentifiers.id_aes128_OFB.getId(), + NISTObjectIdentifiers.id_aes128_CFB.getId(), + NISTObjectIdentifiers.id_aes192_ECB.getId(), + NISTObjectIdentifiers.id_aes192_CBC.getId(), + NISTObjectIdentifiers.id_aes192_OFB.getId(), + NISTObjectIdentifiers.id_aes192_CFB.getId(), + NISTObjectIdentifiers.id_aes256_ECB.getId(), + NISTObjectIdentifiers.id_aes256_CBC.getId(), + NISTObjectIdentifiers.id_aes256_OFB.getId(), + NISTObjectIdentifiers.id_aes256_CFB.getId() + }; + + String[] names = { + "AES/ECB/PKCS7Padding", + "AES/CBC/PKCS7Padding", + "AES/OFB/NoPadding", + "AES/CFB/NoPadding", + "AES/ECB/PKCS7Padding", + "AES/CBC/PKCS7Padding", + "AES/OFB/NoPadding", + "AES/CFB/NoPadding", + "AES/ECB/PKCS7Padding", + "AES/CBC/PKCS7Padding", + "AES/OFB/NoPadding", + "AES/CFB/NoPadding" + }; + + oidTest(oids, names, 4); + + + String[] wrapOids = { + NISTObjectIdentifiers.id_aes128_wrap.getId(), + NISTObjectIdentifiers.id_aes192_wrap.getId(), + NISTObjectIdentifiers.id_aes256_wrap.getId(), + }; + + wrapOidTest(wrapOids, "AESWrap"); + + wrapOids = new String[] { + NISTObjectIdentifiers.id_aes128_wrap_pad.getId(), + NISTObjectIdentifiers.id_aes192_wrap_pad.getId(), + NISTObjectIdentifiers.id_aes256_wrap_pad.getId() + }; + + wrapOidTest(wrapOids, "AESWrapPad"); + + eaxTest(); + ccmTest(); + gcmTest(); + ocbTest(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new AESTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ARIATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ARIATest.java new file mode 100644 index 000000000..e374b91c5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ARIATest.java @@ -0,0 +1,427 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.asn1.nsri.NSRIObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.prng.FixedSecureRandom; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +/** + * basic test class for the ARIA cipher vectors from FIPS-197 + */ +public class ARIATest + extends BaseBlockCipherTest +{ + static String[] cipherTests = + { + "128", + "000102030405060708090a0b0c0d0e0f", + "00112233445566778899aabbccddeeff", + "d718fbd6ab644c739da95f3be6451778", + "192", + "000102030405060708090a0b0c0d0e0f1011121314151617", + "00112233445566778899aabbccddeeff", + "26449c1805dbe7aa25a468ce263a9e79", + "256", + "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + "00112233445566778899aabbccddeeff", + "f92bd7c79fb72e2f2b8f80c1972d24fc" + }; + + public ARIATest() + { + super("ARIA"); + } + + private void test( + int strength, + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "ARIA"); + + in = Cipher.getInstance("ARIA/ECB/NoPadding", "BC"); + out = Cipher.getInstance("ARIA/ECB/NoPadding", "BC"); + + try + { + out.init(Cipher.ENCRYPT_MODE, key); + } + catch (Exception e) + { + fail("ARIA failed initialisation - " + e.toString(), e); + } + + try + { + in.init(Cipher.DECRYPT_MODE, key); + } + catch (Exception e) + { + fail("ARIA failed initialisation - " + e.toString(), e); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail("ARIA failed encryption - " + e.toString(), e); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("ARIA failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + } + catch (Exception e) + { + fail("ARIA failed encryption - " + e.toString(), e); + } + + if (!areEqual(bytes, input)) + { + fail("ARIA failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + private void eaxTest() + throws Exception + { + byte[] K = Hex.decode("233952DEE4D5ED5F9B9C6D6FF80FF478"); + byte[] N = Hex.decode("62EC67F9C3A4A407FCB2A8C49031A8B3"); + byte[] P = Hex.decode("68656c6c6f20776f726c642121"); + byte[] C = Hex.decode("85fe63d6cfb872d2420e65425c074dfad6fe752e03"); + + Key key; + Cipher in, out; + + key = new SecretKeySpec(K, "ARIA"); + + in = Cipher.getInstance("ARIA/EAX/NoPadding", "BC"); + out = Cipher.getInstance("ARIA/EAX/NoPadding", "BC"); + + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] enc = in.doFinal(P); + if (!areEqual(enc, C)) + { + fail("ciphertext doesn't match in EAX: " + Hex.toHexString(enc)); + } + + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] dec = out.doFinal(C); + if (!areEqual(dec, P)) + { + fail("plaintext doesn't match in EAX"); + } + + try + { + in = Cipher.getInstance("ARIA/EAX/PKCS5Padding", "BC"); + + fail("bad padding missed in EAX"); + } + catch (NoSuchPaddingException e) + { + // expected + } + } + + private void ccmTest() + throws Exception + { + byte[] K = Hex.decode("404142434445464748494a4b4c4d4e4f"); + byte[] N = Hex.decode("10111213141516"); + byte[] P = Hex.decode("68656c6c6f20776f726c642121"); + byte[] C = Hex.decode("0af625ff69cd9dbe65fae181d654717eb7a0263bcd"); + + Key key; + Cipher in, out; + + key = new SecretKeySpec(K, "ARIA"); + + in = Cipher.getInstance("ARIA/CCM/NoPadding", "BC"); + out = Cipher.getInstance("ARIA/CCM/NoPadding", "BC"); + + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] enc = in.doFinal(P); + if (!areEqual(enc, C)) + { + fail("ciphertext doesn't match in CCM: " + Hex.toHexString(enc)); + } + + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] dec = out.doFinal(C); + if (!areEqual(dec, P)) + { + fail("plaintext doesn't match in CCM"); + } + + try + { + in = Cipher.getInstance("ARIA/CCM/PKCS5Padding", "BC"); + + fail("bad padding missed in CCM"); + } + catch (NoSuchPaddingException e) + { + // expected + } + } + + private void gcmTest() + throws Exception + { + // Test Case 15 from McGrew/Viega + byte[] K = Hex.decode( + "feffe9928665731c6d6a8f9467308308" + + "feffe9928665731c6d6a8f9467308308"); + byte[] P = Hex.decode( + "d9313225f88406e5a55909c5aff5269a" + + "86a7a9531534f7da2e4c303d8a318a72" + + "1c3c0c95956809532fcf0e2449a6b525" + + "b16aedf5aa0de657ba637b391aafd255"); + byte[] N = Hex.decode("cafebabefacedbaddecaf888"); + String T = "c8f245c8619ca9ba7d6d9545e7f48214"; + byte[] C = Hex.decode( + "c3aa0e01a4f8b5dfdb25d0f1c78c275e516114080e2be7a7f7bffd4504b19a8552f80ad5b55f3d911725489629996d398d5ed6f077e22924c5b8ebe20a219693" + + T); + + Key key; + Cipher in, out; + + key = new SecretKeySpec(K, "ARIA"); + + in = Cipher.getInstance("ARIA/GCM/NoPadding", "BC"); + out = Cipher.getInstance("ARIA/GCM/NoPadding", "BC"); + + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] enc = in.doFinal(P); + if (!areEqual(enc, C)) + { + fail("ciphertext doesn't match in GCM: " + Hex.toHexString(enc)); + } + + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] dec = out.doFinal(C); + if (!areEqual(dec, P)) + { + fail("plaintext doesn't match in GCM"); + } + + try + { + in = Cipher.getInstance("ARIA/GCM/PKCS5Padding", "BC"); + + fail("bad padding missed in GCM"); + } + catch (NoSuchPaddingException e) + { + // expected + } + } + + private void ocbTest() + throws Exception + { + byte[] K = Hex.decode( + "000102030405060708090A0B0C0D0E0F"); + byte[] P = Hex.decode( + "000102030405060708090A0B0C0D0E0F"); + byte[] N = Hex.decode("000102030405060708090A0B"); + String T = "0027ce4f3aaeec75"; + byte[] C = Hex.decode( + "7bcae9eac9f1f54704a630e309099a87f53a1c1559de1b3b" + T); + + Key key; + Cipher in, out; + + key = new SecretKeySpec(K, "ARIA"); + + in = Cipher.getInstance("ARIA/OCB/NoPadding", "BC"); + out = Cipher.getInstance("ARIA/OCB/NoPadding", "BC"); + + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] enc = in.doFinal(P); + if (!areEqual(enc, C)) + { + fail("ciphertext doesn't match in OCB: " + Hex.toHexString(enc)); + } + + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] dec = out.doFinal(C); + if (!areEqual(dec, P)) + { + fail("plaintext doesn't match in OCB"); + } + + try + { + in = Cipher.getInstance("ARIA/OCB/PKCS5Padding", "BC"); + + fail("bad padding missed in OCB"); + } + catch (NoSuchPaddingException e) + { + // expected + } + } + + public void performTest() + throws Exception + { + for (int i = 0; i != cipherTests.length; i += 4) + { + test(Integer.parseInt(cipherTests[i]), + Hex.decode(cipherTests[i + 1]), + Hex.decode(cipherTests[i + 2]), + Hex.decode(cipherTests[i + 3])); + } + + byte[] kek1 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] in1 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out1 = Hex.decode("a93f148d4909d85f1aae656909879275ae597b3acf9d60db"); + + wrapTest(1, "ARIAWrap", kek1, in1, out1); + + byte[] kek2 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] in2 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out2 = Hex.decode("9b2d3cac0acf9d4bde7c1bdb0313fbef931f025acc77bf57d3d1cabc88b514d0"); + + wrapTest(2, "ARIARFC3211WRAP", kek2, kek2, new FixedSecureRandom(Hex.decode("9688df2af1b7b1ac9688df2a")), in2, out2); + + byte[] kek3 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] in3 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out3 = Hex.decode("ac0e22699a036ced63adeb75f4946f82dc98ad8af43b24d5"); + + wrapTest(3, "ARIAWrapPad", kek3, in3, out3); + + String[] oids = { + NSRIObjectIdentifiers.id_aria128_ecb.getId(), + NSRIObjectIdentifiers.id_aria128_cbc.getId(), + NSRIObjectIdentifiers.id_aria128_ofb.getId(), + NSRIObjectIdentifiers.id_aria128_cfb.getId(), + NSRIObjectIdentifiers.id_aria192_ecb.getId(), + NSRIObjectIdentifiers.id_aria192_cbc.getId(), + NSRIObjectIdentifiers.id_aria192_ofb.getId(), + NSRIObjectIdentifiers.id_aria192_cfb.getId(), + NSRIObjectIdentifiers.id_aria256_ecb.getId(), + NSRIObjectIdentifiers.id_aria256_cbc.getId(), + NSRIObjectIdentifiers.id_aria256_ofb.getId(), + NSRIObjectIdentifiers.id_aria256_cfb.getId() + }; + + String[] names = { + "ARIA/ECB/PKCS7Padding", + "ARIA/CBC/PKCS7Padding", + "ARIA/OFB/NoPadding", + "ARIA/CFB/NoPadding", + "ARIA/ECB/PKCS7Padding", + "ARIA/CBC/PKCS7Padding", + "ARIA/OFB/NoPadding", + "ARIA/CFB/NoPadding", + "ARIA/ECB/PKCS7Padding", + "ARIA/CBC/PKCS7Padding", + "ARIA/OFB/NoPadding", + "ARIA/CFB/NoPadding" + }; + + oidTest(oids, names, 4); + + + String[] wrapOids = { + NSRIObjectIdentifiers.id_aria128_kw.getId(), + NSRIObjectIdentifiers.id_aria192_kw.getId(), + NSRIObjectIdentifiers.id_aria256_kw.getId() + }; + + wrapOidTest(wrapOids, "ARIAWrap"); + + wrapOids = new String[] { + NSRIObjectIdentifiers.id_aria128_kwp.getId(), + NSRIObjectIdentifiers.id_aria192_kwp.getId(), + NSRIObjectIdentifiers.id_aria256_kwp.getId() + }; + + wrapOidTest(wrapOids, "ARIAWrapPad"); + + eaxTest(); + ccmTest(); + gcmTest(); + ocbTest(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new ARIATest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java new file mode 100644 index 000000000..4f7e8bda2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AlgorithmParametersTest.java @@ -0,0 +1,128 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.IOException; +import java.security.AlgorithmParameters; +import java.security.Security; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.DSAParameterSpec; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +import javax.crypto.spec.IvParameterSpec; + +import com.fr.third.org.bouncycastle.asn1.sec.SECObjectIdentifiers; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class AlgorithmParametersTest + extends SimpleTest +{ + private byte[] dsaParams = Base64.decode( + "MIGcAkEAjfKklEkidqo9JXWbsGhpy+rA2Dr7jQz3y7gyTw14guXQdi/FtyEOr8Lprawyq3qsSWk9+/g3J" + + "MLsBzbuMcgCkQIVAMdzIYxzfsjumTtPLe0w9I7azpFfAkBP3Z9K7oNeZMXEXYpqvrMUgVdFjq4lnWJoV8" + + "Rwe+TERStHTkqSO7sp0lq7EEggVMcuXtarKNsxaJ+qyYv/n1t6"); + + private void basicTest(String algorithm, Class algorithmParameterSpec, byte[] asn1Encoded) + throws Exception + { + AlgorithmParameters alg = AlgorithmParameters.getInstance(algorithm, "BC"); + + alg.init(asn1Encoded); + + try + { + alg.init(asn1Encoded); + fail("encoded re-initialization not detected"); + } + catch (IOException e) + { + // expected already initialized + } + + AlgorithmParameterSpec spec = alg.getParameterSpec(algorithmParameterSpec); + + try + { + alg.init(spec); + fail("spec re-initialization not detected"); + } + catch (InvalidParameterSpecException e) + { + // expected already initialized + } + + // check default + spec = alg.getParameterSpec(AlgorithmParameterSpec.class); + + try + { + spec = alg.getParameterSpec(IvParameterSpec.class); + fail("wrong spec not detected"); + } + catch (InvalidParameterSpecException e) + { + // expected unknown object + } + + try + { + spec = alg.getParameterSpec(null); + fail("null spec not detected"); + } + catch (NullPointerException e) + { + // expected unknown object + } + + alg = AlgorithmParameters.getInstance(algorithm, "BC"); + + alg.init(asn1Encoded, "ASN.1"); + + alg = AlgorithmParameters.getInstance(algorithm, "BC"); + + alg.init(asn1Encoded, null); + + alg = AlgorithmParameters.getInstance(algorithm, "BC"); + + try + { + alg.init(asn1Encoded, "FRED"); + fail("unknown spec not detected"); + } + catch (IOException e) + { + // expected already initialized + } + } + + public void performTest() + throws Exception + { + basicTest("DSA", DSAParameterSpec.class, dsaParams); + + AlgorithmParameters al = AlgorithmParameters.getInstance("EC", "BC"); + + al.init(new ECGenParameterSpec(SECObjectIdentifiers.secp256r1.getId())); + + if (!Arrays.areEqual(Hex.decode("06082a8648ce3d030107"), al.getEncoded())) + { + fail("EC param test failed"); + } + } + + public String getName() + { + return "AlgorithmParameters"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new AlgorithmParametersTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AttrCertData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AttrCertData.java new file mode 100644 index 000000000..c439a8901 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/AttrCertData.java @@ -0,0 +1,119 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.spec.RSAPrivateCrtKeySpec; + +import com.fr.third.org.bouncycastle.util.encoders.Base64; + +public class AttrCertData +{ + private static final RSAPrivateCrtKeySpec RSA_PRIVATE_KEY_SPEC = new RSAPrivateCrtKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16), + new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16), + new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16), + new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16), + new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16), + new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16), + new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16)); + + public static byte[] attrCert = Base64.decode( + "MIIHQDCCBqkCAQEwgZChgY2kgYowgYcxHDAaBgkqhkiG9w0BCQEWDW1sb3JjaEB2" + + "dC5lZHUxHjAcBgNVBAMTFU1hcmt1cyBMb3JjaCAobWxvcmNoKTEbMBkGA1UECxMS" + + "VmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAyMQswCQYDVQQKEwJ2" + + "dDELMAkGA1UEBhMCVVMwgYmkgYYwgYMxGzAZBgkqhkiG9w0BCQEWDHNzaGFoQHZ0" + + "LmVkdTEbMBkGA1UEAxMSU3VtaXQgU2hhaCAoc3NoYWgpMRswGQYDVQQLExJWaXJn" + + "aW5pYSBUZWNoIFVzZXIxEDAOBgNVBAsTB0NsYXNzIDExCzAJBgNVBAoTAnZ0MQsw" + + "CQYDVQQGEwJVUzANBgkqhkiG9w0BAQQFAAIBBTAiGA8yMDAzMDcxODE2MDgwMloY" + + "DzIwMDMwNzI1MTYwODAyWjCCBU0wggVJBgorBgEEAbRoCAEBMYIFORaCBTU8UnVs" + + "ZSBSdWxlSWQ9IkZpbGUtUHJpdmlsZWdlLVJ1bGUiIEVmZmVjdD0iUGVybWl0Ij4K" + + "IDxUYXJnZXQ+CiAgPFN1YmplY3RzPgogICA8U3ViamVjdD4KICAgIDxTdWJqZWN0" + + "TWF0Y2ggTWF0Y2hJZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5j" + + "dGlvbjpzdHJpbmctZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlw" + + "ZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjc3RyaW5nIj4KICAg" + + "ICAgIENOPU1hcmt1cyBMb3JjaDwvQXR0cmlidXRlVmFsdWU+CiAgICAgPFN1Ympl" + + "Y3RBdHRyaWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFt" + + "ZXM6dGM6eGFjbWw6MS4wOnN1YmplY3Q6c3ViamVjdC1pZCIgRGF0YVR5cGU9Imh0" + + "dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI3N0cmluZyIgLz4gCiAgICA8" + + "L1N1YmplY3RNYXRjaD4KICAgPC9TdWJqZWN0PgogIDwvU3ViamVjdHM+CiAgPFJl" + + "c291cmNlcz4KICAgPFJlc291cmNlPgogICAgPFJlc291cmNlTWF0Y2ggTWF0Y2hJ" + + "ZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5jdGlvbjpzdHJpbmct" + + "ZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlwZT0iaHR0cDovL3d3" + + "dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIj4KICAgICAgaHR0cDovL3p1" + + "bmkuY3MudnQuZWR1PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICA8UmVzb3VyY2VBdHRy" + + "aWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6" + + "eGFjbWw6MS4wOnJlc291cmNlOnJlc291cmNlLWlkIiBEYXRhVHlwZT0iaHR0cDov" + + "L3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIiAvPiAKICAgIDwvUmVz" + + "b3VyY2VNYXRjaD4KICAgPC9SZXNvdXJjZT4KICA8L1Jlc291cmNlcz4KICA8QWN0" + + "aW9ucz4KICAgPEFjdGlvbj4KICAgIDxBY3Rpb25NYXRjaCBNYXRjaElkPSJ1cm46" + + "b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmZ1bmN0aW9uOnN0cmluZy1lcXVhbCI+" + + "CiAgICAgPEF0dHJpYnV0ZVZhbHVlIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9y" + + "Zy8yMDAxL1hNTFNjaGVtYSNzdHJpbmciPgpEZWxlZ2F0ZSBBY2Nlc3MgICAgIDwv" + + "QXR0cmlidXRlVmFsdWU+CgkgIDxBY3Rpb25BdHRyaWJ1dGVEZXNpZ25hdG9yIEF0" + + "dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmFjdGlvbjph" + + "Y3Rpb24taWQiIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNj" + + "aGVtYSNzdHJpbmciIC8+IAogICAgPC9BY3Rpb25NYXRjaD4KICAgPC9BY3Rpb24+" + + "CiAgPC9BY3Rpb25zPgogPC9UYXJnZXQ+CjwvUnVsZT4KMA0GCSqGSIb3DQEBBAUA" + + "A4GBAGiJSM48XsY90HlYxGmGVSmNR6ZW2As+bot3KAfiCIkUIOAqhcphBS23egTr" + + "6asYwy151HshbPNYz+Cgeqs45KkVzh7bL/0e1r8sDVIaaGIkjHK3CqBABnfSayr3" + + "Rd1yBoDdEv8Qb+3eEPH6ab9021AsLEnJ6LWTmybbOpMNZ3tv"); + + byte[] signCert = Base64.decode( + "MIIGjTCCBXWgAwIBAgICAPswDQYJKoZIhvcNAQEEBQAwaTEdMBsGCSqGSIb3DQEJ" + + "ARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZpcmdpbmlhIFRlY2ggQ2VydGlm" + + "aWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0MQswCQYDVQQGEwJVUzAeFw0w" + + "MzAxMzExMzUyMTRaFw0wNDAxMzExMzUyMTRaMIGDMRswGQYJKoZIhvcNAQkBFgxz" + + "c2hhaEB2dC5lZHUxGzAZBgNVBAMTElN1bWl0IFNoYWggKHNzaGFoKTEbMBkGA1UE" + + "CxMSVmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAxMQswCQYDVQQK" + + "EwJ2dDELMAkGA1UEBhMCVVMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPDc" + + "scgSKmsEp0VegFkuitD5j5PUkDuzLjlfaYONt2SN8WeqU4j2qtlCnsipa128cyKS" + + "JzYe9duUdNxquh5BPIkMkHBw4jHoQA33tk0J/sydWdN74/AHPpPieK5GHwhU7GTG" + + "rCCS1PJRxjXqse79ExAlul+gjQwHeldAC+d4A6oZAgMBAAGjggOmMIIDojAMBgNV" + + "HRMBAf8EAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAOBgNVHQ8BAf8EBAMCA/gwHQYD" + + "VR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMEMB0GA1UdDgQWBBRUIoWAzlXbzBYE" + + "yVTjQFWyMMKo1jCBkwYDVR0jBIGLMIGIgBTgc3Fm+TGqKDhen+oKfbl+xVbj2KFt" + + "pGswaTEdMBsGCSqGSIb3DQEJARYOaXJtaGVscEB2dC5lZHUxLjAsBgNVBAMTJVZp" + + "cmdpbmlhIFRlY2ggQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxCzAJBgNVBAoTAnZ0" + + "MQswCQYDVQQGEwJVU4IBADCBiwYJYIZIAYb4QgENBH4WfFZpcmdpbmlhIFRlY2gg" + + "Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgZGlnaXRhbCBjZXJ0aWZpY2F0ZXMgYXJl" + + "IHN1YmplY3QgdG8gcG9saWNpZXMgbG9jYXRlZCBhdCBodHRwOi8vd3d3LnBraS52" + + "dC5lZHUvY2EvY3BzLy4wFwYDVR0RBBAwDoEMc3NoYWhAdnQuZWR1MBkGA1UdEgQS" + + "MBCBDmlybWhlbHBAdnQuZWR1MEMGCCsGAQUFBwEBBDcwNTAzBggrBgEFBQcwAoYn" + + "aHR0cDovL2JveDE3Ny5jYy52dC5lZHUvY2EvaXNzdWVycy5odG1sMEQGA1UdHwQ9" + + "MDswOaA3oDWGM2h0dHA6Ly9ib3gxNzcuY2MudnQuZWR1L2h0ZG9jcy1wdWJsaWMv" + + "Y3JsL2NhY3JsLmNybDBUBgNVHSAETTBLMA0GCysGAQQBtGgFAQEBMDoGCysGAQQB" + + "tGgFAQEBMCswKQYIKwYBBQUHAgEWHWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9jYS9j" + + "cHMvMD8GCWCGSAGG+EIBBAQyFjBodHRwOi8vYm94MTc3LmNjLnZ0LmVkdS9jZ2kt" + + "cHVibGljL2NoZWNrX3Jldl9jYT8wPAYJYIZIAYb4QgEDBC8WLWh0dHA6Ly9ib3gx" + + "NzcuY2MudnQuZWR1L2NnaS1wdWJsaWMvY2hlY2tfcmV2PzBLBglghkgBhvhCAQcE" + + "PhY8aHR0cHM6Ly9ib3gxNzcuY2MudnQuZWR1L35PcGVuQ0E4LjAxMDYzMC9jZ2kt" + + "cHVibGljL3JlbmV3YWw/MCwGCWCGSAGG+EIBCAQfFh1odHRwOi8vd3d3LnBraS52" + + "dC5lZHUvY2EvY3BzLzANBgkqhkiG9w0BAQQFAAOCAQEAHJ2ls9yjpZVcu5DqiE67" + + "r7BfkdMnm7IOj2v8cd4EAlPp6OPBmjwDMwvKRBb/P733kLBqFNWXWKTpT008R0KB" + + "8kehbx4h0UPz9vp31zhGv169+5iReQUUQSIwTGNWGLzrT8kPdvxiSAvdAJxcbRBm" + + "KzDic5I8PoGe48kSCkPpT1oNmnivmcu5j1SMvlx0IS2BkFMksr0OHiAW1elSnE/N" + + "RuX2k73b3FucwVxB3NRo3vgoHPCTnh9r4qItAHdxFlF+pPtbw2oHESKRfMRfOIHz" + + "CLQWSIa6Tvg4NIV3RRJ0sbCObesyg08lymalQMdkXwtRn5eGE00SHWwEUjSXP2gR" + + "3g=="); + + static byte[] certWithBaseCertificateID = Base64.decode( + "MIIBqzCCARQCAQEwSKBGMD6kPDA6MQswCQYDVQQGEwJJVDEOMAwGA1UEChMFVU5JVE4xDDAKBgNV" + + "BAsTA0RJVDENMAsGA1UEAxMEcm9vdAIEAVMVjqB6MHikdjB0MQswCQYDVQQGEwJBVTEoMCYGA1UE" + + "ChMfVGhlIExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFByaW1h" + + "cnkgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUJvdW5jeSBDYXN0bGUwDQYJKoZIhvcNAQEFBQACBQKW" + + "RhnHMCIYDzIwMDUxMjEyMTIwMDQyWhgPMjAwNTEyMTkxMjAxMzJaMA8wDQYDVRhIMQaBBGVWSVAw" + + "DQYJKoZIhvcNAQEFBQADgYEAUAVin9StDaA+InxtXq/av6rUQLI9p1X6louBcj4kYJnxRvTrHpsr" + + "N3+i9Uq/uk5lRdAqmPFvcmSbuE3TRAsjrXON5uFiBBKZ1AouLqcr8nHbwcdwjJ9TyUNO9I4hfpSH" + + "UHHXMtBKgp4MOkhhX8xTGyWg3hp23d3GaUeg/IYlXBI="); + + byte[] holderCertWithBaseCertificateID = Base64.decode( + "MIIBwDCCASmgAwIBAgIEAVMVjjANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJJVDEOMAwGA1UE" + + "ChMFVU5JVE4xDDAKBgNVBAsTA0RJVDENMAsGA1UEAxMEcm9vdDAeFw0wNTExMTExMjAxMzJaFw0w" + + "NjA2MTYxMjAxMzJaMD4xCzAJBgNVBAYTAklUMQ4wDAYDVQQKEwVVTklUTjEMMAoGA1UECxMDRElU" + + "MREwDwYDVQQDEwhMdWNhQm9yejBaMA0GCSqGSIb3DQEBAQUAA0kAMEYCQQC0p+RhcFdPFqlwgrIr" + + "5YtqKmKXmEGb4ShypL26Ymz66ZAPdqv7EhOdzl3lZWT6srZUMWWgQMYGiHQg4z2R7X7XAgERoxUw" + + "EzARBglghkgBhvhCAQEEBAMCBDAwDQYJKoZIhvcNAQEFBQADgYEAsX50VPQQCWmHvPq9y9DeCpmS" + + "4szcpFAhpZyn6gYRwY9CRZVtmZKH8713XhkGDWcIEMcG0u3oTz3tdKgPU5uyIPrDEWr6w8ClUj4x" + + "5aVz5c2223+dVY7KES//JSB2bE/KCIchN3kAioQ4K8O3e0OL6oDVjsqKGw5bfahgKuSIk/Q="); + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java new file mode 100644 index 000000000..fdf4fbf0e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/BCFKSStoreTest.java @@ -0,0 +1,1560 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.Security; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.util.Date; +import java.util.Enumeration; +import java.util.concurrent.atomic.AtomicBoolean; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.asn1.bc.EncryptedObjectStoreData; +import com.fr.third.org.bouncycastle.asn1.bc.ObjectStore; +import com.fr.third.org.bouncycastle.asn1.bc.ObjectStoreIntegrityCheck; +import com.fr.third.org.bouncycastle.asn1.bc.PbkdMacIntegrityCheck; +import com.fr.third.org.bouncycastle.asn1.misc.MiscObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.misc.ScryptParams; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PBES2Parameters; +import com.fr.third.org.bouncycastle.asn1.pkcs.PBKDF2Params; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.crypto.util.PBKDF2Config; +import com.fr.third.org.bouncycastle.crypto.util.PBKDFConfig; +import com.fr.third.org.bouncycastle.crypto.util.ScryptConfig; +import com.fr.third.org.bouncycastle.jcajce.BCFKSLoadStoreParameter; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Exercise the BCFKS KeyStore, + */ +public class BCFKSStoreTest + extends SimpleTest +{ + private static byte[] trustedCertData = Base64.decode( + "MIIB/DCCAaagAwIBAgIBATANBgkqhkiG9w0BAQQFADCBhjELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb24gb2YgdGhlIE" + + "JvdW5jeSBDYXN0bGUxEjAQBgNVBAcMCU1lbGJvdXJuZTERMA8GA1UECAwIVmljdG9yaWExJjAkBgkqhkiG9w0BCQEWF2lzc3VlckBi" + + "b3VuY3ljYXN0bGUub3JnMB4XDTE0MDIyODExMjcxMVoXDTE0MDQyOTExMjcxMVowgYcxCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaG" + + "UgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHDAlNZWxib3VybmUxETAPBgNVBAgMCFZpY3RvcmlhMScwJQYJKoZI" + + "hvcNAQkBFhhzdWJqZWN0QGJvdW5jeWNhc3RsZS5vcmcwWjANBgkqhkiG9w0BAQEFAANJADBGAkEAtKfkYXBXTxapcIKyK+WLaipil5" + + "hBm+EocqS9umJs+umQD3ar+xITnc5d5WVk+rK2VDFloEDGBoh0IOM9ke1+1wIBETANBgkqhkiG9w0BAQQFAANBAJ/ZhfF21NykhbEY" + + "RQrAo/yRr9XfpmBTVUSlLJXYoNVVRT5u9SGQqmPNfHElrTvNMZQPC0ridDZtBWb6S2tg9/E="); + + static char[] testPassword = {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; + static char[] invalidTestPassword = {'Y', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; + + static byte[] kwpKeyStore = Base64.decode( + "MIIJ/TCCCT8wgZUGCSqGSIb3DQEFDTCBhzBlBgkqhkiG9w0BBQwwWARAKXQjiKdsRc8lgCbMh8wLqjNPCiLcXVxArXA4/n6Y72G8jn" + + "jWUsXqvMQFmruTbQF6USSVaMgS1UlTbdLtu7yH9wIDAMgAAgEgMAwGCCqGSIb3DQILBQAwHgYJYIZIAWUDBAEvMBEEDJMoeNdAkcnM" + + "QjtxowIBCASCCKMU5dCIAkTb84CUiUGy4no3nGgVZL+2t4MNPKhMiL+2Xv7Ok9rucD2SMitzm+kxnkVU+aYGLVUrwEPFCvq5GWdnzO" + + "yjCd3XzTieySlfxhIxYMixGfz8NAvPu+P2LwtE+j2C4poHS7+MG22OXpxTTLGzWGuYusxb1zVLTujP6gSVGbtBikLxOXRiYXapZQzL" + + "32bOIKV/tHLv3JCKvIGyJAnTQBDlHQxVsm8fcYBhc101qc9vd3qMborJEZK3E+znJ++lI0yIb+WcZJ3PDI11Fzf22M1D6qtV8RELsL" + + "b5zfLheFLc4rJcY0YSja24se0tFvT7X9cSyrpvXdNDmzBlBThPdINsKPf3N6fO/9ibn/0QIJPY5bQc3SwbN8c7vboHOJzbWjq7n7Q7" + + "1ZkFeiYO/NIXKZ4/KN8sqlRLjvEy4BFnbGoufim+K1zpFGdUPbYpDkuzCkfQfiEaQ9Zt69p5w5e6qh04kgHue0Ac/0IsnRIFy78k4J" + + "lK5TlrB3exqpuISZEWP72WDa+0yTaRM6ecMfIqieDNQmpD9U3HpmdMgiWZXTpCTtM/3I62Bv7EkwcVccRP9z4QUcoGZy81EemQ4d3e" + + "OVfYgvgZBCsbSpf+V8HlsnApTbJubTY1wJQAA19h49E7l3VCxSmeNcUSSE68xJjdJPPAzU1v83+RkYUDPlRx1YsO77zYBSuOwJr0g4" + + "BDTfnyd1vZCM6APt9N7Z2MfALoSSg4EF68nr144GLAMZw4ZVjfUeZ+kF3mjTDPujOoyI3vDztA5ZFa0JCQpp8Yh0CuO+sGnWLh+7Tb" + + "irH2ifEscmNI++csUwDPSInjfGzv722JY6c9XzbaqDGqstpykwwUVN01IceolCvgeHZW7P0feDyqbpgmpdRxiGuBWshFEdcttXDSl9" + + "mQVEyYAMHQFVQKIx2RrFD7QPWZhITGqCvF44GNst/3962Au9oyGAY6rRQfN/HdF4+ygWjOS0t/50c1eAyBj1Rfk/M4sHBi8dKDjOpX" + + "QzqfqLqHjevxQPw1761q629iTagOO/3AIebbraD2qLqDHjmqUAW0ZVLkdS5n8zYyiqGsVeKok7SSDDKQfqwouPHJvRmKzHAK6bZDdr" + + "qMBqNfNcRghWHSH0jM4j8G1w3H2FQsNfBHqTb+kiFx1jEovKkf2HumctWwI5hqV2R2I23ThRNQbh6bdtFc8D3a8YnuXpUK+Tw/RTzM" + + "eGtUsVeakGOZDHh9AlxsdcLChY9xTLMzbpLfb6VAE9kpZ86Uwe60i+S4ropyIp5cwXizAgJPh1T51ZWTzEu+s8BDEAkXSDgxs1PFML" + + "Ha2pWnHPMNSs4VF6eeyK0Vj66m4LcQ0AgE35jAGxWQm31KbWI/h8EMxiC/tDJfMJ3UUKxYCRdbcneDBRc4E4cNmZVqajc8o9Fexr97" + + "GLQ6Is1HVoG65qtq6I9Wt6wmA/5i8ptG7bl7NrIzn3Fg0bMbwHEaKIoXrFHTM0EjwnOkVtQWBNDhnBa66IDJXMxJzXDB2uoMU/wX2y" + + "4dGpM+mgomJt0U3i29HqeihEQjHDc0hTJLkp2SJ2tKw3+VtoXUinV1W7tsG9TMj3F+XNSeiGFrcZpryi6+Fml3Tohg/FaiJQLpB9pL" + + "tzNd61ln1Q6RTHcOMChNocCRaagH6ntX5j8GcVp0auPfw8zyR5iNGueQdnV38Q6MhiGxlMQKC/gjBdKAHRI2q+31tGK8ZslHFxDee1" + + "fy3wtRZpLDwgecH74g4+1TYTLPj/PNeYRQicRCa1BbvI3zB1d8t+LKTg/f34MeEzdMpRT8fRb6vw/O1CRhtdl/0pBQ7RZQSrZFPdEr" + + "KPRv4/1IG46crTCw1/AOMTXKjPeaUeADjff7aLKizJHUSPr6sTRxoMWQeOYfBDnRiLDZ/XYvSDkjnzesa0hdQIIe/tHnqSZ23Jbi46" + + "bLD7Lhf3lfZzbEOqKXAlq0m/ooidubndc0K1xVex4M/T+M0mMPRwO0uICJM4EtivU9Fp5/12GXdvimGEhr/adGodf+JduhsUoIUiz5" + + "TghRV0dSuLtQkcD2d0GkfxgHkCBlhbS3WifMWLTa3lHWrCVyhdIf6m5UOtqfzj5CEEkwE+L6urNBo3D4zHUjm8XJekjI3xjGbQHjBo" + + "sr+BFHkwGNfTXXBHVqRE0L8lH6kSpLaCF5iMpU2NuAeaJ/xdS7LUXBtn4Zvi34PR3/akwMYIr4X+uDM0eB0KkOyyqSXZVPsT7uGMef" + + "wOHmbx1eHe22mR/q1r1iczDwOtXNYo8OB9jSsL3XWFdt4STxdA7kFEsAvK001x0pjrpTa/j/4ixjKhBGu8V/WVuBl0Hlicybtdl7xF" + + "CgoeF3FrAsn2Rw0EjVJm4uLpdEHGIVCWWTgadhZ9YyMWoMenLOUoGMlWXGE9hLGUfJG1wOMlFg33zq4dwCj17O0ULdpHh7QFQFEEpM" + + "+zscDhOHKmrZZEuiJvhR0JFkZz2rml0TEfSjCmdQ8XfJMzLbQ8BKZhWLOQdVh8Scn96Hm0EGkFBkcb4dO/Ubw+cu+bGskxHL1Q6uW0" + + "hGOdejiS7yWclE//uzSlSTa7GRtZ1F/vziWIVno0IInEyiOsCGagagWmxMvv1GTnRJwJl8Bt0BPJmWS2L4CClD6ocH2DrCEEYjMraP" + + "dquGbe0/0eYv3qANDWjvzJs4o4/4SoKZuRBuVj5YQMs69XdaxPgnC3Xfx59pf1Q5qOQe94R8oVTnT6z6G1Radsoweh1UnwItjjt4pt" + + "pfjyUn4bF2Ovz6bs/Tprbo2B4gmBraimCVHT5pruScBY2q4Vd8XiGbiviS8SgqUnxhH/4XmRRdeYpHpZyet1DT+nNTdJdOCfrsE630" + + "9CEQNhQRXt9j5c9S8fnwEA3x/FsriCOAnXsmjVZTnMmctnEYs0aChPxnCBgW1vb2dVUTJQ+KR+2CD3xPNiIEwdk9rA+80k1z3JXek8" + + "tac4cwgbcwDAYIKoZIhvcNAgsFADBlBgkqhkiG9w0BBQwwWARAvH3U5H5R/XeTJYthNF/5aUAsqnHPEeperLR1iXVAiVH8t4iby2WP" + + "FbvQtoKDbREOo9NaULKIWlDlimxCJosvygIDAMgAAgFAMAwGCCqGSIb3DQILBQAEQGeIvocQlW6yjPCczqj+yNdn6sTcmuHI9AnFtn" + + "aY0K7Ki2oIlXl5D9TLznFhJuHDtrIA3VYy2XTCvyrY3qEIySo="); + + static byte[] oldKeyStoreNoPW = Base64.decode( + "MIIF/jCCBUEwgZQGCSqGSIb3DQEFDTCBhjBkBgkqhkiG9w0BBQwwVwRAr1ik7Ut78AkRAXYcwhwjOjlSjfjzLzCqFFFsT2OHXWtCK1h" + + "FEnbVpdi5OFL+TQ6g8kU9w8EYrIZH7elwkMt+6wICBAACASAwDAYIKoZIhvcNAgsFADAeBglghkgBZQMEAS8wEQQMi3d/cdRmlkhW1" + + "B43AgEIBIIEpvp3Y9FgZwdOCGGd3pJmhTy4z3FQ+xQD5yQizR3GtuNwLQvrsDfaZOPdmt6bKSLQdjVXX214d2JmBlKNOj9MD6SDIsW" + + "+yEVoqk4asmQjY5KZi/l7o9IRMTAVFBSKyXYcmnV/0Wqpv/AEOaV1ytrxwu2TOW3gZcbNHs3YQvAArxMcqCLyyGJYJ73Qt2xuccZa8" + + "YgagCovr0t2KJYHdpeTIFvhaAU7/iHKa0z4ES0YjZoEKNu7jA91WCnKIaFdJCRLS5NKqcuHw93KgGNelEEJt9BbhmddlzZ3upxdw9Q" + + "vZsaasD30ezK6viROxAkerfXzI5QVS8Qlz1/TQ10/ri8Lf04H3+HNRV5YS0cH9ghoBxKvvu8whcA43FdvGE7MREIEykJBWWWK5bgul" + + "duf2ONNA5cIBTLwLOmPdT2I4PkXUjCROHBmX9m4F0p41+9DCpqS2z5H2oS4+n+sBLHFWZbsOu/NAXKswLDVRaBbSGJW270dc8Gv1Vo" + + "B9VWlkqX4wLZTLp+Gbk2aJaKlp9zeN5EHG/vh1wJWYq138h2MB+cYZ2TCl3+orhzlzx6xfRVAtbBz9kpPDpfgpnahM0+IdcuVc5B2s" + + "UR6hBM/GQY4cgFdsBI1XhoEjLxzD8PxF4Se2KbseB6fq0+h1GKSB8YXv+IVvroF1ueqsi8DisNcrkN3Bdbl28gopF7kG+aJ84JkEHP" + + "bmN+EaYIZZ6yRBHa/nfXltblCIRbSfB0x4L8Uz+/lbEen5hov7v/60+v+6nAlNWs3Af0ZlmOU4KAcSgmLBJzh3+83qld8BlJH1t1HI" + + "Ct/md7BQLXn4fRWeKUhbwvSvlut7knai1ZKaLxEhNCh+/7UDE7Y1wvzBfWJYfyAFkCxW9U0erkwp8euea7OgMd1U+6R9H8FEgEjzaj" + + "maMCKqmAizZromgxsiPzZgMkz9J1eY/VtWqk1Gu3mq7O/6ilWh/dogxVfeVZ2kyS17rXL152pcJHIx20Vsd4gnFx8sLqfqiO5n/qoA" + + "8BkbbwdrBmURNCVmDMuqlMl/yiOpqohQ8kcp81l6B6NHAtxAWCSz7ypfKw43G80tTKhHYDguCUvdbLCuR43DJj22SuuxoRKHjnhtYD" + + "xKL58W5HhIcSFliI5qBuRc+EHVOdHfFfqNhisitOzuTk9z1Emg0lweVFzaWkpqxiwtNfOmiYrg+EzDYiGmiQ7/r5Uxqku+aX69khXN" + + "OKQbx1d48PI/0mNJV7qUY6k1hhU3ZkMSnuR1akaq/Skds7BnC3yj8byDlWouJ5AYreHPc4uxoH6YwSrBGBWw9omxGPFE6aGWze8pV/" + + "95HOrftINptVRDPtuBvV8fo9qPJ7Xr6unG3kEbKoflYTbolguI4YN338+QIc6+53I7N7H+3kkb8TJhUPj4ImS1dvN5KfkSwYuKX8sQ" + + "r4MGUVTfJwbRCKkbimtJ1MY/Rcpe9No1xQObp/3G4Tfam1KlhhLaM3A9fCLm+WwS7zlemJ+KcWa7iOyoS5f646+aLRZ7sNeuoxYecq" + + "9ybT5W8mYitUdvxcPwMlh2w1DqwmDqXVqkevs8WnDBJM2FYWVJenoU98oPd3pbFicZsjuMIG2MAwGCCqGSIb3DQILBQAwZAYJKoZIh" + + "vcNAQUMMFcEQAI9+HvmFMWhbl/EmZBy/B2CDIKcCs4AuhrKu50UVHSHobnuX7phOAtxdI9VevE2ehMCbWkLrUa3Qtkv4CmozFwCAgQ" + + "AAgFAMAwGCCqGSIb3DQILBQAEQHGAl3x6ij1f4oSoeKX/KQOYByXY/Kk4BinJM0cG0zXapG4vYidgmTMPTguuWXxL1u3+ncAGmW2EY" + + "gEAHiOUu5c="); + + static byte[] oldKeyStore = Base64.decode( + "MIIF/jCCBUEwgZQGCSqGSIb3DQEFDTCBhjBkBgkqhkiG9w0BBQwwVwRA1njcCRF+e+s3pQsVaifZNKCablZ+5cLEeJXEdsAtJt7ZG2" + + "6dq5iYzBhbol5L5D0n9RLYFW5IoK9rCd8UpD61GAICBAACASAwDAYIKoZIhvcNAgsFADAeBglghkgBZQMEAS8wEQQMhT2rGv09UX8P" + + "pmcZAgEIBIIEpu8KeIMyG7FZL+rxPCJ7YFNRXEjykNt70W1BD8VDsN/bGuW4kCnKXNlzV2SAx/44mhdR47qiKrXziCwZUgpck9d1R5" + + "nQQtTKw0Q2F1EuWGm9ErFpCMYl6E43/URmkmjuCMIpEbrKHTmuEjqsdHJ7+CST4cFU3lCsBj7dMl9G7tLxJhq5aCTYxhFX6R5kM5QH" + + "t/pkxE/5Ei94nh606cKNjLA7Zlrbn1c5WlTpesOjE1pZp/QY9UuSiSA0nucNd8Ir0H4PK120QerdQQ4EWY/KHEDn4EqGpaE1Z6WVAS" + + "qyYING7g1q4YeYeJjFA2V8fqsj0j/wxG29x5J5ghcERnrcQGTL2P3uLvy2chgHdqIaFxKStANVntW+dy9MD/uCZnYi7DzeS3qWEZcl" + + "cpp5oImL79k08uc9jpfOnNaqbxz8b76ABH39OVQVSGRhh7fkYYSlUEWpSlaFoKaywV3yJwXlilhX7JqyiqRt/hrlVLTlQZZeJbYMrE" + + "KA/Fn2ePmNt5hJRiHzF5w/YVd5My27QtPvInCgJ2bV+Z0Di3l+Sd4SCS1NiHtR6uB7G3xlI8E3uQVV4dRNXM8drb1Uu/eTGxGSH0hY" + + "2Z0N8TvSGdz+TAQRNn/nXaMA2nZdfhVmwiRPPP3BaiBCJM6y5FroOT1rkPupA+gpmlw1M7Ey+rABphsqEig2XyRe4FMMmIc4i8ga6m" + + "KH+F0e26ycsb+nSycdhLIs5Dcdo42wzmvmoG8fvM+/C1N98TfB0m2KbtS1TV9dohagJi4l685iUMnUbH3nmha7RPYUVnpZdDokiATV" + + "WjuSezCdpIxv1m6HOqXuArvDtvExDzyVZnPoIF4DEuRypDpW8tkppvLGA6VEo1TPJvjvyrX6SqorwDa1JINVnQGPpx5StjL+eIQBzV" + + "RHoy+NP2dcPBHUlAfwWrkk7V7CwST6uNYBL+YVhTYYIN1HnJY0CkmmraqMvkMks17WAd9hONzSLmNT3St6s3VIQMMPC7qNatB+570Q" + + "BxgiQC7ieFu1wqy9ZNnNLU9DC69HR37uUFyiCnbCb54XY/zmCUhc8ONBi3L8DwmiDZ2oF7WIEmWvblcbWaQNFPNBMS9KzejHLpvopW" + + "+XcfRX4jCz9PwZ9HhUwGk8R7b1MALgJhXxuAD/a4VQK2OtlTHeAgSGBrGcGgjzSa7JWM5ks+EHdTuLaiU3ViVXLrZq4lr/D8ni1Ipt" + + "kKPaVcWnl56i7AXZtPj5xVE5v2eVual3sBOkObpoObyrDfmouZW0A9GPk69jGTm5j2FU+50p7JxSfR78BZJitBqrcYS4boVDFmTZYN" + + "MBpgGkHqW79gWKIde/pf6nf9cSnDEjZEIZJQI5rnLqmGG6+vKxJQJt7be4vCzGTVMqiY3+QgVCuwtK7Vd44RaPDnzQDxC9OwJOhIUF" + + "s1UwoS/vU/n5kbaYmD+py3dgffw4EicaOv5hG7NELZRKxueCjnVwdeCGH+WgJL7AIUdruK/SvsQbJX1asEFKU5KCG4Z9Sw0Sw4MjL+" + + "OAiyIbpQpMfHtG+9ORfWWmlH8McA3rjT07fKelhPn1YauY2jGZLfBrpBrQKxvcL82og7rUMIG2MAwGCCqGSIb3DQILBQAwZAYJKoZI" + + "hvcNAQUMMFcEQOchs+KAXDWhUaENOgpSls0plNpIUYDkgnMa/iL4RzEOCwiZBOuBdGsEfP3oKLWUS3wO83vrgetSLK5fkN6QNnoCAg" + + "QAAgFAMAwGCCqGSIb3DQILBQAEQBLCR5e4teCd8JX0xJbGadSCFaO1oEehyXSZrnKahsYJ7yTHqJTvlcWvqTiwn7Gud/SJmMXPQkZC" + + "SQhMQ5k+xZ4="); + + public void shouldCreateEmptyBCFKSNoPassword() + throws Exception + { + checkEmptyStore(null); + } + + public void shouldCreateEmptyBCFKSPassword() + throws Exception + { + checkEmptyStore(testPassword); + } + + private void checkEmptyStore(char[] passwd) + throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + } + + private void checkInvalidLoad(KeyStore store, char[] passwd, byte[] data) + throws NoSuchAlgorithmException, CertificateException, KeyStoreException + { + checkInvalidLoadForPassword(store, invalidTestPassword, data); + + if (passwd != null) + { + checkInvalidLoadForPassword(store, null, data); + } + } + + private void checkInvalidLoadForPassword(KeyStore store, char[] password, byte[] data) + throws NoSuchAlgorithmException, CertificateException, KeyStoreException + { + try + { + store.load(new ByteArrayInputStream(data), password); + } + catch (IOException e) + { + isTrue("wrong message", "BCFKS KeyStore corrupted: MAC calculation failed".equals(e.getMessage())); + } + + isTrue("", 0 == store.size()); + isTrue("", !store.aliases().hasMoreElements()); + } + + public void shouldStoreOneCertificate() + throws Exception + { + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + checkOneCertificate(cert, null); + checkOneCertificate(cert, testPassword); + } + + public void shouldStoreOneCertificateWithECDSASignature() + throws Exception + { + KeyPairGenerator kpG = KeyPairGenerator.getInstance("EC", "BC"); + + kpG.initialize(new ECGenParameterSpec("P-256")); + + KeyPair kp = kpG.generateKeyPair(); + + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setCertificateEntry("cert", cert); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "cert".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + certStorageCheck(store1, "cert", cert); + + Date entryDate = store1.getCreationDate("cert"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + BCFKSLoadStoreParameter storeParameter = new BCFKSLoadStoreParameter.Builder(bOut, kp.getPrivate()) + .withStoreSignatureAlgorithm(BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withECDSA) + .build(); + + store1.store(storeParameter); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + BCFKSLoadStoreParameter loadParameter = new BCFKSLoadStoreParameter.Builder( + new ByteArrayInputStream(bOut.toByteArray()), kp.getPublic()) + .withStoreSignatureAlgorithm(BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withECDSA) + .build(); + + store2.load(loadParameter); + } + + public void shouldStoreOneCertificateWithECDSASignatureAndCertificates() + throws Exception + { + KeyPairGenerator kpG = KeyPairGenerator.getInstance("EC", "BC"); + + kpG.initialize(new ECGenParameterSpec("P-256")); + + KeyPair kp = kpG.generateKeyPair(); + + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setCertificateEntry("cert", cert); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "cert".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + certStorageCheck(store1, "cert", cert); + + Date entryDate = store1.getCreationDate("cert"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + final X509Certificate selfSignedCert = TestUtils.createSelfSignedCert("CN=ECDSA", "SHA256withECDSA", kp); + BCFKSLoadStoreParameter storeParameter = new BCFKSLoadStoreParameter.Builder(bOut, kp.getPrivate()) + .withStoreSignatureAlgorithm(BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withECDSA) + .withCertificates( + new X509Certificate[] {selfSignedCert}) + .build(); + + store1.store(storeParameter); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + final AtomicBoolean isCalled = new AtomicBoolean(false); + + BCFKSLoadStoreParameter loadParameter = new BCFKSLoadStoreParameter.Builder( + new ByteArrayInputStream(bOut.toByteArray()), new BCFKSLoadStoreParameter.CertChainValidator() + { + public boolean isValid(X509Certificate[] chain) + { + isEquals(selfSignedCert, chain[0]); + isCalled.set(true); + return true; + } + }) + .withStoreSignatureAlgorithm(BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withECDSA) + .build(); + + store2.load(loadParameter); + + isTrue(isCalled.get()); + + loadParameter = new BCFKSLoadStoreParameter.Builder( + new ByteArrayInputStream(bOut.toByteArray()), new BCFKSLoadStoreParameter.CertChainValidator() + { + public boolean isValid(X509Certificate[] chain) + { + isEquals(selfSignedCert, chain[0]); + + return false; + } + }) + .withStoreSignatureAlgorithm(BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withECDSA) + .build(); + + try + { + store2.load(loadParameter); + fail("no exception"); + } + catch (IOException e) + { + isEquals("certificate chain in key store signature not valid", e.getMessage()); + } + } + + public void shouldStoreOneCertificateWithDSASignature() + throws Exception + { + KeyPairGenerator kpG = KeyPairGenerator.getInstance("DSA", "BC"); + + kpG.initialize(2048); + + KeyPair kp = kpG.generateKeyPair(); + + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setCertificateEntry("cert", cert); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "cert".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + certStorageCheck(store1, "cert", cert); + + Date entryDate = store1.getCreationDate("cert"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + BCFKSLoadStoreParameter storeParameter = new BCFKSLoadStoreParameter.Builder(bOut, kp.getPrivate()) + .withStoreSignatureAlgorithm(BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withDSA) + .build(); + + store1.store(storeParameter); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + BCFKSLoadStoreParameter loadParameter = new BCFKSLoadStoreParameter.Builder( + new ByteArrayInputStream(bOut.toByteArray()), kp.getPublic()) + .withStoreSignatureAlgorithm(BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withDSA) + .build(); + + store2.load(loadParameter); + } + + public void shouldStoreOneCertificateWithRSASignature() + throws Exception + { + KeyPairGenerator kpG = KeyPairGenerator.getInstance("RSA", "BC"); + + kpG.initialize(2048); + + KeyPair kp = kpG.generateKeyPair(); + + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setCertificateEntry("cert", cert); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "cert".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + certStorageCheck(store1, "cert", cert); + + Date entryDate = store1.getCreationDate("cert"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + BCFKSLoadStoreParameter storeParameter = new BCFKSLoadStoreParameter.Builder(bOut, kp.getPrivate()) + .withStoreSignatureAlgorithm(BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withRSA) + .build(); + + store1.store(storeParameter); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + BCFKSLoadStoreParameter loadParameter = new BCFKSLoadStoreParameter.Builder( + new ByteArrayInputStream(bOut.toByteArray()), kp.getPublic()) + .withStoreSignatureAlgorithm(BCFKSLoadStoreParameter.SignatureAlgorithm.SHA512withRSA) + .build(); + + store2.load(loadParameter); + } + + private void checkOneCertificate(X509Certificate cert, char[] passwd) + throws KeyStoreException, NoSuchProviderException, IOException, NoSuchAlgorithmException, CertificateException + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setCertificateEntry("cert", cert); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "cert".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + certStorageCheck(store1, "cert", cert); + + Date entryDate = store1.getCreationDate("cert"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", entryDate.equals(store2.getCreationDate("cert"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "cert".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + certStorageCheck(store2, "cert", cert); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("cert"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + public void shouldStoreOnePrivateKey() + throws Exception + { + PrivateKey privKey = getPrivateKey(); + + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + checkOnePrivateKeyFips(privKey, new X509Certificate[]{cert}, null); + checkOnePrivateKeyFips(privKey, new X509Certificate[]{cert}, testPassword); + checkOnePrivateKeyDef(privKey, new X509Certificate[]{cert}, null); + checkOnePrivateKeyDef(privKey, new X509Certificate[]{cert}, testPassword); + } + + public void shouldStoreOnePrivateKeyWithChain() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withRSA", + null, + kp1.getPublic()); + + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + } + + public void shouldStoreOneECKeyWithChain() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(256); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withECDSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withECDSA", + null, + kp1.getPublic()); + + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyFips(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, null); + checkOnePrivateKeyDef(kp1.getPrivate(), new X509Certificate[]{interCert, finalCert}, testPassword); + } + + public void shouldRejectInconsistentKeys() + throws Exception + { + PrivateKey privKey = getPrivateKey(); + + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.interCertBin)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + try + { + store1.setKeyEntry("privkey", privKey, "hello".toCharArray(), new X509Certificate[]{interCert}); + fail("no exception"); + } + catch (KeyStoreException e) + { + isTrue("", "RSA keys do not have the same modulus".equals(e.getCause().getMessage())); + } + } + + private void checkOnePrivateKeyFips(PrivateKey key, X509Certificate[] certs, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + checkOnePrivateKey(key, store1, certs, passwd); + } + + private void checkOnePrivateKeyDef(PrivateKey key, X509Certificate[] certs, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS-DEF", "BC"); + + store1.load(null, null); + + checkOnePrivateKey(key, store1, certs, passwd); + } + + private void checkOnePrivateKey(PrivateKey key, KeyStore store1, X509Certificate[] certs, char[] passwd) + throws Exception + { + store1.setKeyEntry("privkey", key, passwd, certs); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "privkey".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + privateKeyStorageCheck(store1, "privkey", key, certs[0], passwd); + + Date entryDate = store1.getCreationDate("privkey"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", store2.getCertificateChain("privkey").length == certs.length); + Certificate[] sChain = store2.getCertificateChain("privkey"); + for (int i = 0; i != sChain.length; i++) + { + isTrue("", certs[i].equals(sChain[i])); + } + isTrue("", entryDate.equals(store2.getCreationDate("privkey"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "privkey".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + privateKeyStorageCheck(store2, "privkey", key, certs[0], passwd); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("privkey"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + public void shouldStoreMultipleKeys() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2); + X509Certificate interCert = TestUtils.createCert( + TestUtils.getCertSubject(finalCert), + kp2.getPrivate(), + "CN=EE", + "SHA1withRSA", + null, + kp1.getPublic()); + + PrivateKey privKey = kp1.getPrivate(); + + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(trustedCertData)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setKeyEntry("privkey", privKey, testPassword, new X509Certificate[]{interCert, finalCert}); + store1.setCertificateEntry("trusted", cert); + SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES"); + store1.setKeyEntry("secret1", aesKey, "secretPwd1".toCharArray(), null); + SecretKeySpec edeKey = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede"); + store1.setKeyEntry("secret2", edeKey, "secretPwd2".toCharArray(), null); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, testPassword); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), testPassword); + + isTrue("", 4 == store2.size()); + + Key storeDesEde = store2.getKey("secret2", "secretPwd2".toCharArray()); + + isTrue("", edeKey.getAlgorithm().equals(storeDesEde.getAlgorithm())); + + isTrue("", Arrays.areEqual(edeKey.getEncoded(), storeDesEde.getEncoded())); + + Key storeAes = store2.getKey("secret1", "secretPwd1".toCharArray()); + isTrue("", Arrays.areEqual(aesKey.getEncoded(), storeAes.getEncoded())); + isTrue("", aesKey.getAlgorithm().equals(storeAes.getAlgorithm())); + + Key storePrivKey = store2.getKey("privkey", testPassword); + isTrue("", privKey.equals(storePrivKey)); + isTrue("", 2 == store2.getCertificateChain("privkey").length); + + Certificate storeCert = store2.getCertificate("trusted"); + isTrue("", cert.equals(storeCert)); + + isTrue("", null == store2.getCertificate("unknown")); + + isTrue("", null == store2.getCertificateChain("unknown")); + + isTrue("", !store2.isCertificateEntry("unknown")); + + isTrue("", !store2.isKeyEntry("unknown")); + + isTrue("", !store2.containsAlias("unknown")); + } + + public void shouldParseKWPKeyStore() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(trustedCertData)); + + SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES"); + SecretKeySpec edeKey = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede"); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(kwpKeyStore), testPassword); + + isTrue("", 4 == store2.size()); + + Key storeDesEde = store2.getKey("secret2", "secretPwd2".toCharArray()); + + isTrue("", edeKey.getAlgorithm().equals(storeDesEde.getAlgorithm())); + + isTrue("", Arrays.areEqual(edeKey.getEncoded(), storeDesEde.getEncoded())); + + Key storeAes = store2.getKey("secret1", "secretPwd1".toCharArray()); + isTrue("", Arrays.areEqual(aesKey.getEncoded(), storeAes.getEncoded())); + isTrue("", aesKey.getAlgorithm().equals(storeAes.getAlgorithm())); + + Key storePrivKey = store2.getKey("privkey", testPassword); + isTrue("", 2 == store2.getCertificateChain("privkey").length); + isTrue("", storePrivKey instanceof RSAPrivateCrtKey); + + Certificate storeCert = store2.getCertificate("trusted"); + isTrue("", cert.equals(storeCert)); + + isTrue("", null == store2.getCertificate("unknown")); + + isTrue("", null == store2.getCertificateChain("unknown")); + + isTrue("", !store2.isCertificateEntry("unknown")); + + isTrue("", !store2.isKeyEntry("unknown")); + + isTrue("", !store2.containsAlias("unknown")); + } + + public void shouldStoreSecretKeys() + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + SecretKeySpec aesKey = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "AES"); + SecretKeySpec edeKey1 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "DESede"); + SecretKeySpec edeKey2 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "TripleDES"); + SecretKeySpec edeKey3 = new SecretKeySpec(Hex.decode("010102020404070708080b0b0d0d0e0e"), "TDEA"); + SecretKeySpec hmacKey1 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff"), "HmacSHA1"); + SecretKeySpec hmacKey224 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff"), "HmacSHA224"); + SecretKeySpec hmacKey256 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff01ff"), "HmacSHA256"); + SecretKeySpec hmacKey384 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff0102ff"), "HmacSHA384"); + SecretKeySpec hmacKey512 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0eff010203ff"), "HmacSHA512"); + + SecretKeySpec camellia128 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "Camellia"); + SecretKeySpec camellia192 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f0001020304050607"), "Camellia"); + SecretKeySpec camellia256 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "Camellia"); + SecretKeySpec seed = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "SEED"); + SecretKeySpec aria128 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "ARIA"); + SecretKeySpec aria192 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f0001020304050607"), "ARIA"); + SecretKeySpec aria256 = new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f000102030405060708090a0b0c0d0e0f"), "ARIA"); + + store1.setKeyEntry("secret1", aesKey, "secretPwd1".toCharArray(), null); + store1.setKeyEntry("secret2", edeKey1, "secretPwd2".toCharArray(), null); + store1.setKeyEntry("secret3", edeKey2, "secretPwd3".toCharArray(), null); + store1.setKeyEntry("secret4", edeKey3, "secretPwd4".toCharArray(), null); + store1.setKeyEntry("secret5", hmacKey1, "secretPwd5".toCharArray(), null); + store1.setKeyEntry("secret6", hmacKey224, "secretPwd6".toCharArray(), null); + store1.setKeyEntry("secret7", hmacKey256, "secretPwd7".toCharArray(), null); + store1.setKeyEntry("secret8", hmacKey384, "secretPwd8".toCharArray(), null); + store1.setKeyEntry("secret9", hmacKey512, "secretPwd9".toCharArray(), null); + + store1.setKeyEntry("secret10", camellia128, "secretPwd10".toCharArray(), null); + store1.setKeyEntry("secret11", camellia192, "secretPwd11".toCharArray(), null); + store1.setKeyEntry("secret12", camellia256, "secretPwd12".toCharArray(), null); + store1.setKeyEntry("secret13", seed, "secretPwd13".toCharArray(), null); + store1.setKeyEntry("secret14", aria128, "secretPwd14".toCharArray(), null); + store1.setKeyEntry("secret15", aria192, "secretPwd15".toCharArray(), null); + store1.setKeyEntry("secret16", aria256, "secretPwd16".toCharArray(), null); + + checkSecretKey(store1, "secret1", "secretPwd1".toCharArray(), aesKey); + checkSecretKey(store1, "secret2", "secretPwd2".toCharArray(), edeKey1); // TRIPLEDES and TDEA will convert to DESEDE + checkSecretKey(store1, "secret3", "secretPwd3".toCharArray(), edeKey1); + checkSecretKey(store1, "secret4", "secretPwd4".toCharArray(), edeKey1); + // TODO: +// checkSecretKey(store1, "secret5", "secretPwd5".toCharArray(), hmacKey1); +// checkSecretKey(store1, "secret6", "secretPwd6".toCharArray(), hmacKey224); +// checkSecretKey(store1, "secret7", "secretPwd7".toCharArray(), hmacKey256); +// checkSecretKey(store1, "secret8", "secretPwd8".toCharArray(), hmacKey384); +// checkSecretKey(store1, "secret9", "secretPwd9".toCharArray(), hmacKey512); + + checkSecretKey(store1, "secret10", "secretPwd10".toCharArray(), camellia128); + checkSecretKey(store1, "secret11", "secretPwd11".toCharArray(), camellia192); + checkSecretKey(store1, "secret12", "secretPwd12".toCharArray(), camellia256); + checkSecretKey(store1, "secret13", "secretPwd13".toCharArray(), seed); + checkSecretKey(store1, "secret14", "secretPwd14".toCharArray(), aria128); + checkSecretKey(store1, "secret15", "secretPwd15".toCharArray(), aria192); + checkSecretKey(store1, "secret16", "secretPwd16".toCharArray(), aria256); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, "secretkeytest".toCharArray()); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), "secretkeytest".toCharArray()); + + checkSecretKey(store2, "secret1", "secretPwd1".toCharArray(), aesKey); + checkSecretKey(store2, "secret2", "secretPwd2".toCharArray(), edeKey1); // TRIPLEDES and TDEA will convert to DESEDE + checkSecretKey(store2, "secret3", "secretPwd3".toCharArray(), edeKey1); + checkSecretKey(store2, "secret4", "secretPwd4".toCharArray(), edeKey1); + // TODO: +// checkSecretKey(store2, "secret5", "secretPwd5".toCharArray(), hmacKey1); +// checkSecretKey(store2, "secret6", "secretPwd6".toCharArray(), hmacKey224); +// checkSecretKey(store2, "secret7", "secretPwd7".toCharArray(), hmacKey256); +// checkSecretKey(store2, "secret8", "secretPwd8".toCharArray(), hmacKey384); +// checkSecretKey(store2, "secret9", "secretPwd9".toCharArray(), hmacKey512); + + isTrue("", null == store2.getKey("secret17", new char[0])); + } + + public void shouldFailOnWrongPassword() + throws Exception + { + failOnWrongPasswordTest("IBCFKS"); + failOnWrongPasswordTest("IBCFKS-DEF"); + } + + public void failOnWrongPasswordTest(String storeName) + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2); + X509Certificate interCert = TestUtils.createCert( + X500Name.getInstance(finalCert.getSubjectX500Principal().getEncoded()), + kp2.getPrivate(), + "CN=EE", + "SHA1withRSA", + null, + kp1.getPublic()); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setKeyEntry("privkey", kp1.getPrivate(), testPassword, new X509Certificate[]{interCert, finalCert}); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, testPassword); + + store1 = KeyStore.getInstance(storeName, "BC"); + + store1.load(new ByteArrayInputStream(bOut.toByteArray()), testPassword); + + isTrue("privKey test 1", store1.getKey("privkey", testPassword) != null); + + try + { + store1.getKey("privkey", invalidTestPassword); + fail("no exception"); + } + catch (UnrecoverableKeyException e) + { + isEquals("wrong message, got : " + e.getMessage(), "unable to recover key (privkey)", e.getMessage()); + } + + isTrue("privKey test 2", store1.getKey("privkey", testPassword) != null); + } + + private void checkSecretKey(KeyStore store, String alias, char[] passwd, SecretKey key) + throws Exception + { + SecretKey sKey = (SecretKey)store.getKey(alias, passwd); + + isTrue("", Arrays.areEqual(key.getEncoded(), sKey.getEncoded())); + isTrue("", key.getAlgorithm().equals(sKey.getAlgorithm())); + + if (!store.isKeyEntry(alias)) + { + fail("key not identified as key entry"); + } + if (!store.entryInstanceOf(alias, KeyStore.SecretKeyEntry.class)) + { + fail("not identified as key entry via SecretKeyEntry"); + } + } + + private PrivateKey getPrivateKey() + { + PrivateKey privKey = null; + + RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16), + new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16), + new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16), + new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16), + new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16), + new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16), + new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16)); + + + try + { + KeyFactory fact = KeyFactory.getInstance("RSA", "BC"); + + privKey = fact.generatePrivate(privKeySpec); + } + catch (Exception e) + { + fail("error setting up keys - " + e.toString()); + } + + return privKey; + } + + public void shouldFailOnRemovesOrOverwrite() + throws Exception + { + failOnRemovesOrOverwrite("IBCFKS"); + failOnRemovesOrOverwrite("IBCFKS-DEF"); + } + + private void failOnRemovesOrOverwrite(String storeName) + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + X509Certificate finalCert = TestUtils.createSelfSignedCert("CN=Final", "SHA1withRSA", kp2); + X509Certificate interCert = TestUtils.createCert( + X500Name.getInstance(finalCert.getSubjectX500Principal().getEncoded()), + kp2.getPrivate(), + "CN=EE", + "SHA1withRSA", + null, + kp1.getPublic()); + + KeyStore store1 = KeyStore.getInstance(storeName, "BC"); + + store1.load(new ByteArrayInputStream(oldKeyStoreNoPW), null); + + try + { + store1.setKeyEntry("privkey", kp1.getPrivate(), testPassword, new X509Certificate[]{interCert, finalCert}); + fail("no exception"); + } + catch (KeyStoreException e) + { + isTrue("set operation not supported in shared mode".equals(e.getMessage())); + } + + try + { + store1.setKeyEntry("privkey", kp1.getPrivate().getEncoded(), new X509Certificate[]{interCert, finalCert}); + fail("no exception"); + } + catch (KeyStoreException e) + { + isTrue("set operation not supported in shared mode".equals(e.getMessage())); + } + + try + { + store1.setCertificateEntry("cert", interCert); + fail("no exception"); + } + catch (KeyStoreException e) + { + isTrue("set operation not supported in shared mode".equals(e.getMessage())); + } + + try + { + store1.deleteEntry("privkey"); + fail("no exception"); + } + catch (KeyStoreException e) + { + isTrue("delete operation not supported in shared mode".equals(e.getMessage())); + } + } + + public void shouldStoreOneSecretKey() + throws Exception + { + checkOneSecretKey(new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "AES"), null); + checkOneSecretKey(new SecretKeySpec(Hex.decode("000102030405060708090a0b0c0d0e0f"), "AES"), testPassword); + } + + private void checkOneSecretKey(SecretKey key, char[] passwd) + throws Exception + { + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setKeyEntry("seckey", key, passwd, null); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "seckey".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + secretKeyStorageCheck(store1, "seckey", key, passwd); + + Date entryDate = store1.getCreationDate("seckey"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", entryDate.equals(store2.getCreationDate("seckey"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "seckey".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + secretKeyStorageCheck(store2, "seckey", key, passwd); + + // check invalid load with content + + checkInvalidLoad(store2, passwd, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("seckey"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + } + + private void privateKeyStorageCheck(KeyStore store, String keyName, PrivateKey key, Certificate cert, char[] password) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException + { + if (!store.containsAlias(keyName)) + { + fail("couldn't find alias privateKey"); + } + + if (store.isCertificateEntry(keyName)) + { + fail("key identified as certificate entry"); + } + + if (!store.isKeyEntry(keyName)) + { + fail("key not identified as key entry"); + } + + Key storeKey = store.getKey(keyName, password); + + if (store.getType().equals("BCFKS")) + { + isTrue("", key.equals(storeKey)); + } + + if (password != null) + { + try + { + store.getKey(keyName, null); + } + catch (UnrecoverableKeyException e) + { + isTrue("", e.getMessage().startsWith("BCFKS KeyStore unable to recover private key (privkey)")); + } + } + + Certificate[] certificateChain = store.getCertificateChain(keyName); + if (certificateChain == null) + { + fail("Did not return certificate chain"); + } + isTrue("", cert.equals(certificateChain[0])); + + isTrue("", keyName.equals(store.getCertificateAlias(cert))); + + if (store.entryInstanceOf(keyName, KeyStore.TrustedCertificateEntry.class)) + { + fail("identified as TrustedCertificateEntry"); + } + + if (!store.entryInstanceOf(keyName, KeyStore.PrivateKeyEntry.class)) + { + fail("not identified as key entry via PrivateKeyEntry"); + } + + if (store.entryInstanceOf(keyName, KeyStore.SecretKeyEntry.class)) + { + fail("identified as key entry via SecretKeyEntry"); + } + } + + private void certStorageCheck(KeyStore store, String certName, Certificate cert) + throws KeyStoreException + { + if (!store.containsAlias(certName)) + { + fail("couldn't find alias " + certName); + } + + if (!store.isCertificateEntry(certName)) + { + fail("cert not identified as certificate entry"); + } + + if (store.isKeyEntry(certName)) + { + fail("cert identified as key entry"); + } + + if (!store.entryInstanceOf(certName, KeyStore.TrustedCertificateEntry.class)) + { + fail("cert not identified as TrustedCertificateEntry"); + } + + if (store.entryInstanceOf(certName, KeyStore.PrivateKeyEntry.class)) + { + fail("cert identified as key entry via PrivateKeyEntry"); + } + + if (store.entryInstanceOf(certName, KeyStore.SecretKeyEntry.class)) + { + fail("cert identified as key entry via SecretKeyEntry"); + } + + if (!certName.equals(store.getCertificateAlias(cert))) + { + fail("Did not return alias for certificate entry"); + } + } + + private void secretKeyStorageCheck(KeyStore store, String keyName, SecretKey key, char[] password) + throws KeyStoreException, UnrecoverableKeyException, NoSuchAlgorithmException + { + if (!store.containsAlias(keyName)) + { + fail("couldn't find alias privateKey"); + } + + if (store.isCertificateEntry(keyName)) + { + fail("key identified as certificate entry"); + } + + if (!store.isKeyEntry(keyName)) + { + fail("key not identified as key entry"); + } + + Key storeKey = store.getKey(keyName, password); + + isTrue("", Arrays.areEqual(key.getEncoded(), storeKey.getEncoded())); + + if (password != null) + { + try + { + store.getKey(keyName, null); + } + catch (UnrecoverableKeyException e) + { + isTrue("", e.getMessage().startsWith("BCFKS KeyStore unable to recover secret key (seckey)")); + } + } + + Certificate[] certificateChain = store.getCertificateChain(keyName); + if (certificateChain != null) + { + fail("returned certificates!"); + } + + if (store.entryInstanceOf(keyName, KeyStore.TrustedCertificateEntry.class)) + { + fail("identified as TrustedCertificateEntry"); + } + + if (store.entryInstanceOf(keyName, KeyStore.PrivateKeyEntry.class)) + { + fail("identified as key entry via PrivateKeyEntry"); + } + + if (!store.entryInstanceOf(keyName, KeyStore.SecretKeyEntry.class)) + { + fail("not identified as key entry via SecretKeyEntry"); + } + } + + private void shouldParseOldStores() + throws Exception + { + KeyStore store = KeyStore.getInstance("BCFKS", "BC"); + + store.load(new ByteArrayInputStream(oldKeyStore), testPassword); + + checkStore(store, oldKeyStore, testPassword); + + store.load(new ByteArrayInputStream(oldKeyStoreNoPW), null); + + checkStore(store, oldKeyStoreNoPW, null); + } + + private void checkStore(KeyStore store1, byte[] data, char[] passwd) + throws Exception + { + isEquals(store1.getCertificateChain("privkey").length, 2); + isEquals(1, store1.size()); + Enumeration en2 = store1.aliases(); + + isEquals("privkey", en2.nextElement()); + isTrue(!en2.hasMoreElements()); + + // check invalid load with content + + checkInvalidLoad(store1, passwd, data); + + try + { + store1.store(new ByteArrayOutputStream(), passwd); + fail("no exception"); + } + catch (IOException e) + { + isEquals("KeyStore not initialized", e.getMessage()); + } + + // check deletion on purpose + + store1.load(new ByteArrayInputStream(data), passwd); + + store1.deleteEntry("privkey"); + + isEquals(0, store1.size()); + isTrue(!store1.aliases().hasMoreElements()); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, passwd); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + isEquals(0, store2.size()); + isTrue(!store2.aliases().hasMoreElements()); + } + + private void shouldStoreUsingSCRYPT() + throws Exception + { + byte[] enc = doStoreUsingStoreParameter(new ScryptConfig.Builder(1024, 8, 1) + .withSaltLength(20).build()); + + ObjectStore store = ObjectStore.getInstance(enc); + + ObjectStoreIntegrityCheck integrityCheck = store.getIntegrityCheck(); + + isEquals(integrityCheck.getType(), ObjectStoreIntegrityCheck.PBKD_MAC_CHECK); + + PbkdMacIntegrityCheck check = PbkdMacIntegrityCheck.getInstance(integrityCheck.getIntegrityCheck()); + + isTrue("wrong MAC", check.getMacAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_hmacWithSHA512)); + isTrue("wrong PBE", check.getPbkdAlgorithm().getAlgorithm().equals(MiscObjectIdentifiers.id_scrypt)); + + ScryptParams sParams = ScryptParams.getInstance(check.getPbkdAlgorithm().getParameters()); + + isEquals(20, sParams.getSalt().length); + isEquals(1024, sParams.getCostParameter().intValue()); + isEquals(8, sParams.getBlockSize().intValue()); + isEquals(1, sParams.getParallelizationParameter().intValue()); + + EncryptedObjectStoreData objStore = EncryptedObjectStoreData.getInstance(store.getStoreData()); + + AlgorithmIdentifier encryptionAlgorithm = objStore.getEncryptionAlgorithm(); + isTrue(encryptionAlgorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_PBES2)); + + PBES2Parameters pbeParams = PBES2Parameters.getInstance(encryptionAlgorithm.getParameters()); + + isTrue(pbeParams.getKeyDerivationFunc().getAlgorithm().equals(MiscObjectIdentifiers.id_scrypt)); + + sParams = ScryptParams.getInstance(pbeParams.getKeyDerivationFunc().getParameters()); + + isEquals(20, sParams.getSalt().length); + isEquals(1024, sParams.getCostParameter().intValue()); + isEquals(8, sParams.getBlockSize().intValue()); + isEquals(1, sParams.getParallelizationParameter().intValue()); + } + + private void shouldStoreUsingKWP() + throws Exception + { + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(new BCFKSLoadStoreParameter.Builder().withStoreEncryptionAlgorithm(BCFKSLoadStoreParameter.EncryptionAlgorithm.AES256_KWP).build()); + + store1.setCertificateEntry("cert", cert); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(bOut, testPassword); + + byte[] enc = bOut.toByteArray(); + + ObjectStore store = ObjectStore.getInstance(enc); + + ObjectStoreIntegrityCheck integrityCheck = store.getIntegrityCheck(); + + isEquals(integrityCheck.getType(), ObjectStoreIntegrityCheck.PBKD_MAC_CHECK); + + PbkdMacIntegrityCheck check = PbkdMacIntegrityCheck.getInstance(integrityCheck.getIntegrityCheck()); + + isTrue("wrong MAC", check.getMacAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_hmacWithSHA512)); + isTrue("wrong PBE", check.getPbkdAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_PBKDF2)); + + EncryptedObjectStoreData objStore = EncryptedObjectStoreData.getInstance(store.getStoreData()); + + AlgorithmIdentifier encryptionAlgorithm = objStore.getEncryptionAlgorithm(); + isTrue(encryptionAlgorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_PBES2)); + + PBES2Parameters pbeParams = PBES2Parameters.getInstance(encryptionAlgorithm.getParameters()); + + isTrue(pbeParams.getKeyDerivationFunc().getAlgorithm().equals(PKCSObjectIdentifiers.id_PBKDF2)); + + isTrue(pbeParams.getEncryptionScheme().getAlgorithm().equals(NISTObjectIdentifiers.id_aes256_wrap_pad)); + } + + private void shouldStoreUsingPBKDF2() + throws Exception + { + doStoreUsingPBKDF2(PBKDF2Config.PRF_SHA512); + doStoreUsingPBKDF2(PBKDF2Config.PRF_SHA3_512); + } + + private void doStoreUsingPBKDF2(AlgorithmIdentifier prf) + throws Exception + { + byte[] enc = doStoreUsingStoreParameter(new PBKDF2Config.Builder() + .withPRF(prf) + .withIterationCount(1024) + .withSaltLength(20).build()); + + ObjectStore store = ObjectStore.getInstance(enc); + + ObjectStoreIntegrityCheck integrityCheck = store.getIntegrityCheck(); + + isEquals(integrityCheck.getType(), ObjectStoreIntegrityCheck.PBKD_MAC_CHECK); + + PbkdMacIntegrityCheck check = PbkdMacIntegrityCheck.getInstance(integrityCheck.getIntegrityCheck()); + + isTrue("wrong MAC", check.getMacAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_hmacWithSHA512)); + isTrue("wrong PBE", check.getPbkdAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_PBKDF2)); + + PBKDF2Params pParams = PBKDF2Params.getInstance(check.getPbkdAlgorithm().getParameters()); + + isTrue(pParams.getPrf().equals(prf)); + isEquals(20, pParams.getSalt().length); + isEquals(1024, pParams.getIterationCount().intValue()); + + EncryptedObjectStoreData objStore = EncryptedObjectStoreData.getInstance(store.getStoreData()); + + AlgorithmIdentifier encryptionAlgorithm = objStore.getEncryptionAlgorithm(); + isTrue(encryptionAlgorithm.getAlgorithm().equals(PKCSObjectIdentifiers.id_PBES2)); + + PBES2Parameters pbeParams = PBES2Parameters.getInstance(encryptionAlgorithm.getParameters()); + + isTrue(pbeParams.getKeyDerivationFunc().getAlgorithm().equals(PKCSObjectIdentifiers.id_PBKDF2)); + + pParams = PBKDF2Params.getInstance(check.getPbkdAlgorithm().getParameters()); + + isTrue(pParams.getPrf().equals(prf)); + isEquals(20, pParams.getSalt().length); + isEquals(1024, pParams.getIterationCount().intValue()); + } + + private byte[] doStoreUsingStoreParameter(PBKDFConfig config) + throws Exception + { + X509Certificate cert = (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(trustedCertData)); + + KeyStore store1 = KeyStore.getInstance("BCFKS", "BC"); + + store1.load(null, null); + + store1.setCertificateEntry("cert", cert); + + isTrue("", 1 == store1.size()); + Enumeration en1 = store1.aliases(); + + isTrue("", "cert".equals(en1.nextElement())); + isTrue("", !en1.hasMoreElements()); + + certStorageCheck(store1, "cert", cert); + + Date entryDate = store1.getCreationDate("cert"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store1.store(new BCFKSLoadStoreParameter.Builder(bOut, testPassword).withStorePBKDFConfig(config).build()); + + KeyStore store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), testPassword); + + isTrue("", entryDate.equals(store2.getCreationDate("cert"))); + isTrue("", 1 == store2.size()); + Enumeration en2 = store2.aliases(); + + isTrue("", "cert".equals(en2.nextElement())); + isTrue("", !en2.hasMoreElements()); + + certStorageCheck(store2, "cert", cert); + + // check invalid load with content + + checkInvalidLoad(store2, testPassword, bOut.toByteArray()); + + // check deletion on purpose + + store1.deleteEntry("cert"); + + isTrue("", 0 == store1.size()); + isTrue("", !store1.aliases().hasMoreElements()); + + bOut = new ByteArrayOutputStream(); + + store1.store(bOut, testPassword); + + store2 = KeyStore.getInstance("BCFKS", "BC"); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), testPassword); + + isTrue("", 0 == store2.size()); + isTrue("", !store2.aliases().hasMoreElements()); + + return bOut.toByteArray(); + } + + public String getName() + { + return "BCFKS"; + } + + public void performTest() + throws Exception + { + shouldCreateEmptyBCFKSNoPassword(); + shouldCreateEmptyBCFKSPassword(); + shouldStoreMultipleKeys(); + shouldStoreOneCertificate(); + shouldStoreOneCertificateWithECDSASignature(); + shouldStoreOneCertificateWithDSASignature(); + shouldStoreOneCertificateWithRSASignature(); + shouldStoreOneCertificateWithECDSASignatureAndCertificates(); + shouldStoreOneECKeyWithChain(); + shouldStoreOnePrivateKey(); + shouldStoreOnePrivateKeyWithChain(); + shouldStoreOneSecretKey(); + shouldStoreSecretKeys(); + shouldStoreUsingSCRYPT(); + shouldStoreUsingPBKDF2(); + shouldFailOnWrongPassword(); + shouldParseKWPKeyStore(); + shouldFailOnRemovesOrOverwrite(); + shouldParseOldStores(); + shouldStoreUsingKWP(); + //shouldRejectInconsistentKeys(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new BCFKSStoreTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/BaseBlockCipherTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/BaseBlockCipherTest.java new file mode 100644 index 000000000..5fe1b5c36 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/BaseBlockCipherTest.java @@ -0,0 +1,172 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Key; +import java.security.SecureRandom; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +public abstract class BaseBlockCipherTest + extends SimpleTest +{ + String algorithm; + + BaseBlockCipherTest( + String algorithm) + { + this.algorithm = algorithm; + } + + public String getName() + { + return algorithm; + } + + protected void oidTest(String[] oids, String[] names, int groupSize) + throws Exception + { + byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + IvParameterSpec ivSpec = new IvParameterSpec(new byte[16]); + + for (int i = 0; i != oids.length; i++) + { + Cipher c1 = Cipher.getInstance(oids[i], "BC"); + Cipher c2 = Cipher.getInstance(names[i], "BC"); + KeyGenerator kg = KeyGenerator.getInstance(oids[i], "BC"); + + SecretKey k = kg.generateKey(); + + if (names[i].indexOf("/ECB/") > 0) + { + c1.init(Cipher.ENCRYPT_MODE, k); + c2.init(Cipher.DECRYPT_MODE, k); + } + else + { + c1.init(Cipher.ENCRYPT_MODE, k, ivSpec); + c2.init(Cipher.DECRYPT_MODE, k, ivSpec); + } + + byte[] result = c2.doFinal(c1.doFinal(data)); + + if (!areEqual(data, result)) + { + fail("failed OID test"); + } + + if (k.getEncoded().length != (16 + ((i / groupSize) * 8))) + { + fail("failed key length test"); + } + } + } + + protected void wrapOidTest(String[] oids, String name) + throws Exception + { + byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}; + + for (int i = 0; i != oids.length; i++) + { + Cipher c1 = Cipher.getInstance(oids[i], "BC"); + Cipher c2 = Cipher.getInstance(name, "BC"); + KeyGenerator kg = KeyGenerator.getInstance(oids[i], "BC"); + + SecretKey k = kg.generateKey(); + + c1.init(Cipher.WRAP_MODE, k); + c2.init(Cipher.UNWRAP_MODE, k); + + Key wKey = c2.unwrap(c1.wrap(new SecretKeySpec(data, algorithm)), algorithm, Cipher.SECRET_KEY); + + if (!areEqual(data, wKey.getEncoded())) + { + fail("failed wrap OID test"); + } + + if (k.getEncoded().length != (16 + (i * 8))) + { + fail("failed key length test"); + } + } + } + + protected void wrapTest( + int id, + String wrappingAlgorithm, + byte[] kek, + byte[] in, + byte[] out) + throws Exception + { + wrapTest(id, wrappingAlgorithm, kek, null, null, in, out); + } + + protected void wrapTest( + int id, + String wrappingAlgorithm, + byte[] kek, + byte[] iv, + SecureRandom rand, + byte[] in, + byte[] out) + throws Exception + { + Cipher wrapper = Cipher.getInstance(wrappingAlgorithm, "BC"); + + if (iv != null) + { + wrapper.init(Cipher.WRAP_MODE, new SecretKeySpec(kek, algorithm), new IvParameterSpec(iv), rand); + } + else + { + wrapper.init(Cipher.WRAP_MODE, new SecretKeySpec(kek, algorithm), rand); + } + + try + { + byte[] cText = wrapper.wrap(new SecretKeySpec(in, algorithm)); + if (!areEqual(cText, out)) + { + fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail("failed wrap test exception " + e.toString(), e); + } + + if (iv != null) + { + wrapper.init(Cipher.UNWRAP_MODE, new SecretKeySpec(kek, algorithm), new IvParameterSpec(iv)); + } + else + { + wrapper.init(Cipher.UNWRAP_MODE, new SecretKeySpec(kek, algorithm)); + } + + try + { + Key pText = wrapper.unwrap(out, algorithm, Cipher.SECRET_KEY); + if (!areEqual(pText.getEncoded(), in)) + { + fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText.getEncoded()))); + } + } + catch (Exception e) + { + fail("failed unwrap test exception " + e.toString(), e); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/BlockCipherTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/BlockCipherTest.java new file mode 100644 index 000000000..5c66e344e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/BlockCipherTest.java @@ -0,0 +1,1630 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.util.HashSet; +import java.util.Set; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.DESedeKeySpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.RC2ParameterSpec; +import javax.crypto.spec.RC5ParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +/** + * basic test class for a block cipher, basically this just exercises the provider, and makes sure we + * are behaving sensibly, correctness of the implementation is shown in the lightweight test classes. + */ +public class BlockCipherTest + extends SimpleTest +{ + private static Set shortIvOkay = new HashSet(); + + static + { + shortIvOkay.add("EAX"); + shortIvOkay.add("OCB"); + shortIvOkay.add("CCM"); + shortIvOkay.add("GCM"); + shortIvOkay.add("SIC"); + shortIvOkay.add("CTR"); + } + + static String[] cipherTests1 = + { + "DES", + "466da00648ef0e1f9617b1f002e225251a3248d09172f46b9617b1f002e225250112ecb3da61bc99", + "DESede", + "2f4bc6b30c893fa549d82c560d61cf3eb088aed020603de249d82c560d61cf3e529e95ecd8e05394", + "SKIPJACK", + "d4de46d52274dbb029f33b076043f8c40089f906751623de29f33b076043f8c4ac99b90f9396cb04", + "Blowfish", + "7870ebe7f6a52803eb9396ba6c5198216ce81d76d8d4c74beb9396ba6c5198211212473b05214e9f", + "GOST28147", + "0a77f4114451b37d44c5192619b723dd49093d1047c2373544c5192619b723dd06618da5b04d3670", + "Twofish", + "70336d9c9718a8a2ced1b19deed973a3c58af7ea71a69e7efc4df082dca581c0839e31468661bcfc57a14899ceeb0253", + "RC2", + "eb5b889bbcced12eb6b1a3da6a3d965bba66a5edfdd4c8a6b6b1a3da6a3d965b994a5b859e765797", + "RC5", + "220053543e3eca3bc9503a091ca67b08372560d8a4fdbee8c9503a091ca67b08a796d53bb8a4b7e0", + "RC5-64", + "e0b4a526ba3bc5f09199c3b1fe3737fe6d248cde70e565b0feea59ebfda375ae1946c386a48d8d8a74d7b1947ff6a788", + "RC6", + "44c97b67ca8486067f8b6c5b97632f3049e5e52c1d61fdd527dc3da39616540f19a3db39aac1ffd713795cd886cce0c0", + "IDEA", + "8c9fd56823ffdc523f6ccf7f614aa6173553e594fc7a21b53f6ccf7f614aa61740c54f7a66e95108", + "TEA", + "fcf45062104fda7c35712368b56dd4216a6ca998dc297b5435712368b56dd421208027ed2923cd0c", + "XTEA", + "4b427893d3d6aaded2afafabe25f7b233fb5589faa2b6389d2afafabe25f7b239d12979ac67e1c07", + "Camellia", + "3a68b4ad145bc2c76010669d68f2826359887afce763a78d9994143266adfaec8ba7ee562a1688ef9dfd7f897e5c44dc", + "SEED", + "d53d4ce1f48b9879420949467bfcbfbe2c6a7d4a8770bee0c71211def898d7c5024ce2007dd85accb3f69d906ae2164d", + "Noekeon", + "7e68ceb33aad9db04af6b878a16dd6c6b4f880d6c89027ba581884c10690bb6b3dbfd6ed5513e2c4f5670c3528023121", + "DES/CBC/NoPadding", + "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a", + "DESede/CBC/NoPadding", + "4d3d7931875cf25593dc402298add8b914761e4936c9585ae22b2c1441169231", + "SKIPJACK/CBC/NoPadding", + "ceebcc2e5e2b847f9ed797b4930b95f115b9e6cf49c457fc2ea0df79ad5c8334", + "Blowfish/CBC/NoPadding", + "80823abbabc109733e7ebf3ce3344d67fc387c306b782086b452f7fbe8e844ce", + "Twofish/CBC/NoPadding", + "f819694251a00bdd403928745cd1d8a094de61f49ddf8e7692e9d81a83812943", + "RC2/CBC/NoPadding", + "a51facdb3933c9676795cd38cc3146fd4694722b468b1a979a399c77606abf99", + "RC5/CBC/NoPadding", + "9ee7517eab0280445f3a7c60c90c0f75029d65bca8b1af83ace5399d388c83c3", + "RC6/CBC/NoPadding", + "c44695633c07010f3a0d8f7ea046a642d4a96bf4e44f89fd91b46830bc95b130", + "IDEA/CBC/NoPadding", + "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d9", + "DES/CBC/PKCS5Padding", + "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122afdc70484fb9c0232", + "DES/CBC/ISO10126Padding", + "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a980639850a2cc3e8", + "DES/CBC/ISO7816-4Padding", + "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a1f80b9b0f1be49ac", + "DES/CBC/X9.23Padding", + "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122a980639850a2cc3e8", + "DESede/CBC/PKCS7Padding", + "4d3d7931875cf25593dc402298add8b914761e4936c9585ae22b2c1441169231a41e40695f1cff84", + "SKIPJACK/CBC/PKCS7Padding", + "ceebcc2e5e2b847f9ed797b4930b95f115b9e6cf49c457fc2ea0df79ad5c8334df7042de5db89c96", + "Blowfish/CBC/PKCS7Padding", + "80823abbabc109733e7ebf3ce3344d67fc387c306b782086b452f7fbe8e844cef986562ab1a675e8", + "Twofish/CBC/PKCS7Padding", + "f819694251a00bdd403928745cd1d8a094de61f49ddf8e7692e9d81a838129433e5f1343d6cdb0b41838619da1541f04", + "RC2/CBC/PKCS7Padding", + "a51facdb3933c9676795cd38cc3146fd4694722b468b1a979a399c77606abf9958435525f770f137", + "RC5/CBC/PKCS7Padding", + "9ee7517eab0280445f3a7c60c90c0f75029d65bca8b1af83ace5399d388c83c3edd95ff49be76651", + "RC5-64/CBC/PKCS7Padding", + "e479fd11f89dab22d2f3dd062b1d2abd5b5962553421a5c562dc7214c3b23b8e21949fda87f2f820e5f032c552c6ec78", + "RC6/CBC/PKCS7Padding", + "c44695633c07010f3a0d8f7ea046a642d4a96bf4e44f89fd91b46830bc95b130824b972c9019a69d2dd05ef2d36b37ac", + "IDEA/CBC/PKCS7Padding", + "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d9e584751325ef7c32", + "IDEA/CBC/ISO10126Padding", + "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d978b3fd73135f033b", + "IDEA/CBC/X9.23Padding", + "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d978b3fd73135f033b", + "AES/CBC/PKCS7Padding", + "cf87f4d8bb9d1abb36cdd9f44ead7d046db2f802d99e1ef0a5940f306079e08389a44c4a8cc1a47cbaee1128da55bbb7", + "AES/CBC/ISO7816-4Padding", + "cf87f4d8bb9d1abb36cdd9f44ead7d046db2f802d99e1ef0a5940f306079e08306d84876508a33efec701118d8eeaf6d", + "Rijndael/CBC/PKCS7Padding", + "cf87f4d8bb9d1abb36cdd9f44ead7d046db2f802d99e1ef0a5940f306079e08389a44c4a8cc1a47cbaee1128da55bbb7", + "Serpent/CBC/PKCS7Padding", + "d8b971931de211cb2d31721773a5b1f9dc4e263efe0465f97c024daa26dd7d03473e9beb82ba809cf36071d4807e4706", + "Tnepres/CBC/PKCS7Padding", + "f8940ca31aba8ce1e0693b1ae0b1e08daef6de03c80f019774280052f824ac44540bb8dd74dfad47f83f9c7ec268ca68", + "CAST5/CBC/PKCS7Padding", + "87b6dc0c5a1d23d42fa740b0548be0b298112000544610d889d6361994cf8e670a19d6af72d7289f", + "CAST6/CBC/PKCS7Padding", + "943445569cfdda174118e433828f84e137faee38cac5c827d87a3c9a5a46a07dd64e7ad8accd921f248eea627cd6826f", + "DES/CBC/WithCTS", + "60fa2f8fae5aa2a38e9ac77d0246726bcf99f75cc6e0122aeb7511e4515feb12", + "IDEA/CBC/PKCS7Padding", + "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d9e584751325ef7c32", + "DES/CBC/ZeroBytePadding", + "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122ad3b3f002c927f1fd", + "DES/CTS/NoPadding", // official style + "60fa2f8fae5aa2a38e9ac77d0246726bcf99f75cc6e0122aeb7511e4515feb12", + "DESede/CTS/NoPadding", + "4d3d7931875cf25593dc402298add8b9e22b2c144116923114761e4936c9585a", + "SKIPJACK/CTS/NoPadding", + "ceebcc2e5e2b847f9ed797b4930b95f12ea0df79ad5c833415b9e6cf49c457fc", + "Blowfish/CTS/NoPadding", + "80823abbabc109733e7ebf3ce3344d67b452f7fbe8e844cefc387c306b782086", + "Twofish/CTS/NoPadding", + "94de61f49ddf8e7692e9d81a83812943f819694251a00bdd403928745cd1d8a0", + "AES/CTS/NoPadding", + "6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04", + "Rijndael/CTS/NoPadding", + "6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04", + "Serpent/CTS/NoPadding", + "dc4e263efe0465f97c024daa26dd7d03d8b971931de211cb2d31721773a5b1f9", + "Tnepres/CTS/NoPadding", + "aef6de03c80f019774280052f824ac44f8940ca31aba8ce1e0693b1ae0b1e08d", + "CAST5/CTS/NoPadding", + "87b6dc0c5a1d23d42fa740b0548be0b289d6361994cf8e6798112000544610d8", + "CAST6/CTS/NoPadding", + "37faee38cac5c827d87a3c9a5a46a07d943445569cfdda174118e433828f84e1", + "RC2/CTS/NoPadding", + "a51facdb3933c9676795cd38cc3146fd9a399c77606abf994694722b468b1a97", + "RC5/CTS/NoPadding", + "9ee7517eab0280445f3a7c60c90c0f75ace5399d388c83c3029d65bca8b1af83", + "RC6/CTS/NoPadding", + "d4a96bf4e44f89fd91b46830bc95b130c44695633c07010f3a0d8f7ea046a642", + "IDEA/CTS/NoPadding", + "30cd990ebdae80fe12b6c6e4fcd1c06497351c8684e4c4d9a27d985c276b3d70", + "DES/CBC/WithCTS", // older style + "60fa2f8fae5aa2a38e9ac77d0246726bcf99f75cc6e0122aeb7511e4515feb12", + "DESede/CBC/WithCTS", + "4d3d7931875cf25593dc402298add8b9e22b2c144116923114761e4936c9585a", + "SKIPJACK/CBC/WithCTS", + "ceebcc2e5e2b847f9ed797b4930b95f12ea0df79ad5c833415b9e6cf49c457fc", + "Blowfish/CBC/WithCTS", + "80823abbabc109733e7ebf3ce3344d67b452f7fbe8e844cefc387c306b782086", + "Twofish/CBC/WithCTS", + "94de61f49ddf8e7692e9d81a83812943f819694251a00bdd403928745cd1d8a0", + "AES/CBC/WithCTS", + "6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04", + "Rijndael/CBC/WithCTS", + "6db2f802d99e1ef0a5940f306079e083cf87f4d8bb9d1abb36cdd9f44ead7d04", + "Serpent/CBC/WithCTS", + "dc4e263efe0465f97c024daa26dd7d03d8b971931de211cb2d31721773a5b1f9", + "Tnepres/CBC/WithCTS", + "aef6de03c80f019774280052f824ac44f8940ca31aba8ce1e0693b1ae0b1e08d", + "CAST5/CBC/WithCTS", + "87b6dc0c5a1d23d42fa740b0548be0b289d6361994cf8e6798112000544610d8", + "CAST6/CBC/WithCTS", + "37faee38cac5c827d87a3c9a5a46a07d943445569cfdda174118e433828f84e1", + "RC2/CBC/WithCTS", + "a51facdb3933c9676795cd38cc3146fd9a399c77606abf994694722b468b1a97", + "RC5/CBC/WithCTS", + "9ee7517eab0280445f3a7c60c90c0f75ace5399d388c83c3029d65bca8b1af83", + "RC6/CBC/WithCTS", + "d4a96bf4e44f89fd91b46830bc95b130c44695633c07010f3a0d8f7ea046a642", + "IDEA/CBC/WithCTS", + "30cd990ebdae80fe12b6c6e4fcd1c06497351c8684e4c4d9a27d985c276b3d70", + "Blowfish/CTR/NoPadding", + "6cd6f7c5d2c65555d2b31f8614f54ec654f5e7888d515008d59302c3edfcc6cb", + "CAST5/CTR/NoPadding", + "9ef6c08987f02d3dc218513450cf0f8d6aa9eb15d0ad92dde14863731a7e39c2", + "Camellia/CTR/NoPadding", + "9132cee4b4f13574ed61c00997f8049e8b45f941f6394e333926a3245f11d759", + "DES/OFB/NoPadding", + "537572e480c1714f5c9a4f3b874df824dc6681b1fd6c11982debcad91e3f78b7", + "DESede/OFB/NoPadding", + "481e9872acea7fcf8e29a453242da774e5f6a28f15f7723659a73e4ff4939f80", + "SKIPJACK/OFB/NoPadding", + "71143a124e3a0cde753b60fe9b200e559018b6a0fe0682659f7c13feb9df995c", + "Blowfish/OFB/NoPadding", + "6cd6f7c5d2c655556d7a9e98a1696d1875e9f1b2fc991e28a2d55b56861e80bd", + "Twofish/OFB/NoPadding", + "821c54b1b54ae113cf74595eefe10c83b61c9682fc81f92c52f39a3a693f88b8", + "Threefish-256/OFB/NoPadding", + "546ea995dd302f1efcb1f27d14bad468280a3a7994c2af75dfdf1e9fc5ef2373", + "Threefish-512/OFB/NoPadding", + "152df966484ecc2e9ddfc386559732f7f632e4008920804a1bde4efcf2e6e2f2", + "Threefish-1024/OFB/NoPadding", + "03953ac751a7377812c6e3e4d14b36c6953f9b390acaa892811c10001c9be454", + "RC2/OFB/NoPadding", + "0a07cb78537cb04c0c74e28a7b86b80f80acadf87d6ef32792f1a8cf74b39f74", + "RC5/OFB/NoPadding", + "c62b233df296283b918a2b4cc53a54fbf061850e781b97332ed1bd78b88d9670", + "IDEA/OFB/NoPadding", + "dd447da3cbdcf81f4053fb446596261cb00a3c49a66085485af5f7c10ba20dad", + "DES/OFB8/NoPadding", + "53cb5010d189f94cf584e5ff1c4a9d86443c45ddb6fa3c2d1a5dadfcdf01db8a", + "DESede/OFB8/NoPadding", + "482c0c1ccd0e6d218e1cffb0a295352c2357ffaa673f2257ef5c77b6c04f03b5", + "SKIPJACK/OFB8/NoPadding", + "719ea1b432b3d2c8011e5aa873f95978420022b5e2c9c1a1c1082cd1f4999da2", + "Blowfish/OFB8/NoPadding", + "6ca6078755b263f09787d830b6fda7b7748494634bdc73ab68540cf9f6b7eccf", + "Twofish/OFB8/NoPadding", + "825dcec234ad52253d6e064b0d769bc04b1142435933f4a510ffc20d70095a88", + "Threefish-256/OFB8/NoPadding", + "545fbd92313512127218262dd4394569aca96ba122e1432b661ecfc01af3a25c", + "Threefish-512/OFB8/NoPadding", + "15f6e7d215662c525ea982cab56409cf833157e1af06edd57a13c71487904fea", + "Threefish-1024/OFB8/NoPadding", + "03d80b67ff7139d9dd8b07280642f94074496e5fc37b1ba1f8593cdf64a1e4ca", + "RC2/OFB8/NoPadding", + "0aa26c6f6a820fe7d38da97085995ad62e2e293323a76300fcd4eb572810f7c6", + "RC5/OFB8/NoPadding", + "c601a9074dbd874f4d3293f6a32d93d9f0a4f5685d8597f0102fcc96d444f976", + "IDEA/OFB8/NoPadding", + "dd7897b6ced43d060a518bb38d570308b83b4de577eb208130daabf619e9b1fb", + "DES/CFB/NoPadding", + "537572e480c1714fec3c7424f88d4202219244c5ca8f5e4361d64f08fe747bb2", + "DESede/CFB/NoPadding", + "481e9872acea7fcfb75bb58670fe64c59123265139e357d161cd4ddb5eba042a", + "SKIPJACK/CFB/NoPadding", + "71143a124e3a0cde70a69ede4ceb14376b1e6a80bafde0a6330508dfa86a7c41", + "Blowfish/CFB/NoPadding", + "6cd6f7c5d2c6555561167fe9b10665102206869339122f1ed89efa4a985397f6", + "Twofish/CFB/NoPadding", + "821c54b1b54ae113cf74595eefe10c8308b7a438277de4f40948ac2d172d53d2", + "Threefish-256/CFB/NoPadding", + "546ea995dd302f1efcb1f27d14bad468280a3a7994c2af75dfdf1e9fc5ef2373", + "Threefish-512/CFB/NoPadding", + "152df966484ecc2e9ddfc386559732f7f632e4008920804a1bde4efcf2e6e2f2", + "Threefish-1024/CFB/NoPadding", + "03953ac751a7377812c6e3e4d14b36c6953f9b390acaa892811c10001c9be454", + "RC2/CFB/NoPadding", + "0a07cb78537cb04ca1401450d5cd411c7da7fa5b6baaa17bb2137bd95c9f26a5", + "RC5/CFB/NoPadding", + "c62b233df296283b989352bbebf616a19e11503ac737f9e0eaf19049cde05d34", + "IDEA/CFB/NoPadding", + "dd447da3cbdcf81fcbe4661dcbed88aed899f87585118384bd0565067fa6c13a", + "DES/CFB8/NoPadding", + "53cb0cdff712a825eb283b23c31e7323aa12495e7e751428b5c4eb89b28a25d4", + "DESede/CFB8/NoPadding", + "482cd5bf87ca4cee0b573d66a077231bfea93843ce2d1f948550a1d208e18279", + "SKIPJACK/CFB8/NoPadding", + "719eef3906bef23f7b63599285437d8e34183b165acf3e855b4e160d4f036508", + "Blowfish/CFB8/NoPadding", + "6ca63aaada9188d2410c07513cc0736b9888770768c25a5befc776beea5bdc4c", + "Twofish/CFB8/NoPadding", + "825d12af040721cf5ed4a4798647837ac5eb14d752aace28728aeb37b2010abd", + "Threefish-256/CFB8/NoPadding", + "545fbf0a4b925f399cf7540f1cc1cc6012e329ab2d4db0aa0dfa29ee2a2019d1", + "Threefish-512/CFB8/NoPadding", + "15f695964f20b95ed72afad75f905788839c53bed2ae5fdfdfb13e3241fd7f94", + "Threefish-1024/CFB8/NoPadding", + "03d897c89e740d2254f717b73315151d9a34c829e4162232b3cd5f5158ff367b", + "RC2/CFB8/NoPadding", + "0aa227f94be3a32ff927c5d25647ea41d7c2a1e94012fc7f2ad6767b9664bce5", + "RC5/CFB8/NoPadding", + "c601cf88725411f119965b9cd38d6c313b91128ed7c98c7604cc62d9b210be79", + "IDEA/CFB8/NoPadding", + "dd7839d2525420d10f95eec23dbaf3463302c445972a28c563c2635191bc19af", + "IDEA/PGPCFB/NoPadding", + "dd447da3cbdcf81fcbe4661dcbed88aed899f87585118384bd0565067fa6c13a", + "IDEA/PGPCFBwithIv/NoPadding", + "ed5adbac0e730cc0f00df7e4f6fef672ab042673106435faf3ecf3996a72a0e127b440ba9e5313501de3", + "Twofish/ECB/TBCPadding", + "70336d9c9718a8a2ced1b19deed973a3c58af7ea71a69e7efc4df082dca581c019d7daa58d02b89aab6e8c0d17202439", + "RC2/ECB/TBCPadding", + "eb5b889bbcced12eb6b1a3da6a3d965bba66a5edfdd4c8a6b6b1a3da6a3d965b6b5359ba5e69b179", + "DES/CTR/NoPadding", + "537572e480c1714fb47081d35eb18eaca9e0a5aee982f105438a0db6cece1f6d", + "DESede/CTR/NoPadding", + "481e9872acea7fcfa93b7d4e34ec7bab340c10faba2e43b879d40d38e07c422d", + "SKIPJACK/CTR/NoPadding", + "71143a124e3a0cdeee98a7b843baa05bd1d59faee8ec9b89880e070314a04cc2", + "Blowfish/CTR/NoPadding", + "6cd6f7c5d2c65555d2b31f8614f54ec654f5e7888d515008d59302c3edfcc6cb", + "Twofish/CTR/NoPadding", + "821c54b1b54ae113cf74595eefe10c83d09e95d4599190b9bbd5bc71dd703730", + "Threefish-256/CTR/NoPadding", + "546ea995dd302f1efcb1f27d14bad468280a3a7994c2af75dfdf1e9fc5ef2373", + "Threefish-512/CTR/NoPadding", + "152df966484ecc2e9ddfc386559732f7f632e4008920804a1bde4efcf2e6e2f2", + "Threefish-1024/CTR/NoPadding", + "03953ac751a7377812c6e3e4d14b36c6953f9b390acaa892811c10001c9be454", + "RC2/CTR/NoPadding", + "0a07cb78537cb04c8c5a0a39a15977a7eb19f3c48a42759c234868c391a99c63", + "RC5/CTR/NoPadding", + "c62b233df296283b97f17364d5f69a1ff91f46659cf9856caefd322a936203a7", + "IDEA/CTR/NoPadding", + "dd447da3cbdcf81f4694ab7715d79e3f90af5682e8c318b8f7dadbed6b5c9714", + "Blowfish/EAX/NoPadding", + "bee85ae6512b8a2346d46f7bac31526238091ccc5de75760c9a39628fb45d44a653bfac0", + "CAST5/EAX/NoPadding", + "85e0dbd3402f2179f96d231315ec73f04f64f1b7ab1347423b9aec51a07a7222e2bc65a3", + "DES/EAX/NoPadding", + "07d12249945e77607086f7463f316966466e6a0c0789b3307b8b51a7cc807e3c1fb91f98", + "DESede/EAX/NoPadding", + "278b28f13537dc13bb688c95391754bd6d39c79a7361b407f8dee0b111b264f20391cb0e", + "GOST28147/EAX/NoPadding", + "1416713d52affb595b880be996e838edd377e67dfe822fbb0ff235f1b706e6ce34d68dc5", + "IDEA/EAX/NoPadding", + "b2e9f3e40954c140ac60423466dee0138f84e879fbde003780202bd83c91571b64df7bb7", + "RC2/EAX/NoPadding", + "5d1c095de75bd5eef6a5146f7d6c44545807a8b452f7a38e2719a14f1a269709d2eda2d3", + "SEED/EAX/NoPadding", + "6780f18b2dd1f75a934b5a3e45e8fd44877fd3498a9b919b417b3d8a7c67c6021d74bbaef71841ef", + "Serpent/EAX/NoPadding", + "13c2b1fec2bda74f5ccc8ca31b36a2e91ee024a215387219808640b2fc7a6a41e017aacee3ed893a", + "Tnepres/EAX/NoPadding", + "8d5ac312ca0d436a0154d56568d39811ccf6bb970012398014fc8a49ed669b117443c0249b07ead8", + "SM4/EAX/NoPadding", + "e072a95da8e529b41199859482142b3fdfa6b7af27348e5ebf35445a099583dae882affde90ea4a4", + "Twofish/EAX/NoPadding", + "9a90dffe1233a04733fc8869e8ec4cba2fa53d9543f0206825293b1ff102e63f81a60b12204e1fd8", + "IDEA/OFB/NoPadding", + "dd447da3cbdcf81f4053fb446596261cb00a3c49a66085485af5f7c10ba20dad", + "RC2/OFB/NoPadding", + "0a07cb78537cb04c0c74e28a7b86b80f80acadf87d6ef32792f1a8cf74b39f74", + "SEED/OFB/NoPadding", + "9fd249435dc66d3d5d41abad270df5e3c6b972692fadfcb6c311b047f96fb114", + "SEED/OCB/NoPadding", + "eb04b3612769e1ad681f975af1a6f401d94dc88276dd50fc3ebce791c28825c652b7351acbad8c63d4d66191de94c970", + "SEED/CCM/NoPadding", + "da684e8cab782d4ebae835726f43c3aeea97ee270897255714d464e981ac39af06c9483153f8a05a", + "SEED/GCM/NoPadding", + "ed5f6293c9a4f280af6695750bfb3bb3b60c214565a049494df955152757812ebfb93705895606c4378498a93f2541b5", + "SM4/GCM/NoPadding", + "323b601a951da693f87e53c6832380719b4d4bd306c94248202b7e337c81e2d9de0044b77a4c556f15f6fd19f828236b", + "DES/ECB/TBCPadding", + "466da00648ef0e1f9617b1f002e225251a3248d09172f46b9617b1f002e22525698575eb3998481b", + "GOST28147/ECB/TBCPadding", + "0a77f4114451b37d44c5192619b723dd49093d1047c2373544c5192619b723dde7b0810d205c07ab", + "IDEA/ECB/TBCPadding", + "8c9fd56823ffdc523f6ccf7f614aa6173553e594fc7a21b53f6ccf7f614aa61747a7c95a57b9eaf4", + "RC2/ECB/TBCPadding", + "eb5b889bbcced12eb6b1a3da6a3d965bba66a5edfdd4c8a6b6b1a3da6a3d965b6b5359ba5e69b179", + "SEED/ECB/TBCPadding", + "d53d4ce1f48b9879420949467bfcbfbe2c6a7d4a8770bee0c71211def898d7c509f6e111845db39b4cce1dd155aa592b", + "DES/CBC/TBCPadding", + "60fa2f8fae5aa2a38e9ac77d0246726beb7511e4515feb12cf99f75cc6e0122ad3b3f002c927f1fd", + "GOST28147/CBC/TBCPadding", + "ba87be9c465cbb30e1bf0148daa9639c2e4cbc1b6777cfcda860760686596159aa564fd65e66c125", + "IDEA/CBC/TBCPadding", + "30cd990ebdae80fe12b6c6e4fcd1c064a27d985c276b3d7097351c8684e4c4d922f14e12faecaa0b", + "RC2/CBC/TBCPadding", + "a51facdb3933c9676795cd38cc3146fd4694722b468b1a979a399c77606abf9997b47d2f64a37e2f", + "SEED/CBC/TBCPadding", + "fc34f03ddf4d2a4d9934addc82011af1d5f76ee015b691a6524d7ad5464422d7989825d19e23a60ba759407e13d1ea02", + "DES/CFB8/NoPadding", + "53cb0cdff712a825eb283b23c31e7323aa12495e7e751428b5c4eb89b28a25d4", + "GOST28147/CFB8/NoPadding", + "29f6ca1ca7ae9670413183932a28cdd4a09f2ba630c3c3fbf6f071d3774d7577", + "IDEA/CFB8/NoPadding", + "dd7839d2525420d10f95eec23dbaf3463302c445972a28c563c2635191bc19af", + "RC2/CFB8/NoPadding", + "0aa227f94be3a32ff927c5d25647ea41d7c2a1e94012fc7f2ad6767b9664bce5", + "SEED/CFB8/NoPadding", + "9f1622c3785a034ee4c595df05fb11e69e4d52036e238d2d451e190e87ee876e", + "DES/CTS/NoPadding", + "60fa2f8fae5aa2a38e9ac77d0246726bcf99f75cc6e0122aeb7511e4515feb12", + "GOST28147/CTS/NoPadding", + "ba87be9c465cbb30e1bf0148daa9639ca8607606865961592e4cbc1b6777cfcd", + "IDEA/CTS/NoPadding", + "30cd990ebdae80fe12b6c6e4fcd1c06497351c8684e4c4d9a27d985c276b3d70", + "RC2/CTS/NoPadding", + "a51facdb3933c9676795cd38cc3146fd9a399c77606abf994694722b468b1a97", + "SEED/CTS/NoPadding", + "d5f76ee015b691a6524d7ad5464422d7fc34f03ddf4d2a4d9934addc82011af1", + "SHACAL-2/CBC/PKCS7Padding", + "3af7c54ea55d2497162ac9c79d9b2f7837898f83aa4b50b7b762979aa8087669b6a81cdec475ed4d2394d7ad771404a52eb52d245a39f0d7d3e8062d3b0f0e54", + "SHACAL-2/CBC/TBCPadding", + "3af7c54ea55d2497162ac9c79d9b2f7837898f83aa4b50b7b762979aa80876693f17fbe9a5baa88ed21b2e1a863dc449061f40cafadfc3cf73486208f87b9352", + }; + + static String[] cipherTests2 = + { + "DES/OFB64/NoPadding", + "537572e480c1714f5c9a4f3b874df824dc6681b1fd6c11982debcad91e", + "DES/CFB64/NoPadding", + "537572e480c1714fec3c7424f88d4202219244c5ca8f5e4361d64f08fe", + "DES/CTR/NoPadding", + "537572e480c1714fb47081d35eb18eaca9e0a5aee982f105438a0db6ce", + "DES/CTS/NoPadding", + "60fa2f8fae5aa2a38e9ac77d0246726b32df660db51a710ceb7511e451" + }; + + static String[] cipherTestsLargeBlock = + { + "SHACAL-2/CBC/withCTS", + "3af7c54ea55d2497162ac9c79d9b2f7837898f83aa4b50b7b762979aa8087669c7228283218babbc53af6eb9edefe37ddd827ded8dd6d99557e9f10075b53e18fff454cccdc913a1817dcad39fca72820e014892ff16432233e9a0a19aa499b456478bbaaa6c1a4adcda6564906a71fd49669fffec5806dd86c451052d70f276", + "SHACAL-2/CBC/PKCS7Padding", + "3af7c54ea55d2497162ac9c79d9b2f7837898f83aa4b50b7b762979aa8087669c7228283218babbc53af6eb9edefe37ddd827ded8dd6d99557e9f10075b53e1856478bbaaa6c1a4adcda6564906a71fd49669fffec5806dd86c451052d70f276fff454cccdc913a1817dcad39fca72820e014892ff16432233e9a0a19aa499b4dda7154ca3f53f3c8ff443f31b7821aa05cdcf584add4dbfb436abb2cffec14d", + "SHACAL-2/CBC/ISO10126-2Padding", + "3af7c54ea55d2497162ac9c79d9b2f7837898f83aa4b50b7b762979aa8087669c7228283218babbc53af6eb9edefe37ddd827ded8dd6d99557e9f10075b53e1856478bbaaa6c1a4adcda6564906a71fd49669fffec5806dd86c451052d70f276fff454cccdc913a1817dcad39fca72820e014892ff16432233e9a0a19aa499b46ba38f310460943eca68cbe924899c32e4436e71c3b7c9714d139ca559a4a63c", + "SHACAL-2/CBC/ISO7816-4Padding", + "3af7c54ea55d2497162ac9c79d9b2f7837898f83aa4b50b7b762979aa8087669c7228283218babbc53af6eb9edefe37ddd827ded8dd6d99557e9f10075b53e1856478bbaaa6c1a4adcda6564906a71fd49669fffec5806dd86c451052d70f276fff454cccdc913a1817dcad39fca72820e014892ff16432233e9a0a19aa499b499af44e121ef1a08eaaa3b96f2c4fe6248c375435a69f7fc0e1c22eed8aeeac2", + "SHACAL-2/CBC/X923Padding", + "3af7c54ea55d2497162ac9c79d9b2f7837898f83aa4b50b7b762979aa8087669c7228283218babbc53af6eb9edefe37ddd827ded8dd6d99557e9f10075b53e1856478bbaaa6c1a4adcda6564906a71fd49669fffec5806dd86c451052d70f276fff454cccdc913a1817dcad39fca72820e014892ff16432233e9a0a19aa499b46ba38f310460943eca68cbe924899c32e4436e71c3b7c9714d139ca559a4a63c", + "SHACAL-2/CBC/TBCPadding", + "3af7c54ea55d2497162ac9c79d9b2f7837898f83aa4b50b7b762979aa8087669c7228283218babbc53af6eb9edefe37ddd827ded8dd6d99557e9f10075b53e1856478bbaaa6c1a4adcda6564906a71fd49669fffec5806dd86c451052d70f276fff454cccdc913a1817dcad39fca72820e014892ff16432233e9a0a19aa499b49607ddd0d5c54de11ed6ae50afa7fe6ed7f298b5963254e60e069f0916b8f0e1", + "SHACAL-2/CTR/NoPadding", + "e128b4dd0a8a3bf0d4b558ec2a76700a754a1f99cf83a28b3e3a4c2c6b7c6d2cbeb759073b08aa4294730bbed03cfb77a506efb833a4c09a906bbabf25daca6d7ee7df13ef0c462a54dcede0b282914f7914b1cf6f64409c6ce4ea48c7da26ea95fcb7f4b8d169f4bd6b0515f6a37d784b3b9fbb519f931a912391250a78e0c5", + "SHACAL-2/CFB8/NoPadding", + "e185119f49ecb9370bc6915d9f3748e352a4bbd26a7d4911089762cd2933912e220909b2c4a5c047038a547f89701ab6b0ab7fb6cc3e48c79ab573e218793d01f78c3b590ad9d6ce078d3ccecedd228bb8cce130b94dcfe8d5d0ed6fcbb9d1d06768da1f0a4b979c2cdd590474f05e6c0073c35e5202b3f8f73e5e9028120c2b", + "SHACAL-2/CFB256/NoPadding", + "e128b4dd0a8a3bf0d4b558ec2a76700a754a1f99cf83a28b3e3a4c2c6b7c6d2ccd3ea6711fea5531f1bb21be35c6cc8b25e86942f397106b65c56b42267f4bf62782bd6011cb320bb073ceb037de8a5bd775f6fb3ee74525ef6286c54bbb1d19f29e2ed08c7519ecd1440a50fc68a254f7f5ac085f9b7d63e4fa651a25ab7a3b", + "SHACAL-2/CFB/NoPadding", + "e128b4dd0a8a3bf0d4b558ec2a76700a754a1f99cf83a28b3e3a4c2c6b7c6d2ccd3ea6711fea5531f1bb21be35c6cc8b25e86942f397106b65c56b42267f4bf62782bd6011cb320bb073ceb037de8a5bd775f6fb3ee74525ef6286c54bbb1d19f29e2ed08c7519ecd1440a50fc68a254f7f5ac085f9b7d63e4fa651a25ab7a3b", + "SHACAL-2/OFB/NoPadding", + "e128b4dd0a8a3bf0d4b558ec2a76700a754a1f99cf83a28b3e3a4c2c6b7c6d2cb231d2897aba5cffa1b64a99fb6f9b5c9df8875dcd0d88412dacfaf61c2985ee726c4f534c109b16289811f1fc8e20d73c3a4c07dc30e07e806bc631a7e901e5d77fe48114b52abbed9a0c58bde5622c1a624ad8714e5044081016da78518d58", + "SHACAL-2/EAX/NoPadding", + "002e7bac7a8776e78ae9f0ea5df37b3c02a9210a91d583b1ef8dfad22cc346acbe9ff20ea8707e49ba85ed5718225b9f5b4550cefd6ef93566283f411ec0a05f4852b92f2a5b68a5c2c2acd170ac98dcbdc4c2b30787f5b55f3dd88f596852f0bda40ed840dfbb4cc1c8504e729ba724f3fada64e2d3897a3335da5b8c04f1afc2daf2d3a3012b3fec847f663e22a842", + "Threefish-256", + "9f82b577cf4cca7a504e9f7a2cd7dbb4ef4ac167c716fca19ab1211f195f610f" + + "9f82b577cf4cca7a504e9f7a2cd7dbb4ef4ac167c716fca19ab1211f195f610f" + + "9f82b577cf4cca7a504e9f7a2cd7dbb4ef4ac167c716fca19ab1211f195f610f" + + "9f82b577cf4cca7a504e9f7a2cd7dbb4ef4ac167c716fca19ab1211f195f610f" + + "31533aa864e6a40edc3e24b36260d94374893dc2e479793292e29c18a6ee01a9", + "Threefish-512", + "35d0c46770ebb3bf62fadd48765db209df215d7cd18a8b18d11625e70067e1fa" + + "bb98982312ce1fdfccae1a59408e1d5418b400a7bf0d1c4e9ea4afa4395886d7" + + "35d0c46770ebb3bf62fadd48765db209df215d7cd18a8b18d11625e70067e1fa" + + "bb98982312ce1fdfccae1a59408e1d5418b400a7bf0d1c4e9ea4afa4395886d7" + + "ad7ec86b2137af1ddb64794d714c4e1d7b687b19fc9781ef887a0ad7f88e18fc" + + "1baa6123ec8bc497e7eb7b5090cfd756fd5333425ed5a240cb96735dea9713d9", + "Threefish-1024", + "df6d789e301c6a5e22e0cff0b44666630d44ce774a41b628ebaff6adc86d9e66" + + "af50a282a4313552bc9b861cb286ab569e2e23b1c97cdb5cb1fde1bacfba9bfb" + + "de3b443218e16b6038537b3d803ff5dbd26b13c177a5bfb597ffccca142a5905" + + "8c0f74623daa96bff95b716674701034e7947ce0541426fa5177bc1a519b23ba" + + "462f1724989612e49ca5e92a0129ec7be576846fe2616664674e16a29ce8679c" + + "0adda9034fbd652910c2ae5afacde10281ab18dbeeb83464dc21ff66b0d358ff" + + "2328c73aca59e9095a7bca94acc79d10038eab6ef865545bcf73f4caeeba1844" + + "6add98350c8276e5abfb8709bb6c01ef3297b862818a4996b744f375b9126e5c", + "Threefish-256/CBC/NoPadding", + "1c46830ef0a43a0869bf070a87f0d4e63f2458edfa5654bafd8520358dae8bf9" + + "2a8c039d41e87bb65a907331dde317450d38aba6cb3885bfbe0aee148503e37b" + + "973c5e8a16c4309f7a4229d9943ab403082b5836431b9d1646b619f368e057b3" + + "0931ce1b791b641dd3e79f2b536897f3c537e3b4588dc03c3888f9bab3bc7a0e", + "Threefish-512/CBC/NoPadding", + "caee9b663eba4663de1cd6f17ffc51dc8b808c95f91e12a818ab31436985830b" + + "3aa886a93e53849d34e713f36db52bac3557b137328434f41f825f3948a611c6" + + "03efe066d8d6d57b15b04729632de0ce5636b8ccd28219ac17ef836734556e15" + + "e90356111279412a814b660150323a416138b2b62942f2d0cd08ee0bb45b0dd7", + "Threefish-1024/CBC/NoPadding", + "7540a8fe54a1a1d117ba1f970a12002cf9e24477daef9439dfc43b79a88a9e87" + + "b59be63aa448b4e02e8b9a6464419c35b0b3f97219e6c88ed5429d0f9ffb40bb" + + "491f280f4281af177e254828f82e90d196c6bf9afa31926cf5bf0cc3dc81f28a" + + "419544ef5907f3b8bf6179da37ff07134d9c6d147521e5c840d5086ec74c1003", + "Threefish-256/CBC/PKCS7Padding", + "1c46830ef0a43a0869bf070a87f0d4e63f2458edfa5654bafd8520358dae8bf9" + + "2a8c039d41e87bb65a907331dde317450d38aba6cb3885bfbe0aee148503e37b" + + "973c5e8a16c4309f7a4229d9943ab403082b5836431b9d1646b619f368e057b3" + + "0931ce1b791b641dd3e79f2b536897f3c537e3b4588dc03c3888f9bab3bc7a0e" + + "f96cb468a5cd39a003f976464a7d072c94cb72a3fe739f101aa7b5452bc3fbba", + "Threefish-512/CBC/PKCS7Padding", + "caee9b663eba4663de1cd6f17ffc51dc8b808c95f91e12a818ab31436985830b" + + "3aa886a93e53849d34e713f36db52bac3557b137328434f41f825f3948a611c6" + + "03efe066d8d6d57b15b04729632de0ce5636b8ccd28219ac17ef836734556e15" + + "e90356111279412a814b660150323a416138b2b62942f2d0cd08ee0bb45b0dd7" + + "03902162280012e59efa15c6beecfbf440a6a0c4474bbbb2f74a0ad31bcd398f" + + "b24728c3605a4ced3c92c30a5e231113abafaf6f83a3867978e3cdd74091d09f", + "Threefish-1024/CBC/PKCS7Padding", + "7540a8fe54a1a1d117ba1f970a12002cf9e24477daef9439dfc43b79a88a9e87" + + "b59be63aa448b4e02e8b9a6464419c35b0b3f97219e6c88ed5429d0f9ffb40bb" + + "491f280f4281af177e254828f82e90d196c6bf9afa31926cf5bf0cc3dc81f28a" + + "419544ef5907f3b8bf6179da37ff07134d9c6d147521e5c840d5086ec74c1003" + + "4ddd16ad731ad9a32d0f196a72284f7a8df98918e3e22f1708662edeb1810d2b" + + "bafd4200e849f3288b55634b37f99f0f7b2dd192a5944fc211ef9e37b67a829b" + + "005a5ec609f736875fdf8946bd79c1daa6c44c9d6733a2223cf8b7e5203b1cfd" + + "76995f67e570d9c403b2a2e3f3a89c63c7850ee8d47d4398ac377345a139dda4", + "Threefish-256/CTS/NoPadding", + "1c46830ef0a43a0869bf070a87f0d4e63f2458edfa5654bafd8520358dae8bf9" + + "2a8c039d41e87bb65a907331dde317450d38aba6cb3885bfbe0aee148503e37b" + + "0931ce1b791b641dd3e79f2b536897f3c537e3b4588dc03c3888f9bab3bc7a0e" + + "973c5e8a16c4309f7a4229d9943ab403082b5836431b9d1646b619f368e057b3", + "Threefish-512/CTS/NoPadding", + "03efe066d8d6d57b15b04729632de0ce5636b8ccd28219ac17ef836734556e15" + + "e90356111279412a814b660150323a416138b2b62942f2d0cd08ee0bb45b0dd7" + + "caee9b663eba4663de1cd6f17ffc51dc8b808c95f91e12a818ab31436985830b" + + "3aa886a93e53849d34e713f36db52bac3557b137328434f41f825f3948a611c6", + "Threefish-1024/CTS/NoPadding", + "7540a8fe54a1a1d117ba1f970a12002cf9e24477daef9439dfc43b79a88a9e87b59b" + + "e63aa448b4e02e8b9a6464419c35b0b3f97219e6c88ed5429d0f9ffb40bb491f280f" + + "4281af177e254828f82e90d196c6bf9afa31926cf5bf0cc3dc81f28a419544ef5907" + + "f3b8bf6179da37ff07134d9c6d147521e5c840d5086ec74c1003", + "Threefish-256/CBC/WithCTS", + "1c46830ef0a43a0869bf070a87f0d4e63f2458edfa5654bafd8520358dae8bf9" + + "2a8c039d41e87bb65a907331dde317450d38aba6cb3885bfbe0aee148503e37b" + + "0931ce1b791b641dd3e79f2b536897f3c537e3b4588dc03c3888f9bab3bc7a0e" + + "973c5e8a16c4309f7a4229d9943ab403082b5836431b9d1646b619f368e057b3", + "Threefish-512/CBC/WithCTS", + "03efe066d8d6d57b15b04729632de0ce5636b8ccd28219ac17ef836734556e15" + + "e90356111279412a814b660150323a416138b2b62942f2d0cd08ee0bb45b0dd7" + + "caee9b663eba4663de1cd6f17ffc51dc8b808c95f91e12a818ab31436985830b" + + "3aa886a93e53849d34e713f36db52bac3557b137328434f41f825f3948a611c6", + "Threefish-1024/CBC/WithCTS", + "7540a8fe54a1a1d117ba1f970a12002cf9e24477daef9439dfc43b79a88a9e87b59b" + + "e63aa448b4e02e8b9a6464419c35b0b3f97219e6c88ed5429d0f9ffb40bb491f280f" + + "4281af177e254828f82e90d196c6bf9afa31926cf5bf0cc3dc81f28a419544ef5907" + + "f3b8bf6179da37ff07134d9c6d147521e5c840d5086ec74c1003", + "Threefish-256/ECB/TBCPadding", + "9f82b577cf4cca7a504e9f7a2cd7dbb4ef4ac167c716fca19ab1211f195f610f" + + "9f82b577cf4cca7a504e9f7a2cd7dbb4ef4ac167c716fca19ab1211f195f610f" + + "9f82b577cf4cca7a504e9f7a2cd7dbb4ef4ac167c716fca19ab1211f195f610f" + + "9f82b577cf4cca7a504e9f7a2cd7dbb4ef4ac167c716fca19ab1211f195f610f" + + "89c4e79b90153a821bdd4efd5eb1e2cda89b6a91540a003eef03868472d8cfce", + "Threefish-512/ECB/TBCPadding", + "35d0c46770ebb3bf62fadd48765db209df215d7cd18a8b18d11625e70067e1fa" + + "bb98982312ce1fdfccae1a59408e1d5418b400a7bf0d1c4e9ea4afa4395886d7" + + "35d0c46770ebb3bf62fadd48765db209df215d7cd18a8b18d11625e70067e1fa" + + "bb98982312ce1fdfccae1a59408e1d5418b400a7bf0d1c4e9ea4afa4395886d7" + + "dd6bfa1006e4df51298e382ca397a2c398cdb4d65009dce77c5f0a31f9807218" + + "a72372a8a0df3b1bacd5dbfb116ebbe314e0b0cd64fd2c8ae8a81491c2534a2a", + "Threefish-1024/ECB/TBCPadding", + "df6d789e301c6a5e22e0cff0b44666630d44ce774a41b628ebaff6adc86d9e66" + + "af50a282a4313552bc9b861cb286ab569e2e23b1c97cdb5cb1fde1bacfba9bfb" + + "de3b443218e16b6038537b3d803ff5dbd26b13c177a5bfb597ffccca142a5905" + + "8c0f74623daa96bff95b716674701034e7947ce0541426fa5177bc1a519b23ba" + + "7312262dc3a25984847d1b05cb624f5751946f136ee7bd0a9a4bbac5dd3bd213" + + "702390d3a53d1a4132f59383cce4fe61e08cd3c73c570190d1c8b60940031ef7" + + "42f6775b00fb0b4273a14b46a3fc0e760e02f75dc6100ca9c038c3f151e03145" + + "92686fd8cccbee74d246a8c59ad80205c9f9aaeb100ea5812837ee8699753301", + "Threefish-256/EAX/NoPadding", + "13e8b245045cd24c287c8eff69efff7eb884d6451e06825a16b5877a5c31701d" + + "873c4ad59b6920ad065a661dc3318299f2ce6bfffef82c5f8d076ca619fb785b" + + "799c08e25920e8e4ec322a5059adf8ccecf19b68233c912c64e95327e65f8643" + + "8bc1a9d71a872e706b1fd948c6dd2544ba8cee4e535d0e4fde2034be790b316f" + + "71c6eb1b6282d6abe5d47b8918e0bd68", + "Threefish-512/EAX/NoPadding", + "a27669576966dc3c623f4e14e57cbd039c54dcdf44290905b147b5f2debcc58b" + + "5e6c35a18f24de3ad1f5103c67705ba30eab18e02e2813650ab2ab2daabfdf7" + + "ebae0ecb2d0b90cc8a3d9cbbd68a4b4542e5289f84dc7f4eff5a9e2589d5aa0" + + "bab92db80824956f2b74961456943f8f99c81bc986b4e8a089e9085f665f1bd" + + "b455f05cedbaddb01ef90a70a51272fca60f49021fa0b699faef835fa14a32a" + + "3152", + "Threefish-1024/EAX/NoPadding", + "e247bb71d487cd77edb8eabfeb1f8d2501f6b408dd1004f9c2c4463ea897993" + + "c2288c8bb0334d56a5e239adf1d463a7dc21c690307a5c48612be7f56d57f48" + + "a5a145c4955a7a13a2ae21f49194dc8ce65c4d7d4c88d122dbe6bc869f2d39e" + + "04f983344122d15bffb4e0dfdda82512c5d6450a32d019a5f08f214b0843a03" + + "22095a9d37588d3d469c1051b473c4d645512a805f06d34971c83e18c5b5dab" + + "2e8ed2958f038f7d8133333f90cfef1d72eefc69623e2f07a19ff520b8b4e75" + + "3d9255", + }; + + static byte[] input1 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); + static byte[] input2 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c"); + static byte[] inputLargeBlock = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f" + + "000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f" + + "000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f" + + "000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); + + static RC2ParameterSpec rc2Spec = new RC2ParameterSpec(128, Hex.decode("0123456789abcdef")); + static RC5ParameterSpec rc5Spec = new RC5ParameterSpec(16, 16, 32, Hex.decode("0123456789abcdef")); + static RC5ParameterSpec rc564Spec = new RC5ParameterSpec(16, 16, 64, Hex.decode("0123456789abcdef0123456789abcdef")); + + /** + * a fake random number generator - we just want to make sure the random numbers + * aren't random so that we get the same output, while still getting to test the + * key generation facilities. + */ + private class FixedSecureRandom + extends SecureRandom + { + byte[] seed = { + (byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59, + (byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4, + (byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde, + (byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f + }; + + public void nextBytes( + byte[] bytes) + { + int offset = 0; + + while ((offset + seed.length) < bytes.length) + { + System.arraycopy(seed, 0, bytes, offset, seed.length); + offset += seed.length; + } + + System.arraycopy(seed, 0, bytes, offset, bytes.length - offset); + } + } + + public String getName() + { + return "BlockCipher"; + } + + public void test( + String algorithm, + byte[] input, + byte[] output) + { + Key key = null; + KeyGenerator keyGen; + SecureRandom rand; + Cipher in = null; + Cipher out = null; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + rand = new FixedSecureRandom(); + + String baseAlgorithm, mode; + try + { + + int index = algorithm.indexOf('/'); + + if (index > 0) + { + baseAlgorithm = algorithm.substring(0, index); + mode = algorithm.substring(index + 1, algorithm.lastIndexOf('/')); + } + else + { + baseAlgorithm = algorithm; + mode = null; + } + + if (baseAlgorithm.equals("IDEA") & noIDEA()) + { + return; + } + + keyGen = KeyGenerator.getInstance(baseAlgorithm, "BC"); + if (!keyGen.getAlgorithm().equals(baseAlgorithm)) + { + fail("wrong key generator returned!"); + } + keyGen.init(rand); + + key = keyGen.generateKey(); + + in = Cipher.getInstance(algorithm, "BC"); + out = Cipher.getInstance(algorithm, "BC"); + + if (!in.getAlgorithm().startsWith(baseAlgorithm)) + { + fail("wrong cipher returned!"); + } + + if (algorithm.startsWith("RC2")) + { + out.init(Cipher.ENCRYPT_MODE, key, rc2Spec, rand); + } + else if (algorithm.startsWith("RC5")) + { + if (algorithm.startsWith("RC5-64")) + { + out.init(Cipher.ENCRYPT_MODE, key, rc564Spec, rand); + } + else + { + out.init(Cipher.ENCRYPT_MODE, key, rc5Spec, rand); + } + } + else + { + out.init(Cipher.ENCRYPT_MODE, key, rand); + } + } + catch (Exception e) + { + fail("" + algorithm + " failed initialisation - " + e.toString(), e); + return; + } + + // + // grab the iv if there is one + // + try + { + if (algorithm.startsWith("RC2")) + { + in.init(Cipher.DECRYPT_MODE, key, rc2Spec); + } + else if (algorithm.startsWith("RC5")) + { + if (algorithm.startsWith("RC5-64")) + { + in.init(Cipher.DECRYPT_MODE, key, rc564Spec, rand); + } + else + { + in.init(Cipher.DECRYPT_MODE, key, rc5Spec, rand); + } + } + else + { + byte[] iv; + + iv = out.getIV(); + if (iv != null) + { + if (!shortIvOkay.contains(mode)) + { + try + { + byte[] nIv = new byte[iv.length - 1]; + + in.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(nIv)); + fail("failed to pick up short IV"); + } + catch (InvalidAlgorithmParameterException e) + { + // ignore - this is what we want... + } + } + + IvParameterSpec spec; + + spec = new IvParameterSpec(iv); + + in.init(Cipher.DECRYPT_MODE, key, spec); + } + else + { + in.init(Cipher.DECRYPT_MODE, key); + } + } + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail("" + algorithm + " failed initialisation - " + e.toString()); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail("" + algorithm + " failed encryption - " + e.toString()); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("" + algorithm + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + + dIn.close(); + } + catch (Exception e) + { + fail("" + algorithm + " failed decryption - " + e.toString()); + } + + if (!areEqual(bytes, input)) + { + fail("" + algorithm + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + + // + // short buffer test + // + try + { + byte[] out1 = new byte[input.length / 2]; + + try + { + in.doFinal(output, 0, output.length, out1, 0); + + fail("ShortBufferException not triggered"); + } + catch (ShortBufferException e) + { + byte[] out2 = new byte[in.getOutputSize(output.length)]; + + int count = in.doFinal(output, 0, output.length, out2, 0); + + if (!areEqual(out2, count, input)) + { + fail("doFinal " + algorithm + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out2))); + } + } + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail("" + algorithm + " failed short buffer decryption - " + e.toString()); + } + + try + { + if (algorithm.indexOf("CCM") < 0 && algorithm.indexOf("Threefish") < 0 && algorithm.indexOf("PGPCFB") < 0) + { + // + // short buffer on update test + // + byte[] input2 = new byte[input.length * 8]; + + System.arraycopy(input, 0, input2, 0, input.length); + System.arraycopy(input, 0, input2, input.length, input.length); + System.arraycopy(input, 0, input2, input.length * 2, input.length); + System.arraycopy(input, 0, input2, input.length * 3, input.length); + + if (algorithm.indexOf("GCM") > 0) + { + out = Cipher.getInstance(algorithm, "BC"); + out.init(Cipher.ENCRYPT_MODE, key, rand); + } + + byte[] output2 = out.doFinal(input2); + + if (algorithm.indexOf("GCM") > 0) + { + out = Cipher.getInstance(algorithm, "BC"); + out.init(Cipher.ENCRYPT_MODE, key, rand); + } + + byte[] out1 = new byte[input2.length / 2 - out.getBlockSize() * 2 - 1]; + + try + { + out.update(input2, 0, input2.length / 2, out1, 0); + + fail("ShortBufferException not triggered: " + algorithm + " " + input2.length); + } + catch (ShortBufferException e) + { + byte[] out2 = new byte[out.getOutputSize(input2.length / 2)]; + + System.arraycopy(input2, 0, out2, 0, out2.length); + + int count = out.update(out2, 0, out2.length, out2, 0); + + if (!areEqual(out2, count, Arrays.copyOfRange(output2, 0, count))) + { + fail("update " + algorithm + " failed decryption - expected " + new String(Hex.encode(output2)) + " got " + new String(Hex.encode(out2))); + } + } + } + + serialiseTest(algorithm, input, output); + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail("" + algorithm + " failed short buffer decryption - " + e.toString()); + } + } + + private void serialiseTest( + String algorithm, + byte[] input, + byte[] output) + throws Exception + { + Key key = null; + KeyGenerator keyGen; + SecureRandom rand; + Cipher in = null; + Cipher out = null; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + rand = new FixedSecureRandom(); + + String baseAlgorithm, mode; + int index = algorithm.indexOf('/'); + + if (index > 0) + { + baseAlgorithm = algorithm.substring(0, index); + mode = algorithm.substring(index + 1, algorithm.lastIndexOf('/')); + } + else + { + baseAlgorithm = algorithm; + mode = null; + } + + keyGen = KeyGenerator.getInstance(baseAlgorithm, "BC"); + if (!keyGen.getAlgorithm().equals(baseAlgorithm)) + { + fail("wrong key generator returned!"); + } + keyGen.init(rand); + + key = keyGen.generateKey(); + + bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(key); + + bIn = new ByteArrayInputStream(bOut.toByteArray()); + ObjectInputStream oIn = new ObjectInputStream(bIn); + + in = Cipher.getInstance(algorithm, "BC"); + out = Cipher.getInstance(algorithm, "BC"); + + key = (Key)oIn.readObject(); + + if (!in.getAlgorithm().startsWith(baseAlgorithm)) + { + fail("wrong cipher returned!"); + } + + if (algorithm.startsWith("RC2")) + { + if (baseAlgorithm.equals(algorithm) || algorithm.indexOf("ECB") > 0) + { + out.init(Cipher.ENCRYPT_MODE, key, new RC2ParameterSpec(rc2Spec.getEffectiveKeyBits()), rand); + } + else + { + out.init(Cipher.ENCRYPT_MODE, key, rc2Spec, rand); + } + } + else if (algorithm.startsWith("RC5")) + { + if (algorithm.startsWith("RC5-64")) + { + out.init(Cipher.ENCRYPT_MODE, key, rc564Spec, rand); + } + else + { + out.init(Cipher.ENCRYPT_MODE, key, rc5Spec, rand); + } + } + else + { + out.init(Cipher.ENCRYPT_MODE, key, rand); + } + + // + // grab the iv if there is one + // + if (algorithm.startsWith("RC2")) + { + if (baseAlgorithm.equals(algorithm) || algorithm.indexOf("ECB") > 0) + { + in.init(Cipher.DECRYPT_MODE, key, new RC2ParameterSpec(rc2Spec.getEffectiveKeyBits()), rand); + } + else + { + in.init(Cipher.DECRYPT_MODE, key, rc2Spec, rand); + } + } + else if (algorithm.startsWith("RC5")) + { + if (algorithm.startsWith("RC5-64")) + { + in.init(Cipher.DECRYPT_MODE, key, rc564Spec, rand); + } + else + { + in.init(Cipher.DECRYPT_MODE, key, rc5Spec, rand); + } + } + else + { + byte[] iv; + + iv = out.getIV(); + if (iv != null) + { + if (!shortIvOkay.contains(mode)) + { + try + { + byte[] nIv = new byte[iv.length - 1]; + + in.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(nIv)); + fail("failed to pick up short IV"); + } + catch (InvalidAlgorithmParameterException e) + { + // ignore - this is what we want... + } + } + + IvParameterSpec spec; + + spec = new IvParameterSpec(iv); + + in.init(Cipher.DECRYPT_MODE, key, spec); + } + else + { + in.init(Cipher.DECRYPT_MODE, key); + } + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail("" + algorithm + " failed encryption - " + e.toString()); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!Arrays.areEqual(bytes, output)) + { + fail("" + algorithm + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + + dIn.close(); + } + catch (Exception e) + { + fail("" + algorithm + " failed decryption - " + e.toString()); + } + + if (!Arrays.areEqual(bytes, input)) + { + fail("" + algorithm + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + + private boolean noIDEA() + { + try + { + Cipher.getInstance("IDEA", "BC"); + + return false; + } + catch (Exception e) + { + return true; + } + } + + private boolean areEqual(byte[] a, int aLen, byte[] b) + { + if (b.length != aLen) + { + return false; + } + + for (int i = 0; i != aLen; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + private void testExceptions() + { + SecretKeyFactory skF = null; + + try + { + skF = SecretKeyFactory.getInstance("DESede", "BC"); + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + + KeySpec ks = null; + SecretKey secKey = null; + byte[] bb = new byte[24]; + + try + { + skF.getKeySpec(null, null); + + fail("failed exception test - no exception thrown"); + } + catch (InvalidKeySpecException e) + { + // ignore okay + } + catch (Exception e) + { + fail("failed exception test.", e); + } + try + { + ks = (KeySpec)new DESedeKeySpec(bb); + skF.getKeySpec(null, ks.getClass()); + + fail("failed exception test - no exception thrown"); + } + catch (InvalidKeySpecException e) + { + // ignore okay; + } + catch (Exception e) + { + fail("failed exception test.", e); + } + try + { + skF.getKeySpec(secKey, null); + } + catch (InvalidKeySpecException e) + { + // ignore okay + } + catch (Exception e) + { + fail("failed exception test.", e); + } + + try + { + KeyGenerator kg = KeyGenerator.getInstance("DESede", "BC"); + try + { + kg.init(Integer.MIN_VALUE, new SecureRandom()); + + fail("failed exception test - no exception thrown"); + } + catch (InvalidParameterException e) + { + // ignore okay + } + catch (Exception e) + { + fail("failed exception test.", e); + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + + try + { + skF = SecretKeyFactory.getInstance("DESede", "BC"); + + try + { + skF.translateKey(null); + + fail("failed exception test - no exception thrown"); + } + catch (InvalidKeyException e) + { + // ignore okay + } + catch (Exception e) + { + fail("failed exception test.", e); + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + + try + { + byte[] rawDESKey = { (byte)128, (byte)131, (byte)133, (byte)134, + (byte)137, (byte)138, (byte)140, (byte)143 }; + + SecretKeySpec cipherKey = new SecretKeySpec(rawDESKey, "DES"); + + Cipher cipher = Cipher.getInstance("DES/CBC/NoPadding", "BC"); + + try + { + // According specification engineInit(int opmode, Key key, + // SecureRandom random) throws InvalidKeyException if this + // cipher is being + // initialized for decryption and requires algorithm parameters + // that cannot be determined from the given key + cipher.init(Cipher.DECRYPT_MODE, cipherKey, (SecureRandom)null); + + fail("failed exception test - no InvalidKeyException thrown"); + } + catch (InvalidKeyException e) + { + // ignore + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + + try + { + byte[] rawDESKey = { -128, -125, -123, -122, -119, -118 }; + + SecretKeySpec cipherKey = new SecretKeySpec(rawDESKey, "DES"); + Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding", "BC"); + try + { + // According specification engineInit(int opmode, Key key, + // SecureRandom random) throws InvalidKeyException if the given + // key is inappropriate for initializing this cipher + cipher.init(Cipher.ENCRYPT_MODE, cipherKey); + + fail("failed exception test - no InvalidKeyException thrown"); + } + catch (InvalidKeyException e) + { + // ignore + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + + try + { + byte[] rawDESKey = { -128, -125, -123, -122, -119, -118, -117, -115, -114 }; + + SecretKeySpec cipherKey = new SecretKeySpec(rawDESKey, "DES"); + Cipher cipher = Cipher.getInstance("DES/ECB/NoPadding", "BC"); + try + { + // According specification engineInit(int opmode, Key key, + // SecureRandom random) throws InvalidKeyException if the given + // key is inappropriate for initializing this cipher + cipher.init(Cipher.ENCRYPT_MODE, cipherKey); + + fail("failed exception test - no InvalidKeyException thrown"); + } + catch (InvalidKeyException e) + { + // ignore + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + + + try + { + byte[] rawDESKey = { (byte)128, (byte)131, (byte)133, (byte)134, + (byte)137, (byte)138, (byte)140, (byte)143 }; + + SecretKeySpec cipherKey = new SecretKeySpec(rawDESKey, "DES"); + Cipher ecipher = Cipher.getInstance("DES/ECB/PKCS5Padding", "BC"); + ecipher.init(Cipher.ENCRYPT_MODE, cipherKey); + + byte[] cipherText = new byte[0]; + try + { + // According specification Method engineUpdate(byte[] input, + // int inputOffset, int inputLen, byte[] output, int + // outputOffset) + // throws ShortBufferException - if the given output buffer is + // too + // small to hold the result + ecipher.update(new byte[20], 0, 20, cipherText); + + fail("failed exception test - no ShortBufferException thrown"); + } + catch (ShortBufferException e) + { + // ignore + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + + try + { + byte[] rawDESKey = { (byte)128, (byte)131, (byte)133, (byte)134, + (byte)137, (byte)138, (byte)140, (byte)143 }; + + SecretKeySpec cipherKey = new SecretKeySpec(rawDESKey, "DES"); + Cipher ecipher = Cipher.getInstance("DES/ECB/PKCS5Padding", "BC"); + ecipher.init(Cipher.ENCRYPT_MODE, cipherKey); + + byte[] cipherText = new byte[0]; + try + { + // According specification Method enginedoFinal(byte[] input, + // int inputOffset, int inputLen, byte[] output, int + // outputOffset) + // throws ShortBufferException - if the given output buffer is + // too + // small to hold the result + ecipher.doFinal(new byte[20], 0, 20, cipherText); + + fail("failed exception test - no ShortBufferException thrown"); + } + catch (ShortBufferException e) + { + // ignore + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + + try + { + KeyGenerator keyGen = KeyGenerator.getInstance("DES", "BC"); + + keyGen.init((SecureRandom)null); + + // According specification engineGenerateKey() doesn't throw any exceptions. + + SecretKey key = keyGen.generateKey(); + if (key == null) + { + fail("key is null!"); + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + + try + { + AlgorithmParameters algParams = AlgorithmParameters.getInstance("DES", "BC"); + + algParams.init(new IvParameterSpec(new byte[8])); + + // According specification engineGetEncoded() returns + // the parameters in their primary encoding format. The primary + // encoding + // format for parameters is ASN.1, if an ASN.1 specification for + // this type + // of parameters exists. + byte[] iv = algParams.getEncoded(); + + if (iv.length != 10) + { + fail("parameters encoding wrong length - " + iv.length); + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + + try + { + try + { + AlgorithmParameters algParams = AlgorithmParameters.getInstance("DES", "BC"); + + byte[] encoding = new byte[10]; + encoding[0] = 3; + encoding[1] = 8; + + // According specification engineInit(byte[] params, String format) + // throws + // IOException on decoding errors, but BC throws ClassCastException. + algParams.init(encoding, "ASN.1"); + + fail("failed exception test - no IOException thrown"); + } + catch (IOException e) + { + // okay + } + + try + { + Cipher c = Cipher.getInstance("DES", "BC"); + + Key k = new PublicKey() + { + + public String getAlgorithm() + { + return "STUB"; + } + + public String getFormat() + { + return null; + } + + public byte[] getEncoded() + { + return null; + } + + }; + + c.init(Cipher.ENCRYPT_MODE, k); + + fail("failed exception test - no InvalidKeyException thrown for public key"); + } + catch (InvalidKeyException e) + { + // okay + } + + try + { + Cipher c = Cipher.getInstance("DES", "BC"); + + Key k = new PrivateKey() + { + + public String getAlgorithm() + { + return "STUB"; + } + + public String getFormat() + { + return null; + } + + public byte[] getEncoded() + { + return null; + } + + }; + + c.init(Cipher.DECRYPT_MODE, k); + + fail("failed exception test - no InvalidKeyException thrown for private key"); + } + catch (InvalidKeyException e) + { + // okay + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + } + + public void performTest() + { + for (int i = 0; i != cipherTests1.length; i += 2) + { + test(cipherTests1[i], input1, Hex.decode(cipherTests1[i + 1])); + } + + for (int i = 0; i != cipherTests2.length; i += 2) + { + test(cipherTests2[i], input2, Hex.decode(cipherTests2[i + 1])); + } + + for (int i = 0; i != cipherTestsLargeBlock.length; i += 2) + { + test(cipherTestsLargeBlock[i], inputLargeBlock, Hex.decode(cipherTestsLargeBlock[i + 1])); + } + + // + // check for less than a block + // + try + { + Cipher c = Cipher.getInstance("AES/CTS/NoPadding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(new byte[16], "AES")); + + c.doFinal(new byte[4]); + + fail("CTS failed to throw exception"); + } + catch (Exception e) + { + if (!(e instanceof IllegalBlockSizeException)) + { + fail("CTS exception test - " + e, e); + } + } + + testExceptions(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new BlockCipherTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CMacTest.java new file mode 100644 index 000000000..e4f73006b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CMacTest.java @@ -0,0 +1,329 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Key; +import java.security.Security; + +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * CMAC tester - AES Official Test Vectors. + */ +public class CMacTest + extends SimpleTest +{ + private static final byte[] keyBytes128 = Hex.decode("2b7e151628aed2a6abf7158809cf4f3c"); + private static final byte[] keyBytes192 = Hex.decode( + "8e73b0f7da0e6452c810f32b809079e5" + + "62f8ead2522c6b7b"); + private static final byte[] keyBytes256 = Hex.decode( + "603deb1015ca71be2b73aef0857d7781" + + "1f352c073b6108d72d9810a30914dff4"); + + private static final byte[] input0 = Hex.decode(""); + private static final byte[] input16 = Hex.decode("6bc1bee22e409f96e93d7e117393172a"); + private static final byte[] input40 = Hex.decode( + "6bc1bee22e409f96e93d7e117393172a" + + "ae2d8a571e03ac9c9eb76fac45af8e5130c81c46a35ce411"); + private static final byte[] input64 = Hex.decode( + "6bc1bee22e409f96e93d7e117393172a" + + "ae2d8a571e03ac9c9eb76fac45af8e51" + + "30c81c46a35ce411e5fbc1191a0a52ef" + + "f69f2445df4f9b17ad2b417be66c3710"); + + private static final byte[] output_k128_m0 = Hex.decode("bb1d6929e95937287fa37d129b756746"); + private static final byte[] output_k128_m16 = Hex.decode("070a16b46b4d4144f79bdd9dd04a287c"); + private static final byte[] output_k128_m40 = Hex.decode("dfa66747de9ae63030ca32611497c827"); + private static final byte[] output_k128_m64 = Hex.decode("51f0bebf7e3b9d92fc49741779363cfe"); + + private static final byte[] output_k192_m0 = Hex.decode("d17ddf46adaacde531cac483de7a9367"); + private static final byte[] output_k192_m16 = Hex.decode("9e99a7bf31e710900662f65e617c5184"); + private static final byte[] output_k192_m40 = Hex.decode("8a1de5be2eb31aad089a82e6ee908b0e"); + private static final byte[] output_k192_m64 = Hex.decode("a1d5df0eed790f794d77589659f39a11"); + + private static final byte[] output_k256_m0 = Hex.decode("028962f61b7bf89efc6b551f4667d983"); + private static final byte[] output_k256_m16 = Hex.decode("28a7023f452e8f82bd4bf28d8c37c35c"); + private static final byte[] output_k256_m40 = Hex.decode("aaf3d8f1de5640c232f5b169b9c911e6"); + private static final byte[] output_k256_m64 = Hex.decode("e1992190549f6ed5696a2c056c315410"); + + private final byte[] output_des_ede = Hex.decode("1ca670dea381d37c"); + + private static final byte[] general_input = Strings.toByteArray("The quick brown fox jumps over the lazy dog."); + + public CMacTest() + { + } + + public void performTest() + throws Exception + { + Mac mac = Mac.getInstance("AESCMAC", "BC"); + + //128 bytes key + + SecretKeySpec key = new SecretKeySpec(keyBytes128, "AES"); + + // 0 bytes message - 128 bytes key + mac.init(key); + + mac.update(input0, 0, input0.length); + + byte[] out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m0)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m0)) + + " got " + new String(Hex.encode(out))); + } + + // 16 bytes message - 128 bytes key + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m16)) + + " got " + new String(Hex.encode(out))); + } + + // 40 bytes message - 128 bytes key + mac.init(key); + + mac.update(input40, 0, input40.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m40)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m40)) + + " got " + new String(Hex.encode(out))); + } + + // 64 bytes message - 128 bytes key + mac.init(key); + + mac.update(input64, 0, input64.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k128_m64)) + { + fail("Failed - expected " + new String(Hex.encode(output_k128_m64)) + + " got " + new String(Hex.encode(out))); + } + + //192 bytes key + + key = new SecretKeySpec(keyBytes192, "AES"); + + // 0 bytes message - 192 bytes key + mac.init(key); + + mac.update(input0, 0, input0.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m0)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m0)) + + " got " + new String(Hex.encode(out))); + } + + // 16 bytes message - 192 bytes key + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m16)) + + " got " + new String(Hex.encode(out))); + } + + // 40 bytes message - 192 bytes key + mac.init(key); + + mac.update(input40, 0, input40.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m40)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m40)) + + " got " + new String(Hex.encode(out))); + } + + // 64 bytes message - 192 bytes key + mac.init(key); + + mac.update(input64, 0, input64.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k192_m64)) + { + fail("Failed - expected " + new String(Hex.encode(output_k192_m64)) + + " got " + new String(Hex.encode(out))); + } + + //256 bytes key + + key = new SecretKeySpec(keyBytes256, "AES"); + + // 0 bytes message - 256 bytes key + mac.init(key); + + mac.update(input0, 0, input0.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m0)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m0)) + + " got " + new String(Hex.encode(out))); + } + + // 16 bytes message - 256 bytes key + mac.init(key); + + mac.update(input16, 0, input16.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m16)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m16)) + + " got " + new String(Hex.encode(out))); + } + + // 40 bytes message - 256 bytes key + mac.init(key); + + mac.update(input40, 0, input40.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m40)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m40)) + + " got " + new String(Hex.encode(out))); + } + + // 64 bytes message - 256 bytes key + mac.init(key); + + mac.update(input64, 0, input64.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_k256_m64)) + { + fail("Failed - expected " + new String(Hex.encode(output_k256_m64)) + + " got " + new String(Hex.encode(out))); + } + + mac = Mac.getInstance("DESedeCMAC", "BC"); + + //DESede + + key = new SecretKeySpec(keyBytes128, "DESede"); + + // 0 bytes message - 128 bytes key + mac.init(key); + + mac.update(input0, 0, input0.length); + + out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, output_des_ede)) + { + fail("Failed - expected " + new String(Hex.encode(output_des_ede)) + + " got " + new String(Hex.encode(out))); + } + + testCMac(Mac.getInstance("DESedeCMAC", "BC"), keyBytes128, "DESede", input0, output_des_ede); + + testCMac(Mac.getInstance("BlowfishCMAC", "BC"), "2b7e151628aed2a6abf7158809cf4f3c", "Blowfish", "875d73b9bc3de78a"); + testCMac(Mac.getInstance("SEED-CMAC", "BC"), "2b7e151628aed2a6abf7158809cf4f3c", "SEED", "73624c03548a1aaeab9104e47fbd14b1"); + testCMac(Mac.getInstance("SM4-CMAC", "BC"), "2b7e151628aed2a6abf7158809cf4f3c", "SM4", "25b84c0bb3f0cb0c285148a62a09940a"); + testCMac(Mac.getInstance("SHACAL-2CMAC", "BC"), "2b7e151628aed2a6abf7158809cf4f3c", "SHACAL-2", "794b2766cd0d550877f1ded48ab74f9ddff20f32e6d69fae8a1ede4205e7d640"); + testCMac(Mac.getInstance("Threefish-256CMAC", "BC"), "2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c", "Threefish-256", "107a7afec4d17ba4a7bf6b80e5f34b39d066abf168d413ddd16d7ad97515bfff"); + testCMac(Mac.getInstance("Threefish-512CMAC", "BC"), "2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c", "Threefish-512", "b3499567f5846fa6de3bd3f8d885d726976026cd0b04ec2e95431d9aed7743b7c1629d5759b3bca48aeb0c76a905ddfed5cd45c598dfd41d3a9f5964b3a6c4cf"); + testCMac(Mac.getInstance("Threefish-1024CMAC", "BC"), "2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c2b7e151628aed2a6abf7158809cf4f3c", + "Threefish-1024", "644009204fcf388e692f989c435a41b4218c6cb7ee3589170e3cf791d007f5c9fd0b389be769f144d36ea19b4c7489812a68c81ba7cc756c6d143a4bbe3175a415897b70f736cd4251b98cff3d357d0c2a1036d0df154bf6cf514c04ce01c1059002082c4792dbb4b7638aa04064d8b93c2c8fe5512f2e05d14ac9bf66397dea"); + } + + private void testCMac(Mac mac, String keyBytes, String algorithm, String expected) + throws Exception + { + testCMac(mac, Hex.decode(keyBytes), algorithm, general_input, Hex.decode(expected)); + } + + private void testCMac(Mac mac, byte[] keyBytes, String algorithm, byte[] input, byte[] expected) + throws Exception + { + Key key = new SecretKeySpec(keyBytes, algorithm); + + mac.init(key); + + mac.update(input, 0, input.length); + + byte[] out = new byte[mac.getMacLength()]; + + mac.doFinal(out, 0); + + if (!areEqual(out, expected)) + { + fail("Failed - expected " + new String(Hex.encode(expected)) + + " got " + new String(Hex.encode(out))); + } + } + + public String getName() + { + return "CMac"; + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new CMacTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CRL5Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CRL5Test.java new file mode 100644 index 000000000..e45e28f15 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CRL5Test.java @@ -0,0 +1,268 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.security.Security; +import java.security.cert.CertificateFactory; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLEntry; +import java.util.Iterator; +import java.util.Set; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class CRL5Test + extends SimpleTest +{ + byte[] inDirectCrl = Base64.decode( + "MIIdXjCCHMcCAQEwDQYJKoZIhvcNAQEFBQAwdDELMAkGA1UEBhMCREUxHDAaBgNV" + +"BAoUE0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0" + +"MS4wDAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBO" + +"Fw0wNjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIbfzB+AgQvrj/pFw0wMzA3" + +"MjIwNTQxMjhaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD" + +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU" + +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+oXDTAzMDcyMjA1NDEyOFowZzBlBgNV" + +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl" + +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6" + +"UE4wfgIEL64/5xcNMDQwNDA1MTMxODE3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw" + +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC" + +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/oFw0wNDA0" + +"MDUxMzE4MTdaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD" + +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU" + +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+UXDTAzMDExMzExMTgxMVowZzBlBgNV" + +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl" + +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6" + +"UE4wfgIEL64/5hcNMDMwMTEzMTExODExWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw" + +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC" + +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/jFw0wMzAx" + +"MTMxMTI2NTZaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD" + +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU" + +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP+QXDTAzMDExMzExMjY1NlowZzBlBgNV" + +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl" + +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6" + +"UE4wfgIEL64/4hcNMDQwNzEzMDc1ODM4WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw" + +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC" + +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/eFw0wMzAy" + +"MTcwNjMzMjVaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD" + +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU" + +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP98XDTAzMDIxNzA2MzMyNVowZzBlBgNV" + +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl" + +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6" + +"UE4wfgIEL64/0xcNMDMwMjE3MDYzMzI1WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw" + +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC" + +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/dFw0wMzAx" + +"MTMxMTI4MTRaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD" + +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU" + +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP9cXDTAzMDExMzExMjcwN1owZzBlBgNV" + +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl" + +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6" + +"UE4wfgIEL64/2BcNMDMwMTEzMTEyNzA3WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw" + +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC" + +"BgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNDpQTjB+AgQvrj/VFw0wMzA0" + +"MzAxMjI3NTNaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYD" + +"VQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMU" + +"EVNpZ0cgVGVzdCBDQSA0OlBOMH4CBC+uP9YXDTAzMDQzMDEyMjc1M1owZzBlBgNV" + +"HR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl" + +"bGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDQ6" + +"UE4wfgIEL64/xhcNMDMwMjEyMTM0NTQwWjBnMGUGA1UdHQEB/wRbMFmkVzBVMQsw" + +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKC" + +"BgEKBxQTATEwGAYDVQQDFBFUVEMgVGVzdCBDQSAxMTpQTjCBkAIEL64/xRcNMDMw" + +"MjEyMTM0NTQwWjB5MHcGA1UdHQEB/wRtMGukaTBnMQswCQYDVQQGEwJERTEcMBoG" + +"A1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEQMA4GA1UECxQHVGVsZVNlYzEoMAwG" + +"BwKCBgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0EgNTpQTjB+AgQvrj/CFw0w" + +"MzAyMTIxMzA5MTZaMGcwZQYDVR0dAQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRww" + +"GgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNV" + +"BAMUEVRUQyBUZXN0IENBIDExOlBOMIGQAgQvrj/BFw0wMzAyMTIxMzA4NDBaMHkw" + +"dwYDVR0dAQH/BG0wa6RpMGcxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2No" + +"ZSBUZWxla29tIEFHMRAwDgYDVQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAY" + +"BgNVBAMUEVNpZ0cgVGVzdCBDQSA1OlBOMH4CBC+uP74XDTAzMDIxNzA2MzcyNVow" + +"ZzBlBgNVHR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRz" + +"Y2hlIFRlbGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRVFRDIFRlc3Qg" + +"Q0EgMTE6UE4wgZACBC+uP70XDTAzMDIxNzA2MzcyNVoweTB3BgNVHR0BAf8EbTBr" + +"pGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcx" + +"EDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBU" + +"ZXN0IENBIDU6UE4wgZACBC+uP7AXDTAzMDIxMjEzMDg1OVoweTB3BgNVHR0BAf8E" + +"bTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20g" + +"QUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2ln" + +"RyBUZXN0IENBIDU6UE4wgZACBC+uP68XDTAzMDIxNzA2MzcyNVoweTB3BgNVHR0B" + +"Af8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVr" + +"b20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQR" + +"U2lnRyBUZXN0IENBIDU6UE4wfgIEL64/kxcNMDMwNDEwMDUyNjI4WjBnMGUGA1Ud" + +"HQEB/wRbMFmkVzBVMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVs" + +"ZWtvbSBBRzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFUVEMgVGVzdCBDQSAxMTpQ" + +"TjCBkAIEL64/khcNMDMwNDEwMDUyNjI4WjB5MHcGA1UdHQEB/wRtMGukaTBnMQsw" + +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEQMA4GA1UE" + +"CxQHVGVsZVNlYzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFTaWdHIFRlc3QgQ0Eg" + +"NTpQTjB+AgQvrj8/Fw0wMzAyMjYxMTA0NDRaMGcwZQYDVR0dAQH/BFswWaRXMFUx" + +"CzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMSgwDAYH" + +"AoIGAQoHFBMBMTAYBgNVBAMUEVRUQyBUZXN0IENBIDExOlBOMIGQAgQvrj8+Fw0w" + +"MzAyMjYxMTA0NDRaMHkwdwYDVR0dAQH/BG0wa6RpMGcxCzAJBgNVBAYTAkRFMRww" + +"GgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAwDgYDVQQLFAdUZWxlU2VjMSgw" + +"DAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVzdCBDQSA1OlBOMH4CBC+uPs0X" + +"DTAzMDUyMDA1MjczNlowZzBlBgNVHR0BAf8EWzBZpFcwVTELMAkGA1UEBhMCREUx" + +"HDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxKDAMBgcCggYBCgcUEwExMBgG" + +"A1UEAxQRVFRDIFRlc3QgQ0EgMTE6UE4wgZACBC+uPswXDTAzMDUyMDA1MjczNlow" + +"eTB3BgNVHR0BAf8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRz" + +"Y2hlIFRlbGVrb20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwEx" + +"MBgGA1UEAxQRU2lnRyBUZXN0IENBIDY6UE4wfgIEL64+PBcNMDMwNjE3MTAzNDE2" + +"WjBnMGUGA1UdHQEB/wRbMFmkVzBVMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1" + +"dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFUVEMgVGVz" + +"dCBDQSAxMTpQTjCBkAIEL64+OxcNMDMwNjE3MTAzNDE2WjB5MHcGA1UdHQEB/wRt" + +"MGukaTBnMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBB" + +"RzEQMA4GA1UECxQHVGVsZVNlYzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFTaWdH" + +"IFRlc3QgQ0EgNjpQTjCBkAIEL64+OhcNMDMwNjE3MTAzNDE2WjB5MHcGA1UdHQEB" + +"/wRtMGukaTBnMQswCQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtv" + +"bSBBRzEQMA4GA1UECxQHVGVsZVNlYzEoMAwGBwKCBgEKBxQTATEwGAYDVQQDFBFT" + +"aWdHIFRlc3QgQ0EgNjpQTjB+AgQvrj45Fw0wMzA2MTcxMzAxMDBaMGcwZQYDVR0d" + +"AQH/BFswWaRXMFUxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxl" + +"a29tIEFHMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVRUQyBUZXN0IENBIDExOlBO" + +"MIGQAgQvrj44Fw0wMzA2MTcxMzAxMDBaMHkwdwYDVR0dAQH/BG0wa6RpMGcxCzAJ" + +"BgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAwDgYDVQQL" + +"FAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVzdCBDQSA2" + +"OlBOMIGQAgQvrj43Fw0wMzA2MTcxMzAxMDBaMHkwdwYDVR0dAQH/BG0wa6RpMGcx" + +"CzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAwDgYD" + +"VQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVzdCBD" + +"QSA2OlBOMIGQAgQvrj42Fw0wMzA2MTcxMzAxMDBaMHkwdwYDVR0dAQH/BG0wa6Rp" + +"MGcxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMRAw" + +"DgYDVQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cgVGVz" + +"dCBDQSA2OlBOMIGQAgQvrj4zFw0wMzA2MTcxMDM3NDlaMHkwdwYDVR0dAQH/BG0w" + +"a6RpMGcxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFH" + +"MRAwDgYDVQQLFAdUZWxlU2VjMSgwDAYHAoIGAQoHFBMBMTAYBgNVBAMUEVNpZ0cg" + +"VGVzdCBDQSA2OlBOMH4CBC+uPjEXDTAzMDYxNzEwNDI1OFowZzBlBgNVHR0BAf8E" + +"WzBZpFcwVTELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20g" + +"QUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRVFRDIFRlc3QgQ0EgMTE6UE4wgZAC" + +"BC+uPjAXDTAzMDYxNzEwNDI1OFoweTB3BgNVHR0BAf8EbTBrpGkwZzELMAkGA1UE" + +"BhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAOBgNVBAsUB1Rl" + +"bGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDY6UE4w" + +"gZACBC+uPakXDTAzMTAyMjExMzIyNFoweTB3BgNVHR0BAf8EbTBrpGkwZzELMAkG" + +"A1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAOBgNVBAsU" + +"B1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENBIDY6" + +"UE4wgZACBC+uPLIXDTA1MDMxMTA2NDQyNFoweTB3BgNVHR0BAf8EbTBrpGkwZzEL" + +"MAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAOBgNV" + +"BAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0IENB" + +"IDY6UE4wgZACBC+uPKsXDTA0MDQwMjA3NTQ1M1oweTB3BgNVHR0BAf8EbTBrpGkw" + +"ZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcxEDAO" + +"BgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBUZXN0" + +"IENBIDY6UE4wgZACBC+uOugXDTA1MDEyNzEyMDMyNFoweTB3BgNVHR0BAf8EbTBr" + +"pGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20gQUcx" + +"EDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2lnRyBU" + +"ZXN0IENBIDY6UE4wgZACBC+uOr4XDTA1MDIxNjA3NTcxNloweTB3BgNVHR0BAf8E" + +"bTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVrb20g" + +"QUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRU2ln" + +"RyBUZXN0IENBIDY6UE4wgZACBC+uOqcXDTA1MDMxMDA1NTkzNVoweTB3BgNVHR0B" + +"Af8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRlbGVr" + +"b20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQR" + +"U2lnRyBUZXN0IENBIDY6UE4wgZACBC+uOjwXDTA1MDUxMTEwNDk0NloweTB3BgNV" + +"HR0BAf8EbTBrpGkwZzELMAkGA1UEBhMCREUxHDAaBgNVBAoUE0RldXRzY2hlIFRl" + +"bGVrb20gQUcxEDAOBgNVBAsUB1RlbGVTZWMxKDAMBgcCggYBCgcUEwExMBgGA1UE" + +"AxQRU2lnRyBUZXN0IENBIDY6UE4wgaoCBC+sbdUXDTA1MTExMTEwMDMyMVowgZIw" + +"gY8GA1UdHQEB/wSBhDCBgaR/MH0xCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0" + +"c2NoZSBUZWxla29tIEFHMR8wHQYDVQQLFBZQcm9kdWt0emVudHJ1bSBUZWxlU2Vj" + +"MS8wDAYHAoIGAQoHFBMBMTAfBgNVBAMUGFRlbGVTZWMgUEtTIFNpZ0cgQ0EgMTpQ" + +"TjCBlQIEL64uaBcNMDYwMTIzMTAyNTU1WjB+MHwGA1UdHQEB/wRyMHCkbjBsMQsw" + +"CQYDVQQGEwJERTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEWMBQGA1UE" + +"CxQNWmVudHJhbGUgQm9ubjEnMAwGBwKCBgEKBxQTATEwFwYDVQQDFBBUVEMgVGVz" + +"dCBDQSA5OlBOMIGVAgQvribHFw0wNjA4MDEwOTQ4NDRaMH4wfAYDVR0dAQH/BHIw" + +"cKRuMGwxCzAJBgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFH" + +"MRYwFAYDVQQLFA1aZW50cmFsZSBCb25uMScwDAYHAoIGAQoHFBMBMTAXBgNVBAMU" + +"EFRUQyBUZXN0IENBIDk6UE6ggZswgZgwCwYDVR0UBAQCAhEMMB8GA1UdIwQYMBaA" + +"FANbyNumDI9545HwlCF26NuOJC45MA8GA1UdHAEB/wQFMAOEAf8wVwYDVR0SBFAw" + +"ToZMbGRhcDovL3Brc2xkYXAudHR0Yy5kZS9vdT1ULVRlbGVTZWMgVGVzdCBESVIg" + +"ODpQTixvPURldXRzY2hlIFRlbGVrb20gQUcsYz1kZTANBgkqhkiG9w0BAQUFAAOB" + +"gQBewL5gLFHpeOWO07Vk3Gg7pRDuAlvaovBH4coCyCWpk5jEhUfFSYEDuaQB7do4" + +"IlJmeTHvkI0PIZWJ7bwQ2PVdipPWDx0NVwS/Cz5jUKiS3BbAmZQZOueiKLFpQq3A" + +"b8aOHA7WHU4078/1lM+bgeu33Ln1CGykEbmSjA/oKPi/JA=="); + + byte[] directCRL = Base64.decode( + "MIIGXTCCBckCAQEwCgYGKyQDAwECBQAwdDELMAkGA1UEBhMCREUxHDAaBgNVBAoU" + +"E0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0MS4w" + +"DAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBOFw0w" + +"NjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIElTAVAgQvrj/pFw0wMzA3MjIw" + +"NTQxMjhaMBUCBC+uP+oXDTAzMDcyMjA1NDEyOFowFQIEL64/5xcNMDQwNDA1MTMx" + +"ODE3WjAVAgQvrj/oFw0wNDA0MDUxMzE4MTdaMBUCBC+uP+UXDTAzMDExMzExMTgx" + +"MVowFQIEL64/5hcNMDMwMTEzMTExODExWjAVAgQvrj/jFw0wMzAxMTMxMTI2NTZa" + +"MBUCBC+uP+QXDTAzMDExMzExMjY1NlowFQIEL64/4hcNMDQwNzEzMDc1ODM4WjAV" + +"AgQvrj/eFw0wMzAyMTcwNjMzMjVaMBUCBC+uP98XDTAzMDIxNzA2MzMyNVowFQIE" + +"L64/0xcNMDMwMjE3MDYzMzI1WjAVAgQvrj/dFw0wMzAxMTMxMTI4MTRaMBUCBC+u" + +"P9cXDTAzMDExMzExMjcwN1owFQIEL64/2BcNMDMwMTEzMTEyNzA3WjAVAgQvrj/V" + +"Fw0wMzA0MzAxMjI3NTNaMBUCBC+uP9YXDTAzMDQzMDEyMjc1M1owFQIEL64/xhcN" + +"MDMwMjEyMTM0NTQwWjAVAgQvrj/FFw0wMzAyMTIxMzQ1NDBaMBUCBC+uP8IXDTAz" + +"MDIxMjEzMDkxNlowFQIEL64/wRcNMDMwMjEyMTMwODQwWjAVAgQvrj++Fw0wMzAy" + +"MTcwNjM3MjVaMBUCBC+uP70XDTAzMDIxNzA2MzcyNVowFQIEL64/sBcNMDMwMjEy" + +"MTMwODU5WjAVAgQvrj+vFw0wMzAyMTcwNjM3MjVaMBUCBC+uP5MXDTAzMDQxMDA1" + +"MjYyOFowFQIEL64/khcNMDMwNDEwMDUyNjI4WjAVAgQvrj8/Fw0wMzAyMjYxMTA0" + +"NDRaMBUCBC+uPz4XDTAzMDIyNjExMDQ0NFowFQIEL64+zRcNMDMwNTIwMDUyNzM2" + +"WjAVAgQvrj7MFw0wMzA1MjAwNTI3MzZaMBUCBC+uPjwXDTAzMDYxNzEwMzQxNlow" + +"FQIEL64+OxcNMDMwNjE3MTAzNDE2WjAVAgQvrj46Fw0wMzA2MTcxMDM0MTZaMBUC" + +"BC+uPjkXDTAzMDYxNzEzMDEwMFowFQIEL64+OBcNMDMwNjE3MTMwMTAwWjAVAgQv" + +"rj43Fw0wMzA2MTcxMzAxMDBaMBUCBC+uPjYXDTAzMDYxNzEzMDEwMFowFQIEL64+" + +"MxcNMDMwNjE3MTAzNzQ5WjAVAgQvrj4xFw0wMzA2MTcxMDQyNThaMBUCBC+uPjAX" + +"DTAzMDYxNzEwNDI1OFowFQIEL649qRcNMDMxMDIyMTEzMjI0WjAVAgQvrjyyFw0w" + +"NTAzMTEwNjQ0MjRaMBUCBC+uPKsXDTA0MDQwMjA3NTQ1M1owFQIEL6466BcNMDUw" + +"MTI3MTIwMzI0WjAVAgQvrjq+Fw0wNTAyMTYwNzU3MTZaMBUCBC+uOqcXDTA1MDMx" + +"MDA1NTkzNVowFQIEL646PBcNMDUwNTExMTA0OTQ2WjAVAgQvrG3VFw0wNTExMTEx" + +"MDAzMjFaMBUCBC+uLmgXDTA2MDEyMzEwMjU1NVowFQIEL64mxxcNMDYwODAxMDk0" + +"ODQ0WqCBijCBhzALBgNVHRQEBAICEQwwHwYDVR0jBBgwFoAUA1vI26YMj3njkfCU" + +"IXbo244kLjkwVwYDVR0SBFAwToZMbGRhcDovL3Brc2xkYXAudHR0Yy5kZS9vdT1U" + +"LVRlbGVTZWMgVGVzdCBESVIgODpQTixvPURldXRzY2hlIFRlbGVrb20gQUcsYz1k" + +"ZTAKBgYrJAMDAQIFAAOBgQArj4eMlbAwuA2aS5O4UUUHQMKKdK/dtZi60+LJMiMY" + +"ojrMIf4+ZCkgm1Ca0Cd5T15MJxVHhh167Ehn/Hd48pdnAP6Dfz/6LeqkIHGWMHR+" + +"z6TXpwWB+P4BdUec1ztz04LypsznrHcLRa91ixg9TZCb1MrOG+InNhleRs1ImXk8" + +"MQ=="); + + + public String getName() + { + return "CRL5"; + } + + public void indirectCRLTest() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + ByteArrayInputStream in = new ByteArrayInputStream(inDirectCrl); + X509CRL crl = (X509CRL) cf.generateCRL(in); + Set set = crl.getRevokedCertificates(); + Iterator it = set.iterator(); + while (it.hasNext()) + { + if (((X509CRLEntry)it.next()).getCertificateIssuer() == null) + { + fail("certificate issuer CRL entry extension is null"); + } + } + } + + public void directCRLTest() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + ByteArrayInputStream in = new ByteArrayInputStream(directCRL); + X509CRL crl = (X509CRL) cf.generateCRL(in); + Set set = crl.getRevokedCertificates(); + Iterator it = set.iterator(); + while (it.hasNext()) + { + if (((X509CRLEntry)it.next()).getCertificateIssuer() != null) + { + fail("certificate issuer CRL entry extension is not null"); + } + } + } + + public void performTest() + throws Exception + { + indirectCRLTest(); + directCRLTest(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new CRL5Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CamelliaTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CamelliaTest.java new file mode 100644 index 000000000..459283cae --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CamelliaTest.java @@ -0,0 +1,189 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import com.fr.third.org.bouncycastle.asn1.ntt.NTTObjectIdentifiers; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.Security; + +/** + * basic test class for Camellia + */ +public class CamelliaTest + extends BaseBlockCipherTest +{ + static String[] cipherTests = + { + "128", + "0123456789abcdeffedcba9876543210", + "0123456789abcdeffedcba9876543210", + "67673138549669730857065648eabe43", + "192", + "0123456789abcdeffedcba98765432100011223344556677", + "0123456789abcdeffedcba9876543210", + "b4993401b3e996f84ee5cee7d79b09b9", + "256", + "0123456789abcdeffedcba987654321000112233445566778899aabbccddeeff", + "0123456789abcdeffedcba9876543210", + "9acc237dff16d76c20ef7c919e3a7509", + }; + + public CamelliaTest() + { + super("Camellia"); + } + + public void test( + int strength, + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "Camellia"); + + in = Cipher.getInstance("Camellia/ECB/NoPadding", "BC"); + out = Cipher.getInstance("Camellia/ECB/NoPadding", "BC"); + + try + { + out.init(Cipher.ENCRYPT_MODE, key); + } + catch (Exception e) + { + fail("Camellia failed initialisation - " + e.toString(), e); + } + + try + { + in.init(Cipher.DECRYPT_MODE, key); + } + catch (Exception e) + { + fail("Camellia failed initialisation - " + e.toString(), e); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail("Camellia failed encryption - " + e.toString(), e); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("Camellia failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + } + catch (Exception e) + { + fail("Camellia failed encryption - " + e.toString(), e); + } + + if (!areEqual(bytes, input)) + { + fail("Camellia failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + public void performTest() + throws Exception + { + for (int i = 0; i != cipherTests.length; i += 4) + { + test(Integer.parseInt(cipherTests[i]), + Hex.decode(cipherTests[i + 1]), + Hex.decode(cipherTests[i + 2]), + Hex.decode(cipherTests[i + 3])); + } + + byte[] kek1 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] in1 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out1 = Hex.decode("635d6ac46eedebd3a7f4a06421a4cbd1746b24795ba2f708"); + + wrapTest(1, "CamelliaWrap", kek1, in1, out1); + + String[] oids = { + NTTObjectIdentifiers.id_camellia128_cbc.getId(), + NTTObjectIdentifiers.id_camellia192_cbc.getId(), + NTTObjectIdentifiers.id_camellia256_cbc.getId() + }; + + String[] names = { + "Camellia/CBC/PKCS7Padding", + "Camellia/CBC/PKCS7Padding", + "Camellia/CBC/PKCS7Padding" + }; + + oidTest(oids, names, 1); + + String[] wrapOids = { + NTTObjectIdentifiers.id_camellia128_wrap.getId(), + NTTObjectIdentifiers.id_camellia192_wrap.getId(), + NTTObjectIdentifiers.id_camellia256_wrap.getId() + }; + + wrapOidTest(wrapOids, "CamelliaWrap"); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new CamelliaTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertPathBuilderTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertPathBuilderTest.java new file mode 100644 index 000000000..08ca48058 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertPathBuilderTest.java @@ -0,0 +1,140 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.Security; +import java.security.cert.CertPath; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertStore; +import java.security.cert.CertificateFactory; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXCertPathBuilderResult; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class CertPathBuilderTest + extends SimpleTest +{ + + private void baseTest() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + // initialise CertStore + X509Certificate rootCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.rootCertBin)); + X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.interCertBin)); + X509Certificate finalCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.finalCertBin)); + X509CRL rootCrl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(CertPathTest.rootCrlBin)); + X509CRL interCrl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(CertPathTest.interCrlBin)); + List list = new ArrayList(); + list.add(rootCert); + list.add(interCert); + list.add(finalCert); + list.add(rootCrl); + list.add(interCrl); + CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list); + CertStore store = CertStore.getInstance("Collection", ccsp, "BC"); + Date validDate = new Date(rootCrl.getThisUpdate().getTime() + 60 * 60 * 1000); + + //Searching for rootCert by subjectDN without CRL + Set trust = new HashSet(); + trust.add(new TrustAnchor(rootCert, null)); + + CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX","BC"); + X509CertSelector targetConstraints = new X509CertSelector(); + targetConstraints.setSubject(finalCert.getSubjectX500Principal().getEncoded()); + PKIXBuilderParameters params = new PKIXBuilderParameters(trust, targetConstraints); + params.addCertStore(store); + params.setDate(validDate); + PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult) cpb.build(params); + CertPath path = result.getCertPath(); + + if (path.getCertificates().size() != 2) + { + fail("wrong number of certs in baseTest path"); + } + } + + private void v0Test() + throws Exception + { + // create certificates and CRLs + KeyPair rootPair = TestUtils.generateRSAKeyPair(); + KeyPair interPair = TestUtils.generateRSAKeyPair(); + KeyPair endPair = TestUtils.generateRSAKeyPair(); + + X509Certificate rootCert = TestUtils.generateRootCert(rootPair); + X509Certificate interCert = TestUtils.generateIntermediateCert(interPair.getPublic(), rootPair.getPrivate(), rootCert); + X509Certificate endCert = TestUtils.generateEndEntityCert(endPair.getPublic(), interPair.getPrivate(), interCert); + + BigInteger revokedSerialNumber = BigInteger.valueOf(2); + X509CRL rootCRL = TestUtils.createCRL(rootCert, rootPair.getPrivate(), revokedSerialNumber); + X509CRL interCRL = TestUtils.createCRL(interCert, interPair.getPrivate(), revokedSerialNumber); + + // create CertStore to support path building + List list = new ArrayList(); + + list.add(rootCert); + list.add(interCert); + list.add(endCert); + list.add(rootCRL); + list.add(interCRL); + + CollectionCertStoreParameters params = new CollectionCertStoreParameters(list); + CertStore store = CertStore.getInstance("Collection", params); + + // build the path + CertPathBuilder builder = CertPathBuilder.getInstance("PKIX", "BC"); + X509CertSelector pathConstraints = new X509CertSelector(); + + pathConstraints.setSubject(endCert.getSubjectX500Principal().getEncoded()); + + PKIXBuilderParameters buildParams = new PKIXBuilderParameters(Collections.singleton(new TrustAnchor(rootCert, null)), pathConstraints); + + buildParams.addCertStore(store); + buildParams.setDate(new Date()); + + PKIXCertPathBuilderResult result = (PKIXCertPathBuilderResult)builder.build(buildParams); + CertPath path = result.getCertPath(); + + if (path.getCertificates().size() != 2) + { + fail("wrong number of certs in v0Test path"); + } + } + + public void performTest() + throws Exception + { + baseTest(); + v0Test(); + } + + public String getName() + { + return "CertPathBuilder"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new CertPathBuilderTest()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertPathTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertPathTest.java new file mode 100644 index 000000000..957b4c71d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertPathTest.java @@ -0,0 +1,369 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.Security; +import java.security.SignatureException; +import java.security.cert.CertPath; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertPathBuilderException; +import java.security.cert.CertPathBuilderResult; +import java.security.cert.CertStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class CertPathTest + extends SimpleTest +{ + public static byte[] rootCertBin = Base64.decode( + "MIIBqzCCARQCAQEwDQYJKoZIhvcNAQEFBQAwHjEcMBoGA1UEAxMTVGVzdCBDQSBDZXJ0aWZpY2F0ZTAeFw0wODA5MDQwNDQ1MDhaFw0wODA5MTEwNDQ1MDhaMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMRLUjhPe4YUdLo6EcjKcWUOG7CydFTH53Pr1lWjOkbmszYDpkhCTT9LOsI+disk18nkBxSl8DAHTqV+VxtuTPt64iyi10YxyDeep+DwZG/f8cVQv97U3hA9cLurZ2CofkMLGr6JpSGCMZ9FcstcTdHB4lbErIJ54YqfF4pNOs4/AgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAgyrTEFY7ALpeY59jL6xFOLpuPqoBOWrUWv6O+zy5BCU0qiX71r3BpigtxRj+DYcfLIM9FNERDoHu3TthD3nwYWUBtFX8N0QUJIdJabxqAMhLjSC744koiFpCYse5Ye3ZvEdFwDzgAQsJTp5eFGgTZPkPzcdhkFJ2p9+OWs+cb24="); + + + static byte[] interCertBin = Base64.decode( + "MIICSzCCAbSgAwIBAgIBATANBgkqhkiG9w0BAQUFADAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlMB4XDTA4MDkwNDA0NDUwOFoXDTA4MDkxMTA0NDUwOFowKDEmMCQGA1UEAxMdVGVzdCBJbnRlcm1lZGlhdGUgQ2VydGlmaWNhdGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAISS9OOZ2wxzdWny9aVvk4Joq+dwSJ+oqvHUxX3PflZyuiLiCBUOUE4q59dGKdtNX5fIfwyK3cpV0e73Y/0fwfM3m9rOWFrCKOhfeswNTes0w/2PqPVVDDsF/nj7NApuqXwioeQlgTL251RDF4sVoxXqAU7lRkcqwZt3mwqS4KTJAgMBAAGjgY4wgYswRgYDVR0jBD8wPYAUhv8BOT27EB9JaCccJD4YASPP5XWhIqQgMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGWCAQEwHQYDVR0OBBYEFL/IwAGOkHzaQyPZegy79CwM5oTFMBIGA1UdEwEB/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBBQUAA4GBAE4TRgUz4sUvZyVdZxqV+XyNRnqXAeLOOqFGYv2D96tQrS+zjd0elVlT6lFrtchZdOmmX7R6/H/tjMWMcTBICZyRYrvK8cCAmDOI+EIdq5p6lj2Oq6Pbw/wruojAqNrpaR6IkwNpWtdOSSupv4IJL+YU9q2YFTh4R1j3tOkPoFGr"); + + static byte[] finalCertBin = Base64.decode( + "MIICRjCCAa+gAwIBAgIBATANBgkqhkiG9w0BAQUFADAoMSYwJAYDVQQDEx1UZXN0IEludGVybWVkaWF0ZSBDZXJ0aWZpY2F0ZTAeFw0wODA5MDQwNDQ1MDhaFw0wODA5MTEwNDQ1MDhaMB8xHTAbBgNVBAMTFFRlc3QgRW5kIENlcnRpZmljYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChpUeo0tPYywWKiLlbWKNJBcCpSaLSlaZ+4+yer1AxI5yJIVHP6SAlBghlbD5Qne5ImnN/15cz1xwYAiul6vGKJkVPlFEe2Mr+g/J/WJPQQPsjbZ1G+vxbAwXEDA4KaQrnpjRZFq+CdKHwOjuPLYS/MYQNgdIvDVEQcTbPQ8GaiQIDAQABo4GIMIGFMEYGA1UdIwQ/MD2AFL/IwAGOkHzaQyPZegy79CwM5oTFoSKkIDAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlggEBMB0GA1UdDgQWBBSVkw+VpqBf3zsLc/9GdkK9TzHPwDAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIFoDANBgkqhkiG9w0BAQUFAAOBgQBLv/0bVDjzTs/y1vN3FUiZNknEbzupIZduTuXJjqv/vBX+LDPjUfu/+iOCXOSKoRn6nlOWhwB1z6taG2usQkFG8InMkRcPREi2uVgFdhJ/1C3dAWhsdlubjdL926bftXvxnx/koDzyrePW5U96RlOQM2qLvbaky2Giz6hrc3Wl+w=="); + public static byte[] rootCrlBin = Base64.decode( + "MIIBYjCBzAIBATANBgkqhkiG9w0BAQsFADAeMRwwGgYDVQQDExNUZXN0IENBIENlcnRpZmljYXRlFw0wODA5MDQwNDQ1MDhaFw0wODA5MDQwNzMxNDhaMCIwIAIBAhcNMDgwOTA0MDQ0NTA4WjAMMAoGA1UdFQQDCgEJoFYwVDBGBgNVHSMEPzA9gBSG/wE5PbsQH0loJxwkPhgBI8/ldaEipCAwHjEcMBoGA1UEAxMTVGVzdCBDQSBDZXJ0aWZpY2F0ZYIBATAKBgNVHRQEAwIBATANBgkqhkiG9w0BAQsFAAOBgQCAbaFCo0BNG4AktVf6jjBLeawP1u0ELYkOCEGvYZE0mBpQ+OvFg7subZ6r3lRIj030nUli28sPFtu5ZQMBNcpE4nS1ziF44RfT3Lp5UgHx9x17Krz781iEyV+7zU8YxYMY9wULD+DCuK294kGKIssVNbmTYXZatBNoXQN5CLIocA=="); + static byte[] interCrlBin = Base64.decode( + "MIIBbDCB1gIBATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDEx1UZXN0IEludGVybWVkaWF0ZSBDZXJ0aWZpY2F0ZRcNMDgwOTA0MDQ0NTA4WhcNMDgwOTA0MDczMTQ4WjAiMCACAQIXDTA4MDkwNDA0NDUwOFowDDAKBgNVHRUEAwoBCaBWMFQwRgYDVR0jBD8wPYAUv8jAAY6QfNpDI9l6DLv0LAzmhMWhIqQgMB4xHDAaBgNVBAMTE1Rlc3QgQ0EgQ2VydGlmaWNhdGWCAQEwCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADgYEAEVCr5TKs5yguGgLH+dBzmSPoeSIWJFLsgWwJEit/iUDJH3dgYmaczOcGxIDtbYYHLWIHM+P2YRyQz3MEkCXEgm/cx4y7leAmux5l+xQWgmxFPz+197vaphPeCZo+B7V1CWtm518gcq4mrs9ovfgNqgyFj7KGjcBpWdJE32KMt50="); + + /* + * certpath with a circular reference + */ + static byte[] certA = Base64.decode( + "MIIC6jCCAlOgAwIBAgIBBTANBgkqhkiG9w0BAQUFADCBjTEPMA0GA1UEAxMGSW50" + + "ZXIzMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX" + + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq" + + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ2NTda" + + "Fw0xNzAzMzAwODQ0MDBaMIGlMScwJQYDVQQDHh4AQQByAG0AaQBuACAASADkAGIA" + + "ZQByAGwAaQBuAGcxCzAJBgNVBAYTAkNIMQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNV" + + "BAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNwaGVyZSBBRzEQMA4GA1UECxMHVGVzdGlu" + + "ZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5AcHJpdmFzcGhlcmUuY29tMIGfMA0GCSqG" + + "SIb3DQEBAQUAA4GNADCBiQKBgQCfHfyVs5dbxG35H/Thd29qR4NZU88taCu/OWA1" + + "GdACI02lXWYpmLWiDgnU0ULP+GG8OnVp1IES9fz2zcrXKQ19xZzsen/To3h5sNte" + + "cJpS00XMM24q/jDwy5NvkBP9YIfFKQ1E/0hFHXcqwlw+b/y/v6YGsZCU2h6QDzc4" + + "5m0+BwIDAQABo0AwPjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIE8DAeBglg" + + "hkgBhvhCAQ0EERYPeGNhIGNlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAA4GBAJEu" + + "KiSfIwsY7SfobMLrv2v/BtLhGLi4RnmjiwzBhuv5rn4rRfBpq1ppmqQMJ2pmA67v" + + "UWCY+mNwuyjHyivpCCyJGsZ9d5H09g2vqxzkDBMz7X9VNMZYFH8j/R3/Cfvqks31" + + "z0OFslJkeKLa1I0P/dfVHsRKNkLRT3Ws5LKksErQ"); + + static byte[] certB = Base64.decode( + "MIICtTCCAh6gAwIBAgIBBDANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50" + + "ZXIyMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX" + + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq" + + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ2Mzha" + + "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjMxCzAJBgNVBAYTAkNI" + + "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw" + + "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A" + + "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCxCXIB" + + "QRnmVvl2h7Q+0SsRxDLnyM1dJG9jMa+UCCmHy0k/ZHs5VirSbjEJSjkQ9BGeh9SC" + + "7JwbMpXO7UE+gcVc2RnWUY+MA+fWIeTV4KtkYA8WPu8wVGCXbN8wwh/StOocszxb" + + "g+iLvGeh8CYSRqg6QN3S/02etH3o8H4e7Z0PZwIDAQABoyMwITAPBgNVHRMBAf8E" + + "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCtWdirSsmt" + + "+CBBCNn6ZnbU3QqQfiiQIomjenNEHESJgaS/+PvPE5i3xWFXsunTHLW321/Km16I" + + "7+ZvT8Su1cqHg79NAT8QB0yke1saKSy2C0Pic4HwrNqVBWFNSxMU0hQzpx/ZXDbZ" + + "DqIXAp5EfyRYBy2ul+jm6Rot6aFgzuopKg=="); + + static byte[] certC = Base64.decode( + "MIICtTCCAh6gAwIBAgIBAjANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50" + + "ZXIxMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX" + + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq" + + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ0Mzla" + + "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjIxCzAJBgNVBAYTAkNI" + + "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw" + + "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A" + + "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD0rLr6" + + "f2/ONeJzTb0q9M/NNX+MnAFMSqiQGVBkT76u5nOH4KLkpHXkzI82JI7GuQMzoT3a" + + "+RP1hO6FneO92ms2soC6xiOFb4EC69Dfhh87Nww5O35JxVF0bzmbmIAWd6P/7zGh" + + "nd2S4tKkaZcubps+C0j9Fgi0hipVicAOUVVoDQIDAQABoyMwITAPBgNVHRMBAf8E" + + "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCLPvc1IMA4" + + "YP+PmnEldyUoRWRnvPWjBGeu0WheBP7fdcnGBf93Nmc5j68ZN+eTZ5VMuZ99YdvH" + + "CXGNX6oodONLU//LlFKdLl5xjLAS5X9p1RbOEGytnalqeiEpjk4+C/7rIBG1kllO" + + "dItmI6LlEMV09Hkpg6ZRAUmRkb8KrM4X7A=="); + + static byte[] certD = Base64.decode( + "MIICtTCCAh6gAwIBAgIBBjANBgkqhkiG9w0BAQQFADCBjTEPMA0GA1UEAxMGSW50" + + "ZXIzMQswCQYDVQQGEwJDSDEPMA0GA1UEBxMGWnVyaWNoMQswCQYDVQQIEwJaSDEX" + + "MBUGA1UEChMOUHJpdmFzcGhlcmUgQUcxEDAOBgNVBAsTB1Rlc3RpbmcxJDAiBgkq" + + "hkiG9w0BCQEWFWFybWluQHByaXZhc3BoZXJlLmNvbTAeFw0wNzA0MDIwODQ5NTNa" + + "Fw0xNzAzMzAwODQ0MDBaMIGNMQ8wDQYDVQQDEwZJbnRlcjExCzAJBgNVBAYTAkNI" + + "MQ8wDQYDVQQHEwZadXJpY2gxCzAJBgNVBAgTAlpIMRcwFQYDVQQKEw5Qcml2YXNw" + + "aGVyZSBBRzEQMA4GA1UECxMHVGVzdGluZzEkMCIGCSqGSIb3DQEJARYVYXJtaW5A" + + "cHJpdmFzcGhlcmUuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCae3TP" + + "jIVKeASqvNabaiUHAMGUgFxB7L0yUsIj39azLcLtUj4S7XkDf7SMGtYV0JY1XNaQ" + + "sHJAsnJivDZc50oiYvqDYfgFZx5+AsN5l5X5rjRzs/OX+Jo+k1OgsIyu6+mf9Kfb" + + "5IdWOVB2EcOg4f9tPjLM8CIj9Pp7RbKLyqUUgwIDAQABoyMwITAPBgNVHRMBAf8E" + + "BTADAQH/MA4GA1UdDwEB/wQEAwIB9jANBgkqhkiG9w0BAQQFAAOBgQCgr9kUdWUT" + + "Lt9UcztSzR3pnHRsyvS0E/z850OKQKS5/VxLEalpFvhj+3EcZ7Y6mFxaaS2B7vXg" + + "2YWyqV1PRb6iF7/u9EXkpSTKGrJahwANirCa3V/HTUuPdCE2GITlnWI8h3eVA+xQ" + + "D4LF0PXHOkXbwmhXRSb10lW1bSGkUxE9jg=="); + + private void testExceptions() + throws Exception + { + byte[] enc = { (byte)0, (byte)2, (byte)3, (byte)4, (byte)5 }; + MyCertPath mc = new MyCertPath(enc); + ByteArrayOutputStream os = new ByteArrayOutputStream(); + ByteArrayInputStream is; + byte[] arr; + + ObjectOutputStream oOut = new ObjectOutputStream(os); + oOut.writeObject(mc); + oOut.flush(); + oOut.close(); + + try + { + CertificateFactory cFac = CertificateFactory.getInstance("X.509", + "BC"); + arr = os.toByteArray(); + is = new ByteArrayInputStream(arr); + cFac.generateCertPath(is); + } + catch (CertificateException e) + { + // ignore okay + } + + CertificateFactory cf = CertificateFactory.getInstance("X.509"); + List certCol = new ArrayList(); + + certCol.add(cf.generateCertificate(new ByteArrayInputStream(certA))); + certCol.add(cf.generateCertificate(new ByteArrayInputStream(certB))); + certCol.add(cf.generateCertificate(new ByteArrayInputStream(certC))); + certCol.add(cf.generateCertificate(new ByteArrayInputStream(certD))); + + CertPathBuilder pathBuilder = CertPathBuilder.getInstance("PKIX", "BC"); + X509CertSelector select = new X509CertSelector(); + select.setSubject(((X509Certificate)certCol.get(0)).getSubjectX500Principal().getEncoded()); + + Set trustanchors = new HashSet(); + trustanchors.add(new TrustAnchor((X509Certificate)cf.generateCertificate(new ByteArrayInputStream(rootCertBin)), null)); + + CertStore certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certCol)); + + PKIXBuilderParameters params = new PKIXBuilderParameters(trustanchors, select); + params.addCertStore(certStore); + + try + { + CertPathBuilderResult result = pathBuilder.build(params); + CertPath path = result.getCertPath(); + fail("found cert path in circular set"); + } + catch (CertPathBuilderException e) + { + // expected + } + } + + public void performTest() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate rootCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(rootCertBin)); + X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(interCertBin)); + X509Certificate finalCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(finalCertBin)); + + //Testing CertPath generation from List + List list = new ArrayList(); + list.add(interCert); + CertPath certPath1 = cf.generateCertPath(list); + + //Testing CertPath encoding as PkiPath + byte[] encoded = certPath1.getEncoded("PkiPath"); + + //Testing CertPath generation from InputStream + ByteArrayInputStream inStream = new ByteArrayInputStream(encoded); + CertPath certPath2 = cf.generateCertPath(inStream, "PkiPath"); + + //Comparing both CertPathes + if (!certPath2.equals(certPath1)) + { + fail("CertPath differ after encoding and decoding."); + } + + encoded = certPath1.getEncoded("PKCS7"); + + //Testing CertPath generation from InputStream + inStream = new ByteArrayInputStream(encoded); + certPath2 = cf.generateCertPath(inStream, "PKCS7"); + + //Comparing both CertPathes + if (!certPath2.equals(certPath1)) + { + fail("CertPath differ after encoding and decoding."); + } + + encoded = certPath1.getEncoded("PEM"); + + //Testing CertPath generation from InputStream + inStream = new ByteArrayInputStream(encoded); + certPath2 = cf.generateCertPath(inStream, "PEM"); + + //Comparing both CertPathes + if (!certPath2.equals(certPath1)) + { + fail("CertPath differ after encoding and decoding."); + } + + // + // empty list test + // + list = new ArrayList(); + + CertPath certPath = CertificateFactory.getInstance("X.509","BC").generateCertPath(list); + if (certPath.getCertificates().size() != 0) + { + fail("list wrong size."); + } + + // + // exception tests + // + testExceptions(); + } + + public String getName() + { + return "CertPath"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new CertPathTest()); + } + + private static class MyCertificate extends Certificate + { + private final byte[] encoding; + + public MyCertificate(String type, byte[] encoding) + { + super(type); + // don't copy to allow null parameter in test + this.encoding = encoding; + } + + public byte[] getEncoded() throws CertificateEncodingException + { + // do copy to force NPE in test + return (byte[])encoding.clone(); + } + + public void verify(PublicKey key) throws CertificateException, + NoSuchAlgorithmException, InvalidKeyException, + NoSuchProviderException, SignatureException + { + } + + public void verify(PublicKey key, String sigProvider) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, + SignatureException + { + } + + public String toString() + { + return "[My test Certificate, type: " + getType() + "]"; + } + + public PublicKey getPublicKey() + { + return new PublicKey() + { + public String getAlgorithm() + { + return "TEST"; + } + + public byte[] getEncoded() + { + return new byte[] { (byte)1, (byte)2, (byte)3 }; + } + + public String getFormat() + { + return "TEST_FORMAT"; + } + }; + } + } + + private static class MyCertPath extends CertPath + { + private final Vector certificates; + + private final Vector encodingNames; + + private final byte[] encoding; + + public MyCertPath(byte[] encoding) + { + super("MyEncoding"); + this.encoding = encoding; + certificates = new Vector(); + certificates.add(new MyCertificate("MyEncoding", encoding)); + encodingNames = new Vector(); + encodingNames.add("MyEncoding"); + } + + public List getCertificates() + { + return Collections.unmodifiableList(certificates); + } + + public byte[] getEncoded() throws CertificateEncodingException + { + return (byte[])encoding.clone(); + } + + public byte[] getEncoded(String encoding) + throws CertificateEncodingException + { + if (getType().equals(encoding)) + { + return (byte[])this.encoding.clone(); + } + throw new CertificateEncodingException("Encoding not supported: " + + encoding); + } + + public Iterator getEncodings() + { + return Collections.unmodifiableCollection(encodingNames).iterator(); + } + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java new file mode 100644 index 000000000..4bc73f39f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertPathValidatorTest.java @@ -0,0 +1,1528 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.Provider; +import java.security.PublicKey; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertStore; +import java.security.cert.CertStoreParameters; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.CertificateParsingException; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.PKIXParameters; +import java.security.cert.PolicyNode; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import javax.security.auth.x500.X500Principal; + +import com.fr.third.org.bouncycastle.asn1.ASN1BitString; +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1String; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DERIA5String; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.misc.MiscObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.misc.NetscapeCertType; +import com.fr.third.org.bouncycastle.asn1.misc.NetscapeRevocationURL; +import com.fr.third.org.bouncycastle.asn1.misc.VerisignCzagExtension; +import com.fr.third.org.bouncycastle.asn1.util.ASN1Dump; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.style.RFC4519Style; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.BasicConstraints; +import com.fr.third.org.bouncycastle.asn1.x509.Extension; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.KeyUsage; +import com.fr.third.org.bouncycastle.asn1.x509.X509CertificateStructure; +import com.fr.third.org.bouncycastle.asn1.x509.X509Extension; +import com.fr.third.org.bouncycastle.asn1.x509.X509Extensions; +import com.fr.third.org.bouncycastle.jce.X509Principal; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Integers; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class CertPathValidatorTest + extends SimpleTest +{ + private byte[] AC_PR = Base64.decode( + "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlFU1RDQ0F6R2dBd0lC" + + "QWdJQkJUQU5CZ2txaGtpRzl3MEJBUVVGQURDQnRERUxNQWtHQTFVRUJoTUNR" + + "bEl4DQpFekFSQmdOVkJBb1RDa2xEVUMxQ2NtRnphV3d4UFRBN0JnTlZCQXNU" + + "TkVsdWMzUnBkSFYwYnlCT1lXTnBiMjVoDQpiQ0JrWlNCVVpXTnViMnh2WjJs" + + "aElHUmhJRWx1Wm05eWJXRmpZVzhnTFNCSlZFa3hFVEFQQmdOVkJBY1RDRUp5" + + "DQpZWE5wYkdsaE1Rc3dDUVlEVlFRSUV3SkVSakV4TUM4R0ExVUVBeE1vUVhW" + + "MGIzSnBaR0ZrWlNCRFpYSjBhV1pwDQpZMkZrYjNKaElGSmhhWG9nUW5KaGMy" + + "bHNaV2x5WVRBZUZ3MHdNakEwTURReE9UTTVNREJhRncwd05UQTBNRFF5DQpN" + + "elU1TURCYU1HRXhDekFKQmdOVkJBWVRBa0pTTVJNd0VRWURWUVFLRXdwSlEx" + + "QXRRbkpoYzJsc01UMHdPd1lEDQpWUVFERXpSQmRYUnZjbWxrWVdSbElFTmxj" + + "blJwWm1sallXUnZjbUVnWkdFZ1VISmxjMmxrWlc1amFXRWdaR0VnDQpVbVZ3" + + "ZFdKc2FXTmhNSUlCSWpBTkJna3Foa2lHOXcwQkFRRUZBQU9DQVE4QU1JSUJD" + + "Z0tDQVFFQXMwc0t5NGsrDQp6b016aldyMTQxeTVYQ045UGJMZERFQXN2cjZ4" + + "Z0NCN1l5bEhIQ1NBYmpGR3dOQ0R5NlVxN1h0VjZ6UHdIMXpGDQpFWENlS3Jm" + + "UUl5YXBXSEZ4V1VKajBMblFrY1RZM1FOR1huK0JuVk9EVTZDV3M1c3NoZktH" + + "RXZyVlQ1Z214V1NmDQp4OFlsdDgzY1dwUE1QZzg3VDlCaHVIbHQzazh2M2Ev" + + "NmRPbmF2dytOYTAyZExBaDBlNzZqcCtQUS9LK0pHZlBuDQphQjVVWURrZkd0" + + "em5uTTNBV01tY3VJK0o0ek5OMDZaa3ZnbDFsdEo2UU1qcnZEUFlSak9ndDlT" + + "cklpY1NmbEo4DQptVDdHWGRRaXJnQUNXc3g1QURBSklRK253TU1vNHlyTUtx" + + "SlFhNFFDMHhhT0QvdkdVcG9SaDQzT0FTZFp3c3YvDQpPWFlybmVJeVAwVCs4" + + "UUlEQVFBQm80RzNNSUcwTUQwR0ExVWRId1EyTURRd01xQXdvQzZHTEdoMGRI" + + "QTZMeTloDQpZM0poYVhvdWFXTndZbkpoYzJsc0xtZHZkaTVpY2k5TVExSmhZ" + + "M0poYVhvdVkzSnNNQklHQTFVZElBUUxNQWt3DQpCd1lGWUV3QkFRRXdIUVlE" + + "VlIwT0JCWUVGREpUVFlKNE9TWVB5T09KZkVMZXhDaHppK2hiTUI4R0ExVWRJ" + + "d1FZDQpNQmFBRklyNjhWZUVFUk0xa0VMNlYwbFVhUTJreFBBM01BNEdBMVVk" + + "RHdFQi93UUVBd0lCQmpBUEJnTlZIUk1CDQpBZjhFQlRBREFRSC9NQTBHQ1Nx" + + "R1NJYjNEUUVCQlFVQUE0SUJBUUJRUFNoZ1lidnFjaWV2SDVVb3ZMeXhkbkYr" + + "DQpFcjlOeXF1SWNkMnZ3Y0N1SnpKMkQ3WDBUcWhHQ0JmUEpVVkdBVWorS0NP" + + "SDFCVkgva1l1OUhsVHB1MGtKWFBwDQpBQlZkb2hJUERqRHhkbjhXcFFSL0Yr" + + "ejFDaWtVcldIMDR4eTd1N1p6UUpLSlBuR0loY1FpOElyRm1PYkllMEc3DQpY" + + "WTZPTjdPRUZxY21KTFFHWWdtRzFXMklXcytQd1JwWTdENGhLVEFoVjFSNkVv" + + "amE1L3BPcmVDL09kZXlQWmVxDQo1SUZTOUZZZk02U0Npd2hrK3l2Q1FHbVo0" + + "YzE5SjM0ZjVFYkRrK1NQR2tEK25EQ0E3L3VMUWNUMlJURE14SzBaDQpuZlo2" + + "Nm1Sc0ZjcXRGaWdScjVFcmtKZDdoUVV6eHNOV0VrNzJEVUFIcVgvNlNjeWtt" + + "SkR2V0plSUpqZlcNCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0NCg=="); + + private byte[] AC_RAIZ_ICPBRASIL = Base64.decode( + "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tDQpNSUlFdURDQ0E2Q2dBd0lC" + + "QWdJQkJEQU5CZ2txaGtpRzl3MEJBUVVGQURDQnRERUxNQWtHQTFVRUJoTUNR" + + "bEl4DQpFekFSQmdOVkJBb1RDa2xEVUMxQ2NtRnphV3d4UFRBN0JnTlZCQXNU" + + "TkVsdWMzUnBkSFYwYnlCT1lXTnBiMjVoDQpiQ0JrWlNCVVpXTnViMnh2WjJs" + + "aElHUmhJRWx1Wm05eWJXRmpZVzhnTFNCSlZFa3hFVEFQQmdOVkJBY1RDRUp5" + + "DQpZWE5wYkdsaE1Rc3dDUVlEVlFRSUV3SkVSakV4TUM4R0ExVUVBeE1vUVhW" + + "MGIzSnBaR0ZrWlNCRFpYSjBhV1pwDQpZMkZrYjNKaElGSmhhWG9nUW5KaGMy" + + "bHNaV2x5WVRBZUZ3MHdNVEV4TXpBeE1qVTRNREJhRncweE1URXhNekF5DQpN" + + "elU1TURCYU1JRzBNUXN3Q1FZRFZRUUdFd0pDVWpFVE1CRUdBMVVFQ2hNS1NV" + + "TlFMVUp5WVhOcGJERTlNRHNHDQpBMVVFQ3hNMFNXNXpkR2wwZFhSdklFNWhZ" + + "Mmx2Ym1Gc0lHUmxJRlJsWTI1dmJHOW5hV0VnWkdFZ1NXNW1iM0p0DQpZV05o" + + "YnlBdElFbFVTVEVSTUE4R0ExVUVCeE1JUW5KaGMybHNhV0V4Q3pBSkJnTlZC" + + "QWdUQWtSR01URXdMd1lEDQpWUVFERXloQmRYUnZjbWxrWVdSbElFTmxjblJw" + + "Wm1sallXUnZjbUVnVW1GcGVpQkNjbUZ6YVd4bGFYSmhNSUlCDQpJakFOQmdr" + + "cWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0NBUUVBd1BNdWR3WC9odm0r" + + "VWgyYi9sUUFjSFZBDQppc2FtYUxrV2Rrd1A5L1MvdE9LSWdSckw2T3krWklH" + + "bE9VZGQ2dVl0azlNYS8zcFVwZ2NmTkFqMHZZbTVnc3lqDQpRbzllbXNjK3g2" + + "bTRWV3drOWlxTVpTQ0s1RVFrQXEvVXQ0bjdLdUxFMStnZGZ0d2RJZ3hmVXNQ" + + "dDRDeU5yWTUwDQpRVjU3S00yVVQ4eDVycm16RWpyN1RJQ0dwU1VBbDJnVnFl" + + "NnhhaWkrYm1ZUjFRcm1XYUJTQUc1OUxya3Jqcll0DQpiUmhGYm9VRGUxREsr" + + "NlQ4czVMNms4Yzhva3BiSHBhOXZlTXp0RFZDOXNQSjYwTVdYaDZhblZLbzFV" + + "Y0xjYlVSDQp5RWVOdlpuZVZSS0FBVTZvdXdkakR2d2xzYUt5ZEZLd2VkMFRv" + + "UTQ3Ym1VS2djbSt3VjNlVFJrMzZVT25Ud0lEDQpBUUFCbzRIU01JSFBNRTRH" + + "QTFVZElBUkhNRVV3UXdZRllFd0JBUUF3T2pBNEJnZ3JCZ0VGQlFjQ0FSWXNh" + + "SFIwDQpjRG92TDJGamNtRnBlaTVwWTNCaWNtRnphV3d1WjI5MkxtSnlMMFJR" + + "UTJGamNtRnBlaTV3WkdZd1BRWURWUjBmDQpCRFl3TkRBeW9EQ2dMb1lzYUhS" + + "MGNEb3ZMMkZqY21GcGVpNXBZM0JpY21GemFXd3VaMjkyTG1KeUwweERVbUZq" + + "DQpjbUZwZWk1amNtd3dIUVlEVlIwT0JCWUVGSXI2OFZlRUVSTTFrRUw2VjBs" + + "VWFRMmt4UEEzTUE4R0ExVWRFd0VCDQovd1FGTUFNQkFmOHdEZ1lEVlIwUEFR" + + "SC9CQVFEQWdFR01BMEdDU3FHU0liM0RRRUJCUVVBQTRJQkFRQVpBNWMxDQpV" + + "L2hnSWg2T2NnTEFmaUpnRldwdm1EWldxbFYzMC9iSEZwajhpQm9iSlNtNXVE" + + "cHQ3VGlyWWgxVXhlM2ZRYUdsDQpZakplKzl6ZCtpelBSYkJxWFBWUUEzNEVY" + + "Y3drNHFwV3VmMWhIcmlXZmRyeDhBY3FTcXI2Q3VRRndTcjc1Rm9zDQpTemx3" + + "REFEYTcwbVQ3d1pqQW1RaG5aeDJ4SjZ3ZldsVDlWUWZTLy9KWWVJYzdGdWUy" + + "Sk5MZDAwVU9TTU1haUsvDQp0NzllbktOSEVBMmZ1cEgzdkVpZ2Y1RWg0YlZB" + + "TjVWb2hyVG02TVk1M3g3WFFaWnIxTUU3YTU1bEZFblNlVDB1DQptbE9BalIy" + + "bUFidlNNNVg1b1NaTnJtZXRkenlUajJmbENNOENDN01MYWIwa2tkbmdSSWxV" + + "QkdIRjEvUzVubVBiDQpLKzlBNDZzZDMzb3FLOG44DQotLS0tLUVORCBDRVJU" + + "SUZJQ0FURS0tLS0tDQo="); + + private byte[] schefer = Base64.decode( + "MIIEnDCCBAWgAwIBAgICIPAwDQYJKoZIhvcNAQEEBQAwgcAxCzAJBgNVBAYT" + + "AkRFMQ8wDQYDVQQIEwZIRVNTRU4xGDAWBgNVBAcTDzY1MDA4IFdpZXNiYWRl" + + "bjEaMBgGA1UEChMRU0NIVUZBIEhPTERJTkcgQUcxGjAYBgNVBAsTEVNDSFVG" + + "QSBIT0xESU5HIEFHMSIwIAYDVQQDExlJbnRlcm5ldCBCZW51dHplciBTZXJ2" + + "aWNlMSowKAYJKoZIhvcNAQkBFht6ZXJ0aWZpa2F0QHNjaHVmYS1vbmxpbmUu" + + "ZGUwHhcNMDQwMzMwMTEwODAzWhcNMDUwMzMwMTEwODAzWjCBnTELMAkGA1UE" + + "BhMCREUxCjAIBgNVBAcTASAxIzAhBgNVBAoTGlNIUyBJbmZvcm1hdGlvbnNz" + + "eXN0ZW1lIEFHMRwwGgYDVQQLExM2MDAvMDU5NDktNjAwLzA1OTQ5MRgwFgYD" + + "VQQDEw9TY2hldHRlciBTdGVmYW4xJTAjBgkqhkiG9w0BCQEWFlN0ZWZhbi5T" + + "Y2hldHRlckBzaHMuZGUwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJD0" + + "95Bi76fkAMjJNTGPDiLPHmZXNsmakngDeS0juzKMeJA+TjXFouhYh6QyE4Bl" + + "Nf18fT4mInlgLefwf4t6meIWbiseeTo7VQdM+YrbXERMx2uHsRcgZMsiMYHM" + + "kVfYMK3SMJ4nhCmZxrBkoTRed4gXzVA1AA8YjjTqMyyjvt4TAgMBAAGjggHE" + + "MIIBwDAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIEsDALBgNVHQ8EBAMC" + + "BNAwOQYJYIZIAYb4QgENBCwWKlplcnRpZmlrYXQgbnVyIGZ1ZXIgU0NIVUZB" + + "LU9ubGluZSBndWVsdGlnLjAdBgNVHQ4EFgQUXReirhBfg0Yhf6MsBWoo/nPa" + + "hGwwge0GA1UdIwSB5TCB4oAUf2UyCaBV9JUeG9lS1Yo6OFBUdEKhgcakgcMw" + + "gcAxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIEwZIRVNTRU4xGDAWBgNVBAcTDzY1" + + "MDA4IFdpZXNiYWRlbjEaMBgGA1UEChMRU0NIVUZBIEhPTERJTkcgQUcxGjAY" + + "BgNVBAsTEVNDSFVGQSBIT0xESU5HIEFHMSIwIAYDVQQDExlJbnRlcm5ldCBC" + + "ZW51dHplciBTZXJ2aWNlMSowKAYJKoZIhvcNAQkBFht6ZXJ0aWZpa2F0QHNj" + + "aHVmYS1vbmxpbmUuZGWCAQAwIQYDVR0RBBowGIEWU3RlZmFuLlNjaGV0dGVy" + + "QHNocy5kZTAmBgNVHRIEHzAdgRt6ZXJ0aWZpa2F0QHNjaHVmYS1vbmxpbmUu" + + "ZGUwDQYJKoZIhvcNAQEEBQADgYEAWzZtN9XQ9uyrFXqSy3hViYwV751+XZr0" + + "YH5IFhIS+9ixNAu8orP3bxqTaMhpwoU7T/oSsyGGSkb3fhzclgUADbA2lrOI" + + "GkeB/m+FArTwRbwpqhCNTwZywOp0eDosgPjCX1t53BB/m/2EYkRiYdDGsot0" + + "kQPOVGSjQSQ4+/D+TM8="); + + // circular dependency certificates + private static final byte[] circCA = Base64.decode( + "MIIDTzCCAjegAwIBAgIDARAAMA0GCSqGSIb3DQEBBQUAMDkxCzAJBgNVBAYT" + + "AkZSMRAwDgYDVQQKEwdHSVAtQ1BTMRgwFgYDVQQLEw9HSVAtQ1BTIEFOT05Z" + + "TUUwHhcNMDQxMDExMDAwMDAxWhcNMTQxMjMxMjM1OTU5WjA5MQswCQYDVQQG" + + "EwJGUjEQMA4GA1UEChMHR0lQLUNQUzEYMBYGA1UECxMPR0lQLUNQUyBBTk9O" + + "WU1FMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3WyWDwcM58aU" + + "hPX4ueI1mwETt3WdQtMfIdRiCXeBrjCkYCc7nIgCmGbnfTzXSplHRgKColWh" + + "q/Z+1rHYayje1gjAEU2+4/r1P2pnBmPgquDuguktCIbDtCcGZu0ylyKeHh37" + + "aeIKzkcmRSLRzvGf/eO3RdFksrvaPaSjqCVfGRXVDKK2uftE8rIFJE+bCqow" + + "6+WiaAaDDiJaSJPuu5hC1NA5jw0/BFodlCuAvl1GJ8A+TICkYWcSpKS9bkSC" + + "0i8xdGbSSk94shA1PdDvRdFMfFys8g4aupBXV8yqqEAUkBYmOtZSJckc3W4y" + + "2Gx53y7vY07Xh63mcgtJs2T82WJICwIDAQABo2AwXjAdBgNVHQ4EFgQU8c/P" + + "NNJaL0srd9SwHwgtvwPB/3cwDgYDVR0PAQH/BAQDAgIEMBkGA1UdIAQSMBAw" + + "DgYMKoF6AUcDBwgAAAABMBIGA1UdEwEB/wQIMAYBAf8CAQEwDQYJKoZIhvcN" + + "AQEFBQADggEBAHRjYDPJKlfUzID0YzajZpgR/i2ngJrJqYeaWCmwzBgNUPad" + + "uBKSGHmPVg21sfULMSnirnR+e90i/D0EVzLwQzcbjPDD/85rp9QDCeMxqqPe" + + "9ZCHGs2BpE/HOQMP0QfQ3/Kpk7SvOH/ZcpIf6+uE6lLBQYAGs5cxvtTGOzZk" + + "jCVFG+TrAnF4V5sNkn3maCWiYLmyqcnxtKEFSONy2bYqqudx/dBBlRrDbRfZ" + + "9XsCBdiXAHY1hFHldbfDs8rslmkXJi3fJC028HZYB6oiBX/JE7BbMk7bRnUf" + + "HSpP7Sjxeso2SY7Yit+hQDVAlqTDGmh6kLt/hQMpsOMry4vgBL6XHKw="); + + private static final byte[] circCRLCA = Base64.decode( + "MIIDXDCCAkSgAwIBAgIDASAAMA0GCSqGSIb3DQEBBQUAMDkxCzAJBgNVBAYT" + + "AkZSMRAwDgYDVQQKEwdHSVAtQ1BTMRgwFgYDVQQLEw9HSVAtQ1BTIEFOT05Z" + + "TUUwHhcNMDQxMDExMDAwMDAxWhcNMTQxMjMxMjM1OTU5WjA5MQswCQYDVQQG" + + "EwJGUjEQMA4GA1UEChMHR0lQLUNQUzEYMBYGA1UECxMPR0lQLUNQUyBBTk9O" + + "WU1FMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwfEcFK0g7Kfo" + + "o5f2IBF7VEd/AG+RVGSds0Yg+u2kNYu4k04HR/+tOdBQtJvyr4W5jrQKsC5X" + + "skeFWMyWaFKzAjZDWB52HWp/kiMivGcxnYDuYf5piukSC+d2+vL8YaAphDzV" + + "HPnxEKqoM/J66uUussDTqfcL3JC/Bc7kBwn4srrsZOsamMWTQQtEqVQxNN7A" + + "ROSRsdiTt3hMOKditc9/NBNmjZWxgc7Twr/SaZ8CfN5wf2wuOl23knWL0QsJ" + + "0lSMBSBTzTcfAke4/jIT7d4nVMp3t7dsna8rt56pFK4wpRFGuCt+1P5gi51x" + + "xVSdI+JoNXv6zGO4o8YVaRpC5rQeGQIDAQABo20wazAfBgNVHSMEGDAWgBTx" + + "z8800lovSyt31LAfCC2/A8H/dzAdBgNVHQ4EFgQUGa3SbBrJx/wa2MQwhWPl" + + "dwLw1+IwDgYDVR0PAQH/BAQDAgECMBkGA1UdIAQSMBAwDgYMKoF6AUcDBwgA" + + "AAABMA0GCSqGSIb3DQEBBQUAA4IBAQAPDpYe2WPYnXTLsXSIUREBNMLmg+/7" + + "4Yhq9uOm5Hb5LVkDuHoEHGfmpXXEvucx5Ehu69hw+F4YSrd9wPjOiG8G6GXi" + + "RcrK8nE8XDvvV+E1HpJ7NKN4fSAoSb+0gliiq3aF15bvXP8nfespdd/x1xWQ" + + "mpYCx/mJeuqONQv2/D/7hfRKYoDBaAkWGodenPFPVs6FxwnEuH2R+KWCUdA9" + + "L04v8JBeL3kZiALkU7+DCCm7A0imUAgeeArbAbfIPu6eDygm+XndZ9qi7o4O" + + "AntPxrqbeXFIbDrQ4GV1kpxnW+XpSGDd96SWKe715gxkkDBppR5IKYJwRb6O" + + "1TRQIf2F+muQ"); + + private static final byte[] circCRL = Base64.decode( + "MIIB1DCBvQIBATANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGUjEQMA4G" + + "A1UEChMHR0lQLUNQUzEYMBYGA1UECxMPR0lQLUNQUyBBTk9OWU1FFw0xMDAx" + + "MDcwMzAwMTVaFw0xMDAxMTMwMzAwMTVaMACgTjBMMB8GA1UdIwQYMBaAFBmt" + + "0mwaycf8GtjEMIVj5XcC8NfiMAsGA1UdFAQEAgILgzAcBgNVHRIEFTATgRFh" + + "Yy1naXBAZ2lwLWNwcy5mcjANBgkqhkiG9w0BAQUFAAOCAQEAtF1DdFl1MQvf" + + "vNkbrCPuppNYcHen4+za/ZDepKuwHsH/OpKuaDJc4LndRgd5IwzfpCHkQGzt" + + "shK50bakN8oaYJgthKIOIJzR+fn6NMjftfR2a27Hdk2o3eQXRHQ360qMbpSy" + + "qPb3WfuBhxO2/DlLChJP+OxZIHtT/rNYgE0tlIv7swYi81Gq+DafzaZ9+A5t" + + "I0L2Gp/NUDsp5dF6PllAGiXQzl27qkcu+r50w+u0gul3nobXgbwPcMSYuWUz" + + "1lhA+uDn/EUWV4RSiJciCGSS10WCkFh1/YPo++mV15KDB0m+8chscrSu/bAl" + + "B19LxL/pCX3qr5iLE9ss3olVImyFZg=="); + + private void checkCircProcessing() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate caCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(circCA)); + X509Certificate crlCaCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(circCRLCA)); + X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(circCRL)); + + List list = new ArrayList(); + + list.add(caCert); + list.add(crlCaCert); + list.add(crl); + + CertStoreParameters ccsp = new CollectionCertStoreParameters(list); + CertStore store = CertStore.getInstance("Collection", ccsp); + + Date validDate = new Date(crl.getThisUpdate().getTime() + 60 * 60 * 1000); + + //validating path + List certchain = new ArrayList(); + + certchain.add(crlCaCert); + CertPath cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain); + + Set trust = new HashSet(); + trust.add(new TrustAnchor(caCert, null)); + + CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC"); + //PKIXParameters param = new PKIXParameters(trust); + + PKIXBuilderParameters param = new PKIXBuilderParameters(trust, null); + X509CertSelector certSelector = new X509CertSelector(); + certSelector.setCertificate(crlCaCert); + param.setTargetCertConstraints(certSelector); + param.addCertStore(store); + param.setRevocationEnabled(true); + param.setDate(validDate); + + PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)cpv.validate(cp, param); + } + + private void checkPolicyProcessingAtDomainMatch() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate root = (X509Certificate)cf.generateCertificate(this.getClass().getResourceAsStream("qvRooCa3.crt")); + X509Certificate ca1 = (X509Certificate)cf.generateCertificate(this.getClass().getResourceAsStream("suvaRoot1.crt")); + X509Certificate ca2 = (X509Certificate)cf.generateCertificate(this.getClass().getResourceAsStream("suvaEmail1.crt")); + X509Certificate ee = (X509Certificate)cf.generateCertificate(this.getClass().getResourceAsStream("suvaEE.crt")); + + List certchain = new ArrayList(); + certchain.add(ee); + certchain.add(ca2); + certchain.add(ca1); + + Set trust = new HashSet(); + trust.add(new TrustAnchor(root, null)); + + CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC"); + PKIXParameters param = new PKIXParameters(trust); + param.setRevocationEnabled(false); + param.setDate(new Date(0x156445410b4L)); // around 1st August 2016 + + CertPath cp = cf.generateCertPath(certchain); + + MyChecker checker = new MyChecker(); + param.addCertPathChecker(checker); + + PKIXCertPathValidatorResult result = + (PKIXCertPathValidatorResult)cpv.validate(cp, param); + } + + public void testEmptyPath() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + X509Certificate rootCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.rootCertBin)); + + List list = new ArrayList(); + list.add(rootCert); + CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list); + CertStore store = CertStore.getInstance("Collection", ccsp, "BC"); + + List certchain = new ArrayList(); + CertPath cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain); + Set trust = new HashSet(); + trust.add(new TrustAnchor(rootCert, null)); + + CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC"); + PKIXParameters param = new PKIXParameters(trust); + param.addCertStore(store); + MyChecker checker = new MyChecker(); + param.addCertPathChecker(checker); + + try + { + cpv.validate(cp, param); + } + catch (CertPathValidatorException e) + { + if (!"Certification path is empty.".equals(e.getMessage())) + { + fail("message mismatch"); + } + } + } + + + private void constraintTest() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate rootCert = (X509Certificate)cf.generateCertificate(this.getClass().getResourceAsStream("CERT_CI_ECDSA_NIST.pem")); + X509Certificate interCert = (X509Certificate)cf.generateCertificate(this.getClass().getResourceAsStream("CERT_EUM_ECDSA_NIST.pem")); + X509Certificate finalCert = (X509Certificate)cf.generateCertificate(this.getClass().getResourceAsStream("CERT_EUICC_ECDSA_NIST.pem")); + + List list = new ArrayList(); + list.add(interCert); + list.add(finalCert); + + CertPath certPath = cf.generateCertPath(list); + + Set trust = new HashSet(); + trust.add(new TrustAnchor(rootCert, null)); + + CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC"); + PKIXParameters param = new PKIXParameters(trust); + param.setRevocationEnabled(false); + + cpv.validate(certPath, param); + + } + + public void performTest() + throws Exception + { + constraintTest(); + + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + // initialise CertStore + X509Certificate rootCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.rootCertBin)); + X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.interCertBin)); + X509Certificate finalCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(CertPathTest.finalCertBin)); + X509CRL rootCrl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(CertPathTest.rootCrlBin)); + X509CRL interCrl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(CertPathTest.interCrlBin)); + List list = new ArrayList(); + list.add(rootCert); + list.add(interCert); + list.add(finalCert); + list.add(rootCrl); + list.add(interCrl); + CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list); + CertStore store = CertStore.getInstance("Collection", ccsp, "BC"); + Date validDate = new Date(rootCrl.getThisUpdate().getTime() + 60 * 60 * 1000); + //validating path + List certchain = new ArrayList(); + certchain.add(finalCert); + certchain.add(interCert); + + CertPath cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain); + Set trust = new HashSet(); + trust.add(new TrustAnchor(rootCert, null)); + + CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC"); + PKIXParameters param = new PKIXParameters(trust); + param.addCertStore(store); + param.setDate(validDate); + MyChecker checker = new MyChecker(); + param.addCertPathChecker(checker); + + PKIXCertPathValidatorResult result = + (PKIXCertPathValidatorResult)cpv.validate(cp, param); + PolicyNode policyTree = result.getPolicyTree(); + PublicKey subjectPublicKey = result.getPublicKey(); + + if (checker.getCount() != 2) + { + fail("checker not evaluated for each certificate"); + } + + if (!subjectPublicKey.equals(finalCert.getPublicKey())) + { + fail("wrong public key returned"); + } + + isTrue(result.getTrustAnchor().getTrustedCert().equals(rootCert)); + + // try a path with trust anchor included. + certchain.clear(); + certchain.add(finalCert); + certchain.add(interCert); + certchain.add(rootCert); + + cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain); + + cpv = CertPathValidator.getInstance("PKIX", "BC"); + param = new PKIXParameters(trust); + param.addCertStore(store); + param.setDate(validDate); + + result = (PKIXCertPathValidatorResult)cpv.validate(cp, param); + + isTrue(result.getTrustAnchor().getTrustedCert().equals(rootCert)); + + // + // invalid path containing a valid one test + // + try + { + // initialise CertStore + rootCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(AC_RAIZ_ICPBRASIL)); + interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(AC_PR)); + finalCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(schefer)); + + list = new ArrayList(); + list.add(rootCert); + list.add(interCert); + list.add(finalCert); + + ccsp = new CollectionCertStoreParameters(list); + store = CertStore.getInstance("Collection", ccsp); + validDate = new Date(finalCert.getNotBefore().getTime() + 60 * 60 * 1000); + + //validating path + certchain = new ArrayList(); + certchain.add(finalCert); + certchain.add(interCert); + + cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain); + trust = new HashSet(); + trust.add(new TrustAnchor(rootCert, null)); + + cpv = CertPathValidator.getInstance("PKIX", "BC"); + param = new PKIXParameters(trust); + param.addCertStore(store); + param.setRevocationEnabled(false); + param.setDate(validDate); + + result = (PKIXCertPathValidatorResult)cpv.validate(cp, param); + policyTree = result.getPolicyTree(); + subjectPublicKey = result.getPublicKey(); + + fail("Invalid path validated"); + } + catch (Exception e) + { + if (!(e instanceof CertPathValidatorException + && e.getMessage().startsWith("Could not validate certificate signature."))) + { + fail("unexpected exception", e); + } + } + + checkCircProcessing(); + checkPolicyProcessingAtDomainMatch(); + validateWithExtendedKeyUsage(); + testEmptyPath(); + checkInvalidCertPath(); + } + + // extended key usage chain + static byte[] extEE = Base64.decode("MIICtDCCAh2gAwIBAgIBAzANBgkqhkiG9w0BAQUFADCBkjELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxKDAmBgNVBAsMH0JvdW5jeSBJbnRlcm1lZGlhdGUgQ2VydGlmaWNhdGUxLzAtBgkqhkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMB4XDTE1MDMyNDAzNTEwOVoXDTE1MDUyMzAzNTEwOVowgZYxCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHDAlNZWxib3VybmUxGDAWBgNVBAMMD0VyaWMgSC4gRWNoaWRuYTEvMC0GCSqGSIb3DQEJARYgZmVlZGJhY2stY3J5cHRvQGJvdW5jeWNhc3RsZS5vcmcwWjANBgkqhkiG9w0BAQEFAANJADBGAkEAtKfkYXBXTxapcIKyK+WLaipil5hBm+EocqS9umJs+umQD3ar+xITnc5d5WVk+rK2VDFloEDGBoh0IOM9ke1+1wIBEaNaMFgwHQYDVR0OBBYEFNBs7G01g7xVEhsMyz7+1yamFmRoMB8GA1UdIwQYMBaAFJQIM28yQPeHN9rRIKrtLqduyckeMBYGA1UdJQEB/wQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBBQUAA4GBAICrsNswvaXFMreUHHRHrhU4QqPOds8XJe0INx3v/5TfyjPPDMihMEm8WtWbVpFgFAqUQoZscf8cE/SO5375unYFgxrK+p2/je9E82VLF4Xb0cWizjQoWvvTmvFYjt43cGGXgySFLTrW87ju9uNFr/l4W9xvI0hoLI96vEW7Ccho"); + static byte[] extCA = Base64.decode("MIIDIzCCAoygAwIBAgIBAjANBgkqhkiG9w0BAQUFADBcMQswCQYDVQQGEwJBVTEoMCYGA1UECgwfVGhlIExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECwwaQm91bmN5IFByaW1hcnkgQ2VydGlmaWNhdGUwHhcNMTUwMzI0MDM1MTA5WhcNMTUwNTIzMDM1MTA5WjCBkjELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxKDAmBgNVBAsMH0JvdW5jeSBJbnRlcm1lZGlhdGUgQ2VydGlmaWNhdGUxLzAtBgkqhkiG9w0BCQEWIGZlZWRiYWNrLWNyeXB0b0Bib3VuY3ljYXN0bGUub3JnMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCN4NETxec2lpyNKwR6JD+P4Y7a1kzenoQtNmkjDKSG98/d4fjuxU0ZBf/wSsyF5hCT4YDK3GzqQH8ZPUS7DpRJuNu0l4TNnjYmDDngapRymZeMbtgwByTohxmM/t4g8/veZY+ivQeL6Uajkr00nytJxIbiDEBViOMGcGyQFzCOaQIDAP//o4G9MIG6MB0GA1UdDgQWBBSUCDNvMkD3hzfa0SCq7S6nbsnJHjCBhAYDVR0jBH0we4AUwDYZB63EiJeoXnJvawnr5ebxKVyhYKReMFwxCzAJBgNVBAYTAkFVMSgwJgYDVQQKDB9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMSMwIQYDVQQLDBpCb3VuY3kgUHJpbWFyeSBDZXJ0aWZpY2F0ZYIBATASBgNVHRMBAf8ECDAGAQH/AgEAMA0GCSqGSIb3DQEBBQUAA4GBAJqUlDjse7Og+7qkkFsiXHzQ8FxT82hzfcji8W7bPwZddCPBEluxCJiJBPYXWsLvwo6BEmCDzT9lLQZ+QZyL1fVbOVHiI24hAalbEBEIrEO4GXMD9spqRQ5yoTJ8CgZHTPo0rJkH/ebprp0YHtahVF440zBOvuLM0QTYpERgO2Oe"); + static byte[] extTrust = Base64.decode("MIICJTCCAY4CAQEwDQYJKoZIhvcNAQEFBQAwXDELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxIzAhBgNVBAsMGkJvdW5jeSBQcmltYXJ5IENlcnRpZmljYXRlMB4XDTE1MDMyNDAzNTEwOVoXDTE1MDUyMzAzNTEwOVowXDELMAkGA1UEBhMCQVUxKDAmBgNVBAoMH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxIzAhBgNVBAsMGkJvdW5jeSBQcmltYXJ5IENlcnRpZmljYXRlMIGdMA0GCSqGSIb3DQEBAQUAA4GLADCBhwKBgQCyWdLW5ienaMlL42Fkwtn8edl6q5JTFA5b8XdRGXcx1vdUDSUJ57n/7gpwpuJtVuktLt1/hauoVgC2kInzX2vb88KY4FhCU12fBk5rA5HLfTBuCi0gxN+057SalkC96ibBCtacPwUAfOJRPO5Ez+AZmOYrbDY30/wDkQebJu421QIBETANBgkqhkiG9w0BAQUFAAOBgQCDNfqQnQbbmnGzZTl7ccWIyw7SPzWnijpKsQpuRNGkoXfkCcuQLZudytEFZGEL0cycNBnierjJWAn78zGpCQtab01r1GwytRMYz8qO5IIrhsJ4XNafNypYZbi0WtPa07UCQp8tipMbfQNLzSkvkIAaD5IfhdaWKLrSQJwmGg7YAg=="); + + private void validateWithExtendedKeyUsage() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate rootCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(extTrust)); + X509Certificate interCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(extCA)); + X509Certificate finalCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(extEE)); + + List list = new ArrayList(); + list.add(rootCert); + list.add(interCert); + list.add(finalCert); + + CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list); + CertStore store = CertStore.getInstance("Collection", ccsp, "BC"); + Date validDate = new Date(rootCert.getNotBefore().getTime() + 60 * 60 * 1000); + //validating path + List certchain = new ArrayList(); + certchain.add(finalCert); + certchain.add(interCert); + CertPath cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain); + Set trust = new HashSet(); + trust.add(new TrustAnchor(rootCert, null)); + + CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC"); + PKIXParameters param = new PKIXParameters(trust); + param.addCertStore(store); + param.setDate(validDate); + param.setRevocationEnabled(false); + + PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)cpv.validate(cp, param); + } + + // invalid EE certificate + static byte[] extInvEE = Base64.decode("MIICJjCCAY+gAwIBAAIGAV3Y0TnDMA0GCSqGSIb3DQEBCwUAMBExDzANBgNVBAMMBktQMSBDQTAeFw0xNzA4MTIyMzM5MzJaFw0xNzA4MTMwMDA5MzdaMBExDzANBgNVBAMMBktQMSBFRTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuOcqkp2+HBCuwRDwfR7kkUYXMdhScDG8m6A3Af6hpG86nAimNoVIQe3REaQ6IO0XSdd13rjjRwIXsUFLsrQhQJczF5JeyWXcaYqZyNNbUwFuLeSqOsLS63ltjOJYqOJRxY03Cr//baGWvxGXcRvHoZkg1nEXPcMZhgsy/9JxVoUCAwEAAaOBiDCBhTBABgNVHSMEOTA3gBSPMqzNmTdyjQmr9W1TSDW1h0ZzFaEXpBUwEzERMA8GA1UEAwwIS1AxIFJPT1SCBgFd2NE5wjAdBgNVHQ4EFgQUC1rtYrQdQkA3CLTeV1kbVIdysKQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADgYEAGr841G7E84Ow9+fFGW1zzXeTRfxsafdT/bHXCS75bjF2YPitKLcRLkm92VPxANRXIpmt++3iU/oduWqkLsfXnfTGmCwtjj/XrCvkCBQ4GONwmegltJEThMud0XOEB1UN6tfTINfLYpbyfOdE/wLy4Rte0t43aOTTOBo+/SapYOE="); + static byte[] extInvCA = Base64.decode("MIICKDCCAZGgAwIBAgIGAV3Y0TnCMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMMCEtQMSBST09UMB4XDTE3MDgxMjIzMzkzMloXDTE3MDgxMzAwMDkzN1owETEPMA0GA1UEAwwGS1AxIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7Qd/cTP5S0GoPcomcZU5QlJcb1uWydvmQx3U6p4/KOZBhk6JXQeSzT8QZ/gd+9vfosA62SEX+dq7MvxxzeERxdIsVU0zZ1TrYNxlQjnYXiYRVXBczowsxseQ9oSGD94Y4buhrMAltmIHijdzGRVMY41FZmWqNXqsEwQXj6ULX+QIDAQABo4GIMIGFMEAGA1UdIwQ5MDeAFAbfd2S3aiwFww3/0ocLa6ULQjJMoRekFTATMREwDwYDVQQDDAhLUDEgUk9PVIIGAV3Y0TnBMB0GA1UdDgQWBBSPMqzNmTdyjQmr9W1TSDW1h0ZzFTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOBgQCnmxQYy6LnvRSMxkTsGIQa4LB51O8skbWc4KYVDfcvTYQuvn6rE/ZoYf82jKXJzXksffanfjn/b38l4l8hwAcBQ8we9yjCkjO8OVDUlYiSGYUhH2ZJrl2+K2Z6wpakZ9Lz3pZ/PSS1FIsVd4I1jkexAdAm1+uMlfWXVt/uTZx98w=="); + static byte[] extInvTrust = Base64.decode("MIIBmjCCAQMCBgFd2NE5wTANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhLUDEgUk9PVDAeFw0xNzA4MTIyMzM5MzJaFw0xNzA4MTMwMDA5MzdaMBMxETAPBgNVBAMMCEtQMSBST09UMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8U3p6Y9ah0yQ58wpI3H6vQPMdhN6Hh+zuiNzwX3AIpEspUFTfqXJ6EIhqh/EraDnLnoFBajzihwS1y6a+ZyXYKa5pxbFsslmzms+ozcTaJ4mSMiC+DHbGYdOAEzwx2nsEt7UKyrlnl5h2kQFusUPmnXXEorIxhpS2Lul+zEBo1wIDAQABMA0GCSqGSIb3DQEBCwUAA4GBABClwXaJ8S66GmeySf1thOPc1GxIHuubezIjcBbECLZQqn7iwuzp+eft1vtnqNP7BWM1xBZkSe+/2xUsArc1rb1ffZHF3k92+WLbpDh3+NsQIod/91HRWUuu/S2g9oMK4b7BH8JrmBgy3ewtpNZwOaKF613GPCeGv3ya5Z24vBu+"); + + static byte[] extInvV2Trust = Base64.decode("MIIBmjCCAQMCBgFd2NhVgTANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhLUDEgUk9PVDAeFw0xNzA4MTIyMzQ3MThaFw0xNzA4MTMwMDE3MjNaMBMxETAPBgNVBAMMCEtQMSBST09UMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCQaASWM5avAAJ57eHQ2zQ0k/mAiYSOkRKDLEzptDPYfzuQtTdAlBPn7tsYx+Ylge4YQwtx5bQZbc3apinBK9tn+c++go0kUF1cec2bacYyFokSP2r48j6ZhlY4MYGfrvfWHULrG2JL2BMeuZVP+wiqXktXCEKVG1fh1m6RY0TJPwIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAC9mXO2i2vltBZZa7RMkizvhzhsehDHbEqvJd2aoWE9JG4sDo2tiIVN5vbq9EWLZVga3ejFzmQ+FI1Ty0xX3fwDgvUyxsveGTs40xwA9TEgVk1KNTQQs+sLE9rRB7L0giKn2DDmHFsOPL1KwxdzqD7vYhJr5av3eAsJpMxF+Anyg"); + static byte[] extInvV2CA = Base64.decode("MIICKDCCAZGgAwIBAgIGAV3Y2FWCMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMMCEtQMSBST09UMB4XDTE3MDgxMjIzNDcxOFoXDTE3MDgxMzAwMTcyM1owETEPMA0GA1UEAwwGS1AxIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCgb8h3h9d/FzhIc+PMbF0vwdiDKw7N3dNyY6TrmzCMC1mYDXSKmxxDwNKZCKj6VSNfbTDqxYKlZMoGVT8Cl/iE/+XEhOKYLv73rzTqzdMizqcQTCvwps1enGxI5wPBYKGCMWrpJui5RWV9wH6hMvmzSSZq7bdWTvc/pIltCpIj8wIDAQABo4GIMIGFMEAGA1UdIwQ5MDeAFMOcs/uWpVOkGRQJrVIp6cN6tCJQoRekFTATMREwDwYDVQQDDAhLUDEgUk9PVIIGAV3Y2FWBMB0GA1UdDgQWBBTsZ2B5JbgKm9/up2hOcYVyOaM1SjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOBgQBI8J1bKh/e+uEZtfngKMADS1PSHztAPFFKXgeIfYeJDRznnamtbheensdxrA+aoriJbJfHxmjecr4xA8+s0uN9GPtQ3+ad1K5Sg6mfzsXtNPf3xa9y0pIWOGZavr1s/QugoPLQxEiuHrvkHX5+sZlx47KoBQJ8LBRmJydeSvxz1g=="); + static byte[] extInvV2EE = Base64.decode("MIICJjCCAY+gAwIBAQIGAV3Y2FWDMA0GCSqGSIb3DQEBCwUAMBExDzANBgNVBAMMBktQMSBDQTAeFw0xNzA4MTIyMzQ3MThaFw0xNzA4MTMwMDE3MjNaMBExDzANBgNVBAMMBktQMSBFRTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzWXxtMpnjz8Q1qTdwpB66W2D0vEHhqow2PTsvfQdENL4AFESE1C7Cj3lLBTei1vRHCnpM0jdNghBW8k/u2b2tqeeWLBqwul0tEGbjtUwkYV2WgtTGmiYZZFfMH35HIvqlZMwIIdZqz4lEdkPiAPEUOELvycpVDFnWjF0qah5LqsCAwEAAaOBiDCBhTBABgNVHSMEOTA3gBTsZ2B5JbgKm9/up2hOcYVyOaM1SqEXpBUwEzERMA8GA1UEAwwIS1AxIFJPT1SCBgFd2NhVgjAdBgNVHQ4EFgQUfeKdn63Gmlkub8m8bwjqJook5ywwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADgYEAco35KYLE683l53J6V1q2tcMV3EpM39tifkL7Kl38oX9d3SGiKkEO6YFeQekRyto0Z91mPq7Pe/oOfDrfsY3r9KX7oqnhOKBnnR/58atM9udVLvuLfCJpxiroAldSkhRKvHG5MrFwZyDcVkTZF4GDrP6bojp32wVfU5EYkfwcJN8="); + + static byte[] extInvVersionTrust = Base64.decode("MIIBmjCCAQMCBgFd2RZiPjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhLUDEgUk9PVDAeFw0xNzA4MTMwMDU1MDRaFw0xNzA4MTMwMTI1MDlaMBMxETAPBgNVBAMMCEtQMSBST09UMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCPn6zObnrjGPUb0ozc3MCOOcHwtQABZmUHtB1jxRXWwYXKo+iTms2wJjDS5fhz2UmUptsbdFwPdvT2t7K8cpaZBcovC3jLvEAMmjO+nU3FQrdopZ6MhBjpgIezAvJ9LUhrYctqUJzfViqtLl0dL+YRjaVdfCz5z0iZn4rv2VSf3QIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAHtS9RjMIRzeEpH9MKIaMLR7wVb55MYW7E2CVuIbsHmT+KyDBFsYbAylgc76cH1b8F53ECygS9jCpzfKtO61WVPPlUhsL13i2XbzCtj8DSPXaW5pgvpwClQZ+dpGFz8D/MYLSdjTdls8dbhJ5O08ckSKcrIGHcF90oeepVXOmiTw"); + static byte[] extInvVersionCA = Base64.decode( "MIICKDCCAZGgAwIBAgIGAV3ZFmI/MA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMMCEtQMSBST09UMB4XDTE3MDgxMzAwNTUwNFoXDTE3MDgxMzAxMjUwOVowETEPMA0GA1UEAwwGS1AxIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQChlaZhX9/eHmtfravHzs/E0g6ZhWTmD9aNNvuuz/GCBF9AMS6QQCGVhEzxESn0gLzs1bM/9M/EaylHS3Ecvi6QYdkrTKRDj38FDzrDhiPlM3TxY0XuUQ3Py590k8yZDcuEeVEQeoUx83qOnO7o/cL+vECfMj9ImYFFgY5sMcKkVQIDAQABo4GIMIGFMEAGA1UdIwQ5MDeAFAfTyJtmNkinVjfd7/2Giy6krDTpoRekFTATMREwDwYDVQQDDAhLUDEgUk9PVIIGAV3ZFmI+MB0GA1UdDgQWBBQkMq+wajXvKQaJtSdpvDJn77bU9zASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOBgQAqmKtykmixemAvppo2tTmekLsL93+/DMR+oz1iK2rjhqYzEF1/pM9VUyG+Ni1924U8tzGbXv2lL3MiToRSyjO50HHfnE7PfOvNiTUj73PTn27tPl03eWO3CtsOTGxtE2vpNyXyFXm4SFZlSicOXE0o/kUrNGVYvnjs/jjcNlPiHQ=="); + static byte[] extInvVersionEE = Base64.decode( "MIICJjCCAY+gAwIBBQIGAV3ZFmJAMA0GCSqGSIb3DQEBCwUAMBExDzANBgNVBAMMBktQMSBDQTAeFw0xNzA4MTMwMDU1MDRaFw0xNzA4MTMwMTI1MDlaMBExDzANBgNVBAMMBktQMSBFRTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA6PXdCOvE33+mMcal/rC+I7zdJqcc6OBhn+Lyku29TRcYplMA5mkh7WkjLtRYBUAzHukN/GXb1Mo+dFkvCnKO/l4gLWyVuf23rL6iELt8X1KVJdJlrDElCmTgl6lA0Omq7QhNrsv5Vdk7mK2mbJzl0bj4fcu5dc23nQXEskmGrZsCAwEAAaOBiDCBhTBABgNVHSMEOTA3gBQkMq+wajXvKQaJtSdpvDJn77bU96EXpBUwEzERMA8GA1UEAwwIS1AxIFJPT1SCBgFd2RZiPzAdBgNVHQ4EFgQU3Nw/DFxNqK1fRhc/W8W4o3mkCHQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADgYEAjMTiKgLC2Kb5+elvfD/+CM8pNeLt5Y43sMSTpgIrebdWPA2hyvjvW/upsIYIquGrymOYBU/K0abQlkNUbBHpQCQMPQ6iPXuhTQj/P7rt7McLl6OXV/DQqgF+39y0xWAzoZbgMKrQaSr9oRmEVt6xzLM92JS67w8Xgbh39PGBfEg="); + + static byte[] extInvExtTrust = Base64.decode("MIIBmjCCAQMCBgFd2SFqKjANBgkqhkiG9w0BAQsFADATMREwDwYDVQQDDAhLUDEgUk9PVDAeFw0xNzA4MTMwMTA3MDdaFw0xNzA4MTMwMTM3MTJaMBMxETAPBgNVBAMMCEtQMSBST09UMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDEY3toxiphhoeoTd79/Uznb1YyKjYgxtXkYVQLZ+Q76bJFQftVVcUHw25/A/2qgSc8XPflGRpn82Qn/B7s3fxEglgeY0ekdYjea5+jZSJj70p1QcC60yH1NKGxE0ASBuv/22IoHhdu5dOTmiWegikKUXblBD1wAxbbvOcXFs2x/wIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAJPG9wt9edpTaCc0z03xGNF/M6x5cLx5eLgZaBFt+FO3S1xWIVby+iU8Hw2mzHOc58Fghw1jEwLaslQYadx9667NedGu7dYyY318h+VhaDppQqkhJiQl5Q8aTvVNt60fDEVLjvB7E6Z+CafVGR1jNrXxLDe6zVf/BZJK7QrkTKh4"); + static byte[] extInvExtCA = Base64.decode("MIICKDCCAZGgAwIBAgIGAV3ZIWorMA0GCSqGSIb3DQEBCwUAMBMxETAPBgNVBAMMCEtQMSBST09UMB4XDTE3MDgxMzAxMDcwN1oXDTE3MDgxMzAxMzcxMlowETEPMA0GA1UEAwwGS1AxIENBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCJKySmanEENpLJdPwpM/v0I7H0bW9ZlIxRpiL+/Z4uvF3j0r0O42Tm+dW8Ub42DzHcQ8pK/n/k2Wb4Jf7cP8+TGTAne3bgC24USW131XUZxaunGt4tCqZ0RNWpmBQUcUM0lgntDSfcvyv3QFB+nwLc93GYij9l3FaeUcHkwFiKsQIDAQABo4GIMIGFMEAGA1UdIwQ5MDeAFLnC9UF+JqEqboFH84ab9dEAkwEBoRekFTATMREwDwYDVQQDDAhLUDEgUk9PVIIGAV3ZIWoqMB0GA1UdDgQWBBQkr/0UP1MKPGQH7bkRNctHMsVQsjASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOBgQCZxLwkAPif1H2P398MHK3NLf3mrmLsP41ZphdHnSLNROlY9PdO5I/dfhElzVXW2oxecIIKbOQsjZe0FOSGvZHEhLftQmOdfGc5QfGf5w9CSFCCBe5vHdMjglRLVhNB51jz6DB7Dp0MjFDgkQI4lBHaiMVkE+HUZjNLwBddHH58Sw=="); + static byte[] extInvExtEE = Base64.decode("MIICNjCCAZ+gAwIBAgIGAV3ZIWosMA0GCSqGSIb3DQEBCwUAMBExDzANBgNVBAMMBktQMSBDQTAeFw0xNzA4MTMwMTA3MDdaFw0xNzA4MTMwMTM3MTJaMBExDzANBgNVBAMMBktQMSBFRTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAj6WOoo8xHLLo+CT0l288xZDK3OsF64lPfNVkFnrRI65Ywl89M19nNF5Q24hF1FS6getO5oU+BhvRqft1/De22SME9SzKqs3G6uMxACKrMqgni1QBEOC/DdZ5Uaxh2s4lEgxbN0PQZIarAgLtAIgzRM4CrvofxFMwQy/neUuWmeMCAwEAAaOBmDCBlTBABgNVHSMEOTA3gBQkr/0UP1MKPGQH7bkRNctHMsVQsqEXpBUwEzERMA8GA1UEAwwIS1AxIFJPT1SCBgFd2SFqKzAdBgNVHQ4EFgQU/yuQXlvqXJQsbqB6whCPu5bwFCAwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4GBABYUGar9s7wlM3Qlnja7uc7U8FqU+xH4e8/Jk64ku7DdwXelEbKo/FTFAzh464aiFP4eMDOH7YThXyTruPudEAvYyWY7eaEgRqA2MmL0uWHSrN+HR9aBeqrMCJK/E2e1egvk2whJHMimhDUFJ3cIPsFhazMvLTnVgWGMjOqQtuP+"); + + private void checkInvalidCertPath() + throws Exception + { + checkInvalidPath(extInvTrust, extInvCA, extInvEE, "version 1 certificate contains extra data"); + checkInvalidPath(extInvV2Trust, extInvV2CA, extInvV2EE, "version 2 certificate cannot contain extensions"); + checkInvalidPath(extInvVersionTrust, extInvVersionCA, extInvVersionEE, "version number not recognised"); + checkInvalidPath(extInvExtTrust, extInvExtCA, extInvExtEE, "repeated extension found: 2.5.29.15"); + } + + private void checkInvalidPath(byte[] root, byte[] inter, byte[] ee, String expected) + throws Exception + { + X509Certificate rootCert = new X509CertificateObject(X509CertificateStructure.getInstance(root)); + X509Certificate interCert = new X509CertificateObject(X509CertificateStructure.getInstance(inter)); + X509Certificate finalCert = new X509CertificateObject(X509CertificateStructure.getInstance(ee)); + List list = new ArrayList(); + list.add(rootCert); + list.add(interCert); + list.add(finalCert); + + CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list); + CertStore store = CertStore.getInstance("Collection", ccsp, "BC"); + Date validDate = new Date(rootCert.getNotBefore().getTime() + 60 * 1000); + //validating path + List certchain = new ArrayList(); + certchain.add(finalCert); + certchain.add(interCert); + CertPath cp = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certchain); + Set trust = new HashSet(); + trust.add(new TrustAnchor(rootCert, null)); + + CertPathValidator cpv = CertPathValidator.getInstance("PKIX", "BC"); + PKIXParameters param = new PKIXParameters(trust); + param.addCertStore(store); + param.setDate(validDate); + param.setRevocationEnabled(false); + + try + { + PKIXCertPathValidatorResult result = (PKIXCertPathValidatorResult)cpv.validate(cp, param); + fail("valid path passed"); + } + catch (CertPathValidatorException e) + { + isTrue(e.getMessage().equals(expected)); + } + + // check that our cert factory also rejects - the EE is always the invalid one + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + try + { + cf.generateCertificate(new ByteArrayInputStream(ee)); + } + catch (CertificateException e) + { + isTrue(e.getMessage().equals("parsing issue: " + expected)); + } + } + + public String getName() + { + return "CertPathValidator"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new CertPathValidatorTest()); + } + + private static class MyChecker + extends PKIXCertPathChecker + { + private static int count; + + public void init(boolean forward) + throws CertPathValidatorException + { + //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean isForwardCheckingSupported() + { + return true; + } + + public Set getSupportedExtensions() + { + return null; + } + + public void check(Certificate cert, Collection unresolvedCritExts) + throws CertPathValidatorException + { + count++; + } + + public int getCount() + { + return count; + } + } + + public static class X509CertificateObject + extends X509Certificate + { + static final String CERTIFICATE_POLICIES = Extension.certificatePolicies.getId(); + static final String POLICY_MAPPINGS = Extension.policyMappings.getId(); + static final String INHIBIT_ANY_POLICY = Extension.inhibitAnyPolicy.getId(); + static final String ISSUING_DISTRIBUTION_POINT = Extension.issuingDistributionPoint.getId(); + static final String FRESHEST_CRL = Extension.freshestCRL.getId(); + static final String DELTA_CRL_INDICATOR = Extension.deltaCRLIndicator.getId(); + static final String POLICY_CONSTRAINTS = Extension.policyConstraints.getId(); + static final String BASIC_CONSTRAINTS = Extension.basicConstraints.getId(); + static final String CRL_DISTRIBUTION_POINTS = Extension.cRLDistributionPoints.getId(); + static final String SUBJECT_ALTERNATIVE_NAME = Extension.subjectAlternativeName.getId(); + static final String NAME_CONSTRAINTS = Extension.nameConstraints.getId(); + static final String AUTHORITY_KEY_IDENTIFIER = Extension.authorityKeyIdentifier.getId(); + static final String KEY_USAGE = Extension.keyUsage.getId(); + static final String CRL_NUMBER = Extension.cRLNumber.getId(); + static final String ANY_POLICY = "2.5.29.32.0"; + + private com.fr.third.org.bouncycastle.asn1.x509.X509CertificateStructure c; + private BasicConstraints basicConstraints; + private boolean[] keyUsage; + private boolean hashValueSet; + private int hashValue; + + public X509CertificateObject( + com.fr.third.org.bouncycastle.asn1.x509.X509CertificateStructure c) + throws CertificateParsingException + { + this.c = c; + + try + { + byte[] bytes = this.getExtensionBytes("2.5.29.19"); + + if (bytes != null) + { + basicConstraints = BasicConstraints.getInstance(ASN1Primitive.fromByteArray(bytes)); + } + } + catch (Exception e) + { + throw new CertificateParsingException("cannot construct BasicConstraints: " + e); + } + + try + { + byte[] bytes = this.getExtensionBytes("2.5.29.15"); + if (bytes != null) + { + ASN1BitString bits = DERBitString.getInstance(ASN1Primitive.fromByteArray(bytes)); + + bytes = bits.getBytes(); + int length = (bytes.length * 8) - bits.getPadBits(); + + keyUsage = new boolean[(length < 9) ? 9 : length]; + + for (int i = 0; i != length; i++) + { + keyUsage[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + } + } + else + { + keyUsage = null; + } + } + catch (Exception e) + { + throw new CertificateParsingException("cannot construct KeyUsage: " + e); + } + } + + public void checkValidity() + throws CertificateExpiredException, CertificateNotYetValidException + { + this.checkValidity(new Date()); + } + + public void checkValidity( + Date date) + throws CertificateExpiredException, CertificateNotYetValidException + { + if (date.getTime() > this.getNotAfter().getTime()) // for other VM compatibility + { + throw new CertificateExpiredException("certificate expired on " + c.getEndDate().getTime()); + } + + if (date.getTime() < this.getNotBefore().getTime()) + { + throw new CertificateNotYetValidException("certificate not valid till " + c.getStartDate().getTime()); + } + } + + public int getVersion() + { + return c.getVersion(); + } + + public BigInteger getSerialNumber() + { + return c.getSerialNumber().getValue(); + } + + public Principal getIssuerDN() + { + try + { + return new X509Principal(X500Name.getInstance(c.getIssuer().getEncoded())); + } + catch (IOException e) + { + return null; + } + } + + public X500Principal getIssuerX500Principal() + { + try + { + return new X500Principal(c.getIssuer().getEncoded()); + } + catch (IOException e) + { + throw new IllegalStateException("can't encode issuer DN"); + } + } + + public Principal getSubjectDN() + { + return new X509Principal(X500Name.getInstance(c.getSubject().toASN1Primitive())); + } + + public X500Principal getSubjectX500Principal() + { + try + { + return new X500Principal(c.getSubject().getEncoded()); + } + catch (IOException e) + { + throw new IllegalStateException("can't encode issuer DN"); + } + } + + public Date getNotBefore() + { + return c.getStartDate().getDate(); + } + + public Date getNotAfter() + { + return c.getEndDate().getDate(); + } + + public byte[] getTBSCertificate() + throws CertificateEncodingException + { + try + { + return c.getTBSCertificate().getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CertificateEncodingException(e.toString()); + } + } + + public byte[] getSignature() + { + return c.getSignature().getOctets(); + } + + /** + * return a more "meaningful" representation for the signature algorithm used in + * the certficate. + */ + public String getSigAlgName() + { + Provider prov = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME); + + if (prov != null) + { + String algName = prov.getProperty("Alg.Alias.Signature." + this.getSigAlgOID()); + + if (algName != null) + { + return algName; + } + } + + Provider[] provs = Security.getProviders(); + + // + // search every provider looking for a real algorithm + // + for (int i = 0; i != provs.length; i++) + { + String algName = provs[i].getProperty("Alg.Alias.Signature." + this.getSigAlgOID()); + if (algName != null) + { + return algName; + } + } + + return this.getSigAlgOID(); + } + + /** + * return the object identifier for the signature. + */ + public String getSigAlgOID() + { + return c.getSignatureAlgorithm().getAlgorithm().getId(); + } + + /** + * return the signature parameters, or null if there aren't any. + */ + public byte[] getSigAlgParams() + { + if (c.getSignatureAlgorithm().getParameters() != null) + { + try + { + return c.getSignatureAlgorithm().getParameters().toASN1Primitive().getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + return null; + } + } + else + { + return null; + } + } + + public boolean[] getIssuerUniqueID() + { + DERBitString id = c.getTBSCertificate().getIssuerUniqueId(); + + if (id != null) + { + byte[] bytes = id.getBytes(); + boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()]; + + for (int i = 0; i != boolId.length; i++) + { + boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + } + + return boolId; + } + + return null; + } + + public boolean[] getSubjectUniqueID() + { + DERBitString id = c.getTBSCertificate().getSubjectUniqueId(); + + if (id != null) + { + byte[] bytes = id.getBytes(); + boolean[] boolId = new boolean[bytes.length * 8 - id.getPadBits()]; + + for (int i = 0; i != boolId.length; i++) + { + boolId[i] = (bytes[i / 8] & (0x80 >>> (i % 8))) != 0; + } + + return boolId; + } + + return null; + } + + public boolean[] getKeyUsage() + { + return keyUsage; + } + + public List getExtendedKeyUsage() + throws CertificateParsingException + { + byte[] bytes = this.getExtensionBytes("2.5.29.37"); + + if (bytes != null) + { + try + { + ASN1InputStream dIn = new ASN1InputStream(bytes); + ASN1Sequence seq = (ASN1Sequence)dIn.readObject(); + List list = new ArrayList(); + + for (int i = 0; i != seq.size(); i++) + { + list.add(((ASN1ObjectIdentifier)seq.getObjectAt(i)).getId()); + } + + return Collections.unmodifiableList(list); + } + catch (Exception e) + { + throw new CertificateParsingException("error processing extended key usage extension"); + } + } + + return null; + } + + public int getBasicConstraints() + { + if (basicConstraints != null) + { + if (basicConstraints.isCA()) + { + if (basicConstraints.getPathLenConstraint() == null) + { + return Integer.MAX_VALUE; + } + else + { + return basicConstraints.getPathLenConstraint().intValue(); + } + } + else + { + return -1; + } + } + + return -1; + } + + public Collection getSubjectAlternativeNames() + throws CertificateParsingException + { + return getAlternativeNames(getExtensionBytes(Extension.subjectAlternativeName.getId())); + } + + public Collection getIssuerAlternativeNames() + throws CertificateParsingException + { + return getAlternativeNames(getExtensionBytes(Extension.issuerAlternativeName.getId())); + } + + public Set getCriticalExtensionOIDs() + { + if (this.getVersion() == 3) + { + Set set = new HashSet(); + X509Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + X509Extension ext = extensions.getExtension(oid); + + if (ext.isCritical()) + { + set.add(oid.getId()); + } + } + + return set; + } + } + + return null; + } + + private byte[] getExtensionBytes(String oid) + { + X509Extensions exts = c.getTBSCertificate().getExtensions(); + + if (exts != null) + { + X509Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); + if (ext != null) + { + return ext.getValue().getOctets(); + } + } + + return null; + } + + public byte[] getExtensionValue(String oid) + { + X509Extensions exts = c.getTBSCertificate().getExtensions(); + + if (exts != null) + { + X509Extension ext = exts.getExtension(new ASN1ObjectIdentifier(oid)); + + if (ext != null) + { + try + { + return ext.getValue().getEncoded(); + } + catch (Exception e) + { + throw new IllegalStateException("error parsing " + e.toString()); + } + } + } + + return null; + } + + public Set getNonCriticalExtensionOIDs() + { + if (this.getVersion() == 3) + { + Set set = new HashSet(); + X509Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + X509Extension ext = extensions.getExtension(oid); + + if (!ext.isCritical()) + { + set.add(oid.getId()); + } + } + + return set; + } + } + + return null; + } + + public boolean hasUnsupportedCriticalExtension() + { + if (this.getVersion() == 3) + { + X509Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + String oidId = oid.getId(); + + if (oidId.equals(KEY_USAGE) + || oidId.equals(CERTIFICATE_POLICIES) + || oidId.equals(POLICY_MAPPINGS) + || oidId.equals(INHIBIT_ANY_POLICY) + || oidId.equals(CRL_DISTRIBUTION_POINTS) + || oidId.equals(ISSUING_DISTRIBUTION_POINT) + || oidId.equals(DELTA_CRL_INDICATOR) + || oidId.equals(POLICY_CONSTRAINTS) + || oidId.equals(BASIC_CONSTRAINTS) + || oidId.equals(SUBJECT_ALTERNATIVE_NAME) + || oidId.equals(NAME_CONSTRAINTS)) + { + continue; + } + + X509Extension ext = extensions.getExtension(oid); + + if (ext.isCritical()) + { + return true; + } + } + } + } + + return false; + } + + public PublicKey getPublicKey() + { + try + { + return BouncyCastleProvider.getPublicKey(c.getSubjectPublicKeyInfo()); + } + catch (IOException e) + { + return null; // should never happen... + } + } + + public byte[] getEncoded() + throws CertificateEncodingException + { + try + { + return c.getEncoded(ASN1Encoding.DER); + } + catch (IOException e) + { + throw new CertificateEncodingException(e.toString()); + } + } + + public boolean equals( + Object o) + { + if (o == this) + { + return true; + } + + if (!(o instanceof Certificate)) + { + return false; + } + + Certificate other = (Certificate)o; + + try + { + byte[] b1 = this.getEncoded(); + byte[] b2 = other.getEncoded(); + + return Arrays.areEqual(b1, b2); + } + catch (CertificateEncodingException e) + { + return false; + } + } + + public synchronized int hashCode() + { + if (!hashValueSet) + { + hashValue = calculateHashCode(); + hashValueSet = true; + } + + return hashValue; + } + + private int calculateHashCode() + { + try + { + int hashCode = 0; + byte[] certData = this.getEncoded(); + for (int i = 1; i < certData.length; i++) + { + hashCode += certData[i] * i; + } + return hashCode; + } + catch (CertificateEncodingException e) + { + return 0; + } + } + + public String toString() + { + StringBuffer buf = new StringBuffer(); + String nl = Strings.lineSeparator(); + + buf.append(" [0] Version: ").append(this.getVersion()).append(nl); + buf.append(" SerialNumber: ").append(this.getSerialNumber()).append(nl); + buf.append(" IssuerDN: ").append(this.getIssuerDN()).append(nl); + buf.append(" Start Date: ").append(this.getNotBefore()).append(nl); + buf.append(" Final Date: ").append(this.getNotAfter()).append(nl); + buf.append(" SubjectDN: ").append(this.getSubjectDN()).append(nl); + buf.append(" Public Key: ").append(this.getPublicKey()).append(nl); + buf.append(" Signature Algorithm: ").append(this.getSigAlgName()).append(nl); + + byte[] sig = this.getSignature(); + + buf.append(" Signature: ").append(new String(Hex.encode(sig, 0, 20))).append(nl); + for (int i = 20; i < sig.length; i += 20) + { + if (i < sig.length - 20) + { + buf.append(" ").append(new String(Hex.encode(sig, i, 20))).append(nl); + } + else + { + buf.append(" ").append(new String(Hex.encode(sig, i, sig.length - i))).append(nl); + } + } + + X509Extensions extensions = c.getTBSCertificate().getExtensions(); + + if (extensions != null) + { + Enumeration e = extensions.oids(); + + if (e.hasMoreElements()) + { + buf.append(" Extensions: \n"); + } + + while (e.hasMoreElements()) + { + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier)e.nextElement(); + X509Extension ext = extensions.getExtension(oid); + + if (ext.getValue() != null) + { + byte[] octs = ext.getValue().getOctets(); + ASN1InputStream dIn = new ASN1InputStream(octs); + buf.append(" critical(").append(ext.isCritical()).append(") "); + try + { + if (oid.equals(Extension.basicConstraints)) + { + buf.append(BasicConstraints.getInstance(dIn.readObject())).append(nl); + } + else if (oid.equals(Extension.keyUsage)) + { + buf.append(KeyUsage.getInstance(dIn.readObject())).append(nl); + } + else if (oid.equals(MiscObjectIdentifiers.netscapeCertType)) + { + buf.append(new NetscapeCertType((DERBitString)dIn.readObject())).append(nl); + } + else if (oid.equals(MiscObjectIdentifiers.netscapeRevocationURL)) + { + buf.append(new NetscapeRevocationURL((DERIA5String)dIn.readObject())).append(nl); + } + else if (oid.equals(MiscObjectIdentifiers.verisignCzagExtension)) + { + buf.append(new VerisignCzagExtension((DERIA5String)dIn.readObject())).append(nl); + } + else + { + buf.append(oid.getId()); + buf.append(" value = ").append(ASN1Dump.dumpAsString(dIn.readObject())).append(nl); + //buf.append(" value = ").append("*****").append(nl); + } + } + catch (Exception ex) + { + buf.append(oid.getId()); + // buf.append(" value = ").append(new String(Hex.encode(ext.getExtnValue().getOctets()))).append(nl); + buf.append(" value = ").append("*****").append(nl); + } + } + else + { + buf.append(nl); + } + } + } + + return buf.toString(); + } + + public final void verify( + PublicKey key) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + Signature signature; + String sigName = "SHA256withRSA"; + + try + { + signature = Signature.getInstance(sigName, BouncyCastleProvider.PROVIDER_NAME); + } + catch (Exception e) + { + signature = Signature.getInstance(sigName); + } + + checkSignature(key, signature); + } + + public final void verify( + PublicKey key, + String sigProvider) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, NoSuchProviderException, SignatureException + { + String sigName = "SHA256withRSA"; + Signature signature; + + if (sigProvider != null) + { + signature = Signature.getInstance(sigName, sigProvider); + } + else + { + signature = Signature.getInstance(sigName); + } + + checkSignature(key, signature); + } + + public final void verify( + PublicKey key, + Provider sigProvider) + throws CertificateException, NoSuchAlgorithmException, + InvalidKeyException, SignatureException + { + String sigName = "SHA256withRSA"; + Signature signature; + + if (sigProvider != null) + { + signature = Signature.getInstance(sigName, sigProvider); + } + else + { + signature = Signature.getInstance(sigName); + } + + checkSignature(key, signature); + } + + private void checkSignature( + PublicKey key, + Signature signature) + throws CertificateException, NoSuchAlgorithmException, + SignatureException, InvalidKeyException + { + if (!isAlgIdEqual(c.getSignatureAlgorithm(), c.getTBSCertificate().getSignature())) + { + throw new CertificateException("signature algorithm in TBS cert not same as outer cert"); + } + + ASN1Encodable params = c.getSignatureAlgorithm().getParameters(); + + signature.initVerify(key); + + signature.update(this.getTBSCertificate()); + + if (!signature.verify(this.getSignature())) + { + throw new SignatureException("certificate does not verify with supplied key"); + } + } + + private boolean isAlgIdEqual(AlgorithmIdentifier id1, AlgorithmIdentifier id2) + { + if (!id1.getAlgorithm().equals(id2.getAlgorithm())) + { + return false; + } + + if (id1.getParameters() == null) + { + if (id2.getParameters() != null && !id2.getParameters().equals(DERNull.INSTANCE)) + { + return false; + } + + return true; + } + + if (id2.getParameters() == null) + { + if (id1.getParameters() != null && !id1.getParameters().equals(DERNull.INSTANCE)) + { + return false; + } + + return true; + } + + return id1.getParameters().equals(id2.getParameters()); + } + + private static Collection getAlternativeNames(byte[] extVal) + throws CertificateParsingException + { + if (extVal == null) + { + return null; + } + try + { + Collection temp = new ArrayList(); + Enumeration it = ASN1Sequence.getInstance(extVal).getObjects(); + while (it.hasMoreElements()) + { + GeneralName genName = GeneralName.getInstance(it.nextElement()); + List list = new ArrayList(); + list.add(Integers.valueOf(genName.getTagNo())); + switch (genName.getTagNo()) + { + case GeneralName.ediPartyName: + case GeneralName.x400Address: + case GeneralName.otherName: + list.add(genName.getEncoded()); + break; + case GeneralName.directoryName: + list.add(X500Name.getInstance(RFC4519Style.INSTANCE, genName.getName()).toString()); + break; + case GeneralName.dNSName: + case GeneralName.rfc822Name: + case GeneralName.uniformResourceIdentifier: + list.add(((ASN1String)genName.getName()).getString()); + break; + case GeneralName.registeredID: + list.add(ASN1ObjectIdentifier.getInstance(genName.getName()).getId()); + break; + case GeneralName.iPAddress: + byte[] addrBytes = DEROctetString.getInstance(genName.getName()).getOctets(); + final String addr; + try + { + addr = InetAddress.getByAddress(addrBytes).getHostAddress(); + } + catch (UnknownHostException e) + { + continue; + } + list.add(addr); + break; + default: + throw new IOException("Bad tag number: " + genName.getTagNo()); + } + + temp.add(Collections.unmodifiableList(list)); + } + if (temp.size() == 0) + { + return null; + } + return Collections.unmodifiableCollection(temp); + } + catch (Exception e) + { + throw new CertificateParsingException(e.getMessage()); + } + } + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertStoreTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertStoreTest.java new file mode 100644 index 000000000..d76aecc48 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertStoreTest.java @@ -0,0 +1,235 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +import java.io.ByteArrayInputStream; +import java.security.Security; +import java.security.cert.CertStore; +import java.security.cert.CertificateFactory; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLSelector; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +public class CertStoreTest + extends SimpleTest +{ + + public void performTest() + throws Exception + { + basicTest(); + orderTest(); + } + + private void basicTest() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate rootCert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream( + CertPathTest.rootCertBin)); + X509Certificate interCert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream( + CertPathTest.interCertBin)); + X509Certificate finalCert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream( + CertPathTest.finalCertBin)); + X509CRL rootCrl = (X509CRL)cf.generateCRL(new ByteArrayInputStream( + CertPathTest.rootCrlBin)); + X509CRL interCrl = (X509CRL)cf + .generateCRL(new ByteArrayInputStream( + CertPathTest.interCrlBin)); + + // Testing CollectionCertStore generation from List + List list = new ArrayList(); + list.add(rootCert); + list.add(interCert); + list.add(finalCert); + list.add(rootCrl); + list.add(interCrl); + CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list); + CertStore store = CertStore.getInstance("Collection", ccsp, "BC"); + + // Searching for rootCert by subjectDN + X509CertSelector targetConstraints = new X509CertSelector(); + targetConstraints.setSubject(rootCert.getSubjectX500Principal().getName()); + Collection certs = store.getCertificates(targetConstraints); + if (certs.size() != 1 || !certs.contains(rootCert)) + { + fail("rootCert not found by subjectDN"); + } + + // Searching for rootCert by subjectDN encoded as byte + targetConstraints = new X509CertSelector(); + targetConstraints.setSubject(rootCert.getSubjectX500Principal() + .getEncoded()); + certs = store.getCertificates(targetConstraints); + if (certs.size() != 1 || !certs.contains(rootCert)) + { + fail("rootCert not found by encoded subjectDN"); + } + + // Searching for rootCert by public key encoded as byte + targetConstraints = new X509CertSelector(); + targetConstraints.setSubjectPublicKey(rootCert.getPublicKey() + .getEncoded()); + certs = store.getCertificates(targetConstraints); + if (certs.size() != 1 || !certs.contains(rootCert)) + { + fail("rootCert not found by encoded public key"); + } + + // Searching for interCert by issuerDN + targetConstraints = new X509CertSelector(); + targetConstraints.setIssuer(rootCert.getSubjectX500Principal() + .getEncoded()); + certs = store.getCertificates(targetConstraints); + if (certs.size() != 2) + { + fail("did not found 2 certs"); + } + if (!certs.contains(rootCert)) + { + fail("rootCert not found"); + } + if (!certs.contains(interCert)) + { + fail("interCert not found"); + } + + // Searching for rootCrl by issuerDN + X509CRLSelector targetConstraintsCRL = new X509CRLSelector(); + targetConstraintsCRL.addIssuerName(rootCrl.getIssuerX500Principal() + .getEncoded()); + Collection crls = store.getCRLs(targetConstraintsCRL); + if (crls.size() != 1 || !crls.contains(rootCrl)) + { + fail("rootCrl not found"); + } + } + + private void orderTest() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate rootCert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream( + CertPathTest.rootCertBin)); + X509Certificate interCert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream( + CertPathTest.interCertBin)); + X509Certificate finalCert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream( + CertPathTest.finalCertBin)); + + List list = new ArrayList(); + list.add(rootCert); + list.add(interCert); + list.add(finalCert); + CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list); + CertStore store = CertStore.getInstance("Collection", ccsp, "BC"); + + Iterator certs = store.getCertificates(null).iterator(); + + if (!certs.next().equals(rootCert)) + { + fail("root ordering wrong"); + } + if (!certs.next().equals(interCert)) + { + fail("mid ordering wrong"); + } + if (!certs.next().equals(finalCert)) + { + fail("final ordering wrong"); + } + + list = new ArrayList(); + list.add(finalCert); + list.add(interCert); + list.add(rootCert); + ccsp = new CollectionCertStoreParameters(list); + store = CertStore.getInstance("Collection", ccsp, "BC"); + + certs = store.getCertificates(null).iterator(); + + if (!certs.next().equals(finalCert)) + { + fail("reverse final ordering wrong"); + } + if (!certs.next().equals(interCert)) + { + fail("reverse mid ordering wrong"); + } + if (!certs.next().equals(rootCert)) + { + fail("reverse root ordering wrong"); + } + + X509CRL rootCrl = (X509CRL)cf.generateCRL(new ByteArrayInputStream( + CertPathTest.rootCrlBin)); + X509CRL interCrl = (X509CRL)cf + .generateCRL(new ByteArrayInputStream( + CertPathTest.interCrlBin)); + + list = new ArrayList(); + list.add(finalCert); + list.add(rootCrl); + list.add(interCrl); + + ccsp = new CollectionCertStoreParameters(list); + store = CertStore.getInstance("Collection", ccsp, "BC"); + + Iterator crls = store.getCRLs(null).iterator(); + + if (!crls.next().equals(rootCrl)) + { + fail("root crl ordering wrong"); + } + if (!crls.next().equals(interCrl)) + { + fail("mid crl ordering wrong"); + } + + list = new ArrayList(); + list.add(finalCert); + list.add(interCrl); + list.add(rootCrl); + ccsp = new CollectionCertStoreParameters(list); + store = CertStore.getInstance("Collection", ccsp, "BC"); + + crls = store.getCRLs(null).iterator(); + + if (!crls.next().equals(interCrl)) + { + fail("reverse mid crl ordering wrong"); + } + if (!crls.next().equals(rootCrl)) + { + fail("reverse root crl ordering wrong"); + } + } + + public String getName() + { + return "CertStore"; + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new CertStoreTest()); + } + +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertTest.java new file mode 100644 index 000000000..1995862b7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertTest.java @@ -0,0 +1,1855 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.BufferedInputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.UnsupportedEncodingException; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.CRL; +import java.security.cert.CRLException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.cms.CMSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.cms.ContentInfo; +import com.fr.third.org.bouncycastle.asn1.cms.SignedData; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPublicKey; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.io.Streams; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +public class CertTest + extends SimpleTest +{ + // + // server.crt + // + byte[] cert1 = Base64.decode( + "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx" + + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY" + + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB" + + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ" + + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2" + + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW" + + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM" + + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l" + + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv" + + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re" + + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO" + + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE" + + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy" + + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0" + + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw" + + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL" + + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4" + + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF" + + "5/8="); + + // + // ca.crt + // + byte[] cert2 = Base64.decode( + "MIIDbDCCAtWgAwIBAgIBADANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx" + + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY" + + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB" + + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ" + + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU1MzNaFw0wMTA2" + + "MDIwNzU1MzNaMIG3MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW" + + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM" + + "dGQxHjAcBgNVBAsTFUNlcnRpZmljYXRlIEF1dGhvcml0eTEVMBMGA1UEAxMMQ29u" + + "bmVjdCA0IENBMSgwJgYJKoZIhvcNAQkBFhl3ZWJtYXN0ZXJAY29ubmVjdDQuY29t" + + "LmF1MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDgs5ptNG6Qv1ZpCDuUNGmv" + + "rhjqMDPd3ri8JzZNRiiFlBA4e6/ReaO1U8ASewDeQMH6i9R6degFdQRLngbuJP0s" + + "xcEE+SksEWNvygfzLwV9J/q+TQDyJYK52utb++lS0b48A1KPLwEsyL6kOAgelbur" + + "ukwxowprKUIV7Knf1ajetQIDAQABo4GFMIGCMCQGA1UdEQQdMBuBGXdlYm1hc3Rl" + + "ckBjb25uZWN0NC5jb20uYXUwDwYDVR0TBAgwBgEB/wIBADA2BglghkgBhvhCAQ0E" + + "KRYnbW9kX3NzbCBnZW5lcmF0ZWQgY3VzdG9tIENBIGNlcnRpZmljYXRlMBEGCWCG" + + "SAGG+EIBAQQEAwICBDANBgkqhkiG9w0BAQQFAAOBgQCsGvfdghH8pPhlwm1r3pQk" + + "msnLAVIBb01EhbXm2861iXZfWqGQjrGAaA0ZpXNk9oo110yxoqEoSJSzniZa7Xtz" + + "soTwNUpE0SLHvWf/SlKdFWlzXA+vOZbzEv4UmjeelekTm7lc01EEa5QRVzOxHFtQ" + + "DhkaJ8VqOMajkQFma2r9iA=="); + + // + // testx509.pem + // + byte[] cert3 = Base64.decode( + "MIIBWzCCAQYCARgwDQYJKoZIhvcNAQEEBQAwODELMAkGA1UEBhMCQVUxDDAKBgNV" + + "BAgTA1FMRDEbMBkGA1UEAxMSU1NMZWF5L3JzYSB0ZXN0IENBMB4XDTk1MDYxOTIz" + + "MzMxMloXDTk1MDcxNzIzMzMxMlowOjELMAkGA1UEBhMCQVUxDDAKBgNVBAgTA1FM" + + "RDEdMBsGA1UEAxMUU1NMZWF5L3JzYSB0ZXN0IGNlcnQwXDANBgkqhkiG9w0BAQEF" + + "AANLADBIAkEAqtt6qS5GTxVxGZYWa0/4u+IwHf7p2LNZbcPBp9/OfIcYAXBQn8hO" + + "/Re1uwLKXdCjIoaGs4DLdG88rkzfyK5dPQIDAQABMAwGCCqGSIb3DQIFBQADQQAE" + + "Wc7EcF8po2/ZO6kNCwK/ICH6DobgLekA5lSLr5EvuioZniZp5lFzAw4+YzPQ7XKJ" + + "zl9HYIMxATFyqSiD9jsx"); + + // + // v3-cert1.pem + // + byte[] cert4 = Base64.decode( + "MIICjTCCAfigAwIBAgIEMaYgRzALBgkqhkiG9w0BAQQwRTELMAkGA1UEBhMCVVMx" + + "NjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFuZCBTcGFjZSBBZG1pbmlz" + + "dHJhdGlvbjAmFxE5NjA1MjgxMzQ5MDUrMDgwMBcROTgwNTI4MTM0OTA1KzA4MDAw" + + "ZzELMAkGA1UEBhMCVVMxNjA0BgNVBAoTLU5hdGlvbmFsIEFlcm9uYXV0aWNzIGFu" + + "ZCBTcGFjZSBBZG1pbmlzdHJhdGlvbjEgMAkGA1UEBRMCMTYwEwYDVQQDEwxTdGV2" + + "ZSBTY2hvY2gwWDALBgkqhkiG9w0BAQEDSQAwRgJBALrAwyYdgxmzNP/ts0Uyf6Bp" + + "miJYktU/w4NG67ULaN4B5CnEz7k57s9o3YY3LecETgQ5iQHmkwlYDTL2fTgVfw0C" + + "AQOjgaswgagwZAYDVR0ZAQH/BFowWDBWMFQxCzAJBgNVBAYTAlVTMTYwNAYDVQQK" + + "Ey1OYXRpb25hbCBBZXJvbmF1dGljcyBhbmQgU3BhY2UgQWRtaW5pc3RyYXRpb24x" + + "DTALBgNVBAMTBENSTDEwFwYDVR0BAQH/BA0wC4AJODMyOTcwODEwMBgGA1UdAgQR" + + "MA8ECTgzMjk3MDgyM4ACBSAwDQYDVR0KBAYwBAMCBkAwCwYJKoZIhvcNAQEEA4GB" + + "AH2y1VCEw/A4zaXzSYZJTTUi3uawbbFiS2yxHvgf28+8Js0OHXk1H1w2d6qOHH21" + + "X82tZXd/0JtG0g1T9usFFBDvYK8O0ebgz/P5ELJnBL2+atObEuJy1ZZ0pBDWINR3" + + "WkDNLCGiTkCKp0F5EWIrVDwh54NNevkCQRZita+z4IBO"); + + // + // v3-cert2.pem + // + byte[] cert5 = Base64.decode( + "MIICiTCCAfKgAwIBAgIEMeZfHzANBgkqhkiG9w0BAQQFADB9MQswCQYDVQQGEwJD" + + "YTEPMA0GA1UEBxMGTmVwZWFuMR4wHAYDVQQLExVObyBMaWFiaWxpdHkgQWNjZXB0" + + "ZWQxHzAdBgNVBAoTFkZvciBEZW1vIFB1cnBvc2VzIE9ubHkxHDAaBgNVBAMTE0Vu" + + "dHJ1c3QgRGVtbyBXZWIgQ0EwHhcNOTYwNzEyMTQyMDE1WhcNOTYxMDEyMTQyMDE1" + + "WjB0MSQwIgYJKoZIhvcNAQkBExVjb29rZUBpc3NsLmF0bC5ocC5jb20xCzAJBgNV" + + "BAYTAlVTMScwJQYDVQQLEx5IZXdsZXR0IFBhY2thcmQgQ29tcGFueSAoSVNTTCkx" + + "FjAUBgNVBAMTDVBhdWwgQS4gQ29va2UwXDANBgkqhkiG9w0BAQEFAANLADBIAkEA" + + "6ceSq9a9AU6g+zBwaL/yVmW1/9EE8s5you1mgjHnj0wAILuoB3L6rm6jmFRy7QZT" + + "G43IhVZdDua4e+5/n1ZslwIDAQABo2MwYTARBglghkgBhvhCAQEEBAMCB4AwTAYJ" + + "YIZIAYb4QgENBD8WPVRoaXMgY2VydGlmaWNhdGUgaXMgb25seSBpbnRlbmRlZCBm" + + "b3IgZGVtb25zdHJhdGlvbiBwdXJwb3Nlcy4wDQYJKoZIhvcNAQEEBQADgYEAi8qc" + + "F3zfFqy1sV8NhjwLVwOKuSfhR/Z8mbIEUeSTlnH3QbYt3HWZQ+vXI8mvtZoBc2Fz" + + "lexKeIkAZXCesqGbs6z6nCt16P6tmdfbZF3I3AWzLquPcOXjPf4HgstkyvVBn0Ap" + + "jAFN418KF/Cx4qyHB4cjdvLrRjjQLnb2+ibo7QU="); + + // + // pem encoded pkcs7 + // + byte[] cert6 = Base64.decode( + "MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIJbzCCAj0w" + + "ggGmAhEAzbp/VvDf5LxU/iKss3KqVTANBgkqhkiG9w0BAQIFADBfMQswCQYDVQQGEwJVUzEXMBUG" + + "A1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGljIFByaW1hcnkgQ2Vy" + + "dGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTYwMTI5MDAwMDAwWhcNMjgwODAxMjM1OTU5WjBfMQsw" + + "CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVi" + + "bGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwgZ8wDQYJKoZIhvcNAQEBBQADgY0A" + + "MIGJAoGBAOUZv22jVmEtmUhx9mfeuY3rt56GgAqRDvo4Ja9GiILlc6igmyRdDR/MZW4MsNBWhBiH" + + "mgabEKFz37RYOWtuwfYV1aioP6oSBo0xrH+wNNePNGeICc0UEeJORVZpH3gCgNrcR5EpuzbJY1zF" + + "4Ncth3uhtzKwezC6Ki8xqu6jZ9rbAgMBAAEwDQYJKoZIhvcNAQECBQADgYEATD+4i8Zo3+5DMw5d" + + "6abLB4RNejP/khv0Nq3YlSI2aBFsfELM85wuxAc/FLAPT/+Qknb54rxK6Y/NoIAK98Up8YIiXbix" + + "3YEjo3slFUYweRb46gVLlH8dwhzI47f0EEA8E8NfH1PoSOSGtHuhNbB7Jbq4046rPzidADQAmPPR" + + "cZQwggMuMIICl6ADAgECAhEA0nYujRQMPX2yqCVdr+4NdTANBgkqhkiG9w0BAQIFADBfMQswCQYD" + + "VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xNzA1BgNVBAsTLkNsYXNzIDEgUHVibGlj" + + "IFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNOTgwNTEyMDAwMDAwWhcNMDgwNTEy" + + "MjM1OTU5WjCBzDEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy" + + "dXN0IE5ldHdvcmsxRjBEBgNVBAsTPXd3dy52ZXJpc2lnbi5jb20vcmVwb3NpdG9yeS9SUEEgSW5j" + + "b3JwLiBCeSBSZWYuLExJQUIuTFREKGMpOTgxSDBGBgNVBAMTP1ZlcmlTaWduIENsYXNzIDEgQ0Eg" + + "SW5kaXZpZHVhbCBTdWJzY3JpYmVyLVBlcnNvbmEgTm90IFZhbGlkYXRlZDCBnzANBgkqhkiG9w0B" + + "AQEFAAOBjQAwgYkCgYEAu1pEigQWu1X9A3qKLZRPFXg2uA1Ksm+cVL+86HcqnbnwaLuV2TFBcHqB" + + "S7lIE1YtxwjhhEKrwKKSq0RcqkLwgg4C6S/7wju7vsknCl22sDZCM7VuVIhPh0q/Gdr5FegPh7Yc" + + "48zGmo5/aiSS4/zgZbqnsX7vyds3ashKyAkG5JkCAwEAAaN8MHowEQYJYIZIAYb4QgEBBAQDAgEG" + + "MEcGA1UdIARAMD4wPAYLYIZIAYb4RQEHAQEwLTArBggrBgEFBQcCARYfd3d3LnZlcmlzaWduLmNv" + + "bS9yZXBvc2l0b3J5L1JQQTAPBgNVHRMECDAGAQH/AgEAMAsGA1UdDwQEAwIBBjANBgkqhkiG9w0B" + + "AQIFAAOBgQCIuDc73dqUNwCtqp/hgQFxHpJqbS/28Z3TymQ43BuYDAeGW4UVag+5SYWklfEXfWe0" + + "fy0s3ZpCnsM+tI6q5QsG3vJWKvozx74Z11NMw73I4xe1pElCY+zCphcPXVgaSTyQXFWjZSAA/Rgg" + + "5V+CprGoksVYasGNAzzrw80FopCubjCCA/gwggNhoAMCAQICEBbbn/1G1zppD6KsP01bwywwDQYJ" + + "KoZIhvcNAQEEBQAwgcwxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2ln" + + "biBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3JlcG9zaXRvcnkvUlBB" + + "IEluY29ycC4gQnkgUmVmLixMSUFCLkxURChjKTk4MUgwRgYDVQQDEz9WZXJpU2lnbiBDbGFzcyAx" + + "IENBIEluZGl2aWR1YWwgU3Vic2NyaWJlci1QZXJzb25hIE5vdCBWYWxpZGF0ZWQwHhcNMDAxMDAy" + + "MDAwMDAwWhcNMDAxMjAxMjM1OTU5WjCCAQcxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYD" + + "VQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMUYwRAYDVQQLEz13d3cudmVyaXNpZ24uY29tL3Jl" + + "cG9zaXRvcnkvUlBBIEluY29ycC4gYnkgUmVmLixMSUFCLkxURChjKTk4MR4wHAYDVQQLExVQZXJz" + + "b25hIE5vdCBWYWxpZGF0ZWQxJzAlBgNVBAsTHkRpZ2l0YWwgSUQgQ2xhc3MgMSAtIE1pY3Jvc29m" + + "dDETMBEGA1UEAxQKRGF2aWQgUnlhbjElMCMGCSqGSIb3DQEJARYWZGF2aWRAbGl2ZW1lZGlhLmNv" + + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqxBsdeNmSvFqhMNwhQgNzM8mdjX9eSXb" + + "DawpHtQHjmh0AKJSa3IwUY0VIsyZHuXWktO/CgaMBVPt6OVf/n0R2sQigMP6Y+PhEiS0vCJBL9aK" + + "0+pOo2qXrjVBmq+XuCyPTnc+BOSrU26tJsX0P9BYorwySiEGxGanBNATdVL4NdUCAwEAAaOBnDCB" + + "mTAJBgNVHRMEAjAAMEQGA1UdIAQ9MDswOQYLYIZIAYb4RQEHAQgwKjAoBggrBgEFBQcCARYcaHR0" + + "cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYTARBglghkgBhvhCAQEEBAMCB4AwMwYDVR0fBCwwKjAo" + + "oCagJIYiaHR0cDovL2NybC52ZXJpc2lnbi5jb20vY2xhc3MxLmNybDANBgkqhkiG9w0BAQQFAAOB" + + "gQBC8yIIdVGpFTf8/YiL14cMzcmL0nIRm4kGR3U59z7UtcXlfNXXJ8MyaeI/BnXwG/gD5OKYqW6R" + + "yca9vZOxf1uoTBl82gInk865ED3Tej6msCqFzZffnSUQvOIeqLxxDlqYRQ6PmW2nAnZeyjcnbI5Y" + + "syQSM2fmo7n6qJFP+GbFezGCAkUwggJBAgEBMIHhMIHMMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5j" + + "LjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29yazFGMEQGA1UECxM9d3d3LnZlcmlzaWdu" + + "LmNvbS9yZXBvc2l0b3J5L1JQQSBJbmNvcnAuIEJ5IFJlZi4sTElBQi5MVEQoYyk5ODFIMEYGA1UE" + + "AxM/VmVyaVNpZ24gQ2xhc3MgMSBDQSBJbmRpdmlkdWFsIFN1YnNjcmliZXItUGVyc29uYSBOb3Qg" + + "VmFsaWRhdGVkAhAW25/9Rtc6aQ+irD9NW8MsMAkGBSsOAwIaBQCggbowGAYJKoZIhvcNAQkDMQsG" + + "CSqGSIb3DQEHATAcBgkqhkiG9w0BCQUxDxcNMDAxMDAyMTczNTE4WjAjBgkqhkiG9w0BCQQxFgQU" + + "gZjSaBEY2oxGvlQUIMnxSXhivK8wWwYJKoZIhvcNAQkPMU4wTDAKBggqhkiG9w0DBzAOBggqhkiG" + + "9w0DAgICAIAwDQYIKoZIhvcNAwICAUAwBwYFKw4DAgcwDQYIKoZIhvcNAwICASgwBwYFKw4DAh0w" + + "DQYJKoZIhvcNAQEBBQAEgYAzk+PU91/ZFfoiuKOECjxEh9fDYE2jfDCheBIgh5gdcCo+sS1WQs8O" + + "HreQ9Nop/JdJv1DQMBK6weNBBDoP0EEkRm1XCC144XhXZC82jBZohYmi2WvDbbC//YN58kRMYMyy" + + "srrfn4Z9I+6kTriGXkrpGk9Q0LSGjmG2BIsqiF0dvwAAAAAAAA=="); + + // + // dsaWithSHA1 cert + // + byte[] cert7 = Base64.decode( + "MIIEXAYJKoZIhvcNAQcCoIIETTCCBEkCAQExCzAJBgUrDgMCGgUAMAsGCSqG" + + "SIb3DQEHAaCCAsMwggK/MIIB4AIBADCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7" + + "d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULjw3GobwaJX13kquPh" + + "fVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABj" + + "TUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/z" + + "m8Q12PFp/PjOhh+nMA4xDDAKBgNVBAMTA0lEMzAeFw05NzEwMDEwMDAwMDBa" + + "Fw0zODAxMDEwMDAwMDBaMA4xDDAKBgNVBAMTA0lEMzCB8DCBpwYFKw4DAhsw" + + "gZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61TX5k+7NU4XPf1TULj" + + "w3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BUj+pJOF9ROBM4u+FE" + + "WA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqjijUHfXKTrHL1OEqV3" + + "SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nA0QAAkEAkYkXLYMtGVGWj9OnzjPn" + + "sB9sefSRPrVegZJCZbpW+Iv0/1RP1u04pHG9vtRpIQLjzUiWvLMU9EKQTThc" + + "eNMmWDCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxg" + + "Y61TX5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/Q" + + "F4BUj+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jH" + + "SqjijUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nAy8AMCwC" + + "FBY3dBSdeprGcqpr6wr3xbG+6WW+AhRMm/facKJNxkT3iKgJbp7R8Xd3QTGC" + + "AWEwggFdAgEBMBMwDjEMMAoGA1UEAxMDSUQzAgEAMAkGBSsOAwIaBQCgXTAY" + + "BgkqhkiG9w0BCQMxCwYJKoZIhvcNAQcBMBwGCSqGSIb3DQEJBTEPFw0wMjA1" + + "MjQyMzEzMDdaMCMGCSqGSIb3DQEJBDEWBBS4WMsoJhf7CVbZYCFcjoTRzPkJ" + + "xjCBpwYFKw4DAhswgZ0CQQEkJRHP+mN7d8miwTMN55CUSmo3TO8WGCxgY61T" + + "X5k+7NU4XPf1TULjw3GobwaJX13kquPhfVXk+gVy46n4Iw3hAhUBSe/QF4BU" + + "j+pJOF9ROBM4u+FEWA8CQQD4mSJbrABjTUWrlnAte8pS22Tq4/FPO7jHSqji" + + "jUHfXKTrHL1OEqV3SVWcFy5j/cqBgX/zm8Q12PFp/PjOhh+nBC8wLQIVALID" + + "dt+MHwawrDrwsO1Z6sXBaaJsAhRaKssrpevmLkbygKPV07XiAKBG02Zvb2Jh" + + "cg=="); + + // + // testcrl.pem + // + byte[] crl1 = Base64.decode( + "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT" + + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy" + + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw" + + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw" + + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw" + + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw" + + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw" + + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw" + + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw" + + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw" + + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF" + + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ" + + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt" + + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v"); + + // + // ecdsa cert with extra octet string. + // + byte[] oldEcdsa = Base64.decode( + "MIICljCCAkCgAwIBAgIBATALBgcqhkjOPQQBBQAwgY8xCzAJBgNVBAYTAkFVMSgwJ" + + "gYDVQQKEx9UaGUgTGVnaW9uIG9mIHRoZSBCb3VuY3kgQ2FzdGxlMRIwEAYDVQQHEw" + + "lNZWxib3VybmUxETAPBgNVBAgTCFZpY3RvcmlhMS8wLQYJKoZIhvcNAQkBFiBmZWV" + + "kYmFjay1jcnlwdG9AYm91bmN5Y2FzdGxlLm9yZzAeFw0wMTEyMDcwMTAwMDRaFw0w" + + "MTEyMDcwMTAxNDRaMIGPMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhlIExlZ2lvb" + + "iBvZiB0aGUgQm91bmN5IENhc3RsZTESMBAGA1UEBxMJTWVsYm91cm5lMREwDwYDVQ" + + "QIEwhWaWN0b3JpYTEvMC0GCSqGSIb3DQEJARYgZmVlZGJhY2stY3J5cHRvQGJvdW5" + + "jeWNhc3RsZS5vcmcwgeQwgb0GByqGSM49AgEwgbECAQEwKQYHKoZIzj0BAQIef///" + + "////////////f///////gAAAAAAAf///////MEAEHn///////////////3///////" + + "4AAAAAAAH///////AQeawFsO9zxiUHQ1lSSFHXKcanbL7J9HTd5YYXClCwKBB8CD/" + + "qWPNyogWzMM7hkK+35BcPTWFc9Pyf7vTs8uaqvAh5///////////////9///+eXpq" + + "fXZBx+9FSJoiQnQsDIgAEHwJbbcU7xholSP+w9nFHLebJUhqdLSU05lq/y9X+DHAw" + + "CwYHKoZIzj0EAQUAA0MAMEACHnz6t4UNoVROp74ma4XNDjjGcjaqiIWPZLK8Bdw3G" + + "QIeLZ4j3a6ividZl344UH+UPUE7xJxlYGuy7ejTsqRR"); + + byte[] uncompressedPtEC = Base64.decode( + "MIIDKzCCAsGgAwIBAgICA+kwCwYHKoZIzj0EAQUAMGYxCzAJBgNVBAYTAkpQ" + + "MRUwEwYDVQQKEwxuaXRlY2guYWMuanAxDjAMBgNVBAsTBWFpbGFiMQ8wDQYD" + + "VQQDEwZ0ZXN0Y2ExHzAdBgkqhkiG9w0BCQEWEHRlc3RjYUBsb2NhbGhvc3Qw" + + "HhcNMDExMDEzMTE1MzE3WhcNMjAxMjEyMTE1MzE3WjBmMQswCQYDVQQGEwJK" + + "UDEVMBMGA1UEChMMbml0ZWNoLmFjLmpwMQ4wDAYDVQQLEwVhaWxhYjEPMA0G" + + "A1UEAxMGdGVzdGNhMR8wHQYJKoZIhvcNAQkBFhB0ZXN0Y2FAbG9jYWxob3N0" + + "MIIBczCCARsGByqGSM49AgEwggEOAgEBMDMGByqGSM49AQECKEdYWnajFmnZ" + + "tzrukK2XWdle2v+GsD9l1ZiR6g7ozQDbhFH/bBiMDQcwVAQoJ5EQKrI54/CT" + + "xOQ2pMsd/fsXD+EX8YREd8bKHWiLz8lIVdD5cBNeVwQoMKSc6HfI7vKZp8Q2" + + "zWgIFOarx1GQoWJbMcSt188xsl30ncJuJT2OoARRBAqJ4fD+q6hbqgNSjTQ7" + + "htle1KO3eiaZgcJ8rrnyN8P+5A8+5K+H9aQ/NbBR4Gs7yto5PXIUZEUgodHA" + + "TZMSAcSq5ZYt4KbnSYaLY0TtH9CqAigEwZ+hglbT21B7ZTzYX2xj0x+qooJD" + + "hVTLtIPaYJK2HrMPxTw6/zfrAgEPA1IABAnvfFcFDgD/JicwBGn6vR3N8MIn" + + "mptZf/mnJ1y649uCF60zOgdwIyI7pVSxBFsJ7ohqXEHW0x7LrGVkdSEiipiH" + + "LYslqh3xrqbAgPbl93GUo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB" + + "/wQEAwIBxjAdBgNVHQ4EFgQUAEo62Xm9H6DcsE0zUDTza4BRG90wCwYHKoZI" + + "zj0EAQUAA1cAMFQCKAQsCHHSNOqfJXLgt3bg5+k49hIBGVr/bfG0B9JU3rNt" + + "Ycl9Y2zfRPUCKAK2ccOQXByAWfsasDu8zKHxkZv7LVDTFjAIffz3HaCQeVhD" + + "z+fauEg="); + + byte[] keyUsage = Base64.decode( + "MIIE7TCCBFagAwIBAgIEOAOR7jANBgkqhkiG9w0BAQQFADCByTELMAkGA1UE" + + "BhMCVVMxFDASBgNVBAoTC0VudHJ1c3QubmV0MUgwRgYDVQQLFD93d3cuZW50" + + "cnVzdC5uZXQvQ2xpZW50X0NBX0luZm8vQ1BTIGluY29ycC4gYnkgcmVmLiBs" + + "aW1pdHMgbGlhYi4xJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExp" + + "bWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENsaWVudCBDZXJ0aWZpY2F0" + + "aW9uIEF1dGhvcml0eTAeFw05OTEwMTIxOTI0MzBaFw0xOTEwMTIxOTU0MzBa" + + "MIHJMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50cnVzdC5uZXQxSDBGBgNV" + + "BAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0FfSW5mby9DUFMgaW5jb3Jw" + + "LiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UECxMcKGMpIDE5OTkgRW50" + + "cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5uZXQgQ2xpZW50" + + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGdMA0GCSqGSIb3DQEBAQUAA4GL" + + "ADCBhwKBgQDIOpleMRffrCdvkHvkGf9FozTC28GoT/Bo6oT9n3V5z8GKUZSv" + + "x1cDR2SerYIbWtp/N3hHuzeYEpbOxhN979IMMFGpOZ5V+Pux5zDeg7K6PvHV" + + "iTs7hbqqdCz+PzFur5GVbgbUB01LLFZHGARS2g4Qk79jkJvh34zmAqTmT173" + + "iwIBA6OCAeAwggHcMBEGCWCGSAGG+EIBAQQEAwIABzCCASIGA1UdHwSCARkw" + + "ggEVMIHkoIHhoIHepIHbMIHYMQswCQYDVQQGEwJVUzEUMBIGA1UEChMLRW50" + + "cnVzdC5uZXQxSDBGBgNVBAsUP3d3dy5lbnRydXN0Lm5ldC9DbGllbnRfQ0Ff" + + "SW5mby9DUFMgaW5jb3JwLiBieSByZWYuIGxpbWl0cyBsaWFiLjElMCMGA1UE" + + "CxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50" + + "cnVzdC5uZXQgQ2xpZW50IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MQ0wCwYD" + + "VQQDEwRDUkwxMCygKqAohiZodHRwOi8vd3d3LmVudHJ1c3QubmV0L0NSTC9D" + + "bGllbnQxLmNybDArBgNVHRAEJDAigA8xOTk5MTAxMjE5MjQzMFqBDzIwMTkx" + + "MDEyMTkyNDMwWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUxPucKXuXzUyW" + + "/O5bs8qZdIuV6kwwHQYDVR0OBBYEFMT7nCl7l81MlvzuW7PKmXSLlepMMAwG" + + "A1UdEwQFMAMBAf8wGQYJKoZIhvZ9B0EABAwwChsEVjQuMAMCBJAwDQYJKoZI" + + "hvcNAQEEBQADgYEAP66K8ddmAwWePvrqHEa7pFuPeJoSSJn59DXeDDYHAmsQ" + + "OokUgZwxpnyyQbJq5wcBoUv5nyU7lsqZwz6hURzzwy5E97BnRqqS5TvaHBkU" + + "ODDV4qIxJS7x7EU47fgGWANzYrAQMY9Av2TgXD7FTx/aEkP/TOYGJqibGapE" + + "PHayXOw="); + + byte[] nameCert = Base64.decode( + "MIIEFjCCA3+gAwIBAgIEdS8BozANBgkqhkiG9w0BAQUFADBKMQswCQYDVQQGEwJE" + + "RTERMA8GA1UEChQIREFURVYgZUcxKDAMBgcCggYBCgcUEwExMBgGA1UEAxQRQ0Eg" + + "REFURVYgRDAzIDE6UE4wIhgPMjAwMTA1MTAxMDIyNDhaGA8yMDA0MDUwOTEwMjI0" + + "OFowgYQxCzAJBgNVBAYTAkRFMQ8wDQYDVQQIFAZCYXllcm4xEjAQBgNVBAcUCU7I" + + "dXJuYmVyZzERMA8GA1UEChQIREFURVYgZUcxHTAbBgNVBAUTFDAwMDAwMDAwMDA4" + + "OTU3NDM2MDAxMR4wHAYDVQQDFBVEaWV0bWFyIFNlbmdlbmxlaXRuZXIwgaEwDQYJ" + + "KoZIhvcNAQEBBQADgY8AMIGLAoGBAJLI/LJLKaHoMk8fBECW/od8u5erZi6jI8Ug" + + "C0a/LZyQUO/R20vWJs6GrClQtXB+AtfiBSnyZOSYzOdfDI8yEKPEv8qSuUPpOHps" + + "uNCFdLZF1vavVYGEEWs2+y+uuPmg8q1oPRyRmUZ+x9HrDvCXJraaDfTEd9olmB/Z" + + "AuC/PqpjAgUAwAAAAaOCAcYwggHCMAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUD" + + "AwdAADAxBgNVHSAEKjAoMCYGBSskCAEBMB0wGwYIKwYBBQUHAgEWD3d3dy56cy5k" + + "YXRldi5kZTApBgNVHREEIjAggR5kaWV0bWFyLnNlbmdlbmxlaXRuZXJAZGF0ZXYu" + + "ZGUwgYQGA1UdIwR9MHuhc6RxMG8xCzAJBgNVBAYTAkRFMT0wOwYDVQQKFDRSZWd1" + + "bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0aW9uIHVuZCBQb3N0" + + "MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjVSLUNBIDE6UE6CBACm8LkwDgYHAoIG" + + "AQoMAAQDAQEAMEcGA1UdHwRAMD4wPKAUoBKGEHd3dy5jcmwuZGF0ZXYuZGWiJKQi" + + "MCAxCzAJBgNVBAYTAkRFMREwDwYDVQQKFAhEQVRFViBlRzAWBgUrJAgDBAQNMAsT" + + "A0VVUgIBBQIBATAdBgNVHQ4EFgQUfv6xFP0xk7027folhy+ziZvBJiwwLAYIKwYB" + + "BQUHAQEEIDAeMBwGCCsGAQUFBzABhhB3d3cuZGlyLmRhdGV2LmRlMA0GCSqGSIb3" + + "DQEBBQUAA4GBAEOVX6uQxbgtKzdgbTi6YLffMftFr2mmNwch7qzpM5gxcynzgVkg" + + "pnQcDNlm5AIbS6pO8jTCLfCd5TZ5biQksBErqmesIl3QD+VqtB+RNghxectZ3VEs" + + "nCUtcE7tJ8O14qwCb3TxS9dvIUFiVi4DjbxX46TdcTbTaK8/qr6AIf+l"); + + byte[] probSelfSignedCert = Base64.decode( + "MIICxTCCAi6gAwIBAgIQAQAAAAAAAAAAAAAAAAAAATANBgkqhkiG9w0BAQUFADBF" + + "MScwJQYDVQQKEx4gRElSRUNUSU9OIEdFTkVSQUxFIERFUyBJTVBPVFMxGjAYBgNV" + + "BAMTESBBQyBNSU5FRkkgQiBURVNUMB4XDTA0MDUwNzEyMDAwMFoXDTE0MDUwNzEy" + + "MDAwMFowRTEnMCUGA1UEChMeIERJUkVDVElPTiBHRU5FUkFMRSBERVMgSU1QT1RT" + + "MRowGAYDVQQDExEgQUMgTUlORUZJIEIgVEVTVDCBnzANBgkqhkiG9w0BAQEFAAOB" + + "jQAwgYkCgYEAveoCUOAukZdcFCs2qJk76vSqEX0ZFzHqQ6faBPZWjwkgUNwZ6m6m" + + "qWvvyq1cuxhoDvpfC6NXILETawYc6MNwwxsOtVVIjuXlcF17NMejljJafbPximEt" + + "DQ4LcQeSp4K7FyFlIAMLyt3BQ77emGzU5fjFTvHSUNb3jblx0sV28c0CAwEAAaOB" + + "tTCBsjAfBgNVHSMEGDAWgBSEJ4bLbvEQY8cYMAFKPFD1/fFXlzAdBgNVHQ4EFgQU" + + "hCeGy27xEGPHGDABSjxQ9f3xV5cwDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIB" + + "AQQEAwIBBjA8BgNVHR8ENTAzMDGgL6AthitodHRwOi8vYWRvbmlzLnBrNy5jZXJ0" + + "cGx1cy5uZXQvZGdpLXRlc3QuY3JsMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN" + + "AQEFBQADgYEAmToHJWjd3+4zknfsP09H6uMbolHNGG0zTS2lrLKpzcmkQfjhQpT9" + + "LUTBvfs1jdjo9fGmQLvOG+Sm51Rbjglb8bcikVI5gLbclOlvqLkm77otjl4U4Z2/" + + "Y0vP14Aov3Sn3k+17EfReYUZI4liuB95ncobC4e8ZM++LjQcIM0s+Vs="); + + + byte[] gost34102001base = Base64.decode( + "MIIB1DCCAYECEEjpVKXP6Wn1yVz3VeeDQa8wCgYGKoUDAgIDBQAwbTEfMB0G" + + "A1UEAwwWR29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRv" + + "UHJvMQswCQYDVQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIw" + + "MDFAZXhhbXBsZS5jb20wHhcNMDUwMjAzMTUxNjQ2WhcNMTUwMjAzMTUxNjQ2" + + "WjBtMR8wHQYDVQQDDBZHb3N0UjM0MTAtMjAwMSBleGFtcGxlMRIwEAYDVQQK" + + "DAlDcnlwdG9Qcm8xCzAJBgNVBAYTAlJVMSkwJwYJKoZIhvcNAQkBFhpHb3N0" + + "UjM0MTAtMjAwMUBleGFtcGxlLmNvbTBjMBwGBiqFAwICEzASBgcqhQMCAiQA" + + "BgcqhQMCAh4BA0MABECElWh1YAIaQHUIzROMMYks/eUFA3pDXPRtKw/nTzJ+" + + "V4/rzBa5lYgD0Jp8ha4P5I3qprt+VsfLsN8PZrzK6hpgMAoGBiqFAwICAwUA" + + "A0EAHw5dw/aw/OiNvHyOE65kvyo4Hp0sfz3csM6UUkp10VO247ofNJK3tsLb" + + "HOLjUaqzefrlGb11WpHYrvWFg+FcLA=="); + + byte[] gost341094base = Base64.decode( + "MIICDzCCAbwCEBcxKsIb0ghYvAQeUjfQdFAwCgYGKoUDAgIEBQAwaTEdMBsG" + + "A1UEAwwUR29zdFIzNDEwLTk0IGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1By" + + "bzELMAkGA1UEBhMCUlUxJzAlBgkqhkiG9w0BCQEWGEdvc3RSMzQxMC05NEBl" + + "eGFtcGxlLmNvbTAeFw0wNTAyMDMxNTE2NTFaFw0xNTAyMDMxNTE2NTFaMGkx" + + "HTAbBgNVBAMMFEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlw" + + "dG9Qcm8xCzAJBgNVBAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAt" + + "OTRAZXhhbXBsZS5jb20wgaUwHAYGKoUDAgIUMBIGByqFAwICIAIGByqFAwIC" + + "HgEDgYQABIGAu4Rm4XmeWzTYLIB/E6gZZnFX/oxUJSFHbzALJ3dGmMb7R1W+" + + "t7Lzk2w5tUI3JoTiDRCKJA4fDEJNKzsRK6i/ZjkyXJSLwaj+G2MS9gklh8x1" + + "G/TliYoJgmjTXHemD7aQEBON4z58nJHWrA0ILD54wbXCtrcaqCqLRYGTMjJ2" + + "+nswCgYGKoUDAgIEBQADQQBxKNhOmjgz/i5CEgLOyKyz9pFGkDcaymsWYQWV" + + "v7CZ0pTM8IzMzkUBW3GHsUjCFpanFZDfg2zuN+3kT+694n9B"); + + byte[] gost341094A = Base64.decode( + "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOZGVmYXVsdDM0MTAtOTQx" + + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1vbGExDDAKBgNVBAgT" + + "A01FTDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx" + + "MzExNTdaFw0wNjAzMjkxMzExNTdaMIGBMRcwFQYDVQQDEw5kZWZhdWx0MzQxMC05NDENMAsGA1UE" + + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLW9sYTEMMAoGA1UECBMDTUVMMQsw" + + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq" + + "hQMCAiACBgcqhQMCAh4BA4GEAASBgIQACDLEuxSdRDGgdZxHmy30g/DUYkRxO9Mi/uSHX5NjvZ31" + + "b7JMEMFqBtyhql1HC5xZfUwZ0aT3UnEFDfFjLP+Bf54gA+LPkQXw4SNNGOj+klnqgKlPvoqMGlwa" + + "+hLPKbS561WpvB2XSTgbV+pqqXR3j6j30STmybelEV3RdS2Now8wDTALBgNVHQ8EBAMCB4AwCgYG" + + "KoUDAgIEBQADQQBCFy7xWRXtNVXflKvDs0pBdBuPzjCMeZAXVxK8vUxsxxKu76d9CsvhgIFknFRi" + + "wWTPiZenvNoJ4R1uzeX+vREm"); + + byte[] gost341094B = Base64.decode( + "MIICSDCCAfWgAwIBAgIBATAKBgYqhQMCAgQFADCBgTEXMBUGA1UEAxMOcGFyYW0xLTM0MTAtOTQx" + + "DTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNVBAgT" + + "A01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAzMjkx" + + "MzEzNTZaFw0wNjAzMjkxMzEzNTZaMIGBMRcwFQYDVQQDEw5wYXJhbTEtMzQxMC05NDENMAsGA1UE" + + "ChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMDTWVsMQsw" + + "CQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MIGlMBwGBiqFAwICFDASBgcq" + + "hQMCAiADBgcqhQMCAh4BA4GEAASBgEa+AAcZmijWs1M9x5Pn9efE8D9ztG1NMoIt0/hNZNqln3+j" + + "lMZjyqPt+kTLIjtmvz9BRDmIDk6FZz+4LhG2OTL7yGpWfrMxMRr56nxomTN9aLWRqbyWmn3brz9Y" + + "AUD3ifnwjjIuW7UM84JNlDTOdxx0XRUfLQIPMCXe9cO02Xskow8wDTALBgNVHQ8EBAMCB4AwCgYG" + + "KoUDAgIEBQADQQBzFcnuYc/639OTW+L5Ecjw9KxGr+dwex7lsS9S1BUgKa3m1d5c+cqI0B2XUFi5" + + "4iaHHJG0dCyjtQYLJr0OZjRw"); + + byte[] gost34102001A = Base64.decode( + "MIICCzCCAbigAwIBAgIBATAKBgYqhQMCAgMFADCBhDEaMBgGA1UEAxMRZGVmYXVsdC0zNDEwLTIw" + + "MDExDTALBgNVBAoTBERpZ3QxDzANBgNVBAsTBkNyeXB0bzEOMAwGA1UEBxMFWS1PbGExDDAKBgNV" + + "BAgTA01lbDELMAkGA1UEBhMCcnUxGzAZBgkqhkiG9w0BCQEWDHRlc3RAdGVzdC5ydTAeFw0wNTAz" + + "MjkxMzE4MzFaFw0wNjAzMjkxMzE4MzFaMIGEMRowGAYDVQQDExFkZWZhdWx0LTM0MTAtMjAwMTEN" + + "MAsGA1UEChMERGlndDEPMA0GA1UECxMGQ3J5cHRvMQ4wDAYDVQQHEwVZLU9sYTEMMAoGA1UECBMD" + + "TWVsMQswCQYDVQQGEwJydTEbMBkGCSqGSIb3DQEJARYMdGVzdEB0ZXN0LnJ1MGMwHAYGKoUDAgIT" + + "MBIGByqFAwICIwEGByqFAwICHgEDQwAEQG/4c+ZWb10IpeHfmR+vKcbpmSOClJioYmCVgnojw0Xn" + + "ned0KTg7TJreRUc+VX7vca4hLQaZ1o/TxVtfEApK/O6jDzANMAsGA1UdDwQEAwIHgDAKBgYqhQMC" + + "AgMFAANBAN8y2b6HuIdkD3aWujpfQbS1VIA/7hro4vLgDhjgVmev/PLzFB8oTh3gKhExpDo82IEs" + + "ZftGNsbbyp1NFg7zda0="); + + byte[] gostCA1 = Base64.decode( + "MIIDNDCCAuGgAwIBAgIQZLcKDcWcQopF+jp4p9jylDAKBgYqhQMCAgQFADBm" + + "MQswCQYDVQQGEwJSVTEPMA0GA1UEBxMGTW9zY293MRcwFQYDVQQKEw5PT08g" + + "Q3J5cHRvLVBybzEUMBIGA1UECxMLRGV2ZWxvcG1lbnQxFzAVBgNVBAMTDkNQ" + + "IENTUCBUZXN0IENBMB4XDTAyMDYwOTE1NTIyM1oXDTA5MDYwOTE1NTkyOVow" + + "ZjELMAkGA1UEBhMCUlUxDzANBgNVBAcTBk1vc2NvdzEXMBUGA1UEChMOT09P" + + "IENyeXB0by1Qcm8xFDASBgNVBAsTC0RldmVsb3BtZW50MRcwFQYDVQQDEw5D" + + "UCBDU1AgVGVzdCBDQTCBpTAcBgYqhQMCAhQwEgYHKoUDAgIgAgYHKoUDAgIe" + + "AQOBhAAEgYAYglywKuz1nMc9UiBYOaulKy53jXnrqxZKbCCBSVaJ+aCKbsQm" + + "glhRFrw6Mwu8Cdeabo/ojmea7UDMZd0U2xhZFRti5EQ7OP6YpqD0alllo7za" + + "4dZNXdX+/ag6fOORSLFdMpVx5ganU0wHMPk67j+audnCPUj/plbeyccgcdcd" + + "WaOCASIwggEeMAsGA1UdDwQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud" + + "DgQWBBTe840gTo4zt2twHilw3PD9wJaX0TCBygYDVR0fBIHCMIG/MDygOqA4" + + "hjYtaHR0cDovL2ZpZXdhbGwvQ2VydEVucm9sbC9DUCUyMENTUCUyMFRlc3Ql" + + "MjBDQSgzKS5jcmwwRKBCoECGPmh0dHA6Ly93d3cuY3J5cHRvcHJvLnJ1L0Nl" + + "cnRFbnJvbGwvQ1AlMjBDU1AlMjBUZXN0JTIwQ0EoMykuY3JsMDmgN6A1hjMt" + + "ZmlsZTovL1xcZmlld2FsbFxDZXJ0RW5yb2xsXENQIENTUCBUZXN0IENBKDMp" + + "LmNybC8wEgYJKwYBBAGCNxUBBAUCAwMAAzAKBgYqhQMCAgQFAANBAIJi7ni7" + + "9rwMR5rRGTFftt2k70GbqyUEfkZYOzrgdOoKiB4IIsIstyBX0/ne6GsL9Xan" + + "G2IN96RB7KrowEHeW+k="); + + byte[] gostCA2 = Base64.decode( + "MIIC2DCCAoWgAwIBAgIQe9ZCugm42pRKNcHD8466zTAKBgYqhQMCAgMFADB+" + + "MRowGAYJKoZIhvcNAQkBFgtzYmFAZGlndC5ydTELMAkGA1UEBhMCUlUxDDAK" + + "BgNVBAgTA01FTDEUMBIGA1UEBxMLWW9zaGthci1PbGExDTALBgNVBAoTBERp" + + "Z3QxDzANBgNVBAsTBkNyeXB0bzEPMA0GA1UEAxMGc2JhLUNBMB4XDTA0MDgw" + + "MzEzMzE1OVoXDTE0MDgwMzEzNDAxMVowfjEaMBgGCSqGSIb3DQEJARYLc2Jh" + + "QGRpZ3QucnUxCzAJBgNVBAYTAlJVMQwwCgYDVQQIEwNNRUwxFDASBgNVBAcT" + + "C1lvc2hrYXItT2xhMQ0wCwYDVQQKEwREaWd0MQ8wDQYDVQQLEwZDcnlwdG8x" + + "DzANBgNVBAMTBnNiYS1DQTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMC" + + "Ah4BA0MABEDMSy10CuOH+i8QKG2UWA4XmCt6+BFrNTZQtS6bOalyDY8Lz+G7" + + "HybyipE3PqdTB4OIKAAPsEEeZOCZd2UXGQm5o4HaMIHXMBMGCSsGAQQBgjcU" + + "AgQGHgQAQwBBMAsGA1UdDwQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud" + + "DgQWBBRJJl3LcNMxkZI818STfoi3ng1xoDBxBgNVHR8EajBoMDGgL6Athito" + + "dHRwOi8vc2JhLmRpZ3QubG9jYWwvQ2VydEVucm9sbC9zYmEtQ0EuY3JsMDOg" + + "MaAvhi1maWxlOi8vXFxzYmEuZGlndC5sb2NhbFxDZXJ0RW5yb2xsXHNiYS1D" + + "QS5jcmwwEAYJKwYBBAGCNxUBBAMCAQAwCgYGKoUDAgIDBQADQQA+BRJHbc/p" + + "q8EYl6iJqXCuR+ozRmH7hPAP3c4KqYSC38TClCgBloLapx/3/WdatctFJW/L" + + "mcTovpq088927shE"); + + private final byte[] pkcs7CrlProblem = Base64.decode( + "MIIwSAYJKoZIhvcNAQcCoIIwOTCCMDUCAQExCzAJBgUrDgMCGgUAMAsGCSqG" + + "SIb3DQEHAaCCEsAwggP4MIIC4KADAgECAgF1MA0GCSqGSIb3DQEBBQUAMEUx" + + "CzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQD" + + "ExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUwHhcNMDQxMjAyMjEyNTM5WhcNMDYx" + + "MjMwMjEyNTM5WjBMMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMR2VvVHJ1c3Qg" + + "SW5jMSYwJAYDVQQDEx1HZW9UcnVzdCBBZG9iZSBPQ1NQIFJlc3BvbmRlcjCB" + + "nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4gnNYhtw7U6QeVXZODnGhHMj" + + "+OgZ0DB393rEk6a2q9kq129IA2e03yKBTfJfQR9aWKc2Qj90dsSqPjvTDHFG" + + "Qsagm2FQuhnA3fb1UWhPzeEIdm6bxDsnQ8nWqKqxnWZzELZbdp3I9bBLizIq" + + "obZovzt60LNMghn/unvvuhpeVSsCAwEAAaOCAW4wggFqMA4GA1UdDwEB/wQE" + + "AwIE8DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8BAgEwgcYwgZAGCCsG" + + "AQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMgYmVlbiBpc3N1ZWQg" + + "aW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENyZWRlbnRpYWxzIENQ" + + "UyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jlc291cmNl" + + "cy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2VvdHJ1c3QuY29tL3Jl" + + "c291cmNlcy9jcHMwEwYDVR0lBAwwCgYIKwYBBQUHAwkwOgYDVR0fBDMwMTAv" + + "oC2gK4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5j" + + "cmwwHwYDVR0jBBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwDQYJKoZIhvcN" + + "AQEFBQADggEBAENJf1BD7PX5ivuaawt90q1OGzXpIQL/ClzEeFVmOIxqPc1E" + + "TFRq92YuxG5b6+R+k+tGkmCwPLcY8ipg6ZcbJ/AirQhohzjlFuT6YAXsTfEj" + + "CqEZfWM2sS7crK2EYxCMmKE3xDfPclYtrAoz7qZvxfQj0TuxHSstHZv39wu2" + + "ZiG1BWiEcyDQyTgqTOXBoZmfJtshuAcXmTpgkrYSrS37zNlPTGh+pMYQ0yWD" + + "c8OQRJR4OY5ZXfdna01mjtJTOmj6/6XPoLPYTq2gQrc2BCeNJ4bEhLb7sFVB" + + "PbwPrpzTE/HRbQHDrzj0YimDxeOUV/UXctgvYwHNtEkcBLsOm/uytMYwggSh" + + "MIIDiaADAgECAgQ+HL0oMA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVT" + + "MSMwIQYDVQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UE" + + "CxMUQWRvYmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3Qg" + + "Q0EwHhcNMDMwMTA4MjMzNzIzWhcNMjMwMTA5MDAwNzIzWjBpMQswCQYDVQQG" + + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb" + + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS" + + "b290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAzE9UhPen" + + "ouczU38/nBKIayyZR2d+Dx65rRSI+cMQ2B3w8NWfaQovWTWwzGypTJwVoJ/O" + + "IL+gz1Ti4CBmRT85hjh+nMSOByLGJPYBErA131XqaZCw24U3HuJOB7JCoWoT" + + "aaBm6oCREVkqmwh5WiBELcm9cziLPC/gQxtdswvwrzUaKf7vppLdgUydPVmO" + + "rTE8QH6bkTYG/OJcjdGNJtVcRc+vZT+xqtJilvSoOOq6YEL09BxKNRXO+E4i" + + "Vg+VGMX4lp+f+7C3eCXpgGu91grwxnSUnfMPUNuad85LcIMjjaDKeCBEXDxU" + + "ZPHqojAZn+pMBk0GeEtekt8i0slns3rSAQIDAQABo4IBTzCCAUswEQYJYIZI" + + "AYb4QgEBBAQDAgAHMIGOBgNVHR8EgYYwgYMwgYCgfqB8pHoweDELMAkGA1UE" + + "BhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jwb3JhdGVkMR0w" + + "GwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UEAxMNQWRvYmUg" + + "Um9vdCBDQTENMAsGA1UEAxMEQ1JMMTArBgNVHRAEJDAigA8yMDAzMDEwODIz" + + "MzcyM1qBDzIwMjMwMTA5MDAwNzIzWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgw" + + "FoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFIK3OEqTqpsQ74C7" + + "2VTi8Q/7gJzeMAwGA1UdEwQFMAMBAf8wHQYJKoZIhvZ9B0EABBAwDhsIVjYu" + + "MDo0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4IBAQAy2p9DdcH6b8lv26sdNjc+" + + "vGEZNrcCPB0jWZhsnu5NhedUyCAfp9S74r8Ad30ka3AvXME6dkm10+AjhCpx" + + "aiLzwScpmBX2NZDkBEzDjbyfYRzn/SSM0URDjBa6m02l1DUvvBHOvfdRN42f" + + "kOQU8Rg/vulZEjX5M5LznuDVa5pxm5lLyHHD4bFhCcTl+pHwQjo3fTT5cujN" + + "qmIcIenV9IIQ43sFti1oVgt+fpIsb01yggztVnSynbmrLSsdEF/bJ3Vwj/0d" + + "1+ICoHnlHOX/r2RAUS2em0fbQqV8H8KmSLDXvpJpTaT2KVfFeBEY3IdRyhOy" + + "Yp1PKzK9MaXB+lKrBYjIMIIEyzCCA7OgAwIBAgIEPhy9tTANBgkqhkiG9w0B" + + "AQUFADBpMQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJ" + + "bmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYw" + + "FAYDVQQDEw1BZG9iZSBSb290IENBMB4XDTA0MDExNzAwMDMzOVoXDTE1MDEx" + + "NTA4MDAwMFowRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu" + + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTCCASIwDQYJKoZI" + + "hvcNAQEBBQADggEPADCCAQoCggEBAKfld+BkeFrnOYW8r9L1WygTDlTdSfrO" + + "YvWS/Z6Ye5/l+HrBbOHqQCXBcSeCpz7kB2WdKMh1FOE4e9JlmICsHerBLdWk" + + "emU+/PDb69zh8E0cLoDfxukF6oVPXj6WSThdSG7H9aXFzRr6S3XGCuvgl+Qw" + + "DTLiLYW+ONF6DXwt3TQQtKReJjOJZk46ZZ0BvMStKyBaeB6DKZsmiIo89qso" + + "13VDZINH2w1KvXg0ygDizoNtbvgAPFymwnsINS1klfQlcvn0x0RJm9bYQXK3" + + "5GNZAgL3M7Lqrld0jMfIUaWvuHCLyivytRuzq1dJ7E8rmidjDEk/G+27pf13" + + "fNZ7vR7M+IkCAwEAAaOCAZ0wggGZMBIGA1UdEwEB/wQIMAYBAf8CAQEwUAYD" + + "VR0gBEkwRzBFBgkqhkiG9y8BAgEwODA2BggrBgEFBQcCARYqaHR0cHM6Ly93" + + "d3cuYWRvYmUuY29tL21pc2MvcGtpL2Nkc19jcC5odG1sMBQGA1UdJQQNMAsG" + + "CSqGSIb3LwEBBTCBsgYDVR0fBIGqMIGnMCKgIKAehhxodHRwOi8vY3JsLmFk" + + "b2JlLmNvbS9jZHMuY3JsMIGAoH6gfKR6MHgxCzAJBgNVBAYTAlVTMSMwIQYD" + + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv" + + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0ExDTAL" + + "BgNVBAMTBENSTDEwCwYDVR0PBAQDAgEGMB8GA1UdIwQYMBaAFIK3OEqTqpsQ" + + "74C72VTi8Q/7gJzeMB0GA1UdDgQWBBSrgFnDZYNtHX0TvRnD7BqPDUdqozAZ" + + "BgkqhkiG9n0HQQAEDDAKGwRWNi4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEA" + + "PzlZLqIAjrFeEWEs0uC29YyJhkXOE9mf3YSaFGsITF+Gl1j0pajTjyH4R35Q" + + "r3floW2q3HfNzTeZ90Jnr1DhVERD6zEMgJpCtJqVuk0sixuXJHghS/KicKf4" + + "YXJJPx9epuIRF1siBRnznnF90svmOJMXApc0jGnYn3nQfk4kaShSnDaYaeYR" + + "DJKcsiWhl6S5zfwS7Gg8hDeyckhMQKKWnlG1CQrwlSFisKCduoodwRtWgft8" + + "kx13iyKK3sbalm6vnVc+5nufS4vI+TwMXoV63NqYaSroafBWk0nL53zGXPEy" + + "+A69QhzEViJKn2Wgqt5gt++jMMNImbRObIqgfgF1VjCCBUwwggQ0oAMCAQIC" + + "AgGDMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1H" + + "ZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUw" + + "HhcNMDYwMzI0MTU0MjI5WhcNMDkwNDA2MTQ0MjI5WjBzMQswCQYDVQQGEwJV" + + "UzELMAkGA1UECBMCTUExETAPBgNVBAoTCEdlb1RydXN0MR0wGwYDVQQDExRN" + + "YXJrZXRpbmcgRGVwYXJ0bWVudDElMCMGCSqGSIb3DQEJARYWbWFya2V0aW5n" + + "QGdlb3RydXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB" + + "ANmvajTO4XJvAU2nVcLmXeCnAQX7RZt+7+ML3InmqQ3LCGo1weop09zV069/" + + "1x/Nmieol7laEzeXxd2ghjGzwfXafqQEqHn6+vBCvqdNPoSi63fSWhnuDVWp" + + "KVDOYgxOonrXl+Cc43lu4zRSq+Pi5phhrjDWcH74a3/rdljUt4c4GFezFXfa" + + "w2oTzWkxj2cTSn0Szhpr17+p66UNt8uknlhmu4q44Speqql2HwmCEnpLYJrK" + + "W3fOq5D4qdsvsLR2EABLhrBezamLI3iGV8cRHOUTsbTMhWhv/lKfHAyf4XjA" + + "z9orzvPN5jthhIfICOFq/nStTgakyL4Ln+nFAB/SMPkCAwEAAaOCAhYwggIS" + + "MA4GA1UdDwEB/wQEAwIF4DCB5QYDVR0gAQH/BIHaMIHXMIHUBgkqhkiG9y8B" + + "AgEwgcYwgZAGCCsGAQUFBwICMIGDGoGAVGhpcyBjZXJ0aWZpY2F0ZSBoYXMg" + + "YmVlbiBpc3N1ZWQgaW4gYWNjb3JkYW5jZSB3aXRoIHRoZSBBY3JvYmF0IENy" + + "ZWRlbnRpYWxzIENQUyBsb2NhdGVkIGF0IGh0dHA6Ly93d3cuZ2VvdHJ1c3Qu" + + "Y29tL3Jlc291cmNlcy9jcHMwMQYIKwYBBQUHAgEWJWh0dHA6Ly93d3cuZ2Vv" + + "dHJ1c3QuY29tL3Jlc291cmNlcy9jcHMwOgYDVR0fBDMwMTAvoC2gK4YpaHR0" + + "cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9hZG9iZWNhMS5jcmwwHwYDVR0j" + + "BBgwFoAUq4BZw2WDbR19E70Zw+wajw1HaqMwRAYIKwYBBQUHAQEEODA2MDQG" + + "CCsGAQUFBzABhihodHRwOi8vYWRvYmUtb2NzcC5nZW90cnVzdC5jb20vcmVz" + + "cG9uZGVyMBQGA1UdJQQNMAsGCSqGSIb3LwEBBTA8BgoqhkiG9y8BAQkBBC4w" + + "LAIBAYYnaHR0cDovL2Fkb2JlLXRpbWVzdGFtcC5nZW90cnVzdC5jb20vdHNh" + + "MBMGCiqGSIb3LwEBCQIEBTADAgEBMAwGA1UdEwQFMAMCAQAwDQYJKoZIhvcN" + + "AQEFBQADggEBAAOhy6QxOo+i3h877fvDvTa0plGD2bIqK7wMdNqbMDoSWied" + + "FIcgcBOIm2wLxOjZBAVj/3lDq59q2rnVeNnfXM0/N0MHI9TumHRjU7WNk9e4" + + "+JfJ4M+c3anrWOG3NE5cICDVgles+UHjXetHWql/LlP04+K2ZOLb6LE2xGnI" + + "YyLW9REzCYNAVF+/WkYdmyceHtaBZdbyVAJq0NAJPsfgY1pWcBo31Mr1fpX9" + + "WrXNTYDCqMyxMImJTmN3iI68tkXlNrhweQoArKFqBysiBkXzG/sGKYY6tWKU" + + "pzjLc3vIp/LrXC5zilROes8BSvwu1w9qQrJNcGwo7O4uijoNtyYil1Exgh1Q" + + "MIIdTAIBATBLMEUxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJ" + + "bmMuMR4wHAYDVQQDExVHZW9UcnVzdCBDQSBmb3IgQWRvYmUCAgGDMAkGBSsO" + + "AwIaBQCgggxMMBgGCSqGSIb3DQEJAzELBgkqhkiG9w0BBwEwIwYJKoZIhvcN" + + "AQkEMRYEFP4R6qIdpQJzWyzrqO8X1ZfJOgChMIIMCQYJKoZIhvcvAQEIMYIL" + + "+jCCC/agggZ5MIIGdTCCA6gwggKQMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV" + + "BAYTAlVTMRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMR4wHAYDVQQDExVHZW9U" + + "cnVzdCBDQSBmb3IgQWRvYmUXDTA2MDQwNDE3NDAxMFoXDTA2MDQwNTE3NDAx" + + "MFowggIYMBMCAgC5Fw0wNTEwMTEyMDM2MzJaMBICAVsXDTA0MTEwNDE1MDk0" + + "MVowEwICALgXDTA1MTIxMjIyMzgzOFowEgIBWhcNMDQxMTA0MTUwOTMzWjAT" + + "AgIA5hcNMDUwODI3MDQwOTM4WjATAgIAtxcNMDYwMTE2MTc1NTEzWjATAgIA" + + "hhcNMDUxMjEyMjIzODU1WjATAgIAtRcNMDUwNzA2MTgzODQwWjATAgIA4BcN" + + "MDYwMzIwMDc0ODM0WjATAgIAgRcNMDUwODAyMjIzMTE1WjATAgIA3xcNMDUx" + + "MjEyMjIzNjUwWjASAgFKFw0wNDExMDQxNTA5MTZaMBICAUQXDTA0MTEwNDE1" + + "MDg1M1owEgIBQxcNMDQxMDAzMDEwMDQwWjASAgFsFw0wNDEyMDYxOTQ0MzFa" + + "MBMCAgEoFw0wNjAzMDkxMjA3MTJaMBMCAgEkFw0wNjAxMTYxNzU1MzRaMBIC" + + "AWcXDTA1MDMxODE3NTYxNFowEwICAVEXDTA2MDEzMTExMjcxMVowEgIBZBcN" + + "MDQxMTExMjI0ODQxWjATAgIA8RcNMDUwOTE2MTg0ODAxWjATAgIBThcNMDYw" + + "MjIxMjAxMDM2WjATAgIAwRcNMDUxMjEyMjIzODE2WjASAgFiFw0wNTAxMTAx" + + "NjE5MzRaMBICAWAXDTA1MDExMDE5MDAwNFowEwICAL4XDTA1MDUxNzE0NTYx" + + "MFowDQYJKoZIhvcNAQEFBQADggEBAEKhRMS3wVho1U3EvEQJZC8+JlUngmZQ" + + "A78KQbHPWNZWFlNvPuf/b0s7Lu16GfNHXh1QAW6Y5Hi1YtYZ3YOPyMd4Xugt" + + "gCdumbB6xtKsDyN5RvTht6ByXj+CYlYqsL7RX0izJZ6mJn4fjMkqzPKNOjb8" + + "kSn5T6rn93BjlATtCE8tPVOM8dnqGccRE0OV59+nDBXc90UMt5LdEbwaUOap" + + "snVB0oLcNm8d/HnlVH6RY5LnDjrT4vwfe/FApZtTecEWsllVUXDjSpwfcfD/" + + "476/lpGySB2otALqzImlA9R8Ok3hJ8dnF6hhQ5Oe6OJMnGYgdhkKbxsKkdib" + + "tTVl3qmH5QAwggLFMIIBrQIBATANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQG" + + "EwJVUzEjMCEGA1UEChMaQWRvYmUgU3lzdGVtcyBJbmNvcnBvcmF0ZWQxHTAb" + + "BgNVBAsTFEFkb2JlIFRydXN0IFNlcnZpY2VzMRYwFAYDVQQDEw1BZG9iZSBS" + + "b290IENBFw0wNjAxMjcxODMzMzFaFw0wNzAxMjcwMDAwMDBaMIHeMCMCBD4c" + + "vUAXDTAzMDEyMTIzNDY1NlowDDAKBgNVHRUEAwoBBDAjAgQ+HL1BFw0wMzAx" + + "MjEyMzQ3MjJaMAwwCgYDVR0VBAMKAQQwIwIEPhy9YhcNMDMwMTIxMjM0NzQy" + + "WjAMMAoGA1UdFQQDCgEEMCMCBD4cvWEXDTA0MDExNzAxMDg0OFowDDAKBgNV" + + "HRUEAwoBBDAjAgQ+HL2qFw0wNDAxMTcwMTA5MDVaMAwwCgYDVR0VBAMKAQQw" + + "IwIEPhy9qBcNMDQwMTE3MDEzOTI5WjAMMAoGA1UdFQQDCgEEoC8wLTAKBgNV" + + "HRQEAwIBDzAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jANBgkq" + + "hkiG9w0BAQUFAAOCAQEAwtXF9042wG39icUlsotn5tpE3oCusLb/hBpEONhx" + + "OdfEQOq0w5hf/vqaxkcf71etA+KpbEUeSVaHMHRPhx/CmPrO9odE139dJdbt" + + "9iqbrC9iZokFK3h/es5kg73xujLKd7C/u5ngJ4mwBtvhMLjFjF2vJhPKHL4C" + + "IgMwdaUAhrcNzy16v+mw/VGJy3Fvc6oCESW1K9tvFW58qZSNXrMlsuidgunM" + + "hPKG+z0SXVyCqL7pnqKiaGddcgujYGOSY4S938oVcfZeZQEODtSYGlzldojX" + + "C1U1hCK5+tHAH0Ox/WqRBIol5VCZQwJftf44oG8oviYq52aaqSejXwmfT6zb" + + "76GCBXUwggVxMIIFbQoBAKCCBWYwggViBgkrBgEFBQcwAQEEggVTMIIFTzCB" + + "taIWBBS+8EpykfXdl4h3z7m/NZfdkAQQERgPMjAwNjA0MDQyMDIwMTVaMGUw" + + "YzA7MAkGBSsOAwIaBQAEFEb4BuZYkbjBjOjT6VeA/00fBvQaBBT3fTSQniOp" + + "BbHBSkz4xridlX0bsAICAYOAABgPMjAwNjA0MDQyMDIwMTVaoBEYDzIwMDYw" + + "NDA1MDgyMDE1WqEjMCEwHwYJKwYBBQUHMAECBBIEEFqooq/R2WltD7TposkT" + + "BhMwDQYJKoZIhvcNAQEFBQADgYEAMig6lty4b0JDsT/oanfQG5x6jVKPACpp" + + "1UA9SJ0apJJa7LeIdDFmu5C2S/CYiKZm4A4P9cAu0YzgLHxE4r6Op+HfVlAG" + + "6bzUe1P/hi1KCJ8r8wxOZAktQFPSzs85RAZwkHMfB0lP2e/h666Oye+Zf8VH" + + "RaE+/xZ7aswE89HXoumgggQAMIID/DCCA/gwggLgoAMCAQICAXUwDQYJKoZI" + + "hvcNAQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IElu" + + "Yy4xHjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNDEyMDIy" + + "MTI1MzlaFw0wNjEyMzAyMTI1MzlaMEwxCzAJBgNVBAYTAlVTMRUwEwYDVQQK" + + "EwxHZW9UcnVzdCBJbmMxJjAkBgNVBAMTHUdlb1RydXN0IEFkb2JlIE9DU1Ag" + + "UmVzcG9uZGVyMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDiCc1iG3Dt" + + "TpB5Vdk4OcaEcyP46BnQMHf3esSTprar2SrXb0gDZ7TfIoFN8l9BH1pYpzZC" + + "P3R2xKo+O9MMcUZCxqCbYVC6GcDd9vVRaE/N4Qh2bpvEOydDydaoqrGdZnMQ" + + "tlt2ncj1sEuLMiqhtmi/O3rQs0yCGf+6e++6Gl5VKwIDAQABo4IBbjCCAWow" + + "DgYDVR0PAQH/BAQDAgTwMIHlBgNVHSABAf8EgdowgdcwgdQGCSqGSIb3LwEC" + + "ATCBxjCBkAYIKwYBBQUHAgIwgYMagYBUaGlzIGNlcnRpZmljYXRlIGhhcyBi" + + "ZWVuIGlzc3VlZCBpbiBhY2NvcmRhbmNlIHdpdGggdGhlIEFjcm9iYXQgQ3Jl" + + "ZGVudGlhbHMgQ1BTIGxvY2F0ZWQgYXQgaHR0cDovL3d3dy5nZW90cnVzdC5j" + + "b20vcmVzb3VyY2VzL2NwczAxBggrBgEFBQcCARYlaHR0cDovL3d3dy5nZW90" + + "cnVzdC5jb20vcmVzb3VyY2VzL2NwczATBgNVHSUEDDAKBggrBgEFBQcDCTA6" + + "BgNVHR8EMzAxMC+gLaArhilodHRwOi8vY3JsLmdlb3RydXN0LmNvbS9jcmxz" + + "L2Fkb2JlY2ExLmNybDAfBgNVHSMEGDAWgBSrgFnDZYNtHX0TvRnD7BqPDUdq" + + "ozANBgkqhkiG9w0BAQUFAAOCAQEAQ0l/UEPs9fmK+5prC33SrU4bNekhAv8K" + + "XMR4VWY4jGo9zURMVGr3Zi7Eblvr5H6T60aSYLA8txjyKmDplxsn8CKtCGiH" + + "OOUW5PpgBexN8SMKoRl9YzaxLtysrYRjEIyYoTfEN89yVi2sCjPupm/F9CPR" + + "O7EdKy0dm/f3C7ZmIbUFaIRzINDJOCpM5cGhmZ8m2yG4BxeZOmCSthKtLfvM" + + "2U9MaH6kxhDTJYNzw5BElHg5jlld92drTWaO0lM6aPr/pc+gs9hOraBCtzYE" + + "J40nhsSEtvuwVUE9vA+unNMT8dFtAcOvOPRiKYPF45RX9Rdy2C9jAc20SRwE" + + "uw6b+7K0xjANBgkqhkiG9w0BAQEFAASCAQC7a4yICFGCEMPlJbydK5qLG3rV" + + "sip7Ojjz9TB4nLhC2DgsIHds8jjdq2zguInluH2nLaBCVS+qxDVlTjgbI2cB" + + "TaWS8nglC7nNjzkKAsa8vThA8FZUVXTW0pb74jNJJU2AA27bb4g+4WgunCrj" + + "fpYp+QjDyMmdrJVqRmt5eQN+dpVxMS9oq+NrhOSEhyIb4/rejgNg9wnVK1ms" + + "l5PxQ4x7kpm7+Ua41//owkJVWykRo4T1jo4eHEz1DolPykAaKie2VKH/sMqR" + + "Spjh4E5biKJLOV9fKivZWKAXByXfwUbbMsJvz4v/2yVHFy9xP+tqB5ZbRoDK" + + "k8PzUyCprozn+/22oYIPijCCD4YGCyqGSIb3DQEJEAIOMYIPdTCCD3EGCSqG" + + "SIb3DQEHAqCCD2Iwgg9eAgEDMQswCQYFKw4DAhoFADCB+gYLKoZIhvcNAQkQ" + + "AQSggeoEgecwgeQCAQEGAikCMCEwCQYFKw4DAhoFAAQUoT97qeCv3FXYaEcS" + + "gY8patCaCA8CAiMHGA8yMDA2MDQwNDIwMjA1N1owAwIBPAEB/wIIO0yRre3L" + + "8/6ggZCkgY0wgYoxCzAJBgNVBAYTAlVTMRYwFAYDVQQIEw1NYXNzYWNodXNl" + + "dHRzMRAwDgYDVQQHEwdOZWVkaGFtMRUwEwYDVQQKEwxHZW9UcnVzdCBJbmMx" + + "EzARBgNVBAsTClByb2R1Y3Rpb24xJTAjBgNVBAMTHGFkb2JlLXRpbWVzdGFt" + + "cC5nZW90cnVzdC5jb22gggzJMIIDUTCCAjmgAwIBAgICAI8wDQYJKoZIhvcN" + + "AQEFBQAwRTELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4x" + + "HjAcBgNVBAMTFUdlb1RydXN0IENBIGZvciBBZG9iZTAeFw0wNTAxMTAwMTI5" + + "MTBaFw0xNTAxMTUwODAwMDBaMIGKMQswCQYDVQQGEwJVUzEWMBQGA1UECBMN" + + "TWFzc2FjaHVzZXR0czEQMA4GA1UEBxMHTmVlZGhhbTEVMBMGA1UEChMMR2Vv" + + "VHJ1c3QgSW5jMRMwEQYDVQQLEwpQcm9kdWN0aW9uMSUwIwYDVQQDExxhZG9i" + + "ZS10aW1lc3RhbXAuZ2VvdHJ1c3QuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GN" + + "ADCBiQKBgQDRbxJotLFPWQuuEDhKtOMaBUJepGxIvWxeahMbq1DVmqnk88+j" + + "w/5lfPICPzQZ1oHrcTLSAFM7Mrz3pyyQKQKMqUyiemzuG/77ESUNfBNSUfAF" + + "PdtHuDMU8Is8ABVnFk63L+wdlvvDIlKkE08+VTKCRdjmuBVltMpQ6QcLFQzm" + + "AQIDAQABo4GIMIGFMDoGA1UdHwQzMDEwL6AtoCuGKWh0dHA6Ly9jcmwuZ2Vv" + + "dHJ1c3QuY29tL2NybHMvYWRvYmVjYTEuY3JsMB8GA1UdIwQYMBaAFKuAWcNl" + + "g20dfRO9GcPsGo8NR2qjMA4GA1UdDwEB/wQEAwIGwDAWBgNVHSUBAf8EDDAK" + + "BggrBgEFBQcDCDANBgkqhkiG9w0BAQUFAAOCAQEAmnyXjdtX+F79Nf0KggTd" + + "6YC2MQD9s09IeXTd8TP3rBmizfM+7f3icggeCGakNfPRmIUMLoa0VM5Kt37T" + + "2X0TqzBWusfbKx7HnX4v1t/G8NJJlT4SShSHv+8bjjU4lUoCmW2oEcC5vXwP" + + "R5JfjCyois16npgcO05ZBT+LLDXyeBijE6qWmwLDfEpLyILzVRmyU4IE7jvm" + + "rgb3GXwDUvd3yQXGRRHbPCh3nj9hBGbuzyt7GnlqnEie3wzIyMG2ET/wvTX5" + + "4BFXKNe7lDLvZj/MXvd3V7gMTSVW0kAszKao56LfrVTgp1VX3UBQYwmQqaoA" + + "UwFezih+jEvjW6cYJo/ErDCCBKEwggOJoAMCAQICBD4cvSgwDQYJKoZIhvcN" + + "AQEFBQAwaTELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMg" + + "SW5jb3Jwb3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEW" + + "MBQGA1UEAxMNQWRvYmUgUm9vdCBDQTAeFw0wMzAxMDgyMzM3MjNaFw0yMzAx" + + "MDkwMDA3MjNaMGkxCzAJBgNVBAYTAlVTMSMwIQYDVQQKExpBZG9iZSBTeXN0" + + "ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRvYmUgVHJ1c3QgU2Vydmlj" + + "ZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUA" + + "A4IBDwAwggEKAoIBAQDMT1SE96ei5zNTfz+cEohrLJlHZ34PHrmtFIj5wxDY" + + "HfDw1Z9pCi9ZNbDMbKlMnBWgn84gv6DPVOLgIGZFPzmGOH6cxI4HIsYk9gES" + + "sDXfVeppkLDbhTce4k4HskKhahNpoGbqgJERWSqbCHlaIEQtyb1zOIs8L+BD" + + "G12zC/CvNRop/u+mkt2BTJ09WY6tMTxAfpuRNgb84lyN0Y0m1VxFz69lP7Gq" + + "0mKW9Kg46rpgQvT0HEo1Fc74TiJWD5UYxfiWn5/7sLd4JemAa73WCvDGdJSd" + + "8w9Q25p3zktwgyONoMp4IERcPFRk8eqiMBmf6kwGTQZ4S16S3yLSyWezetIB" + + "AgMBAAGjggFPMIIBSzARBglghkgBhvhCAQEEBAMCAAcwgY4GA1UdHwSBhjCB" + + "gzCBgKB+oHykejB4MQswCQYDVQQGEwJVUzEjMCEGA1UEChMaQWRvYmUgU3lz" + + "dGVtcyBJbmNvcnBvcmF0ZWQxHTAbBgNVBAsTFEFkb2JlIFRydXN0IFNlcnZp" + + "Y2VzMRYwFAYDVQQDEw1BZG9iZSBSb290IENBMQ0wCwYDVQQDEwRDUkwxMCsG" + + "A1UdEAQkMCKADzIwMDMwMTA4MjMzNzIzWoEPMjAyMzAxMDkwMDA3MjNaMAsG" + + "A1UdDwQEAwIBBjAfBgNVHSMEGDAWgBSCtzhKk6qbEO+Au9lU4vEP+4Cc3jAd" + + "BgNVHQ4EFgQUgrc4SpOqmxDvgLvZVOLxD/uAnN4wDAYDVR0TBAUwAwEB/zAd" + + "BgkqhkiG9n0HQQAEEDAOGwhWNi4wOjQuMAMCBJAwDQYJKoZIhvcNAQEFBQAD" + + "ggEBADLan0N1wfpvyW/bqx02Nz68YRk2twI8HSNZmGye7k2F51TIIB+n1Lvi" + + "vwB3fSRrcC9cwTp2SbXT4COEKnFqIvPBJymYFfY1kOQETMONvJ9hHOf9JIzR" + + "REOMFrqbTaXUNS+8Ec6991E3jZ+Q5BTxGD++6VkSNfkzkvOe4NVrmnGbmUvI" + + "ccPhsWEJxOX6kfBCOjd9NPly6M2qYhwh6dX0ghDjewW2LWhWC35+kixvTXKC" + + "DO1WdLKduastKx0QX9sndXCP/R3X4gKgeeUc5f+vZEBRLZ6bR9tCpXwfwqZI" + + "sNe+kmlNpPYpV8V4ERjch1HKE7JinU8rMr0xpcH6UqsFiMgwggTLMIIDs6AD" + + "AgECAgQ+HL21MA0GCSqGSIb3DQEBBQUAMGkxCzAJBgNVBAYTAlVTMSMwIQYD" + + "VQQKExpBZG9iZSBTeXN0ZW1zIEluY29ycG9yYXRlZDEdMBsGA1UECxMUQWRv" + + "YmUgVHJ1c3QgU2VydmljZXMxFjAUBgNVBAMTDUFkb2JlIFJvb3QgQ0EwHhcN" + + "MDQwMTE3MDAwMzM5WhcNMTUwMTE1MDgwMDAwWjBFMQswCQYDVQQGEwJVUzEW" + + "MBQGA1UEChMNR2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0Eg" + + "Zm9yIEFkb2JlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp+V3" + + "4GR4Wuc5hbyv0vVbKBMOVN1J+s5i9ZL9nph7n+X4esFs4epAJcFxJ4KnPuQH" + + "ZZ0oyHUU4Th70mWYgKwd6sEt1aR6ZT788Nvr3OHwTRwugN/G6QXqhU9ePpZJ" + + "OF1Ibsf1pcXNGvpLdcYK6+CX5DANMuIthb440XoNfC3dNBC0pF4mM4lmTjpl" + + "nQG8xK0rIFp4HoMpmyaIijz2qyjXdUNkg0fbDUq9eDTKAOLOg21u+AA8XKbC" + + "ewg1LWSV9CVy+fTHREmb1thBcrfkY1kCAvczsuquV3SMx8hRpa+4cIvKK/K1" + + "G7OrV0nsTyuaJ2MMST8b7bul/Xd81nu9Hsz4iQIDAQABo4IBnTCCAZkwEgYD" + + "VR0TAQH/BAgwBgEB/wIBATBQBgNVHSAESTBHMEUGCSqGSIb3LwECATA4MDYG" + + "CCsGAQUFBwIBFipodHRwczovL3d3dy5hZG9iZS5jb20vbWlzYy9wa2kvY2Rz" + + "X2NwLmh0bWwwFAYDVR0lBA0wCwYJKoZIhvcvAQEFMIGyBgNVHR8Egaowgacw" + + "IqAgoB6GHGh0dHA6Ly9jcmwuYWRvYmUuY29tL2Nkcy5jcmwwgYCgfqB8pHow" + + "eDELMAkGA1UEBhMCVVMxIzAhBgNVBAoTGkFkb2JlIFN5c3RlbXMgSW5jb3Jw" + + "b3JhdGVkMR0wGwYDVQQLExRBZG9iZSBUcnVzdCBTZXJ2aWNlczEWMBQGA1UE" + + "AxMNQWRvYmUgUm9vdCBDQTENMAsGA1UEAxMEQ1JMMTALBgNVHQ8EBAMCAQYw" + + "HwYDVR0jBBgwFoAUgrc4SpOqmxDvgLvZVOLxD/uAnN4wHQYDVR0OBBYEFKuA" + + "WcNlg20dfRO9GcPsGo8NR2qjMBkGCSqGSIb2fQdBAAQMMAobBFY2LjADAgSQ" + + "MA0GCSqGSIb3DQEBBQUAA4IBAQA/OVkuogCOsV4RYSzS4Lb1jImGRc4T2Z/d" + + "hJoUawhMX4aXWPSlqNOPIfhHflCvd+Whbarcd83NN5n3QmevUOFUREPrMQyA" + + "mkK0mpW6TSyLG5ckeCFL8qJwp/hhckk/H16m4hEXWyIFGfOecX3Sy+Y4kxcC" + + "lzSMadifedB+TiRpKFKcNphp5hEMkpyyJaGXpLnN/BLsaDyEN7JySExAopae" + + "UbUJCvCVIWKwoJ26ih3BG1aB+3yTHXeLIorextqWbq+dVz7me59Li8j5PAxe" + + "hXrc2phpKuhp8FaTScvnfMZc8TL4Dr1CHMRWIkqfZaCq3mC376Mww0iZtE5s" + + "iqB+AXVWMYIBgDCCAXwCAQEwSzBFMQswCQYDVQQGEwJVUzEWMBQGA1UEChMN" + + "R2VvVHJ1c3QgSW5jLjEeMBwGA1UEAxMVR2VvVHJ1c3QgQ0EgZm9yIEFkb2Jl" + + "AgIAjzAJBgUrDgMCGgUAoIGMMBoGCSqGSIb3DQEJAzENBgsqhkiG9w0BCRAB" + + "BDAcBgkqhkiG9w0BCQUxDxcNMDYwNDA0MjAyMDU3WjAjBgkqhkiG9w0BCQQx" + + "FgQUp7AnXBqoNcarvO7fMJut1og2U5AwKwYLKoZIhvcNAQkQAgwxHDAaMBgw" + + "FgQU1dH4eZTNhgxdiSABrat6zsPdth0wDQYJKoZIhvcNAQEBBQAEgYCinr/F" + + "rMiQz/MRm9ZD5YGcC0Qo2dRTPd0Aop8mZ4g1xAhKFLnp7lLsjCbkSDpVLDBh" + + "cnCk7CV+3FT5hlvt8OqZlR0CnkSnCswLFhrppiWle6cpxlwGqyAteC8uKtQu" + + "wjE5GtBKLcCOAzQYyyuNZZeB6oCZ+3mPhZ62FxrvvEGJCgAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" + + "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="); + + private final byte[] emptyDNCert = Base64.decode( + "MIICfTCCAeagAwIBAgIBajANBgkqhkiG9w0BAQQFADB8MQswCQYDVQQGEwJVUzEMMAoGA1UEChMD" + + "Q0RXMQkwBwYDVQQLEwAxCTAHBgNVBAcTADEJMAcGA1UECBMAMRowGAYDVQQDExFUZW1wbGFyIFRl" + + "c3QgMTAyNDEiMCAGCSqGSIb3DQEJARYTdGVtcGxhcnRlc3RAY2R3LmNvbTAeFw0wNjA1MjIwNTAw" + + "MDBaFw0xMDA1MjIwNTAwMDBaMHwxCzAJBgNVBAYTAlVTMQwwCgYDVQQKEwNDRFcxCTAHBgNVBAsT" + + "ADEJMAcGA1UEBxMAMQkwBwYDVQQIEwAxGjAYBgNVBAMTEVRlbXBsYXIgVGVzdCAxMDI0MSIwIAYJ" + + "KoZIhvcNAQkBFhN0ZW1wbGFydGVzdEBjZHcuY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKB" + + "gQDH3aJpJBfM+A3d84j5YcU6zEQaQ76u5xO9NSBmHjZykKS2kCcUqPpvVOPDA5WgV22dtKPh+lYV" + + "iUp7wyCVwAKibq8HIbihHceFqMKzjwC639rMoDJ7bi/yzQWz1Zg+075a4FGPlUKn7Yfu89wKkjdW" + + "wDpRPXc/agqBnrx5pJTXzQIDAQABow8wDTALBgNVHQ8EBAMCALEwDQYJKoZIhvcNAQEEBQADgYEA" + + "RRsRsjse3i2/KClFVd6YLZ+7K1BE0WxFyY2bbytkwQJSxvv3vLSuweFUbhNxutb68wl/yW4GLy4b" + + "1QdyswNxrNDXTuu5ILKhRDDuWeocz83aG2KGtr3JlFyr3biWGEyn5WUOE6tbONoQDJ0oPYgI6CAc" + + "EHdUp0lioOCt6UOw7Cs="); + + private final byte[] gostRFC4491_94 = Base64.decode( + "MIICCzCCAboCECMO42BGlSTOxwvklBgufuswCAYGKoUDAgIEMGkxHTAbBgNVBAMM" + + "FEdvc3RSMzQxMC05NCBleGFtcGxlMRIwEAYDVQQKDAlDcnlwdG9Qcm8xCzAJBgNV" + + "BAYTAlJVMScwJQYJKoZIhvcNAQkBFhhHb3N0UjM0MTAtOTRAZXhhbXBsZS5jb20w" + + "HhcNMDUwODE2MTIzMjUwWhcNMTUwODE2MTIzMjUwWjBpMR0wGwYDVQQDDBRHb3N0" + + "UjM0MTAtOTQgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYDVQQGEwJS" + + "VTEnMCUGCSqGSIb3DQEJARYYR29zdFIzNDEwLTk0QGV4YW1wbGUuY29tMIGlMBwG" + + "BiqFAwICFDASBgcqhQMCAiACBgcqhQMCAh4BA4GEAASBgLuEZuF5nls02CyAfxOo" + + "GWZxV/6MVCUhR28wCyd3RpjG+0dVvrey85NsObVCNyaE4g0QiiQOHwxCTSs7ESuo" + + "v2Y5MlyUi8Go/htjEvYJJYfMdRv05YmKCYJo01x3pg+2kBATjeM+fJyR1qwNCCw+" + + "eMG1wra3Gqgqi0WBkzIydvp7MAgGBiqFAwICBANBABHHCH4S3ALxAiMpR3aPRyqB" + + "g1DjB8zy5DEjiULIc+HeIveF81W9lOxGkZxnrFjXBSqnjLeFKgF1hffXOAP7zUM="); + + private final byte[] gostRFC4491_2001 = Base64.decode( + "MIIB0DCCAX8CECv1xh7CEb0Xx9zUYma0LiEwCAYGKoUDAgIDMG0xHzAdBgNVBAMM" + + "Fkdvc3RSMzQxMC0yMDAxIGV4YW1wbGUxEjAQBgNVBAoMCUNyeXB0b1BybzELMAkG" + + "A1UEBhMCUlUxKTAnBgkqhkiG9w0BCQEWGkdvc3RSMzQxMC0yMDAxQGV4YW1wbGUu" + + "Y29tMB4XDTA1MDgxNjE0MTgyMFoXDTE1MDgxNjE0MTgyMFowbTEfMB0GA1UEAwwW" + + "R29zdFIzNDEwLTIwMDEgZXhhbXBsZTESMBAGA1UECgwJQ3J5cHRvUHJvMQswCQYD" + + "VQQGEwJSVTEpMCcGCSqGSIb3DQEJARYaR29zdFIzNDEwLTIwMDFAZXhhbXBsZS5j" + + "b20wYzAcBgYqhQMCAhMwEgYHKoUDAgIkAAYHKoUDAgIeAQNDAARAhJVodWACGkB1" + + "CM0TjDGJLP3lBQN6Q1z0bSsP508yfleP68wWuZWIA9CafIWuD+SN6qa7flbHy7Df" + + "D2a8yuoaYDAIBgYqhQMCAgMDQQA8L8kJRLcnqeyn1en7U23Sw6pkfEQu3u0xFkVP" + + "vFQ/3cHeF26NG+xxtZPz3TaTVXdoiYkXYiD02rEx1bUcM97i"); + + private final byte[] uaczo1 = Base64.decode( + "MIIFWzCCBNegAwIBAgIUMAR1He8seK4BAAAAAQAAAAEAAAAwDQYLKoYkAgEBAQED" + + "AQEwgfoxPzA9BgNVBAoMNtCc0ZbQvdGW0YHRgtC10YDRgdGC0LLQviDRjtGB0YLQ" + + "uNGG0ZbRlyDQo9C60YDQsNGX0L3QuDExMC8GA1UECwwo0JDQtNC80ZbQvdGW0YHR" + + "gtGA0LDRgtC+0YAg0IbQotChINCm0JfQnjFJMEcGA1UEAwxA0KbQtdC90YLRgNCw" + + "0LvRjNC90LjQuSDQt9Cw0YHQstGW0LTRh9GD0LLQsNC70YzQvdC40Lkg0L7RgNCz" + + "0LDQvTEZMBcGA1UEBQwQVUEtMDAwMTU2MjItMjAxMjELMAkGA1UEBhMCVUExETAP" + + "BgNVBAcMCNCa0LjRl9CyMB4XDTEyMDkyODE5NTMwMFoXDTIyMDkyODE5NTMwMFow" + + "gfoxPzA9BgNVBAoMNtCc0ZbQvdGW0YHRgtC10YDRgdGC0LLQviDRjtGB0YLQuNGG" + + "0ZbRlyDQo9C60YDQsNGX0L3QuDExMC8GA1UECwwo0JDQtNC80ZbQvdGW0YHRgtGA" + + "0LDRgtC+0YAg0IbQotChINCm0JfQnjFJMEcGA1UEAwxA0KbQtdC90YLRgNCw0LvR" + + "jNC90LjQuSDQt9Cw0YHQstGW0LTRh9GD0LLQsNC70YzQvdC40Lkg0L7RgNCz0LDQ" + + "vTEZMBcGA1UEBQwQVUEtMDAwMTU2MjItMjAxMjELMAkGA1UEBhMCVUExETAPBgNV" + + "BAcMCNCa0LjRl9CyMIIBUTCCARIGCyqGJAIBAQEBAwEBMIIBATCBvDAPAgIBrzAJ" + + "AgEBAgEDAgEFAgEBBDbzykDGaaTaFzFJyhLDLa4Ya1Osa8Y2WZferq6K0tiI+b/V" + + "NAFpTvnEJz2M/m3Cj3BqD0kQzgMCNj//////////////////////////////////" + + "/7oxdUWACajApyTwL4Gqih/Lr4DZDHqVEQUEzwQ2fIV8lMVDO/2ZHhfCJoQGWFCp" + + "oknte8JJrlpOh4aJ+HLvetUkCC7DA46a7ee6a6Ezgdl5umIaBECp1utF8TxwgoDE" + + "lnsjH16t9ljrpMA3KR042WvwJcpOF/jpcg3GFbQ6KJdfC8Heo2Q4tWTqLBef0BI+" + + "bbj6xXkEAzkABDa2G/m9S2LKqyw5UPXFHV+oDXB+AHtSW3BnZ9zlzRuvbido2tDG" + + "qE/CL5kFHZE0NfTrHrGa1USjggE6MIIBNjApBgNVHQ4EIgQgMAR1He8seK4VC6vv" + + "vv8Nq9v4LOVonutO0xCl+xM4+wowKwYDVR0jBCQwIoAgMAR1He8seK4VC6vvvv8N" + + "q9v4LOVonutO0xCl+xM4+wowDgYDVR0PAQH/BAQDAgEGMBkGA1UdIAEB/wQPMA0w" + + "CwYJKoYkAgEBAQICMBIGA1UdEwEB/wQIMAYBAf8CAQIwHgYIKwYBBQUHAQMBAf8E" + + "DzANMAsGCSqGJAIBAQECATA9BgNVHR8ENjA0MDKgMKAuhixodHRwOi8vY3pvLmdv" + + "di51YS9kb3dubG9hZC9jcmxzL0NaTy1GdWxsLmNybDA+BgNVHS4ENzA1MDOgMaAv" + + "hi1odHRwOi8vY3pvLmdvdi51YS9kb3dubG9hZC9jcmxzL0NaTy1EZWx0YS5jcmww" + + "DQYLKoYkAgEBAQEDAQEDbwAEbPF4bx7drDxzzYABhB33Y0MQ+/N5FuPl7faVx/es" + + "V5n5DXg5TzZovzZeICB5JHPLcbdeCq6aGwvXsgybt34zqf7LKmfq0rFNYfXJVWFH" + + "4Tg5sPA+fCQ+T0O35VN873BLgTGz7bnHH9o8bnjwMA=="); + + private final byte[] uaczo2 = Base64.decode( + "MIIEvTCCBDmgAwIBAgIDAYhwMA0GCyqGJAIBAQEBAwEBMIIBHjELMAkGA1UEBhMC" + + "VUExKDAmBgNVBAgMH9Ca0LjRl9Cy0YHRjNC60LAg0L7QsdC70LDRgdGC0YwxETAP" + + "BgNVBAcMCNCa0LjRl9CyMUkwRwYDVQQKDEDQptC10L3RgtGA0LDQu9GM0L3QuNC5" + + "INC30LDRgdCy0ZbQtNGH0YPQstCw0LvRjNC90LjQuSDQvtGA0LPQsNC9MTUwMwYD" + + "VQQLDCzQotC10YXQvdC+0LvQvtCz0ZbRh9C90LjQuSDRhtC10L3RgtGAINCm0JfQ" + + "njE1MDMGA1UEAwws0KPQutGA0LDRl9C90LAsINCm0JfQniAvIFVrcmFpbmUsIENl" + + "bnRyYWwgQ0ExGTAXBgNVBAUTEFVBLTM3MjAwMzAzLTIwMTAwHhcNMDYxMjI1MDc0" + + "MDU4WhcNMTExMjI0MDc0MDU4WjCCAR4xCzAJBgNVBAYTAlVBMSgwJgYDVQQIDB/Q" + + "mtC40ZfQstGB0YzQutCwINC+0LHQu9Cw0YHRgtGMMREwDwYDVQQHDAjQmtC40ZfQ" + + "sjFJMEcGA1UECgxA0KbQtdC90YLRgNCw0LvRjNC90LjQuSDQt9Cw0YHQstGW0LTR" + + "h9GD0LLQsNC70YzQvdC40Lkg0L7RgNCz0LDQvTE1MDMGA1UECwws0KLQtdGF0L3Q" + + "vtC70L7Qs9GW0YfQvdC40Lkg0YbQtdC90YLRgCDQptCX0J4xNTAzBgNVBAMMLNCj" + + "0LrRgNCw0ZfQvdCwLCDQptCX0J4gLyBVa3JhaW5lLCBDZW50cmFsIENBMRkwFwYD" + + "VQQFExBVQS0zNzIwMDMwMy0yMDEwMIGdMGAGCyqGJAIBAQEBAwEBMFEGDSqGJAIB" + + "AQEBAwEBAgkEQKnW60XxPHCCgMSWeyMfXq32WOukwDcpHTjZa/Alyk4X+OlyDcYV" + + "tDool18Lwd6jZDi1ZOosF5/QEj5tuPrFeQQDOQAENlMfji/H5gxxL5TKtLMFv2X3" + + "0EJrj3orwGV0zEz+EgSChr+I8bsOrnfkr5UwMQIjGJOg1G/nYKOCARgwggEUMA8G" + + "A1UdEwEB/wQFMAMBAf8weQYDVR0gAQH/BG8wbTBeBgkqhiQCAQEBAgEwUTBPBggr" + + "BgEFBQcCARZDaHR0cDovL2N6by5nb3YudWEvY29udGVudC9ub3JtYXRpdmVfZG9j" + + "dW1lbnQvZ2VuZXJhbF9kb2MvcmVnQ1pPLnppcDALBgkqhiQCAQEBAgIwHgYIKwYB" + + "BQUHAQMBAf8EDzANMAsGCSqGJAIBAQECATAOBgNVHQ8BAf8EBAMCAcYwKQYDVR0O" + + "BCIEIPqbNt55OgWdLCn8hfuY9HJE3d3+DTTBlTJBN0nxog+mMCsGA1UdIwQkMCKA" + + "IPqbNt55OgWdLCn8hfuY9HJE3d3+DTTBlTJBN0nxog+mMA0GCyqGJAIBAQEBAwEB" + + "A28ABGx8QNaWcy0admsBt6iB0Vi+kAargzsQuoc/BThskYdxGNftLvYDPYxkEM2N" + + "GQ+9f1RJgCSNVRj3NhWoHhkqcL5R3gxAHie+a+zMqsX0258hGdT3MXkm0Syn/cNo" + + "sga4XzzvnVaas9vsPKMrZTQ="); + + private final byte[] uaczo3 = Base64.decode( + "MIIEtTCCBDGgAwIBAgIDAYisMA0GCyqGJAIBAQEBAwEBMIIBGjELMAkGA1UEBhMC" + + "VUExKDAmBgNVBAgMH9Ca0LjRl9Cy0YHRjNC60LAg0L7QsdC70LDRgdGC0YwxETAP" + + "BgNVBAcMCNCa0LjRl9CyMUkwRwYDVQQKDEDQptC10L3RgtGA0LDQu9GM0L3QuNC5" + + "INC30LDRgdCy0ZbQtNGH0YPQstCw0LvRjNC90LjQuSDQvtGA0LPQsNC9MTEwLwYD" + + "VQQLDCjQkNC00LzRltC90ZbRgdGC0YDQsNGC0L7RgCDQhtCi0KEg0KbQl9CeMTUw" + + "MwYDVQQDDCzQo9C60YDQsNGX0L3QsCwg0KbQl9CeIC8gVWtyYWluZSwgQ2VudHJh" + + "bCBDQTEZMBcGA1UEBRMQVUEtMDAwMTU2MjItMjAxMTAeFw0wNzEyMjAxMDAwMDBa" + + "Fw0xMjEyMTgxMDAwMDBaMIIBGjELMAkGA1UEBhMCVUExKDAmBgNVBAgMH9Ca0LjR" + + "l9Cy0YHRjNC60LAg0L7QsdC70LDRgdGC0YwxETAPBgNVBAcMCNCa0LjRl9CyMUkw" + + "RwYDVQQKDEDQptC10L3RgtGA0LDQu9GM0L3QuNC5INC30LDRgdCy0ZbQtNGH0YPQ" + + "stCw0LvRjNC90LjQuSDQvtGA0LPQsNC9MTEwLwYDVQQLDCjQkNC00LzRltC90ZbR" + + "gdGC0YDQsNGC0L7RgCDQhtCi0KEg0KbQl9CeMTUwMwYDVQQDDCzQo9C60YDQsNGX" + + "0L3QsCwg0KbQl9CeIC8gVWtyYWluZSwgQ2VudHJhbCBDQTEZMBcGA1UEBRMQVUEt" + + "MDAwMTU2MjItMjAxMTCBnTBgBgsqhiQCAQEBAQMBATBRBg0qhiQCAQEBAQMBAQIJ" + + "BECp1utF8TxwgoDElnsjH16t9ljrpMA3KR042WvwJcpOF/jpcg3GFbQ6KJdfC8He" + + "o2Q4tWTqLBef0BI+bbj6xXkEAzkABDajkfNBomH27xjY1N7wklRvY5E0ZFaU53Fh" + + "y4jUY+G4AUhEHHCkTvUja8CUxPqtb9KyfuZELVOjggEYMIIBFDAPBgNVHRMBAf8E" + + "BTADAQH/MHkGA1UdIAEB/wRvMG0wXgYJKoYkAgEBAQIBMFEwTwYIKwYBBQUHAgEW" + + "Q2h0dHA6Ly9jem8uZ292LnVhL2NvbnRlbnQvbm9ybWF0aXZlX2RvY3VtZW50L2dl" + + "bmVyYWxfZG9jL3JlZ0NaTy56aXAwCwYJKoYkAgEBAQICMB4GCCsGAQUFBwEDAQH/" + + "BA8wDTALBgkqhiQCAQEBAgEwDgYDVR0PAQH/BAQDAgHGMCkGA1UdDgQiBCC+e+cA" + + "bIdAgQkh6q3dUAZjPrNhwDDGrVnLNP6telmoCjArBgNVHSMEJDAigCC+e+cAbIdA" + + "gQkh6q3dUAZjPrNhwDDGrVnLNP6telmoCjANBgsqhiQCAQEBAQMBAQNvAARsyq9i" + + "ajEgdBh5mPUZefcLY56AIRWqmsJsWuZuUbCa5oQXRH5iCRa4PSvs8v6zHAKKlMgK" + + "gaoY6jywqmwiMlylbSgo/A0HKdCFnUUl7S8yjE4054MSSIjb2R0c2pmqmwtU25JB" + + "/MkNbe77Uzka"); + + private final byte[] uaczo4 = Base64.decode( + "MIIEKzCCA6egAwIBAgIBATANBgsqhiQCAQEBAQMBATCBzDFJMEcGA1UECwxA0KbQ" + + "tdC90YLRgNCw0LvRjNC90LjQuSDQt9Cw0YHQstGW0LTRh9GD0LLQsNC70YzQvdC4" + + "0Lkg0L7RgNCz0LDQvTE1MDMGA1UEAwws0KPQutGA0LDRl9C90LAsINCm0JfQniAv" + + "IFVrcmFpbmUsIENlbnRyYWwgQ0ExCzAJBgNVBAYTAlVBMREwDwYDVQQHDAjQmtC4" + + "0ZfQsjEoMCYGA1UECAwf0JrQuNGX0LLRgdGM0LrQsCDQvtCx0LvQsNGB0YLRjDAe" + + "Fw0wNTEyMjMyMzAxMDFaFw0xMDEyMjMyMzAxMDFaMIHMMUkwRwYDVQQLDEDQptC1" + + "0L3RgtGA0LDQu9GM0L3QuNC5INC30LDRgdCy0ZbQtNGH0YPQstCw0LvRjNC90LjQ" + + "uSDQvtGA0LPQsNC9MTUwMwYDVQQDDCzQo9C60YDQsNGX0L3QsCwg0KbQl9CeIC8g" + + "VWtyYWluZSwgQ2VudHJhbCBDQTELMAkGA1UEBhMCVUExETAPBgNVBAcMCNCa0LjR" + + "l9CyMSgwJgYDVQQIDB/QmtC40ZfQstGB0YzQutCwINC+0LHQu9Cw0YHRgtGMMIIB" + + "UTCCARIGCyqGJAIBAQEBAwEBMIIBATCBvDAPAgIBrzAJAgEBAgEDAgEFAgEBBDbz" + + "ykDGaaTaFzFJyhLDLa4Ya1Osa8Y2WZferq6K0tiI+b/VNAFpTvnEJz2M/m3Cj3Bq" + + "D0kQzgMCNj///////////////////////////////////7oxdUWACajApyTwL4Gq" + + "ih/Lr4DZDHqVEQUEzwQ2lqAgR9+skUI33jGNgj2Qsh9+3x7so5koelwr4fy89k/x" + + "5eqNSvFZ/1fPHfXz+iz7PmFIhr15BECLwhftNllK8B904j3LmmBY/teFIBSrw2lL" + + "CKc1nWIez+h/01q0GSxgeuwU0oOw9WmwlkGuj13DJ8cSmm70jTULAzkABDa6vb3U" + + "VIxZr2cXcVSvKkPM65Ii2+8biqyoH8i9e0NKJu+IhjDvUrvzlr8U+ywuf5bpSj4N" + + "fEmjezB5MA4GA1UdDwEB/wQEAwIBxjAPBgNVHRMBAf8EBTADAQH/MCsGA1UdIwQk" + + "MCKAIOPEn/xcXE6VGFNB8vbfXS1XMYYzAa4ML8opsOslTHJNMCkGA1UdDgQiBCDj" + + "xJ/8XFxOlRhTQfL2310tVzGGMwGuDC/KKbDrJUxyTTANBgsqhiQCAQEBAQMBAQNv" + + "AARsh0unjBfQoINx2rXAJggrBdoRsCouw8lN771DhcuUrlQUuEEQHTaZrQoYbECu" + + "AGfsxfTyldQDEOVzD/Uq8Xh4gIHuSqki9mRSjMR19MQtTKRmI9TRHIeTdIZ6l3P7" + + "jFfGJvTP0E9NYSolx+kM"); + + private final byte[] sha3Cert = Base64.decode( + "MIID8jCCAqagAwIBAgIICfBykpzUT+IwQQYJKoZIhvcNAQEKMDSgDzANBglg" + + "hkgBZQMEAggFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAggFAKIDAgEg" + + "MCwxCzAJBgNVBAYTAkRFMQ4wDAYDVQQKDAV4aXBraTENMAsGA1UEAwwEUkNB" + + "MTAeFw0xNjEwMTgxODQzMjhaFw0yNjEwMTgxODQzMjdaMCwxCzAJBgNVBAYT" + + "AkRFMQ4wDAYDVQQKDAV4aXBraTENMAsGA1UEAwwEUkNBMTCCASIwDQYJKoZI" + + "hvcNAQEBBQADggEPADCCAQoCggEBAK/pzm1RASDYDg3WBXyW3AnAESRF/+li" + + "qh0X8Y89m+JFJeOi1u89bOSPjsFfo5SbRSElyRXedh/d37KrONg39NEKIcC6" + + "iSuiNfXu0D6nlSzhrQzmvHIyfLnm8N2JtHDr/hZIprOcFO+lZTJIjjrOVe9y" + + "lFGgGDd/uQCEJk1Cmi5Ivi9odeiN3z8lVlGNeN9/Q5n47ijuYWr73z/FyyAK" + + "gAG3B5nhAYWs4ft0O3JWBc0QJZzShqsRjm3SNhAqMDnRoTq04PFgbDYizV8T" + + "ydz2kCne79TDwsY4MckYYaGoNcPoQXVS+9YjQjI72ktSlxiJxodL9WMFl+ED" + + "5ZLBRIRsDJECAwEAAaOBrzCBrDAPBgNVHRMBAf8EBTADAQH/MGoGCCsGAQUF" + + "BwEBBF4wXDAnBggrBgEFBQcwAoYbaHR0cDovL2V4YW1wbGUub3JnL1JDQTEu" + + "ZGVyMDEGCCsGAQUFBzABhiVodHRwOi8vbG9jYWxob3N0OjgwODAvb2NzcC9y" + + "ZXNwb25kZXIxMB0GA1UdDgQWBBRTXKdJI3P1kveLlRxPvzUfDnC8JjAOBgNV" + + "HQ8BAf8EBAMCAQYwQQYJKoZIhvcNAQEKMDSgDzANBglghkgBZQMEAggFAKEc" + + "MBoGCSqGSIb3DQEBCDANBglghkgBZQMEAggFAKIDAgEgA4IBAQCpSVaqOMKz" + + "6NT0+mivEhig9cKsglFhnWStKUtdhrG4HqOf6Qjny9Xvq1nE7x8e2xAoaZLd" + + "GMsNAWFCbwzoJrDL7Ct6itQ5ymxi2haN+Urc5UWJd/8C0R74OdP1uPCiljZ9" + + "DdjbNk/hS36UPYi+FT5r6Jr/1X/EqgL1MOUsSTEXdYlZH662zjbV4D9QSBzx" + + "ul9bYyWrqSZFKvKef4UQwUy8yXtChwiwp50mfJQBdVcIqPBYCgmLYclamjQx" + + "hlkk5VbZb4D/Cv4HxrdxpJfy/ewUZR7uHlzDx0/m4qjzNzWgq+sh3ZbveDrV" + + "wd/FDMFOxSIno9qgHtdfgXRwZJ+l07fF"); + + private final String ecPemCert = + "-----BEGIN CERTIFICATE-----\n" + + "MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC\n" + + "VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ\n" + + "cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ\n" + + "BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt\n" + + "VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D\n" + + "0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9\n" + + "ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G\n" + + "A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G\n" + + "A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs\n" + + "aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I\n" + + "flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==\n" + + "-----END CERTIFICATE-----"; + + private final String pemPKCS7 = + "-----BEGIN PKCS7-----\n" + + "MIIJDAYJKoZIhvcNAQcCoIII/TCCCPkCAQExADALBgkqhkiG9w0BBwGgggjfMIIF\n" + + "wTCCBKmgAwIBAgIJ+pQ4odKc8AABMA0GCSqGSIb3DQEBBQUAMGAxCzAJBgNVBAYT\n" + + "AlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRIwEAYDVQQHEwlTYW4gTWF0ZW8xFzAV\n" + + "BgNVBAoTDkdlbml1cy5jb20gSW5jMQ8wDQYDVQQLEwZOZXRPcHMwHhcNMTQwMTI4\n" + + "MjE0MjE0WhcNMjQwMTI2MjE0MjE0WjBgMQswCQYDVQQGEwJVUzETMBEGA1UECBMK\n" + + "Q2FsaWZvcm5pYTESMBAGA1UEBxMJU2FuIE1hdGVvMRcwFQYDVQQKEw5HZW5pdXMu\n" + + "Y29tIEluYzEPMA0GA1UECxMGTmV0T3BzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A\n" + + "MIIBCgKCAQEArfmkkDffJP6ODl13KnTaB8cwvB4anWw8+bGa8y9N7wPx7RWZWFMr\n" + + "fOac01p2fhq+oUIw3/uxRcDAQBQx0ZFLx3OFMuQkTpFbzHeSctsXi1Kk28pn4K3B\n" + + "K2CModRh8ir/qdhu0PG4SsXdyN8uT8H6bitmH4vpLaAMMi6aa1M6Ygio8a37UCQQ\n" + + "7fw2P7YVR61BsyqwsM/eYtgd2LqrObLwkkOvxTwpZPWDftHI4ucz1rgNnD9q0H3g\n" + + "kyGyGq9NBkBHJ25+CkMe+1q/eh4Xt2kt2ML4q5YZmQEwHm1eIR3/uGlb1+bueRMd\n" + + "hrueth/FsUiKPJ0gzmsxzQefgcLnctIx3wIDAQABo4ICfDCCAngwCQYDVR0TBAIw\n" + + "ADALBgNVHQ8EBAMCBeAwHQYDVR0OBBYEFJ/uU/wudzNDSI/SWkNNTXNLq2EIMIGS\n" + + "BgNVHSMEgYowgYeAFJ/uU/wudzNDSI/SWkNNTXNLq2EIoWSkYjBgMQswCQYDVQQG\n" + + "EwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTESMBAGA1UEBxMJU2FuIE1hdGVvMRcw\n" + + "FQYDVQQKEw5HZW5pdXMuY29tIEluYzEPMA0GA1UECxMGTmV0T3Bzggn6lDih0pzw\n" + + "AAEwHgYJYIZIAYb4QgENBBEWD1guNTA5IFVuaXQgVGVzdDCBwwYDVR0RBIG7MIG4\n" + + "oA4GAyoDBKAHDAV0ZXN0MYEQeDUwOUBleGFtcGxlLmNvbYIQeDUwOS5leGFtcGxl\n" + + "LmNvbaRQME4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1Bd2Vzb21lIER1ZGVzMRcw\n" + + "FQYDVQQLFA7DnGJlciBGcsOuZW5kczEOMAwGA1UEAxQF4oiGxpKGJWh0dHA6Ly93\n" + + "d3cuZXhhbXBsZS5jb20vP3E9YXdlc29tZW5lc3OHBMCoAAGIAyoDBDCBwwYDVR0S\n" + + "BIG7MIG4oA4GAyoDBKAHDAV0ZXN0MYEQeDUwOUBleGFtcGxlLmNvbYIQeDUwOS5l\n" + + "eGFtcGxlLmNvbaRQME4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1Bd2Vzb21lIER1\n" + + "ZGVzMRcwFQYDVQQLFA7DnGJlciBGcsOuZW5kczEOMAwGA1UEAxQF4oiGxpKGJWh0\n" + + "dHA6Ly93d3cuZXhhbXBsZS5jb20vP3E9YXdlc29tZW5lc3OHBMCoAAGIAyoDBDAN\n" + + "BgkqhkiG9w0BAQUFAAOCAQEAQK5jBzTq2lX1GpVD9RHxtTHJn/WkYOpMJYJruw8j\n" + + "HGfQwAkhlL9AqWgodTruoTnXgZbA7F3S8hx9gmUbHVjVeBvxZnGEJ8g7So1erFKv\n" + + "yQD1Ajtn7+uGXw6s0Dvde2ZVzV05pRk9ybg7kxKNXvVbKS3kyd6XoA27H5CSmzDu\n" + + "8cwHQkN4mJlwAiNCwMarpN4m4X0rQ+g1Ncfq+4sRjFLd8VVCbCpzD8UMBOVTpxxj\n" + + "kSyRPJZ7Db8SY0H2vcTUj2Yyog1RQ+RA/xp7Fgw+leEiveIE23Dq62hCHq6rU5Vj\n" + + "6L/LlLiKZ17lZT4z0fJ0lukPUpmVTynALKsKNm57+fOfnzCCAxYwggLWoAMCAQIC\n" + + "CQDcaK5WyhbztjAJBgcqhkjOOAQDMGAxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpD\n" + + "YWxpZm9ybmlhMRIwEAYDVQQHEwlTYW4gTWF0ZW8xFzAVBgNVBAoTDkdlbml1cy5j\n" + + "b20gSW5jMQ8wDQYDVQQLEwZOZXRPcHMwHhcNMTQwMTI4MjE0MjE1WhcNMTQwMjI3\n" + + "MjE0MjE1WjBgMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTESMBAG\n" + + "A1UEBxMJU2FuIE1hdGVvMRcwFQYDVQQKEw5HZW5pdXMuY29tIEluYzEPMA0GA1UE\n" + + "CxMGTmV0T3BzMIIBtzCCASsGByqGSM44BAEwggEeAoGBAIiv42coWuyVXpYoyEwf\n" + + "7uevd4ILhylFuvKH5tRWRcZENuxPOmXfr3L43PCdbnJhXMg3RkkWgjaE7lBk5evx\n" + + "LKH6rU2a1GnGmoY34OIvVvGL3xi96uYTTvLIX3+6NXaAlNppIBSHXcYx8cMdtYIn\n" + + "3J6JGSHEPo36ay4rDZbfS1frAhUAxF6k+/9T00QMolE41R+6ytzrawkCgYA4soyt\n" + + "rrIrQq6gwm2HanT8coIChr3/Et8rMamj7gS1yT9kH8HNGf217XtE3f/LUZZWUkBq\n" + + "3PNOuxhprNmvSAdQ7ZzhWfRvOFHKaH/DtKvLeEC5I00DfYSI64/V869Jy7lnyY7M\n" + + "h7ShLIwOlwnBDIL5oluircfXTr20a/Jv9pS1AAOBhQACgYEAhg6lELBZAIHVkjm7\n" + + "bwVJ5G/ka+KCjXxWXo+BCbqo0LqfrKQoQwUcwDzuKdqWxYbyUd0cl5/9fX59/RT/\n" + + "9ULklGy+dTyUSc/hj85PCXLYly3G6WECiN29TK0QLhEMZfi+iSm3YxNX3rxvmrHb\n" + + "bfO2SMef4r6ujv9KscDg0zQ4AgajGjAYMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgA3\n" + + "MAkGByqGSM44BAMDLwAwLAIUVcYZ1LNv22fDBiajZ99FpTn05SMCFCgMXzUGLdPy\n" + + "gY460q7tGpuydry+oQAxAA==\n" + + "-----END PKCS7-----\n"; + + private static byte[] sm_root = Base64.decode( + "MIICDTCCAbGgAwIBAgIEHPP3OTAMBggqgRzPVQGDdQUAMFoxCzAJBgNVBAYTAkNO" + + "MTAwLgYDVQQKDCdDaGluYSBGaW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBBdXRob3Jp" + + "dHkxGTAXBgNVBAMMEENGQ0EgRVYgU00yIFJPT1QwHhcNMTIwODA4MDMwNjMwWhcN" + + "MjkxMjMxMDMwNjMwWjBaMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmlu" + + "YW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRkwFwYDVQQDDBBDRkNBIEVW" + + "IFNNMiBST09UMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAE/9xokvYPq1PPsvqh" + + "wzc1OvhRJyqfm+FeefW522OMUJeSqmaYRcwAaEC1IH03etyYEOD4R4HQG+ovJr4z" + + "PLZzUqNjMGEwHwYDVR0jBBgwFoAUXxyJKUK15hS66W6X7kBqaMo9lLgwDwYDVR0T" + + "AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFF8ciSlCteYUuulu" + + "l+5AamjKPZS4MAwGCCqBHM9VAYN1BQADSAAwRQIgbE/XnzWMMQItSfz/LH6CyNz1" + + "OxFwvI6WcgcqGGUdCiMCIQDRFwF7M4Cvo7KqGMNuSiByFNUX9PJYXByjxqPart9U" + + "tw=="); + + private static byte[] sm_sign = Base64.decode( + "MIICzTCCAnKgAwIBAgIGAIgmba9KMAwGCCqBHM9VAYN1BQAwWjELMAkGA1UEBhMC" + + "Q04xMDAuBgNVBAoMJ0NoaW5hIEZpbmFuY2lhbCBDZXJ0aWZpY2F0aW9uIEF1dGhv" + + "cml0eTEZMBcGA1UEAwwQQ0ZDQSBFViBTTTIgUk9PVDAeFw0xMjA4MDgwNTU2Mjda" + + "Fw0yOTEyMjkwNTU2MjdaMFkxCzAJBgNVBAYTAkNOMTAwLgYDVQQKDCdDaGluYSBG" + + "aW5hbmNpYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGDAWBgNVBAMMD0NGQ0Eg" + + "RVYgU00yIE9DQTBZMBMGByqGSM49AgEGCCqBHM9VAYItA0IABG6sjKVpVukkQpY1" + + "nokr6wmp44hwkVnzmdXvuBbq/VtwB/8V+awkIfpz4THaSjPGzSGh+hwFcka0NCFK" + + "TQ7y8rqjggEhMIIBHTA4BggrBgEFBQcBAQQsMCowKAYIKwYBBQUHMAGGHGh0dHA6" + + "Ly9vY3NwLmNmY2EuY29tLmNuL29jc3AwHwYDVR0jBBgwFoAUXxyJKUK15hS66W6X" + + "7kBqaMo9lLgwDwYDVR0TAQH/BAUwAwEB/zBEBgNVHSAEPTA7MDkGBFUdIAAwMTAv" + + "BggrBgEFBQcCARYjaHR0cDovL3d3dy5jZmNhLmNvbS5jbi91cy91cy0xMi5odG0w" + + "OgYDVR0fBDMwMTAvoC2gK4YpaHR0cDovL2NybC5jZmNhLmNvbS5jbi9ldnJjYS9T" + + "TTIvY3JsMS5jcmwwDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTDJFfnVXuTdN3s" + + "yIha7AIm0b8vWTAMBggqgRzPVQGDdQUAA0cAMEQCIBgrKO75mE5lfONElZZzkAWh" + + "eb0R0ai6/J7nj7SCZ3jJAiAE2dKJIv9ROkN17bhZpXsVrOtyYULW7YzQePqnNN58" + + "MA=="); + + private static byte[] sm_root1 = Base64.decode( + "MIICwzCCAmmgAwIBAgIIIBQGIgAAAAMwCgYIKoEcz1UBg3UwgdgxCzAJBgNVBAYT" + + "AkNOMRIwEAYDVQQIDAnmsZ/oi4/nnIExEjAQBgNVBAcMCeWNl+S6rOW4gjE8MDoG" + + "A1UECgwz5rGf6IuP55yB55S15a2Q5ZWG5Yqh5pyN5Yqh5Lit5b+D5pyJ6ZmQ6LSj" + + "5Lu75YWs5Y+4MUswSQYDVQQLDELmsZ/oi4/nnIHnlLXlrZDllYbliqHmnI3liqHk" + + "uK3lv4PmnInpmZDotKPku7vlhazlj7jlronlhajkuovkuJrpg6gxFjAUBgNVBAMM" + + "DUpTQ0FfUk9PVF9TTTIwHhcNMTQwNjIyMDQ1MzAyWhcNMzQwNjIyMDQ1MzAyWjCB" + + "1jELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCeaxn+iLj+ecgTESMBAGA1UEBwwJ5Y2X" + + "5Lqs5biCMTwwOgYDVQQKDDPmsZ/oi4/nnIHnlLXlrZDllYbliqHmnI3liqHkuK3l" + + "v4PmnInpmZDotKPku7vlhazlj7gxSzBJBgNVBAsMQuaxn+iLj+ecgeeUteWtkOWV" + + "huWKoeacjeWKoeS4reW/g+aciemZkOi0o+S7u+WFrOWPuOWuieWFqOS6i+S4mumD" + + "qDEUMBIGA1UEAwwLSlNDQV9DQV9TTTIwWTATBgcqhkjOPQIBBggqgRzPVQGCLQNC" + + "AAS/gvW90+LvyXPgpR7L0pwlVoZQdan7V5YQMEpxt47tzer31/8WJIfldx9NL/1A" + + "swkk6ItveCVW5k0u+IIk6crLox0wGzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIB" + + "BjAKBggqgRzPVQGDdQNIADBFAiEAy9NkogihHCj9Jx0ZiHdkMyCHF0wHWX58KZco" + + "CW5mjbgCIC9cAyuVV91ygLWk14PDuIAPFWKm6rJPXbiZL6KzwHQA"); + + private static byte[] sm_ca1 = Base64.decode( + "MIIC/TCCAqKgAwIBAgIIIBYDKQETeGQwCgYIKoEcz1UBg3UwgccxCzAJBgNVBAYT" + + "AkNOMRIwEAYDVQQIDAnmsZ/oi4/nnIExEjAQBgNVBAcMCeWNl+S6rOW4gjE8MDoG" + + "A1UECgwz5rGf6IuP55yB55S15a2Q5ZWG5Yqh5pyN5Yqh5Lit5b+D5pyJ6ZmQ6LSj" + + "5Lu75YWs5Y+4MTwwOgYDVQQLDDPmsZ/oi4/nnIHnlLXlrZDllYbliqHmnI3liqHk" + + "uK3lv4PmnInpmZDotKPku7vlhazlj7gxFDASBgNVBAMMC0pTQ0FfQ0FfU00yMB4X" + + "DTE2MDMyOTA3MzQxOVoXDTIxMDMyOTA3MzQxOVowejENMAsGA1UEAxMEaG9zdDEL" + + "MAkGA1UECxMCMTExETAPBgNVBAoTCEFCQyBsdGQuMQswCQYDVQQHEwJOSjELMAkG" + + "A1UECBMCSlMxIjAgBgRVBC0RExhEOURGQThBN0NFMDg5QTg0Q0Q4Q0RCQjYxCzAJ" + + "BgNVBAYTAkNOMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEaTG1mpejjdsNRr2q" + + "p3ZC0pPXuBO19sNhIJEG6cMSi/kE1hNDosCBRhpr2gOqKP9bXHrIhVGe41Z9Ci8L" + + "jf/hpaOBwzCBwDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIEsDAdBgNVHSUEFjAUBggr" + + "BgEFBQcDAgYIKwYBBQUHAwQwHwYDVR0jBBgwFoAU/9NocgiO5XrE+eYsU0VOkaSx" + + "egMwRwYIKwYBBQUHAQEEOzA5MDcGCCsGAQUFBzAChitodHRwOi8vMTAuMTA4LjUu" + + "Mjo4ODgwL2Rvd25sb2FkL0pTQ0FfQ0EuY2VyMB0GA1UdDgQWBBQQ80pId+SJS9uP" + + "aZaItbNdEE2C0zAKBggqgRzPVQGDdQNJADBGAiEAogpBxL3Cc4P4v+FvQsnCgCZs" + + "oSdFZLZDB4uDlOIqU9wCIQDXmE1iiCsWi1RmdoY+/ics2ZlY8vyHWBJnZ+XFy1Jb" + + "fA=="); + + private static byte[] sm_sign1 = Base64.decode( + "MIID9zCCA5ygAwIBAgIIIBcEJwKSCCMwCgYIKoEcz1UBg3UwgccxCzAJBgNVBAYT" + + "AkNOMRIwEAYDVQQIDAnmsZ/oi4/nnIExEjAQBgNVBAcMCeWNl+S6rOW4gjE8MDoG" + + "A1UECgwz5rGf6IuP55yB55S15a2Q5ZWG5Yqh5pyN5Yqh5Lit5b+D5pyJ6ZmQ6LSj" + + "5Lu75YWs5Y+4MTwwOgYDVQQLDDPmsZ/oi4/nnIHnlLXlrZDllYbliqHmnI3liqHk" + + "uK3lv4PmnInpmZDotKPku7vlhazlj7gxFDASBgNVBAMMC0pTQ0FfQ0FfU00yMB4X" + + "DTE3MDQyNzAwMzkwNVoXDTE4MDQyNzAwMzkwNVowggEdMQ4wDAYDVQRYDAUwMDAw" + + "MTESMBAGA1UEGgwJ5biC6L6W5Yy6MRswGQYDVQQBDBIzMjAxMTIxOTgxMDUxMTAw" + + "MTQxDTALBgRVBIhYDAM0NTYxDTALBgRVBIhXDAMxMjMxEjAQBgNVBC0MCXVzZXJD" + + "ZXJ0MjELMAkGA1UEBhMCQ04xEjAQBgNVBAgMCeaxn+iLj+ecgTESMBAGA1UEBwwJ" + + "5Y2X5Lqs5biCMQwwCgYDVQQLDAMwMDgxHzAdBgkqhkiG9w0BCQEWEDMyNzMyMTU2" + + "OEBxcS5jb20xITAfBgNVBCoMGOa1i+ivlee9keWFs1NNMueul+azlTEyMzEhMB8G" + + "A1UEAwwY5rWL6K+V572R5YWzU00y566X5rOVMTIzMFkwEwYHKoZIzj0CAQYIKoEc" + + "z1UBgi0DQgAEdbrBzy2y8Gz4grOF23iaDipPhRPQRApAMIAP0cAuL1tATFjFuWJs" + + "pBc1cnCZmsOJnVpV4W7VF8hNOaqv3Tq4NqOCARcwggETMAkGA1UdEwQCMAAwCwYD" + + "VR0PBAQDAgbAMB0GA1UdDgQWBBRsWSOQDniy75t7UEvTXugwfq0HpzAfBgNVHSME" + + "GDAWgBT/02hyCI7lesT55ixTRU6RpLF6AzAxBgNVHSUEKjAoBggrBgEFBQcDAgYI" + + "KwYBBQUHAwgGCCsGAQUFBwMEBggrBgEFBQcDCDA9BgNVHR8ENjA0MDKgMKAuhixo" + + "dHRwOi8vY3JsLmpzY2EuY29tLmNuL2NybC9TTTJDUkxfRU5USVRZLmNybDBHBggr" + + "BgEFBQcBAQQ7MDkwNwYIKwYBBQUHMAKBK2h0dHA6Ly8xMC4xMDguNS4yOjg4ODAv" + + "ZG93bmxvYWQvSlNDQV9DQS5jZXIwCgYIKoEcz1UBg3UDSQAwRgIhALFoMoA1+uO4" + + "tXfmoyePz1pmv0CWPBgEP1EfDeS6FPitAiEAjHJYq7ryHKULqpRg6ph9r+xUDoWd" + + "0TPMOQ9jj4XJPO4="); + + private byte[] x25519Cert = Base64.decode( + "MIIBLDCB36ADAgECAghWAUdKKo3DMDAFBgMrZXAwGTEXMBUGA1UEAwwOSUVURiBUZX" + + "N0IERlbW8wHhcNMTYwODAxMTIxOTI0WhcNNDAxMjMxMjM1OTU5WjAZMRcwFQYDVQQD" + + "DA5JRVRGIFRlc3QgRGVtbzAqMAUGAytlbgMhAIUg8AmJMKdUdIt93LQ+91oNvzoNJj" + + "ga9OukqY6qm05qo0UwQzAPBgNVHRMBAf8EBTADAQEAMA4GA1UdDwEBAAQEAwIDCDAg" + + "BgNVHQ4BAQAEFgQUmx9e7e0EM4Xk97xiPFl1uQvIuzswBQYDK2VwA0EAryMB/t3J5v" + + "/BzKc9dNZIpDmAgs3babFOTQbs+BolzlDUwsPrdGxO3YNGhW7Ibz3OGhhlxXrCe1Cg" + + "w1AH9efZBw==" + ); + + private PublicKey dudPublicKey = new PublicKey() + { + public String getAlgorithm() + { + return null; + } + + public String getFormat() + { + return null; + } + + public byte[] getEncoded() + { + return null; + } + + }; + + public String getName() + { + return "CertTest"; + } + + public void checkCertificate( + int id, + byte[] bytes) + { + ByteArrayInputStream bIn; + String dump = ""; + + try + { + bIn = new ByteArrayInputStream(bytes); + + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + Certificate cert = fact.generateCertificate(bIn); + + PublicKey k = cert.getPublicKey(); + +// System.out.println(cert); + } + catch (Exception e) + { + fail(dump + Strings.lineSeparator() + getName() + ": " + id + " failed - exception " + e.toString(), e); + } + + } + + public void checkCertificate( + int id, + byte[] bytes, + PublicKey pubKey) + { + ByteArrayInputStream bIn; + String dump = ""; + + try + { + bIn = new ByteArrayInputStream(bytes); + + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + Certificate cert = fact.generateCertificate(bIn); + + PublicKey k = cert.getPublicKey(); + + cert.verify(pubKey); + // System.out.println(cert); + } + catch (Exception e) + { + fail(dump + Strings.lineSeparator() + getName() + ": " + id + " failed - exception " + e.toString(), e); + } + + } + + public void checkNameCertificate( + int id, + byte[] bytes) + { + ByteArrayInputStream bIn; + String dump = ""; + + try + { + bIn = new ByteArrayInputStream(bytes); + + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn); + + PublicKey k = cert.getPublicKey(); + if (!cert.getIssuerDN().toString().equals("C=DE,O=DATEV eG,0.2.262.1.10.7.20=1+CN=CA DATEV D03 1:PN")) + { + fail(id + " failed - name test."); + } + // System.out.println(cert); + } + catch (Exception e) + { + fail(dump + Strings.lineSeparator() + getName() + ": " + id + " failed - exception " + e.toString(), e); + } + + } + + public void checkKeyUsage( + int id, + byte[] bytes) + { + ByteArrayInputStream bIn; + String dump = ""; + + try + { + bIn = new ByteArrayInputStream(bytes); + + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate cert = (X509Certificate)fact.generateCertificate(bIn); + + PublicKey k = cert.getPublicKey(); + + if (cert.getKeyUsage()[7]) + { + fail("error generating cert - key usage wrong."); + } + + // System.out.println(cert); + } + catch (Exception e) + { + fail(dump + Strings.lineSeparator() + getName() + ": " + id + " failed - exception " + e.toString(), e); + } + + } + + public void checkSelfSignedCertificate( + int id, + byte[] bytes, + String sigAlgName) + { + ByteArrayInputStream bIn; + String dump = ""; + + try + { + bIn = new ByteArrayInputStream(bytes); + + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + Certificate cert = fact.generateCertificate(bIn); + + PublicKey k = cert.getPublicKey(); + + cert.verify(k); + if (sigAlgName != null && !sigAlgName.equals(((X509Certificate)cert).getSigAlgName())) + { + fail("sigAlgName not matched on certificate: " + sigAlgName); + } + + // System.out.println(cert); + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail(dump + Strings.lineSeparator() + getName() + ": " + id + " failed - exception " + e.toString(), e); + } + + } + + public void checkCertificateSignedBy( + int id, + byte[] certBytes, + byte[] signingCertBytes) + { + ByteArrayInputStream bIn; + String dump = ""; + + try + { + bIn = new ByteArrayInputStream(certBytes); + + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + Certificate cert = fact.generateCertificate(bIn); + + bIn = new ByteArrayInputStream(signingCertBytes); + + PublicKey k = fact.generateCertificate(bIn).getPublicKey(); + + cert.verify(k); + + // System.out.println(cert); + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail(dump + Strings.lineSeparator() + getName() + ": " + id + " failed - exception " + e.toString(), e); + } + + } + + private void checkCRL( + int id, + byte[] bytes) + { + ByteArrayInputStream bIn; + String dump = ""; + + try + { + bIn = new ByteArrayInputStream(bytes); + + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + CRL cert = fact.generateCRL(bIn); + + // System.out.println(cert); + } + catch (Exception e) + { + fail(dump + Strings.lineSeparator() + getName() + ": " + id + " failed - exception " + e.toString(), e); + } + + } + + private void testForgedSignature() + throws Exception + { + String cert = "MIIBsDCCAVoCAQYwDQYJKoZIhvcNAQEFBQAwYzELMAkGA1UEBhMCQVUxEzARBgNV" + + "BAgTClF1ZWVuc2xhbmQxGjAYBgNVBAoTEUNyeXB0U29mdCBQdHkgTHRkMSMwIQYD" + + "VQQDExpTZXJ2ZXIgdGVzdCBjZXJ0ICg1MTIgYml0KTAeFw0wNjA5MTEyMzU4NTVa" + + "Fw0wNjEwMTEyMzU4NTVaMGMxCzAJBgNVBAYTAkFVMRMwEQYDVQQIEwpRdWVlbnNs" + + "YW5kMRowGAYDVQQKExFDcnlwdFNvZnQgUHR5IEx0ZDEjMCEGA1UEAxMaU2VydmVy" + + "IHRlc3QgY2VydCAoNTEyIGJpdCkwXDANBgkqhkiG9w0BAQEFAANLADBIAkEAn7PD" + + "hCeV/xIxUg8V70YRxK2A5jZbD92A12GN4PxyRQk0/lVmRUNMaJdq/qigpd9feP/u" + + "12S4PwTLb/8q/v657QIDAQABMA0GCSqGSIb3DQEBBQUAA0EAbynCRIlUQgaqyNgU" + + "DF6P14yRKUtX8akOP2TwStaSiVf/akYqfLFm3UGka5XbPj4rifrZ0/sOoZEEBvHQ" + + "e20sRA=="; + + CertificateFactory certFact = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(Base64.decode(cert))); + try + { + x509.verify(x509.getPublicKey()); + + fail("forged RSA signature passed"); + } + catch (Exception e) + { + // expected + } + } + + + private void pemTest() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + Certificate cert = readPEMCert(cf, PEMData.CERTIFICATE_1); + if (cert == null) + { + fail("PEM cert not read"); + } + cert = readPEMCert(cf, "-----BEGIN CERTIFICATE-----" + PEMData.CERTIFICATE_2); + if (cert == null) + { + fail("PEM cert with extraneous header not read"); + } + CRL crl = cf.generateCRL(new ByteArrayInputStream(PEMData.CRL_1.getBytes("US-ASCII"))); + if (crl == null) + { + fail("PEM crl not read"); + } + Collection col = cf.generateCertificates(new ByteArrayInputStream(PEMData.CERTIFICATE_2.getBytes("US-ASCII"))); + if (col.size() != 1 || !col.contains(cert)) + { + fail("PEM cert collection not right"); + } + col = cf.generateCRLs(new ByteArrayInputStream(PEMData.CRL_2.getBytes("US-ASCII"))); + if (col.size() != 1 || !col.contains(crl)) + { + fail("PEM crl collection not right"); + } + + cert = readPEMCert(cf, ecPemCert); + + SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfo.getInstance(cert.getPublicKey().getEncoded()); + + AlgorithmParameters ecParams = AlgorithmParameters.getInstance("EC", "BC"); + + ecParams.init(pubInfo.getAlgorithm().getParameters().toASN1Primitive().getEncoded()); + + if (!new BigInteger("ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973", 16) + .equals(((ECPublicKey)cert.getPublicKey()).getParameters().getN())) + { + fail("N incorrect"); + } + } + + private static Certificate readPEMCert(CertificateFactory cf, String pemData) + throws CertificateException, UnsupportedEncodingException + { + return cf.generateCertificate(new ByteArrayInputStream(pemData.getBytes("US-ASCII"))); + } + + private void pkcs7Test() + throws Exception + { + ASN1EncodableVector certs = new ASN1EncodableVector(); + + certs.add(new ASN1InputStream(CertPathTest.rootCertBin).readObject()); + certs.add(new DERTaggedObject(false, 2, new ASN1InputStream(AttrCertData.attrCert).readObject())); + + ASN1EncodableVector crls = new ASN1EncodableVector(); + + crls.add(new ASN1InputStream(CertPathTest.rootCrlBin).readObject()); + SignedData sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(certs), new DERSet(crls), new DERSet()); + + ContentInfo info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData); + + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded())); + if (cert == null || !areEqual(cert.getEncoded(), certs.get(0).toASN1Primitive().getEncoded())) + { + fail("PKCS7 cert not read"); + } + X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded())); + if (crl == null || !areEqual(crl.getEncoded(), crls.get(0).toASN1Primitive().getEncoded())) + { + fail("PKCS7 crl not read"); + } + + if (!"SHA256WITHRSA".equals(crl.getSigAlgName())) + { + fail("signature ID not matched in CRL: " + crl.getSigAlgName()); + } + + Collection col = cf.generateCertificates(new ByteArrayInputStream(info.getEncoded())); + if (col.size() != 1 || !col.contains(cert)) + { + fail("PKCS7 cert collection not right"); + } + col = cf.generateCRLs(new ByteArrayInputStream(info.getEncoded())); + if (col.size() != 1 || !col.contains(crl)) + { + fail("PKCS7 crl collection not right"); + } + + // data with no certificates or CRLs + + sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(), new DERSet(), new DERSet()); + + info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData); + + cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded())); + if (cert != null) + { + fail("PKCS7 cert present"); + } + crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded())); + if (crl != null) + { + fail("PKCS7 crl present"); + } + + // data with absent certificates and CRLS + + sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), null, null, new DERSet()); + + info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData); + + cert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(info.getEncoded())); + if (cert != null) + { + fail("PKCS7 cert present"); + } + crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(info.getEncoded())); + if (crl != null) + { + fail("PKCS7 crl present"); + } + + // + // sample message + // + InputStream in = new ByteArrayInputStream(pkcs7CrlProblem); + Collection certCol = cf.generateCertificates(in); + + in.reset(); + Collection crlCol = cf.generateCRLs(in); + + if (crlCol.size() != 0) + { + fail("wrong number of CRLs: " + crlCol.size()); + } + + if (certCol.size() != 4) + { + fail("wrong number of Certs: " + certCol.size()); + } + + in = new ByteArrayInputStream(pemPKCS7.getBytes("US-ASCII")); + certCol = cf.generateCertificates(in); + + in.reset(); + crlCol = cf.generateCRLs(in); + + if (crlCol.size() != 0) + { + fail("wrong number of CRLs: " + crlCol.size()); + } + + if (certCol.size() != 2) + { + fail("wrong number of Certs: " + certCol.size()); + } + } + + private KeyPair generateLongFixedKeys() + throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException + { + RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137", 16), + new BigInteger("010001", 16)); + + RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137", 16), + new BigInteger("010001", 16), + new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325", 16), + new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443", 16), + new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd", 16), + new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979", 16), + new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729", 16), + new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d", 16)); + + KeyFactory fact = KeyFactory.getInstance("RSA", "BC"); + + return new KeyPair(fact.generatePublic(pubKeySpec), fact.generatePrivate(privKeySpec)); + } + + private void rfc4491Test() + throws Exception + { + CertificateFactory certFact = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_94)); + + x509.verify(x509.getPublicKey(), "BC"); + + x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_2001)); + + x509.verify(x509.getPublicKey(), "BC"); + } + + private void testCertificateSerialization() + throws Exception + { + CertificateFactory certFact = CertificateFactory.getInstance("X.509", "BC"); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + X509Certificate x509 = (X509Certificate)certFact.generateCertificate(new ByteArrayInputStream(gostRFC4491_2001)); + + oOut.writeObject(x509); + + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + x509 = (X509Certificate)oIn.readObject(); + + x509.verify(x509.getPublicKey(), "BC"); + } + + private void checkComparison(byte[] encCert) + throws NoSuchProviderException, CertificateException + { + CertificateFactory bcFact = CertificateFactory.getInstance("X.509", "BC"); + CertificateFactory sunFact = CertificateFactory.getInstance("X.509", "SUN"); + + X509Certificate bcCert = (X509Certificate)bcFact.generateCertificate(new ByteArrayInputStream(encCert)); + X509Certificate sunCert = (X509Certificate)sunFact.generateCertificate(new ByteArrayInputStream(encCert)); + + if (!bcCert.equals(sunCert) || !sunCert.equals(bcCert)) + { + fail("BC/Sun equals test failed"); + } + + // Yes, they actually changed hashCode() on a certificate in JDK 1.8... +// if (bcCert.hashCode() != sunCert.hashCode()) +// { +// fail("BC/Sun hashCode test failed"); +// } + } + + private void testV1CRL() + throws Exception + { + byte[] certData = Streams.readAll(this.getClass().getResourceAsStream("ThawteSGCCA.cer")); + byte[] crlData = Streams.readAll(this.getClass().getResourceAsStream("ThawteSGCCA.crl")); + + // verify CRL with default (JCE) provider + CertificateFactory jceFac = CertificateFactory.getInstance("X.509"); + + X509Certificate jceIssuer = (X509Certificate) + jceFac.generateCertificate(new ByteArrayInputStream(certData)); + + X509CRL jceCRL = (X509CRL)jceFac.generateCRL(new ByteArrayInputStream(crlData)); + + jceCRL.verify(jceIssuer.getPublicKey()); + + // verify CRL with BC provider + CertificateFactory bcFac = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate bcIssuer = (X509Certificate) + bcFac.generateCertificate(new ByteArrayInputStream(certData)); + + X509CRL bcCRL = (X509CRL)bcFac.generateCRL(new ByteArrayInputStream(crlData)); + + jceCRL.verify(bcIssuer.getPublicKey()); + + bcCRL.verify(bcIssuer.getPublicKey()); + + if (!"SHA1WITHRSA".equals(bcCRL.getSigAlgName())) + { + fail("signature ID not matched in CRL"); + } + + if (!"SHA1WITHRSA".equals(bcIssuer.getSigAlgName())) + { + fail("signature ID not matched in certificate"); + } + } + + private void testCertPathEncAvailableTest() + throws Exception + { + CertificateFactory certFact = CertificateFactory.getInstance("X.509", "BC"); + + Iterator it = certFact.getCertPathEncodings(); + + if (!"PkiPath".equals(it.next())) + { + fail("available enc 1 wrong"); + } + if (!"PEM".equals(it.next())) + { + fail("available enc 2 wrong"); + } + if (!"PKCS7".equals(it.next())) + { + fail("available enc 3 wrong"); + } + + if (it.hasNext()) + { + fail("wrong number of encodings"); + } + } + + private void pemFileTest() + throws Exception + { + CertificateFactory certFact = CertificateFactory.getInstance("X.509", "BC"); + + Collection certs1 = (Collection)certFact.generateCertificates(this.getClass().getResourceAsStream("cert_chain.txt")); + + isTrue("certs wrong ", 2 == certs1.size()); + + BufferedInputStream in = new BufferedInputStream(this.getClass().getResourceAsStream("cert_chain.txt")); + + Set certs2 = new HashSet(); + while ((in.available() > 0)) + { + Certificate c = certFact.generateCertificate(in); + + // this isn't strictly correct with the way it's defined in the Java JavaDoc - need it for backward + // compatibility. + if (c != null) + { + certs2.add(c); + } + } + + isTrue("certs size ", certs1.size() == certs2.size()); + + for (Iterator it = certs1.iterator(); it.hasNext(); ) + { + certs2.remove(it.next()); + } + + isTrue("collection not empty", certs2.isEmpty()); + } + + private void invalidCRLs() + throws Exception + { + CertificateFactory certFact = CertificateFactory.getInstance("X.509", "BC"); + + try + { + certFact.generateCRLs(this.getClass().getResourceAsStream("cert_chain.txt")); + fail("multi crl - no exception"); + } + catch (CRLException e) + { + // ignore + } + try + { + certFact.generateCRL(this.getClass().getResourceAsStream("cert_chain.txt")); + fail("single crl - no exception"); + } + catch (CRLException e) + { + // ignore + } + } + + private void pemFileTestWithNl() + throws Exception + { + CertificateFactory certFact = CertificateFactory.getInstance("X.509", "BC"); + + Collection certs1 = (Collection)certFact.generateCertificates(this.getClass().getResourceAsStream("cert_chain_nl.txt")); + + isTrue("certs wrong ", 2 == certs1.size()); + + BufferedInputStream in = new BufferedInputStream(this.getClass().getResourceAsStream("cert_chain_nl.txt")); + + Set certs2 = new HashSet(); + while ((in.available() > 0)) + { + Certificate c = certFact.generateCertificate(in); + + // this isn't strictly correct with the way it's defined in the Java JavaDoc - need it for backward + // compatibility. + if (c != null) + { + certs2.add(c); + } + } + + isTrue("certs size ", certs1.size() == certs2.size()); + + for (Iterator it = certs1.iterator(); it.hasNext(); ) + { + certs2.remove(it.next()); + } + + isTrue("collection not empty", certs2.isEmpty()); + } + + public void performTest() + throws Exception + { + testV1CRL(); + + checkCertificate(1, cert1); + checkCertificate(2, cert2); + checkCertificate(3, cert3); + checkCertificate(4, cert4); + checkCertificate(5, cert5); + checkCertificate(6, oldEcdsa); + checkCertificate(7, cert7); + checkCertificate(8, sm_sign); + checkCertificate(9, x25519Cert, + KeyFactory.getInstance("EdDSA").generatePublic(new X509EncodedKeySpec(Base64.decode("MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=")))); + + checkComparison(cert1); + + checkKeyUsage(8, keyUsage); + checkSelfSignedCertificate(9, uncompressedPtEC, "ECDSA"); + checkNameCertificate(10, nameCert); + + checkSelfSignedCertificate(11, probSelfSignedCert, "SHA1WITHRSA"); + checkSelfSignedCertificate(12, gostCA1, "GOST3410"); + checkSelfSignedCertificate(13, gostCA2, "GOST3411WITHECGOST3410"); + checkSelfSignedCertificate(14, gost341094base, "GOST3410"); + checkSelfSignedCertificate(15, gost34102001base, "GOST3411WITHECGOST3410"); + checkSelfSignedCertificate(16, gost341094A, "GOST3410"); + checkSelfSignedCertificate(17, gost341094B, "GOST3410"); + checkSelfSignedCertificate(18, gost34102001A, "GOST3411WITHECGOST3410"); + + try + { + checkSelfSignedCertificate(19, uaczo1, "GOST3411WITHDSTU4145LE"); + checkSelfSignedCertificate(20, uaczo2, "GOST3411WITHDSTU4145LE"); + checkSelfSignedCertificate(21, uaczo3, "GOST3411WITHDSTU4145LE"); + checkSelfSignedCertificate(22, uaczo4, "GOST3411WITHDSTU4145LE"); + } + catch (Exception e) + { + if (e instanceof NoSuchAlgorithmException) + { + // ignore - only valid for jdk1.5+ + } + } + + checkSelfSignedCertificate(23, sha3Cert, "SHA3-256withRSAandMGF1"); + checkSelfSignedCertificate(24, sm_root, "SM3WITHSM2"); + + checkCertificateSignedBy(1, sm_sign, sm_root); + checkCertificateSignedBy(2, sm_ca1, sm_root1); + checkCertificateSignedBy(3, sm_sign1, sm_root1); + + checkCRL(1, crl1); + + pemTest(); + pemFileTest(); + pemFileTestWithNl(); + pkcs7Test(); + rfc4491Test(); + + invalidCRLs(); + + testForgedSignature(); + testCertificateSerialization(); + + checkCertificate(18, emptyDNCert); + + testCertPathEncAvailableTest(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new CertTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertUniqueIDTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertUniqueIDTest.java new file mode 100644 index 000000000..cfcb54388 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CertUniqueIDTest.java @@ -0,0 +1,178 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.util.Date; +import java.util.Set; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.jce.X509Principal; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.x509.X509V3CertificateGenerator; + +public class CertUniqueIDTest + extends SimpleTest +{ + public String getName() + { + return "CertUniqueID"; + } + + public void performTest() throws Exception + { + checkCreation1(); + } + + /** + * we generate a self signed certificate for the sake of testing - RSA + */ + public void checkCreation1() + throws Exception + { + // + // a sample key pair. + // + RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16)); + + RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16), + new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16), + new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16), + new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16), + new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16), + new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16), + new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16)); + + // + // set up the keys + // + PrivateKey privKey; + PublicKey pubKey; + + KeyFactory fact = KeyFactory.getInstance("RSA", "BC"); + + privKey = fact.generatePrivate(privKeySpec); + pubKey = fact.generatePublic(pubKeySpec); + + // + // distinguished name table. + // + Vector ord = new Vector(); + Vector values = new Vector(); + + ord.addElement(X509Principal.C); + ord.addElement(X509Principal.O); + ord.addElement(X509Principal.L); + ord.addElement(X509Principal.ST); + ord.addElement(X509Principal.E); + + values.addElement("AU"); + values.addElement("The Legion of the Bouncy Castle"); + values.addElement("Melbourne"); + values.addElement("Victoria"); + values.addElement("feedback-crypto@bouncycastle.org"); + + // + // extensions + // + + // + // create the certificate - version 3 - without subject unique ID + // + X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); + + certGen.setSerialNumber(BigInteger.valueOf(1)); + certGen.setIssuerDN(new X509Principal(ord, values)); + certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000)); + certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000)); + certGen.setSubjectDN(new X509Principal(ord, values)); + certGen.setPublicKey(pubKey); + certGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); + + X509Certificate cert = certGen.generate(privKey); + + cert.checkValidity(new Date()); + + cert.verify(pubKey); + + Set dummySet = cert.getNonCriticalExtensionOIDs(); + if (dummySet != null) + { + fail("non-critical oid set should be null"); + } + dummySet = cert.getCriticalExtensionOIDs(); + if (dummySet != null) + { + fail("critical oid set should be null"); + } + + // + // create the certificate - version 3 - with subject unique ID + // + certGen = new X509V3CertificateGenerator(); + + certGen.setSerialNumber(BigInteger.valueOf(1)); + certGen.setIssuerDN(new X509Principal(ord, values)); + certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000)); + certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000)); + certGen.setSubjectDN(new X509Principal(ord, values)); + certGen.setPublicKey(pubKey); + certGen.setSignatureAlgorithm("MD5WithRSAEncryption"); + + boolean[] subjectUniqID = {true, false, false, false, true, false, false, true, false, true, true}; + + certGen.setSubjectUniqueID(subjectUniqID); + + boolean[] issuerUniqID = {false, false, true, false, true, false, false, false, true, false, false, true, false, true, true}; + + certGen.setIssuerUniqueID(issuerUniqID); + + cert = certGen.generate(privKey); + + cert.checkValidity(new Date()); + + cert.verify(pubKey); + + boolean[] subjectUniqueId = cert.getSubjectUniqueID(); + if (!Arrays.areEqual(subjectUniqID, subjectUniqueId)) + { + fail("Subject unique id is not correct, original: "+arrayToString(subjectUniqID)+", from cert: "+arrayToString(subjectUniqueId)); + } + + boolean[] issuerUniqueId = cert.getIssuerUniqueID(); + if (!Arrays.areEqual(issuerUniqID, issuerUniqueId)) + { + fail("Issuer unique id is not correct, original: "+arrayToString(issuerUniqID)+", from cert: "+arrayToString(subjectUniqueId)); + } + } + + private String arrayToString(boolean[] array) + { + StringBuffer b = new StringBuffer(); + + for (int i = 0; i != array.length; i++) + { + b.append(array[i] ? "1" : "0"); + } + + return b.toString(); + } + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new CertUniqueIDTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ChaCha20Poly1305Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ChaCha20Poly1305Test.java new file mode 100644 index 000000000..41fc2f14e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ChaCha20Poly1305Test.java @@ -0,0 +1,283 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.Key; +import java.security.Security; +import java.security.spec.AlgorithmParameterSpec; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.jcajce.spec.AEADParameterSpec; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ChaCha20Poly1305Test + extends SimpleTest +{ + private static final String[][] TEST_VECTORS = new String[][] { + { + "Test Case 1", + "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f", + "4c616469657320616e642047656e746c" + + "656d656e206f662074686520636c6173" + + "73206f66202739393a20496620492063" + + "6f756c64206f6666657220796f75206f" + + "6e6c79206f6e652074697020666f7220" + + "746865206675747572652c2073756e73" + + "637265656e20776f756c642062652069" + + "742e", + "50515253c0c1c2c3c4c5c6c7", + "070000004041424344454647", + "d31a8d34648e60db7b86afbc53ef7ec2" + + "a4aded51296e08fea9e2b5a736ee62d6" + + "3dbea45e8ca9671282fafb69da92728b" + + "1a71de0a9e060b2905d6a5b67ecd3b36" + + "92ddbd7f2d778b8c9803aee328091b58" + + "fab324e4fad675945585808b4831d7bc" + + "3ff4def08e4b7a9de576d26586cec64b" + + "6116", + "1ae10b594f09e26a7e902ecbd0600691", + }, + }; + + private boolean aeadAvailable = false; + + public String getName() + { + return "ChaCha20Poly1305"; + } + + public void performTest() throws Exception + { + try + { + this.getClass().getClassLoader().loadClass("javax.crypto.spec.GCMParameterSpec"); + aeadAvailable = true; + } + catch (ClassNotFoundException e) + { + } + + for (int i = 0; i < TEST_VECTORS.length; ++i) + { + runTestCase(TEST_VECTORS[i]); + } + + // basic test using oids + byte[] msg = Strings.toByteArray("Hello, world!"); + + KeyGenerator keyGen = KeyGenerator.getInstance(PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305.getId(), "BC"); + Cipher encCipher = Cipher.getInstance(PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305.getId(), "BC"); + SecretKey key = keyGen.generateKey(); + encCipher.init(Cipher.ENCRYPT_MODE, key); + + byte[] enc = encCipher.doFinal(msg); + + Cipher decCipher = Cipher.getInstance(PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305.getId(), "BC"); + + decCipher.init(Cipher.DECRYPT_MODE, key, encCipher.getParameters()); + + byte[] dec = decCipher.doFinal(enc); + + areEqual(msg, dec); + + // check mac failure + byte[] faulty = new byte[enc.length]; + System.arraycopy(enc, 0, faulty, 0, enc.length - 1); + + try + { + decCipher.doFinal(faulty); + fail("no exception"); + } + catch (Exception e) + { + if (aeadAvailable) + { + if (!e.getClass().getName().equals("javax.crypto.AEADBadTagException")) + { + fail("Tampered AEAD ciphertext should fail with AEADBadTagException when available."); + } + } + isEquals("mac check in ChaCha20Poly1305 failed", e.getMessage()); + } + + System.arraycopy(enc, 0, faulty, 0, enc.length); + faulty[0] ^= -1; + decCipher.init(Cipher.DECRYPT_MODE, key, encCipher.getParameters()); + try + { + decCipher.doFinal(faulty); + fail("no exception"); + } + catch (Exception e) + { + if (aeadAvailable) + { + if (!e.getClass().getName().equals("javax.crypto.AEADBadTagException")) + { + fail("Tampered AEAD ciphertext should fail with AEADBadTagException when available."); + } + } + isEquals("mac check in ChaCha20Poly1305 failed", e.getMessage()); + } + // + // check for alg params. + AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("ChaCha20-Poly1305", "BC"); // to be sure + algorithmParameters = AlgorithmParameters.getInstance(PKCSObjectIdentifiers.id_alg_AEADChaCha20Poly1305.getId(), "BC"); + } + + private void checkTestCase( + Cipher encCipher, + Cipher decCipher, + String testName, + byte[] SA, + byte[] P, + byte[] C, + byte[] T) + throws Exception + { + byte[] enc = new byte[encCipher.getOutputSize(P.length)]; + if (SA != null) + { + encCipher.updateAAD(SA, 0, SA.length); + } + int len = encCipher.update(P, 0, P.length, enc, 0); + len += encCipher.doFinal(enc, len); + + if (enc.length != len) + { + fail("encryption reported incorrect length: " + testName); + } + + //byte[] mac = encCipher.getMac(); + + byte[] data = new byte[P.length]; + System.arraycopy(enc, 0, data, 0, data.length); + byte[] tail = new byte[enc.length - P.length]; + System.arraycopy(enc, P.length, tail, 0, tail.length); + + if (!areEqual(C, data)) + { + fail("incorrect encrypt in: " + testName); + } + +// if (!areEqual(T, mac)) +// { +// fail("getMac() returned wrong mac in: " + testName); +// } + + if (!areEqual(T, tail)) + { + fail("stream contained wrong mac in: " + testName); + } + + byte[] dec = new byte[decCipher.getOutputSize(enc.length)]; + if (SA != null) + { + decCipher.updateAAD(SA, 0, SA.length); + } + len = decCipher.update(enc, 0, enc.length, dec, 0); + len += decCipher.doFinal(dec, len); + // mac = decCipher.getMac(); + + data = new byte[C.length]; + System.arraycopy(dec, 0, data, 0, data.length); + + if (!areEqual(P, data)) + { + fail("incorrect decrypt in: " + testName); + } + } + + private Cipher initCipher(boolean forEncryption, Key key, IvParameterSpec iv) + throws GeneralSecurityException + { + Cipher c = Cipher.getInstance("ChaCha20-Poly1305", "BC"); + + c.init(forEncryption ? Cipher.ENCRYPT_MODE : Cipher.DECRYPT_MODE, key, iv); + return c; + } + + private void runTestCase(String[] testVector) + throws Exception + { + int pos = 0; + String testName = testVector[pos++]; + byte[] K = Hex.decode(testVector[pos++]); + byte[] P = Hex.decode(testVector[pos++]); + byte[] A = Hex.decode(testVector[pos++]); + byte[] N = Hex.decode(testVector[pos++]); + byte[] C = Hex.decode(testVector[pos++]); + byte[] T = Hex.decode(testVector[pos++]); + + runTestCase(testName, K, N, A, P, C, T); + } + + private void runTestCase( + String testName, + byte[] K, + byte[] N, + byte[] A, + byte[] P, + byte[] C, + byte[] T) + throws Exception + { + byte[] fa = new byte[A.length / 2]; + byte[] la = new byte[A.length - (A.length / 2)]; + System.arraycopy(A, 0, fa, 0, fa.length); + System.arraycopy(A, fa.length, la, 0, la.length); + + runTestCase(testName + " all initial associated data", K, N, A, null, P, C, T); + + if (aeadAvailable) + { + runTestCase(testName + " all subsequent associated data", K, N, null, A, P, C, T); + runTestCase(testName + " split associated data", K, N, fa, la, P, C, T); + } + } + + private void runTestCase( + String testName, + byte[] K, + byte[] N, + byte[] A, + byte[] SA, + byte[] P, + byte[] C, + byte[] T) + throws Exception + { + SecretKeySpec keySpec = new SecretKeySpec(K, "ChaCha20"); + AEADParameterSpec parameters = new AEADParameterSpec(N, T.length * 8, A); + Cipher encCipher = initCipher(true, keySpec, parameters); + Cipher decCipher = initCipher(false, keySpec, parameters); + checkTestCase(encCipher, decCipher, testName, SA, P, C, T); + encCipher = initCipher(true, keySpec, parameters); + + AlgorithmParameters algParams = decCipher.getParameters(); + + IvParameterSpec ivSpec = (IvParameterSpec)algParams.getParameterSpec(AlgorithmParameterSpec.class); + + isTrue(areEqual(ivSpec.getIV(), N)); + isTrue(areEqual(encCipher.getIV(), N)); + + checkTestCase(encCipher, decCipher, testName + " (reused)", SA, P, C, T); + } + + public static void main(String[] args) throws Exception + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new ChaCha20Poly1305Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CipherStreamTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CipherStreamTest.java new file mode 100644 index 000000000..1f9fd1ef1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CipherStreamTest.java @@ -0,0 +1,448 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.ShortBufferException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +/** + * check that cipher input/output streams are working correctly + */ +public class CipherStreamTest + extends SimpleTest +{ + + private static byte[] RK = Hex.decode("0123456789ABCDEF"); + private static byte[] RIN = Hex.decode("4e6f772069732074"); + private static byte[] ROUT = Hex.decode("3afbb5c77938280d"); + + private static byte[] SIN = Hex.decode( + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"); + private static final byte[] SK = Hex.decode("80000000000000000000000000000000"); + private static final byte[] SIV = Hex.decode("0000000000000000"); + private static final byte[] SOUT = Hex.decode( + "4DFA5E481DA23EA09A31022050859936" + + "DA52FCEE218005164F267CB65F5CFD7F" + + "2B4F97E0FF16924A52DF269515110A07" + + "F9E460BC65EF95DA58F740B7D1DBB0AA"); + + private static final byte[] XSK = Hex.decode("d5c7f6797b7e7e9c1d7fd2610b2abf2bc5a7885fb3ff78092fb3abe8986d35e2"); + private static final byte[] XSIV = Hex.decode("744e17312b27969d826444640e9c4a378ae334f185369c95"); + private static final byte[] XSIN = Hex.decode("7758298c628eb3a4b6963c5445ef66971222be5d1a4ad839715d1188071739b77cc6e05d5410f963a64167629757"); + private static final byte[] XSOUT= Hex.decode("27b8cfe81416a76301fd1eec6a4d99675069b2da2776c360db1bdfea7c0aa613913e10f7a60fec04d11e65f2d64e"); + + private static final byte[] CHAK = Hex.decode("80000000000000000000000000000000"); + private static final byte[] CHAIV = Hex.decode("0000000000000000"); + private static final byte[] CHAIN = Hex.decode( + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"); + private static final byte[] CHAOUT = Hex.decode("FBB87FBB8395E05DAA3B1D683C422046" + + "F913985C2AD9B23CFC06C1D8D04FF213" + + "D44A7A7CDB84929F915420A8A3DC58BF" + + "0F7ECB4B1F167BB1A5E6153FDAF4493D"); + + private static final byte[] CHA7539K = Hex.decode("8000000000000000000000000000000080000000000000000000000000000000"); + private static final byte[] CHA7539IV = Hex.decode("000000000000000000000000"); + private static final byte[] CHA7539IN = Hex.decode( + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000" + + "00000000000000000000000000000000"); + private static final byte[] CHA7539OUT = Hex.decode("aef50e541e12a65dc21e90ebb4c03987971c540f78eb536df692ff89fc47561ed17eb23b63eb714c09d0c50af703e01485926c140e994b3edff9df635a91d268"); + + private static final byte[] HCIN = new byte[64]; + private static final byte[] HCIV = new byte[32]; + + private static final byte[] HCK256A = new byte[32]; + private static final byte[] HC256A = Hex.decode( + "5B078985D8F6F30D42C5C02FA6B67951" + + "53F06534801F89F24E74248B720B4818" + + "CD9227ECEBCF4DBF8DBF6977E4AE14FA" + + "E8504C7BC8A9F3EA6C0106F5327E6981"); + + private static final byte[] HCK128A = new byte[16]; + private static final byte[] HC128A = Hex.decode( + "82001573A003FD3B7FD72FFB0EAF63AA" + + "C62F12DEB629DCA72785A66268EC758B" + + "1EDB36900560898178E0AD009ABF1F49" + + "1330DC1C246E3D6CB264F6900271D59C"); + + private static final byte[] GRAIN_V1 = Hex.decode("0123456789abcdef1234"); + private static final byte[] GRAIN_V1_IV = Hex.decode("0123456789abcdef"); + private static final byte[] GRAIN_V1_IN = new byte[10]; + private static final byte[] GRAIN_V1_OUT = Hex.decode("7f362bd3f7abae203664"); + + private static final byte[] GRAIN_128 = Hex.decode("0123456789abcdef123456789abcdef0"); + private static final byte[] GRAIN_128_IV = Hex.decode("0123456789abcdef12345678"); + private static final byte[] GRAIN_128_IN = new byte[16]; + private static final byte[] GRAIN_128_OUT = Hex.decode("afb5babfa8de896b4b9c6acaf7c4fbfd"); + + public CipherStreamTest() + { + } + + private void runTest( + String name) + throws Exception + { + String lCode = "ABCDEFGHIJKLMNOPQRSTUVWXY0123456789"; + KeyGenerator kGen; + + if (name.indexOf('/') < 0) + { + kGen = KeyGenerator.getInstance(name, "BC"); + } + else + { + kGen = KeyGenerator.getInstance(name.substring(0, name.indexOf('/')), "BC"); + } + + byte[] data = lCode.getBytes(); + Cipher in = Cipher.getInstance(name, "BC"); + Cipher out = Cipher.getInstance(name, "BC"); + Key key = kGen.generateKey(); + ByteArrayInputStream bIn = new ByteArrayInputStream(data); + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + in.init(Cipher.ENCRYPT_MODE, key); + if (in.getIV() != null) + { + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(in.getIV())); + } + else + { + out.init(Cipher.DECRYPT_MODE, key); + } + + CipherInputStream cIn = new CipherInputStream(bIn, in); + CipherOutputStream cOut = new CipherOutputStream(bOut, out); + + int c; + + while ((c = cIn.read()) >= 0) + { + cOut.write(c); + } + + cIn.close(); + + cOut.flush(); + cOut.close(); + + String res = new String(bOut.toByteArray()); + + if (!res.equals(lCode)) + { + fail("Failed - decrypted data doesn't match."); + } + + + // + // short buffer test + // + try + { + byte[] enc = in.doFinal(data); + byte[] out1 = new byte[enc.length / 2]; + + try + { + out.doFinal(enc, 0, enc.length, out1, 0); + + fail("ShortBufferException not triggered"); + } + catch (ShortBufferException e) + { + byte[] out2 = new byte[in.getOutputSize(enc.length)]; + + int count = out.doFinal(enc, 0, enc.length, out2, 0); + + if (!areEqual(out2, count, data)) + { + fail("" + name + " failed decryption - expected " + new String(Hex.encode(data)) + " got " + new String(Hex.encode(out2))); + } + } + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail("" + name + " failed short buffer decryption - " + e.toString()); + } + + // mode test + if (name.indexOf('/') < 0) + { + Cipher.getInstance(name + "/NONE/NoPadding"); + Cipher.getInstance(name + "/ECB/NoPadding"); // very old school + } + } + + + private boolean areEqual(byte[] a, int aLen, byte[] b) + { + if (b.length != aLen) + { + return false; + } + + for (int i = 0; i != aLen; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + private void testAlgorithm(String name, byte[] keyBytes, byte[] iv, byte[] plainText, byte[] cipherText) + throws Exception + { + SecretKey key = new SecretKeySpec(keyBytes, name); + Cipher in = Cipher.getInstance(name, "BC"); + Cipher out = Cipher.getInstance(name, "BC"); + + if (iv != null) + { + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); + } + else + { + in.init(Cipher.ENCRYPT_MODE, key); + out.init(Cipher.DECRYPT_MODE, key); + } + + if (iv != null) + { + isTrue(Arrays.areEqual(iv, in.getIV())); + isTrue(Arrays.areEqual(iv, out.getIV())); + + AlgorithmParameters algParams = in.getParameters(); + + isTrue(Arrays.areEqual(iv, ((IvParameterSpec)algParams.getParameterSpec(IvParameterSpec.class)).getIV())); + + algParams = out.getParameters(); + isTrue(Arrays.areEqual(iv, ((IvParameterSpec)algParams.getParameterSpec(IvParameterSpec.class)).getIV())); + } + + byte[] enc = in.doFinal(plainText); + if (!areEqual(enc, cipherText)) + { + fail(name + ": cipher text doesn't match got " + new String(Hex.encode(enc))); + } + + byte[] dec = out.doFinal(enc); + + if (!areEqual(dec, plainText)) + { + fail(name + ": plain text doesn't match"); + } + } + + private void testException( + String name) + { + try + { + byte[] key128 = { + (byte)128, (byte)131, (byte)133, (byte)134, + (byte)137, (byte)138, (byte)140, (byte)143, + (byte)128, (byte)131, (byte)133, (byte)134, + (byte)137, (byte)138, (byte)140, (byte)143 }; + + byte[] key256 = { + (byte)128, (byte)131, (byte)133, (byte)134, + (byte)137, (byte)138, (byte)140, (byte)143, + (byte)128, (byte)131, (byte)133, (byte)134, + (byte)137, (byte)138, (byte)140, (byte)143, + (byte)128, (byte)131, (byte)133, (byte)134, + (byte)137, (byte)138, (byte)140, (byte)143, + (byte)128, (byte)131, (byte)133, (byte)134, + (byte)137, (byte)138, (byte)140, (byte)143 }; + + byte[] keyBytes; + if (name.equals("HC256") || name.equals("XSalsa20") || name.equals("ChaCha7539") || name.equals("ChaCha20")) + { + keyBytes = key256; + } + else + { + keyBytes = key128; + } + + SecretKeySpec cipherKey = new SecretKeySpec(keyBytes, name); + Cipher ecipher = Cipher.getInstance(name, "BC"); + ecipher.init(Cipher.ENCRYPT_MODE, cipherKey); + + byte[] cipherText = new byte[0]; + try + { + // According specification Method engineUpdate(byte[] input, + // int inputOffset, int inputLen, byte[] output, int + // outputOffset) + // throws ShortBufferException - if the given output buffer is + // too + // small to hold the result + ecipher.update(new byte[20], 0, 20, cipherText); + + fail("failed exception test - no ShortBufferException thrown"); + } + catch (ShortBufferException e) + { + // ignore + } + + try + { + Cipher c = Cipher.getInstance(name, "BC"); + + Key k = new PublicKey() + { + + public String getAlgorithm() + { + return "STUB"; + } + + public String getFormat() + { + return null; + } + + public byte[] getEncoded() + { + return null; + } + + }; + + c.init(Cipher.ENCRYPT_MODE, k); + + fail("failed exception test - no InvalidKeyException thrown for public key"); + } + catch (InvalidKeyException e) + { + // okay + } + + try + { + Cipher c = Cipher.getInstance(name, "BC"); + + Key k = new PrivateKey() + { + + public String getAlgorithm() + { + return "STUB"; + } + + public String getFormat() + { + return null; + } + + public byte[] getEncoded() + { + return null; + } + + }; + + c.init(Cipher.DECRYPT_MODE, k); + + fail("failed exception test - no InvalidKeyException thrown for private key"); + } + catch (InvalidKeyException e) + { + // okay + } + } + catch (Exception e) + { + fail("unexpected exception.", e); + } + } + + public void performTest() + throws Exception + { + runTest("RC4"); + testException("RC4"); + testAlgorithm("RC4", RK, null, RIN, ROUT); + runTest("Salsa20"); + testException("Salsa20"); + testAlgorithm("Salsa20", SK, SIV, SIN, SOUT); + runTest("XSalsa20"); + testException("XSalsa20"); + testAlgorithm("XSalsa20", XSK, XSIV, XSIN, XSOUT); + runTest("ChaCha"); + testException("ChaCha"); + testAlgorithm("ChaCha", CHAK, CHAIV, CHAIN, CHAOUT); + runTest("ChaCha7539"); + testException("ChaCha7539"); + testAlgorithm("ChaCha7539", CHA7539K, CHA7539IV, CHA7539IN, CHA7539OUT); + runTest("ChaCha20"); + testException("ChaCha20"); + testAlgorithm("ChaCha20", CHA7539K, CHA7539IV, CHA7539IN, CHA7539OUT); + runTest("HC128"); + testException("HC128"); + testAlgorithm("HC128", HCK128A, HCIV, HCIN, HC128A); + runTest("HC256"); + testException("HC256"); + testAlgorithm("HC256", HCK256A, HCIV, HCIN, HC256A); + runTest("VMPC"); + testException("VMPC"); + //testAlgorithm("VMPC", a, iv, in, a); + runTest("VMPC-KSA3"); + testException("VMPC-KSA3"); + //testAlgorithm("VMPC-KSA3", a, iv, in, a); + testAlgorithm("Grainv1", GRAIN_V1, GRAIN_V1_IV, GRAIN_V1_IN, GRAIN_V1_OUT); + testAlgorithm("Grain128", GRAIN_128, GRAIN_128_IV, GRAIN_128_IN, GRAIN_128_OUT); + runTest("DES/ECB/PKCS7Padding"); + runTest("DES/CFB8/NoPadding"); + } + + public String getName() + { + return "CipherStreamTest"; + } + + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new CipherStreamTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CipherStreamTest2.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CipherStreamTest2.java new file mode 100644 index 000000000..bae52fd9c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/CipherStreamTest2.java @@ -0,0 +1,525 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.Key; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.spec.IvParameterSpec; + +import com.fr.third.org.bouncycastle.crypto.io.InvalidCipherTextIOException; +import com.fr.third.org.bouncycastle.jcajce.io.CipherInputStream; +import com.fr.third.org.bouncycastle.jcajce.io.CipherOutputStream; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class CipherStreamTest2 + extends SimpleTest +{ + private int streamSize; + + public String getName() + { + return "CipherStreamTest2"; + } + + private void testModes(String algo, String[] transforms, boolean authenticated) + throws Exception + { + Key key = generateKey(algo); + for (int i = 0; i != transforms.length; i++) + { + String transform = transforms[i]; + String cipherName = algo + transform; + + boolean cts = transform.indexOf("CTS") > -1; + if (cts && streamSize < Cipher.getInstance(cipherName, "BC").getBlockSize()) + { + continue; + } + testWriteRead(cipherName, key, authenticated, true, false); + testWriteRead(cipherName, key, authenticated, true, true); + testWriteRead(cipherName, key, authenticated, false, false); + testWriteRead(cipherName, key, authenticated, false, true); + testReadWrite(cipherName, key, authenticated, true, false); + testReadWrite(cipherName, key, authenticated, true, true); + testReadWrite(cipherName, key, authenticated, false, false); + testReadWrite(cipherName, key, authenticated, false, true); + + if (!cts) + { + testWriteReadEmpty(cipherName, key, authenticated, true, false); + testWriteReadEmpty(cipherName, key, authenticated, true, true); + testWriteReadEmpty(cipherName, key, authenticated, false, false); + testWriteReadEmpty(cipherName, key, authenticated, false, true); + } + + if (authenticated) + { + testTamperedRead(cipherName, key, true, true); + testTamperedRead(cipherName, key, true, false); + testTruncatedRead(cipherName, key, true, true); + testTruncatedRead(cipherName, key, true, false); + testTamperedWrite(cipherName, key, true, true); + testTamperedWrite(cipherName, key, true, false); + } + } + } + + private InputStream createInputStream(byte[] data, Cipher cipher, boolean useBc) + { + ByteArrayInputStream bytes = new ByteArrayInputStream(data); + // cast required for earlier JDK + return useBc ? (InputStream)new CipherInputStream(bytes, cipher) : (InputStream)new javax.crypto.CipherInputStream(bytes, cipher); + } + + private OutputStream createOutputStream(ByteArrayOutputStream bytes, Cipher cipher, boolean useBc) + { + // cast required for earlier JDK + return useBc ? (OutputStream)new CipherOutputStream(bytes, cipher) : (OutputStream)new javax.crypto.CipherOutputStream(bytes, cipher); + } + + /** + * Test tampering of ciphertext followed by read from decrypting CipherInputStream + */ + private void testTamperedRead(String name, Key key, boolean authenticated, boolean useBc) + throws Exception + { + Cipher encrypt = Cipher.getInstance(name, "BC"); + Cipher decrypt = Cipher.getInstance(name, "BC"); + encrypt.init(Cipher.ENCRYPT_MODE, key); + if (encrypt.getIV() != null) + { + decrypt.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(encrypt.getIV())); + } + else + { + decrypt.init(Cipher.DECRYPT_MODE, key); + } + + byte[] ciphertext = encrypt.doFinal(new byte[streamSize]); + + // Tamper + ciphertext[0] += 1; + + InputStream input = createInputStream(ciphertext, decrypt, useBc); + try + { + while (input.read() >= 0) + { + } + fail("Expected invalid ciphertext after tamper and read : " + name, authenticated, useBc); + } + catch (InvalidCipherTextIOException e) + { + // Expected + } + catch (IOException e) // cause will be AEADBadTagException + { + // Expected + } + try + { + input.close(); + } + catch (Exception e) + { + fail("Unexpected exception : " + name, e, authenticated, useBc); + } + } + + /** + * Test truncation of ciphertext to make tag calculation impossible, followed by read from + * decrypting CipherInputStream + */ + private void testTruncatedRead(String name, Key key, boolean authenticated, boolean useBc) + throws Exception + { + Cipher encrypt = Cipher.getInstance(name, "BC"); + Cipher decrypt = Cipher.getInstance(name, "BC"); + encrypt.init(Cipher.ENCRYPT_MODE, key); + if (encrypt.getIV() != null) + { + decrypt.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(encrypt.getIV())); + } + else + { + decrypt.init(Cipher.DECRYPT_MODE, key); + } + + byte[] ciphertext = encrypt.doFinal(new byte[streamSize]); + + // Truncate to just smaller than complete tag + byte[] truncated = new byte[ciphertext.length - streamSize - 1]; + System.arraycopy(ciphertext, 0, truncated, 0, truncated.length); + + // Tamper + ciphertext[0] += 1; + + InputStream input = createInputStream(truncated, decrypt, useBc); + while (true) + { + int read = 0; + try + { + read = input.read(); + } + catch (InvalidCipherTextIOException e) + { + // Expected + break; + } + catch (IOException e) + { + // Expected from JDK 1.7 on + break; + } + catch (Exception e) + { + fail("Unexpected exception : " + name, e, authenticated, useBc); + break; + } + if (read < 0) + { + fail("Expected invalid ciphertext after truncate and read : " + name, authenticated, useBc); + break; + } + } + try + { + input.close(); + } + catch (Exception e) + { + fail("Unexpected exception : " + name, e, authenticated, useBc); + } + } + + /** + * Test tampering of ciphertext followed by write to decrypting CipherOutputStream + */ + private void testTamperedWrite(String name, Key key, boolean authenticated, boolean useBc) + throws Exception + { + Cipher encrypt = Cipher.getInstance(name, "BC"); + Cipher decrypt = Cipher.getInstance(name, "BC"); + encrypt.init(Cipher.ENCRYPT_MODE, key); + if (encrypt.getIV() != null) + { + decrypt.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(encrypt.getIV())); + } + else + { + decrypt.init(Cipher.DECRYPT_MODE, key); + } + + byte[] ciphertext = encrypt.doFinal(new byte[streamSize]); + + // Tamper + ciphertext[0] += 1; + + ByteArrayOutputStream plaintext = new ByteArrayOutputStream(); + OutputStream output = createOutputStream(plaintext, decrypt, useBc); + + for (int i = 0; i < ciphertext.length; i++) + { + output.write(ciphertext[i]); + } + try + { + output.close(); + fail("Expected invalid ciphertext after tamper and write : " + name, authenticated, useBc); + } + catch (InvalidCipherTextIOException e) + { + // Expected + } + } + + /** + * Test CipherOutputStream in ENCRYPT_MODE, CipherInputStream in DECRYPT_MODE + */ + private void testWriteRead(String name, Key key, boolean authenticated, boolean useBc, boolean blocks) + throws Exception + { + byte[] data = new byte[streamSize]; + for (int i = 0; i < data.length; i++) + { + data[i] = (byte)(i % 255); + } + + testWriteRead(name, key, authenticated, useBc, blocks, data); + } + + /** + * Test CipherOutputStream in ENCRYPT_MODE, CipherInputStream in DECRYPT_MODE + */ + private void testWriteReadEmpty(String name, Key key, boolean authenticated, boolean useBc, boolean blocks) + throws Exception + { + byte[] data = new byte[0]; + + testWriteRead(name, key, authenticated, useBc, blocks, data); + } + + private void testWriteRead(String name, Key key, boolean authenticated, boolean useBc, boolean blocks, byte[] data) + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try + { + Cipher encrypt = Cipher.getInstance(name, "BC"); + Cipher decrypt = Cipher.getInstance(name, "BC"); + encrypt.init(Cipher.ENCRYPT_MODE, key); + if (encrypt.getIV() != null) + { + decrypt.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(encrypt.getIV())); + } + else + { + decrypt.init(Cipher.DECRYPT_MODE, key); + } + + OutputStream cOut = createOutputStream(bOut, encrypt, useBc); + if (blocks) + { + int chunkSize = Math.max(1, data.length / 8); + for (int i = 0; i < data.length; i += chunkSize) + { + cOut.write(data, i, Math.min(chunkSize, data.length - i)); + } + } + else + { + for (int i = 0; i < data.length; i++) + { + cOut.write(data[i]); + } + } + cOut.close(); + + byte[] cipherText = bOut.toByteArray(); + bOut.reset(); + InputStream cIn = createInputStream(cipherText, decrypt, useBc); + + if (blocks) + { + byte[] block = new byte[encrypt.getBlockSize() + 1]; + int c; + while ((c = cIn.read(block)) >= 0) + { + bOut.write(block, 0, c); + } + } + else + { + int c; + while ((c = cIn.read()) >= 0) + { + bOut.write(c); + } + + } + cIn.close(); + + } + catch (Exception e) + { + fail("Unexpected exception " + name, e, authenticated, useBc); + } + + byte[] decrypted = bOut.toByteArray(); + if (!Arrays.areEqual(data, decrypted)) + { + fail("Failed - decrypted data doesn't match: " + name, authenticated, useBc); + } + } + + protected void fail(String message, boolean authenticated, boolean bc) + { + if (bc || !authenticated) + { + super.fail(message); + } + else + { + // javax.crypto.CipherInputStream/CipherOutputStream + // are broken wrt handling AEAD failures + // System.err.println("Broken JCE Streams: " + message); + } + } + + protected void fail(String message, Throwable throwable, boolean authenticated, boolean bc) + { + if (bc || !authenticated) + { + super.fail(message, throwable); + } + else + { + // javax.crypto.CipherInputStream/CipherOutputStream + // are broken wrt handling AEAD failures + //System.err.println("Broken JCE Streams: " + message + " : " + throwable); + throwable.printStackTrace(); + } + } + + /** + * Test CipherInputStream in ENCRYPT_MODE, CipherOutputStream in DECRYPT_MODE + */ + private void testReadWrite(String name, Key key, boolean authenticated, boolean useBc, boolean blocks) + throws Exception + { + String lCode = "ABCDEFGHIJKLMNOPQRSTU"; + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + try + { + Cipher in = Cipher.getInstance(name, "BC"); + Cipher out = Cipher.getInstance(name, "BC"); + in.init(Cipher.ENCRYPT_MODE, key); + if (in.getIV() != null) + { + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(in.getIV())); + } + else + { + out.init(Cipher.DECRYPT_MODE, key); + } + + InputStream cIn = createInputStream(lCode.getBytes(), in, useBc); + OutputStream cOut = createOutputStream(bOut, out, useBc); + + if (blocks) + { + byte[] block = new byte[in.getBlockSize() + 1]; + int c; + while ((c = cIn.read(block)) >= 0) + { + cOut.write(block, 0, c); + } + } + else + { + int c; + while ((c = cIn.read()) >= 0) + { + cOut.write(c); + } + } + + cIn.close(); + + cOut.flush(); + cOut.close(); + + } + catch (Exception e) + { + fail("Unexpected exception " + name, e, authenticated, useBc); + } + + String res = new String(bOut.toByteArray()); + if (!res.equals(lCode)) + { + fail("Failed - decrypted data doesn't match: " + name, authenticated, useBc); + } + } + + private static Key generateKey(String name) + throws Exception + { + KeyGenerator kGen; + + if (name.indexOf('/') < 0) + { + kGen = KeyGenerator.getInstance(name, "BC"); + } + else + { + kGen = KeyGenerator.getInstance(name.substring(0, name.indexOf('/')), "BC"); + } + return kGen.generateKey(); + } + + public void performTest() + throws Exception + { + int[] testSizes = new int[]{0, 1, 7, 8, 9, 15, 16, 17, 1023, 1024, 1025, 2047, 2048, 2049, 4095, 4096, 4097}; + for (int i = 0; i < testSizes.length; i++) + { + this.streamSize = testSizes[i]; + performTests(); + } + } + + private void performTests() + throws Exception + { + final String[] blockCiphers64 = new String[]{"BLOWFISH", "DES", "DESEDE", "TEA", "CAST5", "RC2", "XTEA"}; + + for (int i = 0; i != blockCiphers64.length; i++) + { + testModes(blockCiphers64[i], new String[]{ + "/ECB/PKCS5Padding", + "/CBC/PKCS5Padding", + "/OFB/NoPadding", + "/CFB/NoPadding", + "/CTS/NoPadding",}, false); + testModes(blockCiphers64[i], new String[]{"/EAX/NoPadding"}, true); + } + + final String[] blockCiphers128 = new String[]{ + "AES", + "NOEKEON", + "Twofish", + "CAST6", + "SEED", + "Serpent", + "RC6", + "CAMELLIA"}; + + for (int i = 0; i != blockCiphers128.length; i++) + { + testModes(blockCiphers128[i], new String[]{ + "/ECB/PKCS5Padding", + "/CBC/PKCS5Padding", + "/OFB/NoPadding", + "/CFB/NoPadding", + "/CTS/NoPadding", + "/CTR/NoPadding", + "/SIC/NoPadding"}, false); + testModes(blockCiphers128[i], new String[]{"/CCM/NoPadding", "/EAX/NoPadding", "/GCM/NoPadding", "/OCB/NoPadding"}, true); + } + + final String[] streamCiphers = new String[]{ + "ARC4", + "SALSA20", + "XSalsa20", + "ChaCha", + "ChaCha7539", + "Grainv1", + "Grain128", + "HC128", + "HC256"}; + + for (int i = 0; i != streamCiphers.length; i++) + { + testModes(streamCiphers[i], new String[]{""}, false); + } + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + runTest(new CipherStreamTest2()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DESedeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DESedeTest.java new file mode 100644 index 000000000..862816efb --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DESedeTest.java @@ -0,0 +1,326 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.KeyGenerator; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.DESedeKeySpec; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * basic test class for key generation for a DES-EDE block cipher, basically + * this just exercises the provider, and makes sure we are behaving sensibly, + * correctness of the implementation is shown in the lightweight test classes. + */ +public class DESedeTest + extends SimpleTest +{ + static String[] cipherTests1 = + { + "112", + "2f4bc6b30c893fa549d82c560d61cf3eb088aed020603de249d82c560d61cf3e529e95ecd8e05394", + "128", + "2f4bc6b30c893fa549d82c560d61cf3eb088aed020603de249d82c560d61cf3e529e95ecd8e05394", + "168", + "50ddb583a25c21e6c9233f8e57a86d40bb034af421c03096c9233f8e57a86d402fce91e8eb639f89", + "192", + "50ddb583a25c21e6c9233f8e57a86d40bb034af421c03096c9233f8e57a86d402fce91e8eb639f89", + }; + + static byte[] input1 = Hex.decode("000102030405060708090a0b0c0d0e0fff0102030405060708090a0b0c0d0e0f"); + + /** + * a fake random number generator - we just want to make sure the random numbers + * aren't random so that we get the same output, while still getting to test the + * key generation facilities. + */ + private class FixedSecureRandom + extends SecureRandom + { + byte[] seed = { + (byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59, + (byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4, + (byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde, + (byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f + }; + + public void nextBytes( + byte[] bytes) + { + int offset = 0; + + while ((offset + seed.length) < bytes.length) + { + System.arraycopy(seed, 0, bytes, offset, seed.length); + offset += seed.length; + } + + System.arraycopy(seed, 0, bytes, offset, bytes.length - offset); + } + } + + public String getName() + { + return "DESEDE"; + } + + private boolean equalArray( + byte[] a, + byte[] b) + { + if (a.length != b.length) + { + return false; + } + + for (int i = 0; i != a.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + private boolean equalArray( + byte[] a, + byte[] b, + int length) + { + if (a.length < length) + { + return false; + } + + if (b.length < length) + { + return false; + } + + for (int i = 0; i != length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + private void wrapTest( + String alg, + int id, + byte[] kek, + byte[] iv, + byte[] in, + byte[] out) + { + try + { + Cipher wrapper = Cipher.getInstance(alg + "Wrap", "BC"); + + wrapper.init(Cipher.WRAP_MODE, new SecretKeySpec(kek, alg), new IvParameterSpec(iv)); + + try + { + byte[] cText = wrapper.wrap(new SecretKeySpec(in, alg)); + if (!equalArray(cText, out)) + { + fail("failed wrap test " + id + " expected " + new String(Hex.encode(out)) + " got " + new String(Hex.encode(cText))); + } + } + catch (Exception e) + { + fail("failed wrap test exception " + e.toString()); + } + + wrapper.init(Cipher.UNWRAP_MODE, new SecretKeySpec(kek, alg)); + + try + { + Key pText = wrapper.unwrap(out, alg, Cipher.SECRET_KEY); + if (!equalArray(pText.getEncoded(), in)) + { + fail("failed unwrap test " + id + " expected " + new String(Hex.encode(in)) + " got " + new String(Hex.encode(pText.getEncoded()))); + } + } + catch (Exception e) + { + fail("failed unwrap test exception " + e.toString()); + } + } + catch (Exception ex) + { + fail("failed exception " + ex.toString()); + } + } + + public void test( + String alg, + int strength, + byte[] input, + byte[] output) + { + Key key = null; + KeyGenerator keyGen; + SecureRandom rand; + Cipher in = null; + Cipher out = null; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + rand = new FixedSecureRandom(); + + try + { + keyGen = KeyGenerator.getInstance(alg, "BC"); + keyGen.init(strength, rand); + + key = keyGen.generateKey(); + + in = Cipher.getInstance(alg + "/ECB/PKCS7Padding", "BC"); + out = Cipher.getInstance(alg + "/ECB/PKCS7Padding", "BC"); + + out.init(Cipher.ENCRYPT_MODE, key, rand); + } + catch (Exception e) + { + fail(alg + " failed initialisation - " + e.toString()); + } + + try + { + in.init(Cipher.DECRYPT_MODE, key); + } + catch (Exception e) + { + fail(alg + " failed initialisation - " + e.toString()); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail(alg + " failed encryption - " + e.toString()); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!equalArray(bytes, output)) + { + fail(alg + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + } + catch (Exception e) + { + fail(alg + " failed encryption - " + e.toString()); + } + + if (!equalArray(bytes, input)) + { + fail(alg + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + + // + // keyspec test + // + try + { + SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(alg, "BC"); + DESedeKeySpec keySpec = (DESedeKeySpec)keyFactory.getKeySpec((SecretKey)key, DESedeKeySpec.class); + + if (!equalArray(key.getEncoded(), keySpec.getKey(), 16)) + { + fail(alg + " KeySpec does not match key."); + } + } + catch (Exception e) + { + fail(alg + " failed keyspec - " + e.toString()); + } + } + + public void performTest() + { + for (int i = 0; i != cipherTests1.length; i += 2) + { + test("DESEDE", Integer.parseInt(cipherTests1[i]), input1, Hex.decode(cipherTests1[i + 1])); + } + + for (int i = 0; i != cipherTests1.length; i += 2) + { + test("TDEA", Integer.parseInt(cipherTests1[i]), input1, Hex.decode(cipherTests1[i + 1])); + } + + byte[] kek1 = Hex.decode("255e0d1c07b646dfb3134cc843ba8aa71f025b7c0838251f"); + byte[] iv1 = Hex.decode("5dd4cbfc96f5453b"); + byte[] in1 = Hex.decode("2923bf85e06dd6ae529149f1f1bae9eab3a7da3d860d3e98"); + byte[] out1 = Hex.decode("690107618ef092b3b48ca1796b234ae9fa33ebb4159604037db5d6a84eb3aac2768c632775a467d4"); + + wrapTest("DESEDE", 1, kek1, iv1, in1, out1); + wrapTest("TDEA", 1, kek1, iv1, in1, out1); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new DESedeTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DHIESTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DHIESTest.java new file mode 100644 index 000000000..f1cabfd72 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DHIESTest.java @@ -0,0 +1,282 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; + +import com.fr.third.org.bouncycastle.crypto.agreement.DHBasicAgreement; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.IESEngine; +import com.fr.third.org.bouncycastle.crypto.generators.KDF2BytesGenerator; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.dh.IESCipher; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.IESParameterSpec; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test for DHIES - Diffie-Hellman Integrated Encryption Scheme + */ +public class DHIESTest + extends SimpleTest +{ + // Oakley group 2 - RFC 5996 + BigInteger p1024 = new BigInteger( + "FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD1" + + "29024E088A67CC74020BBEA63B139B22514A08798E3404DD" + + "EF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245" + + "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" + + "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" + + "FFFFFFFFFFFFFFFF",16); + + BigInteger g1024 = new BigInteger("2",16); + + BigInteger p2048 = new BigInteger("95475cf5d93e596c3fcd1d902add02f427f5f3c7210313bb45fb4d5b" + + "b2e5fe1cbd678cd4bbdd84c9836be1f31c0777725aeb6c2fc38b85f4" + + "8076fa76bcd8146cc89a6fb2f706dd719898c2083dc8d896f84062e2" + + "c9c94d137b054a8d8096adb8d51952398eeca852a0af12df83e475aa" + + "65d4ec0c38a9560d5661186ff98b9fc9eb60eee8b030376b236bc73b" + + "e3acdbd74fd61c1d2475fa3077b8f080467881ff7e1ca56fee066d79" + + "506ade51edbb5443a563927dbc4ba520086746175c8885925ebc64c6" + + "147906773496990cb714ec667304e261faee33b3cbdf008e0c3fa906" + + "50d97d3909c9275bf4ac86ffcb3d03e6dfc8ada5934242dd6d3bcca2" + + "a406cb0b", 16); + + BigInteger g2048 = new BigInteger("42debb9da5b3d88cc956e08787ec3f3a09bba5f48b889a74aaf53174" + + "aa0fbe7e3c5b8fcd7a53bef563b0e98560328960a9517f4014d3325f" + + "c7962bf1e049370d76d1314a76137e792f3f0db859d095e4a5b93202" + + "4f079ecf2ef09c797452b0770e1350782ed57ddf794979dcef23cb96" + + "f183061965c4ebc93c9c71c56b925955a75f94cccf1449ac43d586d0" + + "beee43251b0b2287349d68de0d144403f13e802f4146d882e057af19" + + "b6f6275c6676c8fa0e3ca2713a3257fd1b27d0639f695e347d8d1cf9" + + "ac819a26ca9b04cb0eb9b7b035988d15bbac65212a55239cfc7e58fa" + + "e38d7250ab9991ffbc97134025fe8ce04c4399ad96569be91a546f49" + + "78693c7a", 16); + + DHParameterSpec param1024 = new DHParameterSpec(p1024, g1024); + + DHParameterSpec param2048 = new DHParameterSpec(p2048, g2048); + + DHIESTest() + { + } + + public String getName() + { + return "DHIES"; + } + + public void performTest() + throws Exception + { + byte[] derivation = Hex.decode("202122232425262728292a2b2c2d2e2f"); + byte[] encoding = Hex.decode("303132333435363738393a3b3c3d3e3f"); + + + IESCipher c1 = new com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.dh.IESCipher.IES(); + IESCipher c2 = new com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.dh.IESCipher.IES(); + IESParameterSpec params = new IESParameterSpec(derivation,encoding,128); + + // Testing DHIES with default prime in streaming mode + KeyPairGenerator g = KeyPairGenerator.getInstance("DH", "BC"); + KeyPairGenerator g512 = KeyPairGenerator.getInstance("DH", "BC"); + + g.initialize(param1024); + + doTest("DHIES with default", g, "DHIES", params); + + // Testing DHIES with 512-bit prime in streaming mode + g512.initialize(512, new SecureRandom()); + doTest("DHIES with 512-bit", g512, "DHIES", params); + + // Testing ECIES with 1024-bit prime in streaming mode + g.initialize(param1024, new SecureRandom()); + doTest("DHIES with 1024-bit", g, "DHIES", params); + + c1 = new IESCipher(new IESEngine(new DHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + new PaddedBufferedBlockCipher(new DESEngine()))); + + c2 = new IESCipher(new IESEngine(new DHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + new PaddedBufferedBlockCipher(new DESEngine()))); + + params = new IESParameterSpec(derivation, encoding, 128, 192, Hex.decode("0001020304050607")); + + // Testing DHIES with default prime (2048) using DESEDE + g = KeyPairGenerator.getInstance("DH", "BC"); + g.initialize(param2048, new SecureRandom()); + + doTest("DHIESwithDES default", g, "DHIESwithDESEDE-CBC", params); + + // Testing DHIES with 512-bit prime using DESEDE + doTest("DHIESwithDES 512-bit", g512, "DHIESwithDESEDE-CBC", params); + + // Testing DHIES with 1024-bit prime using DESEDE + g.initialize(param1024, new SecureRandom()); + doTest("DHIESwithDES 1024-bit", g, "DHIESwithDESEDE-CBC", params); + + g = KeyPairGenerator.getInstance("DH", "BC"); + g.initialize(param1024); + + c1 = new IESCipher.IESwithAESCBC(); + c2 = new IESCipher.IESwithAESCBC(); + params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("00010203040506070001020304050607")); + + // Testing DHIES with default prime using AES + doTest("DHIESwithAES default", g, "DHIESwithAES-CBC", params); + + // Testing DHIES with 512-bit prime using AES + doTest("DHIESwithAES 512-bit", g512, "DHIESwithAES-CBC", params); + + // Testing DHIES with 1024-bit prime using AES + g.initialize(param1024, new SecureRandom()); + doTest("DHIESwithAES 1024-bit", g, "DHIESwithAES-CBC", params); + + KeyPair keyPair = g.generateKeyPair(); + DHPublicKey pub = (DHPublicKey)keyPair.getPublic(); + DHPrivateKey priv = (DHPrivateKey)keyPair.getPrivate(); + + Cipher c = Cipher.getInstance("DHIESwithAES-CBC", "BC"); + + try + { + c.init(Cipher.ENCRYPT_MODE, pub, new IESParameterSpec(derivation, encoding, 128, 128, null)); + + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + + try + { + c.init(Cipher.DECRYPT_MODE, priv); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isTrue("message ", "cannot handle supplied parameter spec: NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + + try + { + c.init(Cipher.DECRYPT_MODE, priv, new IESParameterSpec(derivation, encoding, 128, 128, null)); + + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + } + + public void doTest( + String testname, + KeyPairGenerator g, + String cipher, + IESParameterSpec p) + throws Exception + { + + byte[] message = Hex.decode("0102030405060708090a0b0c0d0e0f10111213141516"); + byte[] out1, out2; + + Cipher c1 = Cipher.getInstance(cipher, "BC"); + Cipher c2 = Cipher.getInstance(cipher, "BC"); + // Generate static key pair + KeyPair keyPair = g.generateKeyPair(); + DHPublicKey pub = (DHPublicKey)keyPair.getPublic(); + DHPrivateKey priv = (DHPrivateKey)keyPair.getPrivate(); + + // Testing with default parameters and DHAES mode off + c1.init(Cipher.ENCRYPT_MODE, pub, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, priv, c1.getParameters()); + + isTrue("nonce mismatch", Arrays.areEqual(c1.getIV(), c2.getIV())); + + out1 = c1.doFinal(message, 0, message.length); + out2 = c2.doFinal(out1, 0, out1.length); + if (!areEqual(out2, message)) + { + fail(testname + " test failed with default parameters, DHAES mode false."); + } + + // Testing with given parameters and DHAES mode off + c1.init(Cipher.ENCRYPT_MODE, pub, p, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, priv, p); + out1 = c1.doFinal(message, 0, message.length); + out2 = c2.doFinal(out1, 0, out1.length); + if (!areEqual(out2, message)) + fail(testname + " test failed with non-null parameters, DHAES mode false."); + + // Testing with null parameters and DHAES mode on + c1 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC"); + c2 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC"); + c1.init(Cipher.ENCRYPT_MODE, pub, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, priv, c1.getParameters(), new SecureRandom()); + out1 = c1.doFinal(message, 0, message.length); + out2 = c2.doFinal(out1, 0, out1.length); + if (!areEqual(out2, message)) + fail(testname + " test failed with null parameters, DHAES mode true."); + + + // Testing with given parameters and DHAES mode on + c1 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC"); + c2 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC"); + + c1.init(Cipher.ENCRYPT_MODE, pub, p, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, priv, p, new SecureRandom()); + + out1 = c1.doFinal(message, 0, message.length); + out2 = c2.doFinal(out1, 0, out1.length); + if (!areEqual(out2, message)) + fail(testname + " test failed with non-null parameters, DHAES mode true."); + + // + // corrupted data test + // + byte[] tmp = new byte[out1.length]; + for (int i = 0; i != out1.length; i++) + { + System.arraycopy(out1, 0, tmp, 0, tmp.length); + tmp[i] = (byte)~tmp[i]; + + try + { + c2.doFinal(tmp, 0, tmp.length); + + fail("decrypted corrupted data"); + } + catch (BadPaddingException e) + { + isTrue("wrong message: " + e.getMessage(), "unable to process block".equals(e.getMessage())); + } + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new DHIESTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DHTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DHTest.java new file mode 100644 index 000000000..d90e94e8e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DHTest.java @@ -0,0 +1,1580 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.math.BigInteger; +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECFieldFp; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.EllipticCurve; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.KeyAgreement; +import javax.crypto.SecretKey; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DESKeySpec; +import javax.crypto.spec.DESedeKeySpec; +import javax.crypto.spec.DHParameterSpec; +import javax.crypto.spec.DHPrivateKeySpec; +import javax.crypto.spec.DHPublicKeySpec; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.agreement.DHStandardGroups; +import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import com.fr.third.org.bouncycastle.jcajce.spec.DHDomainParameterSpec; +import com.fr.third.org.bouncycastle.jcajce.spec.DHUParameterSpec; +import com.fr.third.org.bouncycastle.jcajce.spec.MQVParameterSpec; +import com.fr.third.org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec; +import com.fr.third.org.bouncycastle.jce.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.jce.ECPointUtil; +import com.fr.third.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class DHTest + extends SimpleTest +{ + private BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + private BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + private BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16); + private BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16); + + private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16); + private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16); + + // public key with mismatched oid/parameters + private byte[] oldPubEnc = Base64.decode( + "MIIBnzCCARQGByqGSM4+AgEwggEHAoGBAPxSrN417g43VAM9sZRf1dt6AocAf7D6" + + "WVCtqEDcBJrMzt63+g+BNJzhXVtbZ9kp9vw8L/0PHgzv0Ot/kOLX7Khn+JalOECW" + + "YlkyBhmOVbjR79TY5u2GAlvG6pqpizieQNBCEMlUuYuK1Iwseil6VoRuA13Zm7uw" + + "WO1eZmaJtY7LAoGAQaPRCFKM5rEdkMrV9FNzeSsYRs8m3DqPnnJHpuySpyO9wUcX" + + "OOJcJY5qvHbDO5SxHXu/+bMgXmVT6dXI5o0UeYqJR7fj6pR4E6T0FwG55RFr5Ok4" + + "3C4cpXmaOu176SyWuoDqGs1RDGmYQjwbZUi23DjaaTFUly9LCYXMliKrQfEDgYQA" + + "AoGAQUGCBN4TaBw1BpdBXdTvTfCU69XDB3eyU2FOBE3UWhpx9D8XJlx4f5DpA4Y6" + + "6sQMuCbhfmjEph8W7/sbMurM/awR+PSR8tTY7jeQV0OkmAYdGK2nzh0ZSifMO1oE" + + "NNhN2O62TLs67msxT28S4/S89+LMtc98mevQ2SX+JF3wEVU="); + + // bogus key with full PKCS parameter set + private byte[] oldFullParams = Base64.decode( + "MIIBIzCCARgGByqGSM4+AgEwggELAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E" + + "AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f" + + "6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv" + + "8iIDGZ3RSAHHAoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlX" + + "jrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6j" + + "fwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqAgFk" + + "AwUAAgIH0A=="); + + private byte[] samplePubEnc = Base64.decode( + "MIIBpjCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YRt1I8" + + "70QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWk" + + "n5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HX" + + "Ku/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdR" + + "WVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWR" + + "bqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoC" + + "AgIAA4GEAAKBgEIiqxoUW6E6GChoOgcfNbVFclW91ITf5MFSUGQwt2R0RHoOhxvO" + + "lZhNs++d0VPATLAyXovjfgENT9SGCbuZttYcqqLdKTbMXBWPek+rfnAl9E4iEMED" + + "IDd83FJTKs9hQcPAm7zmp0Xm1bGF9CbUFjP5G02265z7eBmHDaT0SNlB"); + + private byte[] samplePrivEnc = Base64.decode( + "MIIBZgIBADCCARsGCSqGSIb3DQEDATCCAQwCgYEA/X9TgR11EilS30qcLuzk5/YR" + + "t1I870QAwx4/gLZRJmlFXUAiUftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZ" + + "UKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7g/bTxR7DAjVUE1oWkTL2dfOu" + + "K2HXKu/yIgMZndFIAccCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0H" + + "gmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuz" + + "pnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7P" + + "SSoCAgIABEICQAZYXnBHazxXUUdFP4NIf2Ipu7du0suJPZQKKff81wymi2zfCfHh" + + "uhe9gQ9xdm4GpzeNtrQ8/MzpTy+ZVrtd29Q="); + + public String getName() + { + return "DH"; + } + + private void testGP( + String algName, + int size, + int privateValueSize, + BigInteger g, + BigInteger p) + throws Exception + { + DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algName, "BC"); + + keyGen.initialize(dhParams); + + testTwoParty(algName, size, privateValueSize, keyGen); + + KeyPair aKeyPair = keyGen.generateKeyPair(); + + // + // public key encoding test + // + byte[] pubEnc = aKeyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(algName, "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); + DHParameterSpec spec = pubKey.getParams(); + + if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) + { + fail(size + " bit public key encoding/decoding test failed on parameters"); + } + + if (!((DHPublicKey)aKeyPair.getPublic()).getY().equals(pubKey.getY())) + { + fail(size + " bit public key encoding/decoding test failed on y value"); + } + + // + // public key serialisation test + // + pubKey = (DHPublicKey)serializeDeserialize(aKeyPair.getPublic()); + spec = pubKey.getParams(); + + if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) + { + fail(size + " bit public key serialisation test failed on parameters"); + } + + if (!((DHPublicKey)aKeyPair.getPublic()).getY().equals(pubKey.getY())) + { + fail(size + " bit public key serialisation test failed on y value"); + } + + if (!aKeyPair.getPublic().equals(pubKey)) + { + fail("equals test failed"); + } + + if (aKeyPair.getPublic().hashCode() != pubKey.hashCode()) + { + fail("hashCode test failed"); + } + + // + // private key encoding test + // + byte[] privEnc = aKeyPair.getPrivate().getEncoded(); + PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); + DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); + + spec = privKey.getParams(); + + if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) + { + fail(size + " bit private key encoding/decoding test failed on parameters"); + } + + if (!((DHPrivateKey)aKeyPair.getPrivate()).getX().equals(privKey.getX())) + { + fail(size + " bit private key encoding/decoding test failed on y value"); + } + + // + // private key serialisation test + // + privKey = (DHPrivateKey)serializeDeserialize(aKeyPair.getPrivate()); + spec = privKey.getParams(); + + if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) + { + fail(size + " bit private key serialisation test failed on parameters"); + } + + if (!((DHPrivateKey)aKeyPair.getPrivate()).getX().equals(privKey.getX())) + { + fail(size + " bit private key serialisation test failed on X value"); + } + + if (!aKeyPair.getPrivate().equals(privKey)) + { + fail("equals test failed"); + } + + if (aKeyPair.getPrivate().hashCode() != privKey.hashCode()) + { + fail("hashCode test failed"); + } + + if (!(privKey instanceof PKCS12BagAttributeCarrier)) + { + fail("private key not implementing PKCS12 attribute carrier"); + } + + // + // three party test + // + KeyPairGenerator aPairGen = KeyPairGenerator.getInstance(algName, "BC"); + aPairGen.initialize(spec); + KeyPair aPair = aPairGen.generateKeyPair(); + + KeyPairGenerator bPairGen = KeyPairGenerator.getInstance(algName, "BC"); + bPairGen.initialize(spec); + KeyPair bPair = bPairGen.generateKeyPair(); + + KeyPairGenerator cPairGen = KeyPairGenerator.getInstance(algName, "BC"); + cPairGen.initialize(spec); + KeyPair cPair = cPairGen.generateKeyPair(); + + KeyAgreement aKeyAgree = KeyAgreement.getInstance(algName, "BC"); + aKeyAgree.init(aPair.getPrivate()); + + KeyAgreement bKeyAgree = KeyAgreement.getInstance(algName, "BC"); + bKeyAgree.init(bPair.getPrivate()); + + KeyAgreement cKeyAgree = KeyAgreement.getInstance(algName, "BC"); + cKeyAgree.init(cPair.getPrivate()); + + Key ac = aKeyAgree.doPhase(cPair.getPublic(), false); + + Key ba = bKeyAgree.doPhase(aPair.getPublic(), false); + + Key cb = cKeyAgree.doPhase(bPair.getPublic(), false); + + aKeyAgree.doPhase(cb, true); + + bKeyAgree.doPhase(ac, true); + + cKeyAgree.doPhase(ba, true); + + BigInteger aShared = new BigInteger(aKeyAgree.generateSecret()); + BigInteger bShared = new BigInteger(bKeyAgree.generateSecret()); + BigInteger cShared = new BigInteger(cKeyAgree.generateSecret()); + + if (!aShared.equals(bShared)) + { + fail(size + " bit 3-way test failed (a and b differ)"); + } + + if (!cShared.equals(bShared)) + { + fail(size + " bit 3-way test failed (c and b differ)"); + } + + KeyAgreement noKdf = KeyAgreement.getInstance("DH", "BC"); + + + try + { + noKdf.init(aPair.getPrivate(), new UserKeyingMaterialSpec(new byte[20])); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("no KDF specified for UserKeyingMaterialSpec".equals(e.getMessage())); + } + } + + private void testTwoParty(String algName, int size, int privateValueSize, KeyPairGenerator keyGen) + throws Exception + { + testTwoParty(algName, size, privateValueSize, keyGen.generateKeyPair(), keyGen.generateKeyPair()); + } + + private byte[] testTwoParty(String algName, int size, int privateValueSize, KeyPair aKeyPair, KeyPair bKeyPair) + throws Exception + { + // + // a side + // + KeyAgreement aKeyAgree = KeyAgreement.getInstance(algName, "BC"); + + checkKeySize(privateValueSize, aKeyPair); + + aKeyAgree.init(aKeyPair.getPrivate()); + + // + // b side + // + KeyAgreement bKeyAgree = KeyAgreement.getInstance(algName, "BC"); + + checkKeySize(privateValueSize, bKeyPair); + + bKeyAgree.init(bKeyPair.getPrivate()); + + // + // agreement + // + aKeyAgree.doPhase(bKeyPair.getPublic(), true); + bKeyAgree.doPhase(aKeyPair.getPublic(), true); + + byte[] aSecret = aKeyAgree.generateSecret(); + byte[] bSecret = bKeyAgree.generateSecret(); + + if (!Arrays.areEqual(aSecret, bSecret)) + { + fail(size + " bit 2-way test failed"); + } + + return aSecret; + } + + private void testExplicitWrapping( + int size, + int privateValueSize, + BigInteger g, + BigInteger p) + throws Exception + { + DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); + + keyGen.initialize(dhParams); + + // + // a side + // + KeyPair aKeyPair = keyGen.generateKeyPair(); + + KeyAgreement aKeyAgree = KeyAgreement.getInstance("DH", "BC"); + + checkKeySize(privateValueSize, aKeyPair); + + aKeyAgree.init(aKeyPair.getPrivate()); + + // + // b side + // + KeyPair bKeyPair = keyGen.generateKeyPair(); + + KeyAgreement bKeyAgree = KeyAgreement.getInstance("DH", "BC"); + + checkKeySize(privateValueSize, bKeyPair); + + bKeyAgree.init(bKeyPair.getPrivate()); + + // + // agreement + // + aKeyAgree.doPhase(bKeyPair.getPublic(), true); + bKeyAgree.doPhase(aKeyPair.getPublic(), true); + + SecretKey k1 = aKeyAgree.generateSecret(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId()); + SecretKey k2 = bKeyAgree.generateSecret(PKCSObjectIdentifiers.id_alg_CMS3DESwrap.getId()); + + // TODO Compare k1 and k2? + } + + private Object serializeDeserialize(Object o) + throws Exception + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(o); + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + return oIn.readObject(); + } + + private void checkKeySize(int privateValueSize, KeyPair aKeyPair) + { + if (privateValueSize != 0) + { + DHPrivateKey key = (DHPrivateKey)aKeyPair.getPrivate(); + + if (key.getX().bitLength() != privateValueSize) + { + fail("limited key check failed for key size " + privateValueSize); + } + } + } + + private void testRandom( + int size) + throws Exception + { + AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("DH", "BC"); + a.init(size, new SecureRandom()); + AlgorithmParameters params = a.generateParameters(); + + byte[] encodeParams = params.getEncoded(); + + AlgorithmParameters a2 = AlgorithmParameters.getInstance("DH", "BC"); + a2.init(encodeParams); + + // a and a2 should be equivalent! + byte[] encodeParams_2 = a2.getEncoded(); + + if (!areEqual(encodeParams, encodeParams_2)) + { + fail("encode/decode parameters failed"); + } + + DHParameterSpec dhP = (DHParameterSpec)params.getParameterSpec(DHParameterSpec.class); + + testGP("DH", size, 0, dhP.getG(), dhP.getP()); + } + + private void testDefault( + int privateValueSize, + BigInteger g, + BigInteger p) + throws Exception + { + DHParameterSpec dhParams = new DHParameterSpec(p, g, privateValueSize); + String algName = "DH"; + int size = p.bitLength(); + + new BouncyCastleProvider().setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, dhParams); + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance(algName, "BC"); + + keyGen.initialize(dhParams.getP().bitLength()); + + testTwoParty("DH", size, privateValueSize, keyGen); + + KeyPair aKeyPair = keyGen.generateKeyPair(); + + new BouncyCastleProvider().setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, null); + + // + // public key encoding test + // + byte[] pubEnc = aKeyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(algName, "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); + DHParameterSpec spec = pubKey.getParams(); + + if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) + { + fail(size + " bit public key encoding/decoding test failed on parameters"); + } + + if (!((DHPublicKey)aKeyPair.getPublic()).getY().equals(pubKey.getY())) + { + fail(size + " bit public key encoding/decoding test failed on y value"); + } + + // + // public key serialisation test + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(aKeyPair.getPublic()); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + ObjectInputStream oIn = new ObjectInputStream(bIn); + + pubKey = (DHPublicKey)oIn.readObject(); + spec = pubKey.getParams(); + + if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) + { + fail(size + " bit public key serialisation test failed on parameters"); + } + + if (!((DHPublicKey)aKeyPair.getPublic()).getY().equals(pubKey.getY())) + { + fail(size + " bit public key serialisation test failed on y value"); + } + + // + // private key encoding test + // + byte[] privEnc = aKeyPair.getPrivate().getEncoded(); + PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); + DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); + + spec = privKey.getParams(); + + if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) + { + fail(size + " bit private key encoding/decoding test failed on parameters"); + } + + if (!((DHPrivateKey)aKeyPair.getPrivate()).getX().equals(privKey.getX())) + { + fail(size + " bit private key encoding/decoding test failed on y value"); + } + + // + // private key serialisation test + // + bOut = new ByteArrayOutputStream(); + oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(aKeyPair.getPrivate()); + + bIn = new ByteArrayInputStream(bOut.toByteArray()); + oIn = new ObjectInputStream(bIn); + + privKey = (DHPrivateKey)oIn.readObject(); + spec = privKey.getParams(); + + if (!spec.getG().equals(dhParams.getG()) || !spec.getP().equals(dhParams.getP())) + { + fail(size + " bit private key serialisation test failed on parameters"); + } + + if (!((DHPrivateKey)aKeyPair.getPrivate()).getX().equals(privKey.getX())) + { + fail(size + " bit private key serialisation test failed on y value"); + } + + // + // three party test + // + KeyPairGenerator aPairGen = KeyPairGenerator.getInstance(algName, "BC"); + aPairGen.initialize(spec); + KeyPair aPair = aPairGen.generateKeyPair(); + + KeyPairGenerator bPairGen = KeyPairGenerator.getInstance(algName, "BC"); + bPairGen.initialize(spec); + KeyPair bPair = bPairGen.generateKeyPair(); + + KeyPairGenerator cPairGen = KeyPairGenerator.getInstance(algName, "BC"); + cPairGen.initialize(spec); + KeyPair cPair = cPairGen.generateKeyPair(); + + KeyAgreement aKeyAgree = KeyAgreement.getInstance(algName, "BC"); + aKeyAgree.init(aPair.getPrivate()); + + KeyAgreement bKeyAgree = KeyAgreement.getInstance(algName, "BC"); + bKeyAgree.init(bPair.getPrivate()); + + KeyAgreement cKeyAgree = KeyAgreement.getInstance(algName, "BC"); + cKeyAgree.init(cPair.getPrivate()); + + Key ac = aKeyAgree.doPhase(cPair.getPublic(), false); + + Key ba = bKeyAgree.doPhase(aPair.getPublic(), false); + + Key cb = cKeyAgree.doPhase(bPair.getPublic(), false); + + aKeyAgree.doPhase(cb, true); + + bKeyAgree.doPhase(ac, true); + + cKeyAgree.doPhase(ba, true); + + BigInteger aShared = new BigInteger(aKeyAgree.generateSecret()); + BigInteger bShared = new BigInteger(bKeyAgree.generateSecret()); + BigInteger cShared = new BigInteger(cKeyAgree.generateSecret()); + + if (!aShared.equals(bShared)) + { + fail(size + " bit 3-way test failed (a and b differ)"); + } + + if (!cShared.equals(bShared)) + { + fail(size + " bit 3-way test failed (c and b differ)"); + } + } + + private void testECDH(String algorithm, String curveName, String cipher, int keyLen) + throws Exception + { + ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(curveName); + KeyPairGenerator g = KeyPairGenerator.getInstance(algorithm, "BC"); + + g.initialize(parameterSpec); + + // + // a side + // + KeyPair aKeyPair = g.generateKeyPair(); + + KeyAgreement aKeyAgree = KeyAgreement.getInstance(algorithm, "BC"); + + aKeyAgree.init(aKeyPair.getPrivate()); + + // + // b side + // + KeyPair bKeyPair = g.generateKeyPair(); + + KeyAgreement bKeyAgree = KeyAgreement.getInstance(algorithm, "BC"); + + bKeyAgree.init(bKeyPair.getPrivate()); + + // + // agreement + // + aKeyAgree.doPhase(bKeyPair.getPublic(), true); + bKeyAgree.doPhase(aKeyPair.getPublic(), true); + + SecretKey k1 = aKeyAgree.generateSecret(cipher); + SecretKey k2 = bKeyAgree.generateSecret(cipher + "[" + keyLen + "]"); // explicit key-len + + if (!k1.equals(k2)) + { + fail(algorithm + " 2-way test failed"); + } + + if (k1.getEncoded().length != keyLen / 8) + { + fail("key for " + cipher + " the wrong size expected " + keyLen / 8 + " got " + k1.getEncoded().length); + } + } + + private void testECDH(String algorithm, String curveName, ASN1ObjectIdentifier algorithmOid, String cipher, int keyLen) + throws Exception + { + ECNamedCurveParameterSpec parameterSpec = ECNamedCurveTable.getParameterSpec(curveName); + KeyPairGenerator g = KeyPairGenerator.getInstance("EC", "BC"); + + g.initialize(parameterSpec); + + // + // a side + // + KeyPair aKeyPair = g.generateKeyPair(); + + KeyAgreement aKeyAgree = KeyAgreement.getInstance(algorithm, "BC"); + + aKeyAgree.init(aKeyPair.getPrivate()); + + // + // b side + // + KeyPair bKeyPair = g.generateKeyPair(); + + KeyAgreement bKeyAgree = KeyAgreement.getInstance(algorithmOid.getId(), "BC"); + + bKeyAgree.init(bKeyPair.getPrivate()); + + // + // agreement + // + aKeyAgree.doPhase(bKeyPair.getPublic(), true); + bKeyAgree.doPhase(aKeyPair.getPublic(), true); + + SecretKey k1 = aKeyAgree.generateSecret(cipher); + SecretKey k2 = bKeyAgree.generateSecret(cipher + "[" + keyLen + "]"); // explicit key-len + + if (!k1.equals(k2)) + { + fail(algorithm + " 2-way test failed"); + } + + if (k1.getEncoded().length != keyLen / 8) + { + fail("key for " + cipher + " the wrong size expected " + keyLen / 8 + " got " + k1.getEncoded().length); + } + } + + private void testECDH(String algorithm) + throws Exception + { + KeyPairGenerator g = KeyPairGenerator.getInstance(algorithm, "BC"); + + EllipticCurve curve = new EllipticCurve( + new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + + ECParameterSpec ecSpec = new ECParameterSpec( + curve, + ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n + 1); // h + + g.initialize(ecSpec, new SecureRandom()); + + // + // a side + // + KeyPair aKeyPair = g.generateKeyPair(); + + KeyAgreement aKeyAgree = KeyAgreement.getInstance(algorithm, "BC"); + + aKeyAgree.init(aKeyPair.getPrivate()); + + // + // b side + // + KeyPair bKeyPair = g.generateKeyPair(); + + KeyAgreement bKeyAgree = KeyAgreement.getInstance(algorithm, "BC"); + + bKeyAgree.init(bKeyPair.getPrivate()); + + // + // agreement + // + aKeyAgree.doPhase(bKeyPair.getPublic(), true); + bKeyAgree.doPhase(aKeyPair.getPublic(), true); + + BigInteger k1 = new BigInteger(aKeyAgree.generateSecret()); + BigInteger k2 = new BigInteger(bKeyAgree.generateSecret()); + + if (!k1.equals(k2)) + { + fail(algorithm + " 2-way test failed"); + } + + // + // public key encoding test + // + byte[] pubEnc = aKeyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(algorithm, "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509); + + if (!pubKey.getW().equals(((ECPublicKey)aKeyPair.getPublic()).getW())) + { + System.out.println(" expected " + pubKey.getW().getAffineX() + " got " + ((ECPublicKey)aKeyPair.getPublic()).getW().getAffineX()); + System.out.println(" expected " + pubKey.getW().getAffineY() + " got " + ((ECPublicKey)aKeyPair.getPublic()).getW().getAffineY()); + fail(algorithm + " public key encoding (W test) failed"); + } + + if (!pubKey.getParams().getGenerator().equals(((ECPublicKey)aKeyPair.getPublic()).getParams().getGenerator())) + { + fail(algorithm + " public key encoding (G test) failed"); + } + + // + // private key encoding test + // + byte[] privEnc = aKeyPair.getPrivate().getEncoded(); + PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); + ECPrivateKey privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8); + + if (!privKey.getS().equals(((ECPrivateKey)aKeyPair.getPrivate()).getS())) + { + fail(algorithm + " private key encoding (S test) failed"); + } + + if (!privKey.getParams().getGenerator().equals(((ECPrivateKey)aKeyPair.getPrivate()).getParams().getGenerator())) + { + fail(algorithm + " private key encoding (G test) failed"); + } + } + + private void testMinSpecValue() + throws Exception + { + BigInteger p = new BigInteger("16560215747140417249215968347342080587", 16); + BigInteger g = new BigInteger("1234567890", 16); + + DHParameterSpec serverParam = new DHParameterSpec(p, g); + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); + + try + { + keyGen.initialize(serverParam, new SecureRandom()); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("unsafe p value so small specific l required".equals(e.getMessage())); + } + + } + + /* + COUNT = 14 + XstatCAVS = 95fc47b3c755935a5babce2738d70557a43ded59c2ef8926a04e402cdb0c97b8 + YstatCAVS = 0b7faaefb56ea62937c2210c44feca95037d4cedfe01abd61cd8085ea195547e29aa2162951a73f9acf0f79de9da1ed587a1374d7b9c25a3ac4848a857edf28d4d6b80142871cd3fa984d673945a6ae69fbd0bc559a68330e7ba8556189216fe5d25abd8f1857baea7ab42fbdc3bb482272eca02fd0095c6b53c8d9ffb3ec172d97a3a1bde096178e2aaa3f084717f3e4530f58906f8f509533cead788b4efbb69ed78b91109965018b9a094612e60b1af470ec03565729c38e6d131eebac3483e7fdb24a7c85fd9bd362404956b928d6e1762b91b13825f7769b6e9426936c03f0328d9325f6fdd4af0b53ab1bc4201fedc5961c7f2c3a9668aa90ed2c4bb5d + XephemCAVS = 6044f14699de46fe870688b27d5644a78da6e0758f2c999cc5e6d80a69220e2e + YephemCAVS = 4a8d5a1a12cc0aeeb409e07dbffa052d289c4cb49d6550d8483fe063eee9d9faa4e918fe4daa858d535c4ed5cd270d96315db210e20b4446db4f460238b9187accc65b6d43e53b3c85eec3053c8bd675ef34dca5f6189f2233ecf0b1eda0995460ccdded4e31bf3170f9ec3941d010bbd1d7a0e017f0d43c0dd1d6435f8523babfa6599120f3cbf718e755cee86189459bcd20f52d2a0ca04bdff38e26197c211fcb64cc3d7d3f2f28ee4f7eb9dbdc84a420442b8481bfa3218f0d40c00abaedff682e7d66f6e891642bdea3e2d9c6240b768376abc50343cc69ab08b0a12cc4c6f1508444fd662c4825bd6da99eaab40ff5547aae539450062ce70b9722091b + XstatIUT = 133a7729c7f1c1872438738edfa44d4cf44d3356d47b73b62eab45853ebdc66d + YstatIUT = 21e25ee916b7b56a82f9e7622e909bef000997c44434e1149fa30cb1571500be5e61bab977d9ace85ba62a21719199b9a9747e3bcc0fa729a69c17f080633e6c1426db891721ae74b9752effe8a4b9749f8c7d8edd1f4356bab994304d3fde8223de38436a1a7ffb70371d25cf4c75df7f58cd833837318c1c2213f9a058655905d752fb637d3d7f780c3ee4a788120040424199bc99d96f3c3e56a2a9fe8d6d93e60a91b6f61a1cf0559bc68a1e33716a54fdbd2895c0d9d1f7da2cb936ff0c1bc7c60380d9cf4eaa8595366ed86a72cbd964d1e4309b2dd6efad1e944cdb92752ebe13d2e65772295fb13cd9f11d5b89253e4cc109b76d53306a6534be2641 + XephemIUT = 412a15e0866572a825219d3eaf9a4d6c0ed855180e5bdabc90f6d1a2354c3964 + YephemIUT = 8e235a5e20d0d1d431eb832a4309de239403a68217a595d30b2e7fd677ad5eb7a2a3cc5fb0793fe466169d8acac366a20de3863adc542a4fc6dd9dcb59126dfd0336b2c7736d26e87ad4fd84d6240e149f50ffcdaa81b60ca04a26f6335e1c41e49f183bf3a7a39ffe6bf2654874399e07d9a52fb34d08a7246929649171f6e7ceceb19016b83093a9a795245ae348346f9aa8f06380cb2b3cc9176e63e107734e23ead912e408c3085b6ba361cb66cf5b25ed03fdc6893646ea3cddd770fcb51d762a8f549b600044946c362f4dda85288fbc4499e022e2b705b4f1151d5206932da92b36c6b121e3a55a2edca4b42407021f4ea3f4748f21a36d722c086cf6 + CCMNonce = 7def4d439a9b7a6c5700bb9168 + OI = a1b2c3d4e543415653696412daed24199775845035176e67b0ace1b413e0 + CAVSTag = df851c60d5336269c68e42cc0d3b6ea5 + Z = 051f570adc0c2e26f946153f31784409102f5bd9edc2cdc466b14196b7489d2b157847fb7a13bfe89edc9712b2a161be360936802dc2c1158f0a84a2175671a4f46ed6fbadc4238244a217ed21a35e01b966b100daad49e2390e0c11525280b2ecc60ffad1e73ad12aa49e28fd9dfbf7d90ad75514c48a4c05f7bd8482929c68cc62e86424019462b1e2ef6a7a16507577ab144a89dafe57b9b0889d7afda25e62022f69220f0fb32046d0aa478bde5914177aeb4f359e790a6f9fac367f431b4e32acb8616f040c77cd99c1a666d4569c06b62faa4925f9c6f6525fe074cac972aead654c87dcc772b96992202afff62c82cc501b821bf0fd851942f0797dc98be4bdf193bc6d0d95d40146b5dad610bd4123413369686b460018918c493854a14558b302f6bc3d10109cbb549dc624448246e41a32842b1962a3b884b2eb8546f2bb51d30ceb80ae7a631f2f2fb820c7f149d5e53e2ec3d62f1ff5c6cb07f845de1b31be0e1d31143476a22952406c4fa37029b1e4d2107f5efb9df9e04ec2a4d9def274f934a0e34e22003f2142185c1f79d6058f612b1315acff738e94a18a08be36a3b327ae3e28e1c9aa96fe99cbe4fdeb0df92ff133e94929d6d50fad4d5bffe54454832125212c30dad53109e114413f954f02cfa39fcc0ef574074df2f1d6f4fcb9d99dfcbcc252ee42980f1a483508379434e1ef72358f39bb5725 + MacData = 4b435f325f56434156536964a1b2c3d4e54a8d5a1a12cc0aeeb409e07dbffa052d289c4cb49d6550d8483fe063eee9d9faa4e918fe4daa858d535c4ed5cd270d96315db210e20b4446db4f460238b9187accc65b6d43e53b3c85eec3053c8bd675ef34dca5f6189f2233ecf0b1eda0995460ccdded4e31bf3170f9ec3941d010bbd1d7a0e017f0d43c0dd1d6435f8523babfa6599120f3cbf718e755cee86189459bcd20f52d2a0ca04bdff38e26197c211fcb64cc3d7d3f2f28ee4f7eb9dbdc84a420442b8481bfa3218f0d40c00abaedff682e7d66f6e891642bdea3e2d9c6240b768376abc50343cc69ab08b0a12cc4c6f1508444fd662c4825bd6da99eaab40ff5547aae539450062ce70b9722091b8e235a5e20d0d1d431eb832a4309de239403a68217a595d30b2e7fd677ad5eb7a2a3cc5fb0793fe466169d8acac366a20de3863adc542a4fc6dd9dcb59126dfd0336b2c7736d26e87ad4fd84d6240e149f50ffcdaa81b60ca04a26f6335e1c41e49f183bf3a7a39ffe6bf2654874399e07d9a52fb34d08a7246929649171f6e7ceceb19016b83093a9a795245ae348346f9aa8f06380cb2b3cc9176e63e107734e23ead912e408c3085b6ba361cb66cf5b25ed03fdc6893646ea3cddd770fcb51d762a8f549b600044946c362f4dda85288fbc4499e022e2b705b4f1151d5206932da92b36c6b121e3a55a2edca4b42407021f4ea3f4748f21a36d722c086cf6 + DKM = 24a246e6cbaae19e4e8bffbe3167fbbc + Result = P (10 - Z value should have leading 0 nibble ) + */ + private void testDHUnifiedTestVector1() + throws Exception + { + // Test Vector from NIST sample data + KeyFactory dhKeyFact = KeyFactory.getInstance("DH", "BC"); + + DHParameterSpec dhSpec = new DHParameterSpec( + new BigInteger("9a076bb269abfff57c72073053190a2008c3067fdcd9712ec00ee55c8fbf22af7c454dc5f10ae224d1e29fcccb3855a2509b082b934a353c21dfa5d1212f29d24866f022873d1f0b76373d47bb345e7e74f0ffc27e7c6c149282cb68a66705412995ed7a650a784f15107ed14244563b10f61d3f998b1466c9a3dd7c48a1b92d236b99b912a25f1c5279640c29714ce2123d222a6c9775223be80c5a4e9392db9ae45027110b75703c42d53fbfc1484e84cb70cabdcdcdc55066e5c03ce13ad0d7fa3af6f49101d454d5b3b77ce4c8db5772a427af7e351cdad3d7d278f52c3f57fc9274fc101c66d829871435ea2fc1f43f0e0d556a80dba9ab4e57c7b4b5a7", 16), + // Q = fdd88b09ff0c6c6c334a598059c1b55396dab2de01af2e8d06481fd5cd506c71 + new BigInteger("167f9631c8aba192976a396b9df4bca5e54d1c1400eab4bdea27b1ca957211733d847026d2b3e3ea9b4c14d13b6e59f40c0df0c80bdecafb7ac414de2f920642c60d63406d2cc999ad149d24216b08a3952b50a50a088ab747de04bb4fd26899f7052970cfd0f65002cc0639bea634ba5ac2d98170b3a1b3ab5295e9395990b57fbdaf117662a9430da6b74d4e52d3969ce385b2fb61c11febd93867f1062084ca0a62c0de17b1e7265545198355e026818c037c43535de8f0d5cf0159501bcd35a4ba8fe92041a92e85fae03a051dfb3199d9764d17a3b8968eaf32e666ae867d1d0e6178ab31985b665e3178c36565e685046cb1d0611a25b0d559cd31f818", 16)); + + KeyPair U1 = new KeyPair( + dhKeyFact.generatePublic(new DHPublicKeySpec( + new BigInteger("0b7faaefb56ea62937c2210c44feca95037d4cedfe01abd61cd8085ea195547e29aa2162951a73f9acf0f79de9da1ed587a1374d7b9c25a3ac4848a857edf28d4d6b80142871cd3fa984d673945a6ae69fbd0bc559a68330e7ba8556189216fe5d25abd8f1857baea7ab42fbdc3bb482272eca02fd0095c6b53c8d9ffb3ec172d97a3a1bde096178e2aaa3f084717f3e4530f58906f8f509533cead788b4efbb69ed78b91109965018b9a094612e60b1af470ec03565729c38e6d131eebac3483e7fdb24a7c85fd9bd362404956b928d6e1762b91b13825f7769b6e9426936c03f0328d9325f6fdd4af0b53ab1bc4201fedc5961c7f2c3a9668aa90ed2c4bb5d", 16), + dhSpec.getP(), dhSpec.getG())), + dhKeyFact.generatePrivate(new DHPrivateKeySpec( + new BigInteger("95fc47b3c755935a5babce2738d70557a43ded59c2ef8926a04e402cdb0c97b8", 16), + dhSpec.getP(), dhSpec.getG()))); + + KeyPair U2 = new KeyPair( + dhKeyFact.generatePublic(new DHPublicKeySpec( + new BigInteger("4a8d5a1a12cc0aeeb409e07dbffa052d289c4cb49d6550d8483fe063eee9d9faa4e918fe4daa858d535c4ed5cd270d96315db210e20b4446db4f460238b9187accc65b6d43e53b3c85eec3053c8bd675ef34dca5f6189f2233ecf0b1eda0995460ccdded4e31bf3170f9ec3941d010bbd1d7a0e017f0d43c0dd1d6435f8523babfa6599120f3cbf718e755cee86189459bcd20f52d2a0ca04bdff38e26197c211fcb64cc3d7d3f2f28ee4f7eb9dbdc84a420442b8481bfa3218f0d40c00abaedff682e7d66f6e891642bdea3e2d9c6240b768376abc50343cc69ab08b0a12cc4c6f1508444fd662c4825bd6da99eaab40ff5547aae539450062ce70b9722091b", 16), + dhSpec.getP(), dhSpec.getG())), + dhKeyFact.generatePrivate(new DHPrivateKeySpec( + new BigInteger("6044f14699de46fe870688b27d5644a78da6e0758f2c999cc5e6d80a69220e2e", 16), + dhSpec.getP(), dhSpec.getG()))); + + KeyPair V1 = new KeyPair( + dhKeyFact.generatePublic(new DHPublicKeySpec( + new BigInteger("21e25ee916b7b56a82f9e7622e909bef000997c44434e1149fa30cb1571500be5e61bab977d9ace85ba62a21719199b9a9747e3bcc0fa729a69c17f080633e6c1426db891721ae74b9752effe8a4b9749f8c7d8edd1f4356bab994304d3fde8223de38436a1a7ffb70371d25cf4c75df7f58cd833837318c1c2213f9a058655905d752fb637d3d7f780c3ee4a788120040424199bc99d96f3c3e56a2a9fe8d6d93e60a91b6f61a1cf0559bc68a1e33716a54fdbd2895c0d9d1f7da2cb936ff0c1bc7c60380d9cf4eaa8595366ed86a72cbd964d1e4309b2dd6efad1e944cdb92752ebe13d2e65772295fb13cd9f11d5b89253e4cc109b76d53306a6534be2641", 16), + dhSpec.getP(), dhSpec.getG())), + dhKeyFact.generatePrivate(new DHPrivateKeySpec( + new BigInteger("133a7729c7f1c1872438738edfa44d4cf44d3356d47b73b62eab45853ebdc66d", 16), + dhSpec.getP(), dhSpec.getG()))); + + KeyPair V2 = new KeyPair( + dhKeyFact.generatePublic(new DHPublicKeySpec( + new BigInteger("8e235a5e20d0d1d431eb832a4309de239403a68217a595d30b2e7fd677ad5eb7a2a3cc5fb0793fe466169d8acac366a20de3863adc542a4fc6dd9dcb59126dfd0336b2c7736d26e87ad4fd84d6240e149f50ffcdaa81b60ca04a26f6335e1c41e49f183bf3a7a39ffe6bf2654874399e07d9a52fb34d08a7246929649171f6e7ceceb19016b83093a9a795245ae348346f9aa8f06380cb2b3cc9176e63e107734e23ead912e408c3085b6ba361cb66cf5b25ed03fdc6893646ea3cddd770fcb51d762a8f549b600044946c362f4dda85288fbc4499e022e2b705b4f1151d5206932da92b36c6b121e3a55a2edca4b42407021f4ea3f4748f21a36d722c086cf6", 16), + dhSpec.getP(), dhSpec.getG())), + dhKeyFact.generatePrivate(new DHPrivateKeySpec( + new BigInteger("412a15e0866572a825219d3eaf9a4d6c0ed855180e5bdabc90f6d1a2354c3964", 16), + dhSpec.getP(), dhSpec.getG()))); + + byte[] x = calculateUnifiedAgreement("DHUwithSHA256CKDF", "AES[128]", U1, U2, V1, V2, + Hex.decode("a1b2c3d4e543415653696412daed24199775845035176e67b0ace1b413e0")); + + if (x == null + || !areEqual(Hex.decode("24a246e6cbaae19e4e8bffbe3167fbbc"), x)) + { + fail("DH unified Test Vector #1 agreement failed, got: " + Hex.toHexString(x)); + } + } + + private void testECUnifiedTestVector1() + throws Exception + { + // Test Vector from NIST sample data + + ECNamedCurveParameterSpec namedSpec = ECNamedCurveTable.getParameterSpec("P-224"); + KeyFactory ecKeyFact = KeyFactory.getInstance("EC", "BC"); + + EllipticCurve ecCurve = new EllipticCurve( + new ECFieldFp(namedSpec.getCurve().getField().getCharacteristic()), + namedSpec.getCurve().getA().toBigInteger(), namedSpec.getCurve().getB().toBigInteger()); + ECParameterSpec ecSpec = new ECParameterSpec(ecCurve, + new ECPoint(namedSpec.getG().getAffineXCoord().toBigInteger(), namedSpec.getG().getAffineYCoord().toBigInteger()), + namedSpec.getN(), namedSpec.getH().intValue()); + + KeyPair U1 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("040784e946ef1fae0cfe127042a310a018ba639d3f6b41f265904f0a7b21b7953efe638b45e6c0c0d34a883a510ce836d143d831daa9ce8a12")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("86d1735ca357890aeec8eccb4859275151356ecee9f1b2effb76b092", 16), ecSpec))); + + KeyPair U2 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("04b33713dc0d56215be26ee6c5e60ad36d12e02e78529ae3ff07873c6b39598bda41c1cf86ee3981f40e102333c15fef214bda034291c1aca6")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("764010b3137ef8d34a3552955ada572a4fa1bb1f5289f27c1bf18344", 16), ecSpec))); + + KeyPair V1 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("0484c22d9575d09e280613c8758467f84869c6eede4f6c1b644517d6a72c4fc5c68fa12b4c259032fc5949c630259948fca38fb3342d9cb0a8")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("e37964e391f5058fb43435352a9913438a1ec10831f755273285230a", 16), ecSpec))); + + KeyPair V2 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("044b917e9ce693b277c8095e535ea81c2dea089446a8c55438eda750fb6170c85b86390481fff2dff94b7dff3e42d35ff623921cb558967b48")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("ab40d67f59ba7265d8ad33ade8f704d13a7ba2298b69172a7cd02515", 16), ecSpec))); + + byte[] x = calculateUnifiedAgreement("ECCDHUwithSHA224CKDF", "AES[128]", U1, U2, V1, V2, + Hex.decode("a1b2c3d4e54341565369643dba868da77897b6552f6f767ad873b232aa4a810a91863ec3dc86db53359a772dd76933")); + + if (x == null + || !areEqual(Hex.decode("63b7ba5699927cb08e058b76af7fc0b0"), x)) + { + fail("EC unified Test Vector #1 agreement failed, got: " + Hex.toHexString(x)); + } + } + + private void testECUnifiedTestVector2() + throws Exception + { + // Test Vector from NIST sample data + + ECNamedCurveParameterSpec namedSpec = ECNamedCurveTable.getParameterSpec("P-256"); + KeyFactory ecKeyFact = KeyFactory.getInstance("EC", "BC"); + + EllipticCurve ecCurve = new EllipticCurve( + new ECFieldFp(namedSpec.getCurve().getField().getCharacteristic()), + namedSpec.getCurve().getA().toBigInteger(), namedSpec.getCurve().getB().toBigInteger()); + ECParameterSpec ecSpec = new ECParameterSpec(ecCurve, + new ECPoint(namedSpec.getG().getAffineXCoord().toBigInteger(), namedSpec.getG().getAffineYCoord().toBigInteger()), + namedSpec.getN(), namedSpec.getH().intValue()); + + KeyPair U1 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("047581b35964a983414ebdd56f4ebb1ddcad10881b200666a51ae41306e1ecf1db368468a5e8a65ca10ccea526472c8982db68316c468800e171c11f4ee694fce4")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("2eb7ef76d4936123b6f13035045aedf45c1c7731f35d529d25941926b5bb38bb", 16), ecSpec))); + + KeyPair U2 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("045b1e4cdeb0728333c0a51631b1a75269e4878d10732f4cb94d600483db4bd9ee625c374592c3db7e9f8b4f2c91a0098a158bc37b922e4243bd9cbdefe67d6ab0")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("78acde388a022261767e6b3dd6dd016c53b70a084260ec87d395aec761c082de", 16), ecSpec))); + + KeyPair V1 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("04e4916d616803ff1bd9569f35b7d06f792f19c1fb4e6fa916d686c027a17d8dffd570193d8e101624ac2ea0bcb762d5613f05452670f09af66ef70861fb528868")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("9c85898640a1b1de8ce7f557492dc1460530b9e17afaaf742eb953bb644e9c5a", 16), ecSpec))); + + KeyPair V2 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("04d1cd23c29d0fc865c316d44a1fd5adb6605ee47c9ddfec3a9b0a5e532d52704e74ff5d149aeb50856fefb38d5907b6dbb580fe6dc166bcfcbee4eb376d77e95c")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("d6e11d5d3b85b201b8f4c12dadfad3000e267961a806a0658a2b859d44389599", 16), ecSpec))); + + byte[] x = calculateUnifiedAgreement("ECCDHUwithSHA256CKDF", "AES[128]", + U1, U2, V1, V2, Hex.decode("a1b2c3d4e54341565369649018558dc958160b4b1d240d06ea07c6f321a752496c1a3ff45cbb4b43507c6fe1997d1d")); + + if (x == null + || !areEqual(Hex.decode("221d252072d6f85b8298eab6fc38634e"), x)) + { + fail("EC unified Test Vector #2 agreement failed"); + } + } + + private void testECUnifiedTestVector3() + throws Exception + { + // Test Vector from NIST sample data - One pass unified. + + ECNamedCurveParameterSpec namedSpec = ECNamedCurveTable.getParameterSpec("P-224"); + KeyFactory ecKeyFact = KeyFactory.getInstance("EC", "BC"); + + EllipticCurve ecCurve = new EllipticCurve( + new ECFieldFp(namedSpec.getCurve().getField().getCharacteristic()), + namedSpec.getCurve().getA().toBigInteger(), namedSpec.getCurve().getB().toBigInteger()); + ECParameterSpec ecSpec = new ECParameterSpec(ecCurve, + new ECPoint(namedSpec.getG().getAffineXCoord().toBigInteger(), namedSpec.getG().getAffineYCoord().toBigInteger()), + namedSpec.getN(), namedSpec.getH().intValue()); + + KeyPair U1 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("04030f136fa7fef90d185655ed1c6d46bacdb82001714e682cc80ca6b2d7c62e2f2e19d11755dba4aafd7e1ee5fda3e5f4d0af9a3ad773c38a")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("6fc464c741f52b2a2e4cde35673b87fdd0f52caf4e716230b11570ba", 16), ecSpec))); + + KeyPair V1 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("048f87f5f8a632c9a3348ea85b596c01c12ca29ca71583dcdc27ff9766351416a707b95fae67d56be5119b460a446b6a02db20a13bbc8ed13b")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("f5cb57a08a6949d3f2c2cc02e7c2252cecb3ebb8b3572943ceb407c7", 16), ecSpec))); + + KeyPair V2 = new KeyPair( + ecKeyFact.generatePublic(new ECPublicKeySpec( + ECPointUtil.decodePoint(ecCurve, Hex.decode("046fcc7d01f905b279e9413645d24cc30d293b98b0ea7bfe87124e4951eba04a74817f596a67c0bfe3b4f4cee99537a2ac1c6470dd006be8ca")), ecSpec)), + ecKeyFact.generatePrivate(new ECPrivateKeySpec( + new BigInteger("505b6f372725e293cda07bf0dd14dabe2faf0edaa5ab1c7d187a6138", 16), ecSpec))); + + byte[] x = calculateUnifiedAgreement("ECCDHUwithSHA224CKDF", "AES[128]", U1, U1, V1, V2, + Hex.decode("a1b2c3d4e5434156536964b62d3197031c27af0e3b45228a8768efcc0b39a375f8f61852f8765b80c067eed4e4db30")); + + if (x == null + || !areEqual(Hex.decode("0c96fa268b89cf664392621ad5e174a6"), x)) + { + fail("EC unified Test Vector #3 agreement failed, got: " + Hex.toHexString(x)); + } + } + + private byte[] calculateUnifiedAgreement( + String alg, + String keyAlg, + KeyPair U1, + KeyPair U2, + KeyPair V1, + KeyPair V2, + byte[] oi) + throws Exception + { + KeyAgreement u = KeyAgreement.getInstance(alg, "BC"); + + u.init(U1.getPrivate(), new DHUParameterSpec(U2, V2.getPublic(), oi)); + + u.doPhase(V1.getPublic(), true); + + SecretKey uk = u.generateSecret(keyAlg); + byte[] ux = uk.getEncoded(); + + KeyAgreement v = KeyAgreement.getInstance(alg, "BC"); + + v.init(V1.getPrivate(), new DHUParameterSpec(V2, U2.getPublic(), oi)); + + v.doPhase(U1.getPublic(), true); + + SecretKey vk = v.generateSecret(keyAlg); + byte[] vx = vk.getEncoded(); + + if (areEqual(ux, vx)) + { + return ux; + } + + return null; + } + + private void testExceptions() + throws Exception + { + try + { + KeyAgreement aKeyAgree = KeyAgreement.getInstance("DH", "BC"); + + aKeyAgree.generateSecret("DES"); + fail("no exception"); + } + catch (IllegalStateException e) + { + // okay + } + catch (Exception e) + { + fail("Unexpected exception: " + e, e); + } + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC", "BC"); + + keyGen.initialize(256); + + KeyPair kp = keyGen.generateKeyPair(); + KeyAgreement agreement = KeyAgreement.getInstance("ECDH", "BC"); + + agreement.init(kp.getPrivate()); + try + { + ECPoint fakePubPoint = new ECPoint(new BigInteger("12345"), new BigInteger("23457")); + ECPublicKeySpec fakePubSpec = new ECPublicKeySpec(fakePubPoint, ((ECPublicKey)kp.getPublic()).getParams()); + KeyFactory kf = KeyFactory.getInstance("EC", "BC"); + PublicKey fakePub = kf.generatePublic(fakePubSpec); + agreement.doPhase(fakePub, true); + + fail("no exception on dud point"); + } + catch (java.security.spec.InvalidKeySpecException e) + { + isTrue("wrong message: " + e.getMessage(), "invalid KeySpec: Point not on curve".equals(e.getMessage())); + } + catch (java.security.InvalidKeyException e) + { + isTrue("wrong message: " + e.getMessage(), "calculation failed: Invalid point".equals(e.getMessage())); + } + + agreement = KeyAgreement.getInstance("ECDH", "BC"); + + try + { + agreement.init(kp.getPrivate(), new UserKeyingMaterialSpec(new byte[20])); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("no KDF specified for UserKeyingMaterialSpec".equals(e.getMessage())); + } + } + + private void testDESAndDESede(BigInteger g, BigInteger p) + throws Exception + { + DHParameterSpec dhParams = new DHParameterSpec(p, g, 256); + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); + + keyGen.initialize(dhParams); + + KeyPair kp = keyGen.generateKeyPair(); + + KeyAgreement keyAgreement = KeyAgreement.getInstance("DH", "BC"); + + keyAgreement.init(kp.getPrivate()); + keyAgreement.doPhase(kp.getPublic(), true); + + SecretKey key = keyAgreement.generateSecret("DES"); + + if (key.getEncoded().length != 8) + { + fail("DES length wrong"); + } + + if (!DESKeySpec.isParityAdjusted(key.getEncoded(), 0)) + { + fail("DES parity wrong"); + } + + key = keyAgreement.generateSecret("DESEDE"); + + if (key.getEncoded().length != 24) + { + fail("DESEDE length wrong"); + } + + if (!DESedeKeySpec.isParityAdjusted(key.getEncoded(), 0)) + { + fail("DESEDE parity wrong"); + } + + key = keyAgreement.generateSecret("Blowfish"); + + if (key.getEncoded().length != 16) + { + fail("Blowfish length wrong"); + } + } + + private void testInitialise() + throws Exception + { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); + + keyGen.initialize(512); + + keyGen.generateKeyPair(); + + testTwoParty("DH", 512, 0, keyGen); + } + + private void testSmallSecret() + throws Exception + { + BigInteger p = new BigInteger("ff3b512a4cc0961fa625d6cbd9642c377ece46b8dbc3146a98e0567f944034b5e3a1406edb179a77cd2539bdb74dc819f0a74d486606e26e578ff52c5242a5ff", 16); + BigInteger g = new BigInteger("58a66667431136e99d86de8199eb650a21afc9de3dd4ef9da6dfe89c866e928698952d95e68b418becef26f23211572eebfcbf328809bdaf02bba3d24c74f8c0", 16); + + DHPrivateKeySpec aPrivSpec = new DHPrivateKeySpec( + new BigInteger("30a6ea4e2240a42867ad98bd3adbfd5b81aba48bd930f20a595983d807566f7cba4e766951efef2c6c0c1be3823f63d66e12c2a091d5ff3bbeb1ea6e335d072d", 16), p, g); + DHPublicKeySpec aPubSpec = new DHPublicKeySpec( + new BigInteger("694dfea1bfc8897e2fcbfd88033ab34f4581892d7d5cc362dc056e3d43955accda12222bd651ca31c85f008a05dea914de68828dfd83a54a340fa84f3bbe6caf", 16), p, g); + + DHPrivateKeySpec bPrivSpec = new DHPrivateKeySpec( + new BigInteger("775b1e7e162190700e2212dd8e4aaacf8a2af92c9c108b81d5bf9a14548f494eaa86a6c4844b9512eb3e3f2f22ffec44c795c813edfea13f075b99bbdebb34bd", 16), p, g); + + DHPublicKeySpec bPubSpec = new DHPublicKeySpec( + new BigInteger("d8ddd4ff9246635eadbfa0bc2ef06d98a329b6e8cd2d1435d7b4921467570e697c9a9d3c172c684626a9d2b6b2fa0fc725d5b91f9a9625b717a4169bc714b064", 16), p, g); + + KeyFactory kFact = KeyFactory.getInstance("DH", "BC"); + + byte[] secret = testTwoParty("DH", 512, 0, new KeyPair(kFact.generatePublic(aPubSpec), kFact.generatePrivate(aPrivSpec)), new KeyPair(kFact.generatePublic(bPubSpec), kFact.generatePrivate(bPrivSpec))); + + if (secret.length != ((p.bitLength() + 7) / 8)) + { + fail("short secret wrong length"); + } + + if (!Arrays.areEqual(Hex.decode("00340d3309ddc86e99e2f0be4fc212837bfb5c59336b09b9e1aeb1884b72c8b485b56723d0bf1c1d37fc89a292fc1cface9125106f1df15f55f22e4f77c5879b"), secret)) + { + fail("short secret mismatch"); + } + } + + private void testEnc() + throws Exception + { + KeyFactory kFact = KeyFactory.getInstance("DH", "BC"); + + Key k = kFact.generatePrivate(new PKCS8EncodedKeySpec(samplePrivEnc)); + + if (!Arrays.areEqual(samplePrivEnc, k.getEncoded())) + { + fail("private key re-encode failed"); + } + + k = kFact.generatePublic(new X509EncodedKeySpec(samplePubEnc)); + + if (!Arrays.areEqual(samplePubEnc, k.getEncoded())) + { + fail("public key re-encode failed"); + } + + k = kFact.generatePublic(new X509EncodedKeySpec(oldPubEnc)); + + if (!Arrays.areEqual(oldPubEnc, k.getEncoded())) + { + fail("old public key re-encode failed"); + } + + k = kFact.generatePublic(new X509EncodedKeySpec(oldFullParams)); + + if (!Arrays.areEqual(oldFullParams, k.getEncoded())) + { + fail("old full public key re-encode failed"); + } + } + + private void testConfig() + { + ConfigurableProvider prov = new BouncyCastleProvider(); + + DHParameterSpec dhSpec512 = new DHParameterSpec( + new BigInteger("fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16), + new BigInteger("678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16), + 384); + + DHParameterSpec dhSpec640 = new DHParameterSpec( + new BigInteger("c3d5a7f9a1cd7330099cebb60194f5176793a1cf13cd429f37bcbf1a7ddd53893ffdf1228af760c4a448e459d9cbab8302cc8cfc3368db01972108587c72a0f8b512ede0c99a3bef16cda0de529c8be7", 16), + new BigInteger("c066a53c43a55e3474e20de07d14a574f6f1febe0b55e4c49bf72b0c712e02a51b03f379f485884bfd1f53819347b69401b9292196092a635320313ec6ee5ee5a5eac7ab9c57f2631a71452feeab3ef", 16), + 320); + + DHParameterSpec dhSpec1024 = new DHParameterSpec( + new BigInteger("fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b76b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16), + new BigInteger("f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d0782675159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e13c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243bcca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", 16), + 512); + + prov.setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, dhSpec512); + + if (!dhSpec512.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(512))) + { + fail("config mismatch"); + } + + if (BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(640) != null) + { + fail("config found when none expected"); + } + + prov.setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, new DHParameterSpec[]{dhSpec512, dhSpec640, dhSpec1024}); + + if (!dhSpec512.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(512))) + { + fail("512 config mismatch"); + } + + if (!dhSpec640.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(640))) + { + fail("640 config mismatch"); + } + + if (!dhSpec1024.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(1024))) + { + fail("1024 config mismatch"); + } + + prov.setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, null); + + if (BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(640) != null) + { + fail("config found for 640 when none expected"); + } + + prov.setParameter(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS, dhSpec512); + + if (!dhSpec512.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(512))) + { + fail("config mismatch"); + } + + if (BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(640) != null) + { + fail("config found when none expected"); + } + + prov.setParameter(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS, new DHParameterSpec[]{dhSpec512, dhSpec640, dhSpec1024}); + + if (!dhSpec512.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(512))) + { + fail("512 config mismatch"); + } + + if (!dhSpec640.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(640))) + { + fail("640 config mismatch"); + } + + if (!dhSpec1024.equals(BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(1024))) + { + fail("1024 config mismatch"); + } + + prov.setParameter(ConfigurableProvider.THREAD_LOCAL_DH_DEFAULT_PARAMS, null); + + if (BouncyCastleProvider.CONFIGURATION.getDHDefaultParameters(640) != null) + { + fail("config found for 640 when none expected"); + } + } + + static final String MESSAGE = "Hello"; + + static final String PROVIDER_NAME = "BC"; + static final SecureRandom rand = new SecureRandom(); + + public void setUp() + { + // Add BouncyCastle for testing. + Security.insertProviderAt(new BouncyCastleProvider(), 1); + System.out.println("WARNING: Using BouncyCastleProvider"); + } + + public DHParameterSpec ike2048() + { + final BigInteger p = new BigInteger( + "ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a67cc74" + + "020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a6df25f1437" + + "4fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0bff5cb6f406b7ed" + + "ee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b3dc2007cb8a163bf05" + + "98da48361c55d39a69163fa8fd24cf5f83655d23dca3ad961c62f356208552bb" + + "9ed529077096966d670c354e4abc9804f1746c08ca18217c32905e462e36ce3b" + + "e39e772c180e86039b2783a2ec07a28fb5c55df06f4c52c9de2bcbf695581718" + + "3995497cea956ae515d2261898fa051015728e5a8aacaa68ffffffffffffffff", 16); + final BigInteger g = new BigInteger("2"); + return new DHParameterSpec(p, g); + } + + /** + * Tests whether a provider accepts invalid public keys that result in predictable shared secrets. + * This test is based on RFC 2785, Section 4 and NIST SP 800-56A, + * If an attacker can modify both public keys in an ephemeral-ephemeral key agreement scheme then + * it may be possible to coerce both parties into computing the same predictable shared key. + *

+ * Note: the test is quite whimsical. If the prime p is not a safe prime then the provider itself + * cannot prevent all small-subgroup attacks because of the missing parameter q in the + * Diffie-Hellman parameters. Implementations must add additional countermeasures such as the ones + * proposed in RFC 2785. + */ + private void testSubgroupConfinement() + throws Exception + { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DH", "BC"); + DHParameterSpec params = ike2048(); + final BigInteger p = params.getP(); + final BigInteger g = params.getG(); + keyGen.initialize(params); + PrivateKey priv = keyGen.generateKeyPair().getPrivate(); + KeyAgreement ka = KeyAgreement.getInstance("DH", "BC"); + BigInteger[] weakPublicKeys = { + BigInteger.ZERO, BigInteger.ONE, p.subtract(BigInteger.ONE), p, + p.add(BigInteger.ONE), BigInteger.ONE.negate()}; + for (final BigInteger weakKey : weakPublicKeys) + { + DHPublicKeySpec weakSpec = new DHPublicKeySpec(weakKey, p, g); + KeyFactory kf = KeyFactory.getInstance("DH", "BC"); + try + { + kf.generatePublic(weakSpec); + fail("Generated weak public key"); + } + catch (GeneralSecurityException ex) + { + isTrue("wrong message (generate)", "invalid DH public key".equals(ex.getMessage())); + } + ka.init(priv); + try + { + ka.doPhase(new DHPublicKey() + { + public BigInteger getY() + { + return weakKey; + } + + public DHParameterSpec getParams() + { + return new DHParameterSpec(p, g); + } + + public String getAlgorithm() + { + return null; + } + + public String getFormat() + { + return null; + } + + public byte[] getEncoded() + { + return new byte[0]; + } + }, true); + fail("Generated secrets with weak public key"); + } + catch (GeneralSecurityException ex) + { + isTrue("wrong message (doPhase)", "Invalid DH PublicKey".equals(ex.getMessage())); + } + } + } + + private void testGenerateUsingStandardGroup() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DH", "BC"); + DHDomainParameterSpec mySpec = new DHDomainParameterSpec(DHStandardGroups.rfc7919_ffdhe2048); + kpGen.initialize(mySpec, new SecureRandom()); + KeyPair kp = kpGen.generateKeyPair(); + + /* Obtain encoded keys */ + PKCS8EncodedKeySpec pkcs = new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded()); + X509EncodedKeySpec x509 = new X509EncodedKeySpec(kp.getPublic().getEncoded()); + } + + private KeyPair generateDHKeyPair() + throws GeneralSecurityException + { + KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("DH", "BC"); + + keyPairGen.initialize(2048); + + return keyPairGen.generateKeyPair(); + } + + private SecretKey mqvGenerateAESKey( + PrivateKey aPriv, PublicKey aPubEph, PrivateKey aPrivEph, PublicKey bPub, PublicKey bPubEph, byte[] keyMaterial) + throws GeneralSecurityException + { + KeyAgreement agreement = KeyAgreement.getInstance("MQVwithSHA256KDF", "BC"); + + agreement.init(aPriv, new MQVParameterSpec(aPubEph, aPrivEph, bPubEph, keyMaterial)); + + agreement.doPhase(bPub, true); + + return agreement.generateSecret("AES"); + } + + private void mqvTest() + throws Exception + { + Security.addProvider(new BouncyCastleProvider()); + + // Generate the key pairs for party A and party B + KeyPair aKpS = generateDHKeyPair(); + KeyPair aKpE = generateDHKeyPair(); // A's ephemeral pair + KeyPair bKpS = generateDHKeyPair(); + KeyPair bKpE = generateDHKeyPair(); // B's ephemeral pair + + // key agreement generating an AES key + byte[] keyMaterial = Strings.toByteArray("For an AES key"); + + SecretKey aKey = mqvGenerateAESKey( + aKpS.getPrivate(), + aKpE.getPublic(), aKpE.getPrivate(), + bKpS.getPublic(), bKpE.getPublic(), keyMaterial); + SecretKey bKey = mqvGenerateAESKey( + bKpS.getPrivate(), + bKpE.getPublic(), bKpE.getPrivate(), + aKpS.getPublic(), aKpE.getPublic(), keyMaterial); + + // compare the two return values. + isTrue(Arrays.areEqual(aKey.getEncoded(), bKey.getEncoded())); + + // check with encoding + KeyFactory kFact = KeyFactory.getInstance("DH", "BC"); + + aKey = mqvGenerateAESKey( + kFact.generatePrivate(new PKCS8EncodedKeySpec(aKpS.getPrivate().getEncoded())), + aKpE.getPublic(), aKpE.getPrivate(), + bKpS.getPublic(), kFact.generatePublic(new X509EncodedKeySpec(bKpE.getPublic().getEncoded())), keyMaterial); + bKey = mqvGenerateAESKey( + bKpS.getPrivate(), + bKpE.getPublic(), kFact.generatePrivate(new PKCS8EncodedKeySpec(bKpE.getPrivate().getEncoded())), + aKpS.getPublic(), aKpE.getPublic(), keyMaterial); + + // compare the two return values. + isTrue(Arrays.areEqual(aKey.getEncoded(), bKey.getEncoded())); + } + + private void generalKeyTest() + throws Exception + { + SecureRandom random = new SecureRandom(); + + int[] keySizes = new int[]{512, 768, 1024, 2048}; + for (int i = 0; i != keySizes.length; i++) + { + final KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("DH", "BC"); + keyPairGenerator.initialize(keySizes[i], random); + keyPairGenerator.generateKeyPair(); + } + } + + public void performTest() + throws Exception + { + generalKeyTest(); + testDefault(64, g512, p512); + mqvTest(); + + testEnc(); + testGP("DH", 512, 0, g512, p512); + testGP("DiffieHellman", 768, 0, g768, p768); + testGP("DIFFIEHELLMAN", 1024, 0, g1024, p1024); + testGP("DH", 512, 64, g512, p512); + testGP("DiffieHellman", 768, 128, g768, p768); + testGP("DIFFIEHELLMAN", 1024, 256, g1024, p1024); + testExplicitWrapping(512, 0, g512, p512); + testRandom(256); + + testECDH("ECDH"); + testECDH("ECDHC"); + testECDH("ECDH", "secp521r1", "AES", 256); + testECDH("ECDH", "secp521r1", "DESEDE", 192); + testECDH("ECDH", "secp521r1", "DES", 64); + testECDH("ECDHwithSHA1KDF", "secp521r1", "AES", 256); + testECDH("ECDHwithSHA1KDF", "secp521r1", "DESEDE", 192); + testECDH("ECDH", "Curve25519", "AES", 256); + testECDH("ECDH", "Curve25519", "DESEDE", 192); + testECDH("ECDH", "Curve25519", "DES", 64); + testECDH("ECDHwithSHA1KDF", "Curve25519", "AES", 256); + testECDH("ECKAEGWITHSHA1KDF", "secp256r1", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA1, "DESEDE", 192); + testECDH("ECKAEGWITHSHA224KDF", "secp256r1", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA224, "DESEDE", 192); + testECDH("ECKAEGWITHSHA256KDF", "secp256r1", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA256, "DESEDE", 192); + testECDH("ECKAEGWITHSHA384KDF", "secp256r1", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA384,"AES", 256); + testECDH("ECKAEGWITHSHA512KDF", "secp256r1", BSIObjectIdentifiers.ecka_eg_X963kdf_SHA512,"DESEDE", 192); + testECDH("ECKAEGWITHRIPEMD160KDF", "secp256r1", BSIObjectIdentifiers.ecka_eg_X963kdf_RIPEMD160, "AES", 256); + + testExceptions(); + testDESAndDESede(g768, p768); + testInitialise(); + testSmallSecret(); + testConfig(); + testSubgroupConfinement(); + + testECUnifiedTestVector1(); + testECUnifiedTestVector2(); + testECUnifiedTestVector3(); + + testDHUnifiedTestVector1(); + + testMinSpecValue(); + testGenerateUsingStandardGroup(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new DHTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DRBGTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DRBGTest.java new file mode 100644 index 000000000..00da5cdb1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DRBGTest.java @@ -0,0 +1,37 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.SecureRandom; +import java.security.Security; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * This test needs to be run with -Djava.security.debug=provider + */ +public class DRBGTest + extends SimpleTest +{ + public DRBGTest() + { + } + + public String getName() + { + return "DRBG"; + } + + public void performTest() + throws Exception + { + Security.addProvider(new BouncyCastleProvider()); + + SecureRandom.getInstance("DEFAULT", "BC"); + } + + public static void main( + String[] args) + { + runTest(new DRBGTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DSATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DSATest.java new file mode 100644 index 000000000..fd57904ee --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DSATest.java @@ -0,0 +1,1392 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.math.BigInteger; +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.DSAParameterSpec; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.eac.EACObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.nist.NISTNamedCurves; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.params.DSAParameters; +import com.fr.third.org.bouncycastle.crypto.params.DSAPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.signers.DSASigner; +import com.fr.third.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.FixedSecureRandom; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; +import com.fr.third.org.bouncycastle.util.test.TestRandomData; + +public class DSATest + extends SimpleTest +{ + byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); + byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); + + SecureRandom random = new FixedSecureRandom(new byte[][] { k1, k2 }); + + // DSA modified signatures, courtesy of the Google security team + static final DSAPrivateKeySpec PRIVATE_KEY = new DSAPrivateKeySpec( + // x + new BigInteger( + "15382583218386677486843706921635237927801862255437148328980464126979"), + // p + new BigInteger( + "181118486631420055711787706248812146965913392568235070235446058914" + + "1170708161715231951918020125044061516370042605439640379530343556" + + "4101919053459832890139496933938670005799610981765220283775567361" + + "4836626483403394052203488713085936276470766894079318754834062443" + + "1033792580942743268186462355159813630244169054658542719322425431" + + "4088256212718983105131138772434658820375111735710449331518776858" + + "7867938758654181244292694091187568128410190746310049564097068770" + + "8161261634790060655580211122402292101772553741704724263582994973" + + "9109274666495826205002104010355456981211025738812433088757102520" + + "562459649777989718122219159982614304359"), + // q + new BigInteger( + "19689526866605154788513693571065914024068069442724893395618704484701"), + // g + new BigInteger( + "2859278237642201956931085611015389087970918161297522023542900348" + + "0877180630984239764282523693409675060100542360520959501692726128" + + "3149190229583566074777557293475747419473934711587072321756053067" + + "2532404847508798651915566434553729839971841903983916294692452760" + + "2490198571084091890169933809199002313226100830607842692992570749" + + "0504363602970812128803790973955960534785317485341020833424202774" + + "0275688698461842637641566056165699733710043802697192696426360843" + + "1736206792141319514001488556117408586108219135730880594044593648" + + "9237302749293603778933701187571075920849848690861126195402696457" + + "4111219599568903257472567764789616958430")); + + static final DSAPublicKeySpec PUBLIC_KEY = new DSAPublicKeySpec( + new BigInteger( + "3846308446317351758462473207111709291533523711306097971550086650" + + "2577333637930103311673872185522385807498738696446063139653693222" + + "3528823234976869516765207838304932337200968476150071617737755913" + + "3181601169463467065599372409821150709457431511200322947508290005" + + "1780020974429072640276810306302799924668893998032630777409440831" + + "4314588994475223696460940116068336991199969153649625334724122468" + + "7497038281983541563359385775312520539189474547346202842754393945" + + "8755803223951078082197762886933401284142487322057236814878262166" + + "5072306622943221607031324846468109901964841479558565694763440972" + + "5447389416166053148132419345627682740529"), + PRIVATE_KEY.getP(), + PRIVATE_KEY.getQ(), + PRIVATE_KEY.getG()); + + // The following test vectors check for signature malleability and bugs. That means the test + // vectors are derived from a valid signature by modifying the ASN encoding. A correct + // implementation of DSA should only accept correct DER encoding and properly handle the others. + // Allowing alternative BER encodings is in many cases benign. An example where this kind of + // signature malleability was a problem: https://en.bitcoin.it/wiki/Transaction_Malleability + static final String[] MODIFIED_SIGNATURES = { + "303e02811c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9e" + + "f41dd424a4e1c8f16967cf3365813fe8786236", + "303f0282001c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f" + + "9ef41dd424a4e1c8f16967cf3365813fe8786236", + "303e021d001e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9e" + + "f41dd424a4e1c8f16967cf3365813fe8786236", + "303e021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd02811d00ade65988d237d30f9e" + + "f41dd424a4e1c8f16967cf3365813fe8786236", + "303f021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd0282001d00ade65988d237d30f" + + "9ef41dd424a4e1c8f16967cf3365813fe8786236", + "303e021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021e0000ade65988d237d30f9e" + + "f41dd424a4e1c8f16967cf3365813fe8786236", + "30813d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9e" + + "f41dd424a4e1c8f16967cf3365813fe8786236", + "3082003d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f" + + "9ef41dd424a4e1c8f16967cf3365813fe8786236", + "303d021c1e41b479ad576905b960fe14eadb91b0ccf34843dab916173bb8c9cd021d00ade65988d237d30f9ef4" + + "1dd424a4e1c8f16967cf3365813fe87862360000", + "3040021c57b10411b54ab248af03d8f2456676ebc6d3db5f1081492ac87e9ca8021d00942b117051d7d9d107fc42cac9c5a36a1fd7f0f8916ccca86cec4ed3040100", + "303e021c57b10411b54ab248af03d8f2456676ebc6d3db5f1081492ac87e9ca802811d00942b117051d7d9d107fc42cac9c5a36a1fd7f0f8916ccca86cec4ed3" + }; + + private void testModified() + throws Exception + { + KeyFactory kFact = KeyFactory.getInstance("DSA", "BC"); + PublicKey pubKey = kFact.generatePublic(PUBLIC_KEY); + Signature sig = Signature.getInstance("DSA", "BC"); + + for (int i = 0; i != MODIFIED_SIGNATURES.length; i++) + { + sig.initVerify(pubKey); + + sig.update(Strings.toByteArray("Hello")); + + boolean failed; + + try + { + failed = !sig.verify(Hex.decode(MODIFIED_SIGNATURES[i])); + } + catch (SignatureException e) + { + failed = true; + } + + isTrue("sig verified when shouldn't", failed); + } + } + + private void testCompat() + throws Exception + { + if (Security.getProvider("SUN") == null) + { + return; + } + + Signature s = Signature.getInstance("DSA", "SUN"); + KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "SUN"); + byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + + g.initialize(512, new SecureRandom()); + + KeyPair p = g.generateKeyPair(); + + PrivateKey sKey = p.getPrivate(); + PublicKey vKey = p.getPublic(); + + // + // sign SUN - verify with BC + // + s.initSign(sKey); + + s.update(data); + + byte[] sigBytes = s.sign(); + + s = Signature.getInstance("DSA", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("SUN -> BC verification failed"); + } + + // + // sign BC - verify with SUN + // + + s.initSign(sKey); + + s.update(data); + + sigBytes = s.sign(); + + s = Signature.getInstance("DSA", "SUN"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("BC -> SUN verification failed"); + } + + // + // key encoding test - BC decoding Sun keys + // + KeyFactory f = KeyFactory.getInstance("DSA", "BC"); + X509EncodedKeySpec x509s = new X509EncodedKeySpec(vKey.getEncoded()); + + DSAPublicKey k1 = (DSAPublicKey)f.generatePublic(x509s); + + checkPublic(k1, vKey); + + PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(sKey.getEncoded()); + + DSAPrivateKey k2 = (DSAPrivateKey)f.generatePrivate(pkcs8); + + checkPrivateKey(k2, sKey); + + // + // key decoding test - SUN decoding BC keys + // + f = KeyFactory.getInstance("DSA", "SUN"); + x509s = new X509EncodedKeySpec(k1.getEncoded()); + + vKey = (DSAPublicKey)f.generatePublic(x509s); + + checkPublic(k1, vKey); + + pkcs8 = new PKCS8EncodedKeySpec(k2.getEncoded()); + sKey = f.generatePrivate(pkcs8); + + checkPrivateKey(k2, sKey); + } + + private void testNullParameters() + throws Exception + { + KeyFactory f = KeyFactory.getInstance("DSA", "BC"); + X509EncodedKeySpec x509s = new X509EncodedKeySpec(new SubjectPublicKeyInfo(new AlgorithmIdentifier(X9ObjectIdentifiers.id_dsa), new ASN1Integer(10001)).getEncoded()); + + DSAPublicKey key1 = (DSAPublicKey)f.generatePublic(x509s); + DSAPublicKey key2 = (DSAPublicKey)f.generatePublic(x509s); + + isTrue("parameters not absent", key1.getParams() == null && key2.getParams() == null); + isTrue("hashCode mismatch", key1.hashCode() == key2.hashCode()); + isTrue("not equal", key1.equals(key2)); + isTrue("encoding mismatch", Arrays.areEqual(x509s.getEncoded(), key1.getEncoded())); + } + + private void testValidate() + throws Exception + { + DSAParameterSpec dsaParams = new DSAParameterSpec( + new BigInteger( + "F56C2A7D366E3EBDEAA1891FD2A0D099" + + "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" + + "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" + + "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" + + "5909132627F51A0C866877E672E555342BDF9355347DBD43" + + "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" + + "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" + + "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" + + "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" + + "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" + + "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16), + new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16), + new BigInteger( + "8DC6CC814CAE4A1C05A3E186A6FE27EA" + + "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" + + "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" + + "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" + + "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" + + "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" + + "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" + + "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" + + "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" + + "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" + + "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16) + ); + + KeyFactory f = KeyFactory.getInstance("DSA", "BC"); + + try + { + f.generatePublic(new DSAPublicKeySpec(BigInteger.valueOf(1), dsaParams.getP(), dsaParams.getG(), dsaParams.getQ())); + + fail("no exception"); + } + catch (Exception e) + { + isTrue("mismatch", "invalid KeySpec: y value does not appear to be in correct group".equals(e.getMessage())); + } + } + + private void testNONEwithDSA() + throws Exception + { + byte[] dummySha1 = Hex.decode("01020304050607080910111213141516"); + + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("DSA", "BC"); + + kpGen.initialize(512); + + KeyPair kp = kpGen.generateKeyPair(); + + Signature sig = Signature.getInstance("NONEwithDSA", "BC"); + + sig.initSign(kp.getPrivate()); + + sig.update(dummySha1); + + byte[] sigBytes = sig.sign(); + + sig.initVerify(kp.getPublic()); + + sig.update(dummySha1); + + sig.verify(sigBytes); + + // reset test + + sig.update(dummySha1); + + if (!sig.verify(sigBytes)) + { + fail("NONEwithDSA failed to reset"); + } + + // lightweight test + DSAPublicKey key = (DSAPublicKey)kp.getPublic(); + DSAParameters params = new DSAParameters(key.getParams().getP(), key.getParams().getQ(), key.getParams().getG()); + DSAPublicKeyParameters keyParams = new DSAPublicKeyParameters(key.getY(), params); + DSASigner signer = new DSASigner(); + ASN1Sequence derSig = ASN1Sequence.getInstance(ASN1Primitive.fromByteArray(sigBytes)); + + signer.init(false, keyParams); + + if (!signer.verifySignature(dummySha1, ASN1Integer.getInstance(derSig.getObjectAt(0)).getValue(), ASN1Integer.getInstance(derSig.getObjectAt(1)).getValue())) + { + fail("NONEwithDSA not really NONE!"); + } + } + + private void checkPublic(DSAPublicKey k1, PublicKey vKey) + { + if (!k1.getY().equals(((DSAPublicKey)vKey).getY())) + { + fail("public number not decoded properly"); + } + + if (!k1.getParams().getG().equals(((DSAPublicKey)vKey).getParams().getG())) + { + fail("public generator not decoded properly"); + } + + if (!k1.getParams().getP().equals(((DSAPublicKey)vKey).getParams().getP())) + { + fail("public p value not decoded properly"); + } + + if (!k1.getParams().getQ().equals(((DSAPublicKey)vKey).getParams().getQ())) + { + fail("public q value not decoded properly"); + } + } + + private void checkPrivateKey(DSAPrivateKey k2, PrivateKey sKey) + { + if (!k2.getX().equals(((DSAPrivateKey)sKey).getX())) + { + fail("private number not decoded properly"); + } + + if (!k2.getParams().getG().equals(((DSAPrivateKey)sKey).getParams().getG())) + { + fail("private generator not decoded properly"); + } + + if (!k2.getParams().getP().equals(((DSAPrivateKey)sKey).getParams().getP())) + { + fail("private p value not decoded properly"); + } + + if (!k2.getParams().getQ().equals(((DSAPrivateKey)sKey).getParams().getQ())) + { + fail("private q value not decoded properly"); + } + } + + private Object serializeDeserialize(Object o) + throws Exception + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(o); + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + return oIn.readObject(); + } + + /** + * X9.62 - 1998,
+ * J.3.2, Page 155, ECDSA over the field Fp
+ * an example with 239 bit prime + */ + private void testECDSA239bitPrime() + throws Exception + { + BigInteger r = new BigInteger("308636143175167811492622547300668018854959378758531778147462058306432176"); + BigInteger s = new BigInteger("323813553209797357708078776831250505931891051755007842781978505179448783"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); + + SecureRandom k = new TestRandomBigInteger(kData); + + X9ECParameters x9 = ECNamedCurveTable.getByName("prime239v1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec spec = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q + spec); + + Signature sgr = Signature.getInstance("ECDSA", "BC"); + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + PrivateKey sKey = f.generatePrivate(priKey); + PublicKey vKey = f.generatePublic(pubKey); + + sgr.initSign(sKey, k); + + byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail("239 Bit EC verification failed"); + } + + BigInteger[] sig = derDecode(sigBytes); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + } + + private void testNONEwithECDSA239bitPrime() + throws Exception + { + X9ECParameters x9 = ECNamedCurveTable.getByName("prime239v1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec spec = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q + spec); + + Signature sgr = Signature.getInstance("NONEwithECDSA", "BC"); + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + PrivateKey sKey = f.generatePrivate(priKey); + PublicKey vKey = f.generatePublic(pubKey); + + byte[] message = "abc".getBytes(); + byte[] sig = Hex.decode("3040021e2cb7f36803ebb9c427c58d8265f11fc5084747133078fc279de874fbecb0021e64cb19604be06c57e761b3de5518f71de0f6e0cd2df677cec8a6ffcb690d"); + + checkMessage(sgr, sKey, vKey, message, sig); + + message = "abcdefghijklmnopqrstuvwxyz".getBytes(); + sig = Hex.decode("3040021e2cb7f36803ebb9c427c58d8265f11fc5084747133078fc279de874fbecb0021e43fd65b3363d76aabef8630572257dbb67c82818ad9fad31256539b1b02c"); + + checkMessage(sgr, sKey, vKey, message, sig); + + message = "a very very long message gauranteed to cause an overflow".getBytes(); + sig = Hex.decode("3040021e2cb7f36803ebb9c427c58d8265f11fc5084747133078fc279de874fbecb0021e7d5be84b22937a1691859a3c6fe45ed30b108574431d01b34025825ec17a"); + + checkMessage(sgr, sKey, vKey, message, sig); + } + + private void testECDSAP256sha3(ASN1ObjectIdentifier sigOid, int size, BigInteger s) + throws Exception + { + X9ECParameters p = NISTNamedCurves.getByName("P-256"); + KeyFactory ecKeyFact = KeyFactory.getInstance("EC", "BC"); + + ECDomainParameters params = new ECDomainParameters(p.getCurve(), p.getG(), p.getN(), p.getH()); + + ECCurve curve = p.getCurve(); + + ECParameterSpec spec = new ECParameterSpec( + curve, + p.getG(), // G + p.getN()); // n + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("20186677036482506117540275567393538695075300175221296989956723148347484984008"), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + params.getCurve().decodePoint(Hex.decode("03596375E6CE57E0F20294FC46BDFCFD19A39F8161B58695B3EC5B3D16427C274D")), // Q + spec); + + doEcDsaTest("SHA3-" + size + "withECDSA", s, ecKeyFact, pubKey, priKey); + doEcDsaTest(sigOid.getId(), s, ecKeyFact, pubKey, priKey); + } + + private void doEcDsaTest(String sigName, BigInteger s, KeyFactory ecKeyFact, ECPublicKeySpec pubKey, ECPrivateKeySpec priKey) + throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, InvalidKeySpecException, SignatureException + { + SecureRandom k = new TestRandomBigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))); + + byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); + + Signature dsa = Signature.getInstance(sigName, "BC"); + + dsa.initSign(ecKeyFact.generatePrivate(priKey), k); + + dsa.update(M, 0, M.length); + + byte[] encSig = dsa.sign(); + + ASN1Sequence sig = ASN1Sequence.getInstance(encSig); + + BigInteger r = new BigInteger("97354732615802252173078420023658453040116611318111190383344590814578738210384"); + + BigInteger sigR = ASN1Integer.getInstance(sig.getObjectAt(0)).getValue(); + if (!r.equals(sigR)) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sigR.toString(16)); + } + + BigInteger sigS = ASN1Integer.getInstance(sig.getObjectAt(1)).getValue(); + if (!s.equals(sigS)) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sigS.toString(16)); + } + + // Verify the signature + dsa.initVerify(ecKeyFact.generatePublic(pubKey)); + + dsa.update(M, 0, M.length); + + if (!dsa.verify(encSig)) + { + fail("signature fails"); + } + } + + private void testDSAsha3(ASN1ObjectIdentifier sigOid, int size, BigInteger s) + throws Exception + { + DSAParameterSpec dsaParams = new DSAParameterSpec( + new BigInteger( + "F56C2A7D366E3EBDEAA1891FD2A0D099" + + "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" + + "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" + + "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" + + "5909132627F51A0C866877E672E555342BDF9355347DBD43" + + "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" + + "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" + + "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" + + "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" + + "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" + + "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16), + new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16), + new BigInteger( + "8DC6CC814CAE4A1C05A3E186A6FE27EA" + + "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" + + "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" + + "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" + + "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" + + "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" + + "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" + + "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" + + "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" + + "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" + + "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16) + ); + + BigInteger x = new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16); + + BigInteger y = new BigInteger( + "2828003D7C747199143C370FDD07A286" + + "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" + + "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" + + "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" + + "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" + + "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" + + "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" + + "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" + + "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" + + "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" + + "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16); + + DSAPrivateKeySpec priKey = new DSAPrivateKeySpec( + x, dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()); + + DSAPublicKeySpec pubKey = new DSAPublicKeySpec( + y, dsaParams.getP(), dsaParams.getQ(), dsaParams.getG()); + + KeyFactory dsaKeyFact = KeyFactory.getInstance("DSA", "BC"); + + doDsaTest("SHA3-" + size + "withDSA", s, dsaKeyFact, pubKey, priKey); + doDsaTest(sigOid.getId(), s, dsaKeyFact, pubKey, priKey); + } + + private void doDsaTest(String sigName, BigInteger s, KeyFactory ecKeyFact, DSAPublicKeySpec pubKey, DSAPrivateKeySpec priKey) + throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, InvalidKeySpecException, SignatureException + { + SecureRandom k = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.BigInteger(BigIntegers.asUnsignedByteArray(new BigInteger("72546832179840998877302529996971396893172522460793442785601695562409154906335"))), + new FixedSecureRandom.Data(Hex.decode("01020304")) }); + + byte[] M = Hex.decode("1BD4ED430B0F384B4E8D458EFF1A8A553286D7AC21CB2F6806172EF5F94A06AD"); + + Signature dsa = Signature.getInstance(sigName, "BC"); + + dsa.initSign(ecKeyFact.generatePrivate(priKey), k); + + dsa.update(M, 0, M.length); + + byte[] encSig = dsa.sign(); + + ASN1Sequence sig = ASN1Sequence.getInstance(encSig); + + BigInteger r = new BigInteger("4864074fe30e6601268ee663440e4d9b703f62673419864e91e9edb0338ce510", 16); + + BigInteger sigR = ASN1Integer.getInstance(sig.getObjectAt(0)).getValue(); + if (!r.equals(sigR)) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r.toString(16) + Strings.lineSeparator() + + " got : " + sigR.toString(16)); + } + + BigInteger sigS = ASN1Integer.getInstance(sig.getObjectAt(1)).getValue(); + if (!s.equals(sigS)) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s.toString(16) + Strings.lineSeparator() + + " got : " + sigS.toString(16)); + } + + // Verify the signature + dsa.initVerify(ecKeyFact.generatePublic(pubKey)); + + dsa.update(M, 0, M.length); + + if (!dsa.verify(encSig)) + { + fail("signature fails"); + } + } + + private void checkMessage(Signature sgr, PrivateKey sKey, PublicKey vKey, byte[] message, byte[] sig) + throws InvalidKeyException, SignatureException + { + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); + + SecureRandom k = new TestRandomBigInteger(kData); + + sgr.initSign(sKey, k); + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + if (!Arrays.areEqual(sigBytes, sig)) + { + fail(new String(message) + " signature incorrect"); + } + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail(new String(message) + " verification failed"); + } + } + + /** + * X9.62 - 1998,
+ * J.2.1, Page 100, ECDSA over the field F2m
+ * an example with 191 bit binary field + */ + private void testECDSA239bitBinary() + throws Exception + { + BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552"); + BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); + + SecureRandom k = new TestRandomBigInteger(kData); + + X9ECParameters x9 = ECNamedCurveTable.getByName("c2tnb239v1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec params = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + ECPrivateKeySpec priKeySpec = new ECPrivateKeySpec( + new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d + params); + + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec( + curve.decodePoint(Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q + params); + + Signature sgr = Signature.getInstance("ECDSA", "BC"); + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + PrivateKey sKey = f.generatePrivate(priKeySpec); + PublicKey vKey = f.generatePublic(pubKeySpec); + byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + + sgr.initSign(sKey, k); + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail("239 Bit EC verification failed"); + } + + BigInteger[] sig = derDecode(sigBytes); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + } + + private void testECDSA239bitBinary(String algorithm, ASN1ObjectIdentifier oid) + throws Exception + { + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); + + SecureRandom k = new TestRandomBigInteger(kData); + + X9ECParameters x9 = ECNamedCurveTable.getByName("c2tnb239v1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec params = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + ECPrivateKeySpec priKeySpec = new ECPrivateKeySpec( + new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d + params); + + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec( + curve.decodePoint(Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q + params); + + Signature sgr = Signature.getInstance(algorithm, "BC"); + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + PrivateKey sKey = f.generatePrivate(priKeySpec); + PublicKey vKey = f.generatePublic(pubKeySpec); + byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + + sgr.initSign(sKey, k); + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr = Signature.getInstance(oid.getId(), "BC"); + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail("239 Bit EC RIPEMD160 verification failed"); + } + } + + private void testGeneration() + throws Exception + { + Signature s = Signature.getInstance("DSA", "BC"); + KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "BC"); + byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + + + // test exception + // + try + { + g.initialize(513, new SecureRandom()); + + fail("illegal parameter 513 check failed."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + g.initialize(510, new SecureRandom()); + + fail("illegal parameter 510 check failed."); + } + catch (IllegalArgumentException e) + { + // expected + } + + try + { + g.initialize(1025, new SecureRandom()); + + fail("illegal parameter 1025 check failed."); + } + catch (IllegalArgumentException e) + { + // expected + } + + g.initialize(512, new SecureRandom()); + + KeyPair p = g.generateKeyPair(); + + PrivateKey sKey = p.getPrivate(); + PublicKey vKey = p.getPublic(); + + s.initSign(sKey); + + s.update(data); + + byte[] sigBytes = s.sign(); + + s = Signature.getInstance("DSA", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("DSA verification failed"); + } + + // + // key decoding test - serialisation test + // + + DSAPublicKey k1 = (DSAPublicKey)serializeDeserialize(vKey); + + checkPublic(k1, vKey); + + checkEquals(k1, vKey); + + DSAPrivateKey k2 = (DSAPrivateKey)serializeDeserialize(sKey); + + checkPrivateKey(k2, sKey); + + checkEquals(k2, sKey); + + if (!(k2 instanceof PKCS12BagAttributeCarrier)) + { + fail("private key not implementing PKCS12 attribute carrier"); + } + + // + // ECDSA Fp generation test + // + s = Signature.getInstance("ECDSA", "BC"); + g = KeyPairGenerator.getInstance("ECDSA", "BC"); + + X9ECParameters x9 = ECNamedCurveTable.getByName("prime239v1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec ecSpec = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + g.initialize(ecSpec, new SecureRandom()); + + p = g.generateKeyPair(); + + sKey = p.getPrivate(); + vKey = p.getPublic(); + + s.initSign(sKey); + + s.update(data); + + sigBytes = s.sign(); + + s = Signature.getInstance("ECDSA", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("ECDSA verification failed"); + } + + // + // key decoding test - serialisation test + // + + PublicKey eck1 = (PublicKey)serializeDeserialize(vKey); + + checkEquals(eck1, vKey); + + PrivateKey eck2 = (PrivateKey)serializeDeserialize(sKey); + + checkEquals(eck2, sKey); + + // Named curve parameter + g.initialize(new ECNamedCurveGenParameterSpec("P-256"), new SecureRandom()); + + p = g.generateKeyPair(); + + sKey = p.getPrivate(); + vKey = p.getPublic(); + + s.initSign(sKey); + + s.update(data); + + sigBytes = s.sign(); + + s = Signature.getInstance("ECDSA", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("ECDSA verification failed"); + } + + // + // key decoding test - serialisation test + // + + eck1 = (PublicKey)serializeDeserialize(vKey); + + checkEquals(eck1, vKey); + + eck2 = (PrivateKey)serializeDeserialize(sKey); + + checkEquals(eck2, sKey); + + // + // ECDSA F2m generation test + // + s = Signature.getInstance("ECDSA", "BC"); + g = KeyPairGenerator.getInstance("ECDSA", "BC"); + + x9 = ECNamedCurveTable.getByName("c2tnb239v1"); + curve = x9.getCurve(); + ecSpec = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + g.initialize(ecSpec, new SecureRandom()); + + p = g.generateKeyPair(); + + sKey = p.getPrivate(); + vKey = p.getPublic(); + + s.initSign(sKey); + + s.update(data); + + sigBytes = s.sign(); + + s = Signature.getInstance("ECDSA", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("ECDSA verification failed"); + } + + // + // key decoding test - serialisation test + // + + eck1 = (PublicKey)serializeDeserialize(vKey); + + checkEquals(eck1, vKey); + + eck2 = (PrivateKey)serializeDeserialize(sKey); + + checkEquals(eck2, sKey); + + if (!(eck2 instanceof PKCS12BagAttributeCarrier)) + { + fail("private key not implementing PKCS12 attribute carrier"); + } + } + + private void checkEquals(Object o1, Object o2) + { + if (!o1.equals(o2)) + { + fail("comparison test failed"); + } + + if (o1.hashCode() != o2.hashCode()) + { + fail("hashCode test failed"); + } + } + + private void testParameters() + throws Exception + { + AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("DSA", "BC"); + a.init(512, random); + AlgorithmParameters params = a.generateParameters(); + + byte[] encodeParams = params.getEncoded(); + + AlgorithmParameters a2 = AlgorithmParameters.getInstance("DSA", "BC"); + a2.init(encodeParams); + + // a and a2 should be equivalent! + byte[] encodeParams_2 = a2.getEncoded(); + + if (!areEqual(encodeParams, encodeParams_2)) + { + fail("encode/decode parameters failed"); + } + + DSAParameterSpec dsaP = (DSAParameterSpec)params.getParameterSpec(DSAParameterSpec.class); + + KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "BC"); + g.initialize(dsaP, new SecureRandom()); + KeyPair p = g.generateKeyPair(); + + PrivateKey sKey = p.getPrivate(); + PublicKey vKey = p.getPublic(); + + Signature s = Signature.getInstance("DSA", "BC"); + byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + + s.initSign(sKey); + + s.update(data); + + byte[] sigBytes = s.sign(); + + s = Signature.getInstance("DSA", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("DSA verification failed"); + } + } + + private void testDSA2Parameters() + throws Exception + { + byte[] seed = Hex.decode("4783081972865EA95D43318AB2EAF9C61A2FC7BBF1B772A09017BDF5A58F4FF0"); + + AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("DSA", "BC"); + a.init(2048, new DSATestSecureRandom(seed)); + AlgorithmParameters params = a.generateParameters(); + + DSAParameterSpec dsaP = (DSAParameterSpec)params.getParameterSpec(DSAParameterSpec.class); + + if (!dsaP.getQ().equals(new BigInteger("C24ED361870B61E0D367F008F99F8A1F75525889C89DB1B673C45AF5867CB467", 16))) + { + fail("Q incorrect"); + } + + if (!dsaP.getP().equals(new BigInteger( + "F56C2A7D366E3EBDEAA1891FD2A0D099" + + "436438A673FED4D75F594959CFFEBCA7BE0FC72E4FE67D91" + + "D801CBA0693AC4ED9E411B41D19E2FD1699C4390AD27D94C" + + "69C0B143F1DC88932CFE2310C886412047BD9B1C7A67F8A2" + + "5909132627F51A0C866877E672E555342BDF9355347DBD43" + + "B47156B2C20BAD9D2B071BC2FDCF9757F75C168C5D9FC431" + + "31BE162A0756D1BDEC2CA0EB0E3B018A8B38D3EF2487782A" + + "EB9FBF99D8B30499C55E4F61E5C7DCEE2A2BB55BD7F75FCD" + + "F00E48F2E8356BDB59D86114028F67B8E07B127744778AFF" + + "1CF1399A4D679D92FDE7D941C5C85C5D7BFF91BA69F9489D" + + "531D1EBFA727CFDA651390F8021719FA9F7216CEB177BD75", 16))) + { + fail("P incorrect"); + } + + if (!dsaP.getG().equals(new BigInteger( + "8DC6CC814CAE4A1C05A3E186A6FE27EA" + + "BA8CDB133FDCE14A963A92E809790CBA096EAA26140550C1" + + "29FA2B98C16E84236AA33BF919CD6F587E048C52666576DB" + + "6E925C6CBE9B9EC5C16020F9A44C9F1C8F7A8E611C1F6EC2" + + "513EA6AA0B8D0F72FED73CA37DF240DB57BBB27431D61869" + + "7B9E771B0B301D5DF05955425061A30DC6D33BB6D2A32BD0" + + "A75A0A71D2184F506372ABF84A56AEEEA8EB693BF29A6403" + + "45FA1298A16E85421B2208D00068A5A42915F82CF0B858C8" + + "FA39D43D704B6927E0B2F916304E86FB6A1B487F07D8139E" + + "428BB096C6D67A76EC0B8D4EF274B8A2CF556D279AD267CC" + + "EF5AF477AFED029F485B5597739F5D0240F67C2D948A6279", 16))) + { + fail("G incorrect"); + } + + KeyPairGenerator g = KeyPairGenerator.getInstance("DSA", "BC"); + g.initialize(dsaP, new TestRandomBigInteger(Hex.decode("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C"))); + KeyPair p = g.generateKeyPair(); + + DSAPrivateKey sKey = (DSAPrivateKey)p.getPrivate(); + DSAPublicKey vKey = (DSAPublicKey)p.getPublic(); + + if (!vKey.getY().equals(new BigInteger( + "2828003D7C747199143C370FDD07A286" + + "1524514ACC57F63F80C38C2087C6B795B62DE1C224BF8D1D" + + "1424E60CE3F5AE3F76C754A2464AF292286D873A7A30B7EA" + + "CBBC75AAFDE7191D9157598CDB0B60E0C5AA3F6EBE425500" + + "C611957DBF5ED35490714A42811FDCDEB19AF2AB30BEADFF" + + "2907931CEE7F3B55532CFFAEB371F84F01347630EB227A41" + + "9B1F3F558BC8A509D64A765D8987D493B007C4412C297CAF" + + "41566E26FAEE475137EC781A0DC088A26C8804A98C23140E" + + "7C936281864B99571EE95C416AA38CEEBB41FDBFF1EB1D1D" + + "C97B63CE1355257627C8B0FD840DDB20ED35BE92F08C49AE" + + "A5613957D7E5C7A6D5A5834B4CB069E0831753ECF65BA02B", 16))) + { + fail("Y value incorrect"); + } + + if (!sKey.getX().equals( + new BigInteger("0CAF2EF547EC49C4F3A6FE6DF4223A174D01F2C115D49A6F73437C29A2A8458C", 16))) + { + fail("X value incorrect"); + } + + byte[] encodeParams = params.getEncoded(); + + AlgorithmParameters a2 = AlgorithmParameters.getInstance("DSA", "BC"); + a2.init(encodeParams); + + // a and a2 should be equivalent! + byte[] encodeParams_2 = a2.getEncoded(); + + if (!areEqual(encodeParams, encodeParams_2)) + { + fail("encode/decode parameters failed"); + } + + Signature s = Signature.getInstance("DSA", "BC"); + byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + + s.initSign(sKey); + + s.update(data); + + byte[] sigBytes = s.sign(); + + s = Signature.getInstance("DSA", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("DSA verification failed"); + } + } + + private void testKeyGeneration(int keysize) + throws Exception + { + KeyPairGenerator generator = KeyPairGenerator.getInstance("DSA", "BC"); + generator.initialize(keysize); + KeyPair keyPair = generator.generateKeyPair(); + DSAPrivateKey priv = (DSAPrivateKey)keyPair.getPrivate(); + DSAParams params = priv.getParams(); + isTrue("keysize mismatch", keysize == params.getP().bitLength()); + // The NIST standard does not fully specify the size of q that + // must be used for a given key size. Hence there are differences. + // For example if keysize = 2048, then OpenSSL uses 256 bit q's by default, + // but the SUN provider uses 224 bits. Both are acceptable sizes. + // The tests below simply asserts that the size of q does not decrease the + // overall security of the DSA. + int qsize = params.getQ().bitLength(); + switch (keysize) + { + case 1024: + isTrue("Invalid qsize for 1024 bit key:" + qsize, qsize >= 160); + break; + case 2048: + isTrue("Invalid qsize for 2048 bit key:" + qsize, qsize >= 224); + break; + case 3072: + isTrue("Invalid qsize for 3072 bit key:" + qsize, qsize >= 256); + break; + default: + fail("Invalid key size:" + keysize); + } + // Check the length of the private key. + // For example GPG4Browsers or the KJUR library derived from it use + // q.bitCount() instead of q.bitLength() to determine the size of the private key + // and hence would generate keys that are much too small. + isTrue("privkey error", priv.getX().bitLength() >= qsize - 32); + } + + private void testKeyGenerationAll() + throws Exception + { + testKeyGeneration(1024); + testKeyGeneration(2048); + testKeyGeneration(3072); + } + + public void performTest() + throws Exception + { + testCompat(); + testNONEwithDSA(); + + testDSAsha3(NISTObjectIdentifiers.id_dsa_with_sha3_224, 224, new BigInteger("613202af2a7f77e02b11b5c3a5311cf6b412192bc0032aac3ec127faebfc6bd0", 16)); + testDSAsha3(NISTObjectIdentifiers.id_dsa_with_sha3_256, 256, new BigInteger("2450755c5e15a691b121bc833b97864e34a61ee025ecec89289c949c1858091e", 16)); + testDSAsha3(NISTObjectIdentifiers.id_dsa_with_sha3_384, 384, new BigInteger("7aad97c0b71bb1e1a6483b6948a03bbe952e4780b0cee699a11731f90d84ddd1", 16)); + testDSAsha3(NISTObjectIdentifiers.id_dsa_with_sha3_512, 512, new BigInteger("725ad64d923c668e64e7c3898b5efde484cab49ce7f98c2885d2a13a9e355ad4", 16)); + + testECDSA239bitPrime(); + testNONEwithECDSA239bitPrime(); + testECDSA239bitBinary(); + testECDSA239bitBinary("RIPEMD160withECDSA", TeleTrusTObjectIdentifiers.ecSignWithRipemd160); + testECDSA239bitBinary("SHA1withECDSA", TeleTrusTObjectIdentifiers.ecSignWithSha1); + testECDSA239bitBinary("SHA224withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224); + testECDSA239bitBinary("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256); + testECDSA239bitBinary("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384); + testECDSA239bitBinary("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512); + testECDSA239bitBinary("SHA1withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_1); + testECDSA239bitBinary("SHA224withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_224); + testECDSA239bitBinary("SHA256withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_256); + testECDSA239bitBinary("SHA384withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_384); + testECDSA239bitBinary("SHA512withCVC-ECDSA", EACObjectIdentifiers.id_TA_ECDSA_SHA_512); + + testECDSAP256sha3(NISTObjectIdentifiers.id_ecdsa_with_sha3_224, 224, new BigInteger("84d7d8e68e405064109cd9fc3e3026d74d278aada14ce6b7a9dd0380c154dc94", 16)); + testECDSAP256sha3(NISTObjectIdentifiers.id_ecdsa_with_sha3_256, 256, new BigInteger("99a43bdab4af989aaf2899079375642f2bae2dce05bcd8b72ec8c4a8d9a143f", 16)); + testECDSAP256sha3(NISTObjectIdentifiers.id_ecdsa_with_sha3_384, 384, new BigInteger("aa27726509c37aaf601de6f7e01e11c19add99530c9848381c23365dc505b11a", 16)); + testECDSAP256sha3(NISTObjectIdentifiers.id_ecdsa_with_sha3_512, 512, new BigInteger("f8306b57a1f5068bf12e53aabaae39e2658db39bc56747eaefb479995130ad16", 16)); + + testGeneration(); + testParameters(); + testDSA2Parameters(); + testNullParameters(); + testValidate(); + testModified(); + testKeyGenerationAll(); + } + + protected BigInteger[] derDecode( + byte[] encoding) + throws IOException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(encoding); + ASN1InputStream aIn = new ASN1InputStream(bIn); + ASN1Sequence s = (ASN1Sequence)aIn.readObject(); + + BigInteger[] sig = new BigInteger[2]; + + sig[0] = ((ASN1Integer)s.getObjectAt(0)).getValue(); + sig[1] = ((ASN1Integer)s.getObjectAt(1)).getValue(); + + return sig; + } + + public String getName() + { + return "DSA/ECDSA"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new DSATest()); + } + + private class DSATestSecureRandom + extends TestRandomData + { + private boolean first = true; + + public DSATestSecureRandom(byte[] value) + { + super(value); + } + + public void nextBytes(byte[] bytes) + { + if (first) + { + super.nextBytes(bytes); + first = false; + } + else + { + bytes[bytes.length - 1] = 2; + } + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DSTU4145Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DSTU4145Test.java new file mode 100644 index 000000000..957d2130b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DSTU4145Test.java @@ -0,0 +1,213 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.spec.ECGenParameterSpec; + +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; + +public class DSTU4145Test + extends SimpleTest +{ + + public String getName() + { + return "DSTU4145"; + } + + public void performTest() + throws Exception + { + + DSTU4145Test(); + generationTest(); + //parametersTest(); + generateFromCurveTest(); + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + runTest(new DSTU4145Test()); + } + + static final BigInteger r = new BigInteger("00f2702989366e9569d5092b83ac17f918bf040c487a", 16); + static final BigInteger s = new BigInteger("01dd460039db3be70392d7012f2a492d3e59091ab7a6", 16); + + private void generationTest() throws Exception + { + ECCurve.F2m curve = new ECCurve.F2m(173, 1, 2, 10, BigInteger.ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16)); + + ECParameterSpec spec = new ECParameterSpec( + curve, + curve.createPoint(new BigInteger("BE6628EC3E67A91A4E470894FBA72B52C515F8AEE9", 16), new BigInteger("D9DEEDF655CF5412313C11CA566CDC71F4DA57DB45C", 16)), + new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16)); + + SecureRandom k = new TestRandomBigInteger(Hex.decode("00137449348C1249971759D99C252FFE1E14D8B31F00")); + SecureRandom keyRand = new TestRandomBigInteger(Hex.decode("0000955CD7E344303D1034E66933DC21C8044D42ADB8")); + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSTU4145", "BC"); + keyGen.initialize(spec, keyRand); + KeyPair pair = keyGen.generateKeyPair(); + + Signature sgr = Signature.getInstance("DSTU4145", "BC"); + + sgr.initSign(pair.getPrivate(), k); + + byte[] message = new byte[]{(byte)'a', (byte)'b', (byte)'c'}; + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr.initVerify(pair.getPublic()); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail("DSTU4145 verification failed"); + } + + BigInteger[] sig = decode(sigBytes); + + if (!r.equals(sig[0])) + { + fail( + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + fail( + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + } + + private void generateFromCurveTest() + throws Exception + { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSTU4145", "BC"); + + for (int i = 0; i != 10; i++) + { + keyGen.initialize(new ECGenParameterSpec("1.2.804.2.1.1.1.1.3.1.1.2." + i)); + } + + try + { + keyGen.initialize(new ECGenParameterSpec("1.2.804.2.1.1.1.1.3.1.1.2." + 10)); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("unknown curve name: 1.2.804.2.1.1.1.1.3.1.1.2.10".equals(e.getMessage())); + } + } + + private void DSTU4145Test() + throws Exception + { + + SecureRandom k = new TestRandomBigInteger(Hex.decode("00137449348C1249971759D99C252FFE1E14D8B31F00")); + + ECCurve.F2m curve = new ECCurve.F2m(173, 1, 2, 10, BigInteger.ZERO, new BigInteger("108576C80499DB2FC16EDDF6853BBB278F6B6FB437D9", 16)); + + ECParameterSpec spec = new ECParameterSpec( + curve, + curve.createPoint(new BigInteger("BE6628EC3E67A91A4E470894FBA72B52C515F8AEE9", 16), new BigInteger("D9DEEDF655CF5412313C11CA566CDC71F4DA57DB45C", 16)), + new BigInteger("800000000000000000000189B4E67606E3825BB2831", 16)); + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("955CD7E344303D1034E66933DC21C8044D42ADB8", 16), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + curve.createPoint(new BigInteger("22de541d48a75c1c3b8c7c107b2551c5093c6c096e1", 16), new BigInteger("1e5b602efc0269d61e64d97c9193d2788fa05c4b7fd5", 16)), + spec); + + Signature sgr = Signature.getInstance("DSTU4145", "BC"); + KeyFactory f = KeyFactory.getInstance("DSTU4145", "BC"); + PrivateKey sKey = f.generatePrivate(priKey); + PublicKey vKey = f.generatePublic(pubKey); + + sgr.initSign(sKey, k); + + byte[] message = new byte[]{(byte)'a', (byte)'b', (byte)'c'}; + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail("DSTU4145 verification failed"); + } + + BigInteger[] sig = decode(sigBytes); + + if (!r.equals(sig[0])) + { + fail( + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0].toString(16)); + } + + if (!s.equals(sig[1])) + { + fail( + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1].toString(16)); + } + } + + private BigInteger[] decode( + byte[] encoding) + throws IOException + { + ASN1OctetString octetString = (ASN1OctetString)ASN1OctetString.fromByteArray(encoding); + encoding = octetString.getOctets(); + + byte[] r = new byte[encoding.length / 2]; + byte[] s = new byte[encoding.length / 2]; + + System.arraycopy(encoding, 0, s, 0, encoding.length / 2); + + System.arraycopy(encoding, encoding.length / 2, r, 0, encoding.length / 2); + + BigInteger[] sig = new BigInteger[2]; + + sig[0] = new BigInteger(1, r); + sig[1] = new BigInteger(1, s); + + return sig; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DSTU7624Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DSTU7624Test.java new file mode 100644 index 000000000..1f2117f7e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DSTU7624Test.java @@ -0,0 +1,359 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ua.UAObjectIdentifiers; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +/** + * basic test class for DSTU7624 + */ +public class DSTU7624Test + extends BaseBlockCipherTest +{ + public DSTU7624Test() + { + super("DSTU7624"); + } + + public void test( + String name, + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, name); + + in = Cipher.getInstance(name + "/ECB/NoPadding", "BC"); + out = Cipher.getInstance(name + "/ECB/NoPadding", "BC"); + + try + { + out.init(Cipher.ENCRYPT_MODE, key); + } + catch (Exception e) + { + fail("DSTU7624 failed initialisation - " + e.toString(), e); + } + + try + { + in.init(Cipher.DECRYPT_MODE, key); + } + catch (Exception e) + { + fail("DSTU7624 failed initialisation - " + e.toString(), e); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail("DSTU7624 failed encryption - " + e.toString(), e); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("DSTU7624 failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + } + catch (Exception e) + { + fail("DSTU7624 failed encryption - " + e.toString(), e); + } + + if (!areEqual(bytes, input)) + { + fail("DSTU7624 failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + public void performTest() + throws Exception + { + test("DSTU7624", Hex.decode("000102030405060708090A0B0C0D0E0F"), Hex.decode("101112131415161718191A1B1C1D1E1F"), Hex.decode("81BF1C7D779BAC20E1C9EA39B4D2AD06")); + test("DSTU7624", Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), Hex.decode("202122232425262728292A2B2C2D2E2F"), Hex.decode("58EC3E091000158A1148F7166F334F14")); + + test("DSTU7624-128", Hex.decode("000102030405060708090A0B0C0D0E0F"), Hex.decode("101112131415161718191A1B1C1D1E1F"), Hex.decode("81BF1C7D779BAC20E1C9EA39B4D2AD06")); + test("DSTU7624-128", Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), Hex.decode("202122232425262728292A2B2C2D2E2F"), Hex.decode("58EC3E091000158A1148F7166F334F14")); + + test("DSTU7624-256", Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"), Hex.decode("202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"), Hex.decode("F66E3D570EC92135AEDAE323DCBD2A8CA03963EC206A0D5A88385C24617FD92C")); + test("DSTU7624-256", Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"), Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F"), Hex.decode("606990E9E6B7B67A4BD6D893D72268B78E02C83C3CD7E102FD2E74A8FDFE5DD9")); + + test("DSTU7624-512", Hex.decode("000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F"), Hex.decode("404142434445464748494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E7F"), Hex.decode("4A26E31B811C356AA61DD6CA0596231A67BA8354AA47F3A13E1DEEC320EB56B895D0F417175BAB662FD6F134BB15C86CCB906A26856EFEB7C5BC6472940DD9D9")); + + byte[] kek1 = Hex.decode("000102030405060708090A0B0C0D0E0F"); + byte[] in1 = Hex.decode("101112131415161718191A1B1C1D1E1F"); + byte[] out1 = Hex.decode("1DC91DC6E52575F6DBED25ADDA95A1B6AD3E15056E489738972C199FB9EE2913"); + + wrapTest(1, "DSTU7624Wrap", kek1, in1, out1); + + String[] oids = { + + UAObjectIdentifiers.dstu7624ecb_128.getId(), + UAObjectIdentifiers.dstu7624ecb_256.getId(), + UAObjectIdentifiers.dstu7624ecb_512.getId(), + + UAObjectIdentifiers.dstu7624cbc_128.getId(), + UAObjectIdentifiers.dstu7624cbc_256.getId(), + UAObjectIdentifiers.dstu7624cbc_512.getId(), + + UAObjectIdentifiers.dstu7624ofb_128.getId(), + UAObjectIdentifiers.dstu7624ofb_256.getId(), + UAObjectIdentifiers.dstu7624ofb_512.getId(), + + UAObjectIdentifiers.dstu7624cfb_128.getId(), + UAObjectIdentifiers.dstu7624cfb_256.getId(), + UAObjectIdentifiers.dstu7624cfb_512.getId(), + + UAObjectIdentifiers.dstu7624ctr_128.getId(), + UAObjectIdentifiers.dstu7624ctr_256.getId(), + UAObjectIdentifiers.dstu7624ctr_512.getId(), + + UAObjectIdentifiers.dstu7624ccm_128.getId(), + UAObjectIdentifiers.dstu7624ccm_256.getId(), + UAObjectIdentifiers.dstu7624ccm_512.getId(), + }; + + String[] names = { + "DSTU7624-128/ECB/PKCS7Padding", + "DSTU7624-256/ECB/PKCS7Padding", + "DSTU7624-512/ECB/PKCS7Padding", + "DSTU7624-128/CBC/PKCS7Padding", + "DSTU7624-256/CBC/PKCS7Padding", + "DSTU7624-512/CBC/PKCS7Padding", + "DSTU7624-128/OFB/NoPadding", + "DSTU7624-256/OFB/NoPadding", + "DSTU7624-512/OFB/NoPadding", + "DSTU7624-128/CFB/NoPadding", + "DSTU7624-256/CFB/NoPadding", + "DSTU7624-512/CFB/NoPadding", + "DSTU7624-128/CTR/NoPadding", + "DSTU7624-256/CTR/NoPadding", + "DSTU7624-512/CTR/NoPadding", + "DSTU7624-128/CCM/NoPadding", + "DSTU7624-256/CCM/NoPadding", + "DSTU7624-512/CCM/NoPadding", + }; + + int[] keyBlockLengths = { + 16, + 32, + 64, + 16, + 32, + 64, + 16, + 32, + 64, + 16, + 32, + 64, + 16, + 32, + 64, + 16, + 32, + 64, + }; + + oidTest(oids, names, keyBlockLengths); + + wrapOidTest(UAObjectIdentifiers.dstu7624kw_128, "DSTU7624Wrap", 16); + + wrapOidTest(UAObjectIdentifiers.dstu7624kw_256, "DSTU7624-256Wrap", 32); + + wrapOidTest(UAObjectIdentifiers.dstu7624kw_512, "DSTU7624-512Wrap", 64); + + macOidTest(UAObjectIdentifiers.dstu7624gmac_128, "DSTU7624GMAC", 16); + + macOidTest(UAObjectIdentifiers.dstu7624gmac_128, "DSTU7624-128GMAC", 16); + + macOidTest(UAObjectIdentifiers.dstu7624gmac_256, "DSTU7624-256GMAC", 32); + + macOidTest(UAObjectIdentifiers.dstu7624gmac_512, "DSTU7624-512GMAC", 64); + } + + protected void wrapOidTest(ASN1ObjectIdentifier oid, String name, int blockLength) + throws Exception + { + SecureRandom random = new SecureRandom(); + + byte[] data = new byte[blockLength]; + + random.nextBytes(data); + + Cipher c1 = Cipher.getInstance(oid.getId(), "BC"); + Cipher c2 = Cipher.getInstance(name, "BC"); + KeyGenerator kg = KeyGenerator.getInstance(oid.getId(), "BC"); + + SecretKey k = kg.generateKey(); + + c1.init(Cipher.WRAP_MODE, k); + c2.init(Cipher.UNWRAP_MODE, k); + + Key wKey = c2.unwrap(c1.wrap(new SecretKeySpec(data, algorithm)), algorithm, Cipher.SECRET_KEY); + + if (!areEqual(data, wKey.getEncoded())) + { + fail("failed wrap OID test"); + } + + if (k.getEncoded().length != blockLength) + { + fail("failed key length test"); + } + } + + protected void macOidTest(ASN1ObjectIdentifier oid, String name, int blockLength) + throws Exception + { + SecureRandom random = new SecureRandom(); + + byte[] data = new byte[blockLength]; + + random.nextBytes(data); + + Mac m1 = Mac.getInstance(oid.getId(), "BC"); + Mac m2 = Mac.getInstance(name, "BC"); + KeyGenerator kg = KeyGenerator.getInstance(oid.getId(), "BC"); + + SecretKey k = kg.generateKey(); + + m1.init(k, new IvParameterSpec(new byte[blockLength])); + m2.init(k, new IvParameterSpec(new byte[blockLength])); + + m1.update(data); + + m2.update(data); + + byte[] mac = m1.doFinal(); + + if (mac.length != blockLength) + { + fail("mac wrong size"); + } + if (!areEqual(mac, m2.doFinal())) + { + fail("failed mac OID test"); + } + + if (k.getEncoded().length != blockLength) + { + fail("failed key length test"); + } + } + + private void oidTest(String[] oids, String[] names, int[] keyBlockLengths) + throws Exception + { + SecureRandom random = new SecureRandom(); + + for (int i = 0; i != oids.length; i++) + { + byte[] data = new byte[keyBlockLengths[i]]; + + random.nextBytes(data); + + IvParameterSpec ivSpec = new IvParameterSpec(new byte[keyBlockLengths[i]]); + Cipher c1 = Cipher.getInstance(oids[i], "BC"); + Cipher c2 = Cipher.getInstance(names[i], "BC"); + KeyGenerator kg = KeyGenerator.getInstance(oids[i], "BC"); + + SecretKey k = kg.generateKey(); + + if (names[i].indexOf("/ECB/") > 0) + { + c1.init(Cipher.ENCRYPT_MODE, k); + c2.init(Cipher.DECRYPT_MODE, k); + } + else + { + c1.init(Cipher.ENCRYPT_MODE, k, ivSpec); + c2.init(Cipher.DECRYPT_MODE, k, ivSpec); + } + + byte[] result = c2.doFinal(c1.doFinal(data)); + + if (!areEqual(data, result)) + { + fail("failed OID test: " + names[i]); + } + + if (k.getEncoded().length != keyBlockLengths[i]) + { + fail("failed key length test"); + } + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new DSTU7624Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DetDSATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DetDSATest.java new file mode 100644 index 000000000..1de6c53d3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DetDSATest.java @@ -0,0 +1,167 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.Security; +import java.security.Signature; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.ECFieldFp; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.EllipticCurve; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.nist.NISTNamedCurves; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Tests are taken from RFC 6979 - "Deterministic Usage of the Digital Signature Algorithm (DSA) and Elliptic Curve Digital Signature Algorithm (ECDSA)" + */ +public class DetDSATest + extends SimpleTest +{ + + public static final byte[] SAMPLE = Hex.decode("73616d706c65"); // "sample" + public static final byte[] TEST = Hex.decode("74657374"); // "test" + + // test vectors from appendix in RFC 6979 + private void testHMacDeterministic() + throws Exception + { + DSAPrivateKeySpec privKeySpec = new DSAPrivateKeySpec(new BigInteger("411602CB19A6CCC34494D79D98EF1E7ED5AF25F7", 16), + new BigInteger("86F5CA03DCFEB225063FF830A0C769B9DD9D6153AD91D7CE27F787C43278B447" + + "E6533B86B18BED6E8A48B784A14C252C5BE0DBF60B86D6385BD2F12FB763ED88" + + "73ABFD3F5BA2E0A8C0A59082EAC056935E529DAF7C610467899C77ADEDFC846C" + + "881870B7B19B2B58F9BE0521A17002E3BDD6B86685EE90B3D9A1B02B782B1779", 16), + new BigInteger("996F967F6C8E388D9E28D01E205FBA957A5698B1", 16), + new BigInteger("07B0F92546150B62514BB771E2A0C0CE387F03BDA6C56B505209FF25FD3C133D" + + "89BBCD97E904E09114D9A7DEFDEADFC9078EA544D2E401AEECC40BB9FBBF78FD" + + "87995A10A1C27CB7789B594BA7EFB5C4326A9FE59A070E136DB77175464ADCA4" + + "17BE5DCE2F40D10A46A3A3943F26AB7FD9C0398FF8C76EE0A56826A8A88F1DBD", 16)); + + KeyFactory keyFact = KeyFactory.getInstance("DSA", "BC"); + + PrivateKey privKey = keyFact.generatePrivate(privKeySpec); + + doTestHMACDetDSASample("SHA1withDDSA", privKey, new BigInteger("2E1A0C2562B2912CAAF89186FB0F42001585DA55", 16), new BigInteger("29EFB6B0AFF2D7A68EB70CA313022253B9A88DF5", 16)); + doTestHMACDetDSASample("SHA224withDDSA", privKey, new BigInteger("4BC3B686AEA70145856814A6F1BB53346F02101E", 16), new BigInteger("410697B92295D994D21EDD2F4ADA85566F6F94C1", 16)); + doTestHMACDetDSASample("SHA256withDDSA", privKey, new BigInteger("81F2F5850BE5BC123C43F71A3033E9384611C545", 16), new BigInteger("4CDD914B65EB6C66A8AAAD27299BEE6B035F5E89", 16)); + doTestHMACDetDSASample("SHA384withDDSA", privKey, new BigInteger("07F2108557EE0E3921BC1774F1CA9B410B4CE65A", 16), new BigInteger("54DF70456C86FAC10FAB47C1949AB83F2C6F7595", 16)); + doTestHMACDetDSASample("SHA512withDDSA", privKey, new BigInteger("16C3491F9B8C3FBBDD5E7A7B667057F0D8EE8E1B", 16), new BigInteger("02C36A127A7B89EDBB72E4FFBC71DABC7D4FC69C", 16)); + + doTestHMACDetDSATest("SHA3-224withDDSA", privKey, new BigInteger("58748b6ca41d25e41f7bfa51fed204a10a1bd1d3", 16), new BigInteger("86de2fdad0bc848dd20ddd9dc6253fc6d7553268", 16)); + doTestHMACDetDSATest("SHA3-256withDDSA", privKey, new BigInteger("98c7a7906ada494285b3ab15cf9188a425f26bd4", 16), new BigInteger("21c5ed876037470d3959fa12f918674a4bf190e9", 16)); + doTestHMACDetDSATest("SHA3-384withDDSA", privKey, new BigInteger("445ec584ec15c14abc67c99886a30a286cc83b33", 16), new BigInteger("21f564d5bb4b175e89a1a6fb2f27cd34c861142d", 16)); + doTestHMACDetDSATest("SHA3-512withDDSA", privKey, new BigInteger("16918083f4c3ff4fc9b327e9e120a30ec39faaf6", 16), new BigInteger("1e9183a1dc7c20dbb596920cd94da3844a087203", 16)); + } + + private void doTestHMACDetDSASample(String algName, PrivateKey privKey, BigInteger r, BigInteger s) + throws Exception + { + doTestHMACDetECDSA(Signature.getInstance(algName, "BC"), SAMPLE, privKey, r, s); + } + + private void doTestHMACDetDSATest(String algName, PrivateKey privKey, BigInteger r, BigInteger s) + throws Exception + { + doTestHMACDetECDSA(Signature.getInstance(algName, "BC"), TEST, privKey, r, s); + } + + // test vectors from appendix in RFC 6979 + private void testECHMacDeterministic() + throws Exception + { + X9ECParameters x9ECParameters = NISTNamedCurves.getByName("P-192"); + ECCurve curve = x9ECParameters.getCurve(); + + ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec(new BigInteger("6FAB034934E4C0FC9AE67F5B5659A9D7D1FEFD187EE09FD4", 16), + new ECParameterSpec( + new EllipticCurve(new ECFieldFp(((ECCurve.Fp)curve).getQ()), curve.getA().toBigInteger(), curve.getB().toBigInteger(), null), + new ECPoint(x9ECParameters.getG().getXCoord().toBigInteger(), x9ECParameters.getG().getYCoord().toBigInteger()), + x9ECParameters.getN(), x9ECParameters.getH().intValue()) + ); + + KeyFactory keyFact = KeyFactory.getInstance("ECDSA", "BC"); + + PrivateKey privKey = keyFact.generatePrivate(privKeySpec); + + doTestHMACDetECDSASample("SHA1withECDDSA", privKey, new BigInteger("98C6BD12B23EAF5E2A2045132086BE3EB8EBD62ABF6698FF", 16), new BigInteger("57A22B07DEA9530F8DE9471B1DC6624472E8E2844BC25B64", 16)); + doTestHMACDetECDSASample("SHA224withECDDSA", privKey, new BigInteger("A1F00DAD97AEEC91C95585F36200C65F3C01812AA60378F5", 16), new BigInteger("E07EC1304C7C6C9DEBBE980B9692668F81D4DE7922A0F97A", 16)); + doTestHMACDetECDSASample("SHA256withECDDSA", privKey, new BigInteger("4B0B8CE98A92866A2820E20AA6B75B56382E0F9BFD5ECB55", 16), new BigInteger("CCDB006926EA9565CBADC840829D8C384E06DE1F1E381B85", 16)); + doTestHMACDetECDSASample("SHA384withECDDSA", privKey, new BigInteger("DA63BF0B9ABCF948FBB1E9167F136145F7A20426DCC287D5", 16), new BigInteger("C3AA2C960972BD7A2003A57E1C4C77F0578F8AE95E31EC5E", 16)); + doTestHMACDetECDSASample("SHA512withECDDSA", privKey, new BigInteger("4D60C5AB1996BD848343B31C00850205E2EA6922DAC2E4B8", 16), new BigInteger("3F6E837448F027A1BF4B34E796E32A811CBB4050908D8F67", 16)); + + doTestHMACDetECDSATest("SHA1withECDDSA", privKey, new BigInteger("0F2141A0EBBC44D2E1AF90A50EBCFCE5E197B3B7D4DE036D", 16), new BigInteger("EB18BC9E1F3D7387500CB99CF5F7C157070A8961E38700B7", 16)); + doTestHMACDetECDSATest("SHA224withECDDSA", privKey, new BigInteger("6945A1C1D1B2206B8145548F633BB61CEF04891BAF26ED34", 16), new BigInteger("B7FB7FDFC339C0B9BD61A9F5A8EAF9BE58FC5CBA2CB15293", 16)); + doTestHMACDetECDSATest("SHA256withECDDSA", privKey, new BigInteger("3A718BD8B4926C3B52EE6BBE67EF79B18CB6EB62B1AD97AE", 16), new BigInteger("5662E6848A4A19B1F1AE2F72ACD4B8BBE50F1EAC65D9124F", 16)); + doTestHMACDetECDSATest("SHA384withECDDSA", privKey, new BigInteger("B234B60B4DB75A733E19280A7A6034BD6B1EE88AF5332367", 16), new BigInteger("7994090B2D59BB782BE57E74A44C9A1C700413F8ABEFE77A", 16)); + doTestHMACDetECDSATest("SHA512withECDDSA", privKey, new BigInteger("FE4F4AE86A58B6507946715934FE2D8FF9D95B6B098FE739", 16), new BigInteger("74CF5605C98FBA0E1EF34D4B5A1577A7DCF59457CAE52290", 16)); + + doTestHMACDetECDSATest("SHA3-224withECDDSA", privKey, new BigInteger("abfcb817d04cc223f0d9c02c6db9230a91f955bf4556e0c6", 16), new BigInteger("ec2c29065a50d8ea39533d49472ccf538a5388cb31900e8f", 16)); + doTestHMACDetECDSATest("SHA3-256withECDDSA", privKey, new BigInteger("a2c2d5362d3cea77191edb239bf22a14dcc59d6500a744fc", 16), new BigInteger("6c63f3012353082026be7e2c6f37e6d7811066ddc9b9ee47", 16)); + doTestHMACDetECDSATest("SHA3-384withECDDSA", privKey, new BigInteger("2ff2c37d48cd6691c8adb9d2b1c1af203a1a6b8769c588dd", 16), new BigInteger("79c8171097f845c608dafd218ba096a51e0e4882faf2c08d", 16)); + doTestHMACDetECDSATest("SHA3-512withECDDSA", privKey, new BigInteger("384619b82461f4cc852dfa1e87cd87105e8eb3cfd0fb6461", 16), new BigInteger("d0aac03f72e90942821e3af1f77fd8a6ae82d1ed31b8ed06", 16)); + } + + private void doTestHMACDetECDSASample(String sigAlg, PrivateKey privKey, BigInteger r, BigInteger s) + throws Exception + { + doTestHMACDetECDSA(Signature.getInstance(sigAlg, "BC"), SAMPLE, privKey, r, s); + } + + private void doTestHMACDetECDSATest(String sigAlg, PrivateKey privKey, BigInteger r, BigInteger s) + throws Exception + { + doTestHMACDetECDSA(Signature.getInstance(sigAlg, "BC"), TEST, privKey, r, s); + } + + private void doTestHMACDetECDSA(Signature detSigner, byte[] data, PrivateKey privKey, BigInteger r, BigInteger s) + throws Exception + { + detSigner.initSign(privKey); + + detSigner.update(data, 0, data.length); + + byte[] m = detSigner.sign(); + + ASN1Sequence seq = ASN1Sequence.getInstance(m); + + if (!r.equals(ASN1Integer.getInstance(seq.getObjectAt(0)).getValue())) + { + fail("r value wrong, got " + ASN1Integer.getInstance(seq.getObjectAt(0)).getValue().toString(16) + " expected " + r.toString(16)); + } + if (!s.equals(ASN1Integer.getInstance(seq.getObjectAt(1)).getValue())) + { + fail("s value wrong, got " + ASN1Integer.getInstance(seq.getObjectAt(1)).getValue().toString(16)); + } + } + + public String getName() + { + return "DetDSA"; + } + + public void performTest() + throws Exception + { + testHMacDeterministic(); + testECHMacDeterministic(); + } + + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new DetDSATest()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DigestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DigestTest.java new file mode 100644 index 000000000..f630f5619 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DigestTest.java @@ -0,0 +1,223 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.MessageDigest; +import java.security.Security; + +import com.fr.third.org.bouncycastle.asn1.iso.ISOIECObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.misc.MiscObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.ua.UAObjectIdentifiers; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class DigestTest + extends SimpleTest +{ + final static String provider = "BC"; + + static private String[][] abcVectors = + { + { "MD2", "da853b0d3f88d99b30283a69e6ded6bb" }, + { "MD4", "a448017aaf21d8525fc10ae87aa6729d" }, + { "MD5", "900150983cd24fb0d6963f7d28e17f72"}, + { "SHA-1", "a9993e364706816aba3e25717850c26c9cd0d89d" }, + { "SHA-224", "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7" }, + { "SHA-256", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" }, + { "SHA-384", "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7" }, + { "SHA-512", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f" }, + { "SHA-512/224", "4634270F707B6A54DAAE7530460842E20E37ED265CEEE9A43E8924AA" }, + { "SHA-512/256", "53048E2681941EF99B2E29B76B4C7DABE4C2D0C634FC6D46E0E2F13107E7AF23" }, + { "RIPEMD128", "c14a12199c66e4ba84636b0f69144c77" }, + { TeleTrusTObjectIdentifiers.ripemd128.getId(), "c14a12199c66e4ba84636b0f69144c77" }, + { "RIPEMD160", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc" }, + { TeleTrusTObjectIdentifiers.ripemd160.getId(), "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc" }, + { "RIPEMD256", "afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65" }, + { TeleTrusTObjectIdentifiers.ripemd256.getId(), "afbd6e228b9d8cbbcef5ca2d03e6dba10ac0bc7dcbe4680e1e42d2e975459b65" }, + { "RIPEMD320", "de4c01b3054f8930a79d09ae738e92301e5a17085beffdc1b8d116713e74f82fa942d64cdbc4682d" }, + { "Tiger", "2AAB1484E8C158F2BFB8C5FF41B57A525129131C957B5F93" }, + { "GOST3411", "b285056dbf18d7392d7677369524dd14747459ed8143997e163b2986f92fd42c" }, + { "WHIRLPOOL", "4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5" }, + { ISOIECObjectIdentifiers.whirlpool.getId(), "4E2448A4C6F486BB16B6562C73B4020BF3043E3A731BCE721AE1B303D97E6D4C7181EEBDB6C57E277D0E34957114CBD6C797FC9D95D8B582D225292076D4EEF5" }, + { "SM3", "66c7f0f462eeedd9d1f2d46bdc10e4e24167c4875cf2f7a2297da02b8f4ba8e0" }, + { "SHA3-224", "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf" }, + { "SHA3-256", "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532" }, + { "SHA3-384", "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25" }, + { "SHA3-512", "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0" }, + { NISTObjectIdentifiers.id_sha3_224.getId(), "e642824c3f8cf24ad09234ee7d3c766fc9a3a5168d0c94ad73b46fdf" }, + { NISTObjectIdentifiers.id_sha3_256.getId(), "3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532" }, + { NISTObjectIdentifiers.id_sha3_384.getId(), "ec01498288516fc926459f58e2c6ad8df9b473cb0fc08c2596da7cf0e49be4b298d88cea927ac7f539f1edf228376d25" }, + { NISTObjectIdentifiers.id_sha3_512.getId(), "b751850b1a57168a5693cd924b6b096e08f621827444f70d884f5d0240d2712e10e116e9192af3c91a7ec57647e3934057340b4cf408d5a56592f8274eec53f0" }, + { "KECCAK-224", "c30411768506ebe1c2871b1ee2e87d38df342317300a9b97a95ec6a8" }, + { "KECCAK-256", "4e03657aea45a94fc7d47ba826c8d667c0d1e6e33a64a036ec44f58fa12d6c45" }, + { "KECCAK-288", "20ff13d217d5789fa7fc9e0e9a2ee627363ec28171d0b6c52bbd2f240554dbc94289f4d6" }, + { "KECCAK-384", "f7df1165f033337be098e7d288ad6a2f74409d7a60b49c36642218de161b1f99f8c681e4afaf31a34db29fb763e3c28e" }, + { "KECCAK-512", "18587dc2ea106b9a1563e32b3312421ca164c7f1f07bc922a9c83d77cea3a1e5d0c69910739025372dc14ac9642629379540c17e2a65b19d77aa511a9d00bb96" }, + { "BLAKE2B-160", "384264f676f39536840523f284921cdc68b6846b" }, + { "BLAKE2B-256", "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319" }, + { "BLAKE2B-384", "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4" }, + { "BLAKE2B-512", "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923" }, + { MiscObjectIdentifiers.id_blake2b160.getId(), "384264f676f39536840523f284921cdc68b6846b" }, + { MiscObjectIdentifiers.id_blake2b256.getId(), "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319" }, + { MiscObjectIdentifiers.id_blake2b384.getId(), "6f56a82c8e7ef526dfe182eb5212f7db9df1317e57815dbda46083fc30f54ee6c66ba83be64b302d7cba6ce15bb556f4" }, + { MiscObjectIdentifiers.id_blake2b512.getId(), "ba80a53f981c4d0d6a2797b69f12f6e94c212f14685ac4b74b12bb6fdbffa2d17d87c5392aab792dc252d5de4533cc9518d38aa8dbf1925ab92386edd4009923" }, + { "BLAKE2S-128", "aa4938119b1dc7b87cbad0ffd200d0ae" }, + { "BLAKE2S-160", "5ae3b99be29b01834c3b508521ede60438f8de17" }, + { "BLAKE2S-224", "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55" }, + { "BLAKE2S-256", "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982" }, + { MiscObjectIdentifiers.id_blake2s128.getId(), "aa4938119b1dc7b87cbad0ffd200d0ae" }, + { MiscObjectIdentifiers.id_blake2s160.getId(), "5ae3b99be29b01834c3b508521ede60438f8de17" }, + { MiscObjectIdentifiers.id_blake2s224.getId(), "0b033fc226df7abde29f67a05d3dc62cf271ef3dfea4d387407fbd55" }, + { MiscObjectIdentifiers.id_blake2s256.getId(), "508c5e8c327c14e2e1a72ba34eeb452f37458b209ed63a294d999b4c86675982" }, + { "GOST3411-2012-256", "4e2919cf137ed41ec4fb6270c61826cc4fffb660341e0af3688cd0626d23b481" }, + { RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.getId(), "4e2919cf137ed41ec4fb6270c61826cc4fffb660341e0af3688cd0626d23b481" }, + { "GOST3411-2012-512", "28156e28317da7c98f4fe2bed6b542d0dab85bb224445fcedaf75d46e26d7eb8d5997f3e0915dd6b7f0aab08d9c8beb0d8c64bae2ab8b3c8c6bc53b3bf0db728" }, + { RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.getId(), "28156e28317da7c98f4fe2bed6b542d0dab85bb224445fcedaf75d46e26d7eb8d5997f3e0915dd6b7f0aab08d9c8beb0d8c64bae2ab8b3c8c6bc53b3bf0db728" }, + { "DSTU7564-256", "0bd1b36109f1318411a0517315aa46b8839df06622a278676f5487996c9cfc04" }, + { UAObjectIdentifiers.dstu7564digest_256.getId(), "0bd1b36109f1318411a0517315aa46b8839df06622a278676f5487996c9cfc04" }, + { "DSTU7564-384", "72945012b0820c3132846ddc90da511f80bb7b70abd0cb1ab8df785d600c187b9d0ac567e8b6f76fde8a0b417a2ebf88" }, + { UAObjectIdentifiers.dstu7564digest_384.getId(), "72945012b0820c3132846ddc90da511f80bb7b70abd0cb1ab8df785d600c187b9d0ac567e8b6f76fde8a0b417a2ebf88" }, + { "DSTU7564-512", "9e5be7daf7b68b49d2ecbd04c7a5b3af72945012b0820c3132846ddc90da511f80bb7b70abd0cb1ab8df785d600c187b9d0ac567e8b6f76fde8a0b417a2ebf88" }, + { UAObjectIdentifiers.dstu7564digest_512.getId(), "9e5be7daf7b68b49d2ecbd04c7a5b3af72945012b0820c3132846ddc90da511f80bb7b70abd0cb1ab8df785d600c187b9d0ac567e8b6f76fde8a0b417a2ebf88" }, + }; + + public String getName() + { + return "Digest"; + } + + void test(String algorithm, byte[] message) + throws Exception + { + MessageDigest digest = MessageDigest.getInstance(algorithm, provider); + + byte[] result = digest.digest(message); + byte[] result2 = digest.digest(message); + + // test one digest the same message with the same instance + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 1 not equal"); + } + + // test two, single byte updates + for (int i = 0; i < message.length; i++) + { + digest.update(message[i]); + } + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 2 not equal"); + } + + // test three, two half updates + digest.update(message, 0, message.length/2); + digest.update(message, message.length/2, message.length-message.length/2); + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 3 not equal"); + } + + // test four, clone test + digest.update(message, 0, message.length/2); + MessageDigest d = (MessageDigest)digest.clone(); + digest.update(message, message.length/2, message.length-message.length/2); + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 4(a) not equal"); + } + + d.update(message, message.length/2, message.length-message.length/2); + result2 = d.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 4(b) not equal"); + } + + // test five, check reset() method + digest.update(message, 0, message.length/2); + digest.reset(); + digest.update(message, 0, message.length/2); + digest.update(message, message.length/2, message.length-message.length/2); + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 5 not equal"); + } + + // Haraka has a fixed length input + if (algorithm.startsWith("HARAKA")) + { + return; + } + // test six, check reset() method with longer message + digest.update(message); + digest.update(message); + digest.reset(); + + result2 = digest.digest(message); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 6 not equal"); + } + } + + /** + * Test the hash against a standard value for the string "abc" + * + * @param algorithm algorithm to test + * @param hash expected value + * @return the test result. + */ + void abcTest( + String algorithm, + String hash) + throws Exception + { + byte[] abc = { (byte)0x61, (byte)0x62, (byte)0x63 }; + + MessageDigest digest = MessageDigest.getInstance(algorithm, provider); + + byte[] result = digest.digest(abc); + + if (!MessageDigest.isEqual(result, Hex.decode(hash))) + { + fail("abc result not equal for " + algorithm); + } + } + + public void performTest() + throws Exception + { + for (int i = 0; i != abcVectors.length; i++) + { + test(abcVectors[i][0], Strings.toByteArray("hello world")); + + abcTest(abcVectors[i][0], abcVectors[i][1]); + } + + test("HARAKA-256", Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f")); + test("HARAKA-512", Hex.decode("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" + + "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f")); + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new DigestTest()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DoFinalTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DoFinalTest.java new file mode 100644 index 000000000..c16e24b9a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/DoFinalTest.java @@ -0,0 +1,164 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Key; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * check that doFinal is properly reseting the cipher. + */ +public class DoFinalTest + implements Test +{ + public DoFinalTest() + { + } + + private boolean equalArray( + byte[] a, + int aOff, + byte[] b, + int length) + { + if (aOff + a.length < length) + { + return false; + } + + if (b.length < length) + { + return false; + } + + for (int i = 0; i != length; i++) + { + if (a[aOff + i] != b[i]) + { + return false; + } + } + + return true; + } + + public TestResult checkCipher( + String cipherName) + { + String lCode = "ABCDEFGHIJKLMNOPQRSTUVWXY0123456789"; + String baseAlgorithm; + int index = cipherName.indexOf('/'); + + if (index > 0) + { + baseAlgorithm = cipherName.substring(0, index); + } + else + { + baseAlgorithm = cipherName; + } + + try + { + KeyGenerator kGen = KeyGenerator.getInstance(baseAlgorithm, "BC"); + Cipher cipher = Cipher.getInstance(cipherName, "BC"); + Key key = kGen.generateKey(); + + cipher.init(Cipher.ENCRYPT_MODE, key); + + byte[] encrypted = cipher.doFinal(lCode.getBytes()); + + // 2nd try + byte[] encrypted2 = cipher.doFinal(lCode.getBytes()); + + if (encrypted.length != encrypted2.length) + { + return new SimpleTestResult(false, getName() + ": Failed " + cipherName + " - expected length " + encrypted.length + " got " + encrypted2.length); + } + + if (!equalArray(encrypted, 0, encrypted2, encrypted.length)) + { + return new SimpleTestResult(false, getName() + ": Failed " + cipherName + " - first two arrays not equal"); + } + + // 3rd try + byte[] enc1 = cipher.update(lCode.getBytes()); + byte[] enc2 = cipher.doFinal(); + + if ((enc1.length + enc2.length) != encrypted.length) + { + return new SimpleTestResult(false, getName() + ": Failed " + cipherName + " - expected length " + encrypted.length + " got " + (enc1.length + enc2.length)); + } + + if (!equalArray(encrypted, 0, enc1, enc1.length)) + { + return new SimpleTestResult(false, getName() + ": Failed " + cipherName + " - enc1 array not equal"); + } + + if (!equalArray(encrypted, enc1.length, enc2, enc2.length)) + { + return new SimpleTestResult(false, getName() + ": Failed " + cipherName + " - enc1 array not equal"); + } + + enc1 = cipher.update(lCode.getBytes()); + + if (!equalArray(encrypted, 0, enc1, enc1.length)) + { + return new SimpleTestResult(false, getName() + ": Failed " + cipherName + " - 2nd enc1 array not equal"); + } + + int len = cipher.doFinal(enc1, 0); + if ((enc1.length + len) != encrypted.length) + { + return new SimpleTestResult(false, getName() + ": Failed " + cipherName + " - expected length " + encrypted.length + " got " + (enc1.length + len)); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": Failed " + cipherName + " - exception " + e.toString()); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public TestResult perform() + { + TestResult result = checkCipher("RC4"); + + if (!result.isSuccessful()) + { + return result; + } + + result = checkCipher("DES/CBC/PKCS5Padding"); + + if (!result.isSuccessful()) + { + return result; + } + + return checkCipher("Rijndael"); + } + + public String getName() + { + return "DoFinalTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + Test test = new DoFinalTest(); + TestResult result = test.perform(); + + System.out.println(result.toString()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECDSA5Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECDSA5Test.java new file mode 100644 index 000000000..70a5f4d4a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECDSA5Test.java @@ -0,0 +1,1239 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECFieldF2m; +import java.security.spec.ECFieldFp; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.ECParameterSpec; +import java.security.spec.ECPoint; +import java.security.spec.ECPrivateKeySpec; +import java.security.spec.ECPublicKeySpec; +import java.security.spec.EllipticCurve; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.KeyAgreement; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.bsi.BSIObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.eac.EACObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.nist.NISTNamedCurves; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.sec.SECObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x9.X962Parameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import com.fr.third.org.bouncycastle.jcajce.spec.MQVParameterSpec; +import com.fr.third.org.bouncycastle.jce.ECKeyUtil; +import com.fr.third.org.bouncycastle.jce.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.jce.ECPointUtil; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.FixedSecureRandom; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; + +public class ECDSA5Test + extends SimpleTest +{ + private static final byte[] namedPubKey = Base64.decode( + "MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEJMeqHZzm+saHt1m3a4u5BIqgSznd8LNvoeS93zzE9Ll31/AMaveAj" + + "JqWxGdyCwnqmM5m3IFCZV3abKVGNpnuQwhIOPMm1355YX1JeEy/ifCx7lYe1o8Xs/Ajqz8cJB3j"); + + byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); + byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); + + SecureRandom random = new FixedSecureRandom( + new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2)}); + static final BigInteger PubX = + new BigInteger("3390396496586153202365024500890309020181905168626402195853036609" + + "0984128098564"); + static final BigInteger PubY = + new BigInteger("1135421298983937257390683162600855221890652900790509030911087400" + + "65052129055287"); + static final String[] VALID_SIGNATURES = { + "3045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d49" + + "1b39fd2c3f0220747291dd2f3f44af7ace68ea33431d6f94e418c106a6e76285" + + "cd59f43260ecce", + }; + + // The following test vectors check for signature malleability and bugs. That means the test + // vectors are derived from a valid signature by modifying the ASN encoding. A correct + // implementation of ECDSA should only accept correct DER encoding and properly handle the + // others (e.g. integer overflow, infinity, redundant parameters, etc). Allowing alternative BER + // encodings is in many cases benign. An example where this kind of signature malleability was a + // problem: https://en.bitcoin.it/wiki/Transaction_Malleability + static final String[] MODIFIED_SIGNATURES = { + "304602812100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f" + + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "30470282002100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd" + + "2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "304602220000b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f" + + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "3046022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f028120747291dd2f" + + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f02820020747291dd" + + "2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "3046022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f022100747291dd2f" + + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "308145022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f" + + "3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "30820045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd" + + "2f3f44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce3000", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce1000", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0000", + "3045022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0000", + "3048022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce058100", + "3049022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce05820000", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce1100", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0500", + "3047022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce2500", + "3067022100b7babae9332b54b8a3a05b7004579821a887a1b21465f7db8a3d491b39fd2c3f0220747291dd2f3f" + + "44af7ace68ea33431d6f94e418c106a6e76285cd59f43260ecce0220747291dd2f3f44af7ace68ea33431d6f" + + "94e418c106a6e76285cd59f43260ecce" + }; + + private void testModified() + throws Exception + { + ECNamedCurveParameterSpec namedCurve = ECNamedCurveTable.getParameterSpec("P-256"); + com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec pubSpec = new com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec(namedCurve.getCurve().createPoint(PubX, PubY), namedCurve); + KeyFactory kFact = KeyFactory.getInstance("EC", "BC"); + PublicKey pubKey = kFact.generatePublic(pubSpec); + Signature sig = Signature.getInstance("SHA256WithECDSA", "BC"); + + for (int i = 0; i != MODIFIED_SIGNATURES.length; i++) + { + sig.initVerify(pubKey); + + sig.update(Strings.toByteArray("Hello")); + + boolean failed; + + try + { + failed = !sig.verify(Hex.decode(MODIFIED_SIGNATURES[i])); + } + catch (SignatureException e) + { + failed = true; + } + + isTrue("sig verified when shouldn't: " + i, failed); + } + } + + public void testNamedCurveInKeyFactory() + throws Exception + { + KeyFactory kfBc = KeyFactory.getInstance("EC", "BC"); + BigInteger x = new BigInteger("24c7aa1d9ce6fac687b759b76b8bb9048aa04b39ddf0b36fa1e4bddf3cc4f4b977d7f00c6af7808c9a96c467720b09ea", 16); + BigInteger y = new BigInteger("98ce66dc8142655dda6ca5463699ee43084838f326d77e79617d49784cbf89f0b1ee561ed68f17b3f023ab3f1c241de3", 16); + String curveName = "secp384r1"; + ECPoint point = new ECPoint(x, y); + + AlgorithmParameters parameters = AlgorithmParameters.getInstance("EC", "BC"); + parameters.init(new ECGenParameterSpec(curveName)); + ECParameterSpec ecParamSpec = parameters.getParameterSpec(ECParameterSpec.class); + PublicKey pubKey = kfBc.generatePublic(new ECPublicKeySpec(point, ecParamSpec)); + + isTrue(Arrays.areEqual(namedPubKey, pubKey.getEncoded())); + } + + private void decodeTest() + { + EllipticCurve curve = new EllipticCurve( + new ECFieldFp(new BigInteger("6277101735386680763835789423207666416083908700390324961279")), // q + new BigInteger("fffffffffffffffffffffffffffffffefffffffffffffffc", 16), // a + new BigInteger("64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1", 16)); // b + + ECPoint p = ECPointUtil.decodePoint(curve, Hex.decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")); + + if (!p.getAffineX().equals(new BigInteger("188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012", 16))) + { + fail("x uncompressed incorrectly"); + } + + if (!p.getAffineY().equals(new BigInteger("7192b95ffc8da78631011ed6b24cdd573f977a11e794811", 16))) + { + fail("y uncompressed incorrectly"); + } + } + + /** + * X9.62 - 1998,
+ * J.3.2, Page 155, ECDSA over the field Fp
+ * an example with 239 bit prime + */ + private void testECDSA239bitPrime() + throws Exception + { + BigInteger r = new BigInteger("308636143175167811492622547300668018854959378758531778147462058306432176"); + BigInteger s = new BigInteger("323813553209797357708078776831250505931891051755007842781978505179448783"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); + + SecureRandom k = new TestRandomBigInteger(kData); + + EllipticCurve curve = new EllipticCurve( + new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + + ECParameterSpec spec = new ECParameterSpec( + curve, + ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n + 1); // h + + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + ECPointUtil.decodePoint(curve, Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q + spec); + + Signature sgr = Signature.getInstance("ECDSA", "BC"); + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + PrivateKey sKey = f.generatePrivate(priKey); + PublicKey vKey = f.generatePublic(pubKey); + + sgr.initSign(sKey, k); + + byte[] message = new byte[]{(byte)'a', (byte)'b', (byte)'c'}; + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail("239 Bit EC verification failed"); + } + + BigInteger[] sig = derDecode(sigBytes); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + } + + private void testSM2() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("ECDSA", "BC"); + + kpGen.initialize(new ECGenParameterSpec("sm2p256v1")); + + KeyPair kp = kpGen.generateKeyPair(); + + kpGen.initialize(new ECNamedCurveGenParameterSpec("sm2p256v1")); + + kp = kpGen.generateKeyPair(); + } + + private void testNonsense() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("ECDSA", "BC"); + + try + { + kpGen.initialize(new ECGenParameterSpec("no_such_curve")); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isEquals("unknown curve name: no_such_curve", e.getMessage()); + } + KeyPair kp = kpGen.generateKeyPair(); + + try + { + kpGen.initialize(new ECNamedCurveGenParameterSpec("1.2.3.4.5")); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isEquals("unknown curve OID: 1.2.3.4.5", e.getMessage()); + } + + kp = kpGen.generateKeyPair(); + } + + // test BSI algorithm support. + private void testBSI() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("ECDSA", "BC"); + + kpGen.initialize(new ECGenParameterSpec(TeleTrusTObjectIdentifiers.brainpoolP512r1.getId())); + + KeyPair kp = kpGen.generateKeyPair(); + + byte[] data = "Hello World!!!".getBytes(); + String[] cvcAlgs = {"SHA1WITHCVC-ECDSA", "SHA224WITHCVC-ECDSA", + "SHA256WITHCVC-ECDSA", "SHA384WITHCVC-ECDSA", + "SHA512WITHCVC-ECDSA"}; + String[] cvcOids = {EACObjectIdentifiers.id_TA_ECDSA_SHA_1.getId(), EACObjectIdentifiers.id_TA_ECDSA_SHA_224.getId(), + EACObjectIdentifiers.id_TA_ECDSA_SHA_256.getId(), EACObjectIdentifiers.id_TA_ECDSA_SHA_384.getId(), + EACObjectIdentifiers.id_TA_ECDSA_SHA_512.getId()}; + + testBsiAlgorithms(kp, data, cvcAlgs, cvcOids); + + String[] plainAlgs = {"SHA1WITHPLAIN-ECDSA", "SHA224WITHPLAIN-ECDSA", + "SHA256WITHPLAIN-ECDSA", "SHA384WITHPLAIN-ECDSA", + "SHA512WITHPLAIN-ECDSA", "RIPEMD160WITHPLAIN-ECDSA"}; + String[] plainOids = {BSIObjectIdentifiers.ecdsa_plain_SHA1.getId(), BSIObjectIdentifiers.ecdsa_plain_SHA224.getId(), + BSIObjectIdentifiers.ecdsa_plain_SHA256.getId(), BSIObjectIdentifiers.ecdsa_plain_SHA384.getId(), + BSIObjectIdentifiers.ecdsa_plain_SHA512.getId(), BSIObjectIdentifiers.ecdsa_plain_RIPEMD160.getId()}; + + testBsiAlgorithms(kp, data, plainAlgs, plainOids); + + kpGen = KeyPairGenerator.getInstance("ECDSA", "BC"); + + kpGen.initialize(new ECGenParameterSpec(SECObjectIdentifiers.secp521r1.getId())); + + kp = kpGen.generateKeyPair(); + + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(SECObjectIdentifiers.secp521r1.getId()); + testBsiSigSize(kp, spec.getN(), "SHA224WITHPLAIN-ECDSA"); + } + + private void testBsiAlgorithms(KeyPair kp, byte[] data, String[] algs, String[] oids) + throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException + { + for (int i = 0; i != algs.length; i++) + { + Signature sig1 = Signature.getInstance(algs[i], "BC"); + Signature sig2 = Signature.getInstance(oids[i], "BC"); + + sig1.initSign(kp.getPrivate()); + + sig1.update(data); + + byte[] sig = sig1.sign(); + + sig2.initVerify(kp.getPublic()); + + sig2.update(data); + + if (!sig2.verify(sig)) + { + fail("BSI CVC signature failed: " + algs[i]); + } + } + } + + private void testBsiSigSize(KeyPair kp, BigInteger order, String alg) + throws Exception + { + for (int i = 0; i != 20; i++) + { + Signature sig1 = Signature.getInstance(alg, "BC"); + Signature sig2 = Signature.getInstance(alg, "BC"); + + sig1.initSign(kp.getPrivate()); + + sig1.update(new byte[]{(byte)i}); + + byte[] sig = sig1.sign(); + + isTrue(sig.length == (2 * ((order.bitLength() + 7) / 8))); + sig2.initVerify(kp.getPublic()); + + sig2.update(new byte[]{(byte)i}); + + if (!sig2.verify(sig)) + { + fail("BSI CVC signature failed: " + alg); + } + } + } + + /** + * X9.62 - 1998,
+ * J.2.1, Page 100, ECDSA over the field F2m
+ * an example with 191 bit binary field + */ + private void testECDSA239bitBinary() + throws Exception + { + BigInteger r = new BigInteger("21596333210419611985018340039034612628818151486841789642455876922391552"); + BigInteger s = new BigInteger("197030374000731686738334997654997227052849804072198819102649413465737174"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("171278725565216523967285789236956265265265235675811949404040041670216363")); + + SecureRandom k = new TestRandomBigInteger(kData); + + EllipticCurve curve = new EllipticCurve( + new ECFieldF2m(239, // m + new int[]{36}), // k + new BigInteger("32010857077C5431123A46B808906756F543423E8D27877578125778AC76", 16), // a + new BigInteger("790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", 16)); // b + + ECParameterSpec params = new ECParameterSpec( + curve, + ECPointUtil.decodePoint(curve, Hex.decode("0457927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305")), // G + new BigInteger("220855883097298041197912187592864814557886993776713230936715041207411783"), // n + 4); // h + + ECPrivateKeySpec priKeySpec = new ECPrivateKeySpec( + new BigInteger("145642755521911534651321230007534120304391871461646461466464667494947990"), // d + params); + + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec( + ECPointUtil.decodePoint(curve, Hex.decode("045894609CCECF9A92533F630DE713A958E96C97CCB8F5ABB5A688A238DEED6DC2D9D0C94EBFB7D526BA6A61764175B99CB6011E2047F9F067293F57F5")), // Q + params); + + Signature sgr = Signature.getInstance("ECDSA", "BC"); + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + PrivateKey sKey = f.generatePrivate(priKeySpec); + PublicKey vKey = f.generatePublic(pubKeySpec); + byte[] message = new byte[]{(byte)'a', (byte)'b', (byte)'c'}; + + sgr.initSign(sKey, k); + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail("239 Bit EC verification failed"); + } + + BigInteger[] sig = derDecode(sigBytes); + + if (!r.equals(sig[0])) + { + fail("r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail("s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + } + + private void testGeneration() + throws Exception + { + // + // ECDSA generation test + // + byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + Signature s = Signature.getInstance("ECDSA", "BC"); + KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); + + EllipticCurve curve = new EllipticCurve( + new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + + ECParameterSpec ecSpec = new ECParameterSpec( + curve, + ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n + 1); // h + + g.initialize(ecSpec, new SecureRandom()); + + KeyPair p = g.generateKeyPair(); + + PrivateKey sKey = p.getPrivate(); + PublicKey vKey = p.getPublic(); + + s.initSign(sKey); + + s.update(data); + + byte[] sigBytes = s.sign(); + + s = Signature.getInstance("ECDSA", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("ECDSA verification failed"); + } + + testKeyFactory((ECPublicKey)vKey, (ECPrivateKey)sKey); + testSerialise((ECPublicKey)vKey, (ECPrivateKey)sKey); + } + + private void testSerialise(ECPublicKey ecPublicKey, ECPrivateKey ecPrivateKey) + throws Exception + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(ecPublicKey); + oOut.writeObject(ecPrivateKey); + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + PublicKey pubKey = (PublicKey)oIn.readObject(); + PrivateKey privKey = (PrivateKey)oIn.readObject(); + + if (!ecPublicKey.equals(pubKey)) + { + fail("public key serialisation check failed"); + } + + if (!ecPrivateKey.equals(privKey)) + { + fail("private key serialisation check failed"); + } + } + + private void testKeyFactory(ECPublicKey pub, ECPrivateKey priv) + throws Exception + { + KeyFactory ecFact = KeyFactory.getInstance("ECDSA"); + + ECPublicKeySpec pubSpec = (ECPublicKeySpec)ecFact.getKeySpec(pub, ECPublicKeySpec.class); + ECPrivateKeySpec privSpec = (ECPrivateKeySpec)ecFact.getKeySpec(priv, ECPrivateKeySpec.class); + + if (!pubSpec.getW().equals(pub.getW()) || !pubSpec.getParams().getCurve().equals(pub.getParams().getCurve())) + { + fail("pubSpec not correct"); + } + + if (!privSpec.getS().equals(priv.getS()) || !privSpec.getParams().getCurve().equals(priv.getParams().getCurve())) + { + fail("privSpec not correct"); + } + + ECPublicKey pubKey = (ECPublicKey)ecFact.translateKey(pub); + ECPrivateKey privKey = (ECPrivateKey)ecFact.translateKey(priv); + + if (!pubKey.getW().equals(pub.getW()) || !pubKey.getParams().getCurve().equals(pub.getParams().getCurve())) + { + fail("pubKey not correct"); + } + + if (!privKey.getS().equals(priv.getS()) || !privKey.getParams().getCurve().equals(priv.getParams().getCurve())) + { + fail("privKey not correct"); + } + } + + private void testKeyConversion() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("ECDSA", "BC"); + + kpGen.initialize(new ECGenParameterSpec("prime192v1")); + + KeyPair pair = kpGen.generateKeyPair(); + + PublicKey pubKey = ECKeyUtil.publicToExplicitParameters(pair.getPublic(), "BC"); + + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(pubKey.getEncoded())); + X962Parameters params = X962Parameters.getInstance(info.getAlgorithm().getParameters()); + + if (params.isNamedCurve() || params.isImplicitlyCA()) + { + fail("public key conversion to explicit failed"); + } + + if (!((ECPublicKey)pair.getPublic()).getW().equals(((ECPublicKey)pubKey).getW())) + { + fail("public key conversion check failed"); + } + + PrivateKey privKey = ECKeyUtil.privateToExplicitParameters(pair.getPrivate(), "BC"); + PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(privKey.getEncoded())); + params = X962Parameters.getInstance(privInfo.getPrivateKeyAlgorithm().getParameters()); + + if (params.isNamedCurve() || params.isImplicitlyCA()) + { + fail("private key conversion to explicit failed"); + } + + if (!((ECPrivateKey)pair.getPrivate()).getS().equals(((ECPrivateKey)privKey).getS())) + { + fail("private key conversion check failed"); + } + } + + private void testAdaptiveKeyConversion() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("ECDSA", "BC"); + + kpGen.initialize(new ECGenParameterSpec("prime192v1")); + + KeyPair pair = kpGen.generateKeyPair(); + + final PrivateKey privKey = pair.getPrivate(); + final PublicKey pubKey = pair.getPublic(); + + Signature s = Signature.getInstance("ECDSA", "BC"); + + // raw interface tests + s.initSign(new PrivateKey() + { + public String getAlgorithm() + { + return privKey.getAlgorithm(); + } + + public String getFormat() + { + return privKey.getFormat(); + } + + public byte[] getEncoded() + { + return privKey.getEncoded(); + } + }); + + s.initVerify(new PublicKey() + { + public String getAlgorithm() + { + return pubKey.getAlgorithm(); + } + + public String getFormat() + { + return pubKey.getFormat(); + } + + public byte[] getEncoded() + { + return pubKey.getEncoded(); + } + }); + + + s.initSign(new ECPrivateKey() + { + public String getAlgorithm() + { + return privKey.getAlgorithm(); + } + + public String getFormat() + { + return privKey.getFormat(); + } + + public byte[] getEncoded() + { + return privKey.getEncoded(); + } + + public BigInteger getS() + { + return ((ECPrivateKey)privKey).getS(); + } + + public ECParameterSpec getParams() + { + return ((ECPrivateKey)privKey).getParams(); + } + }); + + s.initVerify(new ECPublicKey() + { + public String getAlgorithm() + { + return pubKey.getAlgorithm(); + } + + public String getFormat() + { + return pubKey.getFormat(); + } + + public byte[] getEncoded() + { + return pubKey.getEncoded(); + } + + public ECPoint getW() + { + return ((ECPublicKey)pubKey).getW(); + } + + public ECParameterSpec getParams() + { + return ((ECPublicKey)pubKey).getParams(); + } + }); + + try + { + s.initSign(new PrivateKey() + { + public String getAlgorithm() + { + return privKey.getAlgorithm(); + } + + public String getFormat() + { + return privKey.getFormat(); + } + + public byte[] getEncoded() + { + return null; + } + }); + + fail("no exception thrown!!!"); + } + catch (InvalidKeyException e) + { + // ignore + } + + try + { + s.initVerify(new PublicKey() + { + public String getAlgorithm() + { + return pubKey.getAlgorithm(); + } + + public String getFormat() + { + return pubKey.getFormat(); + } + + public byte[] getEncoded() + { + return null; + } + }); + + fail("no exception thrown!!!"); + } + catch (InvalidKeyException e) + { + // ignore + } + + // try bogus encoding + try + { + s.initSign(new PrivateKey() + { + public String getAlgorithm() + { + return privKey.getAlgorithm(); + } + + public String getFormat() + { + return privKey.getFormat(); + } + + public byte[] getEncoded() + { + return new byte[20]; + } + }); + + fail("no exception thrown!!!"); + } + catch (InvalidKeyException e) + { + // ignore + } + + try + { + s.initVerify(new PublicKey() + { + public String getAlgorithm() + { + return pubKey.getAlgorithm(); + } + + public String getFormat() + { + return pubKey.getFormat(); + } + + public byte[] getEncoded() + { + return new byte[20]; + } + }); + + fail("no exception thrown!!!"); + } + catch (InvalidKeyException e) + { + // ignore + } + + // try encoding of wrong key + kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(512); + + pair = kpGen.generateKeyPair(); + + final PrivateKey privRsa = pair.getPrivate(); + final PublicKey pubRsa = pair.getPublic(); + + try + { + s.initSign(new PrivateKey() + { + public String getAlgorithm() + { + return privRsa.getAlgorithm(); + } + + public String getFormat() + { + return privRsa.getFormat(); + } + + public byte[] getEncoded() + { + return privRsa.getEncoded(); + } + }); + + fail("no exception thrown!!!"); + + } + catch (InvalidKeyException e) + { + // ignore + } + + try + { + s.initVerify(new PublicKey() + { + public String getAlgorithm() + { + return pubRsa.getAlgorithm(); + } + + public String getFormat() + { + return pubRsa.getFormat(); + } + + public byte[] getEncoded() + { + return pubRsa.getEncoded(); + } + }); + + fail("no exception thrown!!!"); + } + catch (InvalidKeyException e) + { + // ignore + } + } + + private void testAlgorithmParameters() + throws Exception + { + AlgorithmParameters algParam = AlgorithmParameters.getInstance("EC", "BC"); + + algParam.init(new ECGenParameterSpec("P-256")); + + byte[] encoded = algParam.getEncoded(); + + algParam = AlgorithmParameters.getInstance("EC", "BC"); + + algParam.init(encoded); + + ECGenParameterSpec genSpec = algParam.getParameterSpec(ECGenParameterSpec.class); + + if (!genSpec.getName().equals(X9ObjectIdentifiers.prime256v1.getId())) + { + fail("curve name not recovered"); + } + + ECParameterSpec ecSpec = algParam.getParameterSpec(ECParameterSpec.class); + + if (!ecSpec.getOrder().equals(NISTNamedCurves.getByName("P-256").getN())) + { + fail("incorrect spec recovered"); + } + } + + private void testKeyPairGenerationWithOIDs() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("ECDSA", "BC"); + + kpGen.initialize(new ECGenParameterSpec(X9ObjectIdentifiers.prime192v1.getId())); + kpGen.initialize(new ECGenParameterSpec(TeleTrusTObjectIdentifiers.brainpoolP160r1.getId())); + kpGen.initialize(new ECGenParameterSpec(SECObjectIdentifiers.secp128r1.getId())); + + try + { + kpGen.initialize(new ECGenParameterSpec("1.1")); + + fail("non-existant curve OID failed"); + } + catch (InvalidAlgorithmParameterException e) + { + if (!"unknown curve OID: 1.1".equals(e.getMessage())) + { + fail("OID message check failed"); + } + } + + try + { + kpGen.initialize(new ECGenParameterSpec("flibble")); + + fail("non-existant curve name failed"); + } + catch (InvalidAlgorithmParameterException e) + { + if (!"unknown curve name: flibble".equals(e.getMessage())) + { + fail("name message check failed"); + } + } + } + + private static class ECRandom + extends SecureRandom + { + public void nextBytes(byte[] bytes) + { + byte[] src = new BigInteger("e2eb6663f551331bda00b90f1272c09d980260c1a70cab1ec481f6c937f34b62", 16).toByteArray(); + + if (src.length <= bytes.length) + { + System.arraycopy(src, 0, bytes, bytes.length - src.length, src.length); + } + else + { + System.arraycopy(src, 0, bytes, 0, bytes.length); + } + } + } + + private void testNamedCurveParameterPreservation() + throws Exception + { + AlgorithmParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec("secp256r1"); + KeyPairGenerator keygen = KeyPairGenerator.getInstance("EC", "BC"); + keygen.initialize(ecSpec, new ECRandom()); + + KeyPair keys = keygen.generateKeyPair(); + + PrivateKeyInfo priv1 = PrivateKeyInfo.getInstance(keys.getPrivate().getEncoded()); + SubjectPublicKeyInfo pub1 = SubjectPublicKeyInfo.getInstance(keys.getPublic().getEncoded()); + + keygen = KeyPairGenerator.getInstance("EC", "BC"); + keygen.initialize(new ECGenParameterSpec("secp256r1"), new ECRandom()); + + PrivateKeyInfo priv2 = PrivateKeyInfo.getInstance(keys.getPrivate().getEncoded()); + SubjectPublicKeyInfo pub2 = SubjectPublicKeyInfo.getInstance(keys.getPublic().getEncoded()); + + if (!priv1.equals(priv2) || !pub1.equals(pub2)) + { + fail("mismatch between alg param spec and ECGenParameterSpec"); + } + + if (!(priv2.getPrivateKeyAlgorithm().getParameters() instanceof ASN1ObjectIdentifier)) + { + fail("OID not preserved in private key"); + } + + if (!(pub1.getAlgorithm().getParameters() instanceof ASN1ObjectIdentifier)) + { + fail("OID not preserved in public key"); + } + } + + private void testNamedCurveSigning() + throws Exception + { + testCustomNamedCurveSigning("secp256r1"); + + try + { + testCustomNamedCurveSigning("secp256k1"); + } + catch (IllegalArgumentException e) + { + if (!e.getMessage().equals("first coefficient is negative")) // bogus jdk 1.5 exception... + { + throw e; + } + } + } + + private void testCustomNamedCurveSigning(String name) + throws Exception + { + X9ECParameters x9Params = ECUtil.getNamedCurveByOid(ECUtil.getNamedCurveOid(name)); + + // TODO: one day this may have to change + if (x9Params.getCurve() instanceof ECCurve.Fp) + { + fail("curve not custom curve!!"); + } + + AlgorithmParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name); + KeyPairGenerator keygen = KeyPairGenerator.getInstance("EC", "BC"); + keygen.initialize(ecSpec, new ECRandom()); + + KeyPair keys = keygen.generateKeyPair(); + + PrivateKeyInfo priv1 = PrivateKeyInfo.getInstance(keys.getPrivate().getEncoded()); + SubjectPublicKeyInfo pub1 = SubjectPublicKeyInfo.getInstance(keys.getPublic().getEncoded()); + + keygen = KeyPairGenerator.getInstance("EC", "BC"); + keygen.initialize(new ECGenParameterSpec("secp256r1"), new ECRandom()); + + Signature ecdsaSigner = Signature.getInstance("ECDSA", "BC"); + + ecdsaSigner.initSign(keys.getPrivate()); + + ecdsaSigner.update(new byte[100]); + + byte[] sig = ecdsaSigner.sign(); + + ecdsaSigner.initVerify(keys.getPublic()); + + ecdsaSigner.update(new byte[100]); + + if (!ecdsaSigner.verify(sig)) + { + fail("signature failed to verify"); + } + + KeyFactory kFact = KeyFactory.getInstance("EC", "BC"); + + PublicKey pub = kFact.generatePublic(new X509EncodedKeySpec(pub1.getEncoded())); + PrivateKey pri = kFact.generatePrivate(new PKCS8EncodedKeySpec(priv1.getEncoded())); + + ecdsaSigner = Signature.getInstance("ECDSA", "BC"); + + ecdsaSigner.initSign(pri); + + ecdsaSigner.update(new byte[100]); + + sig = ecdsaSigner.sign(); + + ecdsaSigner.initVerify(pub); + + ecdsaSigner.update(new byte[100]); + + if (!ecdsaSigner.verify(sig)) + { + fail("signature failed to verify"); + } + } + + /** + * COUNT = 1 + * dsCAVS = 00000179557decd75b797bea9db656ce99c03a6e0ab13804b5b589644f7db41ceba05c3940c300361061074ca72a828428d9198267fa0b75e1e3e785a0ff20e839414be0 + * QsCAVSx = 000001ce7da31681d5f176f3618f205969b9142520363dd26a596866c89988c932e3ce01904d12d1e9b105462e56163dbe7658ba3c472bf1f3c8165813295393ae346764 + * QsCAVSy = 000000e70d6e55b76ebd362ff071ab819315593cec650276209a9fdc2c1c48e03c35945f04e74d958cabd3f5e4d1f096a991e807a8f9d217de306a6b561038ca15aea4b9 + * NonceEphemCAVS = 4214a1a0a1d11679ae22f98d7ae483c1a74008a9cd7f7cf71b1f373a4226f5c58eb621ec56e2537797c01750dcbff07f613b9c58774f9af32aebeadd2226140dc7d56b1aa95c93ab1ec4412e2d0e42cdaac7bf9da3ddbf19fbb1edd0556d9c5a339808905fe8defd8b57ff8f34788192cc0cf7df17d1f351d69ac979a3a495931c287fb8 + * dsIUT = 000000c14895dfcc5a6b24994828cfd0a0cc0a881a70173a3eb05c57b098046c8e60a868f6176284aa346eff1fd1b8b879052c5a6d5fd0ae146b35ed7ecee32e294103cd + * QsIUTx = 00000174a658695049db59f6bbe2ad23e1753bf58384a56fc9b3dec13eb873b33e1f4dbd24b6b4ca05a9a11ad531f6d99e9430a774980e8a8d9fd2d1e2a0d76fe3dd36c7 + * QsIUTy = 00000030639849e1df341973db44e7bbba5bb597884a439f9ce54620c3ca73a9804cc26fcda3aaf73ae5a11d5b325cae0e95cfafe1985c6c2fdb892722e7dd2c5d744cf3 + * deIUT = 00000138f54e986c7b44f49da389fa9f61bb7265f0cebdeddf09d47c72e55186e2520965fc2c31bb9c0a557e3c28e02a751f097e413c4252c7b0d22452d89f9ac314bc6e + * QeIUTx = 000001b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf01120 + * QeIUTy = 000000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a + * OI = a1b2c3d4e54341565369646dbb63a273c81e0aad02f92699bf7baa28fd4509145b0096746894e98e209a85ecb415b8 + * CAVSTag = 4ade5dc983cc1cf61c90fdbf726fa6a88e9bf411bbaf0015db06ff4348560e4d + * Z = 019a19a0a99f60221ee23323b3317292e8c10d57ba04e0b33f6241979ec3895945eed0bdcbc59ab576e7047061f0d63d1aaf78b1d442028605aa1c0f963a3bc9d61a + * MacData = 4b435f315f55a1b2c3d4e543415653696401b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf0112000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a4214a1a0a1d11679ae22f98d7ae483c1a74008a9cd7f7cf71b1f373a4226f5c58eb621ec56e2537797c01750dcbff07f613b9c58774f9af32aebeadd2226140dc7d56b1aa95c93ab1ec4412e2d0e42cdaac7bf9da3ddbf19fbb1edd0556d9c5a339808905fe8defd8b57ff8f34788192cc0cf7df17d1f351d69ac979a3a495931c287fb8 + * DKM = 0744e1774149a8b8f88d3a1e20ac1517efd2f54ba4b5f178de99f33b68eea426 + * Result = P (14 - DKM value should have leading 0 nibble ) + */ + public void testMQVwithHMACOnePass() + throws Exception + { + AlgorithmParameters algorithmParameters = AlgorithmParameters.getInstance("EC", "BC"); + + algorithmParameters.init(new ECGenParameterSpec("P-521")); + + ECParameterSpec ecSpec = algorithmParameters.getParameterSpec(ECParameterSpec.class); + KeyFactory keyFact = KeyFactory.getInstance("EC", "BC"); + + ECPrivateKey dsCAVS = (ECPrivateKey)keyFact.generatePrivate(new ECPrivateKeySpec(new BigInteger("00000179557decd75b797bea9db656ce99c03a6e0ab13804b5b589644f7db41ceba05c3940c300361061074ca72a828428d9198267fa0b75e1e3e785a0ff20e839414be0", 16), ecSpec)); + ECPublicKey qsCAVS = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint( + new BigInteger("000001ce7da31681d5f176f3618f205969b9142520363dd26a596866c89988c932e3ce01904d12d1e9b105462e56163dbe7658ba3c472bf1f3c8165813295393ae346764", 16), + new BigInteger("000000e70d6e55b76ebd362ff071ab819315593cec650276209a9fdc2c1c48e03c35945f04e74d958cabd3f5e4d1f096a991e807a8f9d217de306a6b561038ca15aea4b9", 16)), ecSpec)); + + ECPrivateKey dsIUT = (ECPrivateKey)keyFact.generatePrivate(new ECPrivateKeySpec(new BigInteger("000000c14895dfcc5a6b24994828cfd0a0cc0a881a70173a3eb05c57b098046c8e60a868f6176284aa346eff1fd1b8b879052c5a6d5fd0ae146b35ed7ecee32e294103cd", 16), ecSpec)); + ECPublicKey qsIUT = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint( + new BigInteger("00000174a658695049db59f6bbe2ad23e1753bf58384a56fc9b3dec13eb873b33e1f4dbd24b6b4ca05a9a11ad531f6d99e9430a774980e8a8d9fd2d1e2a0d76fe3dd36c7", 16), + new BigInteger("00000030639849e1df341973db44e7bbba5bb597884a439f9ce54620c3ca73a9804cc26fcda3aaf73ae5a11d5b325cae0e95cfafe1985c6c2fdb892722e7dd2c5d744cf3", 16)), ecSpec)); + + ECPrivateKey deIUT = (ECPrivateKey)keyFact.generatePrivate(new ECPrivateKeySpec(new BigInteger("00000138f54e986c7b44f49da389fa9f61bb7265f0cebdeddf09d47c72e55186e2520965fc2c31bb9c0a557e3c28e02a751f097e413c4252c7b0d22452d89f9ac314bc6e", 16), ecSpec)); + ECPublicKey qeIUT = (ECPublicKey)keyFact.generatePublic(new ECPublicKeySpec(new ECPoint( + new BigInteger("000001b9fbce9c9ebb31070a4a4ac7af54ec9189c1f98948cd24ca0a5029217e4784d3c8692da08a6a512d1c9875d20d8e03664c148fa5d34bbac6d42e499ee5dbf01120", 16), + new BigInteger("000000994a714b6d09afa896dbba9b4f436ab3cdb0d11dcd2aad28b7ba35d6fa6be537b6ffb0f9bf5fe1d594b8f8b8829687c9395c3d938c873f26c7100888c3aca2d59a", 16)), ecSpec)); + + KeyAgreement uAgree = KeyAgreement.getInstance("ECMQVwithSHA512CKDF", "BC"); + + uAgree.init(dsCAVS, new MQVParameterSpec(dsCAVS, qeIUT, Hex.decode("a1b2c3d4e54341565369646dbb63a273c81e0aad02f92699bf7baa28fd4509145b0096746894e98e209a85ecb415b8"))); + + + KeyAgreement vAgree = KeyAgreement.getInstance("ECMQVwithSHA512CKDF", "BC"); + vAgree.init(dsIUT, new MQVParameterSpec(deIUT, qsCAVS, Hex.decode("a1b2c3d4e54341565369646dbb63a273c81e0aad02f92699bf7baa28fd4509145b0096746894e98e209a85ecb415b8"))); + + // + // agreement + // + uAgree.doPhase(qsIUT, true); + vAgree.doPhase(qsCAVS, true); + + byte[] ux = uAgree.generateSecret(PKCSObjectIdentifiers.id_hmacWithSHA512.getId()).getEncoded(); + byte[] vx = vAgree.generateSecret(PKCSObjectIdentifiers.id_hmacWithSHA512.getId()).getEncoded(); + + if (!Arrays.areEqual(ux, vx)) + { + fail("agreement values don't match"); + } + + if (!Arrays.areEqual(Hex.decode("0744e1774149a8b8f88d3a1e20ac1517efd2f54ba4b5f178de99f33b68eea426"), Arrays.copyOfRange(ux, 0, 32))) + { + fail("agreement values not correct"); + } + } + + protected BigInteger[] derDecode( + byte[] encoding) + throws IOException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(encoding); + ASN1InputStream aIn = new ASN1InputStream(bIn); + ASN1Sequence s = (ASN1Sequence)aIn.readObject(); + + BigInteger[] sig = new BigInteger[2]; + + sig[0] = ((ASN1Integer)s.getObjectAt(0)).getValue(); + sig[1] = ((ASN1Integer)s.getObjectAt(1)).getValue(); + + return sig; + } + + public String getName() + { + return "ECDSA5"; + } + + public void performTest() + throws Exception + { + testKeyConversion(); + testAdaptiveKeyConversion(); + decodeTest(); + testECDSA239bitPrime(); + testECDSA239bitBinary(); + testGeneration(); + testKeyPairGenerationWithOIDs(); + testNamedCurveParameterPreservation(); + testNamedCurveSigning(); + testBSI(); + testMQVwithHMACOnePass(); + testAlgorithmParameters(); + testModified(); + testSM2(); + testNonsense(); + testNamedCurveInKeyFactory(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new ECDSA5Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECEncodingTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECEncodingTest.java new file mode 100644 index 000000000..06ec0c7b6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECEncodingTest.java @@ -0,0 +1,214 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.SignatureException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Date; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.jce.X509Principal; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPointEncoder; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPrivateKey; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPublicKey; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.x509.X509V3CertificateGenerator; + +public class ECEncodingTest + extends SimpleTest +{ + public String getName() + { + return "ECEncodingTest"; + } + + /** J.4.7 An Example with m = 304 */ + private int m = 304; + + /** f = 010000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000807 */ + private int k1 = 1; + private int k2 = 2; + private int k3 = 11; + private byte hexa[] = {(byte)0xFD, 0x0D, 0x69, 0x31, 0x49, (byte)0xA1, 0x18, (byte)0xF6, 0x51 + , (byte)0xE6, (byte)0xDC, (byte)0xE6, (byte)0x80, 0x20, (byte)0x85, 0x37, 0x7E, 0x5F, (byte)0x88, 0x2D, 0x1B, 0x51 + , 0x0B, 0x44, 0x16, 0x00, 0x74, (byte)0xC1, 0x28, (byte)0x80, 0x78, 0x36, 0x5A, 0x03 + , (byte)0x96, (byte)0xC8, (byte)0xE6, (byte)0x81}; + private byte hexb[] = {(byte)0xBD, (byte)0xDB, (byte)0x97, (byte)0xE5, (byte)0x55 + , (byte)0xA5, (byte)0x0A, (byte)0x90, (byte)0x8E, (byte)0x43, (byte)0xB0 + , (byte)0x1C, (byte)0x79, (byte)0x8E, (byte)0xA5, (byte)0xDA, (byte)0xA6 + , (byte)0x78, (byte)0x8F, (byte)0x1E, (byte)0xA2, (byte)0x79 + , (byte)0x4E, (byte)0xFC, (byte)0xF5, (byte)0x71, (byte)0x66, (byte)0xB8 + , (byte)0xC1, (byte)0x40, (byte)0x39, (byte)0x60, (byte)0x1E + , (byte)0x55, (byte)0x82, (byte)0x73, (byte)0x40, (byte)0xBE}; + private BigInteger a = new BigInteger(1, hexa); + private BigInteger b = new BigInteger(1, hexb); + + /** Base point G (with point compression) */ + private byte enc[] = + {0x02, 0x19, 0x7B, 0x07, (byte)0x84, 0x5E, (byte)0x9B, (byte)0xE2, (byte)0xD9, 0x6A, (byte)0xDB, 0x0F + , 0x5F, 0x3C, 0x7F, 0x2C, (byte)0xFF, (byte)0xBD, 0x7A, 0x3E, (byte)0xB8, (byte)0xB6, (byte)0xFE, + (byte)0xC3, 0x5C, 0x7F, (byte)0xD6, 0x7F, 0x26, (byte)0xDD, (byte)0xF6 + , 0x28, 0x5A, 0x64, 0x4F, 0x74, 0x0A, 0x26, 0x14}; + + private void testPointCompression() + throws Exception + { + ECCurve curve = new ECCurve.F2m(m, k1, k2, k3, a, b); + curve.decodePoint(enc); + + int ks[] = new int[3]; + ks[0] = k3; + ks[1] = k2; + ks[2] = k1; + } + + public void performTest() + throws Exception + { + byte[] ecParams = Hex.decode("3081C8020101302806072A8648CE3D0101021D00D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF303C041C68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43041C2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B0439040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD021D00D7C134AA264366862A18302575D0FB98D116BC4B6DDEBCA3A5A7939F020101"); + testParams(ecParams, true); + + testParams(ecParams, false); + + ecParams = Hex.decode("3081C8020101302806072A8648CE3D0101021D00D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF303C041C56E6C7E4F11A7B4B961A4DCB5BD282EB22E42E9BCBE3E7B361F18012041C4BE3E7B361F18012F2353D22975E02D8D05D2C6F3342DD8F57D4C76F0439048D127A0C27E0DE207ED3B7FB98F83C8BD5A2A57C827F4B97874DEB2C1BAEB0C006958CE61BB1FC81F5389E288CB3E86E2ED91FB47B08FCCA021D00D7C134AA264366862A18302575D11A5F7AABFBA3D897FF5CA727AF53020101"); + testParams(ecParams, true); + + testParams(ecParams, false); + + ecParams = Hex.decode("30820142020101303c06072a8648ce3d0101023100fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff3066043100fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000fffffffc043100b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef046104aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab73617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f023100ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973020101"); + testParams(ecParams, true); + + testParams(ecParams, false); + + testPointCompression(); + } + + private void testParams(byte[] ecParameterEncoded, boolean compress) + throws Exception + { + String keyStorePass = "myPass"; + ASN1InputStream in = new ASN1InputStream(new ByteArrayInputStream( + ecParameterEncoded)); + X9ECParameters params = X9ECParameters.getInstance(in + .readObject()); + KeyPair kp = null; + boolean success = false; + while (!success) + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECDSA"); + kpg.initialize(new ECParameterSpec(params.getCurve(), + params.getG(), params.getN(), params.getH(), params + .getSeed())); + kp = kpg.generateKeyPair(); + // The very old Problem... we need a certificate chain to + // save a private key... + ECPublicKey pubKey = (ECPublicKey)kp.getPublic(); + if (!compress) + { + ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED"); + } + byte[] x = pubKey.getQ().getAffineXCoord().toBigInteger().toByteArray(); + byte[] y = pubKey.getQ().getAffineYCoord().toBigInteger().toByteArray(); + if (x.length == y.length) + { + success = true; + } + } + + // The very old Problem... we need a certificate chain to + // save a private key... + + Certificate[] chain = new Certificate[] { generateSelfSignedSoftECCert( + kp, compress) }; + + KeyStore keyStore = KeyStore.getInstance("BKS"); + keyStore.load(null, keyStorePass.toCharArray()); + + keyStore.setCertificateEntry("ECCert", chain[0]); + + ECPrivateKey privateECKey = (ECPrivateKey)kp.getPrivate(); + keyStore.setKeyEntry("ECPrivKey", privateECKey, keyStorePass + .toCharArray(), chain); + + // Test ec sign / verify + ECPublicKey pub = (ECPublicKey)kp.getPublic(); + String oldPrivateKey = new String(Hex.encode(privateECKey.getEncoded())); + String oldPublicKey = new String(Hex.encode(pub.getEncoded())); + ECPrivateKey newKey = (ECPrivateKey)keyStore.getKey("ECPrivKey", + keyStorePass.toCharArray()); + ECPublicKey newPubKey = (ECPublicKey)keyStore.getCertificate( + "ECCert").getPublicKey(); + if (!compress) + { + ((ECPointEncoder)newKey).setPointFormat("UNCOMPRESSED"); + ((ECPointEncoder)newPubKey).setPointFormat("UNCOMPRESSED"); + } + + String newPrivateKey = new String(Hex.encode(newKey.getEncoded())); + String newPublicKey = new String(Hex.encode(newPubKey.getEncoded())); + + if (!oldPrivateKey.equals(newPrivateKey)) + { + fail("failed private key comparison"); + } + + if (!oldPublicKey.equals(newPublicKey)) + { + fail("failed public key comparison"); + } + } + + /** + * Create a self signed cert for our software emulation + * + * @param kp + * is the keypair for our certificate + * @return a self signed cert for our software emulation + * @throws InvalidKeyException + * on error + * @throws SignatureException + * on error + */ + private X509Certificate generateSelfSignedSoftECCert(KeyPair kp, + boolean compress) throws Exception + { + X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); + ECPrivateKey privECKey = (ECPrivateKey)kp.getPrivate(); + ECPublicKey pubECKey = (ECPublicKey)kp.getPublic(); + if (!compress) + { + ((ECPointEncoder)privECKey).setPointFormat("UNCOMPRESSED"); + ((ECPointEncoder)pubECKey).setPointFormat("UNCOMPRESSED"); + } + certGen.setSignatureAlgorithm("ECDSAwithSHA1"); + certGen.setSerialNumber(BigInteger.valueOf(1)); + certGen.setIssuerDN(new X509Principal("CN=Software emul (EC Cert)")); + certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000)); + certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000000)); + certGen.setSubjectDN(new X509Principal("CN=Software emul (EC Cert)")); + certGen.setPublicKey((PublicKey)pubECKey); + + return certGen.generate((PrivateKey)privECKey); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new ECEncodingTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECIESTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECIESTest.java new file mode 100644 index 000000000..c87d232bc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECIESTest.java @@ -0,0 +1,302 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; +import java.security.spec.ECGenParameterSpec; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.SealedObject; + +import com.fr.third.org.bouncycastle.crypto.agreement.ECDHBasicAgreement; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.engines.DESEngine; +import com.fr.third.org.bouncycastle.crypto.engines.IESEngine; +import com.fr.third.org.bouncycastle.crypto.generators.KDF2BytesGenerator; +import com.fr.third.org.bouncycastle.crypto.macs.HMac; +import com.fr.third.org.bouncycastle.crypto.paddings.PaddedBufferedBlockCipher; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPrivateKey; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPublicKey; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.IESParameterSpec; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test for ECIES - Elliptic Curve Integrated Encryption Scheme + */ +public class ECIESTest + extends SimpleTest +{ + + ECIESTest() + { + } + + public String getName() + { + return "ECIES"; + } + + public void performTest() + throws Exception + { + byte[] derivation = Hex.decode("202122232425262728292a2b2c2d2e2f"); + byte[] encoding = Hex.decode("303132333435363738393a3b3c3d3e3f"); + + + IESCipher c1 = new com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIES(); + IESCipher c2 = new com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIES(); + IESParameterSpec params = new IESParameterSpec(derivation,encoding,128); + + // Testing ECIES with default curve in streaming mode + KeyPairGenerator g = KeyPairGenerator.getInstance("EC", "BC"); + doTest("ECIES with default", g, "ECIES", params); + + // Testing ECIES with 192-bit curve in streaming mode + g.initialize(192, new SecureRandom()); + doTest("ECIES with 192-bit", g, "ECIES", params); + + // Testing ECIES with 256-bit curve in streaming mode + g.initialize(256, new SecureRandom()); + doTest("ECIES with 256-bit", g, "ECIES", params); + + + c1 = new IESCipher(new IESEngine(new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + new PaddedBufferedBlockCipher(new DESEngine()))); + + c2 = new IESCipher(new IESEngine(new ECDHBasicAgreement(), + new KDF2BytesGenerator(new SHA1Digest()), + new HMac(new SHA1Digest()), + new PaddedBufferedBlockCipher(new DESEngine()))); + + params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("0001020304050607")); + + // Testing ECIES with default curve using DES + g = KeyPairGenerator.getInstance("EC", "BC"); + + // Testing ECIES with 256-bit curve using DES-CBC + g.initialize(256, new SecureRandom()); + doTest("256-bit", g, "ECIESwithDESEDE-CBC", params); + + params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("0001020304050607")); + g.initialize(256, new SecureRandom()); + doTest("256-bit", g, "ECIESwithDESEDE-CBC", params); + + try + { + params = new IESParameterSpec(derivation, encoding, 128, 128, new byte[10]); + g.initialize(256, new SecureRandom()); + doTest("256-bit", g, "ECIESwithDESEDE-CBC", params); + fail("DESEDE no exception!"); + } + catch (InvalidAlgorithmParameterException e) + { + if (!e.getMessage().equals("NONCE in IES Parameters needs to be 8 bytes long")) + { + fail("DESEDE wrong message!"); + } + } + + c1 = new com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIESwithAESCBC(); + c2 = new com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.ec.IESCipher.ECIESwithAESCBC(); + params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("000102030405060708090a0b0c0d0e0f")); + + // Testing ECIES with 256-bit curve using AES-CBC + g.initialize(256, new SecureRandom()); + doTest("256-bit", g, "ECIESwithAES-CBC", params); + + params = new IESParameterSpec(derivation, encoding, 128, 128, Hex.decode("000102030405060708090a0b0c0d0e0f")); + g.initialize(256, new SecureRandom()); + doTest("256-bit", g, "ECIESwithAES-CBC", params); + + try + { + params = new IESParameterSpec(derivation, encoding, 128, 128, new byte[10]); + g.initialize(256, new SecureRandom()); + doTest("256-bit", g, "ECIESwithAES-CBC", params); + fail("AES no exception!"); + } + catch (InvalidAlgorithmParameterException e) + { + if (!e.getMessage().equals("NONCE in IES Parameters needs to be 16 bytes long")) + { + fail("AES wrong message!"); + } + } + + KeyPair keyPair = g.generateKeyPair(); + ECPublicKey pub = (ECPublicKey)keyPair.getPublic(); + ECPrivateKey priv = (ECPrivateKey)keyPair.getPrivate(); + + Cipher c = Cipher.getInstance("ECIESwithAES-CBC", "BC"); + + try + { + c.init(Cipher.ENCRYPT_MODE, pub, new IESParameterSpec(derivation, encoding, 128, 128, null)); + + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + + try + { + c.init(Cipher.DECRYPT_MODE, priv); + + fail("no exception"); + } + catch (IllegalArgumentException e) + { + isTrue("message ", "cannot handle supplied parameter spec: NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + + try + { + c.init(Cipher.DECRYPT_MODE, priv, new IESParameterSpec(derivation, encoding, 128, 128, null)); + + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("message ", "NONCE in IES Parameters needs to be 16 bytes long".equals(e.getMessage())); + } + + sealedObjectTest(); + } + + private void sealedObjectTest() + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("ECIES"); + kpg.initialize(new ECGenParameterSpec("secp256r1")); + KeyPair keyPair = kpg.generateKeyPair(); + + Cipher cipher = Cipher.getInstance("ECIES"); + cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic()); + + String toEncrypt = "Hello"; + + // Check that cipher works ok + cipher.doFinal(toEncrypt.getBytes()); + + // Using a SealedObject to encrypt the same string fails with a NullPointerException + SealedObject sealedObject = new SealedObject(toEncrypt, cipher); + + cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + + String result = (String)sealedObject.getObject(cipher); + + isTrue("result wrong", result.equals(toEncrypt)); + + result = (String)sealedObject.getObject(keyPair.getPrivate()); + + isTrue("result wrong", result.equals(toEncrypt)); + } + + public void doTest( + String testname, + KeyPairGenerator g, + String cipher, + IESParameterSpec p) + throws Exception + { + + byte[] message = Hex.decode("0102030405060708090a0b0c0d0e0f10111213141516"); + byte[] out1, out2; + + // Generate static key pair + KeyPair KeyPair = g.generateKeyPair(); + ECPublicKey Pub = (ECPublicKey) KeyPair.getPublic(); + ECPrivateKey Priv = (ECPrivateKey) KeyPair.getPrivate(); + + Cipher c1 = Cipher.getInstance(cipher); + Cipher c2 = Cipher.getInstance(cipher); + + // Testing with null parameters and DHAES mode off + c1.init(Cipher.ENCRYPT_MODE, Pub, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, Priv, c1.getParameters()); + + isTrue("nonce mismatch", Arrays.areEqual(c1.getIV(), c2.getIV())); + + out1 = c1.doFinal(message, 0, message.length); + out2 = c2.doFinal(out1, 0, out1.length); + if (!areEqual(out2, message)) + fail(testname + " test failed with null parameters, DHAES mode false."); + + + // Testing with given parameters and DHAES mode off + c1.init(Cipher.ENCRYPT_MODE, Pub, p, new SecureRandom()); + c2.init(Cipher.DECRYPT_MODE, Priv, p); + out1 = c1.doFinal(message, 0, message.length); + out2 = c2.doFinal(out1, 0, out1.length); + if (!areEqual(out2, message)) + fail(testname + " test failed with non-null parameters, DHAES mode false."); + + // + // corrupted data test + // + int offset = out1.length - (message.length + 8); + byte[] tmp = new byte[out1.length]; + for (int i = offset; i != out1.length; i++) + { + System.arraycopy(out1, 0, tmp, 0, tmp.length); + tmp[i] = (byte)~tmp[i]; + + try + { + c2.doFinal(tmp, 0, tmp.length); + + fail("decrypted corrupted data"); + } + catch (BadPaddingException e) + { + isTrue("wrong message: " + e.getMessage(), "unable to process block".equals(e.getMessage())); + } + } +// TODO: DHAES mode is not currently implemented, perhaps it shouldn't be... +// c1 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC"); +// c2 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding","BC"); +// +// // Testing with null parameters and DHAES mode on +// c1.init(Cipher.ENCRYPT_MODE, Pub, new SecureRandom()); +// c2.init(Cipher.DECRYPT_MODE, Priv, new SecureRandom()); +// +// out1 = c1.doFinal(message, 0, message.length); +// out2 = c2.doFinal(out1, 0, out1.length); +// if (!areEqual(out2, message)) +// fail(testname + " test failed with null parameters, DHAES mode true."); +// +// c1 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding"); +// c2 = Cipher.getInstance(cipher + "/DHAES/PKCS7Padding"); +// +// // Testing with given parameters and DHAES mode on +// c1.init(Cipher.ENCRYPT_MODE, Pub, p, new SecureRandom()); +// c2.init(Cipher.DECRYPT_MODE, Priv, p, new SecureRandom()); +// +// out1 = c1.doFinal(message, 0, message.length); +// out2 = c2.doFinal(out1, 0, out1.length); +// if (!areEqual(out2, message)) +// fail(testname + " test failed with non-null parameters, DHAES mode true."); + + } + + + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new ECIESTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECIESVectorTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECIESVectorTest.java new file mode 100644 index 000000000..c96334fd2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECIESVectorTest.java @@ -0,0 +1,237 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.Security; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import javax.crypto.Cipher; + +import com.fr.third.org.bouncycastle.crypto.prng.FixedSecureRandom; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPrivateKey; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPublicKey; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.IESParameterSpec; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test for ECIES - Elliptic Curve Integrated Encryption Scheme + */ +public class ECIESVectorTest + extends SimpleTest +{ + static byte[] message = Hex.decode("0102030405060708090a0b0c0d0e0f10111213141516"); + + static byte[] derivation1 = Hex.decode("202122232425262728292a2b2c2d2e2f"); + static byte[] derivation2 = Hex.decode("202122232425262728292a2b2c2d2e2f404142434445464748"); + + static byte[] encoding1 = Hex.decode("af"); + static byte[] encoding2 = Hex.decode("303132333435363738393a3b3c3d3e3f"); + static byte[] encoding3 = Hex.decode("101112131415161718191a1b1c1d1e1f303132333435363738393a3b3c3d3e3f"); + + static byte[] p256_1_pub = Base64.decode("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEGVoxUX5AiyggqzcaXG3yG6cH6PKSX6fVOnCo5SKolfR8kwc6S8zmADXlpnjzMLNUVvGDL805VKIXNJHijq4+gw=="); + static byte[] p256_1_pri = Base64.decode("MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQg+dn4oLSJcx5lxZhVxJCip13O/OblrNzNyCj2b9sNbQegCgYIKoZIzj0DAQehRANCAAQZWjFRfkCLKCCrNxpcbfIbpwfo8pJfp9U6cKjlIqiV9HyTBzpLzOYANeWmePMws1RW8YMvzTlUohc0keKOrj6D"); + static byte[] p256_1_eph = Hex.decode("35ee388194396b5febbddb7e3618eaaba44f3bae766dac70f75ae7b84b210948"); + + static byte[] p256_1_no_params = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae43dfbe605c746ba0c546c0c25ba5a00304587fbed07a35ca06415cf6ad4d6a69d01122c99e2c854fe818f"); + + static byte[] p256_1_with_params11 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4a57474b50621e97254c1f3b32635f694feb57e873a33c5d1948ee93ea5dc7577d42d7c2e41ab08f85835"); + static byte[] p256_1_with_params12 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4a57474b50621e97254c1f3b32635f694feb57e873a3394725300acb7855f71a149d3f51a2e6fbd7f5389"); + static byte[] p256_1_with_params13 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4a57474b50621e97254c1f3b32635f694feb57e873a33920872328f8d05ec561ba8c6e58d82b79c360078"); + static byte[] p256_1_with_params21 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4da4d2bb723cd2ca918d1835dc2716a767085facd5df4499a4f4b6726651fb5e88178f01d831d9e5be0c1"); + static byte[] p256_1_with_params22 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4da4d2bb723cd2ca918d1835dc2716a767085facd5df457c384a0e6402a5bb073120f08c706b49a4775d0"); + static byte[] p256_1_with_params23 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4da4d2bb723cd2ca918d1835dc2716a767085facd5df4039427c24c55a2627df0ebea00f9d1eded9dd64b"); + + static byte[] p256_2_pub = Base64.decode("MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAER4gx8nnRAkP+u76j0COZD81Cu9CTw3vczLnu1DG7ObI/VCzrDzJuswfzNWmxOFYXiXmZMAAkkEFA40nDSGOoqA=="); + static byte[] p256_2_pri = Base64.decode("MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBHkwdwIBAQQgkflw6MQj4RbyuPFHoDE3i1dEaROS9uDSjGvrvPjqL7mgCgYIKoZIzj0DAQehRANCAARHiDHyedECQ/67vqPQI5kPzUK70JPDe9zMue7UMbs5sj9ULOsPMm6zB/M1abE4VheJeZkwACSQQUDjScNIY6io"); + static byte[] p256_2_eph = Hex.decode("0c37e1e0559a60d0b9c5b7b139a3f2df022b23abbd194bd95c8eff0aab1fd544"); + + static byte[] p256_2_no_params = Hex.decode("04d1ef981f81edae5e2e517b498504105b636d950cc13a9e1e31c607d8f0adc00c2152f2abae4870274f8788c08be35a7908f5547416405f24818ef4e8e3ae8dacd99a5cadfe82652a18c6058fc5ef7ffca626235fdbf7e2537f494d049d6f4e53d3d3df489cefb31101e1"); + + static byte[] p256_2_with_params11 = Hex.decode("04d1ef981f81edae5e2e517b498504105b636d950cc13a9e1e31c607d8f0adc00c2152f2abae4870274f8788c08be35a7908f5547416405f24818ef4e8e3ae8dace0e423753f63e054824edbc298a5645d7a4010cc7e65947090625dc0d750c50b2d563f264718d95818d4"); + static byte[] p256_2_with_params12 = Hex.decode("04d1ef981f81edae5e2e517b498504105b636d950cc13a9e1e31c607d8f0adc00c2152f2abae4870274f8788c08be35a7908f5547416405f24818ef4e8e3ae8dace0e423753f63e054824edbc298a5645d7a4010cc7e6502850f65c7a2c466444dea69d95a2df9a4b6cf2c"); + static byte[] p256_2_with_params13 = Hex.decode("04d1ef981f81edae5e2e517b498504105b636d950cc13a9e1e31c607d8f0adc00c2152f2abae4870274f8788c08be35a7908f5547416405f24818ef4e8e3ae8dace0e423753f63e054824edbc298a5645d7a4010cc7e651188a654e47322a60e53ea20a9e02f0e78bf8a32"); + static byte[] p256_2_with_params21 = Hex.decode("04d1ef981f81edae5e2e517b498504105b636d950cc13a9e1e31c607d8f0adc00c2152f2abae4870274f8788c08be35a7908f5547416405f24818ef4e8e3ae8dacdbdbe5e5f72245f4b5c28ee1ae21442868aef592d4047c8149babf4e7faffb5474bd6d84d6b9f1c9faf5"); + static byte[] p256_2_with_params22 = Hex.decode("04d1ef981f81edae5e2e517b498504105b636d950cc13a9e1e31c607d8f0adc00c2152f2abae4870274f8788c08be35a7908f5547416405f24818ef4e8e3ae8dacdbdbe5e5f72245f4b5c28ee1ae21442868aef592d40471190bd9b4bddd63983e4963378c9f55c703a7e6"); + static byte[] p256_2_with_params23 = Hex.decode("04d1ef981f81edae5e2e517b498504105b636d950cc13a9e1e31c607d8f0adc00c2152f2abae4870274f8788c08be35a7908f5547416405f24818ef4e8e3ae8dacdbdbe5e5f72245f4b5c28ee1ae21442868aef592d404ca4307e077a693c6410815c7985b0678a42cbd84"); + + static byte[] p521_1_pub = Base64.decode("MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBLNtLEbQBq2YGA2Q+eCwulIDggr1dCj8CqY/Yj/HuzicYGmVkNpr/gRfZHX4FRrh9HsGrS7tW+UA1pCQmn3p3aeEADiaXGIybDBsnuU20xntomQG/d/OHDkEaPee9nFNbi9Oha7BHTA/x2yyLMhQHeUlMgjz0DQqRxrwGJmvI85eNZpM="); + static byte[] p521_1_pri = Base64.decode("MIH3AgEAMBAGByqGSM49AgEGBSuBBAAjBIHfMIHcAgEBBEIA1QAfnUvK1fAaENAArV0YnNGvnu2H1vGHNgsG3QV7p16gjd6UOgmGCZVM9SLlRH3fi9K1Xreyl4sQH3NeY+ZnInqgBwYFK4EEACOhgYkDgYYABAEs20sRtAGrZgYDZD54LC6UgOCCvV0KPwKpj9iP8e7OJxgaZWQ2mv+BF9kdfgVGuH0ewatLu1b5QDWkJCafendp4QAOJpcYjJsMGye5TbTGe2iZAb9384cOQRo9572cU1uL06FrsEdMD/HbLIsyFAd5SUyCPPQNCpHGvAYma8jzl41mkw=="); + static byte[] p521_1_eph = Hex.decode("d25c44819712555824360eef5afda947373ec462c2a0fd5bebbe0b0e4e40b4ebf483bc5b5eeb84542fc226dc2e5307ceec59fe7c557522b77589210b434295aabfc7"); + + static byte[] p521_1_no_params = Hex.decode("04009d332615586356df7caaabb4ddd1c7902f35595c0a708acf570659061313e44a5d581b0e646e0c623b737327ed2a6fb7391ed76ee5fdceb9480f8b414e37be786301f7f6162afa812f45c15aba6887c6559b4c379c98fddd95af179c457a6a0e414cd921fd3b5736068f2ce6bec2fbf28e0e230784a38bf6f7b6e42672e52959db1b7ee2102423e67f5ee7f46e87a26370b7734548f3baee7729c5ff1c1638b93f068628320c7c56b7a68fb86d"); + + static byte[] p521_1_with_params11 = Hex.decode("04009d332615586356df7caaabb4ddd1c7902f35595c0a708acf570659061313e44a5d581b0e646e0c623b737327ed2a6fb7391ed76ee5fdceb9480f8b414e37be786301f7f6162afa812f45c15aba6887c6559b4c379c98fddd95af179c457a6a0e414cd921fd3b5736068f2ce6bec2fbf28e0e230784a38bf6f7b6e42672e52959db1b7e49225382108fb5bdd6b4ad57fee63c2819d10c1bc7517bd0a5070c123d4e24d66f9f0bf21ec105629cb2"); + static byte[] p521_1_with_params12 = Hex.decode("04009d332615586356df7caaabb4ddd1c7902f35595c0a708acf570659061313e44a5d581b0e646e0c623b737327ed2a6fb7391ed76ee5fdceb9480f8b414e37be786301f7f6162afa812f45c15aba6887c6559b4c379c98fddd95af179c457a6a0e414cd921fd3b5736068f2ce6bec2fbf28e0e230784a38bf6f7b6e42672e52959db1b7e49225382108fb5bdd6b4ad57fee63c2819d10c1bc751a51c6c78d905b0b7702d2edf89d0cf30f0d21c93"); + static byte[] p521_1_with_params13 = Hex.decode("04009d332615586356df7caaabb4ddd1c7902f35595c0a708acf570659061313e44a5d581b0e646e0c623b737327ed2a6fb7391ed76ee5fdceb9480f8b414e37be786301f7f6162afa812f45c15aba6887c6559b4c379c98fddd95af179c457a6a0e414cd921fd3b5736068f2ce6bec2fbf28e0e230784a38bf6f7b6e42672e52959db1b7e49225382108fb5bdd6b4ad57fee63c2819d10c1bc7513a9fb7f21f78ef3467b54153b8e2998de5f46724"); + static byte[] p521_1_with_params21 = Hex.decode("04009d332615586356df7caaabb4ddd1c7902f35595c0a708acf570659061313e44a5d581b0e646e0c623b737327ed2a6fb7391ed76ee5fdceb9480f8b414e37be786301f7f6162afa812f45c15aba6887c6559b4c379c98fddd95af179c457a6a0e414cd921fd3b5736068f2ce6bec2fbf28e0e230784a38bf6f7b6e42672e52959db1b7e1e0e7ac9ade1646519a365ef578f0bbe3556a818c83a0ce6226db7a3f3964e7a18955f9150fb030dcb09"); + static byte[] p521_1_with_params22 = Hex.decode("04009d332615586356df7caaabb4ddd1c7902f35595c0a708acf570659061313e44a5d581b0e646e0c623b737327ed2a6fb7391ed76ee5fdceb9480f8b414e37be786301f7f6162afa812f45c15aba6887c6559b4c379c98fddd95af179c457a6a0e414cd921fd3b5736068f2ce6bec2fbf28e0e230784a38bf6f7b6e42672e52959db1b7e1e0e7ac9ade1646519a365ef578f0bbe3556a818c83ade9180b72d7d2e9218395ea7d83c00cf03c6b39d"); + static byte[] p521_1_with_params23 = Hex.decode("04009d332615586356df7caaabb4ddd1c7902f35595c0a708acf570659061313e44a5d581b0e646e0c623b737327ed2a6fb7391ed76ee5fdceb9480f8b414e37be786301f7f6162afa812f45c15aba6887c6559b4c379c98fddd95af179c457a6a0e414cd921fd3b5736068f2ce6bec2fbf28e0e230784a38bf6f7b6e42672e52959db1b7e1e0e7ac9ade1646519a365ef578f0bbe3556a818c83a605f2a4ef486f9215e546d618eb7624443ee1a7d"); + + static byte[] p521_2_pub = Base64.decode("MIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQACXj0hmGm68PQxI12y5sKMn4mN6mIMOEn1l6PBOeGtk8QuJHt1AS3X5DcPorJTxhuhdcdDHA3if1utfAw9hl7tCIBQELwgw2Vo3gYkdbG7Hj6O9kf8WpqIEJ3UsC4S0hITMY1knO41BaO4UdO+nUiN+PZPRRSqFwm3C5v3fffLSGbpIQ="); + static byte[] p521_2_pri = Base64.decode("MIH3AgEAMBAGByqGSM49AgEGBSuBBAAjBIHfMIHcAgEBBEIB6s6VR/8WgiOvSjHT/n5Y91wESyI9e4GABUNWMXMPhNspwb9++7fyanbeliHNz9K61SjDG7rLXs90K1iRvHPJwmygBwYFK4EEACOhgYkDgYYABAAJePSGYabrw9DEjXbLmwoyfiY3qYgw4SfWXo8E54a2TxC4ke3UBLdfkNw+islPGG6F1x0McDeJ/W618DD2GXu0IgFAQvCDDZWjeBiR1sbsePo72R/xamogQndSwLhLSEhMxjWSc7jUFo7hR076dSI349k9FFKoXCbcLm/d998tIZukhA=="); + static byte[] p521_2_eph = Hex.decode("c9ee178c7f200a51a0053931c697001205f8923fd04b538c3fd5df2be43a6f304581f57138906bba0be631f7e0fd2804d00b5cb053559f080c13c913358f6e1fcc6d"); + + static byte[] p521_2_no_params = Hex.decode("0400ddfd813bbba275fec8896a140036c9ee2fee49793cadc0a4d976d1b7827357b846e1e5aa9326b449c6ab268e3b2d145894cc02d33d849c108db1f696db6e867c2c01d129fcc80937aeb2beff58ebc9e9777ba864546aed12d86c5e6a89767cf5321ec323283032278698642c238b3fda4a5d5e9ea2f0b91ef7d979fda529687931ace65922842dba0351c1cebde53ee4ba9afadbd3a03a88507046f62c7383f96142c09df58be5b0a661893d41"); + + static byte[] p521_2_with_params11 = Hex.decode("0400ddfd813bbba275fec8896a140036c9ee2fee49793cadc0a4d976d1b7827357b846e1e5aa9326b449c6ab268e3b2d145894cc02d33d849c108db1f696db6e867c2c01d129fcc80937aeb2beff58ebc9e9777ba864546aed12d86c5e6a89767cf5321ec323283032278698642c238b3fda4a5d5e9ea2f0b91ef7d979fda529687931ace674ccf084d69e0bc9a728548d887a162ddf53a0002ed034b51a5406b831ce9ea713be7df54934b77dcc84"); + static byte[] p521_2_with_params12 = Hex.decode("0400ddfd813bbba275fec8896a140036c9ee2fee49793cadc0a4d976d1b7827357b846e1e5aa9326b449c6ab268e3b2d145894cc02d33d849c108db1f696db6e867c2c01d129fcc80937aeb2beff58ebc9e9777ba864546aed12d86c5e6a89767cf5321ec323283032278698642c238b3fda4a5d5e9ea2f0b91ef7d979fda529687931ace674ccf084d69e0bc9a728548d887a162ddf53a0002ed0767534663184e99c0958451ea417729e29e02a60"); + static byte[] p521_2_with_params13 = Hex.decode("0400ddfd813bbba275fec8896a140036c9ee2fee49793cadc0a4d976d1b7827357b846e1e5aa9326b449c6ab268e3b2d145894cc02d33d849c108db1f696db6e867c2c01d129fcc80937aeb2beff58ebc9e9777ba864546aed12d86c5e6a89767cf5321ec323283032278698642c238b3fda4a5d5e9ea2f0b91ef7d979fda529687931ace674ccf084d69e0bc9a728548d887a162ddf53a0002ed0517e1040bf7d57f2c8f9c3ce69e5a05a9a292700"); + static byte[] p521_2_with_params21 = Hex.decode("0400ddfd813bbba275fec8896a140036c9ee2fee49793cadc0a4d976d1b7827357b846e1e5aa9326b449c6ab268e3b2d145894cc02d33d849c108db1f696db6e867c2c01d129fcc80937aeb2beff58ebc9e9777ba864546aed12d86c5e6a89767cf5321ec323283032278698642c238b3fda4a5d5e9ea2f0b91ef7d979fda529687931ace68a9e28bb5d49c07d5f5f59a27311619103aea50e48ddc66e0f20686c8d0c329db510facc1c014f800920"); + static byte[] p521_2_with_params22 = Hex.decode("0400ddfd813bbba275fec8896a140036c9ee2fee49793cadc0a4d976d1b7827357b846e1e5aa9326b449c6ab268e3b2d145894cc02d33d849c108db1f696db6e867c2c01d129fcc80937aeb2beff58ebc9e9777ba864546aed12d86c5e6a89767cf5321ec323283032278698642c238b3fda4a5d5e9ea2f0b91ef7d979fda529687931ace68a9e28bb5d49c07d5f5f59a27311619103aea50e48ddbc970a66c80886782713e25ece75a23dec995121"); + static byte[] p521_2_with_params23 = Hex.decode("0400ddfd813bbba275fec8896a140036c9ee2fee49793cadc0a4d976d1b7827357b846e1e5aa9326b449c6ab268e3b2d145894cc02d33d849c108db1f696db6e867c2c01d129fcc80937aeb2beff58ebc9e9777ba864546aed12d86c5e6a89767cf5321ec323283032278698642c238b3fda4a5d5e9ea2f0b91ef7d979fda529687931ace68a9e28bb5d49c07d5f5f59a27311619103aea50e48dd7c3d8a51a95f88813d04a0c681355f6e86bb44e5"); + + static byte[] old_p256_1_no_params = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae43dfbe605c746ba0c546c0c25ba5a00304587fbed07a3ebe44837c43b86025cc08e333b1631a8227b8d49"); + + static byte[] old_p256_1_with_params11 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4a57474b50621e97254c1f3b32635f694feb57e873a332ce23d272262d47a528057eb5b0b11631707b28f"); + static byte[] old_p256_1_with_params12 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4a57474b50621e97254c1f3b32635f694feb57e873a3331e3e514868c771270632c9a9b852f2060d415da"); + static byte[] old_p256_1_with_params13 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4a57474b50621e97254c1f3b32635f694feb57e873a3353e10e6260e937bcdd244201a0de1d3941439076"); + static byte[] old_p256_1_with_params21 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4da4d2bb723cd2ca918d1835dc2716a767085facd5df4912a36ccc3c49de7d3d6b1fb312aeacf2d0b30e7"); + static byte[] old_p256_1_with_params22 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4da4d2bb723cd2ca918d1835dc2716a767085facd5df4171c056b90a3badd0bb689403ab214546b5f6411"); + static byte[] old_p256_1_with_params23 = Hex.decode("04bc8f4da6ea423c0698744b927ec71b67126d97ef9dd804c141a0dfcb466cc1c7df25539375ddb3ae7d08cc46fa2a78434c9f6123b108e39a5fe614729c3d8ae4da4d2bb723cd2ca918d1835dc2716a767085facd5df4ad1a6a561fe0582495cd14ac4494e4610ecddef1"); + + ECIESVectorTest() + { + } + + public String getName() + { + return "ECIESVectorTest"; + } + + public void performTest() + throws Exception + { + KeyFactory ecFact = KeyFactory.getInstance("EC", "BC"); + + KeyPair keyPair = new KeyPair(ecFact.generatePublic(new X509EncodedKeySpec(p256_1_pub)), ecFact.generatePrivate(new PKCS8EncodedKeySpec(p256_1_pri))); + + doTestNoParams("ECIES with P-256 None", keyPair, "ECIES", p256_1_eph, p256_1_no_params); + doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "ECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding1, 128), p256_1_with_params11); + doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "ECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding2, 128), p256_1_with_params12); + doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "ECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding3, 128), p256_1_with_params13); + doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "ECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding1, 128), p256_1_with_params21); + doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "ECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding2, 128), p256_1_with_params22); + doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "ECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding3, 128), p256_1_with_params23); + + // no longer supported +// doTestNoParams("ECIES with P-256 None", keyPair, "OldECIES", p256_1_eph, old_p256_1_no_params); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding1, 128), old_p256_1_with_params11); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding2, 128), old_p256_1_with_params12); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation1, encoding3, 128), old_p256_1_with_params13); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding1, 128), old_p256_1_with_params21); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding2, 128), old_p256_1_with_params22); +// doTestWithParams("ECIES with P-256 KP1 P11", keyPair, "OldECIES", p256_1_eph, new IESParameterSpec(derivation2, encoding3, 128), old_p256_1_with_params23); + + keyPair = new KeyPair(ecFact.generatePublic(new X509EncodedKeySpec(p256_2_pub)), ecFact.generatePrivate(new PKCS8EncodedKeySpec(p256_2_pri))); + + doTestNoParams("ECIES with P-256 None", keyPair, "ECIES", p256_2_eph, p256_2_no_params); + doTestWithParams("ECIES with P-256 KP2 P11", keyPair, "ECIES", p256_2_eph, new IESParameterSpec(derivation1, encoding1, 128), p256_2_with_params11); + doTestWithParams("ECIES with P-256 KP2 P11", keyPair, "ECIES", p256_2_eph, new IESParameterSpec(derivation1, encoding2, 128), p256_2_with_params12); + doTestWithParams("ECIES with P-256 KP2 P11", keyPair, "ECIES", p256_2_eph, new IESParameterSpec(derivation1, encoding3, 128), p256_2_with_params13); + doTestWithParams("ECIES with P-256 KP2 P11", keyPair, "ECIES", p256_2_eph, new IESParameterSpec(derivation2, encoding1, 128), p256_2_with_params21); + doTestWithParams("ECIES with P-256 KP2 P11", keyPair, "ECIES", p256_2_eph, new IESParameterSpec(derivation2, encoding2, 128), p256_2_with_params22); + doTestWithParams("ECIES with P-256 KP2 P11", keyPair, "ECIES", p256_2_eph, new IESParameterSpec(derivation2, encoding3, 128), p256_2_with_params23); + + keyPair = new KeyPair(ecFact.generatePublic(new X509EncodedKeySpec(p521_1_pub)), ecFact.generatePrivate(new PKCS8EncodedKeySpec(p521_1_pri))); + + doTestNoParams("ECIES with P-521 None", keyPair, "ECIES", p521_1_eph, p521_1_no_params); + doTestWithParams("ECIES with P-521 KP1 P11", keyPair, "ECIES", p521_1_eph, new IESParameterSpec(derivation1, encoding1, 128), p521_1_with_params11); + doTestWithParams("ECIES with P-521 KP1 P11", keyPair, "ECIES", p521_1_eph, new IESParameterSpec(derivation1, encoding2, 128), p521_1_with_params12); + doTestWithParams("ECIES with P-521 KP1 P11", keyPair, "ECIES", p521_1_eph, new IESParameterSpec(derivation1, encoding3, 128), p521_1_with_params13); + doTestWithParams("ECIES with P-521 KP1 P11", keyPair, "ECIES", p521_1_eph, new IESParameterSpec(derivation2, encoding1, 128), p521_1_with_params21); + doTestWithParams("ECIES with P-521 KP1 P11", keyPair, "ECIES", p521_1_eph, new IESParameterSpec(derivation2, encoding2, 128), p521_1_with_params22); + doTestWithParams("ECIES with P-521 KP1 P11", keyPair, "ECIES", p521_1_eph, new IESParameterSpec(derivation2, encoding3, 128), p521_1_with_params23); + + keyPair = new KeyPair(ecFact.generatePublic(new X509EncodedKeySpec(p521_2_pub)), ecFact.generatePrivate(new PKCS8EncodedKeySpec(p521_2_pri))); + + doTestNoParams("ECIES with default", keyPair, "ECIES", p521_2_eph, p521_2_no_params); + doTestWithParams("ECIES with P-521 KP2 P11", keyPair, "ECIES", p521_2_eph, new IESParameterSpec(derivation1, encoding1, 128), p521_2_with_params11); + doTestWithParams("ECIES with P-521 KP2 P12", keyPair, "ECIES", p521_2_eph, new IESParameterSpec(derivation1, encoding2, 128), p521_2_with_params12); + doTestWithParams("ECIES with P-521 KP2 P13", keyPair, "ECIES", p521_2_eph, new IESParameterSpec(derivation1, encoding3, 128), p521_2_with_params13); + doTestWithParams("ECIES with P-521 KP2 P21", keyPair, "ECIES", p521_2_eph, new IESParameterSpec(derivation2, encoding1, 128), p521_2_with_params21); + doTestWithParams("ECIES with P-521 KP2 P21", keyPair, "ECIES", p521_2_eph, new IESParameterSpec(derivation2, encoding2, 128), p521_2_with_params22); + doTestWithParams("ECIES with P-521 KP2 P21", keyPair, "ECIES", p521_2_eph, new IESParameterSpec(derivation2, encoding3, 128), p521_2_with_params23); + } + + public void doTestNoParams( + String testname, + KeyPair keyPair, + String cipher, + byte[] ephPrivateValue, + byte[] expected) + throws Exception + { + + + byte[] out1, out2; + + // Generate static key pair + ECPublicKey Pub = (ECPublicKey)keyPair.getPublic(); + ECPrivateKey Priv = (ECPrivateKey)keyPair.getPrivate(); + + Cipher c1 = Cipher.getInstance(cipher); + Cipher c2 = Cipher.getInstance(cipher); + + // Testing with null parameters and DHAES mode off + c1.init(Cipher.ENCRYPT_MODE, Pub, new FixedSecureRandom(ephPrivateValue)); + c2.init(Cipher.DECRYPT_MODE, Priv, new FixedSecureRandom(ephPrivateValue)); + out1 = c1.doFinal(message, 0, message.length); + + if (!areEqual(out1, expected)) + { + fail(testname + " test failed encrypt with null parameters, DHAES mode false."); + } + + out2 = c2.doFinal(out1, 0, out1.length); + if (!areEqual(out2, message)) + { + fail(testname + " test failed decrypt with null parameters, DHAES mode false."); + } + } + + public void doTestWithParams( + String testname, + KeyPair keyPair, + String cipher, + byte[] ephPrivateValue, + IESParameterSpec p, + byte[] expected) + throws Exception + { + byte[] out1, out2; + + // Generate static key pair + ECPublicKey Pub = (ECPublicKey)keyPair.getPublic(); + ECPrivateKey Priv = (ECPrivateKey)keyPair.getPrivate(); + + Cipher c1 = Cipher.getInstance(cipher); + Cipher c2 = Cipher.getInstance(cipher); + + // Testing with given parameters and DHAES mode off + c1.init(Cipher.ENCRYPT_MODE, Pub, p, new FixedSecureRandom(ephPrivateValue)); + c2.init(Cipher.DECRYPT_MODE, Priv, p, new FixedSecureRandom(ephPrivateValue)); + out1 = c1.doFinal(message, 0, message.length); + + if (!areEqual(out1, expected)) + { + fail(testname + " test failed encrypt with non-null parameters, DHAES mode false."); + } + out2 = c2.doFinal(out1, 0, out1.length); + if (!areEqual(out2, message)) + { + fail(testname + " test failed decrypt with non-null parameters, DHAES mode false."); + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new ECIESVectorTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECNRTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECNRTest.java new file mode 100644 index 000000000..8b6628b60 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ECNRTest.java @@ -0,0 +1,231 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.FixedSecureRandom; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; + +public class ECNRTest + extends SimpleTest +{ + byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); + byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); + + SecureRandom random = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2) }); + + /** + * X9.62 - 1998,
+ * J.3.2, Page 155, ECDSA over the field Fp
+ * an example with 239 bit prime + */ + private void testECNR239bitPrime() + throws Exception + { + BigInteger r = new BigInteger("308636143175167811492623515537541734843573549327605293463169625072911693"); + BigInteger s = new BigInteger("852401710738814635664888632022555967400445256405412579597015412971797143"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("700000017569056646655505781757157107570501575775705779575555657156756655")); + + SecureRandom k = new TestRandomBigInteger(kData); + + X9ECParameters x9 = ECNamedCurveTable.getByName("prime239v1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec spec = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("876300101507107567501066130761671078357010671067781776716671676178726717"), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + curve.decodePoint(Hex.decode("025b6dc53bc61a2548ffb0f671472de6c9521a9d2d2534e65abfcbd5fe0c70")), // Q + spec); + + Signature sgr = Signature.getInstance("SHA1withECNR", "BC"); + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + + byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + + checkSignature(239, priKey, pubKey, sgr, k, message, r, s); + } + + // ------------------------------------------------------------------------- + + /** + * X9.62 - 1998,
+ * Page 104-105, ECDSA over the field Fp
+ * an example with 192 bit prime + */ + private void testECNR192bitPrime() + throws Exception + { + BigInteger r = new BigInteger("2474388605162950674935076940284692598330235697454145648371"); + BigInteger s = new BigInteger("2997192822503471356158280167065034437828486078932532073836"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("dcc5d1f1020906df2782360d36b2de7a17ece37d503784af", 16)); + + SecureRandom k = new TestRandomBigInteger(kData); + + X9ECParameters x9 = ECNamedCurveTable.getByName("prime192v1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec spec = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("651056770906015076056810763456358567190100156695615665659"), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + curve.decodePoint(Hex.decode("0262B12D60690CDCF330BABAB6E69763B471F994DD702D16A5")), // Q + spec); + + Signature sgr = Signature.getInstance("SHA1withECNR", "BC"); + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + + byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + + checkSignature(192, priKey, pubKey, sgr, k, message, r, s); + } + + // ------------------------------------------------------------------------- + + /** + * SEC 2: Recommended Elliptic Curve Domain Parameters - September 2000,
+ * Page 17-19, Recommended 521-bit Elliptic Curve Domain Parameters over Fp
+ * an ECC example with a 521 bit prime and a 512 bit hash + */ + private void testECNR521bitPrime() + throws Exception + { + BigInteger r = new BigInteger("1820641608112320695747745915744708800944302281118541146383656165330049339564439316345159057453301092391897040509935100825960342573871340486684575368150970954"); + BigInteger s = new BigInteger("6358277176448326821136601602749690343031826490505780896013143436153111780706227024847359990383467115737705919410755190867632280059161174165591324242446800763"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("cdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef", 16)); + + SecureRandom k = new TestRandomBigInteger(kData); + + X9ECParameters x9 = ECNamedCurveTable.getByName("secp521r1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec spec = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + curve.decodePoint(Hex.decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q + spec); + + Signature sgr = Signature.getInstance("SHA512withECNR", "BC"); + byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + + checkSignature(521, priKey, pubKey, sgr, k, message, r, s); + } + + private void checkSignature( + int size, + ECPrivateKeySpec priKey, + ECPublicKeySpec pubKey, + Signature sgr, + SecureRandom k, + byte[] message, + BigInteger r, + BigInteger s) + throws Exception + { + KeyFactory f = KeyFactory.getInstance("ECDSA", "BC"); + PrivateKey sKey = f.generatePrivate(priKey); + PublicKey vKey = f.generatePublic(pubKey); + + sgr.initSign(sKey, k); + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail(size + " bit EC verification failed"); + } + + BigInteger[] sig = derDecode(sigBytes); + + if (!r.equals(sig[0])) + { + fail(size + "bit" + + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail(size + "bit" + + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + } + + protected BigInteger[] derDecode( + byte[] encoding) + throws IOException + { + ByteArrayInputStream bIn = new ByteArrayInputStream(encoding); + ASN1InputStream aIn = new ASN1InputStream(bIn); + ASN1Sequence s = (ASN1Sequence)aIn.readObject(); + + BigInteger[] sig = new BigInteger[2]; + + sig[0] = ((ASN1Integer)s.getObjectAt(0)).getValue(); + sig[1] = ((ASN1Integer)s.getObjectAt(1)).getValue(); + + return sig; + } + + public String getName() + { + return "ECNR"; + } + + public void performTest() + throws Exception + { + testECNR192bitPrime(); + testECNR239bitPrime(); + testECNR521bitPrime(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new ECNRTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/EdECTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/EdECTest.java new file mode 100644 index 000000000..c247d7c00 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/EdECTest.java @@ -0,0 +1,628 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.crypto.KeyAgreement; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.edec.EdECObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.jcajce.spec.DHUParameterSpec; +import com.fr.third.org.bouncycastle.jcajce.spec.EdDSAParameterSpec; +import com.fr.third.org.bouncycastle.jcajce.spec.UserKeyingMaterialSpec; +import com.fr.third.org.bouncycastle.jcajce.spec.XDHParameterSpec; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class EdECTest + extends SimpleTest +{ + private static final byte[] pubEnc = Base64.decode( + "MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE="); + + private static final byte[] privEnc = Base64.decode( + "MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC"); + + private static final byte[] privWithPubEnc = Base64.decode( + "MHICAQEwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC" + + "oB8wHQYKKoZIhvcNAQkJFDEPDA1DdXJkbGUgQ2hhaXJzgSEAGb9ECWmEzf6FQbrB" + + "Z9w7lshQhqowtrbLDFw4rXAxZuE="); + + public static final byte[] x25519Cert = Base64.decode( + "MIIBLDCB36ADAgECAghWAUdKKo3DMDAFBgMrZXAwGTEXMBUGA1UEAwwOSUVURiBUZX" + + "N0IERlbW8wHhcNMTYwODAxMTIxOTI0WhcNNDAxMjMxMjM1OTU5WjAZMRcwFQYDVQQD" + + "DA5JRVRGIFRlc3QgRGVtbzAqMAUGAytlbgMhAIUg8AmJMKdUdIt93LQ+91oNvzoNJj" + + "ga9OukqY6qm05qo0UwQzAPBgNVHRMBAf8EBTADAQEAMA4GA1UdDwEBAAQEAwIDCDAg" + + "BgNVHQ4BAQAEFgQUmx9e7e0EM4Xk97xiPFl1uQvIuzswBQYDK2VwA0EAryMB/t3J5v" + + "/BzKc9dNZIpDmAgs3babFOTQbs+BolzlDUwsPrdGxO3YNGhW7Ibz3OGhhlxXrCe1Cg" + + "w1AH9efZBw=="); + + public String getName() + { + return "EdEC"; + } + + public void performTest() + throws Exception + { + KeyFactory kFact = KeyFactory.getInstance("EdDSA", "BC"); + + PublicKey pub = kFact.generatePublic(new X509EncodedKeySpec(pubEnc)); + + isTrue("pub failed", areEqual(pubEnc, pub.getEncoded())); + + serializationTest("ref pub", pub); + + PrivateKey priv = kFact.generatePrivate(new PKCS8EncodedKeySpec(privEnc)); + + isTrue("priv failed", areEqual(privEnc, priv.getEncoded())); + + priv = kFact.generatePrivate(new PKCS8EncodedKeySpec(privWithPubEnc)); + + isTrue("priv with pub failed", areEqual(privWithPubEnc, priv.getEncoded())); + + serializationTest("ref priv", priv); + + Signature sig = Signature.getInstance("EDDSA", "BC"); + + Certificate x25519Cert = Certificate.getInstance(EdECTest.x25519Cert); + + sig.initVerify(pub); + + sig.update(x25519Cert.getTBSCertificate().getEncoded()); + + isTrue(sig.verify(x25519Cert.getSignature().getBytes())); + + x448AgreementTest(); + x25519AgreementTest(); + ed448SignatureTest(); + ed25519SignatureTest(); + x448withCKDFTest(); + x25519withCKDFTest(); + x448withKDFTest(); + x25519withKDFTest(); + x448UwithKDFTest(); + x25519UwithKDFTest(); + + xdhGeneratorTest(); + eddsaGeneratorTest(); + + keyTest("X448"); + keyTest("X25519"); + keyTest("Ed448"); + keyTest("Ed25519"); + + keyFactoryTest("X448", EdECObjectIdentifiers.id_X448); + keyFactoryTest("X25519", EdECObjectIdentifiers.id_X25519); + keyFactoryTest("Ed448", EdECObjectIdentifiers.id_Ed448); + keyFactoryTest("Ed25519", EdECObjectIdentifiers.id_Ed25519); + } + + private void keyFactoryTest(String algorithm, ASN1ObjectIdentifier algOid) + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance(algorithm, "BC"); + KeyFactory kFact = KeyFactory.getInstance((algorithm.startsWith("X") ? "XDH" : "EdDSA"), "BC"); + + KeyPair kp = kpGen.generateKeyPair(); + + Set alts = new HashSet(); + + alts.add("X448"); + alts.add("X25519"); + alts.add("Ed448"); + alts.add("Ed25519"); + + alts.remove(algorithm); + + PrivateKey k1 = kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); + + checkEquals(algorithm, kp.getPrivate(), k1); + + PublicKey k2 = kFact.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded())); + + checkEquals(algorithm, kp.getPublic(), k2); + + for (Iterator it = alts.iterator(); it.hasNext(); ) + { + String altAlg = (String)it.next(); + + kFact = KeyFactory.getInstance(altAlg, "BC"); + + try + { + k1 = kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); + fail("no exception"); + } + catch (InvalidKeySpecException e) + { + isEquals("encoded key spec not recognized: algorithm identifier " + algOid.getId() + " in key not recognized", e.getMessage()); + } + + try + { + k2 = kFact.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded())); + fail("no exception"); + } + catch (InvalidKeySpecException e) + { + isEquals("encoded key spec not recognized: algorithm identifier " + algOid.getId() + " in key not recognized", e.getMessage()); + } + } + } + + private void keyTest(String algorithm) + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance(algorithm, "BC"); + + KeyFactory kFact = KeyFactory.getInstance(algorithm, "BC"); + + KeyPair kp = kpGen.generateKeyPair(); + + PrivateKey k1 = kFact.generatePrivate(new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded())); + + checkEquals(algorithm, kp.getPrivate(), k1); + + PublicKey k2 = kFact.generatePublic(new X509EncodedKeySpec(kp.getPublic().getEncoded())); + + checkEquals(algorithm, kp.getPublic(), k2); + + serializationTest(algorithm, kp.getPublic()); + serializationTest(algorithm, kp.getPrivate()); + + String pubString = kp.getPublic().toString(); + String privString = kp.getPrivate().toString(); + + isTrue(pubString.startsWith(algorithm + " Public Key [")); + isTrue(privString.startsWith(algorithm + " Private Key [")); + isTrue(privString.substring((algorithm + " Private Key [").length()) + .equals(pubString.substring((algorithm + " Public Key [").length()))); + } + + private void xdhGeneratorTest() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("XDH", "BC"); + + kpGen.initialize(new XDHParameterSpec(XDHParameterSpec.X448)); + + KeyPair kp = kpGen.generateKeyPair(); + + isTrue("X448".equals(kp.getPublic().getAlgorithm())); + + kpGen.initialize(new ECGenParameterSpec(XDHParameterSpec.X448)); + + kp = kpGen.generateKeyPair(); + + isTrue("X448".equals(kp.getPublic().getAlgorithm())); + + kpGen.initialize(448); + + kp = kpGen.generateKeyPair(); + + isTrue("X448".equals(kp.getPublic().getAlgorithm())); + + kpGen = KeyPairGenerator.getInstance("XDH", "BC"); + + kpGen.initialize(new XDHParameterSpec(XDHParameterSpec.X25519)); + + kp = kpGen.generateKeyPair(); + + isTrue("X25519".equals(kp.getPublic().getAlgorithm())); + + kpGen.initialize(new ECGenParameterSpec(XDHParameterSpec.X25519)); + + kp = kpGen.generateKeyPair(); + + isTrue("X25519".equals(kp.getPublic().getAlgorithm())); + + kpGen.initialize(256); + + kp = kpGen.generateKeyPair(); + + isTrue("X25519".equals(kp.getPublic().getAlgorithm())); + + kpGen.initialize(255); + + kp = kpGen.generateKeyPair(); + + isTrue("X25519".equals(kp.getPublic().getAlgorithm())); + + kpGen = KeyPairGenerator.getInstance("XDH", "BC"); + + try + { + kpGen.generateKeyPair(); + fail("no exception"); + } + catch (IllegalStateException e) + { + isEquals("generator not correctly initialized", e.getMessage()); + } + + try + { + kpGen.initialize(new EdDSAParameterSpec(EdDSAParameterSpec.Ed448)); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isEquals("parameterSpec for wrong curve type", e.getMessage()); + } + + try + { + kpGen.initialize(1024); + fail("no exception"); + } + catch (InvalidParameterException e) + { + isEquals("unknown key size", e.getMessage()); + } + + try + { + kpGen.initialize(new EdDSAParameterSpec(EdDSAParameterSpec.Ed448)); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isEquals("parameterSpec for wrong curve type", e.getMessage()); + } + + try + { + new XDHParameterSpec(EdDSAParameterSpec.Ed448); + } + catch (IllegalArgumentException e) + { + isEquals("unrecognized curve name: Ed448", e.getMessage()); + } + } + + private void eddsaGeneratorTest() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EdDSA", "BC"); + + kpGen.initialize(new EdDSAParameterSpec(EdDSAParameterSpec.Ed448)); + + KeyPair kp = kpGen.generateKeyPair(); + + isTrue("Ed448".equals(kp.getPublic().getAlgorithm())); + + kpGen.initialize(new EdDSAParameterSpec(EdDSAParameterSpec.Ed448)); + + kp = kpGen.generateKeyPair(); + + isTrue("Ed448".equals(kp.getPublic().getAlgorithm())); + + kpGen.initialize(448); + + kp = kpGen.generateKeyPair(); + + isTrue("Ed448".equals(kp.getPublic().getAlgorithm())); + + kpGen = KeyPairGenerator.getInstance("EdDSA", "BC"); + + kpGen.initialize(new EdDSAParameterSpec(EdDSAParameterSpec.Ed25519)); + + kp = kpGen.generateKeyPair(); + + isTrue("Ed25519".equals(kp.getPublic().getAlgorithm())); + + kpGen.initialize(new ECGenParameterSpec(EdDSAParameterSpec.Ed25519)); + + kp = kpGen.generateKeyPair(); + + isTrue("Ed25519".equals(kp.getPublic().getAlgorithm())); + + kpGen.initialize(256); + + kp = kpGen.generateKeyPair(); + + isTrue("Ed25519".equals(kp.getPublic().getAlgorithm())); + + kpGen.initialize(255); + + kp = kpGen.generateKeyPair(); + + isTrue("Ed25519".equals(kp.getPublic().getAlgorithm())); + + kpGen = KeyPairGenerator.getInstance("EdDSA", "BC"); + + try + { + kpGen.generateKeyPair(); + fail("no exception"); + } + catch (IllegalStateException e) + { + isEquals("generator not correctly initialized", e.getMessage()); + } + + try + { + kpGen.initialize(new XDHParameterSpec(XDHParameterSpec.X448)); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isEquals("parameterSpec for wrong curve type", e.getMessage()); + } + + try + { + kpGen.initialize(new XDHParameterSpec(XDHParameterSpec.X25519)); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isEquals("parameterSpec for wrong curve type", e.getMessage()); + } + + try + { + kpGen.initialize(1024); + fail("no exception"); + } + catch (InvalidParameterException e) + { + isEquals("unknown key size", e.getMessage()); + } + + try + { + new EdDSAParameterSpec(XDHParameterSpec.X448); + } + catch (IllegalArgumentException e) + { + isEquals("unrecognized curve name: X448", e.getMessage()); + } + } + + private void checkEquals(String algorithm, Key ka, Key kb) + { + isEquals(algorithm + " check equals", ka, kb); + isEquals(algorithm + " check hashCode", ka.hashCode(), kb.hashCode()); + } + + private void serializationTest(String algorithm, Key key) + throws IOException, ClassNotFoundException + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(key); + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + Key rk = (Key)oIn.readObject(); + + checkEquals(algorithm, key, rk); + } + + private void x448AgreementTest() + throws Exception + { + agreementTest("X448"); + } + + private void x25519AgreementTest() + throws Exception + { + agreementTest("X25519"); + } + + private void x448withCKDFTest() + throws Exception + { + agreementTest("X448withSHA256CKDF", new UserKeyingMaterialSpec(Hex.decode("beeffeed"))); + agreementTest("X448withSHA384CKDF", new UserKeyingMaterialSpec(Hex.decode("beeffeed"))); + agreementTest("X448withSHA512CKDF", new UserKeyingMaterialSpec(Hex.decode("beeffeed"))); + } + + private void x25519withCKDFTest() + throws Exception + { + agreementTest("X25519withSHA256CKDF", new UserKeyingMaterialSpec(Hex.decode("beeffeed"))); + agreementTest("X25519withSHA384CKDF", new UserKeyingMaterialSpec(Hex.decode("beeffeed"))); + agreementTest("X25519withSHA512CKDF", new UserKeyingMaterialSpec(Hex.decode("beeffeed"))); + } + + private void x448withKDFTest() + throws Exception + { + agreementTest("X448withSHA512KDF", new UserKeyingMaterialSpec(Hex.decode("beeffeed"))); + } + + private void x25519withKDFTest() + throws Exception + { + agreementTest("X25519withSHA256KDF", new UserKeyingMaterialSpec(Hex.decode("beeffeed"))); + } + + private void ed448SignatureTest() + throws Exception + { + signatureTest("Ed448"); + } + + private void ed25519SignatureTest() + throws Exception + { + signatureTest("Ed25519"); + } + + private void agreementTest(String algorithm) + throws Exception + { + agreementTest(algorithm, null); + } + + private void agreementTest(String algorithm, AlgorithmParameterSpec spec) + throws Exception + { + KeyAgreement keyAgreement = KeyAgreement.getInstance(algorithm, "BC"); + + KeyPairGenerator kpGen = KeyPairGenerator.getInstance( + algorithm.startsWith("X448") ? "X448" : "X25519", "BC"); + + KeyPair kp1 = kpGen.generateKeyPair(); + KeyPair kp2 = kpGen.generateKeyPair(); + + keyAgreement.init(kp1.getPrivate()); + + keyAgreement.doPhase(kp2.getPublic(), true); + + byte[] sec1 = keyAgreement.generateSecret(); + + keyAgreement.init(kp2.getPrivate()); + + keyAgreement.doPhase(kp1.getPublic(), true); + + byte[] sec2 = keyAgreement.generateSecret(); + + isTrue(areEqual(sec1, sec2)); + + if (spec != null) + { + keyAgreement.init(kp1.getPrivate(), spec); + + keyAgreement.doPhase(kp2.getPublic(), true); + + byte[] sec3 = keyAgreement.generateSecret(); + + keyAgreement.init(kp2.getPrivate(), spec); + + keyAgreement.doPhase(kp1.getPublic(), true); + + byte[] sec4 = keyAgreement.generateSecret(); + + isTrue(areEqual(sec3, sec4)); + isTrue(!areEqual(sec1, sec4)); + } + } + + private void x448UwithKDFTest() + throws Exception + { + unifiedAgreementTest("X448UwithSHA512KDF"); + } + + private void x25519UwithKDFTest() + throws Exception + { + unifiedAgreementTest("X25519UwithSHA256KDF"); + } + + private void unifiedAgreementTest(String algorithm) + throws Exception + { + KeyAgreement keyAgreement = KeyAgreement.getInstance(algorithm, "BC"); + + KeyPairGenerator kpGen = KeyPairGenerator.getInstance( + algorithm.startsWith("X448") ? "X448" : "X25519", "BC"); + + KeyPair aKp1 = kpGen.generateKeyPair(); + KeyPair aKp2 = kpGen.generateKeyPair(); + + KeyPair bKp1 = kpGen.generateKeyPair(); + KeyPair bKp2 = kpGen.generateKeyPair(); + + keyAgreement.init(aKp1.getPrivate(), new DHUParameterSpec(aKp2, bKp2.getPublic(), Hex.decode("beeffeed"))); + + keyAgreement.doPhase(bKp1.getPublic(), true); + + byte[] sec1 = keyAgreement.generateSecret(); + + keyAgreement.init(bKp1.getPrivate(), new DHUParameterSpec(aKp2, bKp2.getPublic(), Hex.decode("beeffeed"))); + + keyAgreement.doPhase(aKp1.getPublic(), true); + + byte[] sec2 = keyAgreement.generateSecret(); + + isTrue(areEqual(sec1, sec2)); + + keyAgreement.init(bKp1.getPrivate(), new DHUParameterSpec(aKp2, bKp2.getPublic(), Hex.decode("feed"))); + + keyAgreement.doPhase(aKp1.getPublic(), true); + + byte[] sec3 = keyAgreement.generateSecret(); + + isTrue(!areEqual(sec1, sec3)); + } + + private void signatureTest(String algorithm) + throws Exception + { + byte[] msg = Strings.toByteArray("Hello, world!"); + Signature signature = Signature.getInstance(algorithm, "BC"); + + KeyPairGenerator kpGen = KeyPairGenerator.getInstance(algorithm, "BC"); + + KeyPair kp = kpGen.generateKeyPair(); + + signature.initSign(kp.getPrivate()); + + signature.update(msg); + + byte[] sig = signature.sign(); + + signature.initVerify(kp.getPublic()); + + signature.update(msg); + + isTrue(signature.verify(sig)); + + // try with random - should be ignored + + signature.initSign(kp.getPrivate(), new SecureRandom()); + + signature.update(msg); + + sig = signature.sign(); + + signature.initVerify(kp.getPublic()); + + signature.update(msg); + + isTrue(signature.verify(sig)); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new EdECTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ElGamalTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ElGamalTest.java new file mode 100644 index 000000000..8e217d27f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ElGamalTest.java @@ -0,0 +1,534 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.math.BigInteger; +import java.security.AlgorithmParameterGenerator; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashSet; + +import javax.crypto.Cipher; +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHParameterSpec; + +import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import com.fr.third.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ElGamalTest + extends SimpleTest +{ + private BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + private BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + private BigInteger g768 = new BigInteger("7c240073c1316c621df461b71ebb0cdcc90a6e5527e5e126633d131f87461c4dc4afc60c2cb0f053b6758871489a69613e2a8b4c8acde23954c08c81cbd36132cfd64d69e4ed9f8e51ed6e516297206672d5c0a69135df0a5dcf010d289a9ca1", 16); + private BigInteger p768 = new BigInteger("8c9dd223debed1b80103b8b309715be009d48860ed5ae9b9d5d8159508efd802e3ad4501a7f7e1cfec78844489148cd72da24b21eddd01aa624291c48393e277cfc529e37075eccef957f3616f962d15b44aeab4039d01b817fde9eaa12fd73f", 16); + + private BigInteger g1024 = new BigInteger("1db17639cdf96bc4eabba19454f0b7e5bd4e14862889a725c96eb61048dcd676ceb303d586e30f060dbafd8a571a39c4d823982117da5cc4e0f89c77388b7a08896362429b94a18a327604eb7ff227bffbc83459ade299e57b5f77b50fb045250934938efa145511166e3197373e1b5b1e52de713eb49792bedde722c6717abf", 16); + private BigInteger p1024 = new BigInteger("a00e283b3c624e5b2b4d9fbc2653b5185d99499b00fd1bf244c6f0bb817b4d1c451b2958d62a0f8a38caef059fb5ecd25d75ed9af403f5b5bdab97a642902f824e3c13789fed95fa106ddfe0ff4a707c85e2eb77d49e68f2808bcea18ce128b178cd287c6bc00efa9a1ad2a673fe0dceace53166f75b81d6709d5f8af7c66bb7", 16); + + public String getName() + { + return "ElGamal"; + } + + private void testGP( + int size, + int privateValueSize, + BigInteger g, + BigInteger p) + throws Exception + { + DHParameterSpec elParams = new DHParameterSpec(p, g, privateValueSize); + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal", "BC"); + byte[] in = "This is a test".getBytes(); + + keyGen.initialize(elParams); + + KeyPair keyPair = keyGen.generateKeyPair(); + SecureRandom rand = new SecureRandom(); + + checkKeySize(privateValueSize, keyPair); + + Cipher cipher = Cipher.getInstance("ElGamal", "BC"); + + cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); + + if (cipher.getOutputSize(in.length) != (size / 8) * 2) + { + fail("getOutputSize wrong on encryption"); + } + + byte[] out = cipher.doFinal(in); + + cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + + if (cipher.getOutputSize(out.length) != (size / 8) - 1) + { + fail("getOutputSize wrong on decryption"); + } + + // + // No Padding - maximum length + // + byte[] modBytes = ((DHPublicKey)keyPair.getPublic()).getParams().getP().toByteArray(); + byte[] maxInput = new byte[modBytes.length - 1]; + + maxInput[0] |= 0x7f; + + cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); + + out = cipher.doFinal(maxInput); + + cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + + out = cipher.doFinal(out); + + if (!areEqual(out, maxInput)) + { + fail("NoPadding test failed on decrypt expected " + new String(Hex.encode(maxInput)) + " got " + new String(Hex.encode(out))); + } + + // + // encrypt/decrypt + // + + Cipher c1 = Cipher.getInstance("ElGamal", "BC"); + Cipher c2 = Cipher.getInstance("ElGamal", "BC"); + + c1.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); + + byte[] out1 = c1.doFinal(in); + + c2.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + + byte[] out2 = c2.doFinal(out1); + + if (!areEqual(in, out2)) + { + fail(size + " encrypt test failed"); + } + + // + // encrypt/decrypt with update + // + int outLen = c1.update(in, 0, 2, out1, 0); + + outLen += c1.doFinal(in, 2, in.length - 2, out1, outLen); + + out2 = new byte[c2.getOutputSize(out1.length)]; + + outLen = c2.update(out1, 0, 2, out2, 0); + + outLen += c2.doFinal(out1, 2, out1.length - 2, out2, outLen); + + if (!areEqual(in, Arrays.copyOfRange(out2, 0, outLen))) + { + fail(size + " encrypt with update test failed"); + } + + // + // public key encoding test + // + byte[] pubEnc = keyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance("ElGamal", "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); + DHParameterSpec spec = pubKey.getParams(); + + if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) + { + fail(size + " bit public key encoding/decoding test failed on parameters"); + } + + if (!((DHPublicKey)keyPair.getPublic()).getY().equals(pubKey.getY())) + { + fail(size + " bit public key encoding/decoding test failed on y value"); + } + + // + // public key serialisation test + // + pubKey = (DHPublicKey)serializeDeserialize(keyPair.getPublic()); + spec = pubKey.getParams(); + + if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) + { + fail(size + " bit public key serialisation test failed on parameters"); + } + + if (!((DHPublicKey)keyPair.getPublic()).getY().equals(pubKey.getY())) + { + fail(size + " bit public key serialisation test failed on y value"); + } + + if (!keyPair.getPublic().equals(pubKey)) + { + fail("equals test failed"); + } + + if (keyPair.getPublic().hashCode() != pubKey.hashCode()) + { + fail("hashCode test failed"); + } + + // + // private key encoding test + // + byte[] privEnc = keyPair.getPrivate().getEncoded(); + PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); + DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); + + spec = privKey.getParams(); + + if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) + { + fail(size + " bit private key encoding/decoding test failed on parameters"); + } + + if (!((DHPrivateKey)keyPair.getPrivate()).getX().equals(privKey.getX())) + { + fail(size + " bit private key encoding/decoding test failed on y value"); + } + + // + // private key serialisation test + // + privKey = (DHPrivateKey)serializeDeserialize(keyPair.getPrivate()); + spec = privKey.getParams(); + + if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) + { + fail(size + " bit private key serialisation test failed on parameters"); + } + + if (!((DHPrivateKey)keyPair.getPrivate()).getX().equals(privKey.getX())) + { + fail(size + " bit private key serialisation test failed on y value"); + } + + if (!keyPair.getPrivate().equals(privKey)) + { + fail("equals test failed"); + } + + if (keyPair.getPrivate().hashCode() != privKey.hashCode()) + { + fail("hashCode test failed"); + } + + if (!(privKey instanceof PKCS12BagAttributeCarrier)) + { + fail("private key not implementing PKCS12 attribute carrier"); + } + } + + private Object serializeDeserialize(Object o) + throws Exception + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(o); + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + return oIn.readObject(); + } + + private void checkKeySize(int privateValueSize, KeyPair aKeyPair) + { + if (privateValueSize != 0) + { + DHPrivateKey key = (DHPrivateKey)aKeyPair.getPrivate(); + + if (key.getX().bitLength() != privateValueSize) + { + fail("limited key check failed for key size " + privateValueSize); + } + } + } + + private void testRandom( + int size) + throws Exception + { + AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("ElGamal", "BC"); + a.init(size, new SecureRandom()); + AlgorithmParameters params = a.generateParameters(); + + byte[] encodeParams = params.getEncoded(); + + AlgorithmParameters a2 = AlgorithmParameters.getInstance("ElGamal", "BC"); + a2.init(encodeParams); + + // a and a2 should be equivalent! + byte[] encodeParams_2 = a2.getEncoded(); + + if (!areEqual(encodeParams, encodeParams_2)) + { + fail(this.getName() + ": encode/decode parameters failed"); + } + + DHParameterSpec elP = (DHParameterSpec)params.getParameterSpec(DHParameterSpec.class); + + testGP(size, 0, elP.getG(), elP.getP()); + } + + private void testDefault( + int privateValueSize, + BigInteger g, + BigInteger p) + throws Exception + { + DHParameterSpec elParams = new DHParameterSpec(p, g, privateValueSize); + int size = p.bitLength(); + + new BouncyCastleProvider().setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, elParams); + + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("ElGamal", "BC"); + byte[] in = "This is a test".getBytes(); + + keyGen.initialize(p.bitLength()); + + KeyPair keyPair = keyGen.generateKeyPair(); + + new BouncyCastleProvider().setParameter(ConfigurableProvider.DH_DEFAULT_PARAMS, elParams); + + SecureRandom rand = new SecureRandom(); + + checkKeySize(privateValueSize, keyPair); + + Cipher cipher = Cipher.getInstance("ElGamal", "BC"); + + cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); + + if (cipher.getOutputSize(in.length) != (size / 8) * 2) + { + fail("getOutputSize wrong on encryption"); + } + + byte[] out = cipher.doFinal(in); + + cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + + if (cipher.getOutputSize(out.length) != (size / 8) - 1) + { + fail("getOutputSize wrong on decryption"); + } + + // + // No Padding - maximum length + // + byte[] modBytes = ((DHPublicKey)keyPair.getPublic()).getParams().getP().toByteArray(); + byte[] maxInput = new byte[modBytes.length - 1]; + + maxInput[0] |= 0x7f; + + cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); + + out = cipher.doFinal(maxInput); + + cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + + out = cipher.doFinal(out); + + if (!areEqual(out, maxInput)) + { + fail("NoPadding test failed on decrypt expected " + new String(Hex.encode(maxInput)) + " got " + new String(Hex.encode(out))); + } + + // + // encrypt/decrypt + // + + Cipher c1 = Cipher.getInstance("ElGamal", "BC"); + Cipher c2 = Cipher.getInstance("ElGamal", "BC"); + + c1.init(Cipher.ENCRYPT_MODE, keyPair.getPublic(), rand); + + byte[] out1 = c1.doFinal(in); + + c2.init(Cipher.DECRYPT_MODE, keyPair.getPrivate()); + + byte[] out2 = c2.doFinal(out1); + + if (!areEqual(in, out2)) + { + fail(size + " encrypt test failed"); + } + + // + // encrypt/decrypt with update + // + int outLen = c1.update(in, 0, 2, out1, 0); + + outLen += c1.doFinal(in, 2, in.length - 2, out1, outLen); + + out2 = new byte[c2.getOutputSize(out1.length)]; + + outLen = c2.update(out1, 0, 2, out2, 0); + + outLen += c2.doFinal(out1, 2, out1.length - 2, out2, outLen); + + if (!areEqual(in, Arrays.copyOfRange(out2, 0, outLen))) + { + fail(size + " encrypt with update test failed"); + } + + // + // public key encoding test + // + byte[] pubEnc = keyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance("ElGamal", "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + DHPublicKey pubKey = (DHPublicKey)keyFac.generatePublic(pubX509); + DHParameterSpec spec = pubKey.getParams(); + + if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) + { + fail(size + " bit public key encoding/decoding test failed on parameters"); + } + + if (!((DHPublicKey)keyPair.getPublic()).getY().equals(pubKey.getY())) + { + fail(size + " bit public key encoding/decoding test failed on y value"); + } + + // + // public key serialisation test + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(keyPair.getPublic()); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + ObjectInputStream oIn = new ObjectInputStream(bIn); + + pubKey = (DHPublicKey)oIn.readObject(); + spec = pubKey.getParams(); + + if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) + { + fail(size + " bit public key serialisation test failed on parameters"); + } + + if (!((DHPublicKey)keyPair.getPublic()).getY().equals(pubKey.getY())) + { + fail(size + " bit public key serialisation test failed on y value"); + } + + // + // private key encoding test + // + byte[] privEnc = keyPair.getPrivate().getEncoded(); + PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); + DHPrivateKey privKey = (DHPrivateKey)keyFac.generatePrivate(privPKCS8); + + spec = privKey.getParams(); + + if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) + { + fail(size + " bit private key encoding/decoding test failed on parameters"); + } + + if (!((DHPrivateKey)keyPair.getPrivate()).getX().equals(privKey.getX())) + { + fail(size + " bit private key encoding/decoding test failed on y value"); + } + + // + // private key serialisation test + // + bOut = new ByteArrayOutputStream(); + oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(keyPair.getPrivate()); + + bIn = new ByteArrayInputStream(bOut.toByteArray()); + oIn = new ObjectInputStream(bIn); + + privKey = (DHPrivateKey)oIn.readObject(); + spec = privKey.getParams(); + + if (!spec.getG().equals(elParams.getG()) || !spec.getP().equals(elParams.getP())) + { + fail(size + " bit private key serialisation test failed on parameters"); + } + + if (!((DHPrivateKey)keyPair.getPrivate()).getX().equals(privKey.getX())) + { + fail(size + " bit private key serialisation test failed on y value"); + } + } + + public void testGetExceptionsPKCS1() + throws Exception + { + SecureRandom rand = new SecureRandom(); + KeyPairGenerator keygen = KeyPairGenerator.getInstance("ELGAMAL", "BC"); + keygen.initialize(new DHParameterSpec(p1024, g1024), rand); + KeyPair keypair = keygen.genKeyPair(); + + Cipher c = Cipher.getInstance("ELGAMAL/ECB/PKCS1Padding", "BC"); + byte[] ciphertext = new byte[1024 / 8]; + HashSet exceptions = new HashSet(); + final int SAMPLES = 1000; + for (int i = 0; i < SAMPLES; i++) + { + rand.nextBytes(ciphertext); + ciphertext[0] = (byte)0; + try + { + c.init(Cipher.DECRYPT_MODE, keypair.getPrivate()); + c.doFinal(ciphertext); + } + catch (Exception ex) + { + String message = ex.toString(); + exceptions.add(message); + } + } + isTrue("exception count wrong", 1 == exceptions.size()); + } + + public void performTest() + throws Exception + { + testDefault(64, g512, p512); + + testGP(512, 0, g512, p512); + testGP(768, 0, g768, p768); + testGP(1024, 0, g1024, p1024); + + testGP(512, 64, g512, p512); + testGP(768, 128, g768, p768); + testGP(1024, 256, g1024, p1024); + + testRandom(256); + testGetExceptionsPKCS1(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new ElGamalTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/EncryptedPrivateKeyInfoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/EncryptedPrivateKeyInfoTest.java new file mode 100644 index 000000000..cc67ccf5c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/EncryptedPrivateKeyInfoTest.java @@ -0,0 +1,199 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.AlgorithmParameters; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.spec.PKCS8EncodedKeySpec; + +import javax.crypto.Cipher; +import javax.crypto.EncryptedPrivateKeyInfo; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; + +import com.fr.third.org.bouncycastle.jcajce.PKCS12KeyWithParameters; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class EncryptedPrivateKeyInfoTest + extends SimpleTest +{ + String alg = "1.2.840.113549.1.12.1.3"; // 3 key triple DES with SHA-1 + + public void performTest() + throws Exception + { + doTestWithExplicitIV(); + + KeyPairGenerator fact = KeyPairGenerator.getInstance("RSA", "BC"); + fact.initialize(512, new SecureRandom()); + + KeyPair keyPair = fact.generateKeyPair(); + + PrivateKey priKey = keyPair.getPrivate(); + PublicKey pubKey = keyPair.getPublic(); + + // + // set up the parameters + // + byte[] salt = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int iterationCount = 100; + PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); + + AlgorithmParameters params = AlgorithmParameters.getInstance(alg, "BC"); + + params.init(defParams); + + // + // set up the key + // + char[] password1 = { 'h', 'e', 'l', 'l', 'o' }; + + PBEKeySpec pbeSpec = new PBEKeySpec(password1); + SecretKeyFactory keyFact = SecretKeyFactory.getInstance(alg, "BC"); + Cipher cipher = Cipher.getInstance(alg, "BC"); + + cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), params); + + byte[] wrappedKey = cipher.wrap(priKey); + + // + // create encrypted object + // + + EncryptedPrivateKeyInfo pInfo = new EncryptedPrivateKeyInfo(params, wrappedKey); + + // + // decryption step + // + char[] password2 = { 'h', 'e', 'l', 'l', 'o' }; + + pbeSpec = new PBEKeySpec(password2); + + cipher = Cipher.getInstance(pInfo.getAlgName(), "BC"); + + cipher.init(Cipher.DECRYPT_MODE, keyFact.generateSecret(pbeSpec), pInfo.getAlgParameters()); + + PKCS8EncodedKeySpec keySpec = pInfo.getKeySpec(cipher); + + if (!MessageDigest.isEqual(priKey.getEncoded(), keySpec.getEncoded())) + { + fail("Private key does not match"); + } + + // + // using Cipher parameters test + // + pbeSpec = new PBEKeySpec(password1); + keyFact = SecretKeyFactory.getInstance(alg, "BC"); + cipher = Cipher.getInstance(alg, "BC"); + + cipher.init(Cipher.WRAP_MODE, keyFact.generateSecret(pbeSpec), params); + + wrappedKey = cipher.wrap(priKey); + + // + // create encrypted object + // + + pInfo = new EncryptedPrivateKeyInfo(cipher.getParameters(), wrappedKey); + + // + // decryption step + // + pbeSpec = new PBEKeySpec(password2); + + cipher = Cipher.getInstance(pInfo.getAlgName(), "BC"); + + cipher.init(Cipher.DECRYPT_MODE, keyFact.generateSecret(pbeSpec), pInfo.getAlgParameters()); + + keySpec = pInfo.getKeySpec(cipher); + + if (!MessageDigest.isEqual(priKey.getEncoded(), keySpec.getEncoded())) + { + fail("Private key does not match"); + } + } + + public void doTestWithExplicitIV() + throws Exception + { + KeyPairGenerator fact = KeyPairGenerator.getInstance("RSA", "BC"); + fact.initialize(512, new SecureRandom()); + + KeyPair keyPair = fact.generateKeyPair(); + + PrivateKey priKey = keyPair.getPrivate(); + PublicKey pubKey = keyPair.getPublic(); + + // + // set up the parameters + // + byte[] salt = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int iterationCount = 100; + PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); + + AlgorithmParameters params = AlgorithmParameters.getInstance(alg, "BC"); + + params.init(defParams); + + // + // set up the key + // + char[] password1 = { 'h', 'e', 'l', 'l', 'o' }; + + Cipher cipher = Cipher.getInstance(alg, "BC"); + + byte[] iv = { 1, 2, 3, 4, 5, 6, 7, 8 }; + + cipher.init(Cipher.WRAP_MODE, new PKCS12KeyWithParameters(password1, salt, iterationCount), new IvParameterSpec(iv)); + + byte[] wrappedKey = cipher.wrap(priKey); + + // + // create encrypted object + // + + EncryptedPrivateKeyInfo pInfo = new EncryptedPrivateKeyInfo(params, wrappedKey); + + // + // decryption step + // + char[] password2 = { 'h', 'e', 'l', 'l', 'o' }; + + cipher = Cipher.getInstance(pInfo.getAlgName(), "BC"); + + cipher.init(Cipher.DECRYPT_MODE, new PKCS12KeyWithParameters(password2, salt, iterationCount), new IvParameterSpec(iv)); + + PKCS8EncodedKeySpec keySpec = pInfo.getKeySpec(cipher); + + if (!MessageDigest.isEqual(priKey.getEncoded(), keySpec.getEncoded())) + { + fail("Private key does not match"); + } + } + + public String getName() + { + return "EncryptedPrivateKeyInfoTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + Test test = new EncryptedPrivateKeyInfoTest(); + TestResult result = test.perform(); + + System.out.println(result.toString()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/FIPSDESTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/FIPSDESTest.java new file mode 100644 index 000000000..7e6daa081 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/FIPSDESTest.java @@ -0,0 +1,229 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.Key; +import java.security.KeyException; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + * basic FIPS test class for a block cipher, just to make sure ECB/CBC/OFB/CFB are behaving + * correctly. Tests from FIPS 81. + */ +public class FIPSDESTest + implements Test +{ + static String[] fips1Tests = + { + "DES/ECB/NoPadding", + "3fa40e8a984d48156a271787ab8883f9893d51ec4b563b53", + "DES/CBC/NoPadding", + "e5c7cdde872bf27c43e934008c389c0f683788499a7c05f6", + "DES/CFB/NoPadding", + "f3096249c7f46e51a69e839b1a92f78403467133898ea622" + }; + + static String[] fips2Tests = + { + "DES/CFB8/NoPadding", + "f31fda07011462ee187f", + "DES/OFB8/NoPadding", + "f34a2850c9c64985d684" + }; + + static byte[] input1 = Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20"); + static byte[] input2 = Hex.decode("4e6f7720697320746865"); + + public String getName() + { + return "FIPSDESTest"; + } + + private boolean equalArray( + byte[] a, + byte[] b) + { + if (a.length != b.length) + { + return false; + } + + for (int i = 0; i != a.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + public TestResult test( + String algorithm, + byte[] input, + byte[] output) + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + IvParameterSpec spec = new IvParameterSpec(Hex.decode("1234567890abcdef")); + + try + { + String baseAlgorithm; + + key = new SecretKeySpec(Hex.decode("0123456789abcdef"), "DES"); + + in = Cipher.getInstance(algorithm, "BC"); + out = Cipher.getInstance(algorithm, "BC"); + + if (algorithm.startsWith("DES/ECB")) + { + out.init(Cipher.ENCRYPT_MODE, key); + } + else + { + out.init(Cipher.ENCRYPT_MODE, key, spec); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": " + algorithm + " failed initialisation - " + e.toString(), e); + } + + try + { + if (algorithm.startsWith("DES/ECB")) + { + in.init(Cipher.DECRYPT_MODE, key); + } + else + { + in.init(Cipher.DECRYPT_MODE, key, spec); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": " + algorithm + " failed initialisation - " + e.toString(), e); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + return new SimpleTestResult(false, getName() + ": " + algorithm + " failed encryption - " + e.toString()); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!equalArray(bytes, output)) + { + return new SimpleTestResult(false, getName() + ": " + algorithm + " failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": " + algorithm + " failed encryption - " + e.toString()); + } + + if (!equalArray(bytes, input)) + { + return new SimpleTestResult(false, getName() + ": " + algorithm + " failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + + return new SimpleTestResult(true, getName() + ": " + algorithm + " Okay"); + } + + public TestResult perform() + { + for (int i = 0; i != fips1Tests.length; i += 2) + { + TestResult result; + + result = test(fips1Tests[i], input1, Hex.decode(fips1Tests[i + 1])); + if (!result.isSuccessful()) + { + return result; + } + } + + for (int i = 0; i != fips2Tests.length; i += 2) + { + TestResult result; + + result = test(fips2Tests[i], input2, Hex.decode(fips2Tests[i + 1])); + if (!result.isSuccessful()) + { + return result; + } + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + + public static void main( + String[] args) + throws KeyException, InvalidAlgorithmParameterException + { + Security.addProvider(new BouncyCastleProvider()); + + Test test = new FIPSDESTest(); + TestResult result = test.perform(); + + System.out.println(result.toString()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GMacTest.java new file mode 100644 index 000000000..50298a3da --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GMacTest.java @@ -0,0 +1,145 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.NoSuchAlgorithmException; +import java.security.Security; +import java.util.ArrayList; +import java.util.List; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +public class GMacTest + extends SimpleTest +{ + public String getName() + { + return "GMac"; + } + + public void performTest() + throws Exception + { + checkRegistrations(); + } + + private void checkRegistrations() + throws Exception + { + List missingMacs = new ArrayList(); + List missingKeyGens = new ArrayList(); + + String[] ciphers = new String[] { "AES", "NOEKEON", "Twofish", "CAST6", "SEED", "Tnepres", "Serpent", "SM4", "RC6", "CAMELLIA" }; + String[] macs = new String[] + { + "a52308801b32d4770c701ace9b826f12", + "cf11dacaf6024a78dba76b256e23caab", + "13db7c428e5a7128149b5ec782d07fac", + "d13a33e78e48b274bf7d64bf9aecdb82", + "d05d550054735c6e7e01b6981fc14b4e", + "4a34dfe4f5410afd7c40b1e110377a73", + "80c3cc898899e41fd4e21c6c1261fedb", + "d394f3d12bec3cf6c5302265ecab9af1", + "d9f597c96b41f641da6c83d4760f543b", + "371ad8cc920c6bda2a26d8f237bd446b" + }; + + for (int i = 0; i < ciphers.length; i++) + { + String cipherName = ciphers[i]; + Cipher cipher; + try + { + cipher = Cipher.getInstance(cipherName, "BC"); + } + catch (Exception e) + { + System.err.println(cipherName + ": " + e.getMessage()); + continue; + } + int blocksize; + try + { + blocksize = cipher.getBlockSize(); + } + catch (Exception e) + { + System.err.println(cipherName + ": " + e.getMessage()); + continue; + } + // GCM is defined over 128 bit block ciphers + if (blocksize == 16) + { + String macName = cipherName + "-GMAC"; + String macNameAlt = cipherName + "GMAC"; + + // Check we have a GMAC registered for each name + checkMac(macName, missingMacs, missingKeyGens, macs[i]); + checkMac(macNameAlt, missingMacs, missingKeyGens, macs[i]); + } + } + if (missingMacs.size() != 0) + { + fail("Did not find GMAC registrations for the following ciphers: " + missingMacs); + } + if (missingKeyGens.size() != 0) + { + fail("Did not find GMAC KeyGenerator registrations for the following macs: " + missingKeyGens); + } + } + + private void checkMac(String name, List missingMacs, List missingKeyGens, String macOutput) + { + try + { + Mac mac = Mac.getInstance(name); + + mac.init(new SecretKeySpec(new byte[mac.getMacLength()], mac.getAlgorithm()), new IvParameterSpec( + new byte[16])); + mac.update(new byte[128]); + byte[] bytes = mac.doFinal(); + + if (!Arrays.areEqual(bytes, Hex.decode(macOutput))) + { + fail("wrong mac value computed for " + name + " " + Hex.toHexString(bytes)); + } + + try + { + KeyGenerator kg = KeyGenerator.getInstance(name); + kg.generateKey(); + } + catch (NoSuchAlgorithmException e) + { + missingKeyGens.add(name); + } + } + catch (NoSuchAlgorithmException e) + { + missingMacs.add(name); + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail("Unexpected error", e); + } + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new GMacTest()); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST28147Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST28147Test.java new file mode 100644 index 000000000..55b6e6ad5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST28147Test.java @@ -0,0 +1,260 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.security.Key; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * basic test class for the GOST28147 cipher + */ +public class GOST28147Test + extends SimpleTest +{ + static String[] cipherTests = + { + "256", + "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + "4e6f77206973207468652074696d6520666f7220616c6c20", + "281630d0d5770030068c252d841e84149ccc1912052dbc02", + + "256", + "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", + "4e6f77206973207468652074696d65208a920c6ed1a804f5", + "88e543dfc04dc4f764fa7b624741cec07de49b007bf36065" + }; + + public String getName() + { + return "GOST28147"; + } + + public void testECB( + int strength, + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "GOST28147"); + + in = Cipher.getInstance("GOST28147/ECB/NoPadding", "BC"); + out = Cipher.getInstance("GOST28147/ECB/NoPadding", "BC"); + out.init(Cipher.ENCRYPT_MODE, key); + in.init(Cipher.DECRYPT_MODE, key); + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("GOST28147 failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + + if (!areEqual(bytes, input)) + { + fail("GOST28147 failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + public void testCFB( + int strength, + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "GOST28147"); + + in = Cipher.getInstance("GOST28147/CFB8/NoPadding", "BC"); + out = Cipher.getInstance("GOST28147/CFB8/NoPadding", "BC"); + byte[] iv = {1,2,3,4,5,6,7,8}; + + out.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); + in.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("GOST28147 failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + + if (!areEqual(bytes, input)) + { + fail("GOST28147 failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + private void oidTest() + { + String[] oids = { + CryptoProObjectIdentifiers.gostR28147_gcfb.getId(), + }; + + String[] names = { + "GOST28147/GCFB/NoPadding" + }; + + try + { + + byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + IvParameterSpec ivSpec = new IvParameterSpec(new byte[8]); + + for (int i = 0; i != oids.length; i++) + { + Cipher c1 = Cipher.getInstance(oids[i], "BC"); + Cipher c2 = Cipher.getInstance(names[i], "BC"); + KeyGenerator kg = KeyGenerator.getInstance(oids[i], "BC"); + + SecretKey k = kg.generateKey(); + + c1.init(Cipher.ENCRYPT_MODE, k, ivSpec); + c2.init(Cipher.DECRYPT_MODE, k, ivSpec); + + byte[] result = c2.doFinal(c1.doFinal(data)); + + if (!areEqual(data, result)) + { + fail("failed OID test"); + } + } + } + catch (Exception ex) + { + fail("failed exception " + ex.toString(), ex); + } + } + + public void performTest() + throws Exception + { + for (int i = 0; i != cipherTests.length; i += 8) + { + testECB(Integer.parseInt(cipherTests[i]), + Hex.decode(cipherTests[i + 1]), + Hex.decode(cipherTests[i + 2]), + Hex.decode(cipherTests[i + 3])); + + testCFB(Integer.parseInt(cipherTests[i + 4]), + Hex.decode(cipherTests[i + 4 + 1]), + Hex.decode(cipherTests[i + 4 + 2]), + Hex.decode(cipherTests[i + 4 + 3])); + + oidTest(); + } + + Mac mac = Mac.getInstance("GOST28147MAC", "BC"); + + mac.init(new SecretKeySpec(Hex.decode("0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"), "GOST28147")); + + if (!Arrays.areEqual(Hex.decode("1b69996e"), mac.doFinal(Hex.decode("4e6f77206973207468652074696d6520666f7220616c6c20")))) + { + fail("mac test failed."); + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new GOST28147Test()); + } + } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST3410KeyPairTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST3410KeyPairTest.java new file mode 100644 index 000000000..7115068ef --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST3410KeyPairTest.java @@ -0,0 +1,179 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.Signature; +import java.security.spec.ECGenParameterSpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class GOST3410KeyPairTest + extends SimpleTest +{ + private void gost2012MismatchTest() + throws Exception + { + KeyPairGenerator keyPair = KeyPairGenerator.getInstance( + "ECGOST3410-2012", "BC"); + + keyPair.initialize(new ECGenParameterSpec("Tc26-Gost-3410-12-512-paramSetA")); + + KeyPair kp = keyPair.generateKeyPair(); + + testWrong256(kp); + + keyPair = KeyPairGenerator.getInstance( + "ECGOST3410-2012", "BC"); + + keyPair.initialize(new ECGenParameterSpec("Tc26-Gost-3410-12-512-paramSetB")); + + kp = keyPair.generateKeyPair(); + + testWrong256(kp); + + keyPair = KeyPairGenerator.getInstance( + "ECGOST3410-2012", "BC"); + + keyPair.initialize(new ECGenParameterSpec("Tc26-Gost-3410-12-512-paramSetC")); + + kp = keyPair.generateKeyPair(); + + testWrong256(kp); + + keyPair = KeyPairGenerator.getInstance( + "ECGOST3410-2012", "BC"); + + keyPair.initialize(new ECGenParameterSpec("Tc26-Gost-3410-12-256-paramSetA")); + + kp = keyPair.generateKeyPair(); + + testWrong512(kp); + } + + private void testWrong512(KeyPair kp) + throws NoSuchAlgorithmException, NoSuchProviderException + { + Signature sig; + sig = Signature.getInstance("ECGOST3410-2012-512", "BC"); + + try + { + sig.initSign(kp.getPrivate()); + + fail("no exception"); + } + catch (InvalidKeyException e) + { + isEquals("key too weak for ECGOST-2012-512", e.getMessage()); + } + + try + { + sig.initVerify(kp.getPublic()); + fail("no exception"); + } + catch (InvalidKeyException e) + { + isEquals("key too weak for ECGOST-2012-512", e.getMessage()); + } + } + + private void testWrong256(KeyPair kp) + throws NoSuchAlgorithmException, NoSuchProviderException + { + Signature sig = Signature.getInstance("ECGOST3410-2012-256", "BC"); + + try + { + sig.initSign(kp.getPrivate()); + fail("no exception"); + } + catch (InvalidKeyException e) + { + isEquals("key out of range for ECGOST-2012-256", e.getMessage()); + } + + try + { + sig.initVerify(kp.getPublic()); + fail("no exception"); + } + catch (InvalidKeyException e) + { + isEquals("key out of range for ECGOST-2012-256", e.getMessage()); + } + } + + private BigInteger[] decode( + byte[] encoding) + { + byte[] r = new byte[32]; + byte[] s = new byte[32]; + + System.arraycopy(encoding, 0, s, 0, 32); + + System.arraycopy(encoding, 32, r, 0, 32); + + BigInteger[] sig = new BigInteger[2]; + + sig[0] = new BigInteger(1, r); + sig[1] = new BigInteger(1, s); + + return sig; + } + + private Object serializeDeserialize(Object o) + throws Exception + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(o); + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + return oIn.readObject(); + } + + public String getName() + { + return "GOST3410/ECGOST3410/ECGOST3410 2012"; + } + + public void performTest() + throws Exception + { + gost2012MismatchTest(); + } + + protected byte[] toByteArray(String input) + { + byte[] bytes = new byte[input.length()]; + + for (int i = 0; i != bytes.length; i++) + { + bytes[i] = (byte)input.charAt(i); + } + + return bytes; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new GOST3410KeyPairTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST3410Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST3410Test.java new file mode 100644 index 000000000..73752bcc6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST3410Test.java @@ -0,0 +1,923 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Date; + +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.cryptopro.GOST3410PublicKeyAlgParameters; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.crypto.params.ECPublicKeyParameters; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.crypto.signers.ECGOST3410_2012Signer; +import com.fr.third.org.bouncycastle.jcajce.provider.asymmetric.util.ECUtil; +import com.fr.third.org.bouncycastle.jce.X509Principal; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPrivateKey; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPublicKey; +import com.fr.third.org.bouncycastle.jce.interfaces.GOST3410PrivateKey; +import com.fr.third.org.bouncycastle.jce.interfaces.GOST3410PublicKey; +import com.fr.third.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec; +import com.fr.third.org.bouncycastle.jce.spec.GOST3410ParameterSpec; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; +import com.fr.third.org.bouncycastle.x509.X509V3CertificateGenerator; + +//import java.security.spec.ECGenParameterSpec; + +public class GOST3410Test + extends SimpleTest +{ + private static byte[] ecgostData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + private static byte[] ecgost2012_256Key = Base64.decode("MGgwIQYIKoUDBwEBAQEwFQYJKoUDBwECAQEBBggqhQMHAQECAgNDAARAuSmiubNU4NMTvYsWb59uIa0dvNvikSyafTFTvHYhfoEeyVj5qeCoED1AjraW3Q44EZdNZaS5exAUIHuK5Bhd/Q=="); + private static byte[] ecgost2012_256Sig = Base64.decode("CNUdC6ny8sryzNcwGy7MG3DUbcU+3RgJNPWb3WVtAwUcbaFKPgL0TERfDM4Vsurwx0POt+PZCTxjaiaoY0UxkQ=="); + + private static byte[] ecgost2012_512Key = Base64.decode("MIGqMCEGCCqFAwcBAQECMBUGCSqFAwcBAgECAQYIKoUDBwEBAgMDgYQABIGAhiwvUj3M58X6KQfFmqvQhka/JxigdS6hy6rqoYZec0pAwPKFNJ+AUl70zvNR/GDLB2DNBGryofKFXJk1l8aZCHM6cpuSzJbD7y728U/rclJ4GVDAbb4ktq4UmiYaJ7JZcc/CSL0qoj7w69sY7rWZm/T2o+hb1cM1jVq5/u5zYqo="); + private static byte[] ecgost2012_512Sig = Base64.decode("uX4splTTDpH6T04tnElszTSmj+aTAl2LV7JxP+1xRRGoQ0ET2+QniOW+6WIOZzCZxEo75fZfx1jRHa7Eo99KfQNzHqmiN7G1Ch9pHQ7eMMwaLVurmWEFpZqBH4k5XfHTSPIa8mUmCn6808xMNy1VfwppbaJwRjtyW0h/CqeDTr8="); + + private void ecGOST3410Test() + throws Exception + { + + BigInteger r = new BigInteger("29700980915817952874371204983938256990422752107994319651632687982059210933395"); + BigInteger s = new BigInteger("46959264877825372965922731380059061821746083849389763294914877353246631700866"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395")); + + SecureRandom k = new TestRandomBigInteger(kData); + + BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); + BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619"); + + ECCurve curve = new ECCurve.Fp( + mod_p, + new BigInteger("7"), // a + new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b + mod_q, ECConstants.ONE); + + ECParameterSpec spec = new ECParameterSpec( + curve, + curve.createPoint( + new BigInteger("2"), // x + new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y + mod_q, ECConstants.ONE); + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("55441196065363246126355624130324183196576709222340016572108097750006097525544"), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + curve.createPoint( + new BigInteger("57520216126176808443631405023338071176630104906313632182896741342206604859403"), // x + new BigInteger("17614944419213781543809391949654080031942662045363639260709847859438286763994")), // y + spec); + + Signature sgr = Signature.getInstance("ECGOST3410", "BC"); + KeyFactory f = KeyFactory.getInstance("ECGOST3410", "BC"); + PrivateKey sKey = f.generatePrivate(priKey); + PublicKey vKey = f.generatePublic(pubKey); + + sgr.initSign(sKey, k); + + byte[] message = new byte[]{(byte)'a', (byte)'b', (byte)'c'}; + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail("ECGOST3410 verification failed"); + } + + BigInteger[] sig = decode(sigBytes); + + if (!r.equals(sig[0])) + { + fail( + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail( + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + } + + private void generationTest() + throws Exception + { + Signature s = Signature.getInstance("GOST3410", "BC"); + KeyPairGenerator g = KeyPairGenerator.getInstance("GOST3410", "BC"); + byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + GOST3410ParameterSpec gost3410P = new GOST3410ParameterSpec(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A.getId()); + + g.initialize(gost3410P, new SecureRandom()); + + KeyPair p = g.generateKeyPair(); + + PrivateKey sKey = p.getPrivate(); + PublicKey vKey = p.getPublic(); + + s.initSign(sKey); + + s.update(data); + + byte[] sigBytes = s.sign(); + + s = Signature.getInstance("GOST3410", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("GOST3410 verification failed"); + } + + // + // default initialisation test + // + s = Signature.getInstance("GOST3410", "BC"); + g = KeyPairGenerator.getInstance("GOST3410", "BC"); + + p = g.generateKeyPair(); + + sKey = p.getPrivate(); + vKey = p.getPublic(); + + s.initSign(sKey); + + s.update(data); + + sigBytes = s.sign(); + + s = Signature.getInstance("GOST3410", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("GOST3410 verification failed"); + } + + // + // encoded test + // + KeyFactory f = KeyFactory.getInstance("GOST3410", "BC"); + + X509EncodedKeySpec x509s = new X509EncodedKeySpec(vKey.getEncoded()); + GOST3410PublicKey k1 = (GOST3410PublicKey)f.generatePublic(x509s); + + if (!k1.getY().equals(((GOST3410PublicKey)vKey).getY())) + { + fail("public number not decoded properly"); + } + + if (!k1.getParameters().equals(((GOST3410PublicKey)vKey).getParameters())) + { + fail("public parameters not decoded properly"); + } + + PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(sKey.getEncoded()); + GOST3410PrivateKey k2 = (GOST3410PrivateKey)f.generatePrivate(pkcs8); + + if (!k2.getX().equals(((GOST3410PrivateKey)sKey).getX())) + { + fail("private number not decoded properly"); + } + + if (!k2.getParameters().equals(((GOST3410PrivateKey)sKey).getParameters())) + { + fail("private number not decoded properly"); + } + + k2 = (GOST3410PrivateKey)serializeDeserialize(sKey); + if (!k2.getX().equals(((GOST3410PrivateKey)sKey).getX())) + { + fail("private number not deserialised properly"); + } + + if (!k2.getParameters().equals(((GOST3410PrivateKey)sKey).getParameters())) + { + fail("private number not deserialised properly"); + } + + checkEquals(k2, sKey); + + if (!(k2 instanceof PKCS12BagAttributeCarrier)) + { + fail("private key not implementing PKCS12 attribute carrier"); + } + + k1 = (GOST3410PublicKey)serializeDeserialize(vKey); + + if (!k1.getY().equals(((GOST3410PublicKey)vKey).getY())) + { + fail("public number not deserialised properly"); + } + + if (!k1.getParameters().equals(((GOST3410PublicKey)vKey).getParameters())) + { + fail("public parameters not deserialised properly"); + } + + checkEquals(k1, vKey); + + // + // ECGOST3410 generation test + // + s = Signature.getInstance("ECGOST3410", "BC"); + g = KeyPairGenerator.getInstance("ECGOST3410", "BC"); + +// BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); //p +// +// ECCurve curve = new ECCurve.Fp( +// mod_p, // p +// new BigInteger("7"), // a +// new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414")); // b +// +// ECParameterSpec ecSpec = new ECParameterSpec( +// curve, +// new ECPoint.Fp(curve, +// new ECFieldElement.Fp(mod_p,new BigInteger("2")), // x +// new ECFieldElement.Fp(mod_p,new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280"))), // y +// new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619")); // q + + g.initialize(new ECNamedCurveGenParameterSpec("GostR3410-2001-CryptoPro-A"), new SecureRandom()); + + p = g.generateKeyPair(); + + sKey = p.getPrivate(); + vKey = p.getPublic(); + + s.initSign(sKey); + + s.update(data); + + sigBytes = s.sign(); + + s = Signature.getInstance("ECGOST3410", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("ECGOST3410 verification failed"); + } + + // + // encoded test + // + f = KeyFactory.getInstance("ECGOST3410", "BC"); + + x509s = new X509EncodedKeySpec(vKey.getEncoded()); + ECPublicKey eck1 = (ECPublicKey)f.generatePublic(x509s); + + if (!eck1.getQ().equals(((ECPublicKey)vKey).getQ())) + { + fail("public number not decoded properly"); + } + + if (!eck1.getParameters().equals(((ECPublicKey)vKey).getParameters())) + { + fail("public parameters not decoded properly"); + } + + pkcs8 = new PKCS8EncodedKeySpec(sKey.getEncoded()); + ECPrivateKey eck2 = (ECPrivateKey)f.generatePrivate(pkcs8); + + if (!eck2.getD().equals(((ECPrivateKey)sKey).getD())) + { + fail("private number not decoded properly"); + } + + if (!eck2.getParameters().equals(((ECPrivateKey)sKey).getParameters())) + { + fail("private number not decoded properly"); + } + + eck2 = (ECPrivateKey)serializeDeserialize(sKey); + if (!eck2.getD().equals(((ECPrivateKey)sKey).getD())) + { + fail("private number not decoded properly"); + } + + if (!eck2.getParameters().equals(((ECPrivateKey)sKey).getParameters())) + { + fail("private number not decoded properly"); + } + + checkEquals(eck2, sKey); + + if (!(eck2 instanceof PKCS12BagAttributeCarrier)) + { + fail("private key not implementing PKCS12 attribute carrier"); + } + + eck1 = (ECPublicKey)serializeDeserialize(vKey); + + if (!eck1.getQ().equals(((ECPublicKey)vKey).getQ())) + { + fail("public number not decoded properly"); + } + + if (!eck1.getParameters().equals(((ECPublicKey)vKey).getParameters())) + { + fail("public parameters not decoded properly"); + } + + checkEquals(eck1, vKey); + } + + + private void ecGOST34102012256Test() + throws Exception + { + + BigInteger r = new BigInteger("29700980915817952874371204983938256990422752107994319651632687982059210933395"); + BigInteger s = new BigInteger("574973400270084654178925310019147038455227042649098563933718999175515839552"); + + BigInteger e = new BigInteger("20798893674476452017134061561508270130637142515379653289952617252661468872421"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("53854137677348463731403841147996619241504003434302020712960838528893196233395")); + SecureRandom k = new TestRandomBigInteger(kData); + + BigInteger mod_p = new BigInteger("57896044618658097711785492504343953926634992332820282019728792003956564821041"); + BigInteger mod_q = new BigInteger("57896044618658097711785492504343953927082934583725450622380973592137631069619"); + + ECCurve curve = new ECCurve.Fp( + mod_p, + new BigInteger("7"), // a + new BigInteger("43308876546767276905765904595650931995942111794451039583252968842033849580414"), // b + mod_q, ECConstants.ONE); + + ECParameterSpec spec = new ECParameterSpec( + curve, + curve.createPoint( + new BigInteger("2"), // x + new BigInteger("4018974056539037503335449422937059775635739389905545080690979365213431566280")), // y + mod_q, ECConstants.ONE); + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("55441196065363246126355624130324183196576709222340016572108097750006097525544"), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + curve.createPoint( + new BigInteger("57520216126176808443631405023338071176630104906313632182896741342206604859403"), // x + new BigInteger("17614944419213781543809391949654080031942662045363639260709847859438286763994")), // y + spec); + + KeyFactory f = KeyFactory.getInstance("ECGOST3410-2012", "BC"); + PrivateKey sKey = f.generatePrivate(priKey); + PublicKey vKey = f.generatePublic(pubKey); + + ECGOST3410_2012Signer signer = new ECGOST3410_2012Signer(); + CipherParameters param = ECUtil.generatePrivateKeyParameter(sKey); + + signer.init(true, new ParametersWithRandom(param, k)); + + byte[] rev = e.toByteArray(); + byte[] message = new byte[rev.length]; + for (int i = 0; i != rev.length; i++) + { + message[i] = rev[rev.length - 1 - i]; + } + BigInteger[] sig = signer.generateSignature(message); + + ECPublicKey ecPublicKey = (ECPublicKey)vKey; + param = new ECPublicKeyParameters( + ecPublicKey.getQ(), + new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN())); + signer.init(false, param); + + if (!signer.verifySignature(message, sig[0], sig[1])) + { + fail("ECGOST3410 2012 verification failed"); + } + + if (!r.equals(sig[0])) + { + fail( + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail( + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + KeyPairGenerator g = KeyPairGenerator.getInstance("ECGOST3410-2012", "BC"); + + g.initialize(new ECNamedCurveGenParameterSpec("Tc26-Gost-3410-12-256-paramSetA"), new SecureRandom()); + + KeyPair p = g.generateKeyPair(); + + signatureGost12Test("ECGOST3410-2012-256", 64, p); + encodedGost12Test(p); + + + g.initialize(new com.fr.third.org.bouncycastle.jcajce.spec.GOST3410ParameterSpec("Tc26-Gost-3410-12-512-paramSetA"), new SecureRandom()); + + p = g.generateKeyPair(); + + signatureGost12Test("ECGOST3410-2012-512", 128, p); + encodedGost12Test(p); + } + + private void ecGOST2012NameCurveGenerationTest() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("ECGOST3410-2012", "BC"); + + kpGen.initialize(new ECNamedCurveGenParameterSpec("Tc26-Gost-3410-12-256-paramSetA")); + + KeyPair kp = kpGen.generateKeyPair(); + + AlgorithmIdentifier expectedAlgId = new AlgorithmIdentifier(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256, + new GOST3410PublicKeyAlgParameters(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256_paramSetA, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256)); + + checkKeyPairAlgId(kp, expectedAlgId); + + kpGen.initialize(new ECNamedCurveGenParameterSpec("Tc26-Gost-3410-12-512-paramSetA")); + + kp = kpGen.generateKeyPair(); + + expectedAlgId = new AlgorithmIdentifier(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512, + new GOST3410PublicKeyAlgParameters(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetA, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512)); + + checkKeyPairAlgId(kp, expectedAlgId); + + kpGen.initialize(new ECNamedCurveGenParameterSpec("Tc26-Gost-3410-12-512-paramSetB")); + + kp = kpGen.generateKeyPair(); + + expectedAlgId = new AlgorithmIdentifier(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512, + new GOST3410PublicKeyAlgParameters(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetB, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512)); + + checkKeyPairAlgId(kp, expectedAlgId); + + kpGen.initialize(new ECNamedCurveGenParameterSpec("Tc26-Gost-3410-12-512-paramSetC")); + + kp = kpGen.generateKeyPair(); + + expectedAlgId = new AlgorithmIdentifier(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512, + new GOST3410PublicKeyAlgParameters(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512_paramSetC, RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512)); + + checkKeyPairAlgId(kp, expectedAlgId); + } + + private void checkKeyPairAlgId(KeyPair kp, AlgorithmIdentifier expectedAlgId) + { + SubjectPublicKeyInfo info = SubjectPublicKeyInfo.getInstance(kp.getPublic().getEncoded()); + + AlgorithmIdentifier algId = info.getAlgorithm(); + + isEquals(expectedAlgId, algId); + + PrivateKeyInfo privInfo = PrivateKeyInfo.getInstance(kp.getPrivate().getEncoded()); + + algId = privInfo.getPrivateKeyAlgorithm(); + + isEquals(expectedAlgId, algId); + } + + private void ecGOST34102012512Test() + throws Exception + { + + BigInteger r = new BigInteger("2489204477031349265072864643032147753667451319282131444027498637357611092810221795101871412928823716805959828708330284243653453085322004442442534151761462"); + BigInteger s = new BigInteger("864523221707669519038849297382936917075023735848431579919598799313385180564748877195639672460179421760770893278030956807690115822709903853682831835159370"); + + BigInteger e = new BigInteger("2897963881682868575562827278553865049173745197871825199562947419041388950970536661109553499954248733088719748844538964641281654463513296973827706272045964"); + + byte[] kData = BigIntegers.asUnsignedByteArray(new BigInteger("359E7F4B1410FEACC570456C6801496946312120B39D019D455986E364F365886748ED7A44B3E794434006011842286212273A6D14CF70EA3AF71BB1AE679F1", 16)); + SecureRandom k = new TestRandomBigInteger(kData); + + BigInteger mod_p = new BigInteger("3623986102229003635907788753683874306021320925534678605086546150450856166624002482588482022271496854025090823603058735163734263822371964987228582907372403"); + BigInteger mod_q = new BigInteger("3623986102229003635907788753683874306021320925534678605086546150450856166623969164898305032863068499961404079437936585455865192212970734808812618120619743"); + + ECCurve curve = new ECCurve.Fp( + mod_p, + new BigInteger("7"), // a + new BigInteger("1518655069210828534508950034714043154928747527740206436194018823352809982443793732829756914785974674866041605397883677596626326413990136959047435811826396"), // b + mod_q, ECConstants.ONE); + + ECParameterSpec spec = new ECParameterSpec( + curve, + curve.createPoint( + new BigInteger("1928356944067022849399309401243137598997786635459507974357075491307766592685835441065557681003184874819658004903212332884252335830250729527632383493573274"), // x + new BigInteger("2288728693371972859970012155529478416353562327329506180314497425931102860301572814141997072271708807066593850650334152381857347798885864807605098724013854")), // y + mod_q, ECConstants.ONE); + + ECPrivateKeySpec priKey = new ECPrivateKeySpec( + new BigInteger("610081804136373098219538153239847583006845519069531562982388135354890606301782255383608393423372379057665527595116827307025046458837440766121180466875860"), // d + spec); + + ECPublicKeySpec pubKey = new ECPublicKeySpec( + curve.createPoint( + new BigInteger("909546853002536596556690768669830310006929272546556281596372965370312498563182320436892870052842808608262832456858223580713780290717986855863433431150561"), // x + new BigInteger("2921457203374425620632449734248415455640700823559488705164895837509539134297327397380287741428246088626609329139441895016863758984106326600572476822372076")), // y + spec); + + KeyFactory f = KeyFactory.getInstance("ECGOST3410-2012", "BC"); + PrivateKey sKey = f.generatePrivate(priKey); + PublicKey vKey = f.generatePublic(pubKey); + + + ECGOST3410_2012Signer signer = new ECGOST3410_2012Signer(); + CipherParameters param = ECUtil.generatePrivateKeyParameter(sKey); + + signer.init(true, new ParametersWithRandom(param, k)); + + byte[] rev = e.toByteArray(); + byte[] message = new byte[rev.length]; + for (int i = 0; i != rev.length; i++) + { + message[i] = rev[rev.length - 1 - i]; + } + BigInteger[] sig = signer.generateSignature(message); + + ECPublicKey ecPublicKey = (ECPublicKey)vKey; + param = new ECPublicKeyParameters( + ecPublicKey.getQ(), + new ECDomainParameters(spec.getCurve(), spec.getG(), spec.getN())); + signer.init(false, param); + + if (!signer.verifySignature(message, sig[0], sig[1])) + { + fail("ECGOST3410 2012 verification failed"); + } + + if (!r.equals(sig[0])) + { + fail( + ": r component wrong." + Strings.lineSeparator() + + " expecting: " + r + Strings.lineSeparator() + + " got : " + sig[0]); + } + + if (!s.equals(sig[1])) + { + fail( + ": s component wrong." + Strings.lineSeparator() + + " expecting: " + s + Strings.lineSeparator() + + " got : " + sig[1]); + } + + + } + + private void ecGOST2012VerifyTest(String signatureAlg, byte[] data, byte[] pubEnc, byte[] sig) + throws Exception + { + KeyFactory keyFact = KeyFactory.getInstance("ECGOST3410-2012", "BC"); + + PublicKey vKey = keyFact.generatePublic(new X509EncodedKeySpec(pubEnc)); + + Signature s = Signature.getInstance(signatureAlg, "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sig)) + { + fail(signatureAlg + " verification failed"); + } + } + + private void signatureGost12Test(String signatureAlg, int expectedSignLen, KeyPair p) + throws Exception + { + byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + + PrivateKey sKey = p.getPrivate(); + PublicKey vKey = p.getPublic(); + Signature s = Signature.getInstance(signatureAlg, "BC"); + s.initSign(sKey); + + s.update(data); + + byte[] sigBytes = s.sign(); + + if (sigBytes.length != expectedSignLen) + { + fail(signatureAlg + " signature failed"); + } + + s = Signature.getInstance(signatureAlg, "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail(signatureAlg + " verification failed"); + } + + } + + private void encodedGost12Test(KeyPair p) + throws Exception + { + PrivateKey sKey = p.getPrivate(); + PublicKey vKey = p.getPublic(); + + KeyFactory f = KeyFactory.getInstance("ECGOST3410-2012", "BC"); + X509EncodedKeySpec x509s = new X509EncodedKeySpec(vKey.getEncoded()); + ECPublicKey eck1 = (ECPublicKey)f.generatePublic(x509s); + + if (!eck1.getQ().equals(((ECPublicKey)vKey).getQ())) + { + fail("public number not decoded properly"); + } + + if (!eck1.getParameters().equals(((ECPublicKey)vKey).getParameters())) + { + fail("public parameters not decoded properly"); + } + + PKCS8EncodedKeySpec pkcs8 = new PKCS8EncodedKeySpec(sKey.getEncoded()); + ECPrivateKey eck2 = (ECPrivateKey)f.generatePrivate(pkcs8); + + if (!eck2.getD().equals(((ECPrivateKey)sKey).getD())) + { + fail("private number not decoded properly"); + } + + if (!eck2.getParameters().equals(((ECPrivateKey)sKey).getParameters())) + { + fail("private number not decoded properly"); + } + + eck2 = (ECPrivateKey)serializeDeserialize(sKey); + if (!eck2.getD().equals(((ECPrivateKey)sKey).getD())) + { + fail("private number not decoded properly"); + } + + if (!eck2.getParameters().equals(((ECPrivateKey)sKey).getParameters())) + { + fail("private number not decoded properly"); + } + + checkEquals(eck2, sKey); + + if (!(eck2 instanceof PKCS12BagAttributeCarrier)) + { + fail("private key not implementing PKCS12 attribute carrier"); + } + + eck1 = (ECPublicKey)serializeDeserialize(vKey); + + if (!eck1.getQ().equals(((ECPublicKey)vKey).getQ())) + { + fail("public number not decoded properly"); + } + + if (!eck1.getParameters().equals(((ECPublicKey)vKey).getParameters())) + { + fail("public parameters not decoded properly"); + } + + checkEquals(eck1, vKey); + } + + private void keyStoreTest(PrivateKey sKey, PublicKey vKey) + throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, NoSuchProviderException, SignatureException, InvalidKeyException, UnrecoverableKeyException + { + // + // keystore test + // + KeyStore ks = KeyStore.getInstance("JKS"); + + ks.load(null, null); + + // + // create the certificate - version 3 + // + X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); + + certGen.setSerialNumber(BigInteger.valueOf(1)); + certGen.setIssuerDN(new X509Principal("CN=Test")); + certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000)); + certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000)); + certGen.setSubjectDN(new X509Principal("CN=Test")); + certGen.setPublicKey(vKey); + certGen.setSignatureAlgorithm("GOST3411withGOST3410"); + + X509Certificate cert = certGen.generate(sKey, "BC"); + + ks.setKeyEntry("gost", sKey, "gost".toCharArray(), new Certificate[]{cert}); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + ks.store(bOut, "gost".toCharArray()); + + ks = KeyStore.getInstance("JKS"); + + ks.load(new ByteArrayInputStream(bOut.toByteArray()), "gost".toCharArray()); + + PrivateKey gKey = (PrivateKey)ks.getKey("gost", "gost".toCharArray()); + } + + private void checkEquals(Object o1, Object o2) + { + if (!o1.equals(o2)) + { + fail("comparison test failed"); + } + + if (o1.hashCode() != o2.hashCode()) + { + fail("hashCode test failed"); + } + } + + private void parametersTest() + throws Exception + { +// AlgorithmParameterGenerator a = AlgorithmParameterGenerator.getInstance("GOST3410", "BC"); +// a.init(512, random); +// AlgorithmParameters params = a.generateParameters(); +// +// byte[] encodeParams = params.getEncoded(); +// +// AlgorithmParameters a2 = AlgorithmParameters.getInstance("GOST3410", "BC"); +// a2.init(encodeParams); +// +// // a and a2 should be equivalent! +// byte[] encodeParams_2 = a2.getEncoded(); +// +// if (!arrayEquals(encodeParams, encodeParams_2)) +// { +// fail("encode/decode parameters failed"); +// } + + GOST3410ParameterSpec gost3410P = new GOST3410ParameterSpec(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_B.getId()); + + KeyPairGenerator g = KeyPairGenerator.getInstance("GOST3410", "BC"); + g.initialize(gost3410P, new SecureRandom()); + KeyPair p = g.generateKeyPair(); + + PrivateKey sKey = p.getPrivate(); + PublicKey vKey = p.getPublic(); + + Signature s = Signature.getInstance("GOST3410", "BC"); + byte[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 0}; + + s.initSign(sKey); + + s.update(data); + + byte[] sigBytes = s.sign(); + + s = Signature.getInstance("GOST3410", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("GOST3410 verification failed"); + } + + keyStoreTest(sKey, vKey); + } + + private BigInteger[] decode( + byte[] encoding) + { + byte[] r = new byte[32]; + byte[] s = new byte[32]; + + System.arraycopy(encoding, 0, s, 0, 32); + + System.arraycopy(encoding, 32, r, 0, 32); + + BigInteger[] sig = new BigInteger[2]; + + sig[0] = new BigInteger(1, r); + sig[1] = new BigInteger(1, s); + + return sig; + } + + private Object serializeDeserialize(Object o) + throws Exception + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(o); + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + return oIn.readObject(); + } + + public String getName() + { + return "GOST3410/ECGOST3410/ECGOST3410 2012"; + } + + public void performTest() + throws Exception + { + ecGOST3410Test(); + + if (Security.getProvider("BC").containsKey("KeyFactory.ECGOST3410-2012")) + { + ecGOST34102012256Test(); + ecGOST34102012512Test(); + ecGOST2012NameCurveGenerationTest(); + ecGOST2012VerifyTest("ECGOST3410-2012-256", ecgostData, ecgost2012_256Key, ecgost2012_256Sig); + ecGOST2012VerifyTest("ECGOST3410-2012-512", ecgostData, ecgost2012_512Key, ecgost2012_512Sig); + } + + generationTest(); + parametersTest(); + } + + protected byte[] toByteArray(String input) + { + byte[] bytes = new byte[input.length()]; + + for (int i = 0; i != bytes.length; i++) + { + bytes[i] = (byte)input.charAt(i); + } + + return bytes; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new GOST3410Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST3412Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST3412Test.java new file mode 100644 index 000000000..7d38f816c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/GOST3412Test.java @@ -0,0 +1,256 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.security.InvalidAlgorithmParameterException; +import java.security.Key; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * basic test class for the GOST28147 cipher + */ +public class GOST3412Test + extends SimpleTest +{ + public String getName() + { + return "GOST3412"; + } + + public void testECB( + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "GOST3412-2015"); + + in = Cipher.getInstance("GOST3412-2015/ECB/NoPadding", "BC"); + out = Cipher.getInstance("GOST3412-2015/ECB/NoPadding", "BC"); + out.init(Cipher.ENCRYPT_MODE, key); + in.init(Cipher.DECRYPT_MODE, key); + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("GOST3412-2015 failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + + if (!areEqual(bytes, input)) + { + fail("GOST3412-2015 failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + public void testCFB( + byte[] keyBytes, + byte[] iv, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "GOST3412-2015"); + + in = Cipher.getInstance("GOST3412-2015/CFB8/NoPadding", "BC"); + out = Cipher.getInstance("GOST3412-2015/CFB8/NoPadding", "BC"); + + out.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv)); + in.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv)); + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("GOST3412-2015 failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + + if (!areEqual(bytes, input)) + { + fail("GOST3412-2015 failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + private void testCTR() + throws Exception + { + testG3413CTRInit(8); + + try + { + testG3413CTRInit(16); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue(e.getMessage().endsWith("IV must be 8 bytes long.")); + } + } + + private void testG3413CTRInit(final int pIVLen) + throws Exception + { + /* Create the generator and generate a key */ + KeyGenerator myGenerator = KeyGenerator.getInstance("GOST3412-2015", "BC"); + + /* Initialise the generator */ + myGenerator.init(256); + SecretKey myKey = myGenerator.generateKey(); + + /* Create IV */ + byte[] myIV = new byte[pIVLen]; + CryptoServicesRegistrar.getSecureRandom().nextBytes(myIV); + + /* Create a G3413CTR Cipher */ + Cipher myCipher = Cipher.getInstance("GOST3412-2015" + "/CTR/NoPadding", "BC"); + myCipher.init(Cipher.ENCRYPT_MODE, myKey, new IvParameterSpec(myIV)); + + byte[] msg = Strings.toByteArray("G3413CTR JCA init Bug fixed"); + + byte[] enc = myCipher.doFinal(msg); + + myCipher.init(Cipher.DECRYPT_MODE, myKey, new IvParameterSpec(myIV)); + + byte[] dec = myCipher.doFinal(enc); + + isTrue(areEqual(msg, dec)); + } + + public void performTest() + throws Exception + { + testECB(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef"), + Hex.decode("1122334455667700ffeeddccbbaa9988"), Hex.decode("7f679d90bebc24305a468d42b9d4edcd")); + + testCFB(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef"), + Hex.decode("1234567890abcef0a1b2c3d4e5f0011223344556677889901213141516171819"), + Hex.decode("1122334455667700ffeeddccbbaa998800112233445566778899aabbcceeff0a112233445566778899aabbcceeff0a002233445566778899aabbcceeff0a0011"), Hex.decode("819b19c5867e61f1cf1b16f664f66e46ed8fcb82b1110b1e7ec03bfa6611f2eabd7a32363691cbdc3bbe403bc80552d822c2cdf483981cd71d5595453d7f057d")); + + byte[][] inputs = new byte[][]{ + Hex.decode("1122334455667700ffeeddccbbaa9988"), + Hex.decode("00112233445566778899aabbcceeff0a"), + Hex.decode("112233445566778899aabbcceeff0a00"), + Hex.decode("2233445566778899aabbcceeff0a0011"), + }; + + Mac mac = Mac.getInstance("GOST3412MAC", "BC"); + + mac.init(new SecretKeySpec(Hex.decode("8899aabbccddeeff0011223344556677fedcba98765432100123456789abcdef"), "GOST3412MAC")); + + for (int i = 0; i != inputs.length; i++) + { + mac.update(inputs[i]); + } + + if (!Arrays.areEqual(Hex.decode("336f4d296059fbe34ddeb35b37749c67"), mac.doFinal())) + { + fail("mac test failed."); + } + + testCTR(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new GOST3412Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/HMacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/HMacTest.java new file mode 100644 index 000000000..0b64b5860 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/HMacTest.java @@ -0,0 +1,338 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Security; +import java.util.Arrays; + +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.RC5ParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.asn1.iana.IANAObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.rosstandart.RosstandartObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.ua.UAObjectIdentifiers; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * HMAC tester + */ +public class HMacTest + extends SimpleTest +{ + static byte[] keyBytes = Hex.decode("0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"); + static byte[] message = Hex.decode("4869205468657265"); + static byte[] output1 = Hex.decode("b617318655057264e28bc0b6fb378c8ef146be00"); + static byte[] outputMD5 = Hex.decode("5ccec34ea9656392457fa1ac27f08fbc"); + static byte[] outputMD2 = Hex.decode("dc1923ef5f161d35bef839ca8c807808"); + static byte[] outputMD4 = Hex.decode("5570ce964ba8c11756cdc3970278ff5a"); + static byte[] output224 = Hex.decode("896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22"); + static byte[] output256 = Hex.decode("b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7"); + static byte[] output384 = Hex.decode("afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6"); + static byte[] output512 = Hex.decode("87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854"); + static byte[] output512_224 = Hex.decode("b244ba01307c0e7a8ccaad13b1067a4cf6b961fe0c6a20bda3d92039"); + static byte[] output512_256 = Hex.decode("9f9126c3d9c3c330d760425ca8a217e31feae31bfe70196ff81642b868402eab"); + static byte[] outputRipeMD128 = Hex.decode("fda5717fb7e20cf05d30bb286a44b05d"); + static byte[] outputRipeMD160 = Hex.decode("24cb4bd67d20fc1a5d2ed7732dcc39377f0a5668"); + static byte[] outputTiger = Hex.decode("1d7a658c75f8f004916e7b07e2a2e10aec7de2ae124d3647"); + static byte[] outputOld384 = Hex.decode("0a046aaa0255e432912228f8ccda437c8a8363fb160afb0570ab5b1fd5ddc20eb1888b9ed4e5b6cb5bc034cd9ef70e40"); + static byte[] outputOld512 = Hex.decode("9656975ee5de55e75f2976ecce9a04501060b9dc22a6eda2eaef638966280182477fe09f080b2bf564649cad42af8607a2bd8d02979df3a980f15e2326a0a22a"); + + static byte[] outputKck224 = Hex.decode("b73d595a2ba9af815e9f2b4e53e78581ebd34a80b3bbaac4e702c4cc"); + static byte[] outputKck256 = Hex.decode("9663d10c73ee294054dc9faf95647cb99731d12210ff7075fb3d3395abfb9821"); + static byte[] outputKck288 = Hex.decode("36145df8742160a1811139494d708f9a12757c30dedc622a98aa6ecb69da32a34ea55441"); + static byte[] outputKck384 = Hex.decode("892dfdf5d51e4679bf320cd16d4c9dc6f749744608e003add7fba894acff87361efa4e5799be06b6461f43b60ae97048"); + static byte[] outputKck512 = Hex.decode("8852c63be8cfc21541a4ee5e5a9a852fc2f7a9adec2ff3a13718ab4ed81aaea0b87b7eb397323548e261a64e7fc75198f6663a11b22cd957f7c8ec858a1c7755"); + + static byte[] outputSha3_224 = Hex.decode("3b16546bbc7be2706a031dcafd56373d9884367641d8c59af3c860f7"); + static byte[] outputSha3_256 = Hex.decode("ba85192310dffa96e2a3a40e69774351140bb7185e1202cdcc917589f95e16bb"); + static byte[] outputSha3_384 = Hex.decode("68d2dcf7fd4ddd0a2240c8a437305f61fb7334cfb5d0226e1bc27dc10a2e723a20d370b47743130e26ac7e3d532886bd"); + static byte[] outputSha3_512 = Hex.decode("eb3fbd4b2eaab8f5c504bd3a41465aacec15770a7cabac531e482f860b5ec7ba47ccb2c6f2afce8f88d22b6dc61380f23a668fd3888bb80537c0a0b86407689e"); + + static byte[] outputGost2012_256 = Hex.decode("f03422dfa37a507ca126ce01b8eba6b7fdda8f8a60dd8f2703e3a372120b8294"); + static byte[] outputGost2012_512 = Hex.decode("86b6a06bfa9f1974aff6ccd7fa3f835f0bd850395d6084efc47b9dda861a2cdf0dcaf959160733d5269f6567966dd7a9f932a77cd6f080012cd476f1c2cc31bb"); + + static byte[] outputDSTU7564_256 = Hex.decode("98ac67aa21eaf6e8666fb748d66cfc15d5d66f5194c87fffa647e406d3375cdb"); + static byte[] outputDSTU7564_384 = Hex.decode("4e46a87e70fcd2ccfb4433a8eaec68991a96b11085c5d5484db71af51bac469c03f76e1f721843c8e8667708fe41a48d"); + static byte[] outputDSTU7564_512 = Hex.decode("5b7acf633a7551b8410fa66a60c74a494e46a87e70fcd2ccfb4433a8eaec68991a96b11085c5d5484db71af51bac469c03f76e1f721843c8e8667708fe41a48d"); + + public HMacTest() + { + } + + public void testHMac( + String hmacName, + byte[] output) + throws Exception + { + SecretKey key = new SecretKeySpec(keyBytes, hmacName); + byte[] out; + Mac mac; + + mac = Mac.getInstance(hmacName, "BC"); + + mac.init(key); + + mac.reset(); + + mac.update(message, 0, message.length); + + out = mac.doFinal(); + + if (!areEqual(out, output)) + { + fail("Failed - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + // no key generator for the old algorithms + if (hmacName.startsWith("Old")) + { + return; + } + + KeyGenerator kGen = KeyGenerator.getInstance(hmacName, "BC"); + + mac.init(kGen.generateKey()); + + mac.update(message); + + out = mac.doFinal(); + } + + public void testHMac( + String hmacName, + int defKeySize, + byte[] output) + throws Exception + { + SecretKey key = new SecretKeySpec(keyBytes, hmacName); + byte[] out; + Mac mac; + + mac = Mac.getInstance(hmacName, "BC"); + + mac.init(key); + + mac.reset(); + + mac.update(message, 0, message.length); + + out = mac.doFinal(); + + if (!areEqual(out, output)) + { + fail("Failed - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + + KeyGenerator kGen = KeyGenerator.getInstance(hmacName, "BC"); + + SecretKey secretKey = kGen.generateKey(); + + mac.init(secretKey); + + mac.update(message); + + out = mac.doFinal(); + + isTrue("default key wrong length", secretKey.getEncoded().length == defKeySize / 8); + } + + + private void testExceptions() + throws Exception + { + Mac mac = null; + + mac = Mac.getInstance("HmacSHA1", "BC"); + + byte[] b = {(byte)1, (byte)2, (byte)3, (byte)4, (byte)5}; + SecretKeySpec sks = new SecretKeySpec(b, "HmacSHA1"); + RC5ParameterSpec algPS = new RC5ParameterSpec(100, 100, 100); + + try + { + mac.init(sks, algPS); + } + catch (InvalidAlgorithmParameterException e) + { + // ignore okay + } + + try + { + mac.init(null, null); + } + catch (InvalidKeyException e) + { + // ignore okay + } + catch (InvalidAlgorithmParameterException e) + { + // ignore okay + } + + try + { + mac.init(null); + } + catch (InvalidKeyException e) + { + // ignore okay + } + } + + public void performTest() + throws Exception + { + testHMac("HMac-SHA1", 160, output1); + testHMac("HMac-MD5", outputMD5); + testHMac("HMac-MD4", outputMD4); + testHMac("HMac-MD2", outputMD2); + testHMac("HMac-SHA224", 224, output224); + testHMac("HMac-SHA256", 256, output256); + testHMac("HMac-SHA384", 384, output384); + testHMac("HMac-SHA512", 512, output512); + testHMac("HMac-SHA512/224", output512_224); + testHMac("HMac-SHA512/256", output512_256); + testHMac("HMac-RIPEMD128", 128, outputRipeMD128); + testHMac("HMac-RIPEMD160", 160, outputRipeMD160); + testHMac("HMac-TIGER", 192, outputTiger); + testHMac("HMac-KECCAK224", 224, outputKck224); + testHMac("HMac-KECCAK256", 256, outputKck256); + testHMac("HMac-KECCAK288", 288, outputKck288); + testHMac("HMac-KECCAK384", 384, outputKck384); + testHMac("HMac-KECCAK512", 512, outputKck512); + testHMac("HMac-SHA3-224", 224, outputSha3_224); + testHMac("HMac-SHA3-256", 256, outputSha3_256); + testHMac("HMac-SHA3-384", 384, outputSha3_384); + testHMac("HMac-SHA3-512", 512, outputSha3_512); + + testHMac("HMac-GOST3411-2012-256", 256, outputGost2012_256); + testHMac("HMac-GOST3411-2012-512", 512, outputGost2012_512); + + testHMac("HMac-DSTU7564-256", 256, outputDSTU7564_256); + testHMac("HMac-DSTU7564-384", 384, outputDSTU7564_384); + testHMac("HMac-DSTU7564-512", 512, outputDSTU7564_512); + + testHMac("HMac/SHA1", output1); + testHMac("HMac/MD5", outputMD5); + testHMac("HMac/MD4", outputMD4); + testHMac("HMac/MD2", outputMD2); + testHMac("HMac/SHA224", 224, output224); + testHMac("HMac/SHA256", 256, output256); + testHMac("HMac/SHA384", 384, output384); + testHMac("HMac/SHA512", 512, output512); + testHMac("HMac/RIPEMD128", 128, outputRipeMD128); + testHMac("HMac/RIPEMD160", 160, outputRipeMD160); + testHMac("HMac/TIGER", 192, outputTiger); + testHMac("HMac/KECCAK224", 224, outputKck224); + testHMac("HMac/KECCAK256", 256, outputKck256); + testHMac("HMac/KECCAK288", 288, outputKck288); + testHMac("HMac/KECCAK384", 384, outputKck384); + testHMac("HMac/KECCAK512", 512, outputKck512); + testHMac("HMac/SHA3-224", 224, outputSha3_224); + testHMac("HMac/SHA3-256", 256, outputSha3_256); + testHMac("HMac/SHA3-384", 384, outputSha3_384); + testHMac("HMac/SHA3-512", 512, outputSha3_512); + testHMac("HMac/GOST3411-2012-256", 256, outputGost2012_256); + testHMac("HMac/GOST3411-2012-512", 512, outputGost2012_512); + + testHMac(PKCSObjectIdentifiers.id_hmacWithSHA1.getId(), 160, output1); + testHMac(PKCSObjectIdentifiers.id_hmacWithSHA224.getId(), 224, output224); + testHMac(PKCSObjectIdentifiers.id_hmacWithSHA256.getId(), 256, output256); + testHMac(PKCSObjectIdentifiers.id_hmacWithSHA384.getId(), 384, output384); + testHMac(PKCSObjectIdentifiers.id_hmacWithSHA512.getId(), 512, output512); + testHMac(IANAObjectIdentifiers.hmacSHA1.getId(), 160, output1); + testHMac(IANAObjectIdentifiers.hmacMD5.getId(), outputMD5); + testHMac(IANAObjectIdentifiers.hmacRIPEMD160.getId(), 160, outputRipeMD160); + testHMac(IANAObjectIdentifiers.hmacTIGER.getId(), 192, outputTiger); + + testHMac(NISTObjectIdentifiers.id_hmacWithSHA3_224.getId(), 224, outputSha3_224); + testHMac(NISTObjectIdentifiers.id_hmacWithSHA3_256.getId(), 256, outputSha3_256); + testHMac(NISTObjectIdentifiers.id_hmacWithSHA3_384.getId(), 384, outputSha3_384); + testHMac(NISTObjectIdentifiers.id_hmacWithSHA3_512.getId(), 512, outputSha3_512); + + testHMac(RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_256.getId(), 256, outputGost2012_256); + testHMac(RosstandartObjectIdentifiers.id_tc26_hmac_gost_3411_12_512.getId(), 512, outputGost2012_512); + + testHMac(UAObjectIdentifiers.dstu7564mac_256.getId(), 256, outputDSTU7564_256); + testHMac(UAObjectIdentifiers.dstu7564mac_384.getId(), 384, outputDSTU7564_384); + testHMac(UAObjectIdentifiers.dstu7564mac_512.getId(), 512, outputDSTU7564_512); + + // test for compatibility with broken HMac. + testHMac("OldHMacSHA384", outputOld384); + testHMac("OldHMacSHA512", outputOld512); + + testExceptions(); + + testPBEWITHHMACSHAVariants(); + } + + private static final int[] SUN_JCA_VARIANTS = { + 1, 224, 256, 384, 512 + }; + + private static final byte[][] SUN_JCA_KNOWN_ANSWERS_FOR_SHA_VARIANTS = { + Hex.decode("2cb29f938331443af79de5863a1b072d57a4b640"), + Hex.decode("3bf31c354fb1817503e9b581d4d1d51c4c8e921a3b46a513cc24c0ca"), + Hex.decode("583697860e49d8d534ebdf99205173356f4e209447b6ac7d500ddddc1b382068"), + Hex.decode("ad3ca42cc656876872bd0e5054d0f2260ec2a07635c5dfa655926989af392bbe636a23f08d1dc8ccd966ffa66ecc30e0"), + Hex.decode("eabbb30bf280870530126bea40d3123c18d6bd6f6e9ded0eebd51a44d8527b27732206bd1bb7c1c8d941b5f2fba2f87ed49f5f1f3d7bef0e7547d335b4a55b87") + }; + + /** + * Test that BC has the same results as the SunJCA provider for PBEwithHMACSHA. + *

+ * Test courtesy of the Android project. + *

+ */ + public void testPBEWITHHMACSHAVariants() + throws Exception + { + byte[] plaintext = new byte[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34}; + byte[] salt = "saltsalt".getBytes(); + char[] password = "password".toCharArray(); + int iterationCount = 100; + + for (int shaVariantIndex = 0; shaVariantIndex < SUN_JCA_VARIANTS.length; shaVariantIndex++) + { + int shaVariant = SUN_JCA_VARIANTS[shaVariantIndex]; + SecretKeyFactory secretKeyFactory = + SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA" + shaVariant, "BC"); + PBEKeySpec pbeKeySpec = new PBEKeySpec(password, + salt, + iterationCount, + // Key depending on block size! + (shaVariant < 384) ? 64 : 128); + SecretKey secretKey = secretKeyFactory.generateSecret(pbeKeySpec); + Mac mac = Mac.getInstance("PBEWITHHMACSHA" + shaVariant, "BC"); + mac.init(secretKey); + + byte[] bcResult = mac.doFinal(plaintext); + + isTrue("value mismatch", Arrays.equals(SUN_JCA_KNOWN_ANSWERS_FOR_SHA_VARIANTS[shaVariantIndex], bcResult)); + } + } + + public String getName() + { + return "HMac"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new HMacTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/IESTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/IESTest.java new file mode 100644 index 000000000..0ac75bfa0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/IESTest.java @@ -0,0 +1,265 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.spec.DHParameterSpec; + +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.IEKeySpec; +import com.fr.third.org.bouncycastle.jce.spec.IESParameterSpec; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * test for ECIES - Elliptic Curve Integrated Encryption Scheme + */ +public class IESTest + extends SimpleTest +{ + private BigInteger g512 = new BigInteger("153d5d6172adb43045b68ae8e1de1070b6137005686d29d3d73a7749199681ee5b212c9b96bfdcfa5b20cd5e3fd2044895d609cf9b410b7a0f12ca1cb9a428cc", 16); + private BigInteger p512 = new BigInteger("9494fec095f3b85ee286542b3836fc81a5dd0a0349b4c239dd38744d488cf8e31db8bcb7d33b41abb9e5a33cca9144b1cef332c94bf0573bf047a3aca98cdf3b", 16); + + IESTest() + { + } + + public String getName() + { + return "IES"; + } + + public void performTest() + throws Exception + { + KeyPairGenerator g = KeyPairGenerator.getInstance("ECIES", "BC"); + + X9ECParameters x9 = ECNamedCurveTable.getByName("prime239v1"); + ECParameterSpec ecSpec = new ECParameterSpec(x9.getCurve(), x9.getG(),x9.getN(), x9.getH()); + + g.initialize(ecSpec, new SecureRandom()); + + Cipher c1 = Cipher.getInstance("ECIES", "BC"); + Cipher c2 = Cipher.getInstance("ECIES", "BC"); + + doTest(g, c1, c2); + + g = KeyPairGenerator.getInstance("ECIES", "BC"); + + g.initialize(192, new SecureRandom()); + + doTest(g, c1, c2); + + g = KeyPairGenerator.getInstance("ECIES", "BC"); + + g.initialize(239, new SecureRandom()); + + doTest(g, c1, c2); + + g = KeyPairGenerator.getInstance("ECIES", "BC"); + + g.initialize(256, new SecureRandom()); + + doTest(g, c1, c2); + + doDefTest(g, c1, c2); + + DHParameterSpec dhParams = new DHParameterSpec(p512, g512); + + c1 = Cipher.getInstance("IES", "BC"); + c2 = Cipher.getInstance("IES", "BC"); + + g = KeyPairGenerator.getInstance("DH", "BC"); + + g.initialize(dhParams); + + doTest(g, c1, c2); + + doDefTest(g, c1, c2); + } + + public void doTest( + KeyPairGenerator g, + Cipher c1, + Cipher c2) + throws Exception + { + // + // a side + // + KeyPair aKeyPair = g.generateKeyPair(); + PublicKey aPub = aKeyPair.getPublic(); + PrivateKey aPriv = aKeyPair.getPrivate(); + + // + // b side + // + KeyPair bKeyPair = g.generateKeyPair(); + PublicKey bPub = bKeyPair.getPublic(); + PrivateKey bPriv = bKeyPair.getPrivate(); + + // + // stream test + // + + IEKeySpec c1Key = new IEKeySpec(aPriv, bPub); + IEKeySpec c2Key = new IEKeySpec(bPriv, aPub); + + byte[] d = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8 }; + byte[] e = new byte[] { 8, 7, 6, 5, 4, 3, 2, 1 }; + + IESParameterSpec param = new IESParameterSpec(d, e, 128); + + c1.init(Cipher.ENCRYPT_MODE, c1Key, param); + + c2.init(Cipher.DECRYPT_MODE, c2Key, param); + + byte[] message = Hex.decode("1234567890abcdef"); + + int estLen1 = c1.getOutputSize(message.length); + + byte[] out1 = c1.doFinal(message, 0, message.length); + + if (estLen1 < out1.length) + { + fail("output size incorrect"); + } + + int estLen2 = c2.getOutputSize(out1.length); + + byte[] out2 = c2.doFinal(out1, 0, out1.length); + + if (estLen2 < out2.length) + { + fail("output size incorrect"); + } + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + } + + public void doDefTest( + KeyPairGenerator g, + Cipher c1, + Cipher c2) + throws Exception + { + // + // a side + // + KeyPair aKeyPair = g.generateKeyPair(); + PublicKey aPub = aKeyPair.getPublic(); + PrivateKey aPriv = aKeyPair.getPrivate(); + + // + // b side + // + KeyPair bKeyPair = g.generateKeyPair(); + PublicKey bPub = bKeyPair.getPublic(); + PrivateKey bPriv = bKeyPair.getPrivate(); + + // + // stream test + // + IEKeySpec c1Key = new IEKeySpec(aPriv, bPub); + IEKeySpec c2Key = new IEKeySpec(bPriv, aPub); + + c1.init(Cipher.ENCRYPT_MODE, c1Key); + + AlgorithmParameters param = c1.getParameters(); + + c2.init(Cipher.DECRYPT_MODE, c2Key, param); + + byte[] message = Hex.decode("1234567890abcdef"); + + int estLen1 = c1.getOutputSize(message.length); + + byte[] out1 = c1.doFinal(message, 0, message.length); + + if (estLen1 < out1.length) + { + fail("output size incorrect"); + } + + int estLen2 = c2.getOutputSize(out1.length); + byte[] out2 = c2.doFinal(out1, 0, out1.length); + + if (estLen2 < out2.length) + { + fail("output size incorrect"); + } + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // int doFinal + // + int len1 = c1.doFinal(message, 0, message.length, out1, 0); + + if (len1 != out1.length) + { + fail("encryption length wrong"); + } + + int len2 = c2.doFinal(out1, 0, out1.length, out2, 0); + + if (len2 != out2.length) + { + fail("decryption length wrong"); + } + + if (!areEqual(out2, message)) + { + fail("stream cipher test failed"); + } + + // + // int doFinal with update + // + len1 = c1.update(message, 0, 2, out1, 0); + + len1 += c1.doFinal(message, 2, message.length - 2, out1, len1); + + if (len1 != out1.length) + { + fail("update encryption length wrong"); + } + + len2 = c2.update(out1, 0, 2, out2, 0); + + len2 += c2.doFinal(out1, 2, out1.length - 2, out2, len2); + + if (len2 != out2.length) + { + fail("update decryption length wrong"); + } + + if (!areEqual(out2, message)) + { + fail("update stream cipher test failed"); + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new IESTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java new file mode 100644 index 000000000..1932b4aee --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ImplicitlyCaTest.java @@ -0,0 +1,330 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.interfaces.ECKey; +import java.security.spec.ECFieldFp; +import java.security.spec.EllipticCurve; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import com.fr.third.org.bouncycastle.jce.ECPointUtil; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPrivateKey; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPublicKey; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.FixedSecureRandom; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ImplicitlyCaTest + extends SimpleTest +{ + byte[] k1 = Hex.decode("d5014e4b60ef2ba8b6211b4062ba3224e0427dd3"); + byte[] k2 = Hex.decode("345e8d05c075c3a508df729a1685690e68fcfb8c8117847e89063bca1f85d968fd281540b6e13bd1af989a1fbf17e06462bf511f9d0b140fb48ac1b1baa5bded"); + + SecureRandom random = new FixedSecureRandom( + new FixedSecureRandom.Source[] { new FixedSecureRandom.Data(k1), new FixedSecureRandom.Data(k2) }); + + public void performTest() + throws Exception + { + testBCAPI(); + + testJDKAPI(); + + testKeyFactory(); + + testBasicThreadLocal(); + } + + private void testBCAPI() + throws Exception + { + KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); + + X9ECParameters x9 = ECNamedCurveTable.getByName("prime239v1"); + ECParameterSpec ecSpec = new ECParameterSpec(x9.getCurve(), x9.getG(), x9.getN(), x9.getH()); + + ConfigurableProvider config = (ConfigurableProvider)Security.getProvider("BC"); + + config.setParameter(ConfigurableProvider.EC_IMPLICITLY_CA, ecSpec); + + g.initialize(null, new SecureRandom()); + + KeyPair p = g.generateKeyPair(); + + ECPrivateKey sKey = (ECPrivateKey)p.getPrivate(); + ECPublicKey vKey = (ECPublicKey)p.getPublic(); + + testECDSA(sKey, vKey); + + testBCParamsAndQ(sKey, vKey); + testEC5Params(sKey, vKey); + + testEncoding(sKey, vKey); + } + + private void testKeyFactory() + throws Exception + { + KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); + + X9ECParameters x9 = ECNamedCurveTable.getByName("prime239v1"); + ECParameterSpec ecSpec = new ECParameterSpec(x9.getCurve(), x9.getG(), x9.getN(), x9.getH()); + + ConfigurableProvider config = (ConfigurableProvider)Security.getProvider("BC"); + + config.setParameter(ConfigurableProvider.EC_IMPLICITLY_CA, ecSpec); + + g.initialize(null, new SecureRandom()); + + KeyPair p = g.generateKeyPair(); + + ECPrivateKey sKey = (ECPrivateKey)p.getPrivate(); + ECPublicKey vKey = (ECPublicKey)p.getPublic(); + + KeyFactory fact = KeyFactory.getInstance("ECDSA", "BC"); + + vKey = (ECPublicKey)fact.generatePublic(new ECPublicKeySpec(vKey.getQ(), null)); + sKey = (ECPrivateKey)fact.generatePrivate(new ECPrivateKeySpec(sKey.getD(), null)); + + testECDSA(sKey, vKey); + + testBCParamsAndQ(sKey, vKey); + testEC5Params(sKey, vKey); + + testEncoding(sKey, vKey); + + ECPublicKey vKey2 = (ECPublicKey)fact.generatePublic(new ECPublicKeySpec(vKey.getQ(), null)); + ECPrivateKey sKey2 = (ECPrivateKey)fact.generatePrivate(new ECPrivateKeySpec(sKey.getD(), null)); + + if (!vKey.equals(vKey2) || vKey.hashCode() != vKey2.hashCode()) + { + fail("public equals/hashCode failed"); + } + + if (!sKey.equals(sKey2) || sKey.hashCode() != sKey2.hashCode()) + { + fail("private equals/hashCode failed"); + } + + // check we can get specs. + fact.getKeySpec(vKey, java.security.spec.ECPublicKeySpec.class); + + fact.getKeySpec(sKey, java.security.spec.ECPrivateKeySpec.class); + } + + private void testJDKAPI() + throws Exception + { + KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); + + EllipticCurve curve = new EllipticCurve( + new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + + java.security.spec.ECParameterSpec ecSpec = new java.security.spec.ECParameterSpec( + curve, + ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n + 1); // h + + + ConfigurableProvider config = (ConfigurableProvider)Security.getProvider("BC"); + + config.setParameter(ConfigurableProvider.EC_IMPLICITLY_CA, ecSpec); + + g.initialize(null, new SecureRandom()); + + KeyPair p = g.generateKeyPair(); + + ECPrivateKey sKey = (ECPrivateKey)p.getPrivate(); + ECPublicKey vKey = (ECPublicKey)p.getPublic(); + + testECDSA(sKey, vKey); + + testBCParamsAndQ(sKey, vKey); + testEC5Params(sKey, vKey); + + testEncoding(sKey, vKey); + } + + private void testBasicThreadLocal() + throws Exception + { + KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); + + EllipticCurve curve = new EllipticCurve( + new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + + java.security.spec.ECParameterSpec ecSpec = new java.security.spec.ECParameterSpec( + curve, + ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n + 1); // h + + + ConfigurableProvider config = (ConfigurableProvider)Security.getProvider("BC"); + + config.setParameter(ConfigurableProvider.THREAD_LOCAL_EC_IMPLICITLY_CA, ecSpec); + + g.initialize(null, new SecureRandom()); + + KeyPair p = g.generateKeyPair(); + + ECPrivateKey sKey = (ECPrivateKey)p.getPrivate(); + ECPublicKey vKey = (ECPublicKey)p.getPublic(); + + testECDSA(sKey, vKey); + + testBCParamsAndQ(sKey, vKey); + testEC5Params(sKey, vKey); + + testEncoding(sKey, vKey); + } + + private void testECDSA( + ECPrivateKey sKey, + ECPublicKey vKey) + throws Exception + { + byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + Signature s = Signature.getInstance("ECDSA", "BC"); + + s.initSign(sKey); + + s.update(data); + + byte[] sigBytes = s.sign(); + + s = Signature.getInstance("ECDSA", "BC"); + + s.initVerify(vKey); + + s.update(data); + + if (!s.verify(sigBytes)) + { + fail("ECDSA verification failed"); + } + } + + private void testEncoding( + ECPrivateKey privKey, + ECPublicKey pubKey) + throws Exception + { + KeyFactory kFact = KeyFactory.getInstance("ECDSA", "BC"); + + byte[] bytes = privKey.getEncoded(); + + PrivateKeyInfo sInfo = PrivateKeyInfo.getInstance(new ASN1InputStream(bytes).readObject()); + + if (!sInfo.getPrivateKeyAlgorithm().getParameters().equals(DERNull.INSTANCE)) + { + fail("private key parameters wrong"); + } + + ECPrivateKey sKey = (ECPrivateKey)kFact.generatePrivate(new PKCS8EncodedKeySpec(bytes)); + + if (!sKey.equals(privKey)) + { + fail("private equals failed"); + } + + if (sKey.hashCode() != privKey.hashCode()) + { + fail("private hashCode failed"); + } + + bytes = pubKey.getEncoded(); + + SubjectPublicKeyInfo vInfo = SubjectPublicKeyInfo.getInstance(new ASN1InputStream(bytes).readObject()); + + if (!vInfo.getAlgorithm().getParameters().equals(DERNull.INSTANCE)) + { + fail("public key parameters wrong"); + } + + ECPublicKey vKey = (ECPublicKey)kFact.generatePublic(new X509EncodedKeySpec(bytes)); + + if (!vKey.equals(pubKey) || vKey.hashCode() != pubKey.hashCode()) + { + fail("public equals/hashCode failed"); + } + + testBCParamsAndQ(sKey, vKey); + testEC5Params(sKey, vKey); + + testECDSA(sKey, vKey); + } + + private void testBCParamsAndQ( + ECPrivateKey sKey, + ECPublicKey vKey) + { + if (sKey.getParameters() != null) + { + fail("parameters exposed in private key"); + } + + if (vKey.getParameters() != null) + { + fail("parameters exposed in public key"); + } + + if (vKey.getQ().getCurve() != null) + { + fail("curve exposed in public point"); + } + } + + private void testEC5Params( + ECPrivateKey sKey, + ECPublicKey vKey) + { + java.security.interfaces.ECKey k = (java.security.interfaces.ECKey)sKey; + + if (k.getParams() != null) + { + fail("parameters exposed in private key"); + } + + k = (ECKey)vKey; + if (k.getParams() != null) + { + fail("parameters exposed in public key"); + } + } + + public String getName() + { + return "ImplicitlyCA"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new ImplicitlyCaTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/JceTestUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/JceTestUtil.java new file mode 100644 index 000000000..47236a65a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/JceTestUtil.java @@ -0,0 +1,49 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Security; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; + +abstract class JceTestUtil +{ + private JceTestUtil() + { + } + + static String[] getRegisteredAlgorithms(String prefix, String[] exclusionPatterns) + { + final BouncyCastleProvider prov = (BouncyCastleProvider)Security.getProvider("BC"); + + List matches = new ArrayList(); + Enumeration algos = prov.keys(); + while (algos.hasMoreElements()) + { + String algo = (String)algos.nextElement(); + if (!algo.startsWith(prefix)) + { + continue; + } + String algoName = algo.substring(prefix.length()); + if (!isExcluded(algoName, exclusionPatterns)) + { + matches.add(algoName); + } + } + return (String[])matches.toArray(new String[matches.size()]); + } + + private static boolean isExcluded(String algoName, String[] exclusionPatterns) + { + for (int i = 0; i < exclusionPatterns.length; i++) + { + if (algoName.contains(exclusionPatterns[i])) + { + return true; + } + } + return false; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/KeccakTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/KeccakTest.java new file mode 100644 index 000000000..c3c1256b6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/KeccakTest.java @@ -0,0 +1,136 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.MessageDigest; +import java.security.Security; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class KeccakTest + extends SimpleTest +{ + final static String provider = "BC"; + + static private byte[] nullMsg = new byte[0]; + + static private String[][] nullVectors = + { + { "KECCAK-224", "f71837502ba8e10837bdd8d365adb85591895602fc552b48b7390abd" }, + { "KECCAK-256", "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470" }, + { "KECCAK-384", "2c23146a63a29acf99e73b88f8c24eaa7dc60aa771780ccc006afbfa8fe2479b2dd2b21362337441ac12b515911957ff" }, + { "KECCAK-512", "0eab42de4c3ceb9235fc91acffe746b29c29a8c366b7c60e4e67c466f36a4304c00fa9caf9d87976ba469bcbe06713b435f091ef2769fb160cdab33d3670680e" }, + }; + + static private byte[] shortMsg = Hex.decode("54686520717569636b2062726f776e20666f78206a756d7073206f76657220746865206c617a7920646f67"); + + static private String[][] shortVectors = + { + { "KECCAK-224", "310aee6b30c47350576ac2873fa89fd190cdc488442f3ef654cf23fe" }, + { "KECCAK-256", "4d741b6f1eb29cb2a9b9911c82f56fa8d73b04959d3d9d222895df6c0b28aa15" }, + { "KECCAK-384", "283990fa9d5fb731d786c5bbee94ea4db4910f18c62c03d173fc0a5e494422e8a0b3da7574dae7fa0baf005e504063b3" }, + { "KECCAK-512", "d135bb84d0439dbac432247ee573a23ea7d3c9deb2a968eb31d47c4fb45f1ef4422d6c531b5b9bd6f449ebcc449ea94d0a8f05f62130fda612da53c79659f609" }, + }; + + public String getName() + { + return "KECCAK"; + } + + void test(String algorithm, byte[] message, String expected) + throws Exception + { + MessageDigest digest = MessageDigest.getInstance(algorithm, provider); + + byte[] result = digest.digest(message); + byte[] result2 = digest.digest(message); + + // test zero results valid + if (!MessageDigest.isEqual(result, Hex.decode(expected))) + { + fail("null result not equal for " + algorithm); + } + + // test one digest the same message with the same instance + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 1 not equal"); + } + + if (!MessageDigest.isEqual(result, Hex.decode(expected))) + { + fail("Result object 1 not equal"); + } + + // test two, single byte updates + for (int i = 0; i < message.length; i++) + { + digest.update(message[i]); + } + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 2 not equal"); + } + + // test three, two half updates + digest.update(message, 0, message.length/2); + digest.update(message, message.length/2, message.length-message.length/2); + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 3 not equal"); + } + + // test four, clone test + digest.update(message, 0, message.length/2); + MessageDigest d = (MessageDigest)digest.clone(); + digest.update(message, message.length/2, message.length-message.length/2); + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 4(a) not equal"); + } + + d.update(message, message.length/2, message.length-message.length/2); + result2 = d.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 4(b) not equal"); + } + + // test five, check reset() method + digest.update(message, 0, message.length/2); + digest.reset(); + digest.update(message, 0, message.length/2); + digest.update(message, message.length/2, message.length-message.length/2); + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 5 not equal"); + } + + } + + public void performTest() + throws Exception + { + for (int i = 0; i != nullVectors.length; i++) + { + test(nullVectors[i][0], nullMsg, nullVectors[i][1]); + test(shortVectors[i][0], shortMsg, shortVectors[i][1]); + } + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new KeccakTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/KeyStoreTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/KeyStoreTest.java new file mode 100644 index 000000000..eedf5ac27 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/KeyStoreTest.java @@ -0,0 +1,419 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Date; +import java.util.Hashtable; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.jce.X509Principal; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.x509.X509V3CertificateGenerator; + +/** + * Exercise the various key stores, making sure we at least get back what we put in! + *

+ * This tests both the BKS, and the UBER key store. + */ +public class KeyStoreTest + extends SimpleTest +{ + static char[] passwd = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; + + byte[] v1BKS = Base64.decode( + "AAAAAQAAABTqZbNMyPjsFazhFplWWDMBLPRdRAAABcYEAAdhbmRyb2lkAAAB" + + "NOifkPwAAAAAAAAAPAAAABTZOLhcyhB0gKyfoDvyQbpzftB7GgAABEYPrZP8" + + "q20AJLETjDv0K9C5rIl1erpyvpv20bqcbghK6wD0b8OP5/XzOz/8knhxmqJZ" + + "3yRJMw=="); + byte[] v2BKS = Base64.decode( + "AAAAAgAAABSkmTXz4VIznO1SSUqsIHdxWcxsuQAABFMEAAdhbmRyb2lkAAABN" + + "OifkPwAAAAAAAAAPAAAABTZOLhcyhB0gKyfoDvyQbpzftB7GgAABEYPrZP8q2" + + "0AJLETjDv0K9C5rIl1erpyvpv20bqcbghK6wBO59KOGPvSrmJpd32P6ZAh9qLZJw=="); + + byte[] v1UBER = Base64.decode( + "AAAAAQAAABRP0F6p2p3FyQKqyJiJt3NbvdybiwAAB2znqrO779YIW5gMtbt+" + + "NUs96VPPcfZiKJPg7RKH7Yu3CQB0/g9nYsvgFB0fQ05mHcW3KjntN2/31A6G" + + "i00n4ZnUTjJL16puZnQrloeGXxFy58tjwkFuwJ7V7ELYgiZlls0beHSdDGQW" + + "iyYECwWs1la/"); + byte[] v2UBER = Base64.decode( + "AAAAAgAAABQ/D9k3376OG/REg4Ams9Up332tLQAABujoVcsRcKWwhlo4mMg5" + + "lF2vJfK+okIYecJGWCvdykF5r8kDn68llt52IDXDkpRXVXcNJ0/aD7sa7iZ0" + + "SL0TAwcfp/9v4j/w8slj/qgO0i/76+zROrP0NGFIa5k/iOg5Z0Tj77muMaJf" + + "n3vLlIHa4IsX"); + + byte[] negSaltBKS = Base64.decode( + "AAAAAv////+WnyglO06djy6JgCxGiIemnZdcOwAAB2AEAAdhbmRyb2lkAAAB" + + "NOifkPwAAAAAAAAAPAAAABTZOLhcyhB0gKyfoDvyQbpzftB7GgAABEYPrZP8" + + "q20AJLETjDv0K9C5rIl1erpyvpv20bqcbghK6wDrg6gUHsh27wNjUwkR+REe" + + "NeFYBg=="); + + char[] oldStorePass = "fredfred".toCharArray(); + + public void ecStoreTest( + String storeName) + throws Exception + { + X9ECParameters x9 = ECNamedCurveTable.getByName("prime239v1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec ecSpec = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); + + g.initialize(ecSpec, new SecureRandom()); + + KeyPair keyPair = g.generateKeyPair(); + + PublicKey pubKey = keyPair.getPublic(); + PrivateKey privKey = keyPair.getPrivate(); + + // + // distinguished name table. + // + Hashtable attrs = new Hashtable(); + Vector order = new Vector(); + + attrs.put(X509Principal.C, "AU"); + attrs.put(X509Principal.O, "The Legion of the Bouncy Castle"); + attrs.put(X509Principal.L, "Melbourne"); + attrs.put(X509Principal.ST, "Victoria"); + attrs.put(X509Principal.E, "feedback-crypto@bouncycastle.org"); + + order.addElement(X509Principal.C); + order.addElement(X509Principal.O); + order.addElement(X509Principal.L); + order.addElement(X509Principal.ST); + order.addElement(X509Principal.E); + + // + // create the certificate - version 3 + // + X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); + + certGen.setSerialNumber(BigInteger.valueOf(1)); + certGen.setIssuerDN(new X509Principal(order, attrs)); + certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000)); + certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000)); + certGen.setSubjectDN(new X509Principal(order, attrs)); + certGen.setPublicKey(pubKey); + certGen.setSignatureAlgorithm("ECDSAwithSHA1"); + + Certificate[] chain = new Certificate[1]; + + try + { + X509Certificate cert = certGen.generate(privKey); + + cert.checkValidity(new Date()); + + cert.verify(pubKey); + + ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded()); + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + cert = (X509Certificate)fact.generateCertificate(bIn); + + chain[0] = cert; + } + catch (Exception e) + { + fail("error generating cert - " + e.toString()); + } + + KeyStore store = KeyStore.getInstance(storeName, "BC"); + + store.load(null, null); + + store.setKeyEntry("private", privKey, passwd, chain); + + // + // write out and read back store + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store.store(bOut, passwd); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + + // + // start with a new key store + // + store = KeyStore.getInstance(storeName, "BC"); + + store.load(bIn, passwd); + + // + // load the private key + // + privKey = (PrivateKey)store.getKey("private", passwd); + + // + // double public key encoding test + // + byte[] pubEnc = pubKey.getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(pubKey.getAlgorithm(), "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + + pubKey = (PublicKey)keyFac.generatePublic(pubX509); + + pubEnc = pubKey.getEncoded(); + keyFac = KeyFactory.getInstance(pubKey.getAlgorithm(), "BC"); + pubX509 = new X509EncodedKeySpec(pubEnc); + + pubKey = (PublicKey)keyFac.generatePublic(pubX509); + + // + // double private key encoding test + // + byte[] privEnc = privKey.getEncoded(); + + keyFac = KeyFactory.getInstance(privKey.getAlgorithm(), "BC"); + + PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); + privKey = (PrivateKey)keyFac.generatePrivate(privPKCS8); + + keyFac = KeyFactory.getInstance(privKey.getAlgorithm(), "BC"); + privPKCS8 = new PKCS8EncodedKeySpec(privEnc); + privKey = (PrivateKey)keyFac.generatePrivate(privPKCS8); + } + + public void keyStoreTest( + String storeName) + throws Exception + { + KeyStore store = KeyStore.getInstance(storeName, "BC"); + + store.load(null, null); + + KeyPairGenerator gen = KeyPairGenerator.getInstance("RSA", "BC"); + + gen.initialize(1024, new SecureRandom()); + + KeyPair pair = gen.generateKeyPair(); + RSAPrivateKey privKey = (RSAPrivateKey)pair.getPrivate(); + RSAPublicKey pubKey = (RSAPublicKey)pair.getPublic(); + BigInteger modulus = privKey.getModulus(); + BigInteger privateExponent = privKey.getPrivateExponent(); + + + // + // distinguished name table. + // + Hashtable attrs = new Hashtable(); + Vector order = new Vector(); + + attrs.put(X509Principal.C, "AU"); + attrs.put(X509Principal.O, "The Legion of the Bouncy Castle"); + attrs.put(X509Principal.L, "Melbourne"); + attrs.put(X509Principal.ST, "Victoria"); + attrs.put(X509Principal.EmailAddress, "feedback-crypto@bouncycastle.org"); + + order.addElement(X509Principal.C); + order.addElement(X509Principal.O); + order.addElement(X509Principal.L); + order.addElement(X509Principal.ST); + order.addElement(X509Principal.EmailAddress); + + // + // extensions + // + + // + // create the certificate. + // + X509V3CertificateGenerator certGen = new X509V3CertificateGenerator(); + + certGen.setSerialNumber(BigInteger.valueOf(1)); + certGen.setIssuerDN(new X509Principal(order, attrs)); + certGen.setNotBefore(new Date(System.currentTimeMillis() - 50000)); + certGen.setNotAfter(new Date(System.currentTimeMillis() + 50000)); + certGen.setSubjectDN(new X509Principal(order, attrs)); + certGen.setPublicKey(pubKey); + certGen.setSignatureAlgorithm("MD5WithRSAEncryption"); + + Certificate[] chain = new Certificate[1]; + + try + { + X509Certificate cert = certGen.generate(privKey); + + cert.checkValidity(new Date()); + + cert.verify(pubKey); + + ByteArrayInputStream bIn = new ByteArrayInputStream(cert.getEncoded()); + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + cert = (X509Certificate)fact.generateCertificate(bIn); + + chain[0] = cert; + } + catch (Exception e) + { + fail("error generating cert - " + e.toString()); + } + + store.setKeyEntry("private", privKey, passwd, chain); + + // + // write out and read back store + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store.store(bOut, passwd); + + ByteArrayInputStream bIn = new ByteArrayInputStream(bOut.toByteArray()); + + // + // start with a new key store + // + store = KeyStore.getInstance(storeName, "BC"); + + store.load(bIn, passwd); + + // + // verify public key + // + privKey = (RSAPrivateKey)store.getKey("private", passwd); + + if (!privKey.getModulus().equals(modulus)) + { + fail("private key modulus wrong"); + } + else if (!privKey.getPrivateExponent().equals(privateExponent)) + { + fail("private key exponent wrong"); + } + + // + // verify certificate + // + Certificate cert = store.getCertificateChain("private")[0]; + + cert.verify(pubKey); + } + + private void oldStoreTest() + throws Exception + { + checkStore(KeyStore.getInstance("BKS", "BC"), v1BKS); + checkStore(KeyStore.getInstance("BKS", "BC"), v2BKS); + checkStore(KeyStore.getInstance("UBER", "BC"), v1UBER); + checkStore(KeyStore.getInstance("UBER", "BC"), v2UBER); + + checkOldStore(KeyStore.getInstance("BKS-V1", "BC"), v1BKS); + checkOldStore(KeyStore.getInstance("BKS-V1", "BC"), v2BKS); + } + + private void checkStore(KeyStore ks, byte[] data) + throws Exception + { + ks.load(new ByteArrayInputStream(data), oldStorePass); + + if (!ks.containsAlias("android")) + { + fail("cannot find alias"); + } + + Key key = ks.getKey("android", oldStorePass); + if (key == null) + { + fail("cannot find key"); + } + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + ks.store(bOut, oldStorePass); + } + + private void checkOldStore(KeyStore ks, byte[] data) + throws Exception + { + ks.load(new ByteArrayInputStream(data), oldStorePass); + + if (!ks.containsAlias("android")) + { + fail("cannot find alias"); + } + + Key key = ks.getKey("android", oldStorePass); + if (key == null) + { + fail("cannot find key"); + } + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + ks.store(bOut, oldStorePass); + + if (data.length != bOut.toByteArray().length) + { + fail("Old version key store write incorrect"); + } + } + + private void checkException() + throws Exception + { + KeyStore ks = KeyStore.getInstance("BKS", "BC"); + + try + { + ks.load(new ByteArrayInputStream(negSaltBKS), oldStorePass); + } + catch (IOException e) + { + if (!e.getMessage().equals("Invalid salt detected")) + { + fail("negative salt length not detected"); + } + } + } + + public String getName() + { + return "KeyStore"; + } + + public void performTest() + throws Exception + { + keyStoreTest("BKS"); + keyStoreTest("UBER"); + keyStoreTest("BKS-V1"); + ecStoreTest("BKS"); + oldStoreTest(); + checkException(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new KeyStoreTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/MQVTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/MQVTest.java new file mode 100644 index 000000000..dc5f3cb02 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/MQVTest.java @@ -0,0 +1,146 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; +import java.security.spec.ECFieldFp; +import java.security.spec.ECParameterSpec; +import java.security.spec.EllipticCurve; + +import javax.crypto.KeyAgreement; + +import com.fr.third.org.bouncycastle.jcajce.spec.MQVParameterSpec; +import com.fr.third.org.bouncycastle.jce.ECPointUtil; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.MQVPrivateKeySpec; +import com.fr.third.org.bouncycastle.jce.spec.MQVPublicKeySpec; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class MQVTest + extends SimpleTest +{ + public String getName() + { + return "MQV"; + } + + public void performTest() + throws Exception + { + testECMQVDeprecated(); + testECMQV(); + } + + private void testECMQVDeprecated() + throws Exception + { + KeyPairGenerator g = KeyPairGenerator.getInstance("ECMQV", "BC"); + + EllipticCurve curve = new EllipticCurve( + new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + + ECParameterSpec ecSpec = new ECParameterSpec( + curve, + ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n + 1); // h + + g.initialize(ecSpec, new SecureRandom()); + + // + // U side + // + KeyPair U1 = g.generateKeyPair(); + KeyPair U2 = g.generateKeyPair(); + + KeyAgreement uAgree = KeyAgreement.getInstance("ECMQV", "BC"); + uAgree.init(new MQVPrivateKeySpec(U1.getPrivate(), U2.getPrivate(), U2.getPublic())); + + // + // V side + // + KeyPair V1 = g.generateKeyPair(); + KeyPair V2 = g.generateKeyPair(); + + KeyAgreement vAgree = KeyAgreement.getInstance("ECMQV", "BC"); + vAgree.init(new MQVPrivateKeySpec(V1.getPrivate(), V2.getPrivate(), V2.getPublic())); + + // + // agreement + // + uAgree.doPhase(new MQVPublicKeySpec(V1.getPublic(), V2.getPublic()), true); + vAgree.doPhase(new MQVPublicKeySpec(U1.getPublic(), U2.getPublic()), true); + + BigInteger ux = new BigInteger(uAgree.generateSecret()); + BigInteger vx = new BigInteger(vAgree.generateSecret()); + + if (!ux.equals(vx)) + { + fail("Deprecated Agreement failed"); + } + } + + private void testECMQV() + throws Exception + { + KeyPairGenerator g = KeyPairGenerator.getInstance("ECMQV", "BC"); + + EllipticCurve curve = new EllipticCurve( + new ECFieldFp(new BigInteger("883423532389192164791648750360308885314476597252960362792450860609699839")), // q + new BigInteger("7fffffffffffffffffffffff7fffffffffff8000000000007ffffffffffc", 16), // a + new BigInteger("6b016c3bdcf18941d0d654921475ca71a9db2fb27d1d37796185c2942c0a", 16)); // b + + ECParameterSpec ecSpec = new ECParameterSpec( + curve, + ECPointUtil.decodePoint(curve, Hex.decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")), // G + new BigInteger("883423532389192164791648750360308884807550341691627752275345424702807307"), // n + 1); // h + + g.initialize(ecSpec, new SecureRandom()); + + // + // U side + // + KeyPair U1 = g.generateKeyPair(); + KeyPair U2 = g.generateKeyPair(); + + // + // V side + // + KeyPair V1 = g.generateKeyPair(); + KeyPair V2 = g.generateKeyPair(); + + KeyAgreement uAgree = KeyAgreement.getInstance("ECMQV", "BC"); + uAgree.init(U1.getPrivate(), new MQVParameterSpec(U2, V2.getPublic())); + + KeyAgreement vAgree = KeyAgreement.getInstance("ECMQV", "BC"); + vAgree.init(V1.getPrivate(), new MQVParameterSpec(V2, U2.getPublic())); + + // + // agreement + // + uAgree.doPhase(V1.getPublic(), true); + vAgree.doPhase(U1.getPublic(), true); + + BigInteger ux = new BigInteger(uAgree.generateSecret()); + BigInteger vx = new BigInteger(vAgree.generateSecret()); + + if (!ux.equals(vx)) + { + fail("Agreement failed"); + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new MQVTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/MacTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/MacTest.java new file mode 100644 index 000000000..29a17a867 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/MacTest.java @@ -0,0 +1,186 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Security; + +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * MAC tester - vectors from + * FIP 81 and + * FIP 113. + */ +public class MacTest + extends SimpleTest +{ + static byte[] keyBytes = Hex.decode("0123456789abcdef"); + static byte[] ivBytes = Hex.decode("1234567890abcdef"); + + static byte[] input = Hex.decode("37363534333231204e6f77206973207468652074696d6520666f7220"); + + static byte[] output1 = Hex.decode("f1d30f68"); + static byte[] output2 = Hex.decode("58d2e77e"); + static byte[] output3 = Hex.decode("cd647403"); + + static byte[] keyBytesISO9797 = Hex.decode("7CA110454A1A6E570131D9619DC1376E"); + + static byte[] inputISO9797 = "Hello World !!!!".getBytes(); + + static byte[] outputISO9797 = Hex.decode("F09B856213BAB83B"); + + static byte[] inputDesEDE64 = "Hello World !!!!".getBytes(); + + static byte[] outputDesEDE64 = Hex.decode("862304d33af01096"); + + public MacTest() + { + } + + private void aliasTest(SecretKey key, String primary, String[] aliases) + throws Exception + { + Mac mac = Mac.getInstance(primary, "BC"); + + // + // standard DAC - zero IV + // + mac.init(key); + + mac.update(input, 0, input.length); + + byte[] ref = mac.doFinal(); + + for (int i = 0; i != aliases.length; i++) + { + mac = Mac.getInstance(aliases[i], "BC"); + + mac.init(key); + + mac.update(input, 0, input.length); + + byte[] out = mac.doFinal(); + if (!areEqual(out, ref)) + { + fail("Failed - expected " + new String(Hex.encode(ref)) + " got " + new String(Hex.encode(out))); + } + } + } + + public void performTest() + throws Exception + { + SecretKey key = new SecretKeySpec(keyBytes, "DES"); + byte[] out; + Mac mac; + + mac = Mac.getInstance("DESMac", "BC"); + + // + // standard DAC - zero IV + // + mac.init(key); + + mac.update(input, 0, input.length); + + out = mac.doFinal(); + + if (!areEqual(out, output1)) + { + fail("Failed - expected " + new String(Hex.encode(output1)) + " got " + new String(Hex.encode(out))); + } + + // + // mac with IV. + // + mac.init(key, new IvParameterSpec(ivBytes)); + + mac.update(input, 0, input.length); + + out = mac.doFinal(); + + if (!areEqual(out, output2)) + { + fail("Failed - expected " + new String(Hex.encode(output2)) + " got " + new String(Hex.encode(out))); + } + + // + // CFB mac with IV - 8 bit CFB mode + // + mac = Mac.getInstance("DESMac/CFB8", "BC"); + + mac.init(key, new IvParameterSpec(ivBytes)); + + mac.update(input, 0, input.length); + + out = mac.doFinal(); + + if (!areEqual(out, output3)) + { + fail("Failed - expected " + new String(Hex.encode(output3)) + " got " + new String(Hex.encode(out))); + } + + // + // ISO9797 algorithm 3 using DESEDE + // + key = new SecretKeySpec(keyBytesISO9797, "DESEDE"); + + mac = Mac.getInstance("ISO9797ALG3", "BC"); + + mac.init(key); + + mac.update(inputISO9797, 0, inputISO9797.length); + + out = mac.doFinal(); + + if (!areEqual(out, outputISO9797)) + { + fail("Failed - expected " + new String(Hex.encode(outputISO9797)) + " got " + new String(Hex.encode(out))); + } + + // + // 64bit DESede Mac + // + key = new SecretKeySpec(keyBytesISO9797, "DESEDE"); + + mac = Mac.getInstance("DESEDE64", "BC"); + + mac.init(key); + + mac.update(inputDesEDE64, 0, inputDesEDE64.length); + + out = mac.doFinal(); + + if (!areEqual(out, outputDesEDE64)) + { + fail("Failed - expected " + new String(Hex.encode(outputDesEDE64)) + " got " + new String(Hex.encode(out))); + } + + aliasTest(new SecretKeySpec(keyBytesISO9797, "DESede"), "DESedeMac64withISO7816-4Padding", + new String[] { "DESEDE64WITHISO7816-4PADDING", "DESEDEISO9797ALG1MACWITHISO7816-4PADDING", "DESEDEISO9797ALG1WITHISO7816-4PADDING" }); + + aliasTest(new SecretKeySpec(keyBytesISO9797, "DESede"), "ISO9797ALG3WITHISO7816-4PADDING", + new String[] { "ISO9797ALG3MACWITHISO7816-4PADDING" }); + + aliasTest(new SecretKeySpec(keyBytes, "DES"), "DES64", + new String[] { "DESMAC64" }); + } + + public String getName() + { + return "Mac"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new MacTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/MultiCertStoreTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/MultiCertStoreTest.java new file mode 100644 index 000000000..9031ce309 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/MultiCertStoreTest.java @@ -0,0 +1,96 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import com.fr.third.org.bouncycastle.jce.MultiCertStoreParameters; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +import java.io.ByteArrayInputStream; +import java.security.Security; +import java.security.cert.CertStore; +import java.security.cert.CertificateFactory; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.X509CRL; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +public class MultiCertStoreTest + extends SimpleTest +{ + + public void performTest() + throws Exception + { + basicTest(); + } + + private void basicTest() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate rootCert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream( + CertPathTest.rootCertBin)); + X509Certificate interCert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream( + CertPathTest.interCertBin)); + X509Certificate finalCert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream( + CertPathTest.finalCertBin)); + X509CRL rootCrl = (X509CRL)cf.generateCRL(new ByteArrayInputStream( + CertPathTest.rootCrlBin)); + X509CRL interCrl = (X509CRL)cf + .generateCRL(new ByteArrayInputStream( + CertPathTest.interCrlBin)); + + // Testing CollectionCertStore generation from List + List list = new ArrayList(); + list.add(rootCert); + list.add(interCert); + list.add(finalCert); + list.add(rootCrl); + list.add(interCrl); + CollectionCertStoreParameters ccsp = new CollectionCertStoreParameters(list); + CertStore store1 = CertStore.getInstance("Collection", ccsp, "BC"); + CertStore store2 = CertStore.getInstance("Collection", ccsp, "BC"); + + List storeList = new ArrayList(); + storeList.add(store1); + storeList.add(store2); + CertStore store = CertStore.getInstance("Multi", new MultiCertStoreParameters(storeList)); + + // Searching for rootCert by subjectDN + X509CertSelector targetConstraints = new X509CertSelector(); + targetConstraints.setSubject(rootCert.getSubjectX500Principal().getName()); + Collection certs = store.getCertificates(targetConstraints); + + if (certs.size() != 2 || !certs.contains(rootCert)) + { + fail("2 rootCerts not found by subjectDN"); + } + + store = CertStore.getInstance("Multi", new MultiCertStoreParameters(storeList, false)); + certs = store.getCertificates(targetConstraints); + + if (certs.size() != 1 || !certs.contains(rootCert)) + { + fail("1 rootCert not found by subjectDN"); + } + } + + public String getName() + { + return "MultiCertStore"; + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new MultiCertStoreTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NISTCertPathTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NISTCertPathTest.java new file mode 100644 index 000000000..b05e98c43 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NISTCertPathTest.java @@ -0,0 +1,5173 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.security.GeneralSecurityException; +import java.security.Security; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertPathBuilderResult; +import java.security.cert.CertStore; +import java.security.cert.CertificateFactory; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.HashSet; +import java.util.Set; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + + +/* + * These tests are taken from the NIST X.509 Validation Test Suite + * available at: http://csrc.nist.gov/pki/testing/x509paths.html + * + * Only the relevant certificate and crl data has been kept, in order + * to keep the class size to a minimum. + * + */ + +public class NISTCertPathTest + extends SimpleTest +{ + private static final String TEST_POLICY_1 = "2.16.840.1.101.3.1.48.1"; + private static final String TEST_POLICY_2 = "2.16.840.1.101.3.1.48.2"; + private static final String TEST_POLICY_3 = "2.16.840.1.101.3.1.48.3"; + private static final String TEST_POLICY_4 = "2.16.840.1.101.3.1.48.4"; + private static final String TEST_POLICY_5 = "2.16.840.1.101.3.1.48.5"; + + private static Set ANY; + private static Set TP1; + private static Set TP2; + private static Set TP3; + private static Set TP4; + private static Set TP1_TP2; + + static { + ANY = new HashSet(); + + TP1 = new HashSet(); + TP1.add(TEST_POLICY_1); + + TP2 = new HashSet(); + TP2.add(TEST_POLICY_2); + + TP3 = new HashSet(); + TP3.add(TEST_POLICY_3); + + TP4 = new HashSet(); + TP4.add(TEST_POLICY_4); + + TP1_TP2 = new HashSet(); + TP1_TP2.add(TEST_POLICY_1); + TP1_TP2.add(TEST_POLICY_2); + } + + /* + * + * FIELDS + * + */ + + private CertificateFactory fact; + + private X509Certificate trustedCert; + private X509CRL trustedCRL; + private Set trustedSet; + private int testCount; + private Vector testFail; + private StringBuffer resultBuf; + + public String getName() + { + return "NISTCertPathTest"; + } + + + public void performTest() + { + init(); + + test(" 1", TEST_1_DATA , true , false); + test(" 2", TEST_2_DATA , false, false); + test(" 3", TEST_3_DATA , false, false); + test(" 4", TEST_4_DATA , true , false); + test(" 5", TEST_5_DATA , false, false); + test(" 6", TEST_6_DATA , false, false); + test(" 7", TEST_7_DATA , true , false); + test(" 8", TEST_8_DATA , false, false); + test(" 9", TEST_9_DATA , false, false); + + test("10", TEST_10_DATA, false, false); + test("11", TEST_11_DATA, false, false); + test("12", TEST_12_DATA, true , false); + test("13", TEST_13_DATA, false, false); + test("14", TEST_14_DATA, false, false); + test("15", TEST_15_DATA, true , false); + test("16", TEST_16_DATA, true , false); + test("17", TEST_17_DATA, true , false); + test("18", TEST_18_DATA, true , false); + test("19", TEST_19_DATA, false, false); + + test("20", TEST_20_DATA, false, false); + test("21", TEST_21_DATA, false, false); + test("22", TEST_22_DATA, false, false); + test("23", TEST_23_DATA, false, false); + test("24", TEST_24_DATA, true , false); + test("25", TEST_25_DATA, false, false); + test("26", TEST_26_DATA, true , false); + test("27", TEST_27_DATA, true , false); + test("28", TEST_28_DATA, false, false); + test("29", TEST_29_DATA, false, false); + + test("30", TEST_30_DATA, true , false); + test("31", TEST_31_DATA, false, false); + test("32", TEST_32_DATA, false, false); + test("33", TEST_33_DATA, true , false); + + + + test("34a", TEST_34_DATA, ANY , true , true , false); + test("34b", TEST_34_DATA, ANY , false, true , false); + test("34c", TEST_34_DATA, TP1 , true , true , false); + test("34d", TEST_34_DATA, TP1 , false, true , false); + test("34e", TEST_34_DATA, TP2 , true , false, false); + test("34f", TEST_34_DATA, TP2 , false, true , false); + + test("35a", TEST_35_DATA, false, true , false); + test("35b", TEST_35_DATA, true , false, false); + + test("36a", TEST_36_DATA, false, true , false); + test("36b", TEST_36_DATA, true , false, false); + + test("37a", TEST_37_DATA, false, true , false); + test("37b", TEST_37_DATA, true , false, false); + + test("38a", TEST_38_DATA, false, true , false); + test("38b", TEST_38_DATA, true , false, false); + + test("39a", TEST_39_DATA, ANY , true , true , false); + test("39b", TEST_39_DATA, ANY , false, true , false); + test("39c", TEST_39_DATA, TP1 , true , true , false); + test("39d", TEST_39_DATA, TP1 , false, true , false); + test("39e", TEST_39_DATA, TP2 , true , false, false); + test("39f", TEST_39_DATA, TP2 , false, true , false); + + + test("40a", TEST_40_DATA, false, true , false); + test("40b", TEST_40_DATA, true , false, false); + + test("41a", TEST_41_DATA, false, true , false); + test("41b", TEST_41_DATA, true , false, false); + + test("42a", TEST_42_DATA, false, true , false); + test("42b", TEST_42_DATA, true , false, false); + + test("43a", TEST_43_DATA, false, true , false); + test("43b", TEST_43_DATA, true , false, false); + + test("44a", TEST_44_DATA, false, true , false); + test("44b", TEST_44_DATA, true , false, false); + + test("45a", TEST_45_DATA, false, false, false); + test("45b", TEST_45_DATA, true , false, false); + + test("46a", TEST_46_DATA, ANY , false, true , false); + test("46b", TEST_46_DATA, ANY , true , true , false); + test("46c", TEST_46_DATA, TP1 , true , true , false); + test("46d", TEST_46_DATA, TP1 , false, true , false); + test("46e", TEST_46_DATA, TP2 , true , false, false); + test("46f", TEST_46_DATA, TP2 , false, false, false); + + test("47a", TEST_47_DATA, false, false, false); + test("47b", TEST_47_DATA, true , false, false); + + test("48a", TEST_48_DATA, TP1 , false, true , false); + test("48b", TEST_48_DATA, TP1 , true , true , false); + test("48c", TEST_48_DATA, ANY , false, true , false); + test("48d", TEST_48_DATA, ANY , true , true , false); + test("48e", TEST_48_DATA, TP2 , false, true , false); + test("48f", TEST_48_DATA, TP2 , true , false, false); + + test("49a", TEST_49_DATA, TP1 , false, true , false); + test("49b", TEST_49_DATA, TP1 , true , true , false); + test("49c", TEST_49_DATA, TP3 , false, true , false); + test("49d", TEST_49_DATA, TP3 , true , false, false); + test("49e", TEST_49_DATA, ANY , false, true , false); + test("49f", TEST_49_DATA, ANY , true , true , false); + + test("50a", TEST_50_DATA, TP1 , false, true , false); + test("50b", TEST_50_DATA, TP1 , true , true , false); + test("50c", TEST_50_DATA, TP1_TP2 , false, true , false); + test("50d", TEST_50_DATA, TP1_TP2 , true , true , false); + test("50e", TEST_50_DATA, ANY , false, true , false); + test("50f", TEST_50_DATA, ANY , true , true , false); + + test("51a", TEST_51_DATA, false, true , false); + test("51b", TEST_51_DATA, true , false, false); + + test("52a", TEST_52_DATA, TP1 , false, true , false); + test("52b", TEST_52_DATA, TP1 , true , false, false); + test("52c", TEST_52_DATA, TP1_TP2 , false, true , false); + test("52d", TEST_52_DATA, TP1_TP2 , true , false, false); + test("52e", TEST_52_DATA, ANY , false, true , false); + test("52f", TEST_52_DATA, ANY , true , true , false); + + test("53a", TEST_53_DATA, TP1 , false, true , false); + test("53b", TEST_53_DATA, TP1 , true , true , false); + test("53c", TEST_53_DATA, TP1_TP2 , false, true , false); + test("53d", TEST_53_DATA, TP1_TP2 , true , true , false); + test("53e", TEST_53_DATA, TP4 , false, true , false); + test("53f", TEST_53_DATA, TP4 , true , false, false); + test("53g", TEST_53_DATA, ANY , false, true , false); + test("53h", TEST_53_DATA, ANY , true , true , false); + + test("54", TEST_54_DATA, false, false); + test("55", TEST_55_DATA, false, false); + test("56", TEST_56_DATA, true , false); + test("57", TEST_57_DATA, true , false); + test("58", TEST_58_DATA, false, false); + test("59", TEST_59_DATA, false, false); + + test("60", TEST_60_DATA, false, false); + test("61", TEST_61_DATA, false, false); + test("62", TEST_62_DATA, true , false); + test("63", TEST_63_DATA, true , false); + test("64", TEST_64_DATA, false, false); + test("65", TEST_65_DATA, false, false); + test("66", TEST_66_DATA, false, false); + test("67", TEST_67_DATA, true , false); + test("68", TEST_68_DATA, false, false); + test("69", TEST_69_DATA, false, false); + + test("70", TEST_70_DATA, false, false); + test("71", TEST_71_DATA, false, false); + test("72", TEST_72_DATA, false, false); + test("73", TEST_73_DATA, false, false); + test("74", TEST_74_DATA, true , false); + test("75", TEST_75_DATA, false, false); + test("76", TEST_76_DATA, false, false); + + resultBuf.append("NISTCertPathTest -- Failed: ").append(testFail.size()).append('/').append(testCount).append('\n'); + if (!testFail.isEmpty()) + { + fail(resultBuf.toString()); + } + } + + private void init() + { + try + { + fact = CertificateFactory.getInstance("X.509", "BC"); + trustedCert = (X509Certificate)fact + .generateCertificate(new ByteArrayInputStream(Base64 + .decode(Trust_Anchor_CP_01_01_crt))); + trustedCRL = (X509CRL)fact.generateCRL(new ByteArrayInputStream( + Base64.decode(Trust_Anchor_CRL_CP_01_01_crl))); + trustedSet = new HashSet(); + + byte[] _ncBytes = null; + byte[] _octBytes = trustedCert.getExtensionValue("2.5.29.30"); + if (_octBytes != null) + { + ASN1InputStream _ais = new ASN1InputStream( + new ByteArrayInputStream(_octBytes)); + ASN1OctetString _oct = ASN1OctetString.getInstance(_ais + .readObject()); + _ais.close(); + _ncBytes = _oct.getOctets(); + } + + trustedSet.add(new TrustAnchor(trustedCert, _ncBytes)); + testCount = 0; + testFail = new Vector(); + resultBuf = new StringBuffer(); + } + catch (Exception ex) + { + throw new RuntimeException(ex.getMessage()); + } + } + + private X509Certificate decodeCertificate(String _str) + throws GeneralSecurityException + { + + return (X509Certificate)fact + .generateCertificate(new ByteArrayInputStream(Base64 + .decode(_str))); + } + + private X509CRL decodeCRL(String _str) + throws GeneralSecurityException + { + + return (X509CRL)fact.generateCRL(new ByteArrayInputStream(Base64 + .decode(_str))); + } + + private CertStore makeCertStore(String[] _strs) + throws GeneralSecurityException + { + + Vector _vec = new Vector(); + _vec.addElement(trustedCRL); + + for (int i = 0; i < _strs.length; i++) + { + if (_strs[i].startsWith("MIIC")) + { + _vec.addElement(fact + .generateCertificate(new ByteArrayInputStream(Base64 + .decode(_strs[i])))); + } + else if (_strs[i].startsWith("MIIB")) + { + _vec.addElement(fact.generateCRL(new ByteArrayInputStream( + Base64.decode(_strs[i])))); + } + else + { + throw new IllegalArgumentException("Invalid certificate or crl"); + } + } + + // Insert elements backwards to muck up forward ordering dependency + Vector _vec2 = new Vector(); + for (int i = _vec.size() - 1; i >= 0; i--) + { + _vec2.add(_vec.elementAt(i)); + } + + return CertStore.getInstance("Collection", + new CollectionCertStoreParameters(_vec2), "BC"); + } + + private void test(String _name, String[] _data, boolean _accept, + boolean _debug) + { + + test(_name, _data, null, false, _accept, _debug); + } + + private void test(String _name, String[] _data, boolean _explicit, + boolean _accept, boolean _debug) + { + + test(_name, _data, null, _explicit, _accept, _debug); + } + + private void test(String _name, String[] _data, Set _ipolset, + boolean _explicit, boolean _accept, boolean _debug) + { + + testCount++; + boolean _pass = true; + + try + { + CertPathBuilder _cpb = CertPathBuilder.getInstance("PKIX", "BC"); + X509Certificate _ee = decodeCertificate(_data[_data.length - 1]); + X509CertSelector _select = new X509CertSelector(); + _select.setSubject(_ee.getSubjectX500Principal().getEncoded()); + + PKIXBuilderParameters _param = new PKIXBuilderParameters( + trustedSet, _select); + _param.setExplicitPolicyRequired(_explicit); + _param.addCertStore(makeCertStore(_data)); + _param.setRevocationEnabled(true); + if (_ipolset != null) + { + _param.setInitialPolicies(_ipolset); + } + + CertPathBuilderResult _result = _cpb.build(_param); + + if (!_accept) + { + System.out.println("Accept when it should reject"); + _pass = false; + testFail.addElement(_name); + } + } + catch (Exception ex) + { + if (_accept) + { + System.out.println("Reject when it should accept"); + _pass = false; + testFail.addElement(_name); + } + } + + resultBuf.append("NISTCertPathTest -- ").append(_name).append(": ") + .append(_pass ? "\n" : "Failed.\n"); + } + + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new NISTCertPathTest()); + } + + /* + * Trust Anchor + * + */ + public static final String Trust_Anchor_CP_01_01_crt = + "MIICbDCCAdWgAwIBAgIDAYafMA0GCSqGSIb3DQEBBQUAMF4xCzAJBgNVBAYTAlVTMRgwFg" + + "YDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsTA0RvRDEQMA4GA1UECxMHVGVzdGlu" + + "ZzEVMBMGA1UEAxMMVHJ1c3QgQW5jaG9yMB4XDTk5MDEwMTEyMDEwMFoXDTQ4MDEwMTEyMD" + + "EwMFowXjELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UE" + + "CxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5nMRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANPzucEztz+nJ/ZBHVyceZ2q0pUQt4TO2qPlWAw+" + + "TotWvz6qIS1QE/7zGS56yxHP89O4X1efnZeArx2VVxLfNNS9865N53ymINQETtpjYT49Ko" + + "03z8U8yfn68DlIBHi9sN31JEYzoUafF58Eu883lAwTQ6qQrJF4HbrzGIQqgitHAgMBAAGj" + + "ODA2MBEGA1UdDgQKBAirmuv5wudUjzAMBgNVHRMEBTADAQH/MBMGA1UdIwQMMAqACKua6/" + + "nC51SPMA0GCSqGSIb3DQEBBQUAA4GBABZWD2Gsh4tP62QSG8OFWUpo4TulIcFZLpGsaP4T" + + "/2Nt7lXUoIJMN7wWjqkmYf5/Rvo4HxNcimq3EkeYcrm1VoDueJUYGvRjcCY5mxkghI27Yl" + + "/fLKE9/BvQOrvYzBs2EqKrrT7m4VK0dRMR7CeVpmPP08z0Tti6uK2tzBplp1pF"; + public static final String Trust_Anchor_CRL_CP_01_01_crl = + "MIIBbzCB2QIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDFRydXN0IEFuY2hvchcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAiMCACAS" + + "cXDTk5MDEwMTEyMDAwMFowDDAKBgNVHRUEAwoBAaAjMCEwCgYDVR0UBAMCAQEwEwYDVR0j" + + "BAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEFBQADgYEAC7lqZwejJRW7QvzH11/7cYcL3r" + + "acgMxH3PSU/ufvyLk7ahR++RtHary/WeCvRdyznLiIOA8ZBiguWtVPqsNysNn7WLofQIVa" + + "+/TD3T+lece4e1NwGQvj5Q+e2wRtGXg+gCuTjTKUFfKRnWz7O7RyiJKKim0jtAF4RkCpLe" + + "bNChY="; + + + /* + * test1 + * + */ + + public static final String End_Certificate_CP_01_01_crt = + "MIIChjCCAe+gAwIBAgIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDEuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMY07G8M4FkOvF+6LpO7BKcDuXCKudfl1+bKSowj" + + "2GCza8uIiMfYSH5k+fYb43lGQeRh9yVHcfNQlE7yfGo3tgxGv5yWpeKvDMqL8Iy6Q0oIjm" + + "qH80ZOz21dUkermcckzTEOfe/R2fNpJPv8M24pq29SdYAqu+CpLDHFtws9O+q1AgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIrNv88bwFLtIwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEFBQADgYEAK4hP" + + "goWtZbHf6qWfRfmrPrz9hDH1644NrJop2Y7MXzuTtpo1zp4NCG4+ii0CSOfvhugc8yOmq3" + + "I6olgE0V16VtC5br2892UHYZ55Q4oQ9BWouVVlOyY9rogOB160BnsqBELFhT0Wf6mnbsdD" + + "G+BB5fFyeK61aYDWV84kS7cSX5w="; + public static final String[] TEST_1_DATA = new String[] { + End_Certificate_CP_01_01_crt, + }; + + /* + * test2 + * + */ + + public static final String Intermediate_Certificate_CP_01_02_crt = + "MIIClTCCAf6gAwIBAgIBAjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAxLjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDWOZ4hk+K6NX/l+OiHC4pfKCWFt+XM2n/TxwkqY+mt" + + "j9Co77rPPPtVA7mDKU4OiYT74mIWH52HQBZr+PRmOFh0Z9S1oTpLbxNLCDc6OmQKBo6iex" + + "SIt/jOatFFmzmTZ78Kq9s3nfrOVA83ggmPDTPkuG5GwcxPgFq0vRmAJ0CESQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQI5o5Am09NlOYwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEA3C7Ye5/Te14LIwo/LK2fnpobbQA3dhOn5UgqZ8lKbQ/HV1D8/eU9dK" + + "2v5gW43XvFq4whK0WKLBvBFchKtp9T1QX3CI2WCqdJRyqla6TkQsS36T17/ww2nzy1853Y" + + "hfDYNsge5XW8YZNfNjjVxcR3RnyFxPax1YIlISiGdI0dnag="; + public static final String Intermediate_CRL_CP_01_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI5o5Am09NlOYwDQYJKoZIhvcNAQEFBQADgYEAl26W" + + "g1Gqq3R93XPjghABVocfeIi8zcSJ0YAKqbifh5V3JCC8Piy19GzZdL244GqBDls44IAhKj" + + "YuXN2mSohdqwULbye4agAgfl37XhhwsBDTYwaJiv3njFQ6Ml7KJ3STmoIpmlLvrXibDuHX" + + "ocuNGo72ckhOdBpXd+PhgGuoTis="; + public static final String End_Certificate_CP_01_02_crt = + "MIIChjCCAe+gAwIBAgIBAzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMS4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDEuMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALwJrZT6bJXQnZzc3socZ/mNsEag4BTdym99ZCP2" + + "3PGsTCfV2z7+p4DehIFrn/N/a1d1nvyqRqpQGPU86tl1CWgFtXS+zCctDR71P76bjd6yef" + + "5vxxdO/SBIRHfQTjM8F3BTLkrC+PVl5wbaLcEXRORXrFvBvsj0oqwZ4C8ZObh/AgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIf5mSjuNhs/gwEwYDVR0jBAwwCoAI5o5Am09NlOYwDQYJKoZIhvcNAQEFBQADgYEAK7wd" + + "MyLlIZ/Qsqj3/A3Gat0d5BORtFTZH0VdlVVOWN1JCZxrnjeIFB92NNzUROemxgBxzneuWN" + + "SlYlcpTk25pAbs6RMdbT8dovKQkQkF2TXeQ+4qktFaLQntVT8UsEzHR4Diw0/gH8tseGqF" + + "F7FyiW8ni6zInSO+embUKiibj9I="; + public static final String[] TEST_2_DATA = new String[] { + Intermediate_Certificate_CP_01_02_crt, + Intermediate_CRL_CP_01_02_crl, + End_Certificate_CP_01_02_crt + }; + + /* + * test3 + * + */ + + public static final String Intermediate_Certificate_CP_01_03_crt = + "MIIClTCCAf6gAwIBAgIBBDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAxLjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC4RZ0R82sA+BfyynFeoIDG7c5IlZ8HorEv+O4Ij3Oy" + + "7FR1MB4no8hDEBPBf5fCrAR/8PVxCZjVj2HOwnSAqUQgxo6WPcmkabux12k8kK6yeKq3b7" + + "u5fL6tb7eKElQzsz8Je4z4rCDkI10vV+X0VZ5Ip/Es428dw2KoN8eyGmw3+QIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIz08WhMpG2JswEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAQ+iqlFvbvDejO/m+RCHh2UuUau1FuABObkPOu2Tv9yTWvTSWDRygdO" + + "LQRiOLsjgrdXPdbDutVGjllBoTN8cdz3SWjCpampg5TBikArxmNEYMDQvL6n2lkUcetRJR" + + "gQ7TYLvFj9+SycKXfM5CUXAyCfcU/QwDghhZgc99AuDZtJc="; + public static final String Intermediate_CRL_CP_01_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMS4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIz08WhMpG2JswDQYJKoZIhvcNAQEFBQADgYEAoyO/" + + "xcpJ0Obj4rTXhHFd7XMzslt79njkEgdwnon9BaYB3xSmkEXCMwLMurrjVYKaB6SWAiPeUv" + + "G7ScDHJE6UFVJwIt4vP/M7gTOJ7uak33aWi9e5DeIuLqE6pFqTGu+uoBkkd82SHg2GhJhZ" + + "VXDtJ3UcO/3JQPbslc02s9HiRBg="; + public static final String End_Certificate_CP_01_03_crt = + "MIIChjCCAe+gAwIBAgIBBTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMS4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDEuMDMwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANAD1vQj//4BGEXW1Q7HX/AUyFJFyHoYcvg5y4u/" + + "8Sj6okriXj3knnBKDiJLpKfcsO5p5MQS5QzAc+lxErXD+duiw8lm61hj0StsRzhDFsaC1g" + + "akjzU70R2Tmz/djUnqO3aa2wICc4NVAXnIMMsH/b6XXFZpC0/C32TPTv9aa9mrAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIPw2wltiRqz4wEwYDVR0jBAwwCoAIz08WhMpG2JswDQYJKoZIhvcNAQEFBQADgYEAln42" + + "iR3eHyazF8CRjS9Jnas/26MaBtjUyDtcSjTVDWFlccwrQ7TgtzjkNm9fCmgSyvryDnUYGM" + + "DoEjwYNLIgtCAkVIEBTmJvlqiPHH+tV5oJvIav+Fn8okHpuuK44umDcdKiFWlOyxrShxzV" + + "3Bez/eHklaPTw/VsVhyh+Uru5zM="; + public static final String[] TEST_3_DATA = new String[] { + Intermediate_Certificate_CP_01_03_crt, + Intermediate_CRL_CP_01_03_crl, + End_Certificate_CP_01_03_crt + }; + + /* + * test4 + * + */ + + public static final String Intermediate_Certificate_1_CP_02_01_crt = + "MIIClTCCAf6gAwIBAgIBBjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05OTAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAyLjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC/lQLtWKzklgYuzhjMiK2CzFmzODsEY/JIVNdn9T8M" + + "W4ufpGwnfIV62EUHCFeMYydKBm8Hyjbjrz1otINJmrGL5WSAX1/UPtHy1chgXOsFYD6nAH" + + "jZAJJGw74nUbKw5+L1wUHU8qXABaaTrRpS1UdKSq4TCZ18NCjC4Oxcf/yDdQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQINsJcxaBqdugwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAOQP3iUX7FtJlL9nvu4F+8o/N5vr+OB28OsbYtW+Q1FzEfjkUGtT9Ri" + + "teradpN/xUnS/oj3BfqFtNANkYKrBeqRtm2VeOC3kdCVFnWFME2aoRAQZbWvOwCFc3yLA7" + + "JBdENtDNI54yYHMHPA4/2CuNQq1Iu1ektAS95DIe7ddxL18="; + public static final String Intermediate_Certificate_2_CP_02_01_crt = + "MIIClTCCAf6gAwIBAgIBBzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMi4wMTAeFw05OTAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLUNQLjAyLjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCx/mIo1Ma/IN8OR7KOjclvIwsv0JFXD/T258DruDZU" + + "uGoYiEbAc/ZN7R8OHI7dnv9pBfsvyEl7m2DVoLZnP0eXJTHjdZxb1TwPHoSIysi9u3xWlP" + + "Rg+v+GGfKLB9pL0m8SZh97SngerZI14w7vQy0kkXziGatSpBoXtWNmsHJNuQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIoI0mSmDmzZUwEwYDVR0jBAwwCoAINsJcxaBqdugwDQYJKoZI" + + "hvcNAQEFBQADgYEAcfs1pH12Qwdhv4NOJO2xxgMZZo8+A9Zl9c7RxsvuoZOOyCxoE9wT/l" + + "PdUpGoGxtIPoWQs1qXEXnAlXJCXjLCJUHIG1/E6gQUXW0Ty6Ztpc5Dz06pPTN2gt+41B3J" + + "sL/Klqc4iyCaWr8sYgEPQ8nColWRmIwk9gAasPNkNhyxA3Y="; + public static final String Intermediate_CRL_1_CP_02_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAINsJcxaBqdugwDQYJKoZIhvcNAQEFBQADgYEAlBaV" + + "VfrZqvyRhGXNYFik169nBHiNfKpw8k1YgFAQeNYdmfScq1KHmKzDhsx9kQteczBL7ltviK" + + "TN3CKlZW82c16mfd4yYx0l5tkU80lwKCHSUzx92+qrvYjSMup+bqSsi8JhqByBf6b0JbKf" + + "yx53Vpw1OCzjxrVHcfHPx8Q/vR4="; + public static final String Intermediate_CRL_2_CP_02_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1DUC4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIoI0mSmDmzZUwDQYJKoZIhvcNAQEFBQADgYEAhAHP" + + "QxpcrTTN0GXeOwoMXuQUoHMvezEpM0BYOVLzI3KbRXWa9iWZINr99cRQvonMtOGkhIH3iS" + + "wSNbsjmF9HX5UvNzrofOWataVP+macpCuNlK0NS3xxJjKRWOB9C1Ib7tiSSrQqIPcchlF6" + + "vofy2ALEL6Usa1UTVYMhzGYnVZU="; + public static final String End_Certificate_CP_02_01_crt = + "MIIChjCCAe+gAwIBAgIBCDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1DUC4wMi4wMTAeFw05OTAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDIuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOzYq2murB5ZjQd4wReI51Lc1F5VwK90OMGRfi71" + + "YvwdRjgCudeDXZGW5ayid82y+eTDKFSzo1Li/BPTUXMpeqHHMCmLeefqxAWmz3aDoilF8I" + + "Q53PlejnXJdntsal44w6WdP6ssiXlwzcZDnobAfuDTPgsnWWfzAkr1/LqEw/QZAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIP5tVdEyxotcwEwYDVR0jBAwwCoAIoI0mSmDmzZUwDQYJKoZIhvcNAQEFBQADgYEAkVx9" + + "S/20Hir8qMnfMpMGTgMKoVeWoljxim83IkNs1Xqe1oLGHdyDUA66uF8wPkoTqGrfDYvgBa" + + "5Mi0iJREnMWoiWvCe467+L1b2gtvRBMl9bcRj40bvelk0Wn4lBl3VuKXarP5M0PKT5OWvN" + + "2cPLNeXHvV6ZIrC4rmK2ISpIXX4="; + public static final String[] TEST_4_DATA = new String[] { + Intermediate_Certificate_1_CP_02_01_crt, + Intermediate_Certificate_2_CP_02_01_crt, + Intermediate_CRL_1_CP_02_01_crl, + Intermediate_CRL_2_CP_02_01_crl, + End_Certificate_CP_02_01_crt + }; + + /* + * test5 + * + */ + + public static final String Intermediate_Certificate_CP_02_02_crt = + "MIIClTCCAf6gAwIBAgIBCTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw00NzAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAyLjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDHJmlRKb+mjc61iiqGe9gx/VUMLNmGrXGRYKMmYSxO" + + "Q5sGLoztd2XtEgtZEPwvzd9KLKGP3XmgTrc4BGohqoFoG9Qb+w2ZGFwVC22GpeSoXc+J2u" + + "2t3uRKYgboHpB0Jk42XLy+2wSEtS+/er7cFu2ufdPsvT4J1AqiuZSco96vtQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIBvoP1E6PGiMwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAmOyFq2vZrUNDVWRcyzYvZhs1uQ4zgXtfqnPE0V19RgaYffCrSCI86z" + + "5kyDUyZwbGABMxBaVxEw536MesyDTdZdEVw6lN5RRtxr8/WEiSH6oI6t0xNxuNOkSNpz4d" + + "28HA4UfUvtXK8RK2YZnPAd6UXsRUPBPXKEpzy4v/9RyihSg="; + public static final String Intermediate_CRL_CP_02_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIBvoP1E6PGiMwDQYJKoZIhvcNAQEFBQADgYEAALlA" + + "f3IDWexcdkMQHWTdGeFe+bG5dBvVPL5ZyQUw9DWbLwrjw/Jm4v9t+HLjETLSymsFT4bW21" + + "OwnEiAAdaKT96k5t+sTyU5QQ6HL/jRXLHLGdCQgMFCglm5iNqaCLIFoMAVCaFkYtFUE3m/" + + "iVt+319JOh5UyshMuWrAEW0IGGQ="; + public static final String End_Certificate_CP_02_02_crt = + "MIIChjCCAe+gAwIBAgIBCjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDIuMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAL/Src6e8qXwL+KJs5+v+JsakZdSDqMAFJUMfA2O" + + "OO2TIqcvDFHzqesX+G+28MUwy6++ux07CD3FCaapgzBN4zO4RfKcamxFReKMKcEvNVVCOO" + + "wO4Lvku1Sad14oYyGLOMzZwZFjRp8paaz5g87k70EOPBLeDlFMcch36czw53sLAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIPoHc2Sfk6XUwEwYDVR0jBAwwCoAIBvoP1E6PGiMwDQYJKoZIhvcNAQEFBQADgYEAFHhm" + + "o6QRFdO1x1wp7Jb1QQAlChFfP8MrGVNK04Ur8f+wfkwIypTDifJ0AoFpjcM3Ohu9Ixvb9q" + + "3kCSIWKDnWtDWw1/dN8mPL5If5gGqPA0+wRbUKVKvduOg7hKr4mWjKw7oYiaJuIIoN9RRZ" + + "ejzltd0NEaODNPW/JaKeQUVgZbY="; + public static final String[] TEST_5_DATA = new String[] { + Intermediate_Certificate_CP_02_02_crt, + Intermediate_CRL_CP_02_02_crl, + End_Certificate_CP_02_02_crt + }; + + /* + * test6 + * + */ + + public static final String Intermediate_Certificate_CP_02_03_crt = + "MIIClTCCAf6gAwIBAgIBCzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAyLjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCaJ7NcOvb22F6HjMF1R/AORa4+pKFfFfd9teXPpVWC" + + "9InTq+alY11QaSj27Qg0znOIItmf2W/8Dub9sjnbg+SgAkoV5+CAkplodRNC8AbD4x8rh/" + + "fioQ8lb0Qb4Dn9I0n2wjOgitmMRdE2uW4uwVpH52vsMyenbDVxVI7jA4NS/wIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIC2T+/BkG93AwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEApr6kDXVY5jYt23wC9n3LmhoxDoWh8cBQxcWmr1wpVxIrCbaP0/y00a" + + "29wbewKfucUoh/W2OfjNcohjpKRrnVmOpi5vN7SmbZIHaxbKLzyQ7JwF17aznyCSZVrGpF" + + "A/S49T5rlCm8KDBcc2ym7gRJzwUApbC0Wws4Pg46czrpQlg="; + public static final String Intermediate_CRL_CP_02_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIC2T+/BkG93AwDQYJKoZIhvcNAQEFBQADgYEAlBFY" + + "vPxhFYsjFOIfQkd7MwKIi7vgPgoWTP5f+QlI0ison5n4N3rYJv31hTZRRRP99JZce1hY6J" + + "Qiv1OtkpG7VfQIhr0FAGxTNaJD6F6rLbGjG8cap4+VibFQf5gZv0XQcyW4akYiRqSXImYn" + + "NVlNyaxiJja+5GA9XVqvWOjjz4o="; + public static final String End_Certificate_CP_02_03_crt = + "MIIChjCCAe+gAwIBAgIBDDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMi4wMzAeFw00NzAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDIuMDMwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMlW6FOLwhRsKZM6p0ww4QEWjQzjpjYhKnz3BnLw" + + "SdGZqMe4wzZnDWc/0eyDOMCSYXIWQhlDMqQn2zCVPbDKzMRkdEeRSvE6ghhYP/hn3ipjSw" + + "D8QwaqofCp0sFkbDPke+xD2tMhLdUyNKynPjpSQmYtfoA98PD7so3cSAtrYuSDAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIc/X6kp7teCQwEwYDVR0jBAwwCoAIC2T+/BkG93AwDQYJKoZIhvcNAQEFBQADgYEAStub" + + "g3DzhJgzYO+ZmRc0acldZGwZFm6F1Ckc1JzQDgVHU0bnCANgBcJj49UV2MwbNKPQdVzdwo" + + "c91rfwrSY/PrvVQ9tUonZ28y/esFRBAdJTLf4u++p/gI3vfCvEXa5xVTIz1Hc+iKzAGKrI" + + "cveDHy3ZZluQ3J6tbHs2BhnQFXM="; + public static final String[] TEST_6_DATA = new String[] { + Intermediate_Certificate_CP_02_03_crt, + Intermediate_CRL_CP_02_03_crl, + End_Certificate_CP_02_03_crt + }; + + /* + * test7 + * + */ + + public static final String Intermediate_Certificate_CP_02_04_crt = + "MIIClTCCAf6gAwIBAgIBDTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAyLjA0MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDgZy2Xs5pIoJrT7GuagmKLrn8F9rj8p8w2wELorGhM" + + "1HJMVOurH+o+y6RXd0oMGJkKNrhjEnbHKm3PBYiLgpCjVEcFNhQF1OOxJ7RdahvA9ifsuw" + + "jV1TxTGq35jeaJYASRXb2TiNfzuPWSVm0MWr5zz+YB6NNuvjxwEBgZvNiV8QIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIWAOnkHkwSVkwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAMiHozz92EOhSXU/krwQVs0GNEWoAUH3LHt70Zr01dFzEF6QhA/wUa4" + + "+V4XwbMob+q4zGnTHj+tL9ChGWi3NDGELQ4cN64OMPsToGKkepLy+sDwdm9LaUP1bDvPxd" + + "v2hjlskJ7TEu4+6ltXSG/k36Jk8C0/I/ayNGbYcEcLyes3s="; + public static final String Intermediate_CRL_CP_02_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIWAOnkHkwSVkwDQYJKoZIhvcNAQEFBQADgYEAVtCi" + + "IocktnWOwWiaOc7tTUJvvH5+IYVyB/XhmMhF7cDbL292gyrnuh1+3+lHwZQBPoF9kzF0vt" + + "WaweG7mDvYKxENQODdph/VcnypgUiFTWRTIPB1ZXfCTMWYf2QSalpHRDR4vVsqF748QbcG" + + "E9mbzvLUz6NDA+Vf8wEwZehqSDM="; + public static final String End_Certificate_CP_02_04_crt = + "MIIChjCCAe+gAwIBAgIBDjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMi4wNDAeFw01MDAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDIuMDQwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALBX5GIQtvwswWwMDDPnphIk1rJSbcq7iClXLM2E" + + "kgvBu+hbOzb0v9mtl0KJB71TWJCfwceVQiXc3Gk+YduujAbZRVTkROf9UOWD9bfrI7g+52" + + "g4ms2n7evCO33b+kGEf4I014xl8dJDWtHK9Bhr+569RW9TzO06IeVeTD7whxMXAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIuKXv5WkUTWAwEwYDVR0jBAwwCoAIWAOnkHkwSVkwDQYJKoZIhvcNAQEFBQADgYEAiu0B" + + "yR5Ru8qVsgRqkOpCvrJnkqBAImbbR6+BUYH0juRxxKzKnbFOjU6a9WvkKpEBB8Q2xLynPN" + + "68ecLpnOynx3xj2sWWSVbsRKPy0iOesQblKrq3yHAm4lhzoWA8t1Xz29Ko1WxylDhyxGpR" + + "QAWsyGVCfJFlsZE0ibw3erlWTnA="; + public static final String[] TEST_7_DATA = new String[] { + Intermediate_Certificate_CP_02_04_crt, + Intermediate_CRL_CP_02_04_crl, + End_Certificate_CP_02_04_crt + }; + + /* + * test8 + * + */ + + public static final String Intermediate_Certificate_CP_02_05_crt = + "MIIClTCCAf6gAwIBAgIBDzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAyLjA1MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC2d80bD1RounqjKizkZJYPFUuVWZQ8W2nZDkEp8qR9" + + "fRWCAGOZGs84tgHj5gasmxy1mxJc9ogyQ2mcZhJRitRm5LVNuGevO6JmfqYtJxbW54aZGE" + + "5AWSRXqjJKJEih4VmPjA3vjQaSZSZJnu0DSnO82qWfu1ZUDlvIG6dfKJWRQQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQI3uNhI+QuI4owEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAG/+Rpk8dYrSFdaEO8Ch5tuvvKTOMi7W/DRA4B4xR7WyRJmosPB+37c" + + "teGKVzqFND22Xc8xQH/b/nxYW08sCSLAfN0cRusoSWwWSRtPO2f9fyC/BqCy2B2kQLFNPM" + + "Bk22jNFwLqPUeZn1UHN05RFAqVx325kpl2m1V7tw/mrXATI="; + public static final String Intermediate_CRL_CP_02_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMi4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI3uNhI+QuI4owDQYJKoZIhvcNAQEFBQADgYEAWZUI" + + "2VGY4pak0kICONP/CKvamYFs5txJfR69AC5tEJ+Fy3PmSeHkLUZf/oc9d8EEyr0MsIjRHj" + + "N4X4MquMlk4FflZcc8GblQK8LdXBK4Dy1SiXHA5GB3U1AmgzAzEQGwGRZnzWP5+rJ65upX" + + "vksAYyPQmruRM0O5sElctPn6B+Y="; + public static final String End_Certificate_CP_02_05_crt = + "MIICiDCCAfGgAwIBAgIBEDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMi4wNTAgGA8yMDUwMDEwMTEyMDEwMFoXDTQ4MDEwMTEyMD" + + "EwMFowYDELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UE" + + "CxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5nMRcwFQYDVQQDEw5Vc2VyMS1DUC4wMi4wNTCBnz" + + "ANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAviLKpW4iblWNLQfmBJJ+ruMgygmjRWfoFGya" + + "Ndv2ma0Ugqm5xXq8c0orbnezwSp+tnzZZhG5KDNZr5+z3krCkqOGGzuUvVLqeJxPOLu7Js" + + "y472nAA7+FhwfZrXUI+Vg9F4qF+Ye81ivDrYVAEmalCpCyHOAKdvwkwQjRucifu90CAwEA" + + "AaNSMFAwDgYDVR0PAQH/BAQDAgXgMBYGA1UdIAQPMA0wCwYJYIZIAWUDATABMBEGA1UdDg" + + "QKBAjgph7BA5L7dzATBgNVHSMEDDAKgAje42Ej5C4jijANBgkqhkiG9w0BAQUFAAOBgQBr" + + "MDMv9NWCTIQ3blMEqPiEyjiBhSJl88Cu797P4lIn+gc6E+0vZp61X7B2k5CHgsnxyVLK5e" + + "bwl0bYAPKwRI9yzHLrj71RNw8HA7PCRPn1GNrtBBbIpLE0/sqLo51UPu/377+CnzYhIycL" + + "tvS0KDLUTDSY/OowDcplF6Xwnt8cUQ=="; + public static final String[] TEST_8_DATA = new String[] { + Intermediate_Certificate_CP_02_05_crt, + Intermediate_CRL_CP_02_05_crl, + End_Certificate_CP_02_05_crt + }; + + /* + * test9 + * + */ + + public static final String Intermediate_Certificate_CP_03_01_crt = + "MIIClTCCAf6gAwIBAgIBETANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw0wMDAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAzLjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCuF8mub5cgUYZytrRjJ5Rhc2fgazGxWIj6EIKzeSpo" + + "FwScItRX9KxnTIXEBTguBk7eQUsbN8yu49/Mlq45EAnemyZRBWzLFLYLPCco7pyTsWm7Ps" + + "2FAGJ3vE9pC9xaZC+KrwF3Ho+DZNDwhj5InXTP8pChAIPfB8/7V/2mk0lN0wIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQI4mI6Ojs0onswEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAMVGzU6f4YOHpHla+YuGCjHOUZYrA9J25G3UFFoPr2JZEG+Fb5hRQUh" + + "4S1qUQKXn6dpVua+qTJDk3Tg2N8OdIHG/gy0hvYHsxhLCSDQBsfPN7p3FClM7r/VHOqgAN" + + "vzT+KYvxx6gwn6O+n7ERkrBIfkyrGFhnmjx3+VOCc9P4SDE="; + public static final String Intermediate_CRL_CP_03_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMy4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI4mI6Ojs0onswDQYJKoZIhvcNAQEFBQADgYEAfwYf" + + "4kAG4srB2VxWimJs1HwXTaPDooellQclZ5hP/EluT7oe03+ReFef6uXbHt/xRdeaoQhJGy" + + "SP8dWf6UIbL82oaSYqChIvAZD6zTMavEgSET0PlUsK1aEMTpMEtKPvedFSOTNBaMNvMzSW" + + "t5xwurn63qyXTOxHf4m2L4w8+i0="; + public static final String End_Certificate_CP_03_01_crt = + "MIIChjCCAe+gAwIBAgIBEjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMy4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDMuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAJ/ALaZ+MdNxKDH49+7jUm+17DII5QQEfjk8IaEU" + + "syApOhsByOG06HPItiBEnnfDDxU5kjsZDtw/9LlouBocNXAJt+ZmL3QYyOgeH4SQ4f21rw" + + "7j8fw57gUkP5oWhEc0loXr/hB92hoKbsBoRpv8F1zPZcPNLUnyUzqLH5+CeIibAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QI822isg/wPCowEwYDVR0jBAwwCoAI4mI6Ojs0onswDQYJKoZIhvcNAQEFBQADgYEAilIn" + + "OD0iQrLrHRkO4zr9S9VXAJXJV3l9wfbLBweXM3q/zt4HGKBw4Wq1Yn+AfDxXrBtJA5hP5e" + + "d7CDd4eM93yeKozdZCLNZfUM8sJ2/MRh07tvwJ19e2STklED8b/ndmr5my8H8jjJDaaYww" + + "qTSnXqpcqsUsj+kV4Mk0DvVWT3w="; + public static final String[] TEST_9_DATA = new String[] { + Intermediate_Certificate_CP_03_01_crt, + Intermediate_CRL_CP_03_01_crl, + End_Certificate_CP_03_01_crt + }; + + /* + * test10 + * + */ + + public static final String Intermediate_Certificate_CP_03_02_crt = + "MIIClTCCAf6gAwIBAgIBEzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAzLjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC4AbP8gDUUcIa8w4pEsGgbYH2sz08QMUXd4xwx691i" + + "9QCcyWSovQO4Jozeb9JwtyN2+f3T+JqZL/gwUHuLO2IEXpzE2C8FzQg6Ma+TiSrlvGJfec" + + "TlSooFmEtD3Xh6I6N5PM1fpyyY2sOOhARN5S6qR9BOuxkBAqrAT0fgqD2TswIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQI97nJCqq6+kIwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAWwpfh9oOOvj9xHS0zcczaUIHTkpjgk09I+pERlu0Z0+rHvpZGge4Ov" + + "NDFtMc4TgthGcydbIwiKogjtGBM2/sNHIO2jcpNeOtNKLxrzD4Y0Ve164kXBu9Mmsxx4sG" + + "7XUXZWgiOPfu/HmyPVdzbIReJdQO515SNx7JdgVyUkyhBxM="; + public static final String Intermediate_CRL_CP_03_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMy4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI97nJCqq6+kIwDQYJKoZIhvcNAQEFBQADgYEAC9Hv" + + "NevV6/Oz3wcgEbDgZYRKJRdr4OW4Es7R4ahjz3sH6GXZ1HiEjx2+frmp8LMshQ4D+hpjRk" + + "drSPko1M4a/fQCYxbonZ0xjpYw067dwLmr56+GPJAxkzcSmFKXx+ejyQpG+9+qCR+zm98V" + + "lop6besAaGUjZKnYShIQOfNzDZk="; + public static final String End_Certificate_CP_03_02_crt = + "MIIChjCCAe+gAwIBAgIBFDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMy4wMjAeFw05ODAxMDExMjAxMDBaFw0wMDAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDMuMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMJMiW+G4bgoRaYz2OUu/+PQ/yp4JgFOB3Vegf5/" + + "vIrF4gsnoQxOCCsO5JTLrbS5fi3COjvM5w9/SZpNHtSfyWb9afmx4DdrT1bNjma7I6PCid" + + "yxMzX4iTLeaMRnqBk4A+/0Wf2+4VzCqr8aViIiQ7u2JfZiTQ4dZxDoUW6G8lrbAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIEjny2GzFXGQwEwYDVR0jBAwwCoAI97nJCqq6+kIwDQYJKoZIhvcNAQEFBQADgYEAJw3T" + + "3aL3pYbZhswgshOvJ9Y1qv65R6rClSxB5lqBw6+Qki4ZpW57NK8LwaGS03XzDUPaDi4/9R" + + "hGCHpP24fIskS4n4jNZgKpGtt6VEVorUH7cOLNCw2cuwMlKbkyZnNdx2JqTMMlHzNJ3cmy" + + "aX3F70IY0OZbwCKdUo/uMVC6hss="; + public static final String[] TEST_10_DATA = new String[] { + Intermediate_Certificate_CP_03_02_crt, + Intermediate_CRL_CP_03_02_crl, + End_Certificate_CP_03_02_crt + }; + + /* + * test11 + * + */ + + public static final String Intermediate_Certificate_CP_03_03_crt = + "MIIClTCCAf6gAwIBAgIBFTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAzLjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCjLYKGKEMJgC/r0NH7vubQZ5qPEFEEN6QdLUWWqf/O" + + "Yqo9hboQq6S8dFHp3DVR5x/4NOdNRjsTABbXsnz8U+L7+4CorhDhXj29weGMYIIfJ3XSIb" + + "T7sE/GOPmXeGhrTv2zucI1j80sN5nTEoiGFm10LQqAgoyV46BxDltf3/D7wwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIhCIOyzfScpAwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAA18kQijoJebmTQS7n/q/fQx2iblOJaJAWQLHeGCCGqKxCjUpOxuD+y" + + "xMspmTKdQqEkqQ5vpHdFYQ5MYuecqAdp6woWUNQGVd4HHPmHsAW3Oppwb0yLggYs8IVHjm" + + "dNO1pYb+YYciCKBtX8D1OnedIRcrQmDMJUjbfmAEv/4b0EM="; + public static final String Intermediate_CRL_CP_03_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMy4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIhCIOyzfScpAwDQYJKoZIhvcNAQEFBQADgYEAk34j" + + "SxMr8p1h1qJWlfoh4er9pu1AkkHujovan6Ctx89VwFdOS5Kw82OCvD+nmJAHrFuncNlClf" + + "51G8FCEAFLhMNwic4WAxrBX15hcUTaWk8Wj00dfUFwjG8/Kv3QUCDBN8f3KC8/oBeORRX9" + + "dHW5ei2IUKuD1ITCeIoyRDBxQIg="; + public static final String End_Certificate_CP_03_03_crt = + "MIIChjCCAe+gAwIBAgIBFjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMy4wMzAeFw05ODAxMDExMjAxMDBaFw01MDA3MDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDMuMDMwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALSw1Ey7kzFzzjMS4oTSrZH/95NMHLxtUSaVGMCy" + + "0q2iLfGZ79eTS9megQUranYlIuK411yvFtskbFKf0idMKBtM8nX3Rxubm5EnbnpgvNrBEg" + + "0FbOPqpSaR+8pxZ6lweB45tkzLU3OZeAZSpGOY1UvT/htn6Ae8JQAVajSvYyfNAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIF014kOHikvcwEwYDVR0jBAwwCoAIhCIOyzfScpAwDQYJKoZIhvcNAQEFBQADgYEAdLMM" + + "zGPPvBLgPbhn2tba/7HiaZaayHIxTXmpW0KAhP+8hwapOitrtLGPwqVtxQ3GoSMZJPMDCV" + + "WsrT3OZm27G6ytqqNZ2ZO49UC7WwQ49TVlN79Ui9RZIBnRzlMIDNKsyuohfSRhFZTkWdoH" + + "/y8ulY8k4xBThV8e8IRgtYj3nhc="; + public static final String[] TEST_11_DATA = new String[] { + Intermediate_Certificate_CP_03_03_crt, + Intermediate_CRL_CP_03_03_crl, + End_Certificate_CP_03_03_crt + }; + + /* + * test12 + * + */ + + public static final String Intermediate_Certificate_CP_03_04_crt = + "MIIClTCCAf6gAwIBAgIBFzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjAzLjA0MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDbUii3czeUQ2zNlxvrhnJ0LcBGxCDHFr3xx+plDg3f" + + "uasDKCY/VjCLEfQ5a2oqcovvGKsd2CPXbCFJtimW1R7Dvt+a0y95fppsdseorYDikiBlOj" + + "ja6LR3Cz3bslYc133C+W/MKHMJ0tdvtTk+SJrq7lqs+iv/b/xHC3k/gDjIswIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIFNw3o1kc4XkwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAn/pr7/noYyjXSKEe/eLk3l4Rb6PEhNAnzySmxGkjIjWKAgh5IVYSGV" + + "KFO/FaNOiYkRFHwXZFNj71q7gbM+HwALurN0Mr/MUA1TSpPy7YhFL0SWq3C3XsC/dVJ50b" + + "HmTW+dGcxboX0h9HeKFxp3VyOY/dUut2oc+s/TnmqQII1CU="; + public static final String Intermediate_CRL_CP_03_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wMy4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIFNw3o1kc4XkwDQYJKoZIhvcNAQEFBQADgYEAMoJ5" + + "jGE1AxxfluixG8Sk7H4W2rqSEkQyNHfnlKSMbh9KZA3evI8HGKGGfkbBNoe4/HauZ4NVFw" + + "FXgllCp+TI8Qd+HafFoDv6ff1K7T86p6r7tE3AEM1XmbnfohP3/ivpIzustv/f2rqjxILK" + + "Ldvrth2/OlNygwY+D54lcWH1DX8="; + public static final String End_Certificate_CP_03_04_crt = + "MIICiDCCAfGgAwIBAgIBGDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wMy4wNDAgFw05ODAxMDExMjAxMDBaGA8yMDUwMDEwMTEyMD" + + "EwMFowYDELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UE" + + "CxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5nMRcwFQYDVQQDEw5Vc2VyMS1DUC4wMy4wNDCBnz" + + "ANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAuSL9tB1JW6JPUO2Xw6TMYkPX41lru3EPyYko" + + "YgXy4giy6LGoqbgtskHehD22v3rfWjqOd9iV2PBio/vYE4zEz0H0n84dpnBvog6A1AlE19" + + "PkQ1txjzIA52FQIRwRfZ38LaulQEfJ0a+fiRHQiM960O3YvHXV+GEbNcw4jo8b0sUCAwEA" + + "AaNSMFAwDgYDVR0PAQH/BAQDAgXgMBYGA1UdIAQPMA0wCwYJYIZIAWUDATABMBEGA1UdDg" + + "QKBAh9/WgM+UT6bTATBgNVHSMEDDAKgAgU3DejWRzheTANBgkqhkiG9w0BAQUFAAOBgQDR" + + "I6PKUGg876/fSljtqxXCR4CoGAAurNFOcM4EWeoc6ZvuDOi3P7rNYiYAXXlmp7epOAgvZP" + + "EV4vS16ODaJO6qIMR1YsaGEPo0ecT2pEStvP37X6pb5TdyjyKYF3586IN6TJdFMFsW/Lqg" + + "tucl9bGlWmfTVwxTexq6+D8diK48KQ=="; + public static final String[] TEST_12_DATA = new String[] { + Intermediate_Certificate_CP_03_04_crt, + Intermediate_CRL_CP_03_04_crl, + End_Certificate_CP_03_04_crt + }; + + /* + * test13 + * + */ + + public static final String Intermediate_Certificate_CP_04_01_crt = + "MIIClTCCAf6gAwIBAgIBGTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA0LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC5UJ+KMj8tAmzr3OGYL2gSFcNTf8ik+ZVxlaPVGHyS" + + "KjYQBAEbefhfg5Ps2aIuqBwYkbtFXuHif5GEhgObA4InCyESeRjYLGcVMqwSZzAOFAR0dP" + + "1LzgzQs3ZgG9JX5MO5wEZ8IMnVN4Otu4XIlWSgIpUNS2vyet8Zi7t9fX+JewIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIOZvfph4Uu9YwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAXMyscmGpKSLG3hQltMQLegy0+g5wzgOrbFOWxZmiVNR+zSsHDD3UAH" + + "H4SyTozlooC0jAY4yAhZ5RX6SSJKx9fHsOZD9ldCmst14qLk3pkI+M0QiPBZkVTx5/7dR2" + + "wGkuNKSVWH6woOq7BbEzpO7xMlrUr6tgHt4Dc6Evt1pVZls="; + public static final String Intermediate_CRL_CP_04_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wNC4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIOZvfph4Uu9YwDQYJKoZIhvcNAQEFBQADgYEAe79z" + + "iEUgP/mvouJ9ufit1y4SjnHQWik75W65eGn/XGArRrBqJ8jZVJE4/rpDBbzm2V0hQoWU8z" + + "zchZFlesUyqQZ9KUlT0YGR0YPcNw/V+58RonWWfmU3M2DvWDrXgCOXPm61+AYq4+kTowsG" + + "0stmeML6NxjDzWpfAgI/MpXqe80="; + public static final String End_Certificate_CP_04_01_crt = + "MIIChjCCAe+gAwIBAgIBGjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC45OS45OTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDQuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPiAZKXPjK8jvaNj34VynyKPK7dQtFysBPKFW5Y1" + + "Bc+OMsyd2pPpQoJYcQTMMomlAqoBvSXUJCMNly/BxVuvn7l6I9crtx6PjBBUlEzdcsscaa" + + "EaHuCCVl+Msnr66cSV3GqVGAhujun81+lyurcTEog3ftsohwbQnfA76qNU/N3/AgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIJZPDbf2xNv8wEwYDVR0jBAwwCoAIOZvfph4Uu9YwDQYJKoZIhvcNAQEFBQADgYEAZf4L" + + "1RDHDXwwA2CgcIhM4CAfZ72CR2zOan0at38VVFB3u9vs4VLwFcrOQCIjDbdLijc0XWLima" + + "4vCD1qrsv6Hk5+6113HfFNmD8mp6X5jAwoNPa/I4kmFOA8iIm4TTk7M75vQyCQTPG0VzbU" + + "Nu3uwTbXKm5ME9C5MFMf7z347CM="; + public static final String[] TEST_13_DATA = new String[] { + Intermediate_Certificate_CP_04_01_crt, + Intermediate_CRL_CP_04_01_crl, + End_Certificate_CP_04_01_crt + }; + + /* + * test14 + * + */ + + public static final String Intermediate_Certificate_CP_04_02_crt = + "MIIClTCCAf6gAwIBAgIBGzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA0LjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCteErspc5ekSOel/wmjn/XQ0HUy4XzxB5Zj0nGn9FD" + + "PbjF2LERCHOn5aBnIMHYhyr7PDynwbvSx2egzGC6wGe9Zrri1MteirQ9Ppw7062IIleloy" + + "UAiuwvD+s0npKsvboarQsCMfOB1hOB1tGG1bjXP6B5B187SZXuR3KawggyJwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIUjnGp96itUMwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAR6fmN+9p5AWy/asEAiVBnbY9q7EQXyB8WuZK9FtFmupe3hlfcTq84E" + + "A+TGvXOlNr05/1iLRv82GsWXDif7DlGVPN8CS1+0kb5Ve8Pmv2ziiWVREqWx916ioPjDRp" + + "wvdGcCNC26+fyvv5TrP8uzojurl1ZlVRRqi2sIbopVX5r8w="; + public static final String Intermediate_CRL_CP_04_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wNC4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIUjnGp96itUMwDQYJKoZIhvcNAQEFBQADgYEAZkXJ" + + "aJG4QDE02wFURwaxWuv2VyD7m+N/2B0/9KR+6UKVpsMd2XHq+G3SlFOa6dA/fHUdhtUs2D" + + "gpx3SfQYbcgKFrryZHqJDK230eP3F41S9g5XJTRaNR5iZvxvh4bmSf4l6a5MXsKEoBoJoT" + + "j8cU4qg6j7Xk4NpIR1JbWiSIYQc="; + public static final String End_Certificate_CP_04_02_crt = + "MIIChjCCAe+gAwIBAgIBHDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MRAwDgYDVQQLEwdUZXN0aW5nMQwwCgYDVQQLEwNEb0Qx" + + "FTATBgNVBAMTDENBMS1DUC4wNC4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDQuMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALM7mfq+hpLfvQdqZUJfIx/2gFcgHS2AsgZn0An+" + + "Yn61WtG8K2+lt/a8aypa/q+J93RVkRYKWKFQcJHiRgx7DMlXElVnfQbSFuLX46ng4hqmQL" + + "sSOKmXDld2BlyMZ41B3rfdhJT8P12RMR6uAwvc9CH3b0UTcsc498Kj+JeaRbzxAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIo7S64S6t5nswEwYDVR0jBAwwCoAIUjnGp96itUMwDQYJKoZIhvcNAQEFBQADgYEApNT5" + + "Y+9Jc28m5Qwjm+/8SKk83iCPnIW3BsAvQUB9Wmd1+kMZvqLySQjm1tBBbcGYuSERMJ2Et5" + + "eoTdL9B6EG2CZYnPqu1vk0TVugRxs7IJm4h5z4MCInf2g1KTt0AMEasQW6ZTj7DIkkU48Z" + + "EKLPoBGXfD9t9Y9cmdj1e1RQbog="; + public static final String[] TEST_14_DATA = new String[] { + Intermediate_Certificate_CP_04_02_crt, + Intermediate_CRL_CP_04_02_crl, + End_Certificate_CP_04_02_crt + }; + + /* + * test15 + * + */ + + public static final String Intermediate_Certificate_CP_04_03_crt = + "MIICmzCCAgSgAwIBAgIBHTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGQxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEbMBkGA1UEAxMSICBDQTEgLSAgIENQLjA0LjAzMI" + + "GfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD11QBcw4P2rTUfPmbVNYqdo0AMmcB3Yxsx" + + "Iz5me/S1I2PJLtRh9KP7lUV20SMEFsFKtE1C+9O7ODtOUCJA/6ECeXbyj20SbG1E2oQrZe" + + "gkcn7IQDUgnuedzdFj4kTevok6ao9hycg+qeZrL6oeBD2XQCd9nqMmzhihNu/QOSnp5wID" + + "AQABo2MwYTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMA" + + "sGCWCGSAFlAwEwATARBgNVHQ4ECgQInx+ELo31rJMwEwYDVR0jBAwwCoAIq5rr+cLnVI8w" + + "DQYJKoZIhvcNAQEFBQADgYEAriYMoRDpSPI4HWrxN1rjqWIzggz8p1wpbEFgK5o/Fi2KT3" + + "jCd6bfCcIFDpoXNqlsc+dvzc4XB1Eg/Qbcror8HP8LSxrbFw/y7VhC+wCaDCmhcqQn3rp/" + + "WaOWnR7/H7HlKM9m1u7MBtwlxHINnLKwPHIA1XwmAnItAXIL2yHRJhU="; + public static final String Intermediate_CRL_CP_04_03_crl = + "MIIBUTCBuwIBATANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxGzAZBgNV" + + "BAMTEiAgQ0ExIC0gICBDUC4wNC4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWq" + + "AjMCEwCgYDVR0UBAMCAQEwEwYDVR0jBAwwCoAInx+ELo31rJMwDQYJKoZIhvcNAQEFBQAD" + + "gYEAvJgOX6tewnRbC9Ch+Fe4KjkB9IAhe5anQKGfnDHuLfga6JEjOzyfhonWZeppJwvYpl" + + "1rZbsKICNphMDkd/eaWnn8Q9w02ah4kzIb0LuzrNBrxpFv9AAidfGU2VeF0gRi02jtAZsh" + + "gUNbrdC+ovA8mAsBigy+HMzCi61+wrumwvo="; + public static final String End_Certificate_CP_04_03_crt = + "MIICijCCAfOgAwIBAgIBHjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "GTAXBgNVBAMTEGNhMSAtIENQLjA0LjAzICAwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMT" + + "IwMTAwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYD" + + "VQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLUNQLjA0LjAzMI" + + "GfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC2Rd0VKnTIrME7hzpnpIPGXGXZCjpf5lSO" + + "19zvB3WdZumLGdwUBXpIQTrl5teYgL62PpOwNC93URZDEUt+rqoqvs8E7MpF3IulStp2+H" + + "/xa6Ihf4OmkgKjpHNTWOIFXeRJ4sVgWuH6cqQ+6GL+0fa1sed1crsEgTTAGYNhFi6ebwID" + + "AQABo1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR" + + "0OBAoECBNwCFdDgPCqMBMGA1UdIwQMMAqACJ8fhC6N9ayTMA0GCSqGSIb3DQEBBQUAA4GB" + + "ABAjSPg794yiVz9RqdNxic8TGnApNrZui/vwr1U8ZkETZfx8W1fWgQ0z7KjryML5IOmvps" + + "zycM7by6jb2kMmxI1SQCwjiNQ1fb1osrNAj2bRfpp2YgjjbHx1XkddommtVc0V8kvyQBcb" + + "7NdxfbwKr8AtpiWTWIajc2uqUlELsLzr"; + public static final String[] TEST_15_DATA = new String[] { + Intermediate_Certificate_CP_04_03_crt, + Intermediate_CRL_CP_04_03_crl, + End_Certificate_CP_04_03_crt + }; + + /* + * test16 + * + */ + + public static final String Intermediate_Certificate_CP_04_04_crt = + "MIIClzCCAgCgAwIBAgIBHzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOQ0ExIC0gQ1AuMDQuMDQwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOFf5hr4R8IqTp53qQSiBEjOFQ3Q3ICcafl+FLzm" + + "K3xIFqERjyXARsTM4gDQ9yntFeNp2TiIi98xBrz7D8TlrbTAmxO/PUfAQ68tXpz9Id/XrU" + + "WeAKxMZULPL9nPFcGQoh0qq3JKpFRSb3Iobryfysblm7cCDDCJOI7uK14XZtTFAgMBAAGj" + + "YzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMBYGA1UdIAQPMA0wCwYJYI" + + "ZIAWUDATABMBEGA1UdDgQKBAjior7qCuLBljATBgNVHSMEDDAKgAirmuv5wudUjzANBgkq" + + "hkiG9w0BAQUFAAOBgQBhh55gTy5htqjxW1Ch2hRrRikhBH7LJz1PmDuzwiIOtnWL+EiQOY" + + "T6h3NV1j8Kn5S4KhUOrhnvrPXRi22HdqRzEPl7y/wXm6G0XcgYlyy2ofZKdYVWCVStKAMW" + + "5SwV2wC5RPK2KphdhnlEqss6QVRUsliDDjnf9Saiey9nzJAfNw=="; + public static final String Intermediate_CRL_CP_04_04_crl = + "MIIBTTCBtwIBATANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNV" + + "BAMTDkNBMSAtIENQLjA0LjA0Fw05OTAxMDExMjAxMDBaFw00ODAxMDExMjAxMDBaoCMwIT" + + "AKBgNVHRQEAwIBATATBgNVHSMEDDAKgAjior7qCuLBljANBgkqhkiG9w0BAQUFAAOBgQBI" + + "VlXD5FnIiO8tavLJ8qo/qRhbBNgUbFBdAgAY6yVnFNP6YN4qPineYPN6NV1XdqNDrZh2Nz" + + "GHzX3YDo1Uv9yABVR0NvXCaMIW5/raqZp/on6bPuQLgJe9UisOPKunzehTm/NmO1RW9dwU" + + "37UzC0XnVHyVipDVh07DrTKBUtQJQw=="; + public static final String End_Certificate_CP_04_04_crt = + "MIICjTCCAfagAwIBAgIBIDANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJVUzEZMBcGA1" + + "UEChMQVS5TLiAgR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRswGQYDVQQDExJDQTEgICAgLSAgQ1AuMDQuMDQwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMT" + + "AxMTIwMTAwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQww" + + "CgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLUNQLjA0Lj" + + "A0MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCegy6qOnM14CS7+enBElgh2DLtF5bn" + + "ah0yfA18/hbqnmUaWOWJQllyXa8QFawnvdXOOEXJm1ErIm3rDYihkbUTP+ybOBH9dprWtl" + + "1cSGL9CkoxwzkJRLQTu5xG72EhET3S3kwqZsmYbgy4MduGKv9VGFbv75Wr17Vo9K4Lz6QK" + + "vQIDAQABo1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQ" + + "YDVR0OBAoECEc4b3BP059HMBMGA1UdIwQMMAqACOKivuoK4sGWMA0GCSqGSIb3DQEBBQUA" + + "A4GBADj73jXpPLev5crwZIoXCJd/nXXp1fJzEEbByWggsR9cFHN4wnp7N6gpIxQbLQwjmo" + + "cLPC1pHQ3A5VHVrCbxAk6nifmSvnKFWHTBftZGpfTGkrXbURFF64T/CB4O+JXr1eBUGheN" + + "Q0T8L17UNgi3oBENKjASWnpjxvD2QrOnH0rb"; + public static final String[] TEST_16_DATA = new String[] { + Intermediate_Certificate_CP_04_04_crt, + Intermediate_CRL_CP_04_04_crl, + End_Certificate_CP_04_04_crt + }; + + /* + * test17 + * + */ + + public static final String Intermediate_Certificate_CP_04_05_crt = + "MIIClzCCAgCgAwIBAgIBITANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOICBDQTEtQ1AuMDQuMDUwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMBsWmrcKH0J9bkI3zHthZ0S3904f3fMUSasY5qp" + + "7CSQ0sbXTwP947sfAPK4Dso6Bpwl0WExRCdFHd6qfY9wR+NtfuI/DkFEY8WveoqM4Vskpi" + + "cutWghCx14PiPY5YGFn8VvXu7wbuHp4TnHtUCMEUt3EfYO5oqm+/I8y0eTKMNHAgMBAAGj" + + "YzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMBYGA1UdIAQPMA0wCwYJYI" + + "ZIAWUDATABMBEGA1UdDgQKBAjOoKlp+BfGqTATBgNVHSMEDDAKgAirmuv5wudUjzANBgkq" + + "hkiG9w0BAQUFAAOBgQDLhQ/RJFqMDNRonAHZ30DYyphf8do4q6ARikhhXSSa6G2G/PzbpS" + + "x3T+3G8ot+NnFhtf9ZWo7KfwmFEbUA/B/X2vJaJbNImkMDT1aTY5sPXtA69B3QKQVz7HST" + + "f5XH6DjuoV0/m1M153A4vf1Z783dOPw1MzOq19t+6tYFeELEHQ=="; + public static final String Intermediate_CRL_CP_04_05_crl = + "MIIBTTCBtwIBATANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNV" + + "BAMTDiAgQ0ExLUNQLjA0LjA1Fw05OTAxMDExMjAxMDBaFw00ODAxMDExMjAxMDBaoCMwIT" + + "AKBgNVHRQEAwIBATATBgNVHSMEDDAKgAjOoKlp+BfGqTANBgkqhkiG9w0BAQUFAAOBgQAp" + + "6gLCdPQw7Hisnr1i3QbD7GybqfD6b1s10GQ3c/j59RYDe1Fk47Srs9ol/baleasWjcdt8M" + + "SlTc66KvK9YPFAqIdYoOW4FidpJBF/1cvSc2hGYwVsxLnXKr9CJ5Py5vBCCjovIRiLdzoL" + + "ZoteOKFIEHkV7V8V2OTFawxpW9hkiA=="; + public static final String End_Certificate_CP_04_05_crt = + "MIICiDCCAfGgAwIBAgIBIjANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FzAVBgNVBAMTDkNBMS1DUC4wNC4wNSAgMB4XDTk4MDEwMTEyMDEwMFoXDTQ4MDEwMTEyMD" + + "EwMFowYDELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UE" + + "CxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5nMRcwFQYDVQQDEw5Vc2VyMS1DUC4wNC4wNTCBnz" + + "ANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwZsiUhXiFHN9dfJb0Yyy+rYtV8gx+d0+8WkW" + + "5C68nQgSqqk2uSTpvZbx0bpHF+s+LKppj2M2tt/AfZgVQHTsp5rO0IftZE2iLwqejj0rYU" + + "Poprq1PE3vVhs818ZlDS0PTUP97YxLysQjq2jS/d/9lF5pS3sMlP4Usp24gXX0vG0CAwEA" + + "AaNSMFAwDgYDVR0PAQH/BAQDAgXgMBYGA1UdIAQPMA0wCwYJYIZIAWUDATABMBEGA1UdDg" + + "QKBAjpC0ZvCXrvBTATBgNVHSMEDDAKgAjOoKlp+BfGqTANBgkqhkiG9w0BAQUFAAOBgQB7" + + "YwJWcx+PU1sUZUOVleoB5amHFu0GT+Hy7cRa82UJMHFkz0bmnyEV8CBNcnn0xa5iVfwe2y" + + "5ZKwy61DLR3MPTar9eKITL67uZag9w+1tnIf594XRbEiUzn20uxuDFX3oPoZCemtWdVanj" + + "2T+9TVQKfrp15+qzOCObNNRHZw29EA=="; + public static final String[] TEST_17_DATA = new String[] { + Intermediate_Certificate_CP_04_05_crt, + Intermediate_CRL_CP_04_05_crl, + End_Certificate_CP_04_05_crt + }; + + /* + * test18 + * + */ + + public static final String Intermediate_Certificate_CP_04_06_crt = + "MIIClTCCAf6gAwIBAgIBIzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA0LjA2MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQD0t0dfe82Su58bJdn4dh7E3OCam1AUPTzPnt7DwT2w" + + "1XwD76OCUYP7SBBjsLYDDfUCb2ek96pSK4jpzyE6/4IOtfObe7OW+iBT9YAB5WeW+SmvEO" + + "TIX+xo13sbz6rG6j9svcOxtth98yv7mxzV/ZwTNBSO72CcfDXIIq20TVunlwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQI0AufZEn1f9AwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAbfhxuNBYizxfMZNcyiN61j+7LXZZo3SmMU21UmOhPBTmdTbIkuVCI+" + + "F1jSWdu3eGShVNJ3jmkidDvojMm+E8ZZ1YGHYfgeG16dDQudaGUjGmOfYzzlkFmsaf0paG" + + "4y4sBerPsZCmhN7BanGh3qYPFvadSmp3OapGfEmDtS+BbVQ="; + public static final String Intermediate_CRL_CP_04_06_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wNC4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI0AufZEn1f9AwDQYJKoZIhvcNAQEFBQADgYEAIAI7" + + "W6K69twJZnHx6CoIMs5+P9DrJ2yKHptmntlOCTSJirC/xdj0Zv2k5FW84VrTtdCSZDT1Ce" + + "4Dh69fT2sUUexJb/4IcDtzloiuASSJzKWCeVIj9A8e6+coNUJVKtRKRX8bHJ5Un7xpFrY6" + + "t1hdxt8gUecAAdXEFGuZ3QEHHN0="; + public static final String End_Certificate_CP_04_06_crt = + "MIIChjCCAe+gAwIBAgIBJDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPdS5zLiBHT1ZFUk5NRU5UMQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1RFU1RJTkcx" + + "FTATBgNVBAMTDGNhMS1DUC4wNC4wNjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDQuMDYwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKq8rAPXsu1RVm3vT7od7CDLn8k/C3x3wvfzoWrm" + + "W0cmlhp9xRy5a3HWiJATD8yCKY1psBgnrOpv37sdtUX4P2kf668HrYOaGo365fKPeT5Wjm" + + "gp0pL3sXKNNsCuJPd3wKAXGHAi1R9arZFYPsKJlfQl1774dwAvzxSOMr5+pbnzAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QI33MEYdo5YX4wEwYDVR0jBAwwCoAI0AufZEn1f9AwDQYJKoZIhvcNAQEFBQADgYEAo8Ge" + + "ADBoJFEIRzdO37uasuyIBhClTUgyFhEKemMBN6aelYeiJMX6FZIL3DgZOce4dg7Zg3Ak/w" + + "B5m8XlGQLW9xIbpEzY/Iq9kr+qK6k9YmvtcOiHFbnudCFNZngTQZpxjiDaj4eA48uqKIxs" + + "51taC5gOv9LYWPnugN8TsUUFZ1s="; + public static final String[] TEST_18_DATA = new String[] { + Intermediate_Certificate_CP_04_06_crt, + Intermediate_CRL_CP_04_06_crl, + End_Certificate_CP_04_06_crt + }; + + /* + * test19 + * + */ + + public static final String Intermediate_Certificate_CP_05_01_crt = + "MIIClTCCAf6gAwIBAgIBJTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA1LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCshocJtyGsxeEd2ouVTVKp+HuhDjnDk9eXtaLQIKaB" + + "7aTODHYbq1mC+1LO5DmRV5PBVd8NuuCA+1DmzFrfYl+nMCjjgOkC0//Gf9O85Hi/n21q0T" + + "F+oVa1j9fc7nAgLIziexaXrflYSbaeNWkwHHftGUninKPuNGM2re0krEeurQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIaUi/P20o4LcwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAWBLeJl4qlAPKxmBM5QZ2JYsbCV3VBeYGAKQ+4L7ehS63VQMCwIjBCI" + + "LaHGIFfCqecDNd6cpYIArdx4tY7X2/Zxm3j5ocngpI1Tv8zydQcFeraILglsHf2UZUuK/N" + + "6jKGjwL68C8YwmA+u6ZhcQFD2Xg4wSMC/xxzAs9zEAQGBPo="; + public static final String End_Certificate_CP_05_01_crt = + "MIIChjCCAe+gAwIBAgIBJjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wNS4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDUuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAO9ODA12Fky/Md5AELkaOvOwB31UlfZq3SHAOvs0" + + "Y4NYoA7Q5KDIwW8RNzMSKD30z51VlgOAaBVR6HLo6rkcWB4wGiV7EPelewdSOdk72IrnYR" + + "npJEm2KEuLkHB+gejgk+paw8CejxMsrvT6loN8Pz0btBKxWaCfknTIyXVyQsolAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QI5LtSKs/inGMwEwYDVR0jBAwwCoAIaUi/P20o4LcwDQYJKoZIhvcNAQEFBQADgYEAOMrC" + + "38uzHckKMkiawXhPUHtDQfyR7bLweS2qro7GyndfxPpeMJwjzVxqvQBtMuHON+al8jyXpy" + + "BsEryV6qvdFC1vczLzJHAJZmLe5np27zQIXOObsyYcOG+aPq727/pKoD90DAlBvrxNW0ox" + + "x7citflEYpmOEv9Do5xiO3MuCFw="; + public static final String[] TEST_19_DATA = new String[] { + Intermediate_Certificate_CP_05_01_crt, + End_Certificate_CP_05_01_crt + }; + + /* + * test20 + * + */ + + public static final String Intermediate_Certificate_CP_06_01_crt = + "MIIClTCCAf6gAwIBAgIBJzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA2LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDI4MXZB08BfUHxo//4Re7Ax0qWkHgy6nb+/XaLQ2Fw" + + "Pbvpb5mkhLhqDZBSX3KQL0YiJ8p81tmdvRQH/LbFzX/3OKBTUfV5imYy979A2NEb4otFp6" + + "EDSskZhttY3d2IzUICoCWUXhObnmkHJ2jEc81bggFkK5Lir1m/tKq2IOPFJQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQICIAmlz6+Cc0wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEA0ZvIG2cnk32p6uxqGw8Bu40NrfHu9gNkJL5MhDHJXA6OxU5BX5bWZp" + + "LnKXLoHiqSdtEdmy5cLZw3kggxndxjsnRFMyCawaYupJBhlgquFbuvBtA8rMtkc5H4zudP" + + "ZcOcvXu7Xw58K+1caSGURL+A6uXFPnMUBd1+k+ejbtO8Pto="; + public static final String Intermediate_CRL_CP_06_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAICIAmlz6+Cc0wDQYJKoZIhvcNAQEFBQADgYEAbkJe" + + "jfc1rztCbtC6xJZ3iZEDDMW2CxFvOvSwhmCjPqVY3lrCPNSQzdjmqepioCnu7ongP+HAA7" + + "hM7bm+SoN7KzXKufQ7C2ONoAwvoPZgnoidg7RVECxUByD6AJu04yd2wCLYRpCfS2tDtXLh" + + "HEDpe+ELwv35pbkCMlCO2u7J+Tc="; + public static final String End_Certificate_CP_06_01_crt = + "MIIChjCCAe+gAwIBAgIBKDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDYuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOh7lUwMRet7t/ABI6mo27CsnRzQ64Xx7f1dqxrJ" + + "NuuSRslVShaWnwiGHjc+5/TS7Urfj9VO0dseBCzPsyYFoIX1q7Q5zlArwy24qpXTGMmlpE" + + "GByzi7jkXO8w5+wqh3+8RFrQQzr71zLtAVV/qPUyleuF8M8jzkwfPvawunmwdLAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIayC0PPU9zyswEwYDVR0jBAwwCoAICIAmlz6+Cc0wDQYJKoZIhvcNAQEFBQADgYEAPz7b" + + "UvaEV7Myjhe8LJO/soj84X71rvVPtBPrhYjWTJ6p69GCfJRyho3vAUIt8RFal1GFb72c45" + + "DQGkcVzLLJw8cDP3ajtWac5HZ9dNPJkW+Kh12l9gqjn061XAjQ4XnbbwQDYCuXhguPE9v3" + + "kzDbimwVwIEOB/4SARX37y7TUWk="; + public static final String[] TEST_20_DATA = new String[] { + Intermediate_Certificate_CP_06_01_crt, + Intermediate_CRL_CP_06_01_crl, + End_Certificate_CP_06_01_crt + }; + + /* + * test21 + * + */ + + public static final String Intermediate_Certificate_CP_06_02_crt = + "MIIClTCCAf6gAwIBAgIBKTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUNQLjA2LjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC/IejV3DmeaLW8OwMfAGyr5+8NOxM1C+UBYslbOfWj" + + "KUGdhlX6TxFc5AOJVJBpS/QjeA+RWoUCxnxKb9QSlOrBmADrcnGz8zV0/c0JDLaU3oSgsV" + + "EWZE0SexBVWrKcl1j7wN0RuxMeAp342/YoyvBwea3VeqJkmSCc7Y2TjruWEQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIaHxWOdHsLbUwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAuzeq/lqp0qs62krK6EA81Silhy42l/KmynE3mVu9GPBgQS0BUDi7+r" + + "QQ+m0UxYElzj2SNO4J5aBYeC98lVJFCHX7QE8yVOoPBQd5rA+rrz4HD9QoP7glxTqLU6Tc" + + "9VFd+iaFpqsVtSh2bxH2BtUB2ARgebTklaNl5VPbu0+yc2I="; + public static final String Intermediate_CRL_CP_06_02_crl = + "MIIBbzCB2QIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1DUC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAiMCACAS" + + "oXDTk5MDEwMTEyMDAwMFowDDAKBgNVHRUEAwoBAaAjMCEwCgYDVR0UBAMCAQEwEwYDVR0j" + + "BAwwCoAIaHxWOdHsLbUwDQYJKoZIhvcNAQEFBQADgYEAYGaAzVoUdlSZ3uGKiRPfHAFIoK" + + "T79hNOvtOxaGA0aIek9OypDrDqYAh/s2jsXSheL0pr/v9WRIHvtCt7ytXDxVyn4Nxjpfv7" + + "BkAMMiccdUx1OH1VElTRkmmtMe7ROzUeHUGzXJNPex1Bc9BvSChH18bWYckyOZdYJBjctC" + + "KJFgw="; + public static final String End_Certificate_CP_06_02_crt = + "MIIChjCCAe+gAwIBAgIBKjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1DUC4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtQ1AuMDYuMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAK4D9H8JxeIrFuOmx0cSkIYNS0p7cDSBlcc57Na3" + + "+1k7lJD7mE9ZP6/47YsDVK2bwe4aTKCTXtPk/kGQ6bsLswJXbyW4k4+f5LeAYoXgbmZXjA" + + "WF+BKIl8uKetsqC3HkCeqhBaY1AGUqef4oOAkakEP+1jYFumNYtMaB+9x/0ncBAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIC9MiJNI71RMwEwYDVR0jBAwwCoAIaHxWOdHsLbUwDQYJKoZIhvcNAQEFBQADgYEAo/ib" + + "mIxteityjZlszjCc/s7yM/0snL78pYpMOZ3P2TPKkYh2Th4+Bw8JqX10+M/zwFBj5Bw7Im" + + "zCIRfS3GFuKmcVcyHB4OZLMcQZtXWA8GOZ94YvWq5TBINlVtThQtusQj15KBq2TJNNFUyD" + + "pBdvyo05AnEsRY0HbIQu6ZhNQ40="; + public static final String[] TEST_21_DATA = new String[] { + Intermediate_Certificate_CP_06_02_crt, + Intermediate_CRL_CP_06_02_crl, + End_Certificate_CP_06_02_crt + }; + + /* + * test22 + * + */ + + public static final String Intermediate_Certificate_IC_01_01_crt = + "MIIChDCCAe2gAwIBAgIBKzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjAxLjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDDOu1J/VIzbB4VcS2Dwf2fsHOmIj3iatM8y61V7CrN" + + "RCxCWTJ1Os8e/mFWOi/zN+0afizA0UzJDTe8L++/RlP68IFg5Ju2OhXqQC3HbUZmQ7ve9g" + + "QdWTfur3oEJV6/XoVE4WG0Ic7D1p7BENb3LUT+8MJdSboTvAggA1CiOI6zRQIDAQABo1Iw" + + "UDAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBAoECP" + + "RyRiSV+4XrMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqGSIb3DQEBBQUAA4GBAJlmJ9EW" + + "9ujUosqHZyZkniu2vX8VOL52OnxtLxw3LqxLyuxivjyYCaMAaJNr7/xfm3C2ozh9mQyZTQ" + + "6TpBapLFUH8QsEKUhy57MDUgIvZsyOvvjJh3AXfSkXDaMZ3ncLg6x0wwjN/Hxu9i+IhX1W" + + "1E7/5foGx7AEVfwY7Fo9S82d"; + public static final String Intermediate_CRL_IC_01_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wMS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI9HJGJJX7heswDQYJKoZIhvcNAQEFBQADgYEAV4DM" + + "F5gU8MZ6E/mnjAWS+dIRKUBJV1GZJ+hOysdbmK1hD0mj5Pd5qTzlcvLjuatIoIsB5DCpYd" + + "AcNRLVvF5EJFhVjqsPzRlfUZth0Xqa+U/DeHjVxHxYsLEOSt+v2bLkbGh88SmOAk6F8xj1" + + "l7YIfPX5cIkUBTVZlsUt51slMXc="; + public static final String End_Certificate_IC_01_01_crt = + "MIIChjCCAe+gAwIBAgIBLDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wMS4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDEuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPrk1fosBu0hemIKgTDCeV/RoFbbsm02X4LfZonX" + + "KeGRGYZXz4tpWgbNpjKBq1e/2bOO1DCn9I8I2kjvZdOkabk4MLeuRDo/sqlNndu4Ar5502" + + "pAo4A2V0QLR4IDHAJoDpxtSFrqELOiiyCx9O9V19ywe5pcBFrxVEWDqTnBUeDJAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIbI6BhABrmQ8wEwYDVR0jBAwwCoAI9HJGJJX7heswDQYJKoZIhvcNAQEFBQADgYEAYzYy" + + "M0wbzNhZftAWz7TfFi64uA9WmTmd4MeK9vga4ChswT4H1zlaV1Sr+3hqpGmOoP5AUd9XIq" + + "O/ui+/gFaeuOLI+ATmK+V2KHGAneMwzcw9qbXRc+xZqGGjbXMb3Bowe3qrj3mhyowfa1n7" + + "x5xB7XEOqO6sfWxLdDjLVo4sn88="; + public static final String[] TEST_22_DATA = new String[] { + Intermediate_Certificate_IC_01_01_crt, + Intermediate_CRL_IC_01_01_crl, + End_Certificate_IC_01_01_crt + }; + + /* + * test23 + * + */ + + public static final String Intermediate_Certificate_IC_02_01_crt = + "MIICkjCCAfugAwIBAgIBLTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjAyLjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDemJgZnOzXOwNGqRA3Xq9aMrAWQU4oFuhSELsEYfLZ" + + "GO3ntBjJLqCn+rs3FjR9N94cu63TduOAgqlXqrNbvyO1+SF9m35JXreqn/OS6KrK6c8W2I" + + "pDAWJcr89nGyyCXMoJeaOOtj8m2NjZblmCZvtAl5UMOew73GE7Z5fE+jtA2wIDAQABo2Aw" + + "XjAMBgNVHRMBAf8EAjAAMA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAw" + + "EwATARBgNVHQ4ECgQIhT9GjaaHj68wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" + + "AQEFBQADgYEAWhKJUujLapxpz/DoD/w48HMzkL6UQCxQPOAjwwHicX8wFcKmcrWLVBdVC3" + + "0+ywrzMraWhaq+QCOqsgtxCwTZrfUxbCNqhKS0lZijCMgNN4Jht+PAZ22tzEsw7nCwiMM2" + + "n1jeKF/3btoDEUvZn9SuzhkIyxy7Q8l2tbNOsANqpxE="; + public static final String Intermediate_CRL_IC_02_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIhT9GjaaHj68wDQYJKoZIhvcNAQEFBQADgYEAJsjf" + + "oS3F1KMpcVBOC1Z6P5N20TYLCCHG6KETlBA3Rjf8ehNxJKJW0lGd7qHpVHp4BGvkSfaOAa" + + "OrC0G59wjDEY+Ci4QS46OYzBcHXMFX5HF2xMq+y5SfQnyV6MQUVVkxJRjgsTLrYwP2JaYm" + + "BK/zExhqQgPfgcR+56swBPXqogo="; + public static final String End_Certificate_IC_02_01_crt = + "MIIChjCCAe+gAwIBAgIBLjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wMi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDIuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANbTVeAxOibAO3KGqxxY3VqKXDr9tKJN+igpKb4w" + + "goR0ZnWGDusSVm4pvneZ9qfmi8A0sM0E91+B2hAwsU6Y9RoA7nPsTkFYi5F+hHGIF46Op6" + + "8blGrZraGf9bsWXCZFoLoxcgltwjGPQqyZ5mnnm8cxUbtaWmgo28MK1yBH/sS5AgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QI3gkBNo/SISMwEwYDVR0jBAwwCoAIhT9GjaaHj68wDQYJKoZIhvcNAQEFBQADgYEAQGl1" + + "7uT2xxYDks6HolrQIpesIoPqEiZ8TkizEBuLG3sUKsC7klHwy2iyVvA6nRUDwf/XzDLpGW" + + "/Gn0KTW6ZYIX6snOC1+7HX5OJglQx8tDpDvcAgyocK8PvCrHfu9o33J49aSeLAVpoCHwne" + + "tTtJxVfTMmjYWKeDbHHHi8a2YTI="; + public static final String[] TEST_23_DATA = new String[] { + Intermediate_Certificate_IC_02_01_crt, + Intermediate_CRL_IC_02_01_crl, + End_Certificate_IC_02_01_crt + }; + + /* + * test24 + * + */ + + public static final String Intermediate_Certificate_IC_02_02_crt = + "MIIClTCCAf6gAwIBAgIBLzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjAyLjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDoeA32BPwgq8pLJoR/tbOSjHtAz6fmzvzJrhJMvl64" + + "ccVuIzGxzOneYsO/ZYWy3ZGtlCoMZJRnS83tw0ikU9vQUwBw7DEcfRlLKYkY68rp25N1V5" + + "JEjnlHw+RvubdGkonWzUNJFbY1GA24J3no2GZHiLPgWmGb1jsA8Ag32MUrCQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIKx4Ybzu2PaYwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAotGeNFzmktvcxpCRcpuARHkv1lW+LegvbDBnSPvGnr1+Cn9rZcuLup" + + "u8ex6VJ7KWtgWBtzdOelerO6ytfWQ67uNpTOuc0SDdk/f3tCagdx44LBVQywuq/Kj57ZuN" + + "jpe4J8UPZSBFFK+P3gTX3S/lIKsDi6xjRnqFLSQYGX2XiIE="; + public static final String Intermediate_CRL_IC_02_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wMi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIKx4Ybzu2PaYwDQYJKoZIhvcNAQEFBQADgYEAOfuX" + + "wRv4skbPZAbOH/LVXdc/cA7vCSTAnWecN3ZKm/eCsxbyRxqn7fcDyHmqg5H3Ac5UOlMHR4" + + "FMe0Dp+Yu4Xg8xg3zRvE/3M/5jyRILGGi7olh4ikkOMD+UlreysvYvUX2MVP1iM9qAkXh8" + + "E8n/LZIlABN2GGkFEMRMJA6KTXg="; + public static final String End_Certificate_IC_02_02_crt = + "MIIChjCCAe+gAwIBAgIBMDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wMi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDIuMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKogqWGx9EpJ/0G7ORopyIQ4IZXYKKTE48WqOJbu" + + "nLD3txGjMUb5Xefl/QyTfd6J758ddGzPiKs1zWO6riffJLIBoOFDmt8tchPBJuIM3gKgXe" + + "VcZMyF5mebm5/GZekMOjbs8P/zbLdrlu1D9CZWZMXONYitdluSg2moMGbewS2NAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIP8N7OmNGshEwEwYDVR0jBAwwCoAIKx4Ybzu2PaYwDQYJKoZIhvcNAQEFBQADgYEAwkpF" + + "j6Kv+OcKrUtOgnH9QddB0Ej0oU6B5/5Hhhf3liAPKtllDHnhUj6nqfh4APNq/iqYFOkKMR" + + "RUZoaj6kakJNSOlgvRIiQfuFIgv3CqLZnhr85YFRnKgoluZE1pq3TvunoiKyJbCjbmyCos" + + "Rd32gVcJq024xvY2eVBTl6tfn5A="; + public static final String[] TEST_24_DATA = new String[] { + Intermediate_Certificate_IC_02_02_crt, + Intermediate_CRL_IC_02_02_crl, + End_Certificate_IC_02_02_crt + }; + + /* + * test25 + * + */ + + public static final String Intermediate_Certificate_IC_02_03_crt = + "MIICjzCCAfigAwIBAgIBMTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjAyLjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC7LFt+yGItQFqSEPi03ICIr5ydWnFPQHZdEMNu2tRU" + + "3XiOpfam1wl0xgAPGBkQK768OfidpP/i1hgYOU/isOB5dyALscvIQ9XJG1OWQXBBLgKuCb" + + "MS5fuDhBNa4KiFuGMbJ3/UjluRsD9qaXwGUavc436JwbRHvW8FomaBYYY1hQIDAQABo10w" + + "WzAJBgNVHRMEAjAAMA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAwEwAT" + + "ARBgNVHQ4ECgQIPsBg9tMABhAwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEF" + + "BQADgYEANZcayTTX+FGhtRUJ+XuYA7jR14CJL6qTHPvdSMgHNw9mGXI/7sO5I4v1vayOCI" + + "YQ9luBvrTYlMPmuej8+bhM8YTYpiiOjVFANwvSKArI9U2CAGBcoBMXydykkm8qYw4gtYQT" + + "neiOz7VqI9plLWA111IRMgayD3CAt4Ntpzd1VSE="; + public static final String Intermediate_CRL_IC_02_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wMi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIPsBg9tMABhAwDQYJKoZIhvcNAQEFBQADgYEAVeQi" + + "tT1FRUaJlhfpkfjZr6VHmvGnqYapdo4DRT/pm8tsp1LbZZXpYW638ztwgZNgeBRPFlcb+x" + + "8naQjEkoaYzLbCYfdY+PPVDv7ym15PE48Kve8ImvANY0YnTGS8pcKdK1dpNKBnYYMOG9JN" + + "+H5K/4cSm/WMCKIuKdsiAWFYauE="; + public static final String End_Certificate_IC_02_03_crt = + "MIIChjCCAe+gAwIBAgIBMjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wMi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDIuMDMwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALGbo9yEujZ9RFU+Vmxb5+Rx1VdIG/3E/5hXV/xI" + + "OFu4mEfYh2tBhP2qIMH2KbrR1tiW5t4DvTCBM3NKKqp75wpiuu7E3q6imt1pLbGW13NVL+" + + "81gYWXnCnzHpxYjMTIqqCkPIAeOG+SBJ1MgERbL+NBl+AK3WG4TeQ8vw7r2CGrAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIS/HbII+ki/kwEwYDVR0jBAwwCoAIPsBg9tMABhAwDQYJKoZIhvcNAQEFBQADgYEAWHy4" + + "sHrTkqY1XjDBY5XpNEyhP6htcnjYD9bos4wjxPlJUyxdIWACWrLDE+R5iRCOYsh/nDAJEt" + + "CUcVASukvP6VLJaFjyxUOaCp6JCVV+txk7Fh0S/Ur3Zyysfp5LllP1plOA3N/k1Hliljp0" + + "+bnSiDhA1+3hJh0gDMjWUdRq9yM="; + public static final String[] TEST_25_DATA = new String[] { + Intermediate_Certificate_IC_02_03_crt, + Intermediate_CRL_IC_02_03_crl, + End_Certificate_IC_02_03_crt + }; + + /* + * test26 + * + */ + + public static final String Intermediate_Certificate_IC_02_04_crt = + "MIICkjCCAfugAwIBAgIBMzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjAyLjA0MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDf5u5ouGQlQmdNfc4ell3RXKWmtq+ar9VKMme3kp8D" + + "cbDbUaVwlvhWTkOKxb9I208wfGG2nQiArezIwutlASf7sWo16EPapmGdCF+rp1dpjAPBUu" + + "fruEyCZ8nu2ITD52wuPY9OAcKHQE2/bBpCJWkw97fYX6Q9PPW5uobWoUJtOwIDAQABo2Aw" + + "XjAMBgNVHRMEBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAw" + + "EwATARBgNVHQ4ECgQIjDm8K5YcGakwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" + + "AQEFBQADgYEAEQIJeZj/HE3HvjjJV7PdU+2Ze8OeCYeeWDocxrA647xpeOksVXBXKmq2OV" + + "NqoFk7YNtlSUqiS2TlqjGqLtKYetk7a17qS/8EIQct+H5KWdvkLkYMkfIAAMJvJZHPGxEv" + + "j+oVPAi9FITRbFdN8Jvdo9MAuU2q8d2x8MF236RmEds="; + public static final String Intermediate_CRL_IC_02_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wMi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIjDm8K5YcGakwDQYJKoZIhvcNAQEFBQADgYEAV5bX" + + "7WsT8sWeA0iQ7V/+ZQESDzvyHA7Ziju0iRsvTL7qOVF/Nl5v+zND+ZNPhdJDKEM/Q0lEaA" + + "ybe0E73NMmM1qRX1daAwE++jHukF9TMeNl750HJaS667H6jcjeRrHUJDD0+AgqrZY52dL6" + + "CPM3V4QSvdfc1/xtKmNIZWSSoqY="; + public static final String End_Certificate_IC_02_04_crt = + "MIIChjCCAe+gAwIBAgIBNDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wMi4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDIuMDQwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMW45d5dPrzUJbuRIDeQ5gIJRYxi80PxPvxSmJe8" + + "ScG1A+l75SAtgLGWAxBqxPSzL+teBBUsnmf2Xsc8/qQHHev74uat0lxq9YrZ3npLW2YNo2" + + "CfxLK0M7F1/bhkHK2f9ttIvOrrKI67BeEjfACULdJEhl431uWINWV0pY+fHq+pAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QII61NnUvgvjYwEwYDVR0jBAwwCoAIjDm8K5YcGakwDQYJKoZIhvcNAQEFBQADgYEAjwgL" + + "6qMnnqUvNspsDaYpPQzTCqXkqshZhsy5G/nLk621H/YbNGlnZ6asHGljYVYMzjmcny16y6" + + "ntiv9QPB7YorAx27WT7pQPFla96s+nM/rfwWHPWI6QGDsquPriwJm/MwQC+1oDXEFKvdIL" + + "0urejfd5hgiXYbRRwMI7km97iHg="; + public static final String[] TEST_26_DATA = new String[] { + Intermediate_Certificate_IC_02_04_crt, + Intermediate_CRL_IC_02_04_crl, + End_Certificate_IC_02_04_crt + }; + + /* + * test27 + * + */ + + public static final String Intermediate_Certificate_IC_04_01_crt = + "MIICjzCCAfigAwIBAgIBNTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA0LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDBtNwpr9LZBF2LRtAp9Tb1FZnfM3b/Jv2sdO5zc/Bk" + + "sO4ByUgY+Mux9dEvFrkVWBK110TvXn+dj+85TuboILv4MDKlu+tI/rtuadXGwwDIg8TQnz" + + "uyC7LWhxM5JZs1/Is+sPKUY4PTCHs3+EHPBWf2tFiP3l6ZftkySEiL6+2LSQIDAQABo10w" + + "WzAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAwEwAT" + + "ARBgNVHQ4ECgQIbMuZ73onuZswEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEF" + + "BQADgYEAhaTSc2xafdP/QceMm9YJ/rZJ5gTgBR/SlmKQwd2BclHabG+Fozdg4delDjtRXS" + + "FKY3sFWBFZHVeprh4T93Oj6IVA5X4DIuUeBpprtS+psCnWZxdtcUWmbyYQwZNCifG5C5D0" + + "lRwxlMlv40xT2oCM1zPZpfmqemBDUPJ2OhkCjvo="; + public static final String Intermediate_CRL_IC_04_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wNC4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIbMuZ73onuZswDQYJKoZIhvcNAQEFBQADgYEAMk6D" + + "Rztz1AyFnFr1KAlbjLLwxtQplf2eIc//zUkDFVUHtX5TrEC/ijUaItjdkOoPGQfpnL0w8x" + + "wyqWndMh593QPCqIJTtv/iACoiJNZ90ZJS0adcdZ+AEmQpa0Zv0e1JOqRrPoAfTq4HrOfR" + + "vhBwhvKQNtTExupW/EBudznKC6Q="; + public static final String End_Certificate_IC_04_01_crt = + "MIIChjCCAe+gAwIBAgIBNjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wNC4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDQuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAM2dGkraKGdIi6EXxAu6/ekMqDloX5YSVBGh4Hp2" + + "faujr1u4j8Lp8afqjngRxFUpTqGbqH0ETgm4cVPXmc9rUvUzYTMdxTUmIZ+iW+ULZEvzNB" + + "712kxRPCD2kDFN2fH2ai8miXr434w+weLm8VQN4jJGo4nswhSs2w1gsUmWyn/ZAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QITsLx/sO1edwwEwYDVR0jBAwwCoAIbMuZ73onuZswDQYJKoZIhvcNAQEFBQADgYEAeKft" + + "0RM8/b3zQodaKrTdWiFyLg5fzoOsTecSfdFPXoqz9J5ejLVkvJevSmfXJrIUhKXySzsQi+" + + "GazuTh/hvWjwUTIvmupi+EiFudnMpXCro8bgi48+NkepNjXvjsSmOfzlrK3SxtpH5dqonL" + + "6LHjGyg+Xp0Nor1m5g1rLHyrcEk="; + public static final String[] TEST_27_DATA = new String[] { + Intermediate_Certificate_IC_04_01_crt, + Intermediate_CRL_IC_04_01_crl, + End_Certificate_IC_04_01_crt + }; + + /* + * test28 + * + */ + + public static final String Intermediate_Certificate_IC_05_01_crt = + "MIIClTCCAf6gAwIBAgIBNzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA1LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDM3aWmgX3OzAaBg6lnWjpFQ9ufeTOia3+lIUqn+Ypf" + + "5OH/s9dLRqg1ZynV3YIUyzaJPP/YlUEmrhheJn3Bjw25bHeIKdge73pfEbuBAugbUMS75D" + + "csBV7Ze9D+sVw8w/LtT3ZPcvM3Vju4d+c14Ip/8pC15jlgQPhwVQSf0x3V2QIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBAjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIJ2DFtxoQnXkwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEASvdcfBOh2d1dC10pGLZLI3T+oSPCup/U9riynIR3RxZsIaS/+Q2s81" + + "oeg++WQV6pyYvCLneZIp0efvqh5DThNV9lhBcJjlYwm/T8Hi2IaRGsSMwIvzrFN7zxA/zu" + + "tW98wigAKM2myk/nlYxmholgbQkQ7ZxYM3lD1TDRl69N66Q="; + public static final String Intermediate_CRL_IC_05_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wNS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIJ2DFtxoQnXkwDQYJKoZIhvcNAQEFBQADgYEAK7Ym" + + "Y9PjX5CpVewe2E9PNxj3dLYElghaQyapYoVtNq3jDqLMWspdmHdNdeaQoXsjlSJe0Zy8xH" + + "ZvpimwifnFZ5hq4yByzHjzNMpcA2yFtg2MtPWGEia+BmaZYZi3X0lR+OShKpNLFc4CfVM/" + + "aWG6W2BulHjIAThZhTg3uRekDzs="; + public static final String End_Certificate_IC_05_01_crt = + "MIIChjCCAe+gAwIBAgIBODANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wNS4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDUuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALlcUtceuxDznvI3pVM7YddPcBOrNvrOtpuLOa1L" + + "Lj9LeNH6+8CzRZnMsUtt+bRGqCKMEJLUIIstWwGg4SskXWk2m+nDKm5Ai6Kyx4nldpgtgQ" + + "xZSEwNcwRhpy7TtmLkxDVM9DoTbIbK0dZ7aWw4bXVHPK/lnOMtOaJbFDq0sLfxAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIiXgrRBVcDf0wEwYDVR0jBAwwCoAIJ2DFtxoQnXkwDQYJKoZIhvcNAQEFBQADgYEAhyO6" + + "SP6brWDDKZwdQGULno4Om5+DuilJKamyEcvSqE666z1KhvOCdLicqwVa6tQiAL6akrt5Kv" + + "R+TT0xqHR4JGosGLGolvK4DLrMeD+PRK7m1a+nJl44luo5Mn48HrKI7jn7n8Lp9bNdCHvr" + + "NHaQksCIR/Q8xoucPa+8sCTVSj4="; + public static final String[] TEST_28_DATA = new String[] { + Intermediate_Certificate_IC_05_01_crt, + Intermediate_CRL_IC_05_01_crl, + End_Certificate_IC_05_01_crt + }; + + /* + * test29 + * + */ + + public static final String Intermediate_Certificate_IC_05_02_crt = + "MIICkjCCAfugAwIBAgIBOTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA1LjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCrtIYqo2Is8Cd6Ld+fyWC755oA6hQiiruooaR/6O4z" + + "ikyhOUztnHkOGMF5H4CKWafwwVrfFtqe7iop3N6AToEIpNlJLVy3cj14A/IASVYSSNFeHd" + + "O44Id1NWhPiKx3paPTWslMEdKQV9BlXb7gu8pQpvqTa/38hNQ9vdil/4QZbQIDAQABo2Aw" + + "XjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBAjAWBgNVHSAEDzANMAsGCWCGSAFlAw" + + "EwATARBgNVHQ4ECgQI9P78RavuWW8wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" + + "AQEFBQADgYEA0sAEmWBYSazUav6RtuNFtZgNrlQ2i5i138VzRHoF/kq/CxeR/lINQqgJhC" + + "ZlUnlslUuM86g8OQGlR8SS0Wsi0MdCQCtPCKA2hStlTx9MMux2IZAGoyHy6P95UE9qINHE" + + "fYZUYjO9rh96fzNyJ5Oy2kJdJWdhFXtSh3BSOe0ZD+Y="; + public static final String Intermediate_CRL_IC_05_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wNS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI9P78RavuWW8wDQYJKoZIhvcNAQEFBQADgYEAlPLh" + + "+CMqRcbLgUKEAL2UlSY5tjsF8At0hf000kec93TnBf7f1NKYVJ5eyeoh/WK4s+k4paAA5E" + + "/P2C8JMlGXNTrqKZXMy2zIlufE1ymXAZCKLOLC5ezXRSpwIsBWxko2nfw8Bz/mZO/bCSCT" + + "nDwkH8BJIbFV51vJFlyyOmZnCz4="; + public static final String End_Certificate_IC_05_02_crt = + "MIIChjCCAe+gAwIBAgIBOjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wNS4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDUuMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMPsWBfT8HqaiLnoUCPAFniq502odL4uVqzOOxkx" + + "evZtjh7NaFlRjuYjTofdkj/IAgg7lkkBEW3auK47Td3TvqnHO401PqvOFNTlbhr5wDLmXS" + + "WWcR6XrvgYL3Z3wx15/z6eojcSgu07kdvKqzuLzcDs+noG8lbcruokX0A186pVAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QImgomUTkzwbEwEwYDVR0jBAwwCoAI9P78RavuWW8wDQYJKoZIhvcNAQEFBQADgYEATAEq" + + "YVV0iYdYomPqxbTapSCJFAMQO/WZhN9brCXP88+jRfk6cAHzTodQOYTOAVe8YXa904505e" + + "RA11NNTViP3s/AseGWuqbWjsom9mbR+tVkvufGqPQtm1JhfLgR/68e29AI7tj7zIJyFVYD" + + "nLRXGwMGnosqSHDle+WYyfok6a8="; + public static final String[] TEST_29_DATA = new String[] { + Intermediate_Certificate_IC_05_02_crt, + Intermediate_CRL_IC_05_02_crl, + End_Certificate_IC_05_02_crt + }; + + /* + * test30 + * + */ + + public static final String Intermediate_Certificate_IC_05_03_crt = + "MIICkjCCAfugAwIBAgIBOzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA1LjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCajRjoRNL9HFTytLLx7C8WYouW0uONGsrtGS5tKMiW" + + "oLlQUkohqB2a2PhA1InNGQqnbDtNdqKbR1k6EzD6MyegvXK1sXs0ZE8gt0LZYio7Xp3k+Q" + + "7i4Rk5iTruAUrV8bFMYmeIXHXL/9rl5LQV8YRp/Ut3Bg3VECzfhQG4EavMlwIDAQABo2Aw" + + "XjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAw" + + "EwATARBgNVHQ4ECgQI9041oiwvHsgwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" + + "AQEFBQADgYEAYwGYwLsA/kxYZG/RM+kvoH+mUebrBVZRBxjovYsYzNznD26fssjBFfiTmg" + + "zwZJfG7MZRsgDSRsS+bxuTlXMVeGRKH8fVj7PNq05sS18QZQOF0CCKzg9DLkCzkzkEWBxc" + + "5ersciPrL90UarOIPIJWUxQ/5sdMS/wZtYTU34rNNWE="; + public static final String Intermediate_CRL_IC_05_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wNS4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI9041oiwvHsgwDQYJKoZIhvcNAQEFBQADgYEAJHTp" + + "k+RRsD0dUv59J1GQMWjQTjVz39Xaonx2sk38WHcrHBB78L0W6Skjvt082PwZg32sb7FQBt" + + "boAQ3PIKpXMnFnkjnkyaFihrnMdfa0abCPtQhFl3yra+w+1a2RDjQBZOOdq3xlFcLi9unT" + + "YYome7eS93wchIvNWFpgwF5A5XY="; + public static final String End_Certificate_IC_05_03_crt = + "MIIChjCCAe+gAwIBAgIBPDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wNS4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDUuMDMwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMYxdSZq7qRBdPOz6H+l0GGAtymAWTshfZZCubHK" + + "lQjbVq98qudORfhCOZgOy83j/mo2KAecBhxaxB9YA5ggWNAgaKtFvknvjFemtBCZwt6cVK" + + "8LCyUGKzStwAV1+HSDlHxdWo7pRwP0beXFvFECrX418osGt6E/v7Cz++ZtvaDhAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIgTuCLfTVa+QwEwYDVR0jBAwwCoAI9041oiwvHsgwDQYJKoZIhvcNAQEFBQADgYEAQRuC" + + "rAx9zzu9QwOq9weNit9PNgFHBpo3Gh9jPVYGJjOQxeSqqou503xi82H3W30FT/3ESCO7IF" + + "hfpr/uQZVEmUQnvDsVwbKvED1QF9qkTp6ILk38ITJJgfb+sdSL3bsUeNqVXd0C9wzVoErc" + + "OuoCulwkZzfoIOlO2YAjAnR1nUc="; + public static final String[] TEST_30_DATA = new String[] { + Intermediate_Certificate_IC_05_03_crt, + Intermediate_CRL_IC_05_03_crl, + End_Certificate_IC_05_03_crt + }; + + /* + * test31 + * + */ + + public static final String Intermediate_Certificate_IC_06_01_crt = + "MIIClTCCAf6gAwIBAgIBPTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA2LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDmutL9PY/BLXvXMEDQLQnWE7dCOsrLNvJiuSjDdznF" + + "vBz6WS/RqUr9zsDFknpOWB3Epo2syV4ZFto+v4VWNo61uaClIEsw5x1y0saG19px34KVpQ" + + "wkpvLeRZySdCydKdE1rptYR/JbHvPo5TU4mxOo6L7JeEwAvjSI4tK4rwJ4MwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwICBDAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQI1BB9j6Jyny4wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAajWMbY8zL8jS2VUjCPBMuIjUvBfy55+92EXg5pZnyNNwN1diZfJFiB" + + "rrPWEg3Fa4NMLgaDKWZsYkOcDDo8I+Qb9FsU9LphCzQ1ubIEuxu6KPX9X29BscFOxUnZCz" + + "yuzVfadACxi5Y7Bz5pN5LfC/jEb2iXjkdN5Rm8AqT81syIo="; + public static final String Intermediate_CRL_IC_06_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI1BB9j6Jyny4wDQYJKoZIhvcNAQEFBQADgYEAxH4/" + + "mgACT847PyufmF1nob9TSqBj+cM5ye2bgv83gTVd3B1Gopr75Tnu4iP10d0PpSXjySWCjB" + + "0HPJ7BdxzkKxSrcM5vcb/jLdk9PqMUS30ohexsx1xK+E38pDJdLX4kbJ3E62AgyXm9WQlD" + + "9xsDk7TMXwuxHT4fX070HL6lWGI="; + public static final String End_Certificate_IC_06_01_crt = + "MIIChjCCAe+gAwIBAgIBPjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDYuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAO1VOl25MTf068LOgzmQOmyh8MXunBrQ4t6UYuEj" + + "H7v+owR9JTDXpfzLPcYfkR+BH2jjISSHIJsUDesKVhpmhABNXcOI5tiRNkeDlV2zKCBXKC" + + "wFi5qkhrE8FUCP0hL8YzbybOrYZYSVEP8GgIgMSQcTvhN/Tor0o1jdJvRLmevXAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIFJA9XGd9UZUwEwYDVR0jBAwwCoAI1BB9j6Jyny4wDQYJKoZIhvcNAQEFBQADgYEApRQC" + + "OTU9cp16BHM2n0TdZThgj9kSAQ4wHk/dKNOjYNEWu6n/GQ0alxy1dyRzpsr058FOvft23Z" + + "Kp0YhdKG/7F1hkcoNvC2yN+Re44n7S+F/jcEPTWnOX6h1Nkw8OS7Uz2fZ8t61iHjqjX4sv" + + "M/cKP+AkC8g7p2tfdkP1fQ6ww5E="; + public static final String[] TEST_31_DATA = new String[] { + Intermediate_Certificate_IC_06_01_crt, + Intermediate_CRL_IC_06_01_crl, + End_Certificate_IC_06_01_crt + }; + + /* + * test32 + * + */ + + public static final String Intermediate_Certificate_IC_06_02_crt = + "MIICkjCCAfugAwIBAgIBPzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA2LjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC0JoTnPaI/HT2eAqCW1204nRNjcA8EQSp87tvHLpWy" + + "5aafmxeJxvk5V9Ba7Ye8eY8yX9losbNUpHJFNdE46fD5qp/oS7Cn3NXA0dwIDQEn1X9vaz" + + "nqtZtMjt1S/yGv2xDOb2LKT9zRrqSvxGszCHFUBcJ4HDFJMAdhXPUZiLyXVQIDAQABo2Aw" + + "XjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwICBDAWBgNVHSAEDzANMAsGCWCGSAFlAw" + + "EwATARBgNVHQ4ECgQI7j2LO1CcsE4wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" + + "AQEFBQADgYEAfXIh0oYlM2pagAWzTuYqTl0NavtfqibPgolvhgIG/XmmjswHOg/JVCLb7O" + + "jIYtEG2MAD0xQXwu0mc9Deufed2embP/wc0qVG7rj7lxUq6p0aMQJNndBw4m9KlSnjdzyG" + + "lwE9pNd2BgEeD516J2k7dspCZHDw3qLer4i2JYoCo2Y="; + public static final String Intermediate_CRL_IC_06_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI7j2LO1CcsE4wDQYJKoZIhvcNAQEFBQADgYEAJej7" + + "23qVtwkcvCTPb6afTosYMnVppPXWbtvqn0N5mAFHQfE27x1YPOXOQHBrpQuTyiUdUmPXiH" + + "xMKbuR5o2lfdQgew9hbYVk6GegSu+DBC1JKv2YSTgzgRAlJfyByDZ7mbJwZWHVHys08oGk" + + "adG6zstavg5EkEeRuAp47T+7cZc="; + public static final String End_Certificate_IC_06_02_crt = + "MIIChjCCAe+gAwIBAgIBQDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDYuMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMkIzl9+NRTZf/xaA8noiHRt65Zo6Zp57YvCKUe+" + + "YfoC8koMq12MBgrc0IyIfJoqEDEMfD1WbitZdGZMQZ7D9BP2Bk09NXLEAAuj+waFhYk0bW" + + "vHBH90O7HpMGmxwHmzOjDV3JHYsU8hq77/5gRFDNRkSCJe2A1Maj8Gcqi6tYf5AgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIYDfThEjNL28wEwYDVR0jBAwwCoAI7j2LO1CcsE4wDQYJKoZIhvcNAQEFBQADgYEAJiHT" + + "CjLGZK5Lyw+7ICDHs3eS1OGJH/wfsLcBP5sLER41qJfrXGTl2XdKvBMIpriUmJYzjkjof4" + + "bvS/VPDNlhI9AJadicW8LM4L3qpy7/YV4Dd/C/BJphJ6cZcT+hjaRKeC7gQVjMeC/npu/p" + + "jLgIgzf7HC4WYnaS3h9oYl0cMJk="; + public static final String[] TEST_32_DATA = new String[] { + Intermediate_Certificate_IC_06_02_crt, + Intermediate_CRL_IC_06_02_crl, + End_Certificate_IC_06_02_crt + }; + + /* + * test33 + * + */ + + public static final String Intermediate_Certificate_IC_06_03_crt = + "MIICkjCCAfugAwIBAgIBQTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLUlDLjA2LjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCuUtIYFbVjg8VLLUqIEQ6r7hjTaqYVs8DJnJPHUWPA" + + "JW9HEIV+d6hj/so76Bff4KJRX7MgoXbvq4ivmn8656N7YSGk9GPuJ25SXK7RJyoqzG/x2R" + + "AVUCx/wG99VXVDZhd5ZAVBG2JCkHImsWAei6/Tz8UgXmmLBM8rZNJ/hNtTBwIDAQABo2Aw" + + "XjAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSAFlAw" + + "EwATARBgNVHQ4ECgQIpwUlwG1W+sMwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcN" + + "AQEFBQADgYEAqJhUfgar10fl5qG+oH34s/JS3ku0dRm4cTQvqUNOWA9ALnBhSkmOpoMMzH" + + "sE9FXXcZ072a8/ecpviP04X5mt5QSLreh3hPVvgWv1LiZ9YkS4Z2kcr+3Gx7zj4gQgT5vG" + + "QPpbIBAtBRH5xNHIYQsk6kOe2+t7b0Q82Wnj8UoznmQ="; + public static final String Intermediate_CRL_IC_06_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1JQy4wNi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIpwUlwG1W+sMwDQYJKoZIhvcNAQEFBQADgYEAKCp7" + + "ViY1cajXpbjCIqe8yo/98SQRIxoTNgp7EUaaV17FeHZ59nJhRtsF1XnLP4cK0lPBkKFhHK" + + "2XyDEWx2hK3X7Z3lSAtn12WFJHOP5T5i0DmYfMJYAFbuPD0JQEWCM3aYsgbXKbbFH1BURh" + + "L/uy3arVBP4FaJB8gH678K4J1p4="; + public static final String End_Certificate_IC_06_03_crt = + "MIIChjCCAe+gAwIBAgIBQjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1JQy4wNi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtSUMuMDYuMDMwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALZw+GpvdleGlmdqZ/zEO2DUGhwgrsselBUNnEzR" + + "bcuzr5O1WwiG6aLjrPxIXeL1wLS1/u9AD9p3CQU0XFhi+bEI9+LLnt2y3707O+AQxy1PnQ" + + "6qmYE4jMwqDGHn8WVanN2joFT3isLH5wJD0Jh74eoG0tqCHUyOiXaZNo78qgB3AgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIJOeyCnvfJtAwEwYDVR0jBAwwCoAIpwUlwG1W+sMwDQYJKoZIhvcNAQEFBQADgYEAJbz1" + + "RipbW6uu7B+f2Ol1iq4AVOUuET2S9vi9ojReyAIka3q1XUceZCm5Et0KqpOoOLiu8IRuNB" + + "bvKwRcZ4hcVEXv5bRMqaPEK2B0VrRAV/Llj5A+RGn6yc1ZdkJeBRhoSsaHn5whfICaiJX6" + + "j3lMpo/CiMRViL+gZLU3SdKqvdY="; + public static final String[] TEST_33_DATA = new String[] { + Intermediate_Certificate_IC_06_03_crt, + Intermediate_CRL_IC_06_03_crl, + End_Certificate_IC_06_03_crt + }; + + /* + * test34 + * + */ + + public static final String Intermediate_Certificate_PP_01_01_crt = + "MIIClTCCAf6gAwIBAgIBQzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDRkBhJJVgOXHjydAHAnokd/XfEiW+bnWd2ZPJrMBmP" + + "7TlvVpxOGqLd6lGdbelbSyAzut1i8lyYn9NSDR0PcyehCSS+MsKS2uNKsTEuH3mlMK/7C5" + + "B1qggKqE8f7opyl9+U+Qyi1WQj01gY6XYXaCxksCB0Oqx2737d7QWMvl15dQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIO1U69B4DBHQwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAcHWV4Q4z7C+IC4bWgIf1+BzkszCN+LSb4JquR7GgICESbwF2JzR+xL" + + "7yoKvB/NBcCqtMY4Hi1DHACbIGJwRe68vVHzz4CmYEK50UUCbAtiAiy9Od6wwrTyFyacBd" + + "CBjiO6mkFEp6jOsoIgXRfxK4kDNcMkGUUwMbSR/wZKFuImc="; + public static final String Intermediate_CRL_PP_01_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wMS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIO1U69B4DBHQwDQYJKoZIhvcNAQEFBQADgYEAHtbX" + + "MUofQlCnbJhgLQw96jsBRu0Kdx/Rk4LWxEbZQOWNaD7aukASjEv63d1qZIDgpefuUNTz5s" + + "3eascdtI6iyWFtBO3r6tihtkkSbxocN2Rz7OlR4rW9VwuUirxP0145nMd5CEL03/CNABP5" + + "zUo1bNgswHW3z/RaH6h0j0yTkbo="; + public static final String End_Certificate_PP_01_01_crt = + "MIIChjCCAe+gAwIBAgIBRDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wMS4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALQaTS1wvv551g3BP9JYBMM+KXXLzxtOwPlO5NR4" + + "LwuJJB2WuO4vmbn8AG35in/0JqwjZeroLQvbCPxZseXsyA0+7cMO0qcjRJ5l5WdFsahT6g" + + "z1YW8pYYY5i2eDUkIRsM7roHMiNjt3zpkuUGX0xZQfAxhuWnRIvlGg5J4r7UOdAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIeyLSANVaTpQwEwYDVR0jBAwwCoAIO1U69B4DBHQwDQYJKoZIhvcNAQEFBQADgYEAvZ4a" + + "SQMNl+Q++D9yVaGr+37XJyxs4yow5e5YM9LXn1qBASQ+GNfqPWoe2cPCPYKj32yulxyFEu" + + "RHrbhpEQe+nrKWJgO9W1bmfwgQDin29ne/JCQPlznhd3EPFvCkmPLnTyJmSLR6B2VxvndM" + + "GO8JEbj3KCf51uf3VnC/Qj11mX8="; + public static final String[] TEST_34_DATA = new String[] { + Intermediate_Certificate_PP_01_01_crt, + Intermediate_CRL_PP_01_01_crl, + End_Certificate_PP_01_01_crt + }; + + /* + * test35 + * + */ + + public static final String Intermediate_Certificate_PP_01_02_crt = + "MIICfTCCAeagAwIBAgIBRTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCkQQXRO+dnU2v7EbaqQNmfPD8v0s5Wa50hl9M1Gfr5" + + "5nuVUZs/RI//1VksTNrW10MVh11nsxpA/XRPntEIbHiH1OoECd4dnZBiA/2xEueM02fTjj" + + "fb/t7g+pr9dSU/TzCVZDVWFBcPn4VNz7BBqIrTAOXaJkyBZ8hh7vyiE1Y2VQIDAQABo0sw" + + "STAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHQ4ECgQIoTKVlZ8YCR" + + "AwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEFBQADgYEADhtnd6ifr6kyfC5D" + + "UWuAXLtoccMj8Jaur/1YT1DgnH1XbBsEeZwm9Jkzr1a3cXPIHgaHYgXvBeGUtZ3XhbCSGp" + + "8U6clJz3lm3qKPKkb5rdDrpdTaPnEJJjS3C4ZK1L7UZtQga2Enlelm5vIkhjsF3Sexe1kY" + + "mzqiLZZ8yLxJ/Tg="; + public static final String Intermediate_CRL_PP_01_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wMS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIoTKVlZ8YCRAwDQYJKoZIhvcNAQEFBQADgYEAn94u" + + "sT8ZYNzfHIdnx0+fV0jglL0Kn1duz+ehKHow+RGqH+J9opMYuXVD+rVQnLdZl5LbFBcv+5" + + "TSP9WR9QtyoXar4/jmY2FFdBjfgO9w7p7OHD4WxblJmfPVOvrzFm/slZE39Oe5Qn4KlS03" + + "9tttEFTKDH3qREQbT6g4k4ExxYM="; + public static final String End_Certificate_PP_01_02_crt = + "MIICbjCCAdegAwIBAgIBRjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wMS4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANBwkwTWdZ977UAx6CCpXc9T4MX9T3/Tt6LbtY9I" + + "eXxI9W15eXm/aqrKiXhULB+oF9/qNeUi2fAtrURZ7hgHbTaswr8CZ3Uwc6Rbkyj2GGiM6Z" + + "8sKFztYZfFyGBiNEwfTT0yaUUQ6etIFqPuL/6qLvqXmvNPxFb9gjTH/azs/MdNAgMBAAGj" + + "OjA4MA4GA1UdDwEB/wQEAwIF4DARBgNVHQ4ECgQIW1/BRCbe3c0wEwYDVR0jBAwwCoAIoT" + + "KVlZ8YCRAwDQYJKoZIhvcNAQEFBQADgYEAPJg24q7wCU8CVlxFLchoe7txhkzApkVMIJ9G" + + "+QTnraHDn0CZS6undCsJw8mrTNBQPHFn2Ixa5lrPfJvwW4Med1bcJKbwR4TveL1WeYYq6+" + + "9k1kS/7KmqyKAKC/s504jAc7qgMd4b08oLxbGVfFVjWG/ZMbO770FrsyRHHs2rTOU="; + public static final String[] TEST_35_DATA = new String[] { + Intermediate_Certificate_PP_01_02_crt, + Intermediate_CRL_PP_01_02_crl, + End_Certificate_PP_01_02_crt + }; + + /* + * test36 + * + */ + + public static final String Intermediate_Certificate_1_PP_01_03_crt = + "MIIClTCCAf6gAwIBAgIBRzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDL/XgMvoeszcAzZqMYnv1At5u83Gb/CEX3fv6O1jL4" + + "W3XbdvBNIZpuTwQhTH4Iofk9rIuQdkR7xOmbk4AqZINuas3Y1CPdzss7teraK0CNralNl1" + + "jPYK+ClDBHt32Iw3bAl7RqWX73hl3YH6/7cvG4XCo1HqeeFFHUGa7HXGXq9QIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwAjARBgNVHQ4ECgQITMu5Qbn1Cm4wEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAuCnzXbHg87PIYYRbCCiXKDKA3MOcEKuxpNaSbtm12DQWpnvzmaK5nB" + + "D/Ebko97CS7u9Tpwa7TmTyi39bYzY0dmVaotCDzfSTpzw6qHZl/w8riS+cKr0mimnjW1cq" + + "kGPyHf0zBBqh0liGbd7EOLIBln0ASrn8V+G4Tj0Q6aQVcko="; + public static final String Intermediate_Certificate_2_PP_01_03_crt = + "MIIClTCCAf6gAwIBAgIBSDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wMS4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCu1Fq+gBJsBf5EjKKtNIxgdtgPMObby7tKH7fTJxYE" + + "5LPyPi/IiWQ5Mi/8BCG3zmQhu9ZdBbpal350qCGVTbaMlnpi98D4WwXSw7e8oHIJIK689p" + + "Q6Z5cf8hgwPnwDpYLeEaqxwhd4bu0x1lG1fUISA0ZZIQaEeNSJfdh15IkAswIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQILRhQwULcyPYwEwYDVR0jBAwwCoAITMu5Qbn1Cm4wDQYJKoZI" + + "hvcNAQEFBQADgYEAlEVOqXcdeTU7wT0l+/BJhlG5iaAcanAsOaJFZsXPjLMSjhldQe11/z" + + "BsrrqjcpdctcmBarKO4MnwqVU9DN2RZ/v5Gps6OcPxj3T8wlrCGe4l6s9d1FncBMJ0RAUe" + + "QEn2JLkQW5JWRBQ00+RXJYFuIM6Ger2MipWj1oOciv9MMoc="; + public static final String Intermediate_CRL_1_PP_01_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wMS4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAITMu5Qbn1Cm4wDQYJKoZIhvcNAQEFBQADgYEAycux" + + "rzvy2IiYfFkTw7QgGuBhxIQPbSIbfudqyUumuviHJkIMZpPwYj2wltjyiRaozrDAWq8mlc" + + "PsFYNr2lUYN5Cj4BhNQCNZlyBw7LLdzRgza55zVjmYkHWedyZm3kPWe7Y0w8xc/XIvi3iC" + + "qlwV+X85cgHNJarx3GEYdb7Yos4="; + public static final String Intermediate_CRL_2_PP_01_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wMS4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAILRhQwULcyPYwDQYJKoZIhvcNAQEFBQADgYEAbcjU" + + "+8l6pSik8PcuIzWndAg/w8uRfAgR5W9hPSXZChlx7uM+48wK98DGEXuTkJcbeclZia+Mpi" + + "J5u3qG1zhoL1aHr+RqyJrjiWKC4/rDBuiUk/ftU54mrYn0qev3aSjf/GLtpcC8kC3gpqD+" + + "20bvxLjBG3Vc9ZrxDvzfj8cD9K4="; + public static final String End_Certificate_PP_01_03_crt = + "MIIChjCCAe+gAwIBAgIBSTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wMS4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDMwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMO0l0+X6jfT8cY4DumtseTryyIJ7h+nraogXmYo" + + "uhFGvMUWEAZVGD4x9QTTVEL/UCqNfzpI//Pp/uZpDudSgOX0ZdAbykObqCAEO85msK+eie" + + "8baS1cW1XGjCuWDqNZko3Uo3c5lLPlRMbZ3hjvA1zmYh3prYnOh032GZAArVcVAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIMh2aWvtm0mgwEwYDVR0jBAwwCoAILRhQwULcyPYwDQYJKoZIhvcNAQEFBQADgYEAigVE" + + "FlCgbgKLR9FWIiwnz1bZ0MKsfhytllCI+jGx0Q3o3CxCGXs9PvL6BPDdMOxNIT/oU2uG64" + + "EhZEjcZCnUknGx9OkkSSVq44P/pGuUx1g4Kx4i8gsJ/UPrPpYv/3heuMcKWCr92l33cxPT" + + "IU+kmAtqy0MBvBKL4p635+MSIVA="; + public static final String[] TEST_36_DATA = new String[] { + Intermediate_Certificate_1_PP_01_03_crt, + Intermediate_Certificate_2_PP_01_03_crt, + Intermediate_CRL_1_PP_01_03_crl, + Intermediate_CRL_2_PP_01_03_crl, + End_Certificate_PP_01_03_crt + }; + + /* + * test37 + * + */ + + public static final String Intermediate_Certificate_1_PP_01_04_crt = + "MIIClTCCAf6gAwIBAgIBSjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA0MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC9gxMP8j4L+ISffY9wkislQ/V5sO9LzZOncYK93lZf" + + "HXJG1MPSQzFPNzDLSc2zsilA03v6q+zr4NRrRWwWGmB34NGM4aqkoxox/7ngTn0MIq5gZ2" + + "eOx0FbjA9W9DHEceVDS6kgs9lFcN2W+muCG2/fGqQUED9Fzl9JSM/tE8XAKwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIgdUt9H4i6kwwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAxPe0vM0BvormJLF5HxkyFcTtoombfDGANoLoyj+PTWRD6z1/AcAx5K" + + "rn/0J1sZo13M2ezaZUABbbpNH9X0OS225IJF4mXNpfkYhsz/+jNPGjRpN2p0K+DhMSawUw" + + "QfGv2x6f31k6WCdy/769i1mwKP6Rpph2nkRyYW8MwO0N5HU="; + public static final String Intermediate_Certificate_2_PP_01_04_crt = + "MIIClTCCAf6gAwIBAgIBSzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wMS4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA0MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC7YCtN67S/ItOzaSGqTvfEE483HoQGiQZ0ob3+0beK" + + "kmbSGADBQVBKe/sLJEKddyV2Gl8S4x+cKaKBWUI8lMZViJwWqVnyAFd8ZiAB/BpXaKKgP5" + + "pFsg10Yo/EtsxGlLSTLurst0azNnFv7ca5Hb8te3T91eaI6y59IjbsRgilSQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIGazrt+QRNCkwEwYDVR0jBAwwCoAIgdUt9H4i6kwwDQYJKoZI" + + "hvcNAQEFBQADgYEAUIz/MSc6K5eaIAg8skaAgm6rSPvcU/711b9G0qsIs6YqvEz4zhGi5X" + + "nalYYXfaSQzomuRuABNvuR1Ydaw/B9OdPMro0DhX8VpY6NzCL5Qj60/I4is5a+Hzgk82ck" + + "eAC3okPHbVMd7R9kdFsWNE3Capnv7rriqXO3vwFw8b9vXD4="; + public static final String Intermediate_CRL_1_PP_01_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wMS4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIgdUt9H4i6kwwDQYJKoZIhvcNAQEFBQADgYEAkR24" + + "ebKfvEhDA0C7sawukQbv/q8mjSS3CrhA/oqeb8bML1IlW8rjHSXuRU/n3oeyAZuxLCAQMU" + + "TPG6Vq4dOu8XC1RY74xIm8ps4mE0xB8/nI5kadHUSDPtUZhNzc8tv+z7fUGRaVGL7CBEpq" + + "ICyQKYytCwxyf4xu2Ip71Uy2tuo="; + public static final String Intermediate_CRL_2_PP_01_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wMS4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIGazrt+QRNCkwDQYJKoZIhvcNAQEFBQADgYEAjpUo" + + "XSj0HX7Wm4w1FiRBBazInGOhSQX9VP2GcGb5lfr3GKt75Y+C+C9qd5X25DVkA4M1gPBK+u" + + "XjSMQoHAmFJychQG23rcGcuDJlzRMyfvPCF9dOGLFdmkuHSo5hQUyYsxnXV8cWLIkR1AUz" + + "PtUbTJL9g98R/OJFsCBiPi+By6w="; + public static final String End_Certificate_PP_01_04_crt = + "MIIChjCCAe+gAwIBAgIBTDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wMS4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDQwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOtf65MaydWM3bmMT8tAGCX8gZkx1JlgQyBlJT67" + + "2APIkfmKRFK/dBtSwwCVGHZG4JYBrrwMpzUPrkGKYI6ZVIvvPnPfadZns9i5SM5LZFS+a5" + + "JfbRnSJd8dXhZsKHxqkxIWwG6+VgnRKXE/Uc4m8TePQJZEOra5ezna5yhvqUwPAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwAjARBgNVHQ4ECg" + + "QI4iNoMjKiXMkwEwYDVR0jBAwwCoAIGazrt+QRNCkwDQYJKoZIhvcNAQEFBQADgYEAmOjp" + + "2EupE1AmgjGfiGK1fk9kf39yQXK1EDsyO6KLdWL/bmWeYi/G7ZE57/+yVVADJuHI8xVIDZ" + + "LAC0u5p35OLgbcmmA5bs52KWJJfa0nbgGpVaUSMg9SkEGS997OsgExWMvYhdFIKXlq4Rwc" + + "ca89Hg1GlXdrpfD2OCDNBvcWB5Y="; + public static final String[] TEST_37_DATA = new String[] { + Intermediate_Certificate_1_PP_01_04_crt, + Intermediate_Certificate_2_PP_01_04_crt, + Intermediate_CRL_1_PP_01_04_crl, + Intermediate_CRL_2_PP_01_04_crl, + End_Certificate_PP_01_04_crt + }; + + /* + * test38 + * + */ + + public static final String Intermediate_Certificate_1_PP_01_05_crt = + "MIIClTCCAf6gAwIBAgIBTTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA1MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDFzEEzV/yUEORIOufyqpZzKpYz5aPyBbcDf8AMMCM5" + + "tEz7j39cf1f227cbrTcAaUfYFwkrb07RU4bTS2X+U2Ak7Q5OROz5rrZBbsfwF3yHhwHxCg" + + "KLjbwz7D+OJdNfv7x2HRckwfMUkmP4cEuJIIPwj1ieBbsnUi9dkWZePwl80QIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIjsCjmszYCHMwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAWMUBdOdHMB/SV5kPUk+zut9g/1v/GyxyB60mq9jGqjrIsk4a9JRqa5" + + "MWju+6kVfSLelAOCR24EQsXnZM/5Qqg3Wb/SFJXWDcBnfWQWgh8UmJfmPhD7jViG5QVIxn" + + "iALNCYtz373L+IDECLMO6S3wcTPsHdYv14jl6BKtabwIpE4="; + public static final String Intermediate_Certificate_2_PP_01_05_crt = + "MIIClTCCAf6gAwIBAgIBTjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wMS4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA1MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCZzdj+ixWCuxJGMjcoHUwSNqI9Wt9gYwXUTl+dWg/E" + + "lg2SPJP7lrBOibAhSmaTorhunUSEf2adhdxhuGrd5Ucp6G0oZAa6ZDWaID4rKYWsI7d5kv" + + "mrUhDEEdzk2s4PCoPiQm4dKwRg2rIvA5Dv+W1ldqSVSG376zVrQ5xdjDUX5QIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwAjARBgNVHQ4ECgQIUASviIKBmJgwEwYDVR0jBAwwCoAIjsCjmszYCHMwDQYJKoZI" + + "hvcNAQEFBQADgYEAa3c+0Drcq7iWP7K+gE6Mz/0ATQoiG87irXWfWBUGWtYnsh6K+1THMl" + + "ibmZjYhsztK1P5rm6qL6HAyw0PhrRE9imqZ16cgiMomh65BWQImOeiXx9YWIPvjXWsE6iV" + + "E31XShr9b9OZBA2+Zpydc3ID/SQzy9PiTAfL5yJiW/JZvFw="; + public static final String Intermediate_CRL_1_PP_01_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wMS4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIjsCjmszYCHMwDQYJKoZIhvcNAQEFBQADgYEAZIzN" + + "pXT89MplQgcXcA/K7YKlf62QCbw3rE+bUQiumJMlNGiVdaNJ8T66ObyoOWE+s+KN/Oetlu" + + "HglQ7r6RG68gHYtZZiO6kmxq+wor65dFGQyRggpD+D47yioEgR12wUUksL/8oBW1pfGW2B" + + "dR4sNWjzV5k5EWbLYu7wxj2/ubo="; + public static final String Intermediate_CRL_2_PP_01_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wMS4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIUASviIKBmJgwDQYJKoZIhvcNAQEFBQADgYEAlZ06" + + "h2L/89GvCtU1K1VtbHPMN/LAUYJrWFID1Eo+Cf/5wKEGBr8hxRtvshTK436zqVQRQN/XTq" + + "7u0SLxvIixNRErlmUlGByi5vumN2OA77SxOyqYLCnBXTd5tWbFGz/udjaNk1MxOK0MQxPV" + + "9R+HHUUVojRnAIQvlcqx/sMzU5o="; + public static final String End_Certificate_PP_01_05_crt = + "MIIChjCCAe+gAwIBAgIBTzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wMS4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDUwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALyBn2GKvoKNHcu3AEJRCbWOyUpCc/onvRoQgWRr" + + "wE7vMI7vjqnoR8mXdWDW5u9DFu9V5pb/yHBWn1zpgFGNnLrqn8irwR9i6Q+qlu4lXL5WSr" + + "DqBqEKxrOBDPgkVz8Ldjt/Hy57qEukBarvpAwTc4XEJPAmxNrboMeGCEn2UShbAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIaV3Cd/83r08wEwYDVR0jBAwwCoAIUASviIKBmJgwDQYJKoZIhvcNAQEFBQADgYEAVJXz" + + "gooT1qd6rdehnLxJMf1HZ6JuqpyoQjzWF1jA3SkJmBDMXvAkMmIcQ7r5CZHaVF0iMQl5JW" + + "fxPtM9Bws6jZhVL0TkwJHmbnSvbzUkJYeXPCP7ags4bu5I32co1nFVF6wf3aQDZeLFj/TU" + + "1GCQ4rh80T5oknuazD4xXAYx9sE="; + public static final String[] TEST_38_DATA = new String[] { + Intermediate_Certificate_1_PP_01_05_crt, + Intermediate_Certificate_2_PP_01_05_crt, + Intermediate_CRL_1_PP_01_05_crl, + Intermediate_CRL_2_PP_01_05_crl, + End_Certificate_PP_01_05_crt + }; + + /* + * test39 + * + */ + + public static final String Intermediate_Certificate_1_PP_01_06_crt = + "MIICvjCCAiegAwIBAgIBUDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA2MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCjeJAwaZ0cw6O76hu15XadwJiTsIJcXZxGAETq8H9p" + + "VJs7kJh57oLpO/lG8zG89QS9g1ozxaaGDWsSyXsDzv1eqDVZg3ISQu6XcKdDu8EwgQDY3S" + + "EGkJ2AidFue3l0kEwR9+rtsuVKd/P+ULF1hWcoyLB/sQD5z8GvIiDKyRBiFwIDAQABo4GL" + + "MIGIMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMD0GA1UdIAQ2MDQwCwYJYI" + + "ZIAWUDATABMAsGCWCGSAFlAwEwAjALBglghkgBZQMBMAMwCwYJYIZIAWUDATAEMBEGA1Ud" + + "DgQKBAh9i6tKUsPTgTATBgNVHSMEDDAKgAirmuv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQ" + + "B/Gxsb5lxSTN21CrjBp2aE+U1oTP2MpIFWUD1q8KWhZZF1iCQ7orcDVITqJPdPxDu1YwKk" + + "zOegc4YBSJzHZqF/W4Kw4wisMfnWLTsUAeP/Ucz4vXk5rsf7IRssFG6PLxVmtRZizoxl9a" + + "DO9abTM/jV8Mgi1IB6LdWgmtosBGBzbQ=="; + public static final String Intermediate_Certificate_2_PP_01_06_crt = + "MIICrzCCAhigAwIBAgIBUTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wMS4wNjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA2MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC8DbqYUf437toWlRkOQA5PloqYQjWYpiR67yGSjQHp" + + "j/HlduTYFS4qfUbLCjH4qsNUH8yQDvogImQw5M1IQOsUAqO6mYFxjqUWccuOaHT6XfUaOs" + + "DDHr/tQUvhz3LJryaILiPlNcQF8QiYpujM1utVRyFpmUrMAlOvWUB93c/xUQIDAQABo30w" + + "ezAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAwBgNVHSAEKTAnMAsGCWCGSA" + + "FlAwEwATALBglghkgBZQMBMAIwCwYJYIZIAWUDATADMBEGA1UdDgQKBAgQxGVMTJml1TAT" + + "BgNVHSMEDDAKgAh9i6tKUsPTgTANBgkqhkiG9w0BAQUFAAOBgQALJtPqY5uROJ+2QYTekn" + + "fSUc0gC7j3/cngIvxGT385xDLTrd6TjYSi+12+vU7RNd3MIZoz1o7RpWQV6C751WtOFuZi" + + "iXeQ758aLqfhjYSVW/NHkO8vjrAMUzUbgjqb03k7q5JgtT6udB+9ySmou2/RxYW5p/IT17" + + "euMVGmQb/RFg=="; + public static final String Intermediate_Certificate_3_PP_01_06_crt = + "MIICojCCAgugAwIBAgIBUjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wMS4wNjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjAxLjA2MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCsQqIx0ayxpIE8NduclvK1ubbNkXyvr0RDqnGOoyTj" + + "yMtnfnwRbclkFCNBdalZYofuTWP0reqvqGqsBj+RS3uazvDBqVmn0J0AGRiLILummgEFRJ" + + "ow8IB1hduDYJpDMrHRpfXpbG2H3fzN1XeX/B0hUZgdQ86GyK2qrmyIcyqZXwIDAQABo3Aw" + + "bjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAjBgNVHSAEHDAaMAsGCWCGSA" + + "FlAwEwATALBglghkgBZQMBMAIwEQYDVR0OBAoECNKJMmEWCA+jMBMGA1UdIwQMMAqACBDE" + + "ZUxMmaXVMA0GCSqGSIb3DQEBBQUAA4GBAKv9F3+Y4N8RX4bRZ4fFTKri2rrB4BsVrBFpOr" + + "SLzKnuyO1O5gg45d70pSHUAVBn3pz0f/6WwWLECq9tB7/Fphi0TyqeFmkRnysygZGlvLgs" + + "L19bpIgVPkjFFziMGuzdAFIGy8vnV19yJ2euMygEHr20yiGBUaHHnKyuOGbDg4i7"; + public static final String Intermediate_CRL_1_PP_01_06_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIfYurSlLD04EwDQYJKoZIhvcNAQEFBQADgYEARL4u" + + "DZvfcQDYanTfwU/hWAJDdDO7m7oQZLy3o0PTqXkk2Jd2v3+M2U8UN2PcuqZXT1lwS/piiW" + + "Sc1x1YndD0qUtV4bOZ9SESPhCeOc1lQTk5mMf/zqFxQqYv8rfDB5O3QY4bjS7QQzSsvmal" + + "TGCnoHmUJ4skmZJrQAzYnXyD9G4="; + public static final String Intermediate_CRL_2_PP_01_06_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIEMRlTEyZpdUwDQYJKoZIhvcNAQEFBQADgYEAcEyr" + + "sgLhVq0L6N5fww/U6TW4lqaVAEtjqxluWRyZnL3AJLEHfwh1lllCG5dNM5fahGDOW/53fV" + + "+gW5l92bsi2D/lAkDfNUdQdi5ZpQG9y2zhTArUlx9z1+KXklCi2Gg1X22gi+cYbK2hfzk6" + + "kNGP1v42bjrkF/ECczpy3e41rEg="; + public static final String Intermediate_CRL_3_PP_01_06_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QUC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI0okyYRYID6MwDQYJKoZIhvcNAQEFBQADgYEAp3uQ" + + "Tn2HC65TFmSjzvjuStIJwJcVahNcTWiGdtfTalZrMtuC9vUgQq0K1QIa7QNC9C3hQlzb5e" + + "bO7JhJDs+5GZnnsqHN3pvdKEoueRfWBjUGpPnSGFD61ysf9aDFY2j9Amf3zcBFsXZs4+DM" + + "dIENndbjkwqCV4zRTajAqCsIy20="; + public static final String End_Certificate_PP_01_06_crt = + "MIIClTCCAf6gAwIBAgIBUzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMy1QUC4wMS4wNjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjAxLjA2MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC+IxiNJMOQG2gx1xd9ELNuzs9LrVJVRLvgP0lpWrx2" + + "2HTEXPDB6YmrEg/YgyptmQ5Z4K6CEgJz3EdDOarCSGcL7DmcSEwEw46MV3piS5DrHwQ4GH" + + "a2/ENSh3lF+6dliBwbQR2necmQ5g8ekqkWNb65pLl6RCNGkntJpdu8w5GWbwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIMf/eRyakKwgwEwYDVR0jBAwwCoAI0okyYRYID6MwDQYJKoZI" + + "hvcNAQEFBQADgYEADgpHRDgyPuK4dc+m2p0IELHUAK3qsdTZzBXsaA0rkkk1aRjI6DQ2qg" + + "b4crRU3spQgYwBC7KQYd/hp8Lk17iX6fdV/9wol0DxTGhamOJA0uRl768awRArf4cEUElF" + + "uWPN8D3wJEfL6BWgReUJWg8V9HEtdvXZZgzFN/CgHRkQ2RM="; + public static final String[] TEST_39_DATA = new String[] { + Intermediate_Certificate_1_PP_01_06_crt, + Intermediate_Certificate_2_PP_01_06_crt, + Intermediate_Certificate_3_PP_01_06_crt, + Intermediate_CRL_1_PP_01_06_crl, + Intermediate_CRL_2_PP_01_06_crl, + Intermediate_CRL_3_PP_01_06_crl, + End_Certificate_PP_01_06_crt + }; + + /* + * test40 + * + */ + + public static final String Intermediate_Certificate_1_PP_01_07_crt = + "MIICrzCCAhigAwIBAgIBVDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA3MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDs3Z/FfgJOyKp+Ds8xiQBM053cWylYbD+g+zuWDz3d" + + "nD0eF77TLPITL7hwI058Pn3tXHlveuKMFqbvzWUgFXaBoHmmRohIj1eqfJQhlmKLjlSYyC" + + "N4xhLVi7vg71ZjFdRk1k8ME1HDfpb2WXqXh9LyRYY8b/aqL+NHe1PUDbT6FQIDAQABo30w" + + "ezAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAwBgNVHSAEKTAnMAsGCWCGSA" + + "FlAwEwATALBglghkgBZQMBMAIwCwYJYIZIAWUDATADMBEGA1UdDgQKBAgvehPxsTfSBDAT" + + "BgNVHSMEDDAKgAirmuv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQBpdMBEONGcpFitMN1ihf" + + "W441E4HVTQwtF+h56aagVFndUF1gQsVEdDNmvvN/jdlzXotcfdEj1lOahmcwWbPOlNx3PB" + + "LUPAcaNM9SCrXWi1gKJK3gXC2OAxj0mT5XhfPlAdfhZXTBZLqMqebmk6kVwa+VyPPZFHGy" + + "BW0fV2ClJ69Q=="; + public static final String Intermediate_Certificate_2_PP_01_07_crt = + "MIICojCCAgugAwIBAgIBVTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wMS4wNzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA3MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCrO/98w96Bg5YTTmtdc9sL8AOABGcYx5J8E1Y7/GhU" + + "2sInc/j0dtBbE0Tj4KFIKpVLD0m2mTyHVCUA0/QGiS1Tq6DzmZW/V36Clya3CoX9rDTJyU" + + "cKHpgntV19fFAK58aksyKCdP9jjLpbSspzOlIc+mVW+hkjgw3NcuY6fAOQvQIDAQABo3Aw" + + "bjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAjBgNVHSAEHDAaMAsGCWCGSA" + + "FlAwEwATALBglghkgBZQMBMAIwEQYDVR0OBAoECEmeATXRkM5EMBMGA1UdIwQMMAqACC96" + + "E/GxN9IEMA0GCSqGSIb3DQEBBQUAA4GBAG/Qv60jyImedUXtCYl0QpQ1Ne2ZLxvUHRLms8" + + "B1nXC/Rze7zfz5cwiyQn+6XN2rhuYFdTMDEFZDIjeeCLNllfan4GUAdRGtoJnfoLOGLlQf" + + "RW1ONc80cxd1NTxHqxOtqpWdoJQEn8070WLqQPACEs88XYKBZ00sF9ZdSg5vhHUu"; + public static final String Intermediate_Certificate_3_PP_01_07_crt = + "MIIClTCCAf6gAwIBAgIBVjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wMS4wNzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjAxLjA3MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC+5b7o4iWl80ntDMKGcnquLQDTGlf6Gy/8y34Vw08/" + + "8ij+nuHMiKpo6UCF0OpDcnkJ2ovvMsY5dAb5ErhH64UbnMlKbghnGv0sVidtipoC8u7ey1" + + "YUIzDCdmbNvTfho6IXKzH8ev//K+FJd3qBuKHl9u2Kk5+igsyb+bPSid7d/QIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIUDKu7h5EQ70wEwYDVR0jBAwwCoAISZ4BNdGQzkQwDQYJKoZI" + + "hvcNAQEFBQADgYEAnKhR3OvdgtVtmio7ikCvjxlSoKVbUleazxONOxHUAKdXEv0/mSOTwp" + + "hPPIoE2xAqPOOHvXPmzmJpPADjrfhU6afJ7ThDRFTMk4ZLOkT1SvRlymK7uWhj5bhUgi6S" + + "UQ2LUmrY2hIN4cTrrzZvDw2Q/6UIuqpmySXEOHDL5T5MXEo="; + public static final String Intermediate_CRL_1_PP_01_07_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIL3oT8bE30gQwDQYJKoZIhvcNAQEFBQADgYEA4gZR" + + "71wRXNdxWe7kaQPAw44UUw+cN1bDBU0RV7nwYAFDYxDIaDGOfjhUVTMBq4rb51S7uqIqYS" + + "F6j7BdLXl9WVRJobfkRH0t0cBnuSeQRz3ckrZrCuvyxb3PEL3pbf0UH1i/BfoG+EHJAY7R" + + "OVOL/dyoXeX6ehH6ImGhucDixS0="; + public static final String Intermediate_CRL_2_PP_01_07_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAISZ4BNdGQzkQwDQYJKoZIhvcNAQEFBQADgYEAfzKw" + + "NHrl10PJDHa3olBYXYzXi94zxDsEQSIb+W4pPXUfDZijPqL1NzapLqc/uL1Sl28GmLDrbm" + + "nCrlMn1Kt/gI6XndOnSyC9Sg6WDxAI3HTHxlG5MHLBn9Lb36CHobnwep1BMo8zl2clh0Kz" + + "PIxQSGXM1BDpHkwF5eoFAolDih4="; + public static final String Intermediate_CRL_3_PP_01_07_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QUC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIUDKu7h5EQ70wDQYJKoZIhvcNAQEFBQADgYEAj7+M" + + "EeIe1GmJpbRUFqbNrDvT5tHjKQMNdbe5Y8F920U5t0ig1Up60kc7hs7LH57i6R/quPOpym" + + "a9Eo9Bql+P2Bg9FELih5/a4B021TZBmmdSI5fwQZ6Q5PjgG58Zl2cJitNYvGi7tVUBojA5" + + "CSN7KBMyipia9ivxm9a/llJPrQY="; + public static final String End_Certificate_PP_01_07_crt = + "MIIClTCCAf6gAwIBAgIBVzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMy1QUC4wMS4wNzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjAxLjA3MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC/RmUcYHxgQRHCUh5cMug/J2o8DzYbT+2pIehJkNCr" + + "zfqemV3qshLdMct5GV73oEkG5b6n7tj3/hI1TLh/A3LQpKROAGZybdo9fk4Pa0+6V6ql/U" + + "NnSpcAKct/f3IvchGo9nBGdi9aE+j+xKhMM6E8xj1+Jc7Z0xz7zE4+qRbeZQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwAjARBgNVHQ4ECgQI/y572lfRyH4wEwYDVR0jBAwwCoAIUDKu7h5EQ70wDQYJKoZI" + + "hvcNAQEFBQADgYEANl9zdMKbaq14OP45PeK9D4ftOSuliW2di1qAX38FQoWPYLLoaDU0Q1" + + "9I54PDY/UYRR9jKDl1WPhV6cD+65eadtiOZVr/h1CaW/HxTloouzN4z1zCXMC7AxZKo+EI" + + "XLN8f4w7hKLFYgf6gP9+iVi+T2gKfH5Ch2zjRhlmGFRgsBQ="; + public static final String[] TEST_40_DATA = new String[] { + Intermediate_Certificate_1_PP_01_07_crt, + Intermediate_Certificate_2_PP_01_07_crt, + Intermediate_Certificate_3_PP_01_07_crt, + Intermediate_CRL_1_PP_01_07_crl, + Intermediate_CRL_2_PP_01_07_crl, + Intermediate_CRL_3_PP_01_07_crl, + End_Certificate_PP_01_07_crt + }; + + /* + * test41 + * + */ + + public static final String Intermediate_Certificate_1_PP_01_08_crt = + "MIICojCCAgugAwIBAgIBWDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA4MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDDe20HLq7R8b0fWTsEiNV3Z5IbQseZ8QCW+1cb6yM+" + + "ArKLJDnXx8zmTHSHQCpw3G7xhGsxA1btm0cSC5P/1bw/kFWsSLRe2NFF6oKU+7c+cgIUMB" + + "kzyXk+kpWAQRb7hcb50iKdKFtO8gMNGMAxlHRI05/1tThyAs9suI4TrxTS9QIDAQABo3Aw" + + "bjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAjBgNVHSAEHDAaMAsGCWCGSA" + + "FlAwEwATALBglghkgBZQMBMAIwEQYDVR0OBAoECFxr9vgF31fKMBMGA1UdIwQMMAqACKua" + + "6/nC51SPMA0GCSqGSIb3DQEBBQUAA4GBABaX7TYfmSyVmzGCVbTFweUuPilo4wzy7z/w0x" + + "y4uSaM/YMtixUdDPpTHOJNYDdeV85v+w9oezdL2ZYAaGn7tldC6k8ouq/6hOGGST+ziHJS" + + "gTOD8UVBQPRPvWEwgmDIprnzrVRz8rG6uqslXNiBDnO9BMGpRo4dy8YpOmV6BPCD"; + public static final String Intermediate_Certificate_2_PP_01_08_crt = + "MIIClTCCAf6gAwIBAgIBWTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wMS4wODAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA4MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC8nLZcMLHYKxVqbhwJiqQbAYhf7S6ck2O9AhNor935" + + "Bfm7/8qVZbBAotQy1PoCjSW0UYdknDolWvi8aAtO0f9XVrAv6BZVVW9j3osIGN/XUThaN+" + + "9dZ83kGpyjeoitpGK4wbFNDteuBFYp+8gFNupnX7JQwUK3aGwBUucbe7puRQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIL0xyFYBk4OcwEwYDVR0jBAwwCoAIXGv2+AXfV8owDQYJKoZI" + + "hvcNAQEFBQADgYEAPk+Lys0Ueoyhp544EH9Hqy9+gY+l/+N99v7KvBlZWKuhkwZDE+qAYT" + + "P/SOPsWe8ADZE2iQ4pOlpK8jSqtJSdK69RgGL9omLnR04L9c/zKLArBE+VmoV7mohcQp8x" + + "aB4q/g3QnAqwfFYDjIWW3H6gRAeQ5MOtKdz/4042fJxc5L8="; + public static final String Intermediate_Certificate_3_PP_01_08_crt = + "MIIClTCCAf6gAwIBAgIBWjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wMS4wODAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjAxLjA4MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCvy6bNOyVaP8JTwiySFa3Sj+rdSqzkalK5gA7DLk4q" + + "AyvnAK64HgbCsb8dpnSi94WBDsocrQ4C1Ltoahc/AZyRVLA/REsAh1r3/0FALZgYiIxvSF" + + "m3ihKb3P9URBbotzhl1ahRZPSrcxKwNXEmxB0gjixGW7GZTARq3Il5ressRwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwAjARBgNVHQ4ECgQIwFtfZBe/KqUwEwYDVR0jBAwwCoAIL0xyFYBk4OcwDQYJKoZI" + + "hvcNAQEFBQADgYEAeZhpIDEYyV/LkOtUf1TryemJExQ1jdfirJ3AUtoFIoWz1p9aqnV6Po" + + "GAMozjtdyotfSA2O8c065DwD+CvUXPmdD+2vWpX/2hJPj+x++UvvntAokD2UE9HCeEvBHK" + + "rr59hvKKd6GChyhAjLris202eTLIiMEoyZy9X/Wt1nXF8/g="; + public static final String Intermediate_CRL_1_PP_01_08_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIXGv2+AXfV8owDQYJKoZIhvcNAQEFBQADgYEAhkwT" + + "E/EGAe32J883qVrh1wG5xQzO/GGfp/zuDYGL2k1zZ2zq7MajKfzBoXXQ3WPh5dTK1sy5o5" + + "boPHG0pge0B4/2JvuDVS539+9HAPansUNsrMXzOblg1acjdKtuk4oS8PIYkM/lbA6yJl6F" + + "QMbdIthWqa2gjaWKll3R8fVUjxI="; + public static final String Intermediate_CRL_2_PP_01_08_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIL0xyFYBk4OcwDQYJKoZIhvcNAQEFBQADgYEAN6BQ" + + "sEQT5YCvs9vlUSdG4gjTgNkyQTCdmSIcufpK4MG/AoW/Fn5zJXxiMyHmvT/dkk/UOf82/s" + + "41YI/Inz4qRmGF4IL7jo+l7V+OI1n+Vf4ClgZU6ocb9d1dFoBkJu3xI9dcWK6ExpzaBUXw" + + "rPJilV4M5luGbszdDCs9cLjmiRA="; + public static final String Intermediate_CRL_3_PP_01_08_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QUC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIwFtfZBe/KqUwDQYJKoZIhvcNAQEFBQADgYEAkmDx" + + "t+r59llppKmm9mSTof9/BX2rNyG9LfIH7wweoDi9be2vYOLy0NU1kJ8f3/muEw2v7hWDri" + + "k9ROLDFnb/S8MYVT0l4rymRhpshPF1uMTOZmfJUCfTX9jIaShztSScqcGSP0a3EUfDD14R" + + "1yMu2pdlMM35llE0lV3uf/eUNr0="; + public static final String End_Certificate_PP_01_08_crt = + "MIIClTCCAf6gAwIBAgIBWzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMy1QUC4wMS4wODAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjAxLjA4MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDTWNp6Oz39wwU8AFDzYVs3UfVvXg+t6j/qFavnvllI" + + "NO6aU1o4Hnk1wfmTPZPErc00/MfizMSumTYYRl21hEZWhjNO5uQIHrF9V/4OToo2iOfsPd" + + "gxwpSokwxcl7CJyadwUxhRDYCLhSORXoCK1CPQZjwb+uQz799O5ozb0WVNYQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwAjARBgNVHQ4ECgQIO1TNJtWwaiIwEwYDVR0jBAwwCoAIwFtfZBe/KqUwDQYJKoZI" + + "hvcNAQEFBQADgYEANmP9hyFnYvi8gdtRe8ERoEG90NwoyPTsB8sXd40f+Sm1QxKqMPzKPL" + + "7bOtY12JGwZ55a6HFVgpw4PnU+0iOcCMHS5OQQLtyirxX2HfioiXEmcmRJT6FvLHrGIHGv" + + "KNcfc3rUiksdOb6+j2k8x4IwQ6pBEHQwY8U4Y4DgqALlqM0="; + public static final String[] TEST_41_DATA = new String[] { + Intermediate_Certificate_1_PP_01_08_crt, + Intermediate_Certificate_2_PP_01_08_crt, + Intermediate_Certificate_3_PP_01_08_crt, + Intermediate_CRL_1_PP_01_08_crl, + Intermediate_CRL_2_PP_01_08_crl, + Intermediate_CRL_3_PP_01_08_crl, + End_Certificate_PP_01_08_crt + }; + + /* + * test42 + * + */ + + public static final String Intermediate_Certificate_1_PP_01_09_crt = + "MIICrzCCAhigAwIBAgIBXDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjAxLjA5MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDJqSSqGjgI3JUJfA/XkloAOg2QtZeAGp2nCq1Oiply" + + "MTjJpMpEOSRYrEIgKMGnBPq33seP7X/obCT2jgexmbFT2TmPirM+h1aqbGQ7QAqsx80BdE" + + "ofdcfiNosLbbzli9qFrbarO7fJfBhzraBFGDJj3N8nLi2YtP9IieFYJ/MhKwIDAQABo30w" + + "ezAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAwBgNVHSAEKTAnMAsGCWCGSA" + + "FlAwEwATALBglghkgBZQMBMAIwCwYJYIZIAWUDATADMBEGA1UdDgQKBAiVRMrZuHQ7VjAT" + + "BgNVHSMEDDAKgAirmuv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQCetZy9JMzUVveSPE2fQY" + + "4fRVChyvIc9nCE4wbzhnRl3zduBGmAwTFr7dRWSFTnEq1c2b6B5nJtCzmt4Ovapf69sIlM" + + "s3iV16eBB1WTNCY8YlAsnmZ7q/AR0t0vX+hh6QV6zN5xqulOM4Y8csZEx3RWJzV/LjE5w7" + + "mKvofBEUoqQA=="; + public static final String Intermediate_Certificate_2_PP_01_09_crt = + "MIICojCCAgugAwIBAgIBXTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wMS4wOTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjAxLjA5MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDWUTlTieoi7aLGUYOAgqUC2J/6JarOWfv4vobpwjAA" + + "DjvQGqg/GCZP7FgD/72Z4YefZKJEFZTDnYfmy2qh6iBYxcvLsJ+PJGzPCObNSmyq8gpeXy" + + "KKEeCZtEev1tSywTT6E5Dhee4dX0QHE4ydZEliMMXGRW/8ffT6x54CPwVylQIDAQABo3Aw" + + "bjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAjBgNVHSAEHDAaMAsGCWCGSA" + + "FlAwEwATALBglghkgBZQMBMAIwEQYDVR0OBAoECAMhmGN8+qXoMBMGA1UdIwQMMAqACJVE" + + "ytm4dDtWMA0GCSqGSIb3DQEBBQUAA4GBALNjokGrTnWsPn5KrlO+g3R8tAGM90JQDjfrap" + + "xWM+nN+dUVVdGU6w2pAOAq2UhfySiP42qiFChnPK9oOqPF2Or7/kcmXZzBfZkE/FnJGNUA" + + "gs9je1nZvTPQYsF094OqE7QdJi2k3seA1tqejA1kihMHpwQNmIp8bFpqn4dPO6ys"; + public static final String Intermediate_Certificate_3_PP_01_09_crt = + "MIIClTCCAf6gAwIBAgIBXjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wMS4wOTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjAxLjA5MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDHUpHhF4ANNLOywnvpqyDgzLMtatW3ZxgLBBRYk6TE" + + "jMgTVKmRasVRTA9uatGG4b2f70YWs9cOd4ylQDqPEDdKNZ47bqZdX6RAU3j1dO9LBwWDbp" + + "NvZ3zuDBRDoCZClIcBESDYweaZ9nUgKl/WxTeCnMwqkfSJGYBBcHIonRPnGwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwAjARBgNVHQ4ECgQIyppef22OmjEwEwYDVR0jBAwwCoAIAyGYY3z6pegwDQYJKoZI" + + "hvcNAQEFBQADgYEAOySUCY+PZxomhWgTRSKRodOIe/QSfCMSC+0iw24a2TuJzFLjN9pSm9" + + "0C2PqWbfwD1uDjrteO1NK+1yhtIDySiptR9GmR/fhL7NJ+z7M4fEJBjjeeI9/aEIuHuBFT" + + "TVHfwsJxnZtjujtOdl56B825LsKW8Otumd2A43N9wIgSyBg="; + public static final String Intermediate_Certificate_4_PP_01_09_crt = + "MIIClTCCAf6gAwIBAgIBXzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMy1QUC4wMS4wOTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjAxLjA5MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDR8/c35YqAswoRMgQswlTbKB9oYEzrFSC0G4dt8ydP" + + "O4PyQs+J8wUVrRVMiVDTLO9rUnzR1T3iA0dqM+SvWMIA8pMWKyNV58f73ZPJIejhxMmOZa" + + "sSLHceMmmMRy1zyk38i3ZJP3YhvxffTjWyTZ9k2xSDX+6KNnkiKkJSKpl6nwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIpcWcVIIu63kwEwYDVR0jBAwwCoAIyppef22OmjEwDQYJKoZI" + + "hvcNAQEFBQADgYEAckgV11ND/D1vfPEMUbDGUvtmsziHiSuEoDLJqSAhOmcX+evKWOfoVo" + + "f7og+0ajuul7yuB+7YX1AakOw+33k++Rsgg4o+ImZq3+VScpgnIQ037OOhgH3umwFRC0r3" + + "NpWqhmQuz+mHnKiK3X+IDsQOFkhnpNs06CQSZzmrzbYlQU0="; + public static final String Intermediate_CRL_1_PP_01_09_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIlUTK2bh0O1YwDQYJKoZIhvcNAQEFBQADgYEAkEc6" + + "qHGOWZXYTQ5fsWyJgEtuJyl8uJ+gMcikcMut5SIJTTtOz+q3wclYDevT8z1MM25kNdgwyg" + + "b1bwHNAG8I72eIDtGfLrChFwU3qpvVMTG9gPYJb05Q8On56nsBu/PnnzJervzxjViaeOuv" + + "kjwwfmWqGkyiK433WxzgPqE48eA="; + public static final String Intermediate_CRL_2_PP_01_09_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIAyGYY3z6pegwDQYJKoZIhvcNAQEFBQADgYEAV9Md" + + "8PaNoIlT7WIwnelqrbwsR66vAaT8w3gu8XDYXu+MOYThfyERUvtH6AUrHWfiRvWEzKljHH" + + "3BQB0Zsa9Zz3U5cLzJcqtqDc1lH53aIA8MflrfMVrYSF684s28FikcukmA5Fw3+7S3TJ18" + + "Hq7plHwTCidVD6yG35hsPwcjTrE="; + public static final String Intermediate_CRL_3_PP_01_09_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QUC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIyppef22OmjEwDQYJKoZIhvcNAQEFBQADgYEAjBaP" + + "V/TFQtDLxQFIBCbfqhlgpOfvJBatjNuvB0TuD2rsGS1eaLNfTfyVKlOLpxoKwKYMu36kIO" + + "l/+KEPDq+ofy7uDZ6GLK3KZ/WiJyriqBQjFCvlhNTW1cjA7Ejk2lOM/A46mrUS9xC+aITh" + + "d+/UYGt6O/e256cOwQCUaF2z328="; + public static final String Intermediate_CRL_4_PP_01_09_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBNC1QUC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIpcWcVIIu63kwDQYJKoZIhvcNAQEFBQADgYEApZ1l" + + "w5SJoU8zeKwX5jpVWiFFFomDgKsNlkkX5mF88l0B6MiYbGqJIowJRfeIlxvPOf20imN7Z8" + + "l38DRXFacDQP4y5kxM420dp+ljQL5q9RsrC1+OS7I7TGgGwPoZTO4mHVk8nx9MyT+kW1OU" + + "x9qRYWN0CLmP22kutYBndny222Y="; + public static final String End_Certificate_PP_01_09_crt = + "MIIChjCCAe+gAwIBAgIBYDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBNC1QUC4wMS4wOTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDEuMDkwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALiOjwwwUk1HNwf2rdzPL2okKTgL+lMdzhC7cbq3" + + "6A409EY7iipPCcsDsheo9EaTNOHV9xjWDqOhqjA38h4hGNkRUVOlTW2r8SoHISn3gDXfrh" + + "aHbU3owscAmt1nuA7rzo7L1eBPsisIIxAY16uAmVN5RdiAAaP8VUdshcNI4/1jAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIGZIY3nffEXowEwYDVR0jBAwwCoAIpcWcVIIu63kwDQYJKoZIhvcNAQEFBQADgYEA0Svm" + + "aqjaeQx/lnF223xlCTsU7XzOxbHetRWfeCTw0QrWQaTrKjWTS/TNyzLhGuPBFg+NTTvWML" + + "gzteo/WWdF8+d2rOis9FVRCe/Euok6ZCL/xgzaE86ZSQg0jj6458TpuC2cszSaifRSlhL5" + + "ogy4ADWgJxdVcBrgADo6QZXkXXw="; + public static final String[] TEST_42_DATA = new String[] { + Intermediate_Certificate_1_PP_01_09_crt, + Intermediate_Certificate_2_PP_01_09_crt, + Intermediate_Certificate_3_PP_01_09_crt, + Intermediate_Certificate_4_PP_01_09_crt, + Intermediate_CRL_1_PP_01_09_crl, + Intermediate_CRL_2_PP_01_09_crl, + Intermediate_CRL_3_PP_01_09_crl, + Intermediate_CRL_4_PP_01_09_crl, + End_Certificate_PP_01_09_crt + }; + + /* + * test43 + * + */ + + public static final String Intermediate_Certificate_1_PP_06_01_crt = + "MIICozCCAgygAwIBAgIBYTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA2LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC4mu1oBHB9BeorCFJIuSw5tszmmYBD4bjTklsAfjrz" + + "OknQsYxEoHfifpdgivh1fMUk+mK5YWUz0G8/edquKbJhPBTTWp8opsGzTATsTLSEzkKbVM" + + "DQ84ttxrhJWlrVRlouZTnD5HoLUvujY4EdydmKsjj6UBt/tGL5EKodymcEtwIDAQABo3Ew" + + "bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATAMBgNVHSQEBTADgAEKMBEGA1UdDgQKBAiGRi8YRte8PzATBgNVHSMEDDAKgAir" + + "muv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQDHOaIki9TogVJn54FRPl+7FyzBJ2DnR4RTM/" + + "q1K3COWRdtvmGqtBBtAccxWziQJ5TnAQn1XA0cFPoCgymGPRcUz+0+C+3VhJ/m9LggVP3/" + + "pjJEG0fsmJtUYPyphUlXeUzf4qSj34SlJws3DIHTR8ozAR75HZmlMRnxyZBLl+jAng=="; + public static final String Intermediate_Certificate_2_PP_06_01_crt = + "MIIClTCCAf6gAwIBAgIBYjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjA2LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC2rptuREzhGfEJ3U8ILPBq+z0s+aafMvBRHpqkipDq" + + "bC7v9zpwg1K18F4MYiATpPAEfdEeprKs0mWfdusF93BoMBVm1y0zRgDRUNdyB5GFO8g8+2" + + "yNEO6L37c1PwrMLnvJakaqwbbnwlcMcKtLHoX19fyveQQg5DNj8WcKZj397wIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIJPt6qKdFeYEwEwYDVR0jBAwwCoAIhkYvGEbXvD8wDQYJKoZI" + + "hvcNAQEFBQADgYEAkFJGNze9/6YX7Rv8FR9obFGACIJ7Om4YQQRW9WM9pEDgKls7g9b9El" + + "dJxLKOlWoRoYZIrbEam19traE2O3dxqRevPoYvfAqkR089BkxH/cFYyfqw64IpjDG84dsY" + + "XieajI/Ov/HjgF0VQKF3+Y1ZiDjb2OHNgMkqs9VmUHaE+94="; + public static final String Intermediate_Certificate_3_PP_06_01_crt = + "MIIClTCCAf6gAwIBAgIBYzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjA2LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCzxfyi52gw/5tt6/9aNAXdY3wZYH1GifzGoN4cg8Mt" + + "++5xmTdrc2A9/5biaTUVC0x/Ml6mm940NA9mM/EoEu4SdnP2crNCIFHWNlYz3cJtYJ68rE" + + "rEU+S0gnYaYRiwNGhVpAjV+FPDr0Ghgp5rYQ61evAhmRuNAFwYocUw80G6JQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIZ9yMlboxCIEwEwYDVR0jBAwwCoAIJPt6qKdFeYEwDQYJKoZI" + + "hvcNAQEFBQADgYEATNnRMQmvTxRcSMUL4pa5bejuX2Ixy/OfZIAlJWt9AfLW2tHmdAaGpD" + + "GhTHKfyQQ+HrIMQ+lXau8Yu6nzWXAY8pKpKD1Hbd355VE4dYZ7aPvcAulZHeV0F2EFn09x" + + "qQ1frHDRoCOc11B5qV5hnwgDE/ByZh1+OWUcR4tBQKyEF4g="; + public static final String Intermediate_Certificate_4_PP_06_01_crt = + "MIIClTCCAf6gAwIBAgIBZDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMy1QUC4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjA2LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDB66hLZx1WGcCqmOxHK/rotXOpccJQOB2L3kpWP1M2" + + "ZiWufUguLw45XShdqu31OgmGw0/w9ugwy96aRL+Tiluj4xjIAxJCav5cXF8Dt2Ex7hjIHm" + + "XV0rHbJUiduHEh3fQphgtzlR4QxG6i/i4SbcsoJzsws8x3qOqRPaWDtyWs0QIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIyZsLNvyyIZEwEwYDVR0jBAwwCoAIZ9yMlboxCIEwDQYJKoZI" + + "hvcNAQEFBQADgYEAc7G4BAUsQeqNp/Kv8TKJckfxWygz54PrkBICNw/eGuGamVJMRkYCP3" + + "yJ8NW4jY/rfxzKKyjVB09XuNBLDwYdR5Z5UHSg6Ijes3j8tehZ+9DwEQrR+WQf/adHIsxn" + + "/347MHrSQF7CJzE9tAu6AOu53lKxLeH6C/5YI611or2Ql1I="; + public static final String Intermediate_CRL_1_PP_06_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIhkYvGEbXvD8wDQYJKoZIhvcNAQEFBQADgYEAC7ev" + + "Pqe0veUX+zF51d/NiG6VwgEwOP1HlzD/saDn/FYXStTQDwoIyFjmZ9z0yLGIaVI1O9BWVD" + + "CTU3bCU1dBg61Blo3rI3TlNqmGrYRUSJ857QM9c/G+/+V0XJ/HgId39Pufd9Tob150XNMs" + + "9h0PvqjhYjG1bARMRa8JB4KTBU4="; + public static final String Intermediate_CRL_2_PP_06_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIJPt6qKdFeYEwDQYJKoZIhvcNAQEFBQADgYEAiUbi" + + "qQ3X/hTgjhpQGDZi/7EnZcqSgiAFMreV30/mav2NtXDITE9DqZzCS9x1vHBp4BBsQwYVvp" + + "XvLVSgns4pFwR+0Whc+tPo2j9ScePq3sICsqleWTN1DvuoP9rBe8w7pDN4guA59Kbeku75" + + "5CMA5YjiTUomK4UaqI3htwkBlWo="; + public static final String Intermediate_CRL_3_PP_06_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QUC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIZ9yMlboxCIEwDQYJKoZIhvcNAQEFBQADgYEANowv" + + "f/scWT6FFT393XEpWcTnA18hBT5Nkddw6mHjKBq7ndtBQkydMO8Wym1IeQ2qYbAqu3ifNZ" + + "SKF3PfgJjYPBKImzJdHTKfcclMC5H8Y9JDN0voeyONr9NiXcoj+p24YNYjb+PFI6avRYo7" + + "Xyrqvwnvng/IY9zLtc7SYYUIODk="; + public static final String Intermediate_CRL_4_PP_06_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBNC1QUC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIyZsLNvyyIZEwDQYJKoZIhvcNAQEFBQADgYEAsnA9" + + "ERwsi2mK540oPL45mLdOjGnet7+HhNk14q0hvALTYGB1vEjijc+Yvf6mHJGRbiG207BpJ1" + + "DWeWBY8TLe4YJXlSrWwx1jD46rCt7gdqXAdLpMo+i35yfQ19ZqeWcRLkspmczoUJLJaJza" + + "eLRrnjv62GLJ09KVKpZBGhV3SUM="; + public static final String End_Certificate_PP_06_01_crt = + "MIICbjCCAdegAwIBAgIBZTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBNC1QUC4wNi4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDYuMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKrLB7XA0PKY0qtSC5lMBvvIvbyjBM8XmANrN9Wx" + + "66QxEuloRAz0D5uAu7TnJBv6qNuIPGFl74yusKCSkjEkBMdVpBCfDvpG1/Tz3sALSlxmnz" + + "xbK2ytOncbYuYrzvXttx6wkhLrBLlnfuwpZwGZOr/Pt6WwQJWjXxgTNJ6dcgXbAgMBAAGj" + + "OjA4MA4GA1UdDwEB/wQEAwIF4DARBgNVHQ4ECgQIv0gg7LxDM+swEwYDVR0jBAwwCoAIyZ" + + "sLNvyyIZEwDQYJKoZIhvcNAQEFBQADgYEAgzlxBGGOBvHw20eOzSswMqrHopNMcvwuEO+Z" + + "Mr0h8U2/HIiRqKWQaxMyM8A0oULGJny3B/0WtkfVQ2EIibZGiKIjC1RPAB3QmL0vgSyUmF" + + "s/LZbzugpJW6jvfov7N4O+u0J5rYniRxa4bgrXa89TY9kwDMbr6/z4oiI8bq3gEsw="; + public static final String[] TEST_43_DATA = new String[] { + Intermediate_Certificate_1_PP_06_01_crt, + Intermediate_Certificate_2_PP_06_01_crt, + Intermediate_Certificate_3_PP_06_01_crt, + Intermediate_Certificate_4_PP_06_01_crt, + Intermediate_CRL_1_PP_06_01_crl, + Intermediate_CRL_2_PP_06_01_crl, + Intermediate_CRL_3_PP_06_01_crl, + Intermediate_CRL_4_PP_06_01_crl, + End_Certificate_PP_06_01_crt + }; + + /* + * test44 + * + */ + + public static final String Intermediate_Certificate_1_PP_06_02_crt = + "MIICozCCAgygAwIBAgIBZjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA2LjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDjg5+XWZwW1gLAOldsRshbCXmUCmt1Vs+oZsvyH+6d" + + "2PwKs8ydrz+oD0/D8V7cRXucj7q7cJSLhEY1wJoTTgrWeRg1hQioAXzPW3ZkaZuzhpi+cC" + + "qeZzN5nPvqK18GWvpffNbUUVfOuaHzzHmhmhgQyZaNG7JHwpWM10UMzMawOwIDAQABo3Ew" + + "bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATAMBgNVHSQEBTADgAEFMBEGA1UdDgQKBAh5am+tkndt5zATBgNVHSMEDDAKgAir" + + "muv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQAF0h1iaxxZUp43AjP5gSvbW6JfFRW/ugH9SU" + + "n3e1B29LMH3F/ML0joVhPx5CIVpX4nfaYzdeje9+E2/bHMBGSCFeHz9S/KoBLLiI0GNhzh" + + "I6MytvPMPRx7hkuROouQ69TnslJiGCcoo+MD0fA2YwO1bCtyLdeVHYhJZWQ2Sg8PHQ=="; + public static final String Intermediate_Certificate_2_PP_06_02_crt = + "MIIClTCCAf6gAwIBAgIBZzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjA2LjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDF4KSKxo8HvQ59E77LcuLpZ7ujNDjb30KB+EbIuRmy" + + "khXAkhq2Rp2Iqd3OhC0AXmhSF+enJq3h0dqyxNWP08SIuK5ia3OIeatl1UgEyukuAnrLuI" + + "A7PFUQAGZmDG4OuHv28zza4n/SwfCaKfi8qatIwpwF/29ycB8wYBrHThQD0wIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIKFZV4vjfOOQwEwYDVR0jBAwwCoAIeWpvrZJ3becwDQYJKoZI" + + "hvcNAQEFBQADgYEAuj8P5ga8Xv9eFjk4AdRMx/Fj/doRAOLZfs+OnrduRXPLe7CFKDxhFx" + + "xYOma8In08cgXVVnRR+2nZ54h5qjCYpskGNx+yZRY8+HW3XXE3KpS7QgTnc/1XshUy9VGm" + + "2qX0k661f2d3KnSKiKVKtM/y/j/nNyxPugDz1Yy50NtzQOE="; + public static final String Intermediate_Certificate_3_PP_06_02_crt = + "MIIClTCCAf6gAwIBAgIBaDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjA2LjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCitrzXkbO4hAQpBRQE880MFBPq84umX9pyKbV3iMqK" + + "Z7HBYwZOvEwGQxG+TX1PIj0Jz27oyvoqpLeMkbn9L3K0BuS0AZKlWIOGPPHWpYTDoQCCs9" + + "Mba1evVT/1CMxESsv2kgf49YHMs/6TtxQX0qj5TQzXrkM6CMBc5zyPBDWORQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIxLES0WIVZQYwEwYDVR0jBAwwCoAIKFZV4vjfOOQwDQYJKoZI" + + "hvcNAQEFBQADgYEAdQeDAOFys//2xUFwBilhqr32/jh4gT/ijxRjG0msKTYXmWcCQv9Tms" + + "smtIMtiwwnByhjTdQAtOmEyDm/CFW0/NBnxlRvqZKt+PRtscpExVy7xnnm2MBITTa+9xkC" + + "A361jSDPnRPEOZoKdMRRzNnW4f59m0huibeFNRYJ7y8BnHs="; + public static final String Intermediate_Certificate_4_PP_06_02_crt = + "MIIClTCCAf6gAwIBAgIBaTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMy1QUC4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjA2LjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCg0yQG7oewLD2eFfPuj2DPBgT47iEri2IVeS/r5hUD" + + "nZhxzT2/+UsQfiS+ufdC2Xq+QAcXFcAifPbvRs9xo2q0uLz26mwSq1TH8ilHLKatKwJ/Yf" + + "hcRAfEWDwhLJGRhZ7YrKu8xczZgyxwaeu5m38lEaLIRyaVfVSrw8WhN4z4ewIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQI/dKmuI1u6I0wEwYDVR0jBAwwCoAIxLES0WIVZQYwDQYJKoZI" + + "hvcNAQEFBQADgYEAOEcMpdSAVKUzQ1A7LJnWOh5Tul6yXw6qMsdZNGOZ3vYBXH3vHnSHvp" + + "MqJQ1JIX/4XSiKF8En5dVI/ooNabgyORpPnLGDvrshvO/09iaDlQXxWRsoGAFhcIe7Ibp+" + + "3g6hnBO5U+0pbInioKVYf/1VyZSUK1QQMutshMIye/8gyZw="; + public static final String Intermediate_CRL_1_PP_06_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIeWpvrZJ3becwDQYJKoZIhvcNAQEFBQADgYEAEJ28" + + "g5iyw3ZOqs5ly7O2X0YWtgKK3BnPztxygCUWO1xVy/QbMM5ybAU/UPbJC2pUnkOZMX+h30" + + "RYp/kV9w2o15V1hxj2M0tR8fQ0WXudwi20pZO56uHb+WSaETOmPVoNH5efeXsTvtbHQR5w" + + "95L2vNeEzJEy1l7S/sasUUoQvqY="; + public static final String Intermediate_CRL_2_PP_06_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIKFZV4vjfOOQwDQYJKoZIhvcNAQEFBQADgYEApLIK" + + "X/YJYhSfn7yLTAlKjnhpH1QDlFeaE6/+uj6j7ZgpK6HBjHOvfwbrjurl+L3ZTLrY1FCL4/" + + "SUgXrJxbAyMANlg4Z8u6o73F9cur2gi3sgv5d6FjJ8VwuKYWY2dwZNeXwlWE/W0h01Vd9H" + + "QVuctFxzQaJQdQBadw/XqzvLlyw="; + public static final String Intermediate_CRL_3_PP_06_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QUC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIxLES0WIVZQYwDQYJKoZIhvcNAQEFBQADgYEAE5J9" + + "wJKAb3veF4GhHeoIgy6JvMsrjv7d7dhT+ZIKq+wPNk1909X/Zo1GXxJSjMaMgkLlXa0QN6" + + "LtSJxbyMRCKSJfqTKOezFXirZ7MEQ04FT0z6Hp0m+E2Q7dGs52ZOV3YZBhQUlH+aQ8WNu2" + + "6clf4VqBiUYgGhkE95PhN5AAnOU="; + public static final String Intermediate_CRL_4_PP_06_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBNC1QUC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI/dKmuI1u6I0wDQYJKoZIhvcNAQEFBQADgYEAKgk1" + + "HJ7OW203z9H7jNGxoLCN9bGDKOFcWlWuruzXWOAn+AomjSZpqZkZU1qyKrFaKM320sfn8C" + + "ZJPnVWaVMLBLNddDRWUjJrUHtNdnnZEuYPYlRVb0MmwaxHHR0ZBUIaniqoLuvtQIB9N++T" + + "bu4cjx33mN6MX0oWr4Bbq7ovPnE="; + public static final String End_Certificate_PP_06_02_crt = + "MIICbjCCAdegAwIBAgIBajANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBNC1QUC4wNi4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDYuMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANAr4hFku3Y6jI+vD6JTRFc7ZLL9tIxT7Mq+QcDd" + + "rRHgSEXhPL3MM//3ZFXca3w4rXOUVQyANQncywNM3uwl7T9jC0MD2kJ9PsNGQL2bQcSajX" + + "jrxT403PVFsa6ZrLMU0hwomSO4nJBLCJj3i1rlX9esYbRNCqzep2OMWgAWRUsrAgMBAAGj" + + "OjA4MA4GA1UdDwEB/wQEAwIF4DARBgNVHQ4ECgQIMBvQP4Q8w2UwEwYDVR0jBAwwCoAI/d" + + "KmuI1u6I0wDQYJKoZIhvcNAQEFBQADgYEAnmNf+3jJp4mo4YDznASTMnrBBdXuskhnRXSQ" + + "Gj5dNq6PxEXM+CmBhaNlnFYcr7UCtcD8XwampfyO52tvAZW5kWQKsxyowVtsxtwkAtj6/f" + + "trIeulIM0B1xjyXJshmVST5u6gZ3OegsAyuqyAbo9B1IvkNFOldt624aEG43jq7ho="; + public static final String[] TEST_44_DATA = new String[] { + Intermediate_Certificate_1_PP_06_02_crt, + Intermediate_Certificate_2_PP_06_02_crt, + Intermediate_Certificate_3_PP_06_02_crt, + Intermediate_Certificate_4_PP_06_02_crt, + Intermediate_CRL_1_PP_06_02_crl, + Intermediate_CRL_2_PP_06_02_crl, + Intermediate_CRL_3_PP_06_02_crl, + Intermediate_CRL_4_PP_06_02_crl, + End_Certificate_PP_06_02_crt + }; + + /* + * test45 + * + */ + + public static final String Intermediate_Certificate_1_PP_06_03_crt = + "MIICozCCAgygAwIBAgIBazANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA2LjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCrUMqMxZ4sSrH6sKv2y6nYKagLvUHaforCnf4z/5O1" + + "PeldaW4ANtNPA8SkVBES/zoKgvrLJUmqRi4b+BGhCVqLU77PvWyiPOS40tpJfw7m9pPK53" + + "aeaLC9M6rarjdOvF8MkdtytCMU/Ef1NsuJULwEP+XB90k4lHr9EzbgKhXvoQIDAQABo3Ew" + + "bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATAMBgNVHSQEBTADgAEEMBEGA1UdDgQKBAhF0iXZmlIKsTATBgNVHSMEDDAKgAir" + + "muv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQCmab7noekyx5TzxAqWoQiC9S/aZJtvLkuH1p" + + "KiZnclMpRvIL1CVOukkzLTZXY0EcCHnXuVGjw+9vmiQWGGw8t6TGCXo/CtCo934HGBxOfQ" + + "MVysEjst7L7TDQsqxk4j9O8cU/TFWsghW9Ihu7SVIn8RJmknKMB2xkIhcDe8S8dmxw=="; + public static final String Intermediate_Certificate_2_PP_06_03_crt = + "MIIClTCCAf6gAwIBAgIBbDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wNi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjA2LjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCmT7wL9WwWBr1oY9bHIq4IrJOkbOARK3zOeyZSbBBB" + + "zxcky5kjC9pamMpyZjga+q0CGd2rq9eUjQ2FXZsBSgf/X9B0/g9trNMebYgGnYmHHX2JK+" + + "doyAX+h3afDbZzZ696S0Hw7yRx00+teQe/Gx4h4qKPwbJIW5Bep9SBysikJQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQInXHgY/+onu4wEwYDVR0jBAwwCoAIRdIl2ZpSCrEwDQYJKoZI" + + "hvcNAQEFBQADgYEAhlboR5gzYWluWIaFM5R1Ko0/rprrv5BHONRiXjLfAPkzZmd7FLDE2j" + + "BlU7s7IenICeST4c7HG5zqBigK1814GG75nq5htCGUnM6pn8/gvc58+ckKeWgbJxC5I/0u" + + "olCCs8ORbWIEGWmghGg1USxeI1RQwXGgE8XwtabVibJOVBk="; + public static final String Intermediate_Certificate_3_PP_06_03_crt = + "MIIClTCCAf6gAwIBAgIBbTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wNi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjA2LjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDEouRlqTFQiJQSwc+yhjpvA0dUIbRrNwLF+EPfUWq0" + + "FV1UV0a5lb5BGPW4RGUEbFwsgGCHsfLiY7WmUpC1e6332PZPnrnoJbf28paeiZ8KqcAKZE" + + "pGPWKCmFBwBW23q1w/v/CxcXJoBx5OC1yxG3fGH7CZSzc+4Z/+PxLk9yoASwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIc24GzUM6/LswEwYDVR0jBAwwCoAInXHgY/+onu4wDQYJKoZI" + + "hvcNAQEFBQADgYEANLxcLvJqjyu94HN+X6tTxGcN1s43kQh8yRGotW2ptuA2jmGlAhI8QQ" + + "sXHO0o0bFLBC/Uv0L0YlEJhK1w0ct7Awwn4UYgqupxug2f84yamcvFa1es3osIMJoi0GPz" + + "1WDBM711efRtbzvK6t/4fJ01nG2BlMeEbctVqrehuAip4p4="; + public static final String Intermediate_Certificate_4_PP_06_03_crt = + "MIIClTCCAf6gAwIBAgIBbjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMy1QUC4wNi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjA2LjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDNuzSN3BiT84M3Dy6KeTQkMqWNuYGTENWPP8WvQ0Ot" + + "ggue/lemC+IqYBtIEYtk3A30eKKnF28WIbPlB3oSykrPVV5dMhYGF9ysOtp4wyETHtzdv0" + + "7HyqlMHOCPiFplbwjUSo0uEIRVgS3luBJi9onTpcn97/i0S7VsM2nooooaowIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIDjpr8w0dRq0wEwYDVR0jBAwwCoAIc24GzUM6/LswDQYJKoZI" + + "hvcNAQEFBQADgYEArE6qUMnjXiB5eKiAFc9Elw1dYsQArtnDQAfFGtShDulxYKq9+pxory" + + "4kTMUZZCJc7awEC11tdJp7xJGcpjCJl4I2wBcHiCcVcnwQijqM719PqoQKydXB9MSrXqmU" + + "2CyakSzBpb82VooVNx0IZ3h0nXQSE3V0qSXXCaImJcOIGMo="; + public static final String Intermediate_CRL_1_PP_06_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wNi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIRdIl2ZpSCrEwDQYJKoZIhvcNAQEFBQADgYEAQrHK" + + "VV2MJPJLNdPoEuqFXRTEclSmYhUWC5lthK0JnKUbCUj2cMAku2UdN5sRgVG0475dXV2nvn" + + "huxy+IQVt5OJ+PNZ9MYZlC2CfYsBiW9DEYMA603XhVvX/bxx80MwxNby18oyo/V9ycSyJw" + + "XzUmzYRUtohHk39r3eUSAt5H7zM="; + public static final String Intermediate_CRL_2_PP_06_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wNi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAInXHgY/+onu4wDQYJKoZIhvcNAQEFBQADgYEADOEh" + + "jV8V8y17mFstkVwigOAKURbi7sD24RkLd1QG0Bn21JiwpkGY8Z4vetQps+VX586xKzz6v6" + + "Sj+TJk3jfHCiEAk6a7PLxRcVCCi6y70mzEBCwn6fS5NDfxzxYYLgq+dlUiVwqXsHksEvUz" + + "2Z5dpuLhbUGxHiqazNE9iq9pEEE="; + public static final String Intermediate_CRL_3_PP_06_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QUC4wNi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIc24GzUM6/LswDQYJKoZIhvcNAQEFBQADgYEAK/zi" + + "r7ASgtWA0xGQVrqhHsXH9bdaj+FceW6ivoXo3z6xCFLvzu2uenEu5g849+YI0KMomHsDAY" + + "tX8qO3XEaLGchbhIfywgRVDlSF8ytMKhJTS05R/vZSZAl+eoT3mC92Grihsd3wublyNZ7a" + + "d925Py/oFp3J+geUkKJQK+RVu4M="; + public static final String Intermediate_CRL_4_PP_06_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBNC1QUC4wNi4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIDjpr8w0dRq0wDQYJKoZIhvcNAQEFBQADgYEAcBag" + + "81RFYMBAf8aRP5VXPcfu0OxgJvVE25ZHGLCkLD4TPKAXMjZMHWrf34+5FW7aigDO1YhGA+" + + "2zVtVj8k71DichiCCGXQvH50AqFgeNXNQwn9WcpQ8rRkfmyhlccfeM+MzHI1giRw/RjvCN" + + "0dfJL9g3c7peW+VCKn85REZ1ne4="; + public static final String End_Certificate_PP_06_03_crt = + "MIICbjCCAdegAwIBAgIBbzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBNC1QUC4wNi4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDYuMDMwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKBSOacrUg5H5yuISkqmJuQcK2ao+Ib0FmIKCuek" + + "8mm2HEiux+K5/yIAYsQnz9eDKzKWaS73exPniKOXABHaL6dxsptbdBqWB6II2kIl0BFz9P" + + "82qjz6DMwpUhj5Pwfy5q0Bz8grTe31ZYP19y8AHgcWna+eiY4fNVXVkIEJOJ6tAgMBAAGj" + + "OjA4MA4GA1UdDwEB/wQEAwIF4DARBgNVHQ4ECgQIaZQ3Q55so58wEwYDVR0jBAwwCoAIDj" + + "pr8w0dRq0wDQYJKoZIhvcNAQEFBQADgYEAnNYKc2pSFZ9PtR4gQyVI3j+gQ97tcWu6Alxm" + + "4T48fSb2KtFGuozJyCv0aYjtuZ9ava9r4v04lyFPoAjWYbALHC9F+vz7JLNr4VstuMdy5O" + + "ax+PvJjKGACSXD7QjXJ48qvm+v8OnMbkzf8+rY3LoTJ2KhXo9Ey4+UmU/YuZ0PXuY="; + public static final String[] TEST_45_DATA = new String[] { + Intermediate_Certificate_1_PP_06_03_crt, + Intermediate_Certificate_2_PP_06_03_crt, + Intermediate_Certificate_3_PP_06_03_crt, + Intermediate_Certificate_4_PP_06_03_crt, + Intermediate_CRL_1_PP_06_03_crl, + Intermediate_CRL_2_PP_06_03_crl, + Intermediate_CRL_3_PP_06_03_crl, + Intermediate_CRL_4_PP_06_03_crl, + End_Certificate_PP_06_03_crt + }; + + /* + * test46 + * + */ + + public static final String Intermediate_Certificate_1_PP_06_04_crt = + "MIICozCCAgygAwIBAgIBcDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA2LjA0MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDFoR/YTJlGYenu2IRsTiT6jwIA7yOnFbM9JXcqYIP5" + + "jSgtn/wVztPHgVWP+582foXJ+oEcThQVZ+RBXYt6VU5o7eVCsGJjqMd0DbRzTO+poelVoY" + + "1UEJMrKG0xSEex0T6XLQ+jPU9o5tlXoLYsXvpvbIrCJ0o8kuk4MWTzenDKJwIDAQABo3Ew" + + "bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATAMBgNVHSQEBTADgAEAMBEGA1UdDgQKBAgVwXynYDSYEDATBgNVHSMEDDAKgAir" + + "muv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQC6MnYM9cY3CNb7/KKZvoaSwF/Se5iZYnbdPn" + + "WCnKydnN1AhlDN3kEw0gjTmZo/MkvPqku2aPzg5EiZ0eyeJaR6a4aiICU9z/Hiet19mBF6" + + "BtAUdt0fJ7aL5WPAc4BKXUbONd6vkQNv8uLcBmsqZ4wXDj7ZVBMGKcuDq7uClb0xYw=="; + public static final String Intermediate_Certificate_2_PP_06_04_crt = + "MIIClTCCAf6gAwIBAgIBcTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wNi4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjA2LjA0MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDHqX/4IZpOCsHWgdJ6mICN94nXz/KqsXPNymadVdZA" + + "nVU0fHdMcxehAvsBKju5d791Psly1Xyyda8KQ0BKPgGed6jNKb89JzuEtPBov0VMzskqwR" + + "irjaDCwYKtibiDe+T/kEN9Sq5pbexHcaTbAIeQrAIoSUmGdQ/Up6PYplb0jwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQISKcQDqdBecUwEwYDVR0jBAwwCoAIFcF8p2A0mBAwDQYJKoZI" + + "hvcNAQEFBQADgYEAkAQaOoZYAZOCk881Ro+SIclAj2lp+arAkWPP/gwN4/0lpH62eWqlmY" + + "okWRBjk6+iwCgRxQ56uUjJhE08p5juZ5V32ie3RW+S1ZBPtL/T/+Tqp9HNQQ3GjW1yc/yI" + + "sWQxrd7QKzTER37HBiOr5WjEjn+dzuWlJtClcQetqMLtMgM="; + public static final String Intermediate_Certificate_3_PP_06_04_crt = + "MIIClTCCAf6gAwIBAgIBcjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wNi4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjA2LjA0MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC2tnVj8KHGCm8XBPvDYWZMp3yOKQxuORze6a764qIC" + + "hkdO7hQbgJ9YiuAF/y62W17FnbhKPX6ninaZG0N77bznKvivSC3+T1jIVhw+kpxRh9MRya" + + "L2p+zHJEyO/9JaKWzJZiVi4kebW+hwNgSZc7FSYsAbW7lr4ujDei/yn/AJEwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIaAEiWf4JpfQwEwYDVR0jBAwwCoAISKcQDqdBecUwDQYJKoZI" + + "hvcNAQEFBQADgYEAHNsZDCWtOqt741IJNA9OwpymTA4ES1BRJquEvGj5+4RH2pxi67bYd1" + + "kWTPF1qFC2R1sugSNhbU0wOBMdKUJtKWNacPsK0HbD7CPqt4THOcMXFO36b/2gqHqy9rc/" + + "slWuIwbtT/tEC+Mk67GEATWNPifoPT7TjWHM3RhsDnagZXw="; + public static final String Intermediate_Certificate_4_PP_06_04_crt = + "MIIClTCCAf6gAwIBAgIBczANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMy1QUC4wNi4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjA2LjA0MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDgdk/smDJ5yZYJDH4SG7pIDCzGNZeLO9RI3ybOx4/B" + + "M3YQu3DDFSOv8kq6PgL8ThC8Dk6t1jSbT8QVzaGgx0KMV3p6pIMdaVNkOjVjUb+L0nXVfr" + + "XYpFLON6tZLgh8oIbiz4KznKmsxo6VdYwyUeHmkpGcL5y+8qLspCNdRJnDGwIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIgSY376EamQowEwYDVR0jBAwwCoAIaAEiWf4JpfQwDQYJKoZI" + + "hvcNAQEFBQADgYEAEztvmGSVnDGGeNlIoR+wfRM8ndJogvUxLBZm4N96mDZ9Y+Nr99Dqvw" + + "+mMI3BU0miA5kDO9aFrKIgow3cpruoedhnBUsxTfhrNaFEwp+ORUb3tWn7sSxLfnTim4Vq" + + "y6j/EfUK2CS4ZAy7J5BADWSqDezPnrb5UaY1JFKMuLyGRac="; + public static final String Intermediate_CRL_1_PP_06_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wNi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIFcF8p2A0mBAwDQYJKoZIhvcNAQEFBQADgYEAPlIW" + + "SxwW2LE8qxeD+M+HypNwai7j9XxUA2MhBbGVnsrhH+DKX5VeyP/nyZn2hBoGWhs05IpG2P" + + "S0odnyhbgGSXSj+IOfkZkVT0BmuEJmqv75R15LBzeyONks+eSEhoOIGAaIN4WgJ5mzjSrI" + + "ddDu3c4s6QO/OFVrNF1F6e4laSU="; + public static final String Intermediate_CRL_2_PP_06_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wNi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAISKcQDqdBecUwDQYJKoZIhvcNAQEFBQADgYEAE5wt" + + "y3+jVnr8de/Yi0LV70v3JDHimwG2pQcuDRhR1NLPr4oC+2uxMqwxVzdHITDb3yI2ZT9pVh" + + "PV3UvX85avMdA0/JyaMWSKNpbSah1eNfMwMBY2vzh1Q7f5n+7HYYM+I2kz7HARPvwsLP9d" + + "j4mY7Kq7uiOFdnQzJ6LWjm8qEMs="; + public static final String Intermediate_CRL_3_PP_06_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QUC4wNi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIaAEiWf4JpfQwDQYJKoZIhvcNAQEFBQADgYEAOm2f" + + "m3IdcDnIS915tEZzDmIbTFPBkIn0wjUreZKb9uNxE2a8Jixq+UP2uiyYWiWmXnRdVB1Gsb" + + "ofc5f8ctNgSPVTSYB0U5apIauXjV0y7WMUrLNrDFa5m9lxLRhF9kvXVL8zPhVfMpujnXre" + + "A8WS4UjDMuveyQL6yASGoZvB+Ps="; + public static final String Intermediate_CRL_4_PP_06_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBNC1QUC4wNi4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIgSY376EamQowDQYJKoZIhvcNAQEFBQADgYEAznK9" + + "ekskl4uWU+2Xqp3Pj14wvXuzfPAqFlHR0jl5By7T82JRiRa6LGX6T953vcwwJBsYG1hMqH" + + "pgbnUGB8APQ6YNXN+7ZkudaG6fMVX6bCr8zT+nVSj7PHIK2VFsC1Jpm5SoQMHH6DFit/oH" + + "tm4tdV8+nupMBQn1ZtxQHgUUF14="; + public static final String End_Certificate_PP_06_04_crt = + "MIIChjCCAe+gAwIBAgIBdDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBNC1QUC4wNi4wNDAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDYuMDQwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOCVJmtrW8Z2WGGRNjEgyp2NJn1xaIVDwlxL4C0n" + + "UAPpo1WM/rarQTYejT2Yo8H39TdRfiAlggF0Qsce0W//atey8WewGsFlUem6a4OFwg1X2h" + + "CN/COL0eC4a6lwkdOKmqgxSyWNWeKxXRTM8+EYQIem78uY7A8XuzVUmOpzYWoLAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QION6UOZ2Eky4wEwYDVR0jBAwwCoAIgSY376EamQowDQYJKoZIhvcNAQEFBQADgYEAXota" + + "1N1UrMxj2a/vdII92Wi8uEetcHo9vmiJVYxwPFkp+qo1q93Ww8Qnfp7xzaZwLgVoUOAF8U" + + "TRUVnzqoSwmRrfyEMfrgej3eiBjcU+zS9mNlx9mUUSLmlY+xMeejyVDCntRn6YJWWLesVq" + + "eFOjyNux97/XnGT3T1w0J+wShu4="; + public static final String[] TEST_46_DATA = new String[] { + Intermediate_Certificate_1_PP_06_04_crt, + Intermediate_Certificate_2_PP_06_04_crt, + Intermediate_Certificate_3_PP_06_04_crt, + Intermediate_Certificate_4_PP_06_04_crt, + Intermediate_CRL_1_PP_06_04_crl, + Intermediate_CRL_2_PP_06_04_crl, + Intermediate_CRL_3_PP_06_04_crl, + Intermediate_CRL_4_PP_06_04_crl, + End_Certificate_PP_06_04_crt + }; + + /* + * test47 + * + */ + + public static final String Intermediate_Certificate_1_PP_06_05_crt = + "MIICozCCAgygAwIBAgIBdTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA2LjA1MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDMIUtQ/CgudxHAwAAn8jUsdAY8u7WDslOC4nNbWn5C" + + "tILgZ2hGIZhEnhzP+VCV8ke8zLo1DX0hCRYAgzk5XTGAimExHFv/yDdhpJWEnqMRljkCHx" + + "Hg3XE1439qutBdmWvGUlRF0hQrd9Q/Ubr+PjEzP3a0EUmXo7LYuQKMcFsC4wIDAQABo3Ew" + + "bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATAMBgNVHSQEBTADgAEHMBEGA1UdDgQKBAgha8GqGbO1nDATBgNVHSMEDDAKgAir" + + "muv5wudUjzANBgkqhkiG9w0BAQUFAAOBgQAEG5C3P1A/MYpNJ0qvi26v04GGUWDQWRW1q9" + + "1392XpAxDdv7kODf1FUMpfBpcUblagxrX7Npthv6/6W8poBTjvJuq5BfnnOMQrCwnsNfRy" + + "Y7b1mAZIvcOBhWe+bFVqRLUqZ+JseWkw0YgZIGtX41Znwl0VcFQKJ4lNkuaBgXXdGw=="; + public static final String Intermediate_Certificate_2_PP_06_05_crt = + "MIICozCCAgygAwIBAgIBdjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wNi4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EyLVBQLjA2LjA1MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQC36j0YkXZZSw3qQaxD0g2BfrKYperkGjVAfLwOtOxB" + + "0A3Ufx2ECl/MqNOvi/QWlTkKwnrqw0aEnD25iS1DFM4jMZBmdfJg80oa+y6TJoZcIb+3bv" + + "SK5o3ArCFWkhTHHggIIY3H9dQOgAeYQF57Vb0iu59GPfnYJO8y8ZpxGIYcjQIDAQABo3Ew" + + "bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATAMBgNVHSQEBTADgAECMBEGA1UdDgQKBAhUpoGZzfV7EjATBgNVHSMEDDAKgAgh" + + "a8GqGbO1nDANBgkqhkiG9w0BAQUFAAOBgQAjrFHzC1FLvssJTfV5YsGfw7Luj4EqLDQd6b" + + "MgtBSwPnXqMTUAZpDETyeYvcgM+L2tasB26MSy6IttSKsaJpHPCP+BIs0jji5xosuCX6Cs" + + "wI2gE/LjF85rjZnldrlDShw01DlcmWlWwudit/ieO71Xc8i0F4EhSaTUJX12po5Xkg=="; + public static final String Intermediate_Certificate_3_PP_06_05_crt = + "MIICozCCAgygAwIBAgIBdzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMi1QUC4wNi4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0EzLVBQLjA2LjA1MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDFWhChPQNFYQpLBmVmXSGF2py1wcfhZgZurv0E5AgE" + + "BZwBo2bxSeC36lBQyR3OABGI4nQoEegSQWwuS2Pk3+emG2MZ8R5QINAkMlAKTp5Gj7KTlm" + + "3VVJRx7/VduoFx8sZPjkpvF1bSL+KOH4UZny1xqqTj4bJ+oGu58INeSNVa+wIDAQABo3Ew" + + "bzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATAMBgNVHSQEBTADgAEEMBEGA1UdDgQKBAjN4PvsHY9+YzATBgNVHSMEDDAKgAhU" + + "poGZzfV7EjANBgkqhkiG9w0BAQUFAAOBgQA8KmWbAQOnM59zry9TNtLbA2P5y8R/sO771S" + + "yQYcu6undt9t7UEiOepDp/z3CGsITm9RdtXAobZ5ZqhW+3Ll+UnML1itiCytOPbfC7iiUO" + + "S5jviQnpgJncZD2Lp65yNAB7lMmMleFO15Bsk8VNmzMDMsFtzo508Bs6T33ZW69/vg=="; + public static final String Intermediate_Certificate_4_PP_06_05_crt = + "MIIClTCCAf6gAwIBAgIBeDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMy1QUC4wNi4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0E0LVBQLjA2LjA1MIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDxx57R4j64xdbjpTl7reLby/T2ym4rESC90aBkC2/E" + + "/YUSjsuGG9GiHEVgoGzoQGQNQV0v9ZMIvuoI6q7Fd6VZhIVGE0MGzTFNA9QEEDGPc10ZxC" + + "Gyh9mZYp77PMuhQ12Iv3aDW9KNTr09+HyhK7d3Se7toXLwjE5pKt+A4ZvBFQIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIwmq0fugIX0kwEwYDVR0jBAwwCoAIzeD77B2PfmMwDQYJKoZI" + + "hvcNAQEFBQADgYEAbAbRorTyh6zfAmdg0lfeZyCyW9k4NWfhUs46iSOl6lkZH8c1eoAF5/" + + "q0pOF+CtI3F9VMhfUXChEbVj7QENctU7kDiFe8300OWD5h1VUi+WTK4CG7B36/BjkrVOuG" + + "Os76P9l1WaC+/WRZdcqgFMfPjpn3R179dImBDwZiCMMbVqc="; + public static final String Intermediate_CRL_1_PP_06_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wNi4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIIWvBqhmztZwwDQYJKoZIhvcNAQEFBQADgYEADX3u" + + "wxpN+p8N2HqmhFw8w9LCeoR3Xa/uaqgqh4i/VkDuAC4Bi7VbIO6rcxDO2uAdZgNhb/hnRq" + + "cvKLcy0vrovCa2EPHcFo7dJl7si2q09EeuHT4+lZt/Ek/VOkwHhvh2o6yEvKOGXCnF9hZr" + + "8YbOIknboEz+tRfxoJArRBwpJkE="; + public static final String Intermediate_CRL_2_PP_06_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QUC4wNi4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIVKaBmc31exIwDQYJKoZIhvcNAQEFBQADgYEAQz7u" + + "dfU4yAHFLH5BgeZkYh0l2lZ95af+E/67MSCjQSF7RWWWTffbDMc4HmiRlZLvQdltyGCKmi" + + "kuzcPP8vyYOBQmoIKQ6c2LItBjXVavLdpe91yCOhCWXVVlnMFq5ztrvBEpfO0GVUOnPWfG" + + "1Ugit3SEd4DbhYFTBYHbbOKRWsU="; + public static final String Intermediate_CRL_3_PP_06_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QUC4wNi4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIzeD77B2PfmMwDQYJKoZIhvcNAQEFBQADgYEAkiW6" + + "h9a8v+IITd+p0jxukj2FYfmED59ZXAlYhQdQAGlPE71rOXn6ZPURYoGf7qlmBwQffpksOb" + + "Byb+PX+CBTUNXzhgTzD7ifM9xOhCEKVKai9acQfvokU56OHwfq5AnkRykLZ7IdvdYCP57k" + + "ynrNNV35dsMZXg23/PpreumlOkE="; + public static final String Intermediate_CRL_4_PP_06_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBNC1QUC4wNi4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIwmq0fugIX0kwDQYJKoZIhvcNAQEFBQADgYEAnTbS" + + "MBWyoPaslaLpAMmJ+D6kmmKAdRYurA0okU/QP+0W+YNPV4DducAQUDy8Cg3RkpRK2ze0ad" + + "l6TUW8g83hj9TXSBp+XZuVvzerMCjOeBqhskZN4Ly8101ZZmMmdYdSc3PEhqkme6iZzjwB" + + "ZooAN2dIYjuBj1c1/t5qH80CMAI="; + public static final String End_Certificate_PP_06_05_crt = + "MIICbjCCAdegAwIBAgIBeTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBNC1QUC4wNi4wNTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDYuMDUwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALyVMklPv3uwTPzLG70sXIwKSEt65yiU71ibHyhH" + + "wJ/6dXy3HK2UETkRBK7UVSOYq005EbO9s/3oR3zt7QTFifvRTsIjl1L4TCLC2a8ApBr3BH" + + "xmBWcJDf427Pk1fm5qDdEmZnpyIlpKaKIiBcdtwZfjr0lROL8RNcvgtJPdu/ndAgMBAAGj" + + "OjA4MA4GA1UdDwEB/wQEAwIF4DARBgNVHQ4ECgQISjAUfyAwSA0wEwYDVR0jBAwwCoAIwm" + + "q0fugIX0kwDQYJKoZIhvcNAQEFBQADgYEAC6Af3cJUh/IQgWdbC2Vmk96sYjDlAsbA2keY" + + "J0bgBcNaIVoJ/W0B3rSawqSU+Vv64p7kcuAl6cbvIXPB++19V23jj6HUs1JxtPJZ9IWkS/" + + "FRakv6lD7+j1OdzJvDR8AMZWmPFHJdQnJwQ+I1YOU/O/ShawOnGCmihpIULUINFhk="; + public static final String[] TEST_47_DATA = new String[] { + Intermediate_Certificate_1_PP_06_05_crt, + Intermediate_Certificate_2_PP_06_05_crt, + Intermediate_Certificate_3_PP_06_05_crt, + Intermediate_Certificate_4_PP_06_05_crt, + Intermediate_CRL_1_PP_06_05_crl, + Intermediate_CRL_2_PP_06_05_crl, + Intermediate_CRL_3_PP_06_05_crl, + Intermediate_CRL_4_PP_06_05_crl, + End_Certificate_PP_06_05_crt + }; + + /* + * test48 + * + */ + + public static final String Intermediate_Certificate_PP_08_01_crt = + "MIIClTCCAf6gAwIBAgIBejANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA4LjAxMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCp2vHVX08nyKe+S8NPkNJOZ9Xng22TbYXhUHtXw9yv" + + "ZmPkRhwDrZfBLXZcdZFixidkky3kCzv8Q3aPyPByM2ozH+AHJzEMbwifhyvUbANcS+Jts3" + + "lsZHarN7VyiXO+8J2OtYqX9qzmrAOHGleB2cJopEcmAMdrzgt1JIo98SUs4wIDAQABo2Mw" + + "YTAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAWBgNVHSAEDzANMAsGCWCGSA" + + "FlAwEwATARBgNVHQ4ECgQIoRYqHNcbLacwEwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZI" + + "hvcNAQEFBQADgYEAXchRFC94Pl25d3Kl4wBcueQLyWPRuH9zS0ZPLAqKLcWVdcg3fYMuJ5" + + "SypMMpxLaVjN7xq0KjML1gLiPQPk18iA2TOAUMblvjUl1uFzDdD6SqQidEZh2h3wxFtbLP" + + "U7qBBki7i1+Xn072Bpn2paw/vlh4K+ut0tFQ2BAhqVnQGJ8="; + public static final String Intermediate_CRL_PP_08_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wOC4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIoRYqHNcbLacwDQYJKoZIhvcNAQEFBQADgYEARyX9" + + "2+LoXD2fIAACBMPDgds6m3Equ+Aawlr0kuppPO4ydCU4kiEgtVGK+kY5GzP6fUpAKjC8mh" + + "BrozojhAbkJekDoN0BIJ42Iab70VmdWXRQhPsUDhQwEt+9eSgy+HfiFfpcL1VJx8uY4XMh" + + "VB3hmapIe99P/T2QkZ+Pl8j0MgY="; + public static final String End_Certificate_PP_08_01_crt = + "MIIChjCCAe+gAwIBAgIBezANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wOC4wMTAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDguMDEwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYtrtpgxNl+9jF3TN1B9bSEGQci+cQOKpFsmrtF" + + "AyiGBxKONgGSgSFFuFIhyBKZF5ROaKX1P8lsQkrpnuybUi+Z9ADdyoaLUDD/z/kp5sebAZ" + + "ujmF8HVlqHYj5Ls2smS9EdSN1zgPTXIOTeZd/lv1iFppRZv6cBqlaoapQJsb1JAgMBAAGj" + + "UjBQMA4GA1UdDwEB/wQEAwIF4DAWBgNVHSAEDzANMAsGCWCGSAFlAwEwATARBgNVHQ4ECg" + + "QIZjcOdw0ZTCYwEwYDVR0jBAwwCoAIoRYqHNcbLacwDQYJKoZIhvcNAQEFBQADgYEAarsn" + + "13/g0vOKxy0okOp2JXEsPdsP7aWnCfR8N4+7gFD6dVnkgCIyc5Kbs7MbhB9gtIxYhHOV9W" + + "MaW9QAcBH+eXciFDfQBfaMBkL34ssE/TsZ92r/bhBwKRcH54f96G0QWUnoNMt4U/1j2mKn" + + "faFirltqEPUu9mv4FiQ0pNT9yH0="; + public static final String[] TEST_48_DATA = new String[] { + Intermediate_Certificate_PP_08_01_crt, + Intermediate_CRL_PP_08_01_crl, + End_Certificate_PP_08_01_crt + }; + + /* + * test49 + * + */ + + public static final String Intermediate_Certificate_PP_08_02_crt = + "MIICojCCAgugAwIBAgIBfDANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA4LjAyMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQCmAgNA68ABUEppM9Oo3guiGvguvtrWQzsQIJfMBrE4" + + "/Scwc4SPK4PiJD+kVwtXinXpVclBMQge10uZ48lSJTihfZscJw3RSHt70H4CpPQm44QS7P" + + "7fQqpcZKZvMWmY6A8jju3Phbuq2WgJCIxxVw886GNIAXW8C4ZFmXCjwiGGHwIDAQABo3Aw" + + "bjAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAjBgNVHSAEHDAaMAsGCWCGSA" + + "FlAwEwATALBglghkgBZQMBMAIwEQYDVR0OBAoECOhZ4RAlqGGcMBMGA1UdIwQMMAqACKua" + + "6/nC51SPMA0GCSqGSIb3DQEBBQUAA4GBAGEVSOcNaUu50f6AgGBtz1MDdRiHe08W/nzCNn" + + "0K1/UqrIXVJ7IYgbOLkL3cdHy4PdngCyEblzl5Cwp9chh2zL0PTUbV1uJIBW32ks1HuAVQ" + + "FTZqx0iuopY5AqRCJVDJt4HB5PKObwnmLPNWicI4Juap13j/Tcnw1EP7E7n6OejC"; + public static final String Intermediate_CRL_PP_08_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wOC4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI6FnhECWoYZwwDQYJKoZIhvcNAQEFBQADgYEACLHw" + + "iDARFoF4GauIHnoZlfj6nlOHAFfNSXq06Vvl713bsoAiOSV+2goZjRG62uxhampE+gCdXx" + + "1nwhKQ5R5jOGGOxgLtBFNZwKmD0KiDOSvfIVJ0kYCcaB4mSm0a/7pcCPrrE5ofvkmTW6Wx" + + "k/YIuBZdDoqZC91v4tnu0fSch9Q="; + public static final String End_Certificate_PP_08_02_crt = + "MIICkzCCAfygAwIBAgIBfTANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wOC4wMjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDguMDIwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOJsz8ys71e8UB+VDTBAocVQvADiqh0LjdML3pET" + + "B6VvikiHgbB1PJufxDses+v0WD74ChZEa/octNcMFqMgBlhVBEfvbyGTjiN97LzdZ7SPyd" + + "DsDulqwBG9sACryUGHqwHYnUbjOqsThOXFB8Sg/CGGawpZAosm2AuH2gqNvNuJAgMBAAGj" + + "XzBdMA4GA1UdDwEB/wQEAwIF4DAjBgNVHSAEHDAaMAsGCWCGSAFlAwEwATALBglghkgBZQ" + + "MBMAIwEQYDVR0OBAoECOiMLE2l5u16MBMGA1UdIwQMMAqACOhZ4RAlqGGcMA0GCSqGSIb3" + + "DQEBBQUAA4GBAFf4BCbNtduwn5InkfdtFbQOqhPLAn/5eIhxhVhUu7TekWT7ktdaVQFzGF" + + "G2h1+gXgFP+YKjJy7kGzEVQjlWtuC0l74EwybNHnYAoDg4itKe+0OSNNXdyOmn+i0tE0nx" + + "sWN19VvhLGFC8p38gd0oDr1ziYdg0z2Mx4IlMDxl7QhT"; + public static final String[] TEST_49_DATA = new String[] { + Intermediate_Certificate_PP_08_02_crt, + Intermediate_CRL_PP_08_02_crl, + End_Certificate_PP_08_02_crt + }; + + /* + * test50 + * + */ + + public static final String Intermediate_Certificate_PP_08_03_crt = + "MIICkDCCAfmgAwIBAgIBfjANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb0QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDFRydXN0IEFuY2hvcjAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMF4xCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvZDEQMA4GA1UECxMHVGVzdGluZzEVMBMGA1UEAxMMQ0ExLVBQLjA4LjAzMIGfMA0GCS" + + "qGSIb3DQEBAQUAA4GNADCBiQKBgQDKZDgBum5Ud5i8HWlCKInJ1x9goZ7TQJ+LdfA9iGU1" + + "47xJL5eFcERWy4dr5wM5GNRW/DHXlnA/qsRVE29EuRh6qAVgcPGAfmJxz7s5yhmErfmiQ3" + + "0rh6+pma/EhcjntXqwIqnk1qt6mEk7x9UKO3ksFCVsDEA67/dvownjcZB59wIDAQABo14w" + + "XDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjARBgNVHSAECjAIMAYGBFUdIA" + + "AwEQYDVR0OBAoECGtTrZIwYYHbMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqGSIb3DQEB" + + "BQUAA4GBAM3t13xJJraRiJDAwZFxhTNR570wMdSRiF3yWSRtOjEv8NTVFj/T1oJJ8h9Gqh" + + "hMpTTHU7uGCyVB9S1HCelmS+1zteKr0B+WVzBl9yuhvku3farz6zgIVK3v5hQ6xC4H4Lac" + + "NDhTTKBkRfDf9KskFoxJ/AGxPdZtIEC92DFSblQB"; + public static final String Intermediate_CRL_PP_08_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wOC4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIa1OtkjBhgdswDQYJKoZIhvcNAQEFBQADgYEAcUHo" + + "D00X/pd3D5KGa5C6dY18RsnUovkjUkegGTpbhQfmYZIdBatj7Kv75FeUJ9UpqCUjxHgdiE" + + "EVy60NLVGP2VRuJ1m8vfDz8hu5PaiVjneQoRw2M9ieBnz3PjSETDdBGJLWHyCBZbp/W2+0" + + "iqcZK7Fm9O5EL4PUO6QIwuH76q0="; + public static final String End_Certificate_PP_08_03_crt = + "MIICgTCCAeqgAwIBAgIBfzANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1" + + "UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3Rpbmcx" + + "FTATBgNVBAMTDENBMS1QUC4wOC4wMzAeFw05ODAxMDExMjAxMDBaFw00ODAxMDExMjAxMD" + + "BaMGAxCzAJBgNVBAYTAlVTMRgwFgYDVQQKEw9VLlMuIEdvdmVybm1lbnQxDDAKBgNVBAsT" + + "A0RvRDEQMA4GA1UECxMHVGVzdGluZzEXMBUGA1UEAxMOVXNlcjEtUFAuMDguMDMwgZ8wDQ" + + "YJKoZIhvcNAQEBBQADgY0AMIGJAoGBALsXEPrCg91CObTl5OrHIB5GshIDXgqBmjzxfWPK" + + "ih4STWeBe2eIFO9pONXcM5lstEu2XLBPP6QBMUMWOrphJejrJ3eDQHs404bBnt95O/x17i" + + "665CZtg1jUqoO1kOBOComx2AJGZ46RdBExbfd0tTtdHWtRhMsnQchI+WtEyotdAgMBAAGj" + + "TTBLMA4GA1UdDwEB/wQEAwIF4DARBgNVHSAECjAIMAYGBFUdIAAwEQYDVR0OBAoECEWZkJ" + + "TYQ3z5MBMGA1UdIwQMMAqACGtTrZIwYYHbMA0GCSqGSIb3DQEBBQUAA4GBAHki/TrpHiKW" + + "gvERhguQ/uOqHHZNXsog+fgGVFFMOWwJ9bq4aHKd1fDZpyZF4vBxW7llbhuSt+ob2TNlkR" + + "wkqzfGL+3xOTKNRgzDwJcil8akC1N5uBftrQk+eL7rM1PezWRM7fIbpmv5ZieIVswtTPF5" + + "1Rl3G+JXUBy9E95espls"; + public static final String[] TEST_50_DATA = new String[] { + Intermediate_Certificate_PP_08_03_crt, + Intermediate_CRL_PP_08_03_crl, + End_Certificate_PP_08_03_crt + }; + + /* + * test51 + * + */ + + public static final String Intermediate_Certificate_PP_08_04_crt = + "MIICljCCAf+gAwIBAgICAIAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QUC4wOC4wNDCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsrM3A06j1zDz6VuZh+O2UrAPcKtwSA6KxTShUpgr" + + "t9UB5iIAEvxcDTwDlubEv/cJjDcFj9N57otzW4ppnuT2ztE4ROmkNb0xL6u00deS1yGjXB" + + "wy1G9g8bYDdAXOJlv0tjHOBqXlyKoMny82BOBL2vsCstiqxl14Q3/wBD1w29MCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAMwEQYDVR0OBAoECJiAkexK6/c7MBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBAL4xwcpXZQPTTPYIQ8CMoVla/5P1x6BPmPqSkvh1D/o4ds9Ll9kHBz" + + "//X1ZM8SzYcEO+1r75JUzoHsvDw9yYAk2oclLsCORAPqD8Owhv3jv0QQtYSmf0Sxt5FLx0" + + "MRP9keY/DURRf9KitO4glOawtRtYMq2BeeJk1xusY0KqEnQr"; + public static final String Intermediate_CRL_PP_08_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wOC4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAImICR7Err9zswDQYJKoZIhvcNAQEFBQADgYEAcN3a" + + "jIEcXsQatb0fvVcFnO7d7lzNtgbqL3MtaqJ/PjkRJ/rO7JAXQRwdajUZF4ECHylZKE2HUG" + + "Dk+vidV98T8mNmb0TEuuLV+J1G0q8ezMXRJtDt/2m3y1VBireXlEMd1DdgpsDdCQ4va+XJ" + + "qv0TvVhfxWry+LrVb6Bf5ItexXg="; + public static final String End_Certificate_PP_08_04_crt = + "MIIChzCCAfCgAwIBAgICAIEwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUFAuMDguMDQwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBQLjA4LjA0MIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPJWa/cB7WW7tkGxFhcwxqE+BycXe3Ru2qGbun" + + "NPQZ/j44UT2C6rl1wZwugCY0sR6mXR/P/NR7czZvg4Tt6lwcNtc8PeafFMUeu0u0Kg9uWn" + + "fzQQKeIgRVcEzGTGMPGWXS0ed6X/1+Dj8A+T/tqXKUtM3Jpe0pCmm9CIrYCXLPRQIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAQwEQYDVR0OBA" + + "oECKm9IOyOM1h+MBMGA1UdIwQMMAqACJiAkexK6/c7MA0GCSqGSIb3DQEBBQUAA4GBAEXy" + + "dlTkkZaYK6sUJCiPeCPxfj5cdo/G4RGBImMJbTeDyVTvXSH9G2yWUMqBGnYLrwdJJeXjF3" + + "89miJgnJ+1r/r3r2/NeAUuJDsOHRMFh0KXFmgubyw/kGsZBe3279hDnND8ZjfQBmKQD17f" + + "PycWTTAC5p6GM8tGERiDSnMc5rmm"; + public static final String[] TEST_51_DATA = new String[] { + Intermediate_Certificate_PP_08_04_crt, + Intermediate_CRL_PP_08_04_crl, + End_Certificate_PP_08_04_crt + }; + + /* + * test52 + * + */ + + public static final String Intermediate_Certificate_PP_08_05_crt = + "MIICljCCAf+gAwIBAgICAIIwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QUC4wOC4wNTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwH2d+D0pH8y4QJAPpE0s2oWucV1jlE4pBMGNNPJ5" + + "FIRmyRCt90IpzmK/EuqT6iSZYd9hIB9wa180ByN67PK1z4loLFMUL2RmbWeAFlGy5eEFOy" + + "4d479qfy6JCOzt0TKhYzhukLUqGLa4DDTzvnnUx0o86aLvGq0K5s6DRlNyc08CAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAMwEQYDVR0OBAoECDSeuxr4EVgaMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBAKoGi6qlODB8Lc86PtGXfBhW769jB8xzgmENE59sqNBEvYa/oK9Xxm" + + "1JX1OGEQMq/mqwZXg6hSczpexCIO4tUH8QKTU68yvqcZoZCDV8FLM8aEUPtUoPIpluhAtN" + + "scGfb3uXoV9fg7q1Pi5YlKMnNrDIq1tH1CAGKMDRrjW63Q8C"; + public static final String Intermediate_CRL_PP_08_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wOC4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAINJ67GvgRWBowDQYJKoZIhvcNAQEFBQADgYEAv5Hs" + + "nYPZO1fGC/Z2lIbbUKjIv0+BrR9HbG+b76wXeJTVxfXMlZe0cpOR/KD29DyxI3G4IedHRy" + + "zL8iCDWYbA86arJzl5GZJ1MC2A586vNn/6wiiT6nP3iMj2z/nyvan8L30KNBm9IDXQExOu" + + "PNE/wOWYBxxCjg551fpXfJKqDIo="; + public static final String End_Certificate_PP_08_05_crt = + "MIIChzCCAfCgAwIBAgICAIMwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUFAuMDguMDUwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBQLjA4LjA1MIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC4BZFTwOqI+71v8CdiYbe7x0qYveN524h6+iLh" + + "oEqvzuVKVqvQgVSaSLPcMhoCGDv3nqyP57Znl/3I09vLU6F4HKLtjO9E0PZu8EXOKLjeWP" + + "XmJQkdHfODj/TrrWSsrdorl7s7gdWEUFlbiWvUVUtkqLNbGLJZ5Q1xZvBRLS7loQIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAMwEQYDVR0OBA" + + "oECBDaTXbN11BBMBMGA1UdIwQMMAqACDSeuxr4EVgaMA0GCSqGSIb3DQEBBQUAA4GBAGVa" + + "QNtd4LgoVZQ+Uy1lSr6sog4fsGaoQJCZcvrMJwGpMF0FJsGtOb0R2mfwHi1YXqPF5qZY2I" + + "7cVbwVtRQzbXunk1z12k0iIesMtYUncxb/SBstC7VNS8HNZm9ese+YM6Ac8mGT+IUZsPcP" + + "gI9fQ1L/2u+/3L4fweca1R45xm5M"; + public static final String[] TEST_52_DATA = new String[] { + Intermediate_Certificate_PP_08_05_crt, + Intermediate_CRL_PP_08_05_crl, + End_Certificate_PP_08_05_crt + }; + + /* + * test53 + * + */ + + public static final String Intermediate_Certificate_PP_08_06_crt = + "MIICsDCCAhmgAwIBAgICAIQwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QUC4wOC4wNjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAlSIH/+6DEL1P9tkgbsI2PcW0w9dmqMTLP3jKYPsr" + + "sSWI5bcv55sk6RItVr3hGgkaskZoHeamUBAiGPksVyrqmRwSCJzQDLnLdMnjjudvPjp1ZZ" + + "9UCufTtMPFvnEuVBx5e8A13AQ4OyHqaJgWRVoRJd6vwTa5jzfYCCMJZHHKpcUCAwEAAaN9" + + "MHswDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwMAYDVR0gBCkwJzALBglghk" + + "gBZQMBMAEwCwYJYIZIAWUDATACMAsGCWCGSAFlAwEwAzARBgNVHQ4ECgQI8837JGF7vMAw" + + "EwYDVR0jBAwwCoAIq5rr+cLnVI8wDQYJKoZIhvcNAQEFBQADgYEAKmgbxzWI6V2twYDp65" + + "Gu8zn883CnI08s2FEVupvrKduxYmg+ZDkTBE3ZJFxcOuxJf58MRfDWy8C4jJhLnT3JSSSg" + + "sY3n93jzc0s2h5y2wd1bUTDLqhqWCshisDG/88rpv938O8luiUEwltolzKTa+ScA6nXSQt" + + "LT4I6O3vbTx2g="; + public static final String Intermediate_CRL_PP_08_06_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QUC4wOC4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI8837JGF7vMAwDQYJKoZIhvcNAQEFBQADgYEAHua+" + + "lC3wP4G6796jjr6wuu7xEQqY1azsLVsGtL7YL8fm42rl7hgU40SuFIc7Kc+A7oEEkKgvmu" + + "SLMIv7q5O8J26fQOuduGWQAncPYB8w7sNWjCZbdjVbjp1XIApcAL3djCbLZ8/NYsCoOuwx" + + "hRQKX1hIn+rNDi1DMD4H99QdDGE="; + public static final String End_Certificate_PP_08_06_crt = + "MIICoTCCAgqgAwIBAgICAIUwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUFAuMDguMDYwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBQLjA4LjA2MIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDnaYU/lu+u+LmLQwyACSsRyxQEEvgriE7ApmHj" + + "sNBcd3lovFQMfw9MyOOMsInOgQZU8p/invnhx11/pwi77ViQQ780unhHt5H/tteaYwcsDR" + + "cUxR/8jK0DBnbVWvm8S/NGb8BxfbRmDHBTWGZ70hDSCJypWRfHQj0I/SAqAW/VuwIDAQAB" + + "o2wwajAOBgNVHQ8BAf8EBAMCBeAwMAYDVR0gBCkwJzALBglghkgBZQMBMAEwCwYJYIZIAW" + + "UDATACMAsGCWCGSAFlAwEwAzARBgNVHQ4ECgQIhh/KikcKA7EwEwYDVR0jBAwwCoAI8837" + + "JGF7vMAwDQYJKoZIhvcNAQEFBQADgYEAbHK3lkqbGy61lu9d22uO2H3hzwvjmlccZo8pro" + + "ord45d2nRIxw2ag4dS1YRFrefVdxZtKeR9+5o+tQtvmTcDOer4u6NZ/sVVElTb1d6axtL0" + + "i4cmqv6bGWYECEwtwmPGqAavp9pPZjNRbkBGy9qhVNTXfDQYpA8yzXWO/xUrwNU="; + public static final String[] TEST_53_DATA = new String[] { + Intermediate_Certificate_PP_08_06_crt, + Intermediate_CRL_PP_08_06_crl, + End_Certificate_PP_08_06_crt + }; + + /* + * test54 + * + */ + + public static final String Intermediate_Certificate_1_PL_01_01_crt = + "MIICmTCCAgKgAwIBAgICAIYwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxDV2d7qXbpCvOzBimskBLsgexpEYaHv0s7gOaqhC" + + "4A3K8sxdjyW6QdGZhKX8tCMqnlPp9CNbpY4tQQ5oTSk5pj6HwAsTfGcDwXJnjKWx1FJ7rD" + + "meZZ8c2K7a8voBl6FoPGn8CMhO0WmM9Eyb/vDUPdCZzScb+z/BxTcV1BPFdq0CAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECBpj0+Gcq32oMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" + + "CSqGSIb3DQEBBQUAA4GBAB/9veHrkLeu8jkwXggJtwqPTmkrIBcX+pz85BTSETYeLOzF46" + + "onk+qt+IHptlrm3D7ny2Y5M0dQQ6tPzhGZxCEg9RoDibZGtsx+qeAh1ZjeEpEcQyp/idWY" + + "asH+EIuEIOZA9c1ySxI/3v3ZfzaSGS8jsgSDkLB4JumrE9ZkLNd1"; + public static final String Intermediate_Certificate_2_PL_01_01_crt = + "MIICljCCAf+gAwIBAgICAIcwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3B3UKG3tEL6FQz6dL6iqSvzgGsm1Fg5uzK8npkEq" + + "g2caUM7huYFfXeur1mu6iKiROcGX8ZYxrPi9Orh39YVrSu2EUWvqQui4QScf4dIlzAOunv" + + "0gAa/lIVTHgZhIomKND6/tZLU251dJiFhoV6bXx2tor83vWFVPx2oVd5LL5S0CAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECJmK3jFTIl6lMBMGA1UdIwQMMAqACBpj0+Gcq32oMA0GCSqG" + + "SIb3DQEBBQUAA4GBADkYLTg4RncTpAFmpUy7WGOMvoFV15nDoi91OMxhxVkbGSE0DJFxi3" + + "hPKcfUNvzy0bEUUTaqOXdbIkoLTG77NTckJxurSRyam0jA0+6SUYZ6F9fVotwMul2EiVl9" + + "XP5oCt7LkgqVgMASuwfzMnQozB6Oi/YP2OdSPXLipI6rl2dx"; + public static final String Intermediate_CRL_1_PL_01_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QTC4wMS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIGmPT4ZyrfagwDQYJKoZIhvcNAQEFBQADgYEAd8YZ" + + "8jibr8yjcGYSDicJuyUvHBZntTVQ1sP5XVmtCZcYcQCVjbC0auYTEP5snXbGPW5qeEaaXB" + + "MhekMr776hP4Kl3g4AjguFl3XQGcURlgNd8LsTpMMdNWC7XwooOF2FzFjD1ru0BSEWabzW" + + "NNaVeuMMbu2N0lc6NDJvRC8LkhA="; + public static final String Intermediate_CRL_2_PL_01_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QTC4wMS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAImYreMVMiXqUwDQYJKoZIhvcNAQEFBQADgYEAZFec" + + "GtjOfp8pT0n1dMF/x9n8y5tM+G3LLnZvDJspLc/sqP3E3B/sHBiis81caEkQQAOTBU5goJ" + + "0KOFAUOfEq+IX5uvNhuPuinx0OsSak+2Annvi12zodMQKPNm1uMVt2bMHHHZVEVTqcv36g" + + "xgdbp0YKTmuvSy6s8NtGFpkNmnU="; + public static final String End_Certificate_PL_01_01_crt = + "MIIChzCCAfCgAwIBAgICAIgwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTItUEwuMDEuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBMLjAxLjAxMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCAUPp5j4V5XTA44Ra1EWkp9HgS4w3uXJ7/Vhi" + + "K5bARFrDOOxjV8nmr5hoUYr4jwdi2Rl+60TQK/F08gdcGxdyc9p/yiU5HyAP6i+4iqmvaW" + + "9b2egNyZ5tOmpl/Q9FSFWa9d/PYBKM5Sj/r73RtA+/chc4uq3uyLekSRQGh1MieQIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECAiL3A4CkaFyMBMGA1UdIwQMMAqACJmK3jFTIl6lMA0GCSqGSIb3DQEBBQUAA4GBAJtH" + + "mNNvCt/0uFbHdvUvCuBeZ9cggfpTyUS4X8zgcLDPFbw6VvX65umOZpceZI6hwcre+LZahi" + + "gUEPvXppncEObkeVTcYdOTSDoxh5tZyee1P4sbD9H+suGWeewqUDvFs2ymHtxlkpOttitR" + + "xQc2U6VlCuZ4XU8SwucyhW0z51e4"; + public static final String[] TEST_54_DATA = new String[] { + Intermediate_Certificate_1_PL_01_01_crt, + Intermediate_Certificate_2_PL_01_01_crt, + Intermediate_CRL_1_PL_01_01_crl, + Intermediate_CRL_2_PL_01_01_crl, + End_Certificate_PL_01_01_crt + }; + + /* + * test55 + * + */ + + public static final String Intermediate_Certificate_1_PL_01_02_crt = + "MIICmTCCAgKgAwIBAgICAIkwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wMjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4QmGXEeVKCn1aQx27r+EBuQqfi8fP7gyV5JLkaSu" + + "DOUrqXg8dQxHsBNCf3XilGIvjNFZjVUPdS8FNqC+if9D164VyGQlv/JUor/GlvwVfyotUO" + + "U1PqSzFrAALYTmfm/ZqhMvGYloStSDxlzjDmyKadskzOxZZDNSe5s8dvUpYn0CAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECGk7qDbbBgRbMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" + + "CSqGSIb3DQEBBQUAA4GBAD+eI+jg4jmeC3pJRGEF/hbPPYvL6aocjqqbZyNKN5FWItccQo" + + "PWg/GK1GpusDZadesZBDo6fLIUJzL+OumrIYJLB3HxQsmyOXB1gRg1hcva71RWFJYzx01U" + + "eB8lCbk8Zu24HzLzqjfVuwKOFFELWDEq7bd6Re/aKSHtNnDbsgSE"; + public static final String Intermediate_Certificate_2_PL_01_02_crt = + "MIICljCCAf+gAwIBAgICAIowDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wMjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAl/HiHoos7eHaDIFhMmvIPk63UT33Z+0iiCIuKLW7" + + "tgkT8ia1Yg++np1pC3oqYVeKkXqMcjgonPGQhcek12vLt3/+2PYyYirOTVZaiO9pKQ5An8" + + "ZMWXIJmCEAMHabPO1RnetvRv5JZFxZY9jIUnD2fUADzzUh/eHN6Pur0DDrI6sCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECPk0C10KQLZuMBMGA1UdIwQMMAqACGk7qDbbBgRbMA0GCSqG" + + "SIb3DQEBBQUAA4GBAMJ4+BZQxpxWhNbo8bpGkbbcKT3kfKYrHjHsZADC+/gAJSVL854b1W" + + "VKsGr1YcCX10V1Gcqb6Jgziy+AzRLhcJngszcz0A7LxrMH+FIyWEPgZnOyQCa8B/9bnsh9" + + "bC1gEmXGOVtWboIFOEdGghEbm/ENnQyj+HbIk3jhF3QYbXhw"; + public static final String Intermediate_CRL_1_PL_01_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QTC4wMS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIaTuoNtsGBFswDQYJKoZIhvcNAQEFBQADgYEAZEt+" + + "FjRuXgnOZg70geqS4hVsF1VWWawlAVGmjPsbRH7rADXPUE2bYL54wLdwt/6QYwHqy2KwCf" + + "d4OkWkwn9xwGS4j+XBCw9Y4nbWI+wrsZ9W7vgbeIaVUUUZu6hoin1GxrGDcfbM+bhYzQAA" + + "gNmKIWdlJ4tKD2KNgg0KmZPoj/k="; + public static final String Intermediate_CRL_2_PL_01_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QTC4wMS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI+TQLXQpAtm4wDQYJKoZIhvcNAQEFBQADgYEAXwZO" + + "wr9mrO6yUOoopNjcIcDssCUksYco1PFgWx9O/hGq9ktdoGoGcECGhdkHTLe2ab3WFl9jzW" + + "1/lkysD9Jl3VjbnbRB3dPQlrSfiv7cYBLnfKvyF/CxQg/wCtWo46GJJQgOx/WHzi9aF08m" + + "tQuJEtl7RgoByUSvLtmvKjQWEnc="; + public static final String End_Certificate_PL_01_02_crt = + "MIICljCCAf+gAwIBAgICAIswDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTItUEwuMDEuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wMjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0/rXOZwUebRaHcPPFeKTB2OWIzIAgavqb5HerPAe" + + "c3sJCdNOSLc0OX0dFblso97WR8uueF9I7QeGg3ayQjzDVqm5Tu77ZaCuyb6UU8+fY2eqwD" + + "5lCVuLfJr9U2JD5b2TcdvAD9RqfhefclVjDj9rObLjvzLg3AefO3drsfBtAIMCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAeYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECDBWCFTOp3evMBMGA1UdIwQMMAqACPk0C10KQLZuMA0GCSqG" + + "SIb3DQEBBQUAA4GBAI/JpU3gHo8Izsbjlx6bkQo/e/hD634N5lSMtVHIGnoVLu99dvroRu" + + "2DO8Fhnv6VZpMvYoAc5oEgUqx9hw3bfS/XN9GXaeMssjwN/qM6lzCsvMG7DA9sf59xjf4Y" + + "2+u4KTye4PdpmWaseDDJ1wAihTHEaofnQdaoUffxQgw5UcAf"; + public static final String[] TEST_55_DATA = new String[] { + Intermediate_Certificate_1_PL_01_02_crt, + Intermediate_Certificate_2_PL_01_02_crt, + Intermediate_CRL_1_PL_01_02_crl, + Intermediate_CRL_2_PL_01_02_crl, + End_Certificate_PL_01_02_crt + }; + + /* + * test56 + * + */ + + public static final String Intermediate_Certificate_PL_01_03_crt = + "MIICmTCCAgKgAwIBAgICAIwwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wMzCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA60y6V2WkNCB34dcGfu+Jo3YHQZXzgp76+HgnyFmP" + + "DLj9DjZHqifD3gW8Zk7L+yK4PfLDSHjbrXM9GY1ser6XwhaJQDPUBBYW5X3XTOmDWmV63J" + + "YeRF5r7cfF2h3eEZ460GRLK5tt0Zr8V+hA9oOvwqynrIhDYC/tCzE28ciqA+sCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECPE2FCetVerZMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" + + "CSqGSIb3DQEBBQUAA4GBABUOUWwyfyrRIw7dRIVfLlWyp5R1I+Kmq5e8st0AEMVpPAmLoy" + + "0s+46Xf+THXZy5em1P3bSVTSUhTs+XD6tbFFUcTrX0mQJlshR7yD/A0siMDUNzzt9LJQvP" + + "dwNjQSA2keOrV9q/2CAGce4daL4Wz54jfh33YVqJ8sHT4E8CxQb7"; + public static final String Intermediate_CRL_PL_01_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QTC4wMS4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI8TYUJ61V6tkwDQYJKoZIhvcNAQEFBQADgYEA6FnB" + + "LXWt4B/3oP0PXERYh7ZV39yu/tm9DHBQGcGDF8JIspU7F+mH/+37U/lT6BQxpKOpgOgGeP" + + "nTQeQzN9sRsXxFO22SkHbdPCao84qvv485epgzqFcVsCRBwBBLcnNLMg891q0EYsTW9vSw" + + "Dx7V4CawyYAYGz1MqYuY6SSs6Q0="; + public static final String End_Certificate_PL_01_03_crt = + "MIIChzCCAfCgAwIBAgICAI0wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDMwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBMLjAxLjAzMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwt6B9gpDz/x/vnowXf1MdkAPeaCWZ3pYikgxE" + + "ZLrMuulFaI1UDnAzgSuSvoHE80VKGKjSkrzIX9OFfeilW5rNZAXoZrjtkaJd1Q8l5AtjFn" + + "0tlLytDzIMYo5Tiq/n3IiTdbEzGYzEOCcSyVaQdB7K1WgYI/z/UAaWV/GbqCX1zQIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECMQHLiufEm0IMBMGA1UdIwQMMAqACPE2FCetVerZMA0GCSqGSIb3DQEBBQUAA4GBAD5/" + + "vGn/rpoHvny/mfh6n2zVNNQLTEBiddfAdCWpeBFcwxS5lpxfm4dAWgHhprZTMirF9yS+wO" + + "wWQ4G9/wiqfAtoaNN1qkHMlUMOAPsOSff6ClgP+1uzKVqQa9NTd5HAeMdYfYjMa/fcF/37" + + "plCs5ZsJjb9lhEjNd/tq4/aALQmt"; + public static final String[] TEST_56_DATA = new String[] { + Intermediate_Certificate_PL_01_03_crt, + Intermediate_CRL_PL_01_03_crl, + End_Certificate_PL_01_03_crt + }; + + /* + * test57 + * + */ + + public static final String Intermediate_Certificate_PL_01_04_crt = + "MIICmTCCAgKgAwIBAgICAI4wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wNDCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA06yd2NQEAgpv0kQQEOzhHHU4YqHgtvJgkdLYxb2W" + + "Zordrm4b/43UDnLmsI0790V76y9Aa+Y8SIMBBRBJgnlppFJrFsPaOMO98M3/mXkQotVbY1" + + "59P/AjWMxpzP9h8Bs8KuoPqnl5jN0UZAF4kRoNXHzyS445VBp4DtWz/jcCPm8CAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECHxLORDZ1KKNMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" + + "CSqGSIb3DQEBBQUAA4GBACHmDOaoC0Hr2cmfuQvdyGDF7/RlvTUJ7cvGypCa724SwAZGZk" + + "Tf5GwxgjVcLHY5RlX2kDm9vjneDzP88U3587qA2ZRwxhheK0RGp1kudNQ5y2gAGKZ7YSc0" + + "SENMDxUAa6HUkn9Rfo4rf5ULuGNJZXQZ3DtP+lZSwzkUeCVjKhyQ"; + public static final String Intermediate_CRL_PL_01_04_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QTC4wMS4wNBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIfEs5ENnUoo0wDQYJKoZIhvcNAQEFBQADgYEAb8lX" + + "19SlVNRkc9SKNpRLZQom67djZfMSIPIDkBALfMepdevbquzgO7AufTuiDn5Zqe6J6odTv6" + + "RrQReo64XB4+Lx2pXOe8bZEbzZk0HvzLl9DjN7zxyNglNK+Hd2xS4yT4ps4fBdvXvWAXEx" + + "6DfvWHbGFDoH2auomCKJtCVXxCI="; + public static final String End_Certificate_PL_01_04_crt = + "MIICljCCAf+gAwIBAgICAI8wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDQwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wNDCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA14bXc39XiWvb4r1jzbADzrpfbg2Y9sGBkefSQHsM" + + "QZ1SRLR7uexWD7MuDYh4ZYBL+WPhaJJr3a1jnAIp54h68m8mwS13DgrxBF2/hrVKEm9IRG" + + "s13hoM4Mjjogn/Lvc1xLvB5lctHjZrNRZjyrt+PqDDmqZqgCOmcD61PhrfAoECAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAeYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECB9hXgJfzBvTMBMGA1UdIwQMMAqACHxLORDZ1KKNMA0GCSqG" + + "SIb3DQEBBQUAA4GBAB0HgiURRd/REVfc5DenIPhMu8riVcwVgTUwatsCWragUhXpCtvJmf" + + "z4vGo1rKYai2dltVX6am+NDvN5tROcM0bvC8lOCc/iPfI5eWTy9SJ2nxvs1+q809Rj0rno" + + "zS77TIE8rD7Q8ZUd3qNUiBwdjBoc9misgyN7zUulg4Ueebvv"; + public static final String[] TEST_57_DATA = new String[] { + Intermediate_Certificate_PL_01_04_crt, + Intermediate_CRL_PL_01_04_crl, + End_Certificate_PL_01_04_crt + }; + + /* + * test58 + * + */ + + public static final String Intermediate_Certificate_1_PL_01_05_crt = + "MIICmTCCAgKgAwIBAgICAJAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wNTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA/rVBEGZ4jibDhREeRGV3jPnv05esRL8/En1Bu35y" + + "QrAHi32+kBu42vwwDbeuiTZd/B90bn5srJZoW83rxXxNnpxqbnjN3GgIcRiUVyaVRTp9/U" + + "IT8B9h09b9yT8gpQ5qR0+JDcOHCfJwpogAsyJJa6AM5p/q3TeF39ugfVOWt/cCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECJ7/mkuLuEIGMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" + + "CSqGSIb3DQEBBQUAA4GBADC0A2KMMSSmGI9p85WG7XZVMBX/xdDYOHO0e3ORTRFS3kj9rK" + + "a0yUjc1X+p22AA8kUyOLpYIulfDjPrLKN2E/hWSf3+XWMiC7JfX01F+BBl/avEZoymaZB4" + + "dkH1Hym4IMJoSaEOgf5HFKBnFEA6aUcr+oDYGUP+Sc1dmJMjBW72"; + public static final String Intermediate_Certificate_2_PL_01_05_crt = + "MIICmTCCAgKgAwIBAgICAJEwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDUwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wNTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEArir4GaS6r0Tv9PMbaOXYdPKADNpVbJe79G5t/F6x" + + "7Tz1rwUR+m10E+Jq9RsV+fU/nUzzjJXHbPLZnfodUVVmrXgzvQ8+B2N4jJtdNLG66j2PZG" + + "+P8GQzVK9drDh54VHXdvxAYCXs7GaIprWmCQsxZOKjhFU3YDiRRK8qJGpBG/cCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECMmrFr30fUzZMBMGA1UdIwQMMAqACJ7/mkuLuEIGMA0G" + + "CSqGSIb3DQEBBQUAA4GBAI4qJF6STCi+elUbpZIP7YmcaQsS0PE4G3+LJoMg1LT3rSeobK" + + "Aj/yUetmA7y0B5i0svKjRChLOpfClNPVPCx/+mc75+LG+dh1eVG/qk2UH/lrqLN0XLl8tA" + + "IwZeoPaegBQAIp9oEjhDN1fWtKIkOe6A6wYdH2VPvsqC8g02VcwD"; + public static final String Intermediate_Certificate_3_PL_01_05_crt = + "MIICmTCCAgKgAwIBAgICAJIwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTItUEwuMDEuMDUwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wNTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtRC2/PDG3kx8LpzfWC0yJph5h3LXZJZW0W2voss1" + + "HYPP1/MBoQY067dfbALilVRh9asCNL4F45uu0lT24qS9vjW8SzBOLA18GsVYRmWO7EP+Cd" + + "9f3mgPIMJ5n+UjW+yhBwh0Z2pzVElkX9CxECrs1Mt2ulyuwWA1lR8nRMaTUeMCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECAlV3mzXYPyuMBMGA1UdIwQMMAqACMmrFr30fUzZMA0G" + + "CSqGSIb3DQEBBQUAA4GBAG28iHdlA+nTs/b9pi+m9eMy7niELjIWL9fMgn1r4iXQ0TsPYi" + + "tgpoip+BB4G/jz7MPx/N4nwyAPV+C9wN8cAHALf/ka2MxAORYFVFI+5PDgXzm78ILqj91f" + + "vOFN4jemizTES4/dHxfmdctnsTRpU9ALQgfJLhxEQISOPwuemKB0"; + public static final String Intermediate_CRL_1_PL_01_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QTC4wMS4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAInv+aS4u4QgYwDQYJKoZIhvcNAQEFBQADgYEA5i45" + + "gETFAw6l9Awex9IAVIqYTA1dnbDyrUYDRdzd0x6OxSPODvNfQCwqwlTJXrHidCPO8jRhMS" + + "Zcdn/MTlIeHa6OERFcjOiwOpeTgtchvpTdDchs5ve8Ik+myue+cfgpEVKOE+ZQ2T2tcyz/" + + "+DbeMptECfJ0lVfCKIY7ZOzBPaQ="; + public static final String Intermediate_CRL_2_PL_01_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QTC4wMS4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIyasWvfR9TNkwDQYJKoZIhvcNAQEFBQADgYEAdsNe" + + "ugM8sd8bmIDkYXce2WmS5Zx6QUQ0yT6Ij4OR5/F4CG4Vl+k3JkNPuAiNSs2Z9HeML+F/W8" + + "3yEPe/mdLV4nLw4B/b1/8DmgZN4r1ojaWuHAg+KrA3Zz3Rc/hwQfvBy49mf4NGtY4ArbeB" + + "DYKz5sVlrwR+gOCR5jm4IC7WEDs="; + public static final String Intermediate_CRL_3_PL_01_05_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QTC4wMS4wNRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAICVXebNdg/K4wDQYJKoZIhvcNAQEFBQADgYEAqYex" + + "FaIykZo17O2URpofe8x04L/VsfA9jV28zUgNFruAGld/kUh4rYvgwrdbNZ8NmEFDp9J9aL" + + "93af3bzoNvWCik2VrQLd5nccCFiC04B+LUH9Y2p+7vV2ojrtBks5SMW0q4HaNyPSQu8Fst" + + "4mYVf+QIYZC3iVAF4rsKnaxwzIU="; + public static final String End_Certificate_PL_01_05_crt = + "MIIChzCCAfCgAwIBAgICAJMwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTMtUEwuMDEuMDUwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBMLjAxLjA1MIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDCXJjzKGcLyONTyOa6sQHvIKZIAh0pWdteUiXf" + + "b7yjCn6Z52SCHxB9GZERHwR7fbJpoE3oDcYUY+8pH65bIVm1p3zr5deo4v85DEZQ50cU9a" + + "WEUAO/5X57P7pYb9/47abu0cdsLIWeE+O94HpZS8vz8mxRQKLj27gPY1KzzTbrZQIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECG8ILlM9oqZwMBMGA1UdIwQMMAqACAlV3mzXYPyuMA0GCSqGSIb3DQEBBQUAA4GBAF6S" + + "x3aunfgnDmo42aPOzDh536WSkTTbX9bmUNyg3IQHl/3xhVqjS76bMqreYhx5nh4VNx/Z3N" + + "LD0W75XmASCk0wtW9S1MoxzJMFIozRruaE3oykrbyMMOt0Br5CV12ofUd0WybDkXfNAIze" + + "IRgps3nORHWjV1GwXe8uNoUn6/z7"; + public static final String[] TEST_58_DATA = new String[] { + Intermediate_Certificate_1_PL_01_05_crt, + Intermediate_Certificate_2_PL_01_05_crt, + Intermediate_Certificate_3_PL_01_05_crt, + Intermediate_CRL_1_PL_01_05_crl, + Intermediate_CRL_2_PL_01_05_crl, + Intermediate_CRL_3_PL_01_05_crl, + End_Certificate_PL_01_05_crt + }; + + /* + * test59 + * + */ + + public static final String Intermediate_Certificate_1_PL_01_06_crt = + "MIICmTCCAgKgAwIBAgICAJQwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wNjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAweCAiEGMLycmodjrUMIWEEFshkvhX2r90wGl+/pU" + + "Ia9NSdT23zYzE4Uo8Is1ywyV+YfvgR22j/RXF6j8OK+XZ8jlgfjVTAhjCnTWY9LDR7qAyk" + + "8zuuITxJrYpiPoxqZs9BXLfGkDbye5VpVJXvQdbJNxgKO0hkBBDfe+T9+qw6ECAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECG1DiuoAwV6aMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" + + "CSqGSIb3DQEBBQUAA4GBAMFvtFiMDMP6n3CrqQLSzhpK5Qu0uxa56ARXIKSIqi0OUZAu9v" + + "sCXxMvaG/R5bElwi7ybYZ5KUSN+PnDmlUxWWL5Ib5RZdXgj7L83oyLTQmbDMvka6rSWHgw" + + "Jq8qHVslhh+l+YNOb4fzs8x9ctCrs/BgjX8wkORpQbigU0BUJ9sX"; + public static final String Intermediate_Certificate_2_PL_01_06_crt = + "MIICmTCCAgKgAwIBAgICAJUwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDYwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wNjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwf6Nf0+r7JvE6BO4MbDbS1T1SCzn78haBAmqGZLS" + + "Ac4xQTydvmzr9PwiWlU0xjFfKItqRMt7rfzTTPfvvnwxsAfQNPtxKzi30yCNq/VotMA7j5" + + "iQYaVe2OWVHu13agbXLEZ0pL/ZkmQ3Gvo6UhF4dRmCnjFbd5cMTxQVHUrwgyECAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECE3tS4AYmwZDMBMGA1UdIwQMMAqACG1DiuoAwV6aMA0G" + + "CSqGSIb3DQEBBQUAA4GBADcBTKbhx8PCunjRVJkcLBCcVGHs9HfkChDafwBO51fe5uhHE2" + + "QBpW3J8ZsevuFQiEZvuy2RVFktE6ZoKD8wxwBFhs+OIxe2mergQPy6jHuxoSUiPzr3CVXZ" + + "UsNxe7j3IcJLqbJ15UqGFH5yph7Sa4Ym6x747miF6W9knNkjcx3K"; + public static final String Intermediate_Certificate_3_PL_01_06_crt = + "MIICmTCCAgKgAwIBAgICAJYwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTItUEwuMDEuMDYwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wNjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwq2YlDLHX4KktKnzLCYjnk079IDgXENrkRBuZHTB" + + "IQyZoiBH4ZWHreZKs3LvznP8uSd8eEL8keNw4PwZ6aT1LF/Jr/UlrFQNnpLzQVXwGGAuzh" + + "tFJYRlOfI5cCZYAcpjnyUV4GW+MuwBdoqDycMjmqIv/8A8vupjahffcmBAassCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECB+qYFJjEkJ5MBMGA1UdIwQMMAqACE3tS4AYmwZDMA0G" + + "CSqGSIb3DQEBBQUAA4GBADiXredACtRQTV2TKgu5SDdPlczj7cZZUARJiJKiRfjmxHCc1q" + + "m/Oh7sHkqRvlHqjoX8qp4iSchoZWdOAE5O/q4Ef6rViejDFVyN2ZmlhP6KIiRxznrvYfF1" + + "n08K7CHgHWvDaumm4pNmWeF03nuasHrY0W9h1uk5poVuzaWDpx3A"; + public static final String Intermediate_CRL_1_PL_01_06_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QTC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIbUOK6gDBXpowDQYJKoZIhvcNAQEFBQADgYEAiHM1" + + "xFuYt6tDscqzwj0mLHPHULnR44/vNyPUg0KnV03Dd4XbFHz0FtwDKgVTBZ8x7ybp83ubJH" + + "tE/p8nPW5kN25WQOlYkZoAcMpEXjTzlo9evU0W3nyzJjmlT8YEI7vnmWFz/ahzy6WFwPue" + + "h862EKh2zVO4hoqZYEuDQI33fOc="; + public static final String Intermediate_CRL_2_PL_01_06_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QTC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAITe1LgBibBkMwDQYJKoZIhvcNAQEFBQADgYEAuDSF" + + "W1KOc4x41HGvdRaw/NtipD2y6zSh3mtRoo7Q6J2BvJvunymZNEziozBOiUgT8zMgbdbm4a" + + "PEwlHRaoJP8+yxJIlKaHa9Hc7Yz4SOwSrLicf7EnBSct3Mze0b48UYqbn1q+lf/zKaUGrP" + + "M6oqtE8Fam06T+WUfutU53zTtSs="; + public static final String Intermediate_CRL_3_PL_01_06_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QTC4wMS4wNhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIH6pgUmMSQnkwDQYJKoZIhvcNAQEFBQADgYEAcPfO" + + "+Rj2KmO1CxjuKLEiOUAIq5YmR4U06IcCBGMxlrdHVXHM3vepBKUlMDaT4UGcleABMPX9Iz" + + "/31ofyXlZ/fQJOoTZt0CI7SOPQE5ZkUsR3BDuUqf1+sWwBYyBHkrC95JhJkM4LfGS5K19p" + + "fp0j0bguzNCXSBRTfjSZhy80tcs="; + public static final String End_Certificate_PL_01_06_crt = + "MIICljCCAf+gAwIBAgICAJcwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTMtUEwuMDEuMDYwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNC1QTC4wMS4wNjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3asAqJcjXngEuyM/W3+TAE+Qr4JtNUdwBtmrpGlo" + + "fAvJdmXHARyiN/Zn6Si8bGI8Wz8J4Y+Ll7zLdaMU4MCZo6hwZiaQwkh9a+ZecCpLpjs4mz" + + "MSf5zHSwTYiXKMazlmnGEITVyKLmAiLSyGeeJvOJVqVo/NZXRGVlmnPxZFfgsCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAeYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECLZuS770NcDsMBMGA1UdIwQMMAqACB+qYFJjEkJ5MA0GCSqG" + + "SIb3DQEBBQUAA4GBAGM18aR2i8vSywsWhcLrRN1Xckl/HiBPNphobfKoER4NG29cFjUPQX" + + "zukjQcJl2clAXNCVtcsKCoYRP3YUyAB6At+yskuuJXtES7FIzM3rt/UpDS5ktVC3gh+jgE" + + "pPhMILYIXFzYY1hifkpagfO+mkcr7RqHU3tHAr6LCWjqrB9g"; + public static final String[] TEST_59_DATA = new String[] { + Intermediate_Certificate_1_PL_01_06_crt, + Intermediate_Certificate_2_PL_01_06_crt, + Intermediate_Certificate_3_PL_01_06_crt, + Intermediate_CRL_1_PL_01_06_crl, + Intermediate_CRL_2_PL_01_06_crl, + Intermediate_CRL_3_PL_01_06_crl, + End_Certificate_PL_01_06_crt + }; + + /* + * test60 + * + */ + + public static final String Intermediate_Certificate_1_PL_01_07_crt = + "MIICmTCCAgKgAwIBAgICAJgwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wNzCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5HkS45NLuqq9ZwF79+pTGtQnGWO7DFdetYeQTbeD" + + "sisjZMsK0sCCR5xAKYQsJSS4v/8LQUdxlQR30LMV0SQUKFMJyFsMiSsO8subb6sVINWn8A" + + "tL4zcQK0WiASUZOEkybAFJtP31PahzI5wfD1cikE1M4BlDij5WeaIjt/RTHKUCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECLSUEn5d8YywMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" + + "CSqGSIb3DQEBBQUAA4GBANLO+kEiswkGzEh4ZcF5LtfnPZlnG4gTPSNugeWJc+Xedqmttp" + + "jZ35fr1hiRe2Q1UcyTd4ThkPknawwZednbsZVPqw8u1mo7kuAeL9KrCk199vL4bV8Ag/kj" + + "HJ8TAy40UDB6hMm7l4j8mEKwV03THVrz1Vvz59CQXj+iseH6yUNO"; + public static final String Intermediate_Certificate_2_PL_01_07_crt = + "MIICmTCCAgKgAwIBAgICAJkwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDcwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wNzCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAu78gmT5HwmBHEe+K8fLLgGaPpcv13ZjrgL4twTBS" + + "OkZn5LL9GcfkPuA5WIAZkVYfCWSDPqcAGoOWUIDADfBfdcyLteUH+xI01rHKiLDVexMvU9" + + "vqCmcBKhxK3S6wraW5YhOO0bx4oPrZXVIjyG8fh4e5WTEykzvUWJ8ZbzSJ9JsCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECCT+fDEaN7GaMBMGA1UdIwQMMAqACLSUEn5d8YywMA0G" + + "CSqGSIb3DQEBBQUAA4GBANpKr98PiXAdcXlbgSgif0213H+tg3WwUNKZTw8MpqPyrN2/DZ" + + "HBi6e2KWXLTxttV9AZBRvcKwsveS6oc31eulMe8nHxRNRfadvF6dL3Tsig6HAQkartcJMI" + + "yfW4V3EhXbCdziQkre7XcR9WK5bpQoX04HWeew6YTxjG/cL9MIJR"; + public static final String Intermediate_Certificate_3_PL_01_07_crt = + "MIICmTCCAgKgAwIBAgICAJowDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTItUEwuMDEuMDcwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wNzCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr7YezMXvnkSuNCdXch2HRAEVuCqfzpVRCj6laJI9" + + "Q+NxgXwzaOwnImvwER3Hblh1l0MAt5/I/9hhqCN+918ueME50MkoM1wPbcmrRIlwWLGSVZ" + + "yBKeyPHrLbdPqVIexUlQk7PasLm/Qx4SvRGVe9IMLrEzPV3MFJtrJoWaMobQkCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECKw8JlHMvVfuMBMGA1UdIwQMMAqACCT+fDEaN7GaMA0G" + + "CSqGSIb3DQEBBQUAA4GBAA5JEDEDyqfZzTGzOoMV+8RVke+a4qgOo7rnOEdletgGFEwz8A" + + "tiMHBxR+UMxuHS82Hz3+F8XlyYIwlrG9wWVcB/tOyzgVyA28Yux9Q/meU7T6dco/AnmOdr" + + "2XL6Xm5iLnARG+PkUPHOsxuweyB/sSUSA8ZJPowNRWTik57ul/bO"; + public static final String Intermediate_Certificate_4_PL_01_07_crt = + "MIICljCCAf+gAwIBAgICAJswDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTMtUEwuMDEuMDcwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNC1QTC4wMS4wNzCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7mNS8dGz0gkXDbBRzP2ypdNMahJbM3cSMHO0hYpn" + + "uRsiXGUhIB0K4WVbnz6tr7Hch3yltK4H1Y12Lf8cXEETR2sE9lCY2A3r8/VM5OUbou5Y8k" + + "wIf03VhP7cGKonaFtlj/WD77fidDePVp1Nk28gV0T2F/l4pM5TEJrq5C9PSUcCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECJBEcZsMRq6CMBMGA1UdIwQMMAqACKw8JlHMvVfuMA0GCSqG" + + "SIb3DQEBBQUAA4GBACfbHKpuRJnZ5UU0sih8RuywhUo6Getwl/p6fsi87wYI61pvYru+hm" + + "4R4eAMZvg7MrAarS3Iu3zKBU1HKeq1i+hpwTIXrngR8eL2fU/X6GPzdte3+3tjhah38bqF" + + "zDon+N6ap4MKWRk033SsFYo1K88Mena2tGuFForJlV9DOF1l"; + public static final String Intermediate_CRL_1_PL_01_07_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QTC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAItJQSfl3xjLAwDQYJKoZIhvcNAQEFBQADgYEAJtaE" + + "I1+PCNL1/bgEVKWUIwvh58ugnWhxzbFW6hNJwNEz9/yt+FLZfNrT/Ezort4VVQFLQg7+Gj" + + "KrkIujqfRJG4LXrXAV8ZsvSPuwyQ+hM1GdHGDPhj9x6DkjFusxJYUEs5BzlX7ovpnaIPSW" + + "RPsatheSzu48pMOCmyTKE3MpuZg="; + public static final String Intermediate_CRL_2_PL_01_07_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QTC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIJP58MRo3sZowDQYJKoZIhvcNAQEFBQADgYEALiV+" + + "BFpXhgTjiMZBYLVuc/fqhHcXeXOGOmJZoKUnIXjETH3rzkkt5k4tMN00ycZVgpRwn3ZyQs" + + "cFLcW8taau1J7iQOmGY/7qIT0eFx2OlgNmxqirmwx4OM5VSH5mEpnp9NOr1rfut1GDRzw0" + + "tZ+nhD/PGDXYPu+QPX6jii0vdHo="; + public static final String Intermediate_CRL_3_PL_01_07_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QTC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIrDwmUcy9V+4wDQYJKoZIhvcNAQEFBQADgYEASY47" + + "p94jEh9FZ1TrPS82nWC3Z6ZKdaD9pUbaJpRnAId59QdBaD2Cxq+SfM3HTlz8grCAPKwulv" + + "jDDhXhp4H/m63Q/pJbyl3bbMxnphMOoDwB9wwKIUQPM5wagMovF/UYtC8MoC++m2kuZ1eb" + + "fR/OIJuQr+k/kD5Axhw/xolKPdE="; + public static final String Intermediate_CRL_4_PL_01_07_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBNC1QTC4wMS4wNxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIkERxmwxGroIwDQYJKoZIhvcNAQEFBQADgYEAMhIQ" + + "lE+BdCO6NBz+YgcH+tjP0n4OCdQ+7uxUxUYmPtPbsLwbDDEEZUjykgwiA6P47Cqh5fXB6G" + + "tfInh1cmQi3y2IEHK+bRSx321qczOh34Yx2hw5vp+JFttbQAEl/BHixklrFBrXjN0UsWGC" + + "ibXcZy0YjerWTp/yceoABz9p94U="; + public static final String End_Certificate_PL_01_07_crt = + "MIIChzCCAfCgAwIBAgICAJwwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTQtUEwuMDEuMDcwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBMLjAxLjA3MIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCdH60mBM1eInACvOB83zLrtiebq9B5UBlAAVS8" + + "9ucDwGx1HOJwhwk2AmvhN7pYuDc+BFzuNtgHojqZSDpRMA3rVsGlgOkZ3sOQzvxB73w+/X" + + "XmCYpwcEGLpK4egl8r1aOYm0Zm4OxqWhNu9+Do7nrJczDLi8k/qh8/+Rfdtvt4kwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECEmVurZ+7UXFMBMGA1UdIwQMMAqACJBEcZsMRq6CMA0GCSqGSIb3DQEBBQUAA4GBAANe" + + "AbvpAHwBu9+FlI4DOb65Z+h5f2Ok59FVbVqAj3zkMRkawppngK3CMY/1BQlGXOlHvE+CGz" + + "x/7DsiV0O3rxOUjutt00PNxCyIM2pcOZeGUaAu5DJWn0SRwzTMJa4M5K+7wh/4sSPWyxKi" + + "ueDq2VXvIgAfEVC8Lv44sxcOduSZ"; + public static final String[] TEST_60_DATA = new String[] { + Intermediate_Certificate_1_PL_01_07_crt, + Intermediate_Certificate_2_PL_01_07_crt, + Intermediate_Certificate_3_PL_01_07_crt, + Intermediate_Certificate_4_PL_01_07_crt, + Intermediate_CRL_1_PL_01_07_crl, + Intermediate_CRL_2_PL_01_07_crl, + Intermediate_CRL_3_PL_01_07_crl, + Intermediate_CRL_4_PL_01_07_crl, + End_Certificate_PL_01_07_crt + }; + + /* + * test61 + * + */ + + public static final String Intermediate_Certificate_1_PL_01_08_crt = + "MIICmTCCAgKgAwIBAgICAJ0wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wODCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsr+i9HxgO6LnOa6xOHfe9BeLVTo4iZd8rp6UTc02" + + "C0MmsSjvIgn3UiayU7aoHcTH8tAXSV5bn0CIH4B46qLym//oE69hUFImy6d1kKgNoaUKWB" + + "HztKVtswSSPjIUf7pbyp0wasYMN6fIKYyLpLXUxzA2DrD0kP2Y8ElQJKl2HocCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECPMW3WMPtaowMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" + + "CSqGSIb3DQEBBQUAA4GBAH2N6S9ggfmRJkzhs82uOPXaHF62YEg1pbNxaCyJJbSt2iIIyy" + + "NPSlE1OufPPH3pO7p5xcYi90LCI//0tlUL8y7aULFNygbshFY3B8MSgCz3KPA3UKdtIZYe" + + "7lqP9/ob5wmkjtLpx6oZ4/38jxqe37pH1IwVjaUnoeElSo3EkCI5"; + public static final String Intermediate_Certificate_2_PL_01_08_crt = + "MIICmTCCAgKgAwIBAgICAJ4wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDgwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wODCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqZZolrig33i1rEwdP1pin8a5PgzSk7fT+qhrJRCg" + + "UTOW5WyPtakrLTUipDcR07t8tIe0NsjRoph7+fAwbjWBfbJdydndHHGx5BqWg8Xi4zFhFd" + + "6Mc5O6KO7Yqxs8lmthv/RAdL4Eiir9d9hqskKOtQKbLWz+Bz3+9NwfLGzwzPcCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECFjxM3RkbbhNMBMGA1UdIwQMMAqACPMW3WMPtaowMA0G" + + "CSqGSIb3DQEBBQUAA4GBAJOJKBubTS/kLnfXN5YbQfggxbO2c7DTxx2LhrnPiyVDEow+Xf" + + "lMv4YK5olH6UUm02D8cv6Wxg4NeTtBBnwKQG/GV4Ssgc/rrpEzM7jFRQcUzPu0jfya2fX8" + + "ZNBnSDjovlN6vmZHtiksjh66h3a0aVusEuOQXD29ogMR8qAGYQaZ"; + public static final String Intermediate_Certificate_3_PL_01_08_crt = + "MIICmTCCAgKgAwIBAgICAJ8wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTItUEwuMDEuMDgwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wODCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAogLtEcWxzzkkIYe+KrwKhaQjjGQqy2KDsW00U5lx" + + "+XJoT8eKd5pxFdCa0SPn/jkNILVeh07mIHec1WF8SOeveVT4Ewd3nG/6ZGoVVq6l0j+3RM" + + "jpJbp26BPR69nFn6rmFUMoSNq0VG8Zl+UBqnjq83G3umJCJMMRekUTULSFEGUCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECGAFYeJIhrRzMBMGA1UdIwQMMAqACFjxM3RkbbhNMA0G" + + "CSqGSIb3DQEBBQUAA4GBABHamiW7sPLQ83nXt3LZemcAp4QaDB8X94EuJGBwshEcKLoOHb" + + "/3cZkPRbOiRQUh/YdpfyApndGFSi0DtwM2Z7yup+MzdrR0wzQoNS95A51nHE7XdCuVFemc" + + "LTJ5rdd2BLK3OB5lQagVLzAY9Bs1vaeXKT2Cy+gSUkTIekWcsH3K"; + public static final String Intermediate_Certificate_4_PL_01_08_crt = + "MIICljCCAf+gAwIBAgICAKAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTMtUEwuMDEuMDgwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNC1QTC4wMS4wODCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxVjjKlLlZzeZhamPO2NDnRtWM1oWZ3/kdwdBRn50" + + "o1NRXb60Ir2HjniK1dRdbijAvR5uItLe9tmj4nusBiaPUGM0HNlEdQWSzble8rvUsP0apw" + + "uJusV7zLvzwwbgLbMYT+8lMhxWXM34xszP+dgjWASQOVao1Uqs/MLLibOuueUCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECFMFrvh2hQ18MBMGA1UdIwQMMAqACGAFYeJIhrRzMA0GCSqG" + + "SIb3DQEBBQUAA4GBAFsCOJ4DzuMOKti5PvF71ZKOtcTHSv123ZNdPIbK6OatT9YhVuUOYB" + + "AjMavggywrb+QOXOFfJMctQlS3y/JE9YyoNNt/4UTdx1jQ3I2ablonmzjt8eN5GJ9jUXth" + + "fHjxnmGUeWlAvwMjEdzdigkyuWCi9LJfjyHtTjSf9n7w2rU+"; + public static final String Intermediate_CRL_1_PL_01_08_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QTC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI8xbdYw+1qjAwDQYJKoZIhvcNAQEFBQADgYEAG2Aq" + + "R1oelnrTgh56m6Mm+Lsm0Sf+Ot1W7LzZmMDwoZgmGLcTduVktx+XrtiDDWsf58hmneT1q0" + + "5wl4yNH8y/VCAA3SM/gOq4ddOEiS8GbuEYo5P/julH/U3g6M0vfPUZ5y+7V0s35jIbTkjX" + + "76n3Rhf88nvTscYvMdqrYyUhAmg="; + public static final String Intermediate_CRL_2_PL_01_08_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QTC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIWPEzdGRtuE0wDQYJKoZIhvcNAQEFBQADgYEAX/+I" + + "DkAx7PLTi2x6aYbLacPRaUSjMne84MDaEkYiA64Vo3eL6FbKe14z2mBsM2W7x8xDnxjZ0N" + + "RbhcFZ2E6A1ct6HMunuKxjoROIsdWhrYMqJfKKMTWMviz1UjtupsGUWS0dVQCquAr6DJmr" + + "W88P8wgiVH2VZsc+edDmCGDunrI="; + public static final String Intermediate_CRL_3_PL_01_08_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QTC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIYAVh4kiGtHMwDQYJKoZIhvcNAQEFBQADgYEASw1+" + + "6rGDKgpUtXcCziQCjy8mHFD2zV6x/Ppxm2Gj0U+5eFnIbMPmr4TUYwfSOROUycsiJX/Wa8" + + "HEuqWJhIdcsHMA7TYf0iSXK597Bljjg4F/1Rgz0wqLjgMuA59eFbKjJ6zP1E6Sv2Ck0Ea9" + + "HJsv5zFA1ljVnNWoQwoHsuLk/wk="; + public static final String Intermediate_CRL_4_PL_01_08_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBNC1QTC4wMS4wOBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIUwWu+HaFDXwwDQYJKoZIhvcNAQEFBQADgYEAHHKd" + + "U1SccTsK99BUDrvF930ejNRAvHQM9xv80wcUAy18x+TLwBH8vDTmP210/C5Zk9pQs+rLDd" + + "doQQbWJrQkznyB1OSK0T41KZ9L0UE+YmFGJjz0PEzYHV0Kc57j5uc7Fsi8Xu20Y8JeTaJs" + + "FUXVsvnCuoSxYmwY1futFWHJG7Q="; + public static final String End_Certificate_PL_01_08_crt = + "MIICljCCAf+gAwIBAgICAKEwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTQtUEwuMDEuMDgwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNS1QTC4wMS4wODCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwgNkhQrcqmjhkES6DNAW3uQLKILcFlrFvOlWfDPo" + + "ngXzCKeed85npqL+Enxo4sLarEiywuDLrDgPf0gKnZXQWBmzWViZhvTsiAemH7iNsNS68s" + + "hhb0vnLzlPpDUJDv7KVKW8VbM7nvplKptlEE6g5kmj3iEmM4l2u8Z/pmQoTsMCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAeYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECLfApJ09y/ZNMBMGA1UdIwQMMAqACFMFrvh2hQ18MA0GCSqG" + + "SIb3DQEBBQUAA4GBAG2ANLc/ib9ayz0B0L6/XQf/xuwETEq8kb5vWml/PbcFD1b/uwRHI8" + + "vTvM559nZgtzkhS5ZAvNBTh1CB9Ox/nugHc4srbH6/Wcd94pMQx/sfCB/C6zZ5Tbm7Y4jp" + + "hkjnxwGUYTvgNzxmaAPLyCfqY7KwhCSzns2M+yuncEKqlzuT"; + public static final String[] TEST_61_DATA = new String[] { + Intermediate_Certificate_1_PL_01_08_crt, + Intermediate_Certificate_2_PL_01_08_crt, + Intermediate_Certificate_3_PL_01_08_crt, + Intermediate_Certificate_4_PL_01_08_crt, + Intermediate_CRL_1_PL_01_08_crl, + Intermediate_CRL_2_PL_01_08_crl, + Intermediate_CRL_3_PL_01_08_crl, + Intermediate_CRL_4_PL_01_08_crl, + End_Certificate_PL_01_08_crt + }; + + /* + * test62 + * + */ + + public static final String Intermediate_Certificate_1_PL_01_09_crt = + "MIICmTCCAgKgAwIBAgICAKIwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4wOTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4slldx8rhfz5l2i0rwib2McrCyQkadTjJRoEGQCV" + + "xT0dmw7GhDa6wJg2ozXLLk5y7ZCwlmBOTEoNbigHvcKSnJT8R/S+F4KqBz5d5dbRMNEKYz" + + "jdbD7Sm7id+eyfq1s5cpmta2lBJ5gTaC9YPSOY2mucGcJ1muYzdOc6h+PCCNMCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECO7tq4dJC8OgMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" + + "CSqGSIb3DQEBBQUAA4GBAHbth0HjAygIoWVrz59ZBPntOn5nzgUGpH60aSDOS6i9ZOKSoC" + + "7wCOEt6IpKO7M7SNznxaX2uhFTYotneyq3qENvqZVXKhE6wQRsdK4kG10cxSB5AXPHJRgk" + + "W9+p+Nb0iYVKwHdDCW8KHYIroGhSkKxuflwxhK6DcwQuA7y5q7r7"; + public static final String Intermediate_Certificate_2_PL_01_09_crt = + "MIICmTCCAgKgAwIBAgICAKMwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUEwuMDEuMDkwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4wOTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA70v7BFxmToZHF5M29JK6N0Ha6n729cv1U912mH9O" + + "NTz9tafa+jv4W7njScv21CJbNlUO5rlAFcTlXY0U9vbqHEufhtwRQqi7+pkfa+Ig8bwl26" + + "4U8L5rgmSvZJpEiiKfkmF2Rz9+zPPhHjk58ZcKoAcyhOdZ60KqmaaU/TVtEq8CAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECKOwR13+P/BlMBMGA1UdIwQMMAqACO7tq4dJC8OgMA0G" + + "CSqGSIb3DQEBBQUAA4GBAN71oLHr0+uf6zCOC5L7oeCOGMUwvZyROu8eTztZrPYGjaamSm" + + "Z0ZmUPOJP3g5nO6tHf34Tb9CTkwPdPicEaXuxflkSbJBV3mUFQ1BUDlyYTuaL8uT2N61dg" + + "xt5RgYTIGsW3/2XrRvXsH91gSiEkccoUyjKnQcX3oZmEeITb6H8m"; + public static final String Intermediate_Certificate_3_PL_01_09_crt = + "MIICmTCCAgKgAwIBAgICAKQwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTItUEwuMDEuMDkwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4wOTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAwMLmDs63ai7i4xC/1ufMFWeigJAlbKWMti/PeEKi" + + "7LBfNJDRaO+1kde6QIo1vhkhKtokNu9ue3Rfo1+xGuZVohjRbHnmamEm5G3jihegPQgGCR" + + "fDZoJDI9HMbwBa0RWw1Nes5igIVjdSHQKO/XTul1yyF2Dt03K2qeLwes+2FyECAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECPEAjG80q0FoMBMGA1UdIwQMMAqACKOwR13+P/BlMA0G" + + "CSqGSIb3DQEBBQUAA4GBAN9eiZXma2n0XgzdvYrlV/IEqBIhpcZ7gycjDumVBVITZJD2sJ" + + "bkBi+N8dg7uovgxGxWGsyxqgAboLhMgbpbFzGh+HyIhQu/CeAx93PWYc5rP2l2Y8d7KJvk" + + "p1GZEcG/nTakpjxTQ5MQYFsOHVsnDDOyaZYvqPuMrwGYsfoUa1wq"; + public static final String Intermediate_Certificate_4_PL_01_09_crt = + "MIICljCCAf+gAwIBAgICAKUwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTMtUEwuMDEuMDkwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNC1QTC4wMS4wOTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAo4L9QEqzq2VXzkZI3cvUWR5v6vreKKQPfJPfEwNH" + + "nMS0cgDjC4Fnw9ySI7Eb4A/OJGLIyg84mzTl6JX3kGoYr9/bJ8jOD7pN6CljXuHpwwmd7L" + + "6Nf5Hy0ltjAIr5s67e33OWdPi4gApS4FN6nPSDkZotY73d1xqJYQQZWuNEsGUCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECLfU7BuxzXeCMBMGA1UdIwQMMAqACPEAjG80q0FoMA0GCSqG" + + "SIb3DQEBBQUAA4GBABmQZOvwRpVsTD8uazfQpLJUZkuTap4OOPHie5xJsvOhGend2k+LiP" + + "7btGoFrqmkyVV/+dNA8+45SRsnoOtgctiF2ubeqIvd7xf/J5C9Cmo+T89Mt7WEBEuDmEZm" + + "JPXvOvyh6lRcYVSBnvVW5ZSstNAQKa/8xuyN0OrE1hJWbucn"; + public static final String Intermediate_CRL_1_PL_01_09_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QTC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI7u2rh0kLw6AwDQYJKoZIhvcNAQEFBQADgYEAbXc1" + + "QgR2TAvOPqJmRFFrDQkPVIVyEEDTwZy5aNnoAKK+AmJ5FZkBtbPJ8qt9UeYRh8lbX8+EIk" + + "tyrAKw/1Kc3h7RDqAQ/p8t8kFwVQh2l4KTIukV8hYcj5sMKlt5f49ZwzWPyoOaLDomiUfI" + + "OY/jaDMw293AjQXxGCDtnaTvh0o="; + public static final String Intermediate_CRL_2_PL_01_09_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QTC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIo7BHXf4/8GUwDQYJKoZIhvcNAQEFBQADgYEAq6en" + + "XtvIdh/DifGzWn11hqJIZxLQDGJZPoMmwSOLyB6OzsPrIg1xkOWZYEOELTR8+qP6emmx+D" + + "CaEbUDLj60rso0gRQCBwTgHgjeMRpv8fGnV8MJgMv5BdzsGAGQbLSSY9FxtqeCPfZ6olHC" + + "iUIopdZJZP8ZvGKQ6QGaMnLpJ78="; + public static final String Intermediate_CRL_3_PL_01_09_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QTC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAI8QCMbzSrQWgwDQYJKoZIhvcNAQEFBQADgYEAraCx" + + "ruxopFbKvxOx/CIF4niG27ABB2ZwU6n4NBGYHo1Y9NjuytjjMZvQjMHyoayqpnF5TA1vXL" + + "jXjI3VgQcK7A4ah/0FNLFGtczyY8kXXrpbmdg8+xdNJEG3/e5rDW5VSf7OY1XqU85ySUJQ" + + "ZR5uiy8LxlDdaIT4WT7X5ezs3wk="; + public static final String Intermediate_CRL_4_PL_01_09_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBNC1QTC4wMS4wORcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIt9TsG7HNd4IwDQYJKoZIhvcNAQEFBQADgYEATtjA" + + "BdSZYnIbv1bCL+aSiioJg9S9yWGD1mjsA/CDzvkzSffeSpvqaSy+Zwwf+NDMMG6Cs+SgU+" + + "sxQdJALAbb4sYGEyXj/Exh9BYHvgoVahH4NWuhm6LIN8RTcMDAtGoGYFNGXGuT8XRBUJZ/" + + "tH9re3gpWaE1rjWeB/2ZBR5ONcM="; + public static final String End_Certificate_PL_01_09_crt = + "MIIChzCCAfCgAwIBAgICAKYwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTQtUEwuMDEuMDkwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVBMLjAxLjA5MIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+g1Puqjn+/Of35mqVVUricIV5x+bpZRCAgBDh" + + "VYcmZFXLB/XnRd/mYTu0RR4ISEerC1km5tjGeCN2k3NGdZwz/wEh9kEL8WikSqpxUSUD/N" + + "vQbliz4f3YECLcpNXKzkCvszeB5ZGHa0sLYDg3r62wy+1y2rtcrHzFEoMFgnnruwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECANGcL2klYf7MBMGA1UdIwQMMAqACLfU7BuxzXeCMA0GCSqGSIb3DQEBBQUAA4GBAHm+" + + "/vQ7VxDry3VqiqKnNoOhAHTTIUphNWF4jddRqVc32IsjVaeTbcGwCIRflRm/lUplRvXXxb" + + "JEbW9mP3nfTCREUdm49hjmo/szsPjgosFoEmuEKXThC81/y2vQkb4/jqRoOHEknU++38EU" + + "Juv6Y6psZNa37x8Yn3i7S+b3TM2q"; + public static final String[] TEST_62_DATA = new String[] { + Intermediate_Certificate_1_PL_01_09_crt, + Intermediate_Certificate_2_PL_01_09_crt, + Intermediate_Certificate_3_PL_01_09_crt, + Intermediate_Certificate_4_PL_01_09_crt, + Intermediate_CRL_1_PL_01_09_crl, + Intermediate_CRL_2_PL_01_09_crl, + Intermediate_CRL_3_PL_01_09_crl, + Intermediate_CRL_4_PL_01_09_crl, + End_Certificate_PL_01_09_crt + }; + + /* + * test63 + * + */ + + public static final String Intermediate_Certificate_1_PL_01_10_crt = + "MIICmTCCAgKgAwIBAgICAKcwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1QTC4wMS4xMDCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAr4LmuvhSms70CnuAHIHwz45csKvBPVtcDjA1tWNb" + + "NIvvNHBzyt6G8U4CTVKmsFAZOzrWJem3b/ZywM1WlDarGJAAa/SRIYZ/jQwaOIoPW4OUfK" + + "ZQI6MO7uAPcIQ4ugtPth10viVqZYLZn/6O26Q905YsFltuPFl64KrJVJJBlLECAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBBjAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECGRn9ckrcsEdMBMGA1UdIwQMMAqACKua6/nC51SPMA0G" + + "CSqGSIb3DQEBBQUAA4GBANK+1qalm7Nl+PJHT9nQLVJ3ruQNAoMlH9fN52Q9BZCr30iWCd" + + "+GhQIPRjxZ4GWojMnqbWzYQsxIR2PLdFc6SwjQrq+i2ES/LePDtaLQddS44/+GP/+qDpM9" + + "Mqp3/Nbe1MfOKRBT57qgrxa8eUVieysoKeYX6yQpa8bab3qDwOTH"; + public static final String Intermediate_Certificate_2_PL_01_10_crt = + "MIICmTCCAgKgAwIBAgICAKgwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUEwuMDEuMTAwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1QTC4wMS4xMDCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAx5tMLJ3LRxi9jAzCSNkj8zyrSO0cImNGf6ZCIzEU" + + "V8LrmXjgiZboPTh9LWQ3msWDLpzaxVxDLBXG3eMO8ys46TfJKciyeoiB8wfuNGMKAccm8u" + + "43XjWs1KAdNikWEZupYPgdmA92oRlVcHshG9PqP4+xA6sydpu3V18Nyfa0n3MCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECDE3dDXkS7TxMBMGA1UdIwQMMAqACGRn9ckrcsEdMA0G" + + "CSqGSIb3DQEBBQUAA4GBAE+8cyOUQ7y4atc4BlZNZvGNRZ63dbGDCM2AItTEAf4ETM9v7j" + + "biUWTirJyoWsGxm2eIUk1V+EKxcuO3FotFUe7lS6thmVd6OYOSW+02RXMNklmptzK9I3AK" + + "DZNh82ugLNyrrd06BSiED+0MoGVVI4gi3wdFtRiai+MgQVeWIB4i"; + public static final String Intermediate_Certificate_3_PL_01_10_crt = + "MIICmTCCAgKgAwIBAgICAKkwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTItUEwuMDEuMTAwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMy1QTC4wMS4xMDCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsmSUL/UZBYMdqU0PecjCd+9U+1Ld3mKkH303Fido" + + "K6k5S4ZObxVHKhYDJyp3CcVT2+nENjzIfQQQaA11UK7Uf/jmVs0IC8e2scWzq0W2BeOLef" + + "jVgNgXGsXyfLi9T4KJPPyGsKlIU2R2xKxgHmAOt/tw6OYX/OaEfM1jiQza5lkCAwEAAaNm" + + "MGQwEgYDVR0TAQH/BAgwBgEB/wIBATAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBg" + + "lghkgBZQMBMAEwEQYDVR0OBAoECHYI07i4owpIMBMGA1UdIwQMMAqACDE3dDXkS7TxMA0G" + + "CSqGSIb3DQEBBQUAA4GBAK23Kx99Y9HtFBVnHWW/NfvNro7I5Wx/ZCko6ulHm84FPAjhnL" + + "tvc4jmfAZd0wYPKQKWwUKUDWNEwIU1qkxyJYACckue35GLzj8aLY/z+h037vGonFmNutMM" + + "rcRdiV7gVD17dYLVTt0RgxsDVDtut+twqHgIaKtKyJnl9dSgFFv1"; + public static final String Intermediate_Certificate_4_PL_01_10_crt = + "MIICljCCAf+gAwIBAgICAKowDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTMtUEwuMDEuMTAwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNC1QTC4wMS4xMDCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEArgBnLCnqI6Sa7gXkZOvIKH4EL5i3CoG6eGG2R8aA" + + "kjBs78IKGYj9gY7rRajAKSpf19zvfcW8+2gBDDj5AoCy6uDnBICmqdu+hkdokVi8dJHiTU" + + "9LdS2TeuvFv47eiXoEBjMEAquCuSyHvW3lNrA+ESTnK3s7V4lBoO+o5mZD6dsCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECLTgYziQC9zmMBMGA1UdIwQMMAqACHYI07i4owpIMA0GCSqG" + + "SIb3DQEBBQUAA4GBAEx8wgBjBglU98rocddKAEKXkt4MNzrpUMq75C9HtnuOtFgM2oY/OC" + + "x67aZSTEph9ag6Hc+MyxWB5rzGD9j0y7OLsasE9AX8vjplUq50wq1xAFkGi1GnqRK/Oe7D" + + "S6R66+UFHW/3KAeNe96aaJuMcx0TRbfkGbW1ASSi/ixMd9Gi"; + public static final String Intermediate_CRL_1_PL_01_10_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1QTC4wMS4xMBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIZGf1yStywR0wDQYJKoZIhvcNAQEFBQADgYEAjkY5" + + "nXjLst8CMz0fyEM7Ft2d9TOOJXV4TMAfSAP9QCnit8qzrdVdJ6TJIsJNZYBz9Ryr5K/iSw" + + "KbYk0g6y/pskcMoHG3vJwNAxBbkf+fV7Eyve+90Z6oWDXHKLGCQQpdZ0a0wAqYeiScok8+" + + "YHypEVLfbjWARR9fsci2Ps3tdvA="; + public static final String Intermediate_CRL_2_PL_01_10_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1QTC4wMS4xMBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIMTd0NeRLtPEwDQYJKoZIhvcNAQEFBQADgYEAdpTU" + + "xcywBjX2rD8Gu6zkDqlDmZfRXHDPtnf2RB4bHDx77kDEib6nH6DGoJdx8WnRTZsTjly3MG" + + "62LfVmjp/bJyKHUQqBDrilv21EWsaI9JOr673Nk5iTZa/645GdgyLzSmxvcVDN40BAH0py" + + "/2gvBQTPNzp2W1IR2mebuLdHwTI="; + public static final String Intermediate_CRL_3_PL_01_10_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMy1QTC4wMS4xMBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIdgjTuLijCkgwDQYJKoZIhvcNAQEFBQADgYEATVf2" + + "cEEGphsIe0AsqNJ5rENLe8DeDAV8R4XCKdeP5qmHmLMm9Z4pX8bIfU7bCoXiNIwGvIU6ag" + + "FmHPNHEj70cQFVqCX/ZESc02hit+Os9g7pcl7s9QgwVUCMZdCiF/+pSEp3eCL5tFoKmAZe" + + "nxkL0KOSuKmBzuqRtZufbhDvmbw="; + public static final String Intermediate_CRL_4_PL_01_10_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBNC1QTC4wMS4xMBcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAItOBjOJAL3OYwDQYJKoZIhvcNAQEFBQADgYEAbG2B" + + "BhvRQ1pY/8VFeiCRFD8mBzq5iW5hWv2P7Zdp9zEbQo0fI4Kbis3OGemEttCxvAc/UPfogr" + + "UudImf3s8sLV9BS59xQUGQlxZ5XBNlripY8EjHNWrwgy7/x4hzlZ9yYBbqoNOqnHLy/gbM" + + "XZWoCbIK0co70lh1soOQ6eqLDKM="; + public static final String End_Certificate_PL_01_10_crt = + "MIICljCCAf+gAwIBAgICAKswDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTQtUEwuMDEuMTAwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBNS1QTC4wMS4xMDCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3bx0qx8s4Zse6Ri6NqkLEKUPLIOhTFj/9Dh7sxvE" + + "HpemBlTjbp2in08WTxEb9n8iAIWuGs3Vqm82ttBQmayjIaWD5oE/BE0oV/e91NAv/aRLsl" + + "f7VtOb6vi8Ef6muOAjI2dUaUD6QONkqkJhnZ353uR3LZnsAEAW+InePGFNEGkCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAeYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECIokB8m8Vi4QMBMGA1UdIwQMMAqACLTgYziQC9zmMA0GCSqG" + + "SIb3DQEBBQUAA4GBAKBGQwZQLQFXb+/kjP5xAtq+1rRtrblytjpv3ujJrKH1v2VB2+9boB" + + "0YYYGJTy2Wuj0ZBEMeTzMO8Hol4Mq9pnYv5DCmfnZN3FuDidgnRsCjM3ZL7NcXXG9YwlKF" + + "G2SXj0YfkSwN9gnyN11W8i+F/OSjlm+TDKHB3ePMcY8EnnXy"; + public static final String[] TEST_63_DATA = new String[] { + Intermediate_Certificate_1_PL_01_10_crt, + Intermediate_Certificate_2_PL_01_10_crt, + Intermediate_Certificate_3_PL_01_10_crt, + Intermediate_Certificate_4_PL_01_10_crt, + Intermediate_CRL_1_PL_01_10_crl, + Intermediate_CRL_2_PL_01_10_crl, + Intermediate_CRL_3_PL_01_10_crl, + Intermediate_CRL_4_PL_01_10_crl, + End_Certificate_PL_01_10_crt + }; + + /* + * test64 + * + */ + + public static final String Intermediate_Certificate_RL_02_01_crt = + "MIICljCCAf+gAwIBAgICAKwwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wMi4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA3AN+Y3Hl/9V0nKXHQotb/cA2VfZc5vrRu+ZjwKgK" + + "6KasGegAorKSTybYX/fTbnaPwykDPfSscAnzAW5WdF9+wTLmvYc+6pkcx1ryKkGmofFMXi" + + "bZ5LUO/oK0iuNjBKfLdWoi+hpciKyPb9Bs8SO/svKSNqTEbn9ts3q6tpbngoECAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECGXQ07qiAqv2MBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBADKtN3OOaRdte0X4xLC6nTGaK/u7IEKQ0DjduDHwJR5w27zefrx48Z" + + "dlq8t5lAfQJqWmfk7iCIW1QJPLcZOouWDP2S9Cb0YooGQRIEkMjpBn3Xufx0XUphtCDs3W" + + "9LAMVXqfuce1tpZ6Dvrh6/H2X8rJMU29Czsz949bh6tcsHJi"; + public static final String Intermediate_CRL_RL_02_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIZdDTuqICq/YwDQYJKoZIhvcNAQEFBQADgYEAxrDH" + + "zKno1mkJqPTub0c9To6jC3CGTilV1E12oD0kFjkXqL40+W251qQ2wMC+G7ZrzBIc5dRuJ9" + + "3feHZ7cc03/s3TziXDvSyfNOYpHzkPwT48HuSgBYgJ3uswwk+tDiA64NzbOJqssxxhFRok" + + "9OpwC8eQkzgpA3a6816v2I3XL9s="; + public static final String End_Certificate_RL_02_01_crt = + "MIIChzCCAfCgAwIBAgICAK0wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDIuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjAyLjAxMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCykRGcIKuxia47yRmJT8XpNNi2LTTbUUTteIBp" + + "DZBfz2ExeWLruO9Rn1/oB/EP+4apx4r9rQ2tGsvr/7qQYeQK8W7eJzZgvxFadY57IMfUNq" + + "1nEnj0ZvuWrOSf+K9v6FWX5Y2uyZS5Uvb1VVQv0Ev890+yXTtthPTjepk3JkkouwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECFIkVrx7NRAdMBMGA1UdIwQMMAqACGXQ07qiAqv2MA0GCSqGSIb3DQEBBQUAA4GBAI+B" + + "T6bFZruoeFHXsYVjkQ42jSdYB9JuQkG7JLKte5gGlhyR+jMlJBzxBgNIfvlmYSnbRFPbE8" + + "eqsGm90hJJoUuVMkm0i03H13uddlS494O6HhTGpaKcYwp3hbLhVcaY3wFTqTCuZk1T7Oxq" + + "ggTrCDYvNH+/ZpQuy6nB/FH3SAHS"; + public static final String[] TEST_64_DATA = new String[] { + Intermediate_Certificate_RL_02_01_crt, + Intermediate_CRL_RL_02_01_crl, + End_Certificate_RL_02_01_crt + }; + + /* + * test65 + * + */ + + public static final String Intermediate_Certificate_1_RL_03_01_crt = + "MIICljCCAf+gAwIBAgICAK4wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wMy4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsZG8wsV3Kuo+jtnKxLYGBuAqQwUh6Cs7ioDTNUFI" + + "UDDJ0lOP1HVTMBA7DEcyTCGvnQ02dEVVuCddBTQvG5RvW7G7cCEW37cS56/3yPsU1bD/cp" + + "3C1pPJpoun04va91Sxtgcmx7jnz69QPVrucu6aI1sZyeOlvzb8K7DceaAfR98CAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECMNzJ3SpyOLxMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBABo7oKmQilgji3w1tGz1cMrWxZxqGJqOAKcHywli+oxFo2oxSfEuFS" + + "tN2aEd2Ja5HU5a0ySztvByXF1TTNurGez7ARxmcS2kpoQtQXTloywza4A5N7iQwk0yyo/E" + + "J4lrXUfVRwZHr7FwA7qMODtFb0+Zivv9JLaq19GhnRhzZyWp"; + public static final String Intermediate_Certificate_2_RL_03_01_crt = + "MIICljCCAf+gAwIBAgICAK8wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1STC4wMy4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAt7yNq1QZsV3p7OR8rgPuY7x7Bvs+nPhcLR7zFOgR" + + "+plQUwpWQ2PhuzReVV4jNasKtNK9MIWoeV+eV3pEiso5obb9+Byvha1F6gkYNZMPs9Iv86" + + "cJSMtownNJVGVAL9FEpof1QKLp7kfn08EjkoGmGy85xy9uFytd2S8n5TlrBqcCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECAVwoCPFqMtqMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBAL9GufFieduzBJaMtsXtKHMf64O/KAGLSh1YDXS+a7Ku+EFw+WteKU" + + "Ob6+c1m7VH9P711eATQoACotCdKusPECqeYDEmT9keqA4f7cP4VcvGwhvSVQJsPuB3LL3S" + + "LIILE4zhT+O9G+5v+mkG/pEDirRYk6ZkdM91bsUuzsX40uyn"; + public static final String Intermediate_CRL_RL_03_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1STC4wMy4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIBXCgI8Woy2owDQYJKoZIhvcNAQEFBQADgYEAkwyA" + + "I1rrz6tOmEpBHDzuJfqY2nbXCIXFN6dVuaKNZWHJ4ZNIc4/t29Wa5GgXYrVXyXRcXP/u5k" + + "NEhOX2/NwCm6vL8+tclYP5qPLrh/Dk4v3nvcTFLKCvclAbf4Il0zfMQx+RRnO5PPqPDu5i" + + "1tHHwOtA8Q+oO71lZEwPE+pX1Sc="; + public static final String End_Certificate_RL_03_01_crt = + "MIIChzCCAfCgAwIBAgICALAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDMuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjAzLjAxMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPGLfi8/T5p63cbGE98mqO5VzkeI1r2/2TLgvY" + + "RpL1h8i+CVYKoX37yYwNXf+HkHhj1OXJSNrm7853ctmDf2h1fv3f1+qJLg4VRVzlEgErNq" + + "74OR7XLXV77kGOmhip2g5BF5VKeqAdj0pCo1E5ZFHpRPFq/0DDmSda6GKJ6Dl8hwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECOHM3uWxFmcrMBMGA1UdIwQMMAqACMNzJ3SpyOLxMA0GCSqGSIb3DQEBBQUAA4GBAFBu" + + "doX0TZK/yoUcrSkP8AtFiv5c7QvyEtigFZTT+lbW/g4RX/oJGNZCu78yAxCczl+Z6ft+0V" + + "wInwahjyyAgw4QXxtw3b9CfqvT7HH7hcQ6r9ZA/NA9XpzNtxKfmXjzCZWdfmLJrd8KCnU/" + + "utKRAObRBKiaTGa178SEWvtkoIXd"; + public static final String[] TEST_65_DATA = new String[] { + Intermediate_Certificate_1_RL_03_01_crt, + Intermediate_Certificate_2_RL_03_01_crt, + Intermediate_CRL_RL_03_01_crl, + End_Certificate_RL_03_01_crt + }; + + /* + * test66 + * + */ + + public static final String Intermediate_Certificate_RL_03_02_crt = + "MIICljCCAf+gAwIBAgICALEwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wMy4wMjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAvoTuc2LYBOhziBe02f6F8l9MwX74O1lknBcJjGvq" + + "JcirQx/6hQgBQT4hz4RRXNy7DSBr3swEw4eDNSeyd6kvG0h9oI3+SVmVyPPVi5eKDL1roI" + + "OBzmfx1+Nn/CnwOf8VroKDutBBQ0gJ24IEjwp6er/8hEAVN/yIjIi/MTFeoRkCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECKtCUOlmMPu6MBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBAI9x8O/JgJuZV/s4OBUy3AvcW9QP3HWWBQSdxUdjSosT2schjn7wrR" + + "gttL7vWjT1djsbATAHa5C3inG+VjGIq/NqWaPoHAucRNMs4oZX2ACZFuBLOb/qhywsKh5+" + + "bjv4QgtqkUedzEratY6yQiJSiMSJVJSMzHosTVMX7oOp+cll"; + public static final String Intermediate_CRL_RL_03_02_crl = + "MIIBcDCB2gIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAjMCECAg" + + "CyFw05OTAxMDExMjAwMDBaMAwwCgYDVR0VBAMKAQGgIzAhMAoGA1UdFAQDAgEBMBMGA1Ud" + + "IwQMMAqACKtCUOlmMPu6MA0GCSqGSIb3DQEBBQUAA4GBAAEZ0Hg6sKiVXIeK6zbQrKtMMz" + + "Vz2K68+SqN1LAjlNW6u+HSTlAvhRIFO1Hv5Zj7qbO226rLxas/X2XWXpMlm84NHN8T4dZU" + + "4Yo5rhhpCHckRxNYn3AFcfcV4ra1rrTtdx8e7e7/m0Ghog9Ny52ZuQThasL9caF0JxUx6d" + + "zbBHPm"; + public static final String End_Certificate_RL_03_02_crt = + "MIIChzCCAfCgAwIBAgICALIwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDMuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjAzLjAyMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDNb6HGPRDulLMCCyCq6w2X8rHPtm1gN68JXFkX" + + "j/BZsHhu29Z9hXj76hO//7O775EPVMSLyRy8t15yzYpXfZRHFaGB5bs8U2R5ClvsD2FR0H" + + "t0JVfU6Ggn1lhO+jOiguJtXVRjofsfvHuiOe75ctaJ9lBpgwiV8tk4VRKz2e5xVwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECI3Gy0TgXMrwMBMGA1UdIwQMMAqACKtCUOlmMPu6MA0GCSqGSIb3DQEBBQUAA4GBAISQ" + + "Qh9+7D6nk3FL5YQOzyZ0BSHQYjpbIVykJ+Lr4jBPKyGgCqW6jqWNg7X4waB77J2z/OkavY" + + "A6qtpsk8r2wmG9thi8JyZZNhYMxAszHzFbBmSoxGRMvI0XarxgIu8Ky6V7jKVDLz12C3o9" + + "H0yd+nZXilCD+p9BTjjg5bGUogJS"; + public static final String[] TEST_66_DATA = new String[] { + Intermediate_Certificate_RL_03_02_crt, + Intermediate_CRL_RL_03_02_crl, + End_Certificate_RL_03_02_crt + }; + + /* + * test67 + * + */ + + public static final String Intermediate_Certificate_RL_03_03_crt = + "MIICljCCAf+gAwIBAgICALMwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wMy4wMzCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAu/o0uxgTrAvNDrMNuG2eTla+AmkLVCIXBbsIo0gs" + + "tLm29tLwfBh/8l5OC0y6Xeh5lx+NLdelsiZGRNaaWmWHj9Ji5V6rclr8sXRDUjxe12zLeh" + + "0G+a0TfpL380cx9RItqQyA1ZRiUNymmJHnm13hwrf7LPirR9BMrtyTT2EI3cMCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECHYt39LYdEn0MBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBAIoSGa7MxnOuHoWM/BoJKsCeBmBHYCYDKmQ19JfsDHW8z8oAFiikFb" + + "Gtw1Qpc0GFfJgN0cppaXfe5lDS6BWL2dPorhu3URfXKu84ATLwGmNhqLDY7zh/zPvLtG2m" + + "izaMLC6ZwZL5KELpYpcP15EHPDquyP1xpV3fT17GjpG9IH8k"; + public static final String Intermediate_CRL_1_RL_03_03_crl = + "MIIBcDCB2gIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wMi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAjMCECAg" + + "C0Fw05OTAxMDExMjAwMDBaMAwwCgYDVR0VBAMKAQGgIzAhMAoGA1UdFAQDAgEBMBMGA1Ud" + + "IwQMMAqACHYt39LYdEn0MA0GCSqGSIb3DQEBBQUAA4GBAI3HsXanos/N6uO3QVUaBZzmCt" + + "w1HCHMrLVG614YlUQiEedQ/oEc7dwCeD1rUbGNVkFPIRvMkmUQo1klhKAlEUmrtW+aH+If" + + "6oqumifqxvaycWidacbgNLIAMQtlQmniPF6Pq0dv8sNeKq4CE0gjRHOPJ2zIqy3kJ3tZYB" + + "pTguwO"; + public static final String Intermediate_CRL_2_RL_03_03_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wMy4wMxcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIdi3f0th0SfQwDQYJKoZIhvcNAQEFBQADgYEAXZSZ" + + "ySsD7U6ETy9ZRmiKUCJMUV9CIhCY0mEihHjW0DhFTyV1Hr01yN5zUr/IFVuP/Xcx36IX4l" + + "dVv6/MgR1GeM/BUGZhm4z6YwfAosZ1N3zayIy/pP3fa1rVRl8cgCxc/8qxg9nH9p6yPpxM" + + "AOOu6TLYquk/dA7wJPEW7MPixXY="; + public static final String End_Certificate_RL_03_03_crt = + "MIIChzCCAfCgAwIBAgICALQwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDMuMDMwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjAzLjAzMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC5LNxAB+lm514Hk2ykrFUb7fCX0ryIEMg0mgeT" + + "/z8Iw7xisht57koK4PTXY863aunfNNh+8oFTHZnoLB5dbkROj1nFRgcWPezzv1wNkZEpxn" + + "NINtTPBogW22NPznoZ/rSk9JRFe0sCOVazkW9tZbY2ARqyJsYU1ez5tQIkDS47kQIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECMWddsi+qmxKMBMGA1UdIwQMMAqACHYt39LYdEn0MA0GCSqGSIb3DQEBBQUAA4GBAAv8" + + "nrJaqEycAyIKdPBYTUqaxjkv4SmonDDJG9OqvD78/o9hUKKteoMkNUp8eexTkWk0L72L4N" + + "/eXB30+m65E841V+Dy8L4bXh15n4qz4cyMt8Kvm7nbCqcgpiyBJmBxzfaXDLSthlmhcJ4X" + + "zDFnav1LEw5fZklt7cnMl4YvLD8d"; + public static final String[] TEST_67_DATA = new String[] { + Intermediate_Certificate_RL_03_03_crt, + Intermediate_CRL_1_RL_03_03_crl, + Intermediate_CRL_2_RL_03_03_crl, + End_Certificate_RL_03_03_crt + }; + + /* + * test68 + * + */ + + public static final String Intermediate_Certificate_1_RL_05_01_crt = + "MIICljCCAf+gAwIBAgICALUwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNS4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA59vHTe5A9AcT237mW7HdSfh8Pu4P2wJNLT7RXczN" + + "7DD/P6mAkugSgPTXwwlE1oSB/hCxAtEPhwONYZFYlRClFJidHDdVApalB7UbosTghsUzAg" + + "Lqw7NL+w9i3Un2G7JM2oWwugozQn/1hzr2Cii2TIB6K0RWKoPBJvaWUURS/G8CAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECP55Cc4eBca8MBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBALX594y5uF4Rt7CoRHeKZ5h8QiG7mc+kQDMjaSU4KJwNVVL0mJatQG" + + "w90yFfhvprlgDt9UIAvpF6z5gysbrjHXJaEhVlXeg9D5mcxsL4THEc8f6oU1GjfT/SOD9l" + + "QrT/keX3D9lcFEaTOgi0HIZ7aFIJgoWjXF/9kNNMEAs8sJNI"; + public static final String Intermediate_Certificate_2_RL_05_01_crt = + "MIICljCCAf+gAwIBAgICALYwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDUuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1STC4wNS4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAtl4hX6HlF0M+lSBTG8jHiB06hOy87LL81yAE2JQt" + + "/6F+LZjuOBTCIc2yO2bVM3XzUnjyYDBYGnBFp/7XpRoiADuPJSfmkzmezpyJc+hm96UR1g" + + "Bpo+pPKbRTWuM+FYy+vPtaDk5wKOrmyNx440PwbzxTN3JeWz17xeYE98bXMc0CAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECJOjtwEYV9VSMBMGA1UdIwQMMAqACP55Cc4eBca8MA0GCSqG" + + "SIb3DQEBBQUAA4GBAFbkOffoIjWSfxEuKszoK7Fj27Hf5jlV92xqXtBLURjNGi9jCLUIUd" + + "QLnONZLJYo70Z6XaGjpAK1EtZKVWsz11JDq5egE1zNES//9Tz8xDtJ7Lcq0mwneVFxmBuL" + + "gxkw4GKbBFKz10FoSP7VJWaeW080WwKnp96Me5GtZRe260N1"; + public static final String Intermediate_CRL_1_RL_05_01_crl = + "MIIBhTCB7wIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wNS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjA4MDYCAg" + + "C2Fw05OTAxMDExMjAwMDBaMCEwCgYDVR0VBAMKAQEwEwYJYIZIAWUCAQwCAQH/BAMCAQCg" + + "IzAhMAoGA1UdFAQDAgEBMBMGA1UdIwQMMAqACP55Cc4eBca8MA0GCSqGSIb3DQEBBQUAA4" + + "GBAIdOaBfpAEKWLrSvepVjk3UTfEfsSP6y+kFMl33YXy18xUvVpLarGu6YjQIpXiL+ulkP" + + "eF8TAc9AarUjvDf0kcslIOt3NhdMxR4/F614Ds/rPEXs4c7n4kCkvAlFg/19iIFeCaynx3" + + "X0s/v1SwzgAUHi3P+OwAGDApDTyKbnmzvt"; + public static final String Intermediate_CRL_2_RL_05_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1STC4wNS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIk6O3ARhX1VIwDQYJKoZIhvcNAQEFBQADgYEAfOOd" + + "JiLUCFSurAafQEBfxE9KVrgFC+W9m64cmERicO1QL9aDVIDGJAIY1pdvWVdhLBIKwSugwB" + + "ZH3ToptY+VizvFN1gkKGL2OuvDsXPHn1+QgmqvxYFPmvwDcwuxZ/3zD1VeHgEIKo9ugRnW" + + "F8G2Ph6SWUxJCjJQpB7WIbydowI="; + public static final String End_Certificate_RL_05_01_crt = + "MIIChzCCAfCgAwIBAgICALcwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTItUkwuMDUuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA1LjAxMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC9NWkW/mia20c5gM3DpcTsBWTNC/d/Cob+OVrS" + + "lYytMjK4htO3MavavMZNTLAYFCXWhZ+Uo/uiAF0ddE4HaFI418eKJMSSbQyed0TG5Udw/t" + + "3dhYeLzLEmVc0r00q5v+CLINsCNQAKaPV71UvoHrE092zZjmtacuAetBS1Q2ufpwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECGNPOXdCLpZ3MBMGA1UdIwQMMAqACJOjtwEYV9VSMA0GCSqGSIb3DQEBBQUAA4GBALTo" + + "hfBEPdzZ6A9QNStakOhmhHYox70xOPuWqzSbIugZv4chKXNQGiUAoOGImTw1mcun/uPNtd" + + "0bT+O+a9yX5gzW55CSmR/teHkTkND1mJhOMuYOmaCaBHnqgIIe1iEhMZQgag70+/tSmmQm" + + "UpWGpxeK2c02tBK6gEmnqk75bKRT"; + public static final String[] TEST_68_DATA = new String[] { + Intermediate_Certificate_1_RL_05_01_crt, + Intermediate_Certificate_2_RL_05_01_crt, + Intermediate_CRL_1_RL_05_01_crl, + Intermediate_CRL_2_RL_05_01_crl, + End_Certificate_RL_05_01_crt + }; + + /* + * test69 + * + */ + + public static final String Intermediate_Certificate_RL_05_02_crt = + "MIICljCCAf+gAwIBAgICALgwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNS4wMjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAouNcO1wHvKHPR15L7Fohr/QbTkPWGr9QYp2MXEDy" + + "BRGHt63Ob+yNvsP/C74GJA+PzvcRELSnJxmBVbdRN5y/u4S6Zt4yTTcrvp4vl//luoGLOX" + + "NHhCXbrGavyoP/iKpbfP7fy948AN34i95HuZENoGPjG5stX0uk12P087S2tPcCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECFi86MGPmMsXMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBAFVZVMZEsaVuL0qX5Ls94+x8gBklxPfxgfG5LeBR2/YcqW+7BhsVA1" + + "GQhjBtwqCU9SOL16oTrqgw2+YeWBjaYuNYVlxfdifd0pQydpE1iDQWxmoKLzSDmtWgRYhz" + + "v0TB6j8q+0x5Q0OOrHX0jdIiBnHrLmReCK8dY1x6fb6I0tTH"; + public static final String Intermediate_CRL_RL_05_02_crl = + "MIIBhTCB7wIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wNS4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjA4MDYCAg" + + "C5Fw05OTAxMDExMjAwMDBaMCEwCgYDVR0VBAMKAQEwEwYJYIZIAWUCAQwCAQH/BAMCAQCg" + + "IzAhMAoGA1UdFAQDAgEBMBMGA1UdIwQMMAqACFi86MGPmMsXMA0GCSqGSIb3DQEBBQUAA4" + + "GBAFMN6PWjz2bA1RRySYNXde2rKiYkZYghbtT4ig2yDJBKOiPnjdx+jriFJxGYpt7BvcNx" + + "cDfijmDZ1clzprIvz0lFO6IwsQiWtLxOz4Doj6K2AD+7IxuGLceaXmubvi4e6VVC3xXGsu" + + "OYsNgFzsdUXIazi74+eOcj4dqrHAepbhXT"; + public static final String End_Certificate_RL_05_02_crt = + "MIIChzCCAfCgAwIBAgICALkwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDUuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA1LjAyMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCuWE1aFx3Zjk6gM0Wy6ijcUegbiGvhjBgqIGwv" + + "YissT0v3KGAKoh5wGeKC+rePQNbZ91j4XDLvUNUdNw8HVNdNG/igIwsuaJ9teKSbqrAw9X" + + "aD2YjJz/I6X6WXFd/eQ+g9lY3eidOXJkglYSwWMxUV62RUZbGyqjR1so+XpmYxCQIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECLLbuNyVkkK9MBMGA1UdIwQMMAqACFi86MGPmMsXMA0GCSqGSIb3DQEBBQUAA4GBACKt" + + "GgxIRXYHZGZgwYHjNzquM1pUJTbxxm3qYA4U6r44oAo1UzQTDpHOalflreGFvG05l1BCnQ" + + "olQ8rcXU25v/CDfyww7cl8l7IxjYz7PNht7R97vjfMVqqButbn+BmU6D5kR9YXDCDPzaQ5" + + "DrKNk+3tIjJNj6YhxhqC2tPG9RIN"; + public static final String[] TEST_69_DATA = new String[] { + Intermediate_Certificate_RL_05_02_crt, + Intermediate_CRL_RL_05_02_crl, + End_Certificate_RL_05_02_crt + }; + + /* + * test70 + * + */ + + public static final String Intermediate_Certificate_1_RL_06_01_crt = + "MIICljCCAf+gAwIBAgICALowDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNi4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmhxr4ckU5C3E57odZjgcxl46ZF2QVy+K86YoLOGT" + + "mq34NSHTFxP93mrNqMYdFKFedUTNI68HkecFVvVKoXsDNBnhyyCTQ3xXhBcMUXFByB+55k" + + "W5LeQ8l1G2ugsyZ7Z+P8uylrpeGJt4RjOTilhcI2mnfZ7S+arFGe4KYgnsaFUCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECOS4X3XqhyJYMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBALCPtNwXGxVSUNGErkBHSYCHyqlA55jKQQvZ4P0PznWEQ/gBJx34hq" + + "LxiBO2G+iDomzHszeM77TXkQBpNxCUw26Jxv2HuvyBXuSprgjw5F1tvLqwsBAnD5vsb0uD" + + "NrkKIzJSIBFQ1SRhuCObaXnamfPJHBmkP25t4QqEvoXMtVHB"; + public static final String Intermediate_Certificate_2_RL_06_01_crt = + "MIICljCCAf+gAwIBAgICALswDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDYuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMi1STC4wNi4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA2IKrW6HDZJVFw3e4cC7v/jPGXAexI4B88707NhAc" + + "qxSVfGTPJBdfWo5pkptZKN5/L5n6+rixLItHnei/uwBCHvhwzeEIGo1yVCgz6R2MoNB966" + + "Q5CHWfT43BUjp0rZLJkK4hVKNyXB78NVv2Fly+XWBDEnzQvgVPWbGOvzE3zh0CAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECK/1z9Xbu2jGMBMGA1UdIwQMMAqACOS4X3XqhyJYMA0GCSqG" + + "SIb3DQEBBQUAA4GBAAa/MVC+8ozm9py40a4o/kHbkkmFNQr4s9yi3KXXuVxsNvquFMXm4a" + + "gC8GPoNjvV+RPRmU8wOM6I2/PPl2JEQRb7NDM8LkY/m/Au4GHVeln6FKlldiRm0A+YIr19" + + "ip2RHOldikAjUUYv7JT3SP34sjtq2e8bsXfWEPG5BA/wxtm7"; + public static final String Intermediate_CRL_1_RL_06_01_crl = + "MIIBhTCB7wIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAjMCECAg" + + "C7Fw05OTAxMDExMjAwMDBaMAwwCgYDVR0VBAMKAQGgODA2MAoGA1UdFAQDAgEBMBMGCWCG" + + "SAFlAgEMAgEB/wQDAgEAMBMGA1UdIwQMMAqACOS4X3XqhyJYMA0GCSqGSIb3DQEBBQUAA4" + + "GBAJSexboWDaqLVY6iiWt8ZX5GwuNwDBN1R2TgM95H7JqjMgoWML887dKk24p4eKACFMWI" + + "Ji9nwsqdZ/h1FtPhYpSoJ8l8vo4imMKr+tTnMngDNpMMZPQyRY1AK1jSrLhEtUdjiEtrTY" + + "rG56RNt4YyUtNxxfkEymvwJxmO/4YcAz/l"; + public static final String Intermediate_CRL_2_RL_06_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMi1STC4wNi4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIr/XP1du7aMYwDQYJKoZIhvcNAQEFBQADgYEAImRg" + + "n9A7px9exOJL4Se9jsSHzZ3sAd3y16LdAb+HLtYLl1swNB4KPE+OebtzEoYiSzVVwezdlm" + + "5WseZjfbd0q01srZI4FeACZe99iBSpKymdKxw2gRvfYZ8ZMwFpK2mQq9cmygFn53iOwP7j" + + "3KE+lllielu7sYyEnkliF9wsaG0="; + public static final String End_Certificate_RL_06_01_crt = + "MIIChzCCAfCgAwIBAgICALwwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTItUkwuMDYuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA2LjAxMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDZVBNzD7LZW6mC2GSbVPjpcJ7sWISYsL2eHqXb" + + "/PuxtbOneOjYqx0GeL9pxDGSSNl2NrlG0G1HTU2MaEOVA6h96W9e5ADV/pzGPMr97z+3BV" + + "unxLX+ciM3T7rUQm/LueQTEC2Ww19T6QOg2i8rEadYT0OoW6OcvyuomemspxgClQIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECK5pHDrhL7xjMBMGA1UdIwQMMAqACK/1z9Xbu2jGMA0GCSqGSIb3DQEBBQUAA4GBAF3J" + + "Kskjs4jp+BBoei9YWYtmOupn9w3oGyhknNh2jz7api5Gtgk2SyKfYFvN6EhWZJEab0hPFe" + + "WuYwO7zNCLGHw0cFXT/R48ogd6JkH6xDwj4afZDkWVTu8oaVD4h1rTYS6WPRzizAozOzhi" + + "tmIo+MV/lCG8+jdVtFgeKycI8aX7"; + public static final String[] TEST_70_DATA = new String[] { + Intermediate_Certificate_1_RL_06_01_crt, + Intermediate_Certificate_2_RL_06_01_crt, + Intermediate_CRL_1_RL_06_01_crl, + Intermediate_CRL_2_RL_06_01_crl, + End_Certificate_RL_06_01_crt + }; + + /* + * test71 + * + */ + + public static final String Intermediate_Certificate_RL_06_02_crt = + "MIICljCCAf+gAwIBAgICAL0wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNi4wMjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxMlJ0vbkMRGzuEDTDGuPmwDzU1xn3dFDZ1Tx6ONP" + + "fwNN5gk6r9kYl5TZ8f5TbkQSnOzyhDSqX8dGumCSgukETXtYBU2+KiIAtliu5NJRbXe3La" + + "vn102HxaHDLGsR0FFLiFM9GVhOOXryJoXoGZqUwvqbWyaQQEzrV4RWmuOv7xMCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECFNaMo88Vb5MMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBAJsjJG4/U1OWCJPB1u7UD3TPKRgOR9hT5l3LzFw5s0CEGt2Beg25LP" + + "GEGcr0sEdosVQI5m5CuPolpmlQv0FkZv5M1W+uXX+F/6edtMDEquDpdR97ihQSLZjFFqjE" + + "ytuaD4gqtL/BKBbz3e93mOmR9Wi+kWlXOYl0j8wpU9ePSjDV"; + public static final String Intermediate_CRL_RL_06_02_crl = + "MIIBhTCB7wIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wNi4wMhcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWjAjMCECAg" + + "C+Fw05OTAxMDExMjAwMDBaMAwwCgYDVR0VBAMKAQGgODA2MAoGA1UdFAQDAgEBMBMGCWCG" + + "SAFlAgEMAgEB/wQDAgEAMBMGA1UdIwQMMAqACFNaMo88Vb5MMA0GCSqGSIb3DQEBBQUAA4" + + "GBAAKNj5xmtE7wzO1p5igiAmCDV6KuYsiPAQPHPEBlmo85vzvWv2hpEtmk4nDhehogl0QX" + + "rhvRRqR+cPE5vBLB8mAStW+ZR6FXQPnmU5qGHqCQ4Wh6TWZesd7oyftoS7bJD5Xdf5ErA9" + + "qijWoz8FgxZHVnAFmjA0rUINkdQ5JfE5oj"; + public static final String End_Certificate_RL_06_02_crt = + "MIIChzCCAfCgAwIBAgICAL4wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDYuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA2LjAyMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD3UzwrnwKRlP00Pn49iI35S0wLn7c1I3rsmzdm" + + "YFicetxHNeOKXLg1CN1bqkbAJ+N39fKjrkusqb2T+R3zhAV5LeLT4fzbHYdU7f4r6xgW2/" + + "b2WLv+QVR+ldTsVxgPp/ZUgYi4/vAow4Q/6IT+zWtlawMBob/nLjVl+jQ9N4coFwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECPhq75noL+9WMBMGA1UdIwQMMAqACFNaMo88Vb5MMA0GCSqGSIb3DQEBBQUAA4GBAIU2" + + "5bLX/NyDC8dKUxRwVn8oc3YPQjK0zXGdUr15Ib+cLdRyFVCuAyxVdpTf/csuga6tDhGuTL" + + "B18mTE/fAjhUOiKiOLD6m4P77Nj67l2NTi86RimsI/Z6r5+bU31ahrls/7kr788+f4oEIY" + + "TyOJecojsJUOG3qzK9J50iszclxg"; + public static final String[] TEST_71_DATA = new String[] { + Intermediate_Certificate_RL_06_02_crt, + Intermediate_CRL_RL_06_02_crl, + End_Certificate_RL_06_02_crt + }; + + /* + * test72 + * + */ + + public static final String Intermediate_Certificate_RL_07_01_crt = + "MIICljCCAf+gAwIBAgICAL8wDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNy4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAxjHxSRwJjEkLG9Al5uSQ22QI8N/hJ8hhkhh9qlaJ" + + "mHusM8sWpAp2vnuumlThTA2zZbptXZ8Krb7i/Kpym4wo3ZkEThwi/ijsM5QCunQJmESRGD" + + "yPZJjfhWjoC+lCjbmzsOGLMETpgSEMy+EyoXkRCnKmXcmCMS8HjLrqdnwiWBUCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECHPEkeIs8GuwMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBABCmgEnb8dfnG9lWQKT5BmQm459WqRQAiqdfqf9w0qRMuVrdfLMwqx" + + "oq4uh10A3d+auHohgT2fT9RzNaWnRoNaH9K6qLQsdCUZdqjbEGdyiIFzvWP9MkV9nhDlo2" + + "GgiU68HfnpKO/WA9EaRHyEzwT9o4SA7hAbz+3L12hB2WLSOg"; + public static final String Intermediate_CRL_RL_07_01_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wNy4wMRcNOTgwMTAxMDYwMTAwWhcNOTgwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIc8SR4izwa7AwDQYJKoZIhvcNAQEFBQADgYEAOyZr" + + "f1tRnuzoq7dgQo+eOYhb5JyRyrNaSwNnRy82wOP+/G3NH8V3NGonDFOOcd9SoLTbeW4o71" + + "vdOrKZgom5H2MZK5M4wTdfPAfXB1wBxOMzW5jXzsRtaha4l6EPI+GVL0eXN+aW3k/pscdA" + + "ToI+OxTmRRnCYS6yW3qL9RoTIXQ="; + public static final String End_Certificate_RL_07_01_crt = + "MIIChzCCAfCgAwIBAgICAMAwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDcuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA3LjAxMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCrm/Zem9Tt2UJFUKdAhTNwvhLo03uOax74ZgbV" + + "YNTCpKeEWkV5d5d7DRC4mCTX1yjIlg6K4l7T+sRGI4XAcDRgYLuoyG1X958XCXSdIPTdbK" + + "Hxs/tFv4mrCwi1kU+zjyzDoqgjT6kUxgM39rfcvDMH6qSzHQKgTFp7Tj/DHiELqwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECGFR8c6rRbhcMBMGA1UdIwQMMAqACHPEkeIs8GuwMA0GCSqGSIb3DQEBBQUAA4GBAANZ" + + "TVR288mKpDDzm9XZMZ9+K1kPZ+eQYX+vUul11luVw27AIJGR8Fb4PIGl4+ALvqU3NQP/6v" + + "d+zvS7IfiR6q7aLS3w111BUCgDhTJAp3oSo12qfcp+2DB1M9QfjrM9nKgmh5bBJigdJwJM" + + "W8HHKStUMLdxg+qkZJgZpnyowCFM"; + public static final String[] TEST_72_DATA = new String[] { + Intermediate_Certificate_RL_07_01_crt, + Intermediate_CRL_RL_07_01_crl, + End_Certificate_RL_07_01_crt + }; + + /* + * test73 + * + */ + + public static final String Intermediate_Certificate_RL_07_02_crt = + "MIICljCCAf+gAwIBAgICAMEwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNNTAwMTAxMDYwMDMwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNy4wMjCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0CvEneaAPtxZOTqlh/TXBM6V0bQgKbO58yEyURcO" + + "Zi7jzYsmNtN9Tsr0wAlD41/ZONsW4MMzZ13UCc0aGa+eE8XRULBe5cgaGxJKwVnEqz3W8z" + + "v1MjOk7Anb8TkxMSlWlptC6V3eRA85p5Id9gXbIrP3E3NuSfyx6246oLjNnbECAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECIb5Ia6wKcHtMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBAAYEHQY+Z4qv4bYLmd+sz4aNGwZF7FT6ZIQ43OSeb+t+ibL7rZ0X0y" + + "4SCTMs1mAB44IA6RFurmeCFk0ladRCn3A1xaVI1HlHen13ovzDA9ogL4CWbYXvCUv/znQY" + + "yVSQCTKwT8iVam8xS1MsNCe408iVjhRfR6u9Hi31M+Pf+AUe"; + public static final String Intermediate_CRL_RL_07_02_crl = + "MIIBSzCBtQIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wNy4wMhcNNTAwMTAxMDYwMTAwWhcNNTAwMTAxMTIwMTAwWqAjMCEwCg" + + "YDVR0UBAMCAQEwEwYDVR0jBAwwCoAIhvkhrrApwe0wDQYJKoZIhvcNAQEFBQADgYEALVUq" + + "3Wq/Opvp9ifmQ4VXz4dgLNR+5Nz3muJ4RZt5R5b4R3RYllhgXNYw2EbEVCFjnfm97z73Ke" + + "wzVV+fo/u5GbqJHN2cAVEHarOpasLxySktNA1Cwq5OTzUF0dYISqYbyBvVcaOQBvU/Lwj7" + + "MQJJVVq96iDKnAJYBX03EHKbBeg="; + public static final String End_Certificate_RL_07_02_crt = + "MIIChzCCAfCgAwIBAgICAMIwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDcuMDIwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA3LjAyMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQD6YgsbjW9IL7/SBORKssFUZBUxmluOpxJK/7d7" + + "JA2pxbg7L96xHFPWN36CYDJzTscNpbGrD3G2MPkg4GqoTo0rU28NYVzj4SwqYoSLIbXB+r" + + "SVgWcxNgbJ+4x9bK3YccNLR1PWEFxz1NckhCLBmb5pI4E34MCxQ6PvFO02I19FwQIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECIutV9ItCIbZMBMGA1UdIwQMMAqACIb5Ia6wKcHtMA0GCSqGSIb3DQEBBQUAA4GBALQE" + + "cBr31h3jKUHcuf3yztr9NWUkGMDM0NCXHOpQl7JbV3P5BjvaiRYWlUrN7+92G8EaUFORto" + + "zp8GG+d/MvFooVQOvpOzyhautYWyqq3AWpZLppnxNk1mRAdjUAvJaONtv37eLsma0bhtLM" + + "j62sQQ6CdoKbMtIEGuJgpwWqHYwY"; + public static final String[] TEST_73_DATA = new String[] { + Intermediate_Certificate_RL_07_02_crt, + Intermediate_CRL_RL_07_02_crl, + End_Certificate_RL_07_02_crt + }; + + /* + * test74 + * + */ + + public static final String Intermediate_Certificate_RL_07_03_crt = + "MIICljCCAf+gAwIBAgICAMMwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wNy4wMzCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEA8QzGjV0NVTNrOgkeqTkQFCOvl7M0qmjmYJjuw4R3" + + "YfQIXDN0m9HR2JKp5WKTSUedmWviGS7NbGSzLR7+6OkLwSoxN9PkA/fMko7O0KWBfduhvn" + + "jymlDMb2GPb1hBjScbq8fVJHwzqUm+BtEO2MXwXKYY2hZr+OEyEGhSEThp90MCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECFwl2XphEZRSMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBAAb5GERgYVGuOb62gVZAAnhuk5K7CCkWZucOv6iI7pAgI6S7pvool/" + + "dXHC0tzgQ+/MkuWcr+22k/ya7f+iSfiYokjnQkgoYFYk3PkjyOXA3mzs5qhF0nOP6Gvmz4" + + "asONA+qZSqa4pjxF9Kn8L64f9yeyEXnckmbzdmbjAFCveQIP"; + public static final String Intermediate_CRL_RL_07_03_crl = + "MIIBTTCBtwIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wNy4wMxcNOTkwMTAxMDYwMTAwWhgPMjA1MDAxMDExMjAxMDBaoCMwIT" + + "AKBgNVHRQEAwIBATATBgNVHSMEDDAKgAhcJdl6YRGUUjANBgkqhkiG9w0BAQUFAAOBgQAz" + + "DMl8P16hylNkUEw4z9//PJFObNPZCYdmzBfp0K3tNRrOAouUVegyX0gDHi8O+bmmJNgcnC" + + "tMRXx+D4qP7bx5fDS2MVQhSsncf6u4UZ8pxbRc0JmwR5oGZLPQabrctgmEmg8ZKGApKtsf" + + "pGyvvTwaAzM+GaWXD68bBEN3VfVdeQ=="; + public static final String End_Certificate_RL_07_03_crt = + "MIIChzCCAfCgAwIBAgICAMQwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDcuMDMwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA3LjAzMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDU6mec24uBaVip7fFWHas+o/lpZBOfj/IPHXQ9" + + "QaRZwmJZBB81AX3BJ60DD12o/+RXdHl7B2Eh9kYv/QEXOKmyhJFSPa0Lv7MQ/hCIcL4m1U" + + "FDGtJ3SUixZMqVBP0xjwXoNS88zzaCBL+co2TxhBrYMzeNQOX1eEkXMT4pvULmAwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECBBgFdYLuvk9MBMGA1UdIwQMMAqACFwl2XphEZRSMA0GCSqGSIb3DQEBBQUAA4GBAAof" + + "dPOGa4ZxRPcLw6zWM/NLzF3XYDqXAsZBsC75r0GRrogqEYn07tVUDNaQczDtjRLBRNmxWE" + + "+qCkJwc+wOBJqOFUxcuhK9oag6OE94+UIHdh3Td9i2ELZXj9RSNchnjyFohj5gk1dJSO41" + + "86Ls3mCT9JcssR0dSxxkF0ENfZCG"; + public static final String[] TEST_74_DATA = new String[] { + Intermediate_Certificate_RL_07_03_crt, + Intermediate_CRL_RL_07_03_crl, + End_Certificate_RL_07_03_crt + }; + + /* + * test75 + * + */ + + public static final String Intermediate_Certificate_RL_08_01_crt = + "MIICljCCAf+gAwIBAgICAMUwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wOC4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAs2YRTEl3C1TmmneJ6K110nSACn+KXxSOTGAGN5xv" + + "XW751StpE2iEQIbRVPQdMzmcQX0bcg/WpdrewPQld9NRjFj7it+9YNQh7vMKhZwoAPoDmv" + + "TnTdTEuV0c1FLVDVhiaAD9KMBa4fBLRfTKVzgzAr+oNqLhm3YBd2JWRHg+fA8CAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECB4we8+hIrkKMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBABTQI82uCMwQ4bgUWr9lawSI5DyWg3KY13F45rAlmKyckgne9SHbCH" + + "+Lvm3XkkIqKmeHfJ3QTf7bpz6eErn3CxRrGm5JWblcYbVT+smjboJ9A0BXifqINYLy3qGc" + + "AnNRkPq8OUREj2sU1qWKagUIgA/Vk2WyZhcUiApJPHI4fwv9"; + public static final String Intermediate_CRL_RL_08_01_crl = + "MIIBWjCBxAIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wOC4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqAyMDAwCg" + + "YDVR0UBAMCAQEwDQYDVR0bAQH/BAMCAQEwEwYDVR0jBAwwCoAIHjB7z6EiuQowDQYJKoZI" + + "hvcNAQEFBQADgYEAkjF0oERt5XW2i70gyspkEYIHyGCHnqngky5yuwQSRrlW7t0vGdKV7W" + + "50evTeSVV41uhi1MBcccpx1MdRcB5vsatFSSKcKx4NF3PuHXxXCm2HkfXQy4K5zftE3jOZ" + + "5s+yTHiw3s/QSErtHRca+TQcEZwamI+p402TEa6e82l6xHI="; + public static final String End_Certificate_RL_08_01_crt = + "MIIChzCCAfCgAwIBAgICAMYwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDguMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA4LjAxMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDfEMqWMqk3Rre5m4ILtQIz45JImvU379Al/S6t" + + "2y/TzimJc4nhIKQp80VaZA/gwu/DcvMgJPM+FFz5U5rRkDaYASsc34tZUESF5LC6ZbtGqf" + + "J96IKdajvkGLsHyI7dseuwaQ0FlOwcmKMSR898MGNNbKxaQNLEXsIFypRDsN6JhwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECMT22ARjB1ABMBMGA1UdIwQMMAqACB4we8+hIrkKMA0GCSqGSIb3DQEBBQUAA4GBAIaP" + + "EqI7oHl/+h3MszG4VB1Va9NTN0kaysTyjQSVBi9jhOlPkzuXc2wI1bymBhatHEn6OrgP13" + + "vsOiH2BiyudYcYjKpwI4FUiyKLIc0CXzM0VYFoMzb91QtsK1EnvAPDKNYVVFXrL7ABVIK4" + + "hU6HfMMUbnpKWBxT5274iHScX8tL"; + public static final String[] TEST_75_DATA = new String[] { + Intermediate_Certificate_RL_08_01_crt, + Intermediate_CRL_RL_08_01_crl, + End_Certificate_RL_08_01_crt + }; + + /* + * test76 + * + */ + + public static final String Intermediate_Certificate_RL_09_01_crt = + "MIICljCCAf+gAwIBAgICAMcwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9EMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxUcnVzdCBBbmNob3IwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNVBAMTDENBMS1STC4wOS4wMTCBnzANBg" + + "kqhkiG9w0BAQEFAAOBjQAwgYkCgYEAsvkvLv5fMFYvohaXO8a7GgU4rDHe9iL7LP1VeNUg" + + "GIdJGqPEnuggQ/guhrBHafGh1NtmlEbmPJ4WQ99dBbPHHeO8sfCgkmWC0SqPODoI+t3qJE" + + "kf2z9dWoAij15RXPliywZz+S6bTtcEQAREyBQ6M8/HJ83wRXp/uCpdPOSxVPkCAwEAAaNj" + + "MGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwFgYDVR0gBA8wDTALBglghk" + + "gBZQMBMAEwEQYDVR0OBAoECISY4bvGMEBTMBMGA1UdIwQMMAqACKua6/nC51SPMA0GCSqG" + + "SIb3DQEBBQUAA4GBAAd7g+dWso4V/Vr+QIoNLueCBAYWdOF+Yz3VeomcsDAs2V8E+xcZaq" + + "jo2LrMygYCeMxVfXx/ZdhLPOaZ+ahNAbk+nWRwj35JdTNAAbMMWFdZUgR6N+uzx1v7i86p" + + "AWUpRJ9IYPgUoQ5pmjdf3Ru1nrLfRt4yp+kNHWp6IL/+MwcM"; + public static final String Intermediate_CRL_RL_09_01_crl = + "MIIBXDCBxgIBATANBgkqhkiG9w0BAQUFADBeMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS" + + "5TLiBHb3Zlcm5tZW50MQwwCgYDVQQLEwNEb2QxEDAOBgNVBAsTB1Rlc3RpbmcxFTATBgNV" + + "BAMTDENBMS1STC4wOS4wMRcNOTkwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMTAwWqA0MDIwCg" + + "YDVR0UBAMCAQEwDwYDVR0cAQH/BAUwA4IB/zATBgNVHSMEDDAKgAiEmOG7xjBAUzANBgkq" + + "hkiG9w0BAQUFAAOBgQAKTXYgqlP+upFIwOSpdaVKDT8aqFzY9nSIsxHg5Wdl43U7p44LvQ" + + "lW8XKhw74oQl1ExU5s7mDaEqB0JIozGzmoNyKsErgWKNW+lpKSxR5+1EHOB6Oo2KijpTsv" + + "GFrHFCnF09f9JaTaMRIXOljx3rMO1UZsftKy/L9z3aUz8hQRnQ=="; + public static final String End_Certificate_RL_09_01_crt = + "MIIChzCCAfCgAwIBAgICAMgwDQYJKoZIhvcNAQEFBQAwXjELMAkGA1UEBhMCVVMxGDAWBg" + + "NVBAoTD1UuUy4gR292ZXJubWVudDEMMAoGA1UECxMDRG9kMRAwDgYDVQQLEwdUZXN0aW5n" + + "MRUwEwYDVQQDEwxDQTEtUkwuMDkuMDEwHhcNOTgwMTAxMTIwMTAwWhcNNDgwMTAxMTIwMT" + + "AwWjBgMQswCQYDVQQGEwJVUzEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQwwCgYDVQQL" + + "EwNEb0QxEDAOBgNVBAsTB1Rlc3RpbmcxFzAVBgNVBAMTDlVzZXIxLVJMLjA5LjAxMIGfMA" + + "0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpz09VCXzAhH4/ifMk0RAzaBqJCXaHHqAdO/TW" + + "6uvOVtl+fGvWXhXmSSCUfzg5xBqdUXrqcyxOME3vdgF1uOFZ4q2K6+Zuxmm+GCOCIpe+Gl" + + "Jzqz4WKXG0iaXXQOYa56itNc/6Z6D/aAjNJavI19w0lmb9l6U2WBfn3LywxHp4dwIDAQAB" + + "o1IwUDAOBgNVHQ8BAf8EBAMCBeAwFgYDVR0gBA8wDTALBglghkgBZQMBMAEwEQYDVR0OBA" + + "oECOri1JgnJfLjMBMGA1UdIwQMMAqACISY4bvGMEBTMA0GCSqGSIb3DQEBBQUAA4GBADmV" + + "Ee0xy25Z0HtmWwprKPjJDr/p7TgzbmNC58pUPkgtxnJFP4yrzNB9FQBWSfnjZpzQkLSU7i" + + "7O6cf5HkqjQqoPErDnJLWgGzjbF80v2IIyZk7rEpAAM4MwjIk7hFvJK8QkTht9F4N1zj2X" + + "0TQkmlbo9Z4SFj/3fsbl9h2GdKuU"; + public static final String[] TEST_76_DATA = new String[] { + Intermediate_Certificate_RL_09_01_crt, + Intermediate_CRL_RL_09_01_crl, + End_Certificate_RL_09_01_crt + }; + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NamedCurveTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NamedCurveTest.java new file mode 100644 index 000000000..c155f07be --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NamedCurveTest.java @@ -0,0 +1,445 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.interfaces.ECPrivateKey; +import java.security.interfaces.ECPublicKey; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Collections; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; + +import javax.crypto.KeyAgreement; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.cryptopro.ECGOST3410NamedCurves; +import com.fr.third.org.bouncycastle.asn1.nist.NISTNamedCurves; +import com.fr.third.org.bouncycastle.asn1.sec.SECNamedCurves; +import com.fr.third.org.bouncycastle.asn1.teletrust.TeleTrusTNamedCurves; +import com.fr.third.org.bouncycastle.asn1.x509.Extension; +import com.fr.third.org.bouncycastle.asn1.x9.X962NamedCurves; +import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveSpec; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class NamedCurveTest + extends SimpleTest +{ + private static Hashtable CURVE_NAMES = new Hashtable(); + private static Hashtable CURVE_ALIASES = new Hashtable(); + + static + { + CURVE_NAMES.put("prime192v1", "prime192v1"); // X9.62 + CURVE_NAMES.put("sect571r1", "sect571r1"); // sec + CURVE_NAMES.put("secp224r1", "secp224r1"); + CURVE_NAMES.put("B-409", SECNamedCurves.getName(NISTNamedCurves.getOID("B-409"))); // nist + CURVE_NAMES.put("P-521", SECNamedCurves.getName(NISTNamedCurves.getOID("P-521"))); + CURVE_NAMES.put("brainpoolP160r1", "brainpoolp160r1"); // TeleTrusT + + CURVE_ALIASES.put("secp192r1", "prime192v1"); + CURVE_ALIASES.put("secp256r1", "prime256v1"); + } + + public void testCurve( + String name) + throws Exception + { + ECGenParameterSpec ecSpec = new ECGenParameterSpec(name); + + KeyPairGenerator g = KeyPairGenerator.getInstance("ECDH", "BC"); + + g.initialize(ecSpec, new SecureRandom()); + + // + // a side + // + KeyPair aKeyPair = g.generateKeyPair(); + + KeyAgreement aKeyAgree = KeyAgreement.getInstance("ECDHC", "BC"); + + aKeyAgree.init(aKeyPair.getPrivate()); + + // + // b side + // + KeyPair bKeyPair = g.generateKeyPair(); + + KeyAgreement bKeyAgree = KeyAgreement.getInstance("ECDHC", "BC"); + + bKeyAgree.init(bKeyPair.getPrivate()); + + // + // agreement + // + aKeyAgree.doPhase(bKeyPair.getPublic(), true); + bKeyAgree.doPhase(aKeyPair.getPublic(), true); + + BigInteger k1 = new BigInteger(aKeyAgree.generateSecret()); + BigInteger k2 = new BigInteger(bKeyAgree.generateSecret()); + + if (!k1.equals(k2)) + { + fail("2-way test failed"); + } + + // + // public key encoding test + // + byte[] pubEnc = aKeyPair.getPublic().getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance("ECDH", "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509); + + if (!pubKey.getW().equals(((ECPublicKey)aKeyPair.getPublic()).getW())) + { + fail("public key encoding (Q test) failed"); + } + + if (!(pubKey.getParams() instanceof ECNamedCurveSpec)) + { + fail("public key encoding not named curve"); + } + + // + // private key encoding test + // + byte[] privEnc = aKeyPair.getPrivate().getEncoded(); + PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); + ECPrivateKey privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8); + + if (!privKey.getS().equals(((ECPrivateKey)aKeyPair.getPrivate()).getS())) + { + fail("private key encoding (S test) failed"); + } + + if (!(privKey.getParams() instanceof ECNamedCurveSpec)) + { + fail("private key encoding not named curve"); + } + + ECNamedCurveSpec privSpec = (ECNamedCurveSpec)privKey.getParams(); + if (!(privSpec.getName().equals(name) || privSpec.getName().equals(CURVE_NAMES.get(name)))) + { + fail("private key encoding wrong named curve. Expected: " + CURVE_NAMES.get(name) + " got " + privSpec.getName()); + } + } + + public void testECDSA( + String name) + throws Exception + { + ECGenParameterSpec ecSpec = new ECGenParameterSpec(name); + + KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); + + g.initialize(ecSpec, new SecureRandom()); + + Signature sgr = Signature.getInstance("ECDSA", "BC"); + KeyPair pair = g.generateKeyPair(); + PrivateKey sKey = pair.getPrivate(); + PublicKey vKey = pair.getPublic(); + + sgr.initSign(sKey); + + byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail(name + " verification failed"); + } + + // + // public key encoding test + // + byte[] pubEnc = vKey.getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance("ECDH", "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509); + + if (!pubKey.getW().equals(((ECPublicKey)vKey).getW())) + { + fail("public key encoding (Q test) failed"); + } + + if (!(pubKey.getParams() instanceof ECNamedCurveSpec)) + { + fail("public key encoding not named curve"); + } + + // + // private key encoding test + // + byte[] privEnc = sKey.getEncoded(); + PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); + ECPrivateKey privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8); + + if (!privKey.getS().equals(((ECPrivateKey)sKey).getS())) + { + fail("private key encoding (S test) failed"); + } + + if (!(privKey.getParams() instanceof ECNamedCurveSpec)) + { + fail("private key encoding not named curve"); + } + + ECNamedCurveSpec privSpec = (ECNamedCurveSpec)privKey.getParams(); + if (!privSpec.getName().equalsIgnoreCase(name) + && !privSpec.getName().equalsIgnoreCase((String)CURVE_ALIASES.get(name))) + { + fail("private key encoding wrong named curve. Expected: " + name + " got " + privSpec.getName()); + } + } + + public void testECGOST( + String name) + throws Exception + { + ECGenParameterSpec ecSpec = new ECGenParameterSpec(name); + + KeyPairGenerator g; + Signature sgr; + String keyAlgorithm; + + if (name.startsWith("Tc26-Gost-3410")) + { + keyAlgorithm = "ECGOST3410-2012"; + if (name.indexOf("256") > 0) + { + sgr = Signature.getInstance("ECGOST3410-2012-256", "BC"); + } + else + { + sgr = Signature.getInstance("ECGOST3410-2012-512", "BC"); + } + } + else + { + keyAlgorithm = "ECGOST3410"; + + sgr = Signature.getInstance("ECGOST3410", "BC"); + } + + g = KeyPairGenerator.getInstance(keyAlgorithm, "BC"); + + g.initialize(ecSpec, new SecureRandom()); + + KeyPair pair = g.generateKeyPair(); + PrivateKey sKey = pair.getPrivate(); + PublicKey vKey = pair.getPublic(); + + sgr.initSign(sKey); + + byte[] message = new byte[] { (byte)'a', (byte)'b', (byte)'c' }; + + sgr.update(message); + + byte[] sigBytes = sgr.sign(); + + sgr.initVerify(vKey); + + sgr.update(message); + + if (!sgr.verify(sigBytes)) + { + fail(name + " verification failed"); + } + + // + // public key encoding test + // + byte[] pubEnc = vKey.getEncoded(); + KeyFactory keyFac = KeyFactory.getInstance(keyAlgorithm, "BC"); + X509EncodedKeySpec pubX509 = new X509EncodedKeySpec(pubEnc); + ECPublicKey pubKey = (ECPublicKey)keyFac.generatePublic(pubX509); + + if (!pubKey.getW().equals(((ECPublicKey)vKey).getW())) + { + fail("public key encoding (Q test) failed"); + } + + if (!(pubKey.getParams() instanceof ECNamedCurveSpec)) + { + fail("public key encoding not named curve"); + } + + // + // private key encoding test + // + byte[] privEnc = sKey.getEncoded(); + PKCS8EncodedKeySpec privPKCS8 = new PKCS8EncodedKeySpec(privEnc); + ECPrivateKey privKey = (ECPrivateKey)keyFac.generatePrivate(privPKCS8); + + if (!privKey.getS().equals(((ECPrivateKey)sKey).getS())) + { + fail("GOST private key encoding (S test) failed"); + } + + if (!(privKey.getParams() instanceof ECNamedCurveSpec)) + { + fail("GOST private key encoding not named curve"); + } + + ECNamedCurveSpec privSpec = (ECNamedCurveSpec)privKey.getParams(); + if (!privSpec.getName().equalsIgnoreCase(name) + && !privSpec.getName().equalsIgnoreCase((String)CURVE_ALIASES.get(name))) + { + fail("GOST private key encoding wrong named curve. Expected: " + name + " got " + privSpec.getName()); + } + } + + public void testAcceptable() + throws Exception + { + ECGenParameterSpec ecSpec = new ECGenParameterSpec("P-256"); + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(ecSpec); + + KeyPair kp = kpGen.generateKeyPair(); + + X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(kp.getPublic().getEncoded()); + PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded()); + + KeyFactory kf = KeyFactory.getInstance("EC", "BC"); + + ConfigurableProvider bcProv = ((ConfigurableProvider)Security.getProvider("BC")); + + bcProv.setParameter(ConfigurableProvider.ACCEPTABLE_EC_CURVES, Collections.singleton(NISTNamedCurves.getOID("P-384"))); + + try + { + kf.generatePrivate(privSpec); + fail("no exception"); + } + catch (InvalidKeySpecException e) + { + isTrue("wrong message", "encoded key spec not recognized: named curve not acceptable".equals(e.getMessage())); + } + + try + { + kf.generatePublic(pubSpec); + fail("no exception"); + } + catch (InvalidKeySpecException e) + { + isTrue("wrong message", "encoded key spec not recognized: named curve not acceptable".equals(e.getMessage())); + } + + bcProv.setParameter(ConfigurableProvider.ACCEPTABLE_EC_CURVES, Collections.singleton(NISTNamedCurves.getOID("P-256"))); + + kf.generatePrivate(privSpec); + kf.generatePublic(pubSpec); + + bcProv.setParameter(ConfigurableProvider.ACCEPTABLE_EC_CURVES, Collections.EMPTY_SET); + + kf.generatePrivate(privSpec); + kf.generatePublic(pubSpec); + } + + public void testAdditional() + throws Exception + { + ConfigurableProvider bcProv = ((ConfigurableProvider)Security.getProvider("BC")); + ASN1ObjectIdentifier bogusCurveID = Extension.auditIdentity; + + bcProv.setParameter(ConfigurableProvider.ADDITIONAL_EC_PARAMETERS, Collections.singletonMap(bogusCurveID, NISTNamedCurves.getByName("P-384"))); + + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(new ECGenParameterSpec(bogusCurveID.getId())); + + KeyPair kp = kpGen.generateKeyPair(); + + X509EncodedKeySpec pubSpec = new X509EncodedKeySpec(kp.getPublic().getEncoded()); + PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(kp.getPrivate().getEncoded()); + + KeyFactory kf = KeyFactory.getInstance("EC", "BC"); + + kf.generatePrivate(privSpec); + kf.generatePublic(pubSpec); + } + + public String getName() + { + return "NamedCurve"; + } + + public void performTest() + throws Exception + { + testCurve("prime192v1"); // X9.62 + testCurve("sect571r1"); // sec + testCurve("secp224r1"); + testCurve("B-409"); // nist + testCurve("P-521"); + testCurve("brainpoolP160r1"); // TeleTrusT + + for (Enumeration en = X962NamedCurves.getNames(); en.hasMoreElements();) + { + testECDSA((String)en.nextElement()); + } + + // these curves can't be used under JDK 1.5 + Set problemCurves = new HashSet(); + + problemCurves.add("secp256k1"); + problemCurves.add("secp160k1"); + problemCurves.add("secp224k1"); + problemCurves.add("secp192k1"); + + for (Enumeration en = SECNamedCurves.getNames(); en.hasMoreElements();) + { + String curveName = (String)en.nextElement(); + + if (!problemCurves.contains(curveName)) + { + testECDSA(curveName); + } + } + + for (Enumeration en = TeleTrusTNamedCurves.getNames(); en.hasMoreElements();) + { + testECDSA((String)en.nextElement()); + } + + for (Enumeration en = ECGOST3410NamedCurves.getNames(); en.hasMoreElements();) + { + testECGOST((String)en.nextElement()); + } + + testAcceptable(); + testAdditional(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new NamedCurveTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NetscapeCertRequestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NetscapeCertRequestTest.java new file mode 100644 index 000000000..fa0d5eff9 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NetscapeCertRequestTest.java @@ -0,0 +1,125 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Security; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.jce.netscape.NetscapeCertRequest; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +/** + */ +public class NetscapeCertRequestTest + implements Test +{ + /* from NS 4.75 */ + static final String test1 = + "MIIBRzCBsTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAmwdh+LJXQ8AtXczo"+ + "4EIGfXjpmDwsoIRpPaXEx1CBHhpon/Dpo/o5Vw2WoWNICXj5lmqhftIpCPO9qKxx"+ + "85x6k/fuyTPH8P02hkmscAYsgqOgb/1yRCNXFryuFOATqxw1tsuye5Q3lTU9JCLU"+ + "UilQ6BV8n3fm2egtPPUaJEuCvcsCAwEAARYNZml4ZWQtZm9yLW5vdzANBgkqhkiG"+ + "9w0BAQQFAAOBgQAImbJD6xHbJtXl6kOTbCFoMnDk7U0o6pHy9l56DYVsiluXegiY"+ + "6twB4o7OWsrqTb+gVvzK65FfP+NBVVzxY8UzcjbqC51yvO/9wnpUsIBqD/Gvi1gE"+ + "qvw7RHwVEhdzsvLwlL22G8CfDxHnWLww39j8uRJsmoNiKJly3BcsZkLd9g=="; + + public String getName() + { + return "NetscapeCertRequest"; + } + + public TestResult perform() + { + try + { + String challenge = "fixed-for-now"; + + byte data [] = Base64.decode (test1); + + ASN1InputStream in = new ASN1InputStream (new ByteArrayInputStream(data)); + ASN1Sequence spkac = (ASN1Sequence)in.readObject (); + // System.out.println("SPKAC: \n"+DERDump.dumpAsString (spkac)); + + + NetscapeCertRequest nscr = new NetscapeCertRequest (spkac); + + if (!nscr.verify (challenge)) + { + return new SimpleTestResult(false, getName() + ": 1 - not verified"); + } + + //now try to generate one + KeyPairGenerator kpg = + KeyPairGenerator.getInstance (nscr.getKeyAlgorithm().getAlgorithm().getId(), "BC"); + + kpg.initialize (1024); + + KeyPair kp = kpg.genKeyPair(); + + nscr.setPublicKey (kp.getPublic()); + nscr.sign (kp.getPrivate()); + + byte[] derEncoding = nscr.getEncoded(ASN1Encoding.DER); + + ASN1InputStream in2 = + new ASN1InputStream (new ByteArrayInputStream(derEncoding)); + ASN1Sequence spkac2 = (ASN1Sequence)in2.readObject (); + + // System.out.println("SPKAC2: \n"+DERDump.dumpAsString (spkac2)); + + NetscapeCertRequest nscr2 = new NetscapeCertRequest (spkac2); + + if (!nscr2.verify (challenge)) + { + return new SimpleTestResult(false, getName() + ": 2 - not verified"); + } + + //lets build it from scratch + + + challenge = "try it"; + + NetscapeCertRequest nscr3 = + new NetscapeCertRequest (challenge, + new AlgorithmIdentifier(PKCSObjectIdentifiers.sha1WithRSAEncryption, null), + kp.getPublic()); + + nscr3.sign (kp.getPrivate()); + + // System.out.println("SPKAC3: \n"+DERDump.dumpAsString (nscr3)); + + if (nscr3.verify (challenge)) + { + return new SimpleTestResult(true, getName() + ": Okay"); + } + else + { + return new SimpleTestResult(false, getName() + ": 3 - not verified"); + } + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": exception - " + e.toString()); + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + Test test = new NetscapeCertRequestTest(); + TestResult result = test.perform(); + + System.out.println(result.toString()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NoekeonTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NoekeonTest.java new file mode 100644 index 000000000..3af7c750b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/NoekeonTest.java @@ -0,0 +1,152 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.Security; + +/** + * basic test class for SEED + */ +public class NoekeonTest + extends BaseBlockCipherTest +{ + static String[] cipherTests = + { + "128", + "b1656851699e29fa24b70148503d2dfc", + "2a78421b87c7d0924f26113f1d1349b2", + "e2f687e07b75660ffc372233bc47532c" + }; + + public NoekeonTest() + { + super("Noekeon"); + } + + public void test( + int strength, + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "Noekeon"); + + in = Cipher.getInstance("Noekeon/ECB/NoPadding", "BC"); + out = Cipher.getInstance("Noekeon/ECB/NoPadding", "BC"); + + try + { + out.init(Cipher.ENCRYPT_MODE, key); + } + catch (Exception e) + { + fail("Noekeon failed initialisation - " + e.toString(), e); + } + + try + { + in.init(Cipher.DECRYPT_MODE, key); + } + catch (Exception e) + { + fail("Noekeoen failed initialisation - " + e.toString(), e); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail("Noekeon failed encryption - " + e.toString(), e); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("Noekeon failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + } + catch (Exception e) + { + fail("Noekeon failed encryption - " + e.toString(), e); + } + + if (!areEqual(bytes, input)) + { + fail("Noekeon failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + public void performTest() + throws Exception + { + for (int i = 0; i != cipherTests.length; i += 4) + { + test(Integer.parseInt(cipherTests[i]), + Hex.decode(cipherTests[i + 1]), + Hex.decode(cipherTests[i + 2]), + Hex.decode(cipherTests[i + 3])); + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new NoekeonTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/OCBTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/OCBTest.java new file mode 100644 index 000000000..f69767576 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/OCBTest.java @@ -0,0 +1,105 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Key; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class OCBTest + extends SimpleTest +{ + public String getName() + { + return "OCB"; + } + + public void performTest() + throws Exception + { + checkRegistrations(); + } + + private void checkRegistrations() + throws Exception + { + String[] ciphers = new String[] { "AES", "NOEKEON", "Twofish", "CAST6", "SEED", "Tnepres", "Serpent", "RC6", "CAMELLIA" }; + String[] cipherText = new String[] + { + "BEA5E8798DBE7110031C144DA0B2612213CC8B747807121A4CBB3E4BD6B456AF", + "a2545b927e0f2e6db2998e20b17d5fc0564dcab63b748327e2ef4eaed88cb059", + "1cfafe72f7181cae331610c116345e51fc356b379aca04da2a53337c5428d8e4", + "5b9b738b2ac7000b33b89dd4eec18dd853f4f7c1d9e17b565405f17a0a8c8b63", + "fcdbcee69d02c69858ed4569f78b81920b3027cdb7f1f154634aa5ace9e6ba29", + "4f7154cb34558940e85db7d3e96ac6c9cb0d9c1b00b18e82e15d1be83deef9df", + "3dd3477801e71807ea1f1f690d8428ed6b1002831428a64f88c36b6d5610022f", + "23f3e450c4c7199563a0ed601a5c60d75eb88db2a0d090ae5e84d98438a146aa", + "ac13ce9db4af148e910a813fc728e5785e23b1bf1d04a961a3f95f356b9417ab" + }; + + for (int i = 0; i < ciphers.length; i++) + { + ocbTest(ciphers[i], cipherText[i]); + } + } + + private void ocbTest(String cipher, String cText) + throws Exception + { + byte[] K = Hex.decode( + "000102030405060708090A0B0C0D0E0F"); + byte[] P = Hex.decode( + "000102030405060708090A0B0C0D0E0F"); + byte[] N = Hex.decode("000102030405060708090A0B"); + String T = "4CBB3E4BD6B456AF"; + byte[] C = Hex.decode(cText); + + Key key; + Cipher in, out; + + key = new SecretKeySpec(K, cipher); + + in = Cipher.getInstance(cipher + "/OCB/NoPadding", "BC"); + out = Cipher.getInstance(cipher + "/OCB/NoPadding", "BC"); + + in.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] enc = in.doFinal(P); + if (!areEqual(enc, C)) + { + fail("ciphertext doesn't match in OCB got " + new String(Hex.encode(enc))); + } + + out.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(N)); + + byte[] dec = out.doFinal(C); + if (!areEqual(dec, P)) + { + fail("plaintext doesn't match in OCB"); + } + + try + { + in = Cipher.getInstance(cipher + "/OCB/PKCS5Padding", "BC"); + + fail("bad padding missed in OCB"); + } + catch (NoSuchPaddingException e) + { + // expected + } + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new OCBTest()); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/OpenSSHSpecTests.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/OpenSSHSpecTests.java new file mode 100644 index 000000000..da6248dd4 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/OpenSSHSpecTests.java @@ -0,0 +1,214 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.StringReader; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; + +import com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec; +import com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.io.pem.PemReader; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class OpenSSHSpecTests + extends SimpleTest +{ + private static final SecureRandom secureRandom = new SecureRandom(); + + public void testEncodingRSA() + throws Exception + { + byte[] rawPub = Base64.decode("AAAAB3NzaC1yc2EAAAADAQABAAAAgQDvh2BophdIp8ojwGZQR0FQ/awowXnV24nAPm+/na8MOUrdySNhOnlek4LAZl82/+Eu2t21XD6hQUiHKAj6XaNFBthTuss7Cz/tA348DLEMHD9wUtT0FXVmsxqN4BfusunbcULxxVWG2z8FvqeaGgc/Unkp9y7/kyf54pPUCBcClw=="); + byte[] rawPriv = new PemReader(new StringReader("-----BEGIN RSA PRIVATE KEY-----\n" + + "MIICXgIBAAKBgQDvh2BophdIp8ojwGZQR0FQ/awowXnV24nAPm+/na8MOUrdySNh\n" + + "Onlek4LAZl82/+Eu2t21XD6hQUiHKAj6XaNFBthTuss7Cz/tA348DLEMHD9wUtT0\n" + + "FXVmsxqN4BfusunbcULxxVWG2z8FvqeaGgc/Unkp9y7/kyf54pPUCBcClwIDAQAB\n" + + "AoGBAOMXYEoXHgAeREE9CkOWKtDUkEJbnF0rNSB0kZIDt5BJSTeYmNh3jdYi2FX9\n" + + "OMx2MFIx4v0tJZvQvyiUxl5IJJ9ZJsYUWF+6VbcTVwYYfdVzZzP2TNyGmF9/ADZW\n" + + "wBehqP04uRlYjt94kqb4HoOKF3gJ3LC4uW9xcEltTBeHWCfhAkEA/2biF5St9/Ya\n" + + "540E4zu/FKPsxLSaT8LWCo9+X7IqIzlBQCB4GjM+nZeTm7eZOkfAFZoxwfiNde/9\n" + + "qleXXf6B2QJBAPAW+jDBC3QF4/g8n9cDxm/A3ICmcOFSychLSrydk9ZyRPbTRyQC\n" + + "YlC2mf/pCrO/yO7h189BXyQ3PXOEhnujce8CQQD7gDy0K90EiH0F94AQpA0OLj5B\n" + + "lfc/BAXycEtpwPBtrzvqAg9C/aNzXIgmly10jqNAoo7NDA2BTcrlq0uLa8xBAkBl\n" + + "7Hs+I1XnZXDIO4Rn1VRysN9rRj15ipnbDAuoUwUl7tDUMBFteg2e0kZCW/6NHIgC\n" + + "0aG6fLgVOdY+qi4lYtfFAkEAqqiBgEgSrDmnJLTm6j/Pv1mBA6b9bJbjOqomrDtr\n" + + "AWTXe+/kSCv/jYYdpNA/tDgAwEmtkWWEie6+SwJB5cXXqg==\n" + + "-----END RSA PRIVATE KEY-----\n")).readPemObject().getContent(); + + + OpenSSHPublicKeySpec pubSpec = new OpenSSHPublicKeySpec(rawPub); + OpenSSHPrivateKeySpec privSpec = new OpenSSHPrivateKeySpec(rawPriv); + + isEquals("Pk type", pubSpec.getType(), "ssh-rsa"); + isEquals("Spec Type", privSpec.getFormat(), "ASN.1"); + + + byte[] originalMessage = new byte[10]; + secureRandom.nextBytes(originalMessage); + + originalMessage[0] |= 1; + + KeyFactory kpf = KeyFactory.getInstance("RSA", "BC"); + + PublicKey pk = kpf.generatePublic(pubSpec); + PrivateKey prk = kpf.generatePrivate(privSpec); + + OpenSSHPublicKeySpec rcPublicKeySpec = (OpenSSHPublicKeySpec)kpf.getKeySpec(pk, OpenSSHPublicKeySpec.class); + OpenSSHPrivateKeySpec rcPrivateSpec = (OpenSSHPrivateKeySpec)kpf.getKeySpec(prk, OpenSSHPrivateKeySpec.class); + + isEquals("Pk type", rcPublicKeySpec.getType(), "ssh-rsa"); + isEquals("Spec Type", rcPrivateSpec.getFormat(), "ASN.1"); + + isTrue("RSAPublic key not same", Arrays.areEqual(rawPub, rcPublicKeySpec.getEncoded())); + isTrue("RSAPrivate key not same", Arrays.areEqual(rawPriv, rcPrivateSpec.getEncoded())); + + } + + public void testEncodingDSA() + throws Exception + { + byte[] rawPub = Base64.decode("AAAAB3NzaC1kc3MAAACBAJBB5+S4kZZYZLswaQ/zm3GM7YWmHsumwo/Xxu+z6Cg2l5PUoiBBZ4ET9EhhQuL2ja/zrCMCi0ZwiSRuSp36ayPrHLbNJb3VdOuJg8xExRa6F3YfVZfcTPUEKh6FU72fI31HrQmi4rpyHnWxL/iDX496ZG2Hdq6UkPISQpQwj4TtAAAAFQCP9TXcVahR/2rpfEhvdXR0PfhbRwAAAIBdXzAVqoOtb9zog6lNF1cGS1S06W9W/clvuwq2xF1s3bkoI/xUbFSc0IAPsGl2kcB61PAZqcop50lgpvYzt8cq/tbqz3ypq1dCQ0xdmJHj975QsRFax+w6xQ0kgpBhwcS2EOizKb+C+tRzndGpcDSoSMuVXp9i4wn5pJSTZxAYFQAAAIEAhQZc687zYxrEDR/1q6m4hw5GFxuVvLsC+bSHtMF0c11Qy4IPg7mBeP7K5Kq4WyJPtmZhuc5Bb12bJQR6qgd1uLn692fe1UK2kM6eWXBzhlzZ54BslfSKHGNN4qH+ln3Zaf/4rpKE7fvoinkrgkOZmj0PMx9D6wlpHKkXMUxeXtc="); + byte[] rawPriv = new PemReader(new StringReader("-----BEGIN DSA PRIVATE KEY-----\n" + + "MIIBuwIBAAKBgQCQQefkuJGWWGS7MGkP85txjO2Fph7LpsKP18bvs+goNpeT1KIg\n" + + "QWeBE/RIYULi9o2v86wjAotGcIkkbkqd+msj6xy2zSW91XTriYPMRMUWuhd2H1WX\n" + + "3Ez1BCoehVO9nyN9R60JouK6ch51sS/4g1+PemRth3aulJDyEkKUMI+E7QIVAI/1\n" + + "NdxVqFH/aul8SG91dHQ9+FtHAoGAXV8wFaqDrW/c6IOpTRdXBktUtOlvVv3Jb7sK\n" + + "tsRdbN25KCP8VGxUnNCAD7BpdpHAetTwGanKKedJYKb2M7fHKv7W6s98qatXQkNM\n" + + "XZiR4/e+ULERWsfsOsUNJIKQYcHEthDosym/gvrUc53RqXA0qEjLlV6fYuMJ+aSU\n" + + "k2cQGBUCgYEAhQZc687zYxrEDR/1q6m4hw5GFxuVvLsC+bSHtMF0c11Qy4IPg7mB\n" + + "eP7K5Kq4WyJPtmZhuc5Bb12bJQR6qgd1uLn692fe1UK2kM6eWXBzhlzZ54BslfSK\n" + + "HGNN4qH+ln3Zaf/4rpKE7fvoinkrgkOZmj0PMx9D6wlpHKkXMUxeXtcCFELnLOJ8\n" + + "D0akSCUFY/iDLo/KnOIH\n" + + "-----END DSA PRIVATE KEY-----\n")).readPemObject().getContent(); + + + OpenSSHPublicKeySpec pubSpec = new OpenSSHPublicKeySpec(rawPub); + OpenSSHPrivateKeySpec privSpec = new OpenSSHPrivateKeySpec(rawPriv); + + isEquals("Pk type", pubSpec.getType(), "ssh-dss"); + isEquals("Spec Type", privSpec.getFormat(), "ASN.1"); + + + byte[] originalMessage = new byte[10]; + secureRandom.nextBytes(originalMessage); + + + originalMessage[0] |= 1; + + KeyFactory kpf = KeyFactory.getInstance("DSA", "BC"); + + PublicKey pk = kpf.generatePublic(pubSpec); + PrivateKey prk = kpf.generatePrivate(privSpec); + + OpenSSHPublicKeySpec dsaPublicKeySpec = (OpenSSHPublicKeySpec)kpf.getKeySpec(pk, OpenSSHPublicKeySpec.class); + OpenSSHPrivateKeySpec dsaPrivateSpec = (OpenSSHPrivateKeySpec)kpf.getKeySpec(prk, OpenSSHPrivateKeySpec.class); + + isEquals("Pk type", dsaPublicKeySpec.getType(), "ssh-dss"); + isEquals("Spec Type", dsaPrivateSpec.getFormat(), "ASN.1"); + + isTrue("DSA Public key not same", Arrays.areEqual(rawPub, dsaPublicKeySpec.getEncoded())); + isTrue("DSA Private key not same", Arrays.areEqual(rawPriv, dsaPrivateSpec.getEncoded())); + + } + + private void testEncodingECDSA() + throws Exception + { + byte[] rawPub = Base64.decode("AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBHq5qxGqnh93Gpbj2w1Avx1UwBl6z5bZC3Viog1yNHDZYcV6Da4YQ3i0/hN7xY7sUy9dNF6g16tJSYXQQ4tvO3g="); + byte[] rawPriv = new PemReader(new StringReader("-----BEGIN EC PRIVATE KEY-----\n" + + "MHcCAQEEIHeg/+m02j6nr4bO8ubfbzhs0fqOjiuIoWbvGnVg+FmpoAoGCCqGSM49\n" + + "AwEHoUQDQgAEermrEaqeH3caluPbDUC/HVTAGXrPltkLdWKiDXI0cNlhxXoNrhhD\n" + + "eLT+E3vFjuxTL100XqDXq0lJhdBDi287eA==\n" + + "-----END EC PRIVATE KEY-----\n")).readPemObject().getContent(); + + OpenSSHPublicKeySpec pubSpec = new OpenSSHPublicKeySpec(rawPub); + OpenSSHPrivateKeySpec privSpec = new OpenSSHPrivateKeySpec(rawPriv); + + isEquals("ecdsa-sha2-nistp256", pubSpec.getType()); + isEquals("Spec Type", privSpec.getFormat(), "ASN.1"); + + KeyFactory kpf = KeyFactory.getInstance("EC", "BC"); + + PublicKey pk = kpf.generatePublic(pubSpec); + PrivateKey prk = kpf.generatePrivate(privSpec); + + OpenSSHPublicKeySpec ecdsaPublicKeySpec = (OpenSSHPublicKeySpec)kpf.getKeySpec(pk, OpenSSHPublicKeySpec.class); + OpenSSHPrivateKeySpec ecdsaPrivateSpec = (OpenSSHPrivateKeySpec)kpf.getKeySpec(prk, OpenSSHPrivateKeySpec.class); + + isEquals("Spec Type", ecdsaPrivateSpec.getFormat(), "ASN.1"); + + isTrue("ECPublic key not same", Arrays.areEqual(rawPub, ecdsaPublicKeySpec.getEncoded())); + isTrue("ECPrivate key not same", Arrays.areEqual(rawPriv, ecdsaPrivateSpec.getEncoded())); + + isEquals("ecdsa-sha2-nistp256", ecdsaPublicKeySpec.getType()); + } + + public void testED25519() + throws Exception + { + byte[] rawPub = Base64.decode("AAAAC3NzaC1lZDI1NTE5AAAAIM4CaV7WQcy0lht0hclgXf4Olyvzvv2fnUvQ3J8IYsWF"); + byte[] rawPriv = new PemReader(new StringReader("-----BEGIN OPENSSH PRIVATE KEY-----\n" + + "b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW\n" + + "QyNTUxOQAAACDOAmle1kHMtJYbdIXJYF3+Dpcr8779n51L0NyfCGLFhQAAAKBTr4PvU6+D\n" + + "7wAAAAtzc2gtZWQyNTUxOQAAACDOAmle1kHMtJYbdIXJYF3+Dpcr8779n51L0NyfCGLFhQ\n" + + "AAAED4BTHeR3YD7CFQqusztfL5K+YSD4mRGLBwb7jHiXxIJM4CaV7WQcy0lht0hclgXf4O\n" + + "lyvzvv2fnUvQ3J8IYsWFAAAAG21lZ2Fud29vZHNAdHljaGUtMzI2NS5sb2NhbAEC\n" + + "-----END OPENSSH PRIVATE KEY-----\n")).readPemObject().getContent(); + + OpenSSHPublicKeySpec pubSpec = new OpenSSHPublicKeySpec(rawPub); + OpenSSHPrivateKeySpec privSpec = new OpenSSHPrivateKeySpec(rawPriv); + + isEquals("Pk type", pubSpec.getType(), "ssh-ed25519"); + isEquals("Spec Type", privSpec.getFormat(), "OpenSSH"); + + KeyFactory kpf = KeyFactory.getInstance("ED25519", "BC"); + + PublicKey pk = kpf.generatePublic(pubSpec); + PrivateKey prk = kpf.generatePrivate(privSpec); + + OpenSSHPublicKeySpec edDsaPublicKeySpec = (OpenSSHPublicKeySpec)kpf.getKeySpec(pk, OpenSSHPublicKeySpec.class); + OpenSSHPrivateKeySpec edDsaPrivateKeySpec = (OpenSSHPrivateKeySpec)kpf.getKeySpec(prk, OpenSSHPrivateKeySpec.class); + + isEquals("Pk type", edDsaPublicKeySpec.getType(), "ssh-ed25519"); + isEquals("Spec Type", edDsaPrivateKeySpec.getFormat(), "OpenSSH"); + + + isTrue("EDPublic key not same", Arrays.areEqual(rawPub, edDsaPublicKeySpec.getEncoded())); + + // EdEc private keys include a random check int, so we check around it. + byte[] enc = edDsaPrivateKeySpec.getEncoded(); + byte[] base = Hex.decode("6f70656e7373682d6b65792d763100000000046e6f6e65000000046e6f6e650000000000000001000000330000000b7373682d6564323535313900000020ce02695ed641ccb4961b7485c9605dfe0e972bf3befd9f9d4bd0dc9f0862c58500000088"); + byte[] tail = Hex.decode("0000000b7373682d6564323535313900000020ce02695ed641ccb4961b7485c9605dfe0e972bf3befd9f9d4bd0dc9f0862c58500000040f80531de477603ec2150aaeb33b5f2f92be6120f899118b0706fb8c7897c4824ce02695ed641ccb4961b7485c9605dfe0e972bf3befd9f9d4bd0dc9f0862c585000000000102030405"); + isTrue("EDPrivate key base not same", Arrays.areEqual(base, Arrays.copyOfRange(enc, 0, base.length))); + isTrue("EDPrivate key tail not same", Arrays.areEqual(tail, Arrays.copyOfRange(enc, base.length + 8, enc.length))); + + isEquals("ssh-ed25519", edDsaPublicKeySpec.getType()); + } + + public String getName() + { + return "OpenSSHSpec"; + } + + public void performTest() + throws Exception + { + testEncodingDSA(); + testEncodingRSA(); + testEncodingECDSA(); + testED25519(); + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new OpenSSHSpecTests()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PBETest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PBETest.java new file mode 100644 index 000000000..809a5de1f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PBETest.java @@ -0,0 +1,821 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.Security; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.InvalidParameterSpecException; +import java.security.spec.KeySpec; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.PBEParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.asn1.bc.BCObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.PBEParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.generators.PKCS12ParametersGenerator; +import com.fr.third.org.bouncycastle.crypto.params.KeyParameter; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithIV; +import com.fr.third.org.bouncycastle.jcajce.PKCS12Key; +import com.fr.third.org.bouncycastle.jcajce.PKCS12KeyWithParameters; +import com.fr.third.org.bouncycastle.jcajce.provider.symmetric.util.BCPBEKey; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * test out the various PBE modes, making sure the JCE implementations + * are compatible woth the light weight ones. + */ +public class PBETest + extends SimpleTest +{ + private class OpenSSLTest + extends SimpleTest + { + char[] password; + String baseAlgorithm; + String algorithm; + int keySize; + int ivSize; + + OpenSSLTest( + String baseAlgorithm, + String algorithm, + int keySize, + int ivSize) + { + this.password = algorithm.toCharArray(); + this.baseAlgorithm = baseAlgorithm; + this.algorithm = algorithm; + this.keySize = keySize; + this.ivSize = ivSize; + } + + public String getName() + { + return "OpenSSLPBE"; + } + + public void performTest() + throws Exception + { + byte[] salt = new byte[16]; + int iCount = 100; + + for (int i = 0; i != salt.length; i++) + { + salt[i] = (byte)i; + } + + OpenSSLPBEParametersGenerator pGen = new OpenSSLPBEParametersGenerator(); + + pGen.init( + PBEParametersGenerator.PKCS5PasswordToBytes(password), + salt, + iCount); + + ParametersWithIV params = (ParametersWithIV)pGen.generateDerivedParameters(keySize, ivSize); + + SecretKeySpec encKey = new SecretKeySpec(((KeyParameter)params.getParameters()).getKey(), baseAlgorithm); + + Cipher c; + + if (baseAlgorithm.equals("RC4")) + { + c = Cipher.getInstance(baseAlgorithm, "BC"); + + c.init(Cipher.ENCRYPT_MODE, encKey); + } + else + { + c = Cipher.getInstance(baseAlgorithm + "/CBC/PKCS7Padding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, encKey, new IvParameterSpec(params.getIV())); + } + + byte[] enc = c.doFinal(salt); + + c = Cipher.getInstance(algorithm, "BC"); + + PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount); + SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm, "BC"); + + c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec)); + + byte[] dec = c.doFinal(enc); + + if (!Arrays.areEqual(salt, dec)) + { + fail("" + algorithm + "failed encryption/decryption test"); + } + } + } + + private class PKCS12Test + extends SimpleTest + { + char[] password; + String baseAlgorithm; + String algorithm; + Digest digest; + int keySize; + int ivSize; + + PKCS12Test( + String baseAlgorithm, + String algorithm, + Digest digest, + int keySize, + int ivSize) + { + this.password = algorithm.toCharArray(); + this.baseAlgorithm = baseAlgorithm; + this.algorithm = algorithm; + this.digest = digest; + this.keySize = keySize; + this.ivSize = ivSize; + } + + public String getName() + { + return "PKCS12PBE"; + } + + public void performTest() + throws Exception + { + byte[] salt = new byte[digest.getDigestSize()]; + int iCount = 100; + + digest.doFinal(salt, 0); + + PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(digest); + + pGen.init( + PBEParametersGenerator.PKCS12PasswordToBytes(password), + salt, + iCount); + + ParametersWithIV params = (ParametersWithIV)pGen.generateDerivedParameters(keySize, ivSize); + + SecretKeySpec encKey = new SecretKeySpec(((KeyParameter)params.getParameters()).getKey(), baseAlgorithm); + + Cipher c; + + if (baseAlgorithm.equals("RC4")) + { + c = Cipher.getInstance(baseAlgorithm, "BC"); + + c.init(Cipher.ENCRYPT_MODE, encKey); + } + else + { + c = Cipher.getInstance(baseAlgorithm + "/CBC/PKCS7Padding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, encKey, new IvParameterSpec(params.getIV())); + } + + byte[] enc = c.doFinal(salt); + + c = Cipher.getInstance(algorithm, "BC"); + + PBEKeySpec keySpec = new PBEKeySpec(password, salt, iCount); + SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm, "BC"); + + c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec)); + + byte[] dec = c.doFinal(enc); + + if (!Arrays.areEqual(salt, dec)) + { + fail("" + algorithm + "failed encryption/decryption test"); + } + + // + // get the parameters + // + AlgorithmParameters param = checkParameters(c, salt, iCount); + + // + // try using parameters + // + c = Cipher.getInstance(algorithm, "BC"); + + keySpec = new PBEKeySpec(password); + + c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec), param); + + checkParameters(c, salt, iCount); + + dec = c.doFinal(enc); + + if (!Arrays.areEqual(salt, dec)) + { + fail("" + algorithm + "failed encryption/decryption test"); + } + + // + // try using PBESpec + // + c = Cipher.getInstance(algorithm, "BC"); + + keySpec = new PBEKeySpec(password); + + c.init(Cipher.DECRYPT_MODE, fact.generateSecret(keySpec), param.getParameterSpec(PBEParameterSpec.class)); + + checkParameters(c, salt, iCount); + + dec = c.doFinal(enc); + + if (!Arrays.areEqual(salt, dec)) + { + fail("" + algorithm + "failed encryption/decryption test"); + } + } + + private AlgorithmParameters checkParameters(Cipher c, byte[] salt, int iCount) + throws InvalidParameterSpecException + { + AlgorithmParameters param = c.getParameters(); + PBEParameterSpec spec = (PBEParameterSpec)param.getParameterSpec(PBEParameterSpec.class); + + if (!Arrays.areEqual(salt, spec.getSalt())) + { + fail("" + algorithm + "failed salt test"); + } + + if (iCount != spec.getIterationCount()) + { + fail("" + algorithm + "failed count test"); + } + return param; + } + } + + private PKCS12Test[] pkcs12Tests = { + new PKCS12Test("DESede", "PBEWITHSHAAND3-KEYTRIPLEDES-CBC", new SHA1Digest(), 192, 64), + new PKCS12Test("DESede", "PBEWITHSHAAND2-KEYTRIPLEDES-CBC", new SHA1Digest(), 128, 64), + new PKCS12Test("RC4", "PBEWITHSHAAND128BITRC4", new SHA1Digest(), 128, 0), + new PKCS12Test("RC4", "PBEWITHSHAAND40BITRC4", new SHA1Digest(), 40, 0), + new PKCS12Test("RC2", "PBEWITHSHAAND128BITRC2-CBC", new SHA1Digest(), 128, 64), + new PKCS12Test("RC2", "PBEWITHSHAAND40BITRC2-CBC", new SHA1Digest(), 40, 64), + new PKCS12Test("AES", "PBEWithSHA1And128BitAES-CBC-BC", new SHA1Digest(), 128, 128), + new PKCS12Test("AES", "PBEWithSHA1And192BitAES-CBC-BC", new SHA1Digest(), 192, 128), + new PKCS12Test("AES", "PBEWithSHA1And256BitAES-CBC-BC", new SHA1Digest(), 256, 128), + new PKCS12Test("AES", "PBEWithSHA256And128BitAES-CBC-BC", new SHA256Digest(), 128, 128), + new PKCS12Test("AES", "PBEWithSHA256And192BitAES-CBC-BC", new SHA256Digest(), 192, 128), + new PKCS12Test("AES", "PBEWithSHA256And256BitAES-CBC-BC", new SHA256Digest(), 256, 128), + new PKCS12Test("Twofish","PBEWithSHAAndTwofish-CBC", new SHA1Digest(), 256, 128), + new PKCS12Test("IDEA", "PBEWithSHAAndIDEA-CBC", new SHA1Digest(), 128, 64), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes128_cbc.getId(), new SHA1Digest(), 128, 128), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes192_cbc.getId(), new SHA1Digest(), 192, 128), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha1_pkcs12_aes256_cbc.getId(), new SHA1Digest(), 256, 128), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes128_cbc.getId(), new SHA256Digest(), 128, 128), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes192_cbc.getId(), new SHA256Digest(), 192, 128), + new PKCS12Test("AES", BCObjectIdentifiers.bc_pbe_sha256_pkcs12_aes256_cbc.getId(), new SHA256Digest(), 256, 128), + }; + + private OpenSSLTest openSSLTests[] = { + new OpenSSLTest("AES", "PBEWITHMD5AND128BITAES-CBC-OPENSSL", 128, 128), + new OpenSSLTest("AES", "PBEWITHMD5AND192BITAES-CBC-OPENSSL", 192, 128), + new OpenSSLTest("AES", "PBEWITHMD5AND256BITAES-CBC-OPENSSL", 256, 128) + }; + + static byte[] message = Hex.decode("4869205468657265"); + + private byte[] hMac1 = Hex.decode("bcc42174ccb04f425d9a5c8c4a95d6fd7c372911"); + private byte[] hMac2 = Hex.decode("cb1d8bdb6aca9e3fa8980d6eb41ab28a7eb2cfd6"); + private byte[] hMac3 = Hex.decode("514aa173a302c770689269aac08eb8698e5879ac"); + private byte[] hMac4 = Hex.decode("d24b4eb0e5bd611d4ca88bd6428d14ee2e004c7e"); + + private Cipher makePBECipherUsingParam( + String algorithm, + int mode, + char[] password, + byte[] salt, + int iterationCount) + throws Exception + { + PBEKeySpec pbeSpec = new PBEKeySpec(password); + SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, "BC"); + PBEParameterSpec defParams = new PBEParameterSpec(salt, iterationCount); + + Cipher cipher = Cipher.getInstance(algorithm, "BC"); + + cipher.init(mode, keyFact.generateSecret(pbeSpec), defParams); + + return cipher; + } + + private Cipher makePBECipherWithoutParam( + String algorithm, + int mode, + char[] password, + byte[] salt, + int iterationCount) + throws Exception + { + PBEKeySpec pbeSpec = new PBEKeySpec(password, salt, iterationCount); + SecretKeyFactory keyFact = SecretKeyFactory.getInstance(algorithm, "BC"); + + Cipher cipher = Cipher.getInstance(algorithm, "BC"); + + cipher.init(mode, keyFact.generateSecret(pbeSpec)); + + return cipher; + } + + public void testPBEHMac( + String hmacName, + byte[] output) + { + SecretKey key; + byte[] out; + Mac mac; + + try + { + SecretKeyFactory fact = SecretKeyFactory.getInstance(hmacName, "BC"); + + key = fact.generateSecret(new PBEKeySpec("hello".toCharArray())); + + mac = Mac.getInstance(hmacName, "BC"); + } + catch (Exception e) + { + fail("Failed - exception " + e.toString(), e); + return; + } + + try + { + mac.init(key, new PBEParameterSpec(new byte[20], 100)); + } + catch (Exception e) + { + fail("Failed - exception " + e.toString(), e); + return; + } + + mac.reset(); + + mac.update(message, 0, message.length); + + out = mac.doFinal(); + + if (!Arrays.areEqual(out, output)) + { + fail("Failed - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + public void testPKCS12HMac( + String hmacName, + byte[] output) + { + SecretKey key; + byte[] out; + Mac mac; + + try + { + mac = Mac.getInstance(hmacName, "BC"); + } + catch (Exception e) + { + fail("Failed - exception " + e.toString(), e); + return; + } + + try + { + mac.init(new PKCS12Key("hello".toCharArray()), new PBEParameterSpec(new byte[20], 100)); + } + catch (Exception e) + { + fail("Failed - exception " + e.toString(), e); + return; + } + + mac.reset(); + + mac.update(message, 0, message.length); + + out = mac.doFinal(); + + if (!Arrays.areEqual(out, output)) + { + fail("Failed - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + public void testPBEonSecretKeyHmac( + String hmacName, + byte[] output) + { + SecretKey key; + byte[] out; + Mac mac; + + try + { + SecretKeyFactory fact = SecretKeyFactory.getInstance(hmacName, "BC"); + + key = fact.generateSecret(new PBEKeySpec("hello".toCharArray(), new byte[20], 100, 160)); + } + catch (Exception e) + { + fail("Failed - exception " + e.toString(), e); + return; + } + + try + { + mac = Mac.getInstance("HMAC-SHA1", "BC"); + + mac.init(key); + } + catch (Exception e) + { + fail("Failed - exception " + e.toString(), e); + return; + } + + mac.reset(); + + mac.update(message, 0, message.length); + + out = mac.doFinal(); + + if (!Arrays.areEqual(out, output)) + { + fail("Failed - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(out))); + } + } + + private void testCipherNameWithWrap(String name, String simpleName) + throws Exception + { + KeyGenerator kg = KeyGenerator.getInstance("AES"); + kg.init(new SecureRandom()); + SecretKey key = kg.generateKey(); + + byte[] salt = { + (byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c, + (byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99 + }; + char[] password = { 'p','a','s','s','w','o','r','d' }; + + PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 20); + PBEKeySpec pbeKeySpec = new PBEKeySpec(password); + SecretKeyFactory keyFac = + SecretKeyFactory.getInstance(name); + SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec); + Cipher pbeEncryptCipher = Cipher.getInstance(name, "BC"); + + pbeEncryptCipher.init(Cipher.WRAP_MODE, pbeKey, pbeParamSpec); + + byte[] symKeyBytes = pbeEncryptCipher.wrap(key); + + Cipher simpleCipher = Cipher.getInstance(simpleName, "BC"); + + simpleCipher.init(Cipher.UNWRAP_MODE, pbeKey, pbeParamSpec); + + SecretKey unwrappedKey = (SecretKey)simpleCipher.unwrap(symKeyBytes, "AES", Cipher.SECRET_KEY); + + if (!Arrays.areEqual(unwrappedKey.getEncoded(), key.getEncoded())) + { + fail("key mismatch on unwrapping"); + } + } + + public void testNullSalt() + throws Exception + { + SecretKeyFactory skf = SecretKeyFactory.getInstance("PBEWITHSHAAND128BITAES-CBC-BC"); + Key key = skf.generateSecret(new PBEKeySpec("secret".toCharArray())); + + Cipher cipher = Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC"); + + try + { + cipher.init(Cipher.ENCRYPT_MODE, key, (AlgorithmParameterSpec)null); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("wrong message", "PBEKey requires parameters to specify salt".equals(e.getMessage())); + } + } + + public void performTest() + throws Exception + { + byte[] input = Hex.decode("1234567890abcdefabcdef1234567890fedbca098765"); + + // + // DES + // + Cipher cEnc = Cipher.getInstance("DES/CBC/PKCS7Padding", "BC"); + + cEnc.init(Cipher.ENCRYPT_MODE, + new SecretKeySpec(Hex.decode("30e69252758e5346"), "DES"), + new IvParameterSpec(Hex.decode("7c1c1ab9c454a688"))); + + byte[] out = cEnc.doFinal(input); + + char[] password = { 'p', 'a', 's', 's', 'w', 'o', 'r', 'd' }; + + Cipher cDec = makePBECipherUsingParam( + "PBEWithSHA1AndDES", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); + + byte[] in = cDec.doFinal(out); + + if (!Arrays.areEqual(input, in)) + { + fail("DES failed"); + } + + cDec = makePBECipherWithoutParam( + "PBEWithSHA1AndDES", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); + + in = cDec.doFinal(out); + + if (!Arrays.areEqual(input, in)) + { + fail("DES failed without param"); + } + + // + // DESede + // + cEnc = Cipher.getInstance("DESede/CBC/PKCS7Padding", "BC"); + + cEnc.init(Cipher.ENCRYPT_MODE, + new SecretKeySpec(Hex.decode("732f2d33c801732b7206756cbd44f9c1c103ddd97c7cbe8e"), "DES"), + new IvParameterSpec(Hex.decode("b07bf522c8d608b8"))); + + out = cEnc.doFinal(input); + + cDec = makePBECipherUsingParam( + "PBEWithSHAAnd3-KeyTripleDES-CBC", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); + + in = cDec.doFinal(out); + + if (!Arrays.areEqual(input, in)) + { + fail("DESede failed"); + } + + // + // 40Bit RC2 + // + cEnc = Cipher.getInstance("RC2/CBC/PKCS7Padding", "BC"); + + cEnc.init(Cipher.ENCRYPT_MODE, + new SecretKeySpec(Hex.decode("732f2d33c8"), "RC2"), + new IvParameterSpec(Hex.decode("b07bf522c8d608b8"))); + + out = cEnc.doFinal(input); + + cDec = makePBECipherUsingParam( + "PBEWithSHAAnd40BitRC2-CBC", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); + + in = cDec.doFinal(out); + + if (!Arrays.areEqual(input, in)) + { + fail("RC2 failed"); + } + + // + // 128bit RC4 + // + cEnc = Cipher.getInstance("RC4", "BC"); + + cEnc.init(Cipher.ENCRYPT_MODE, + new SecretKeySpec(Hex.decode("732f2d33c801732b7206756cbd44f9c1"), "RC4")); + + out = cEnc.doFinal(input); + + cDec = makePBECipherUsingParam( + "PBEWithSHAAnd128BitRC4", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); + + in = cDec.doFinal(out); + + if (!Arrays.areEqual(input, in)) + { + fail("RC4 failed"); + } + + cDec = makePBECipherWithoutParam( + "PBEWithSHAAnd128BitRC4", + Cipher.DECRYPT_MODE, + password, + Hex.decode("7d60435f02e9e0ae"), + 2048); + + in = cDec.doFinal(out); + + if (!Arrays.areEqual(input, in)) + { + fail("RC4 failed without param"); + } + + for (int i = 0; i != pkcs12Tests.length; i++) + { + pkcs12Tests[i].perform(); + } + + for (int i = 0; i != openSSLTests.length; i++) + { + openSSLTests[i].perform(); + } + + testPKCS12Interop(); + + testPBEHMac("PBEWithHMacSHA1", hMac1); + testPBEHMac("PBEWithHMacRIPEMD160", hMac2); + + testPBEonSecretKeyHmac("PBKDF2WithHmacSHA1", hMac3); + testPBEonSecretKeyHmac("PBKDF2WithHMacSM3", hMac4); + + testCipherNameWithWrap("PBEWITHSHA256AND128BITAES-CBC-BC", "AES/CBC/PKCS5Padding"); + testCipherNameWithWrap("PBEWITHSHAAND40BITRC4", "RC4"); + testCipherNameWithWrap("PBEWITHSHAAND128BITRC4", "RC4"); + + checkPBE("PBKDF2WithHmacSHA1", true, "f14687fc31a66e2f7cc01d0a65f687961bd27e20", "6f6579193d6433a3e4600b243bb390674f04a615"); + + testPKCS12HMac("HMacSHA1", Hex.decode("bcc42174ccb04f425d9a5c8c4a95d6fd7c372911")); + testPKCS12HMac("HMacSHA256", Hex.decode("e1ae77e2d1dcc56a8befa3867ea3ff8c2163b01885504379412e525b120bf9ce")); + testPKCS12HMac("HMacSHA384", Hex.decode("1256a861351db2082f2ba827ca72cede54ee851f533962bba1fd97b500b6d6eb42aa4a51920aca0c817955feaf52d7f8")); + testPKCS12HMac("HMacSHA512", Hex.decode("9090898971914cb2e65eb1b083f1cad1ce9a9d386f963a2e2ede965fbce0a7121526b5f8aed83f81db60b97ced0bc4b0c27cf23407028cc2f289957f607cec98")); + testPKCS12HMac("HMacRIPEMD160", Hex.decode("cb1d8bdb6aca9e3fa8980d6eb41ab28a7eb2cfd6")); + + try + { + Mac mac = Mac.getInstance("HMacRIPEMD256", "BC"); + + mac.init(new PKCS12Key("hello".toCharArray()), new PBEParameterSpec(new byte[20], 100)); + fail("no exception"); + } + catch (InvalidAlgorithmParameterException e) + { + isTrue("wrong exception", "no PKCS12 mapping for HMAC: RIPEMD256/HMAC".equals(e.getMessage())); + } + + testMixedKeyTypes(); + testNullSalt(); + } + + private void testPKCS12Interop() + throws Exception + { + final String algorithm = "PBEWithSHA256And192BitAES-CBC-BC"; + + final PBEKeySpec keySpec = new PBEKeySpec("foo123".toCharArray(), Hex.decode("01020304050607080910"), 1024); + final SecretKeyFactory fact = SecretKeyFactory.getInstance(algorithm, "BC"); + + BCPBEKey bcpbeKey = (BCPBEKey)fact.generateSecret(keySpec); + + Cipher c1 = Cipher.getInstance(algorithm, "BC"); + + c1.init(Cipher.ENCRYPT_MODE, new PKCS12KeyWithParameters("foo123".toCharArray(), Hex.decode("01020304050607080910"), 1024)); + + Cipher c2 = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC"); + + c2.init(Cipher.DECRYPT_MODE, new SecretKeySpec(bcpbeKey.getEncoded(), "AES"), new IvParameterSpec(((ParametersWithIV)bcpbeKey.getParam()).getIV())); + + if (!Arrays.areEqual(Hex.decode("deadbeef"), c2.doFinal(c1.doFinal(Hex.decode("deadbeef"))))) + { + fail("new key failed"); + } + + c1.init(Cipher.ENCRYPT_MODE, bcpbeKey); + + if (!Arrays.areEqual(Hex.decode("deadbeef"), c2.doFinal(c1.doFinal(Hex.decode("deadbeef"))))) + { + fail("old key failed"); + } + } + + private void checkPBE(String baseAlg, boolean defIsUTF8, String utf8, String eightBit) + throws Exception + { + byte[] utf8K = Hex.decode(utf8); + byte[] ascK = Hex.decode(eightBit); + + SecretKeyFactory f = SecretKeyFactory.getInstance(baseAlg, "BC"); + KeySpec ks1 = new PBEKeySpec("\u0141\u0142".toCharArray(), new byte[20], 4096, 160); + if (!Arrays.areEqual((defIsUTF8) ? utf8K : ascK, f.generateSecret(ks1).getEncoded())) + { + fail(baseAlg + " wrong PBKDF2 k1 key generated, got : " + new String(Hex.encode(f.generateSecret(ks1).getEncoded()))); + } + + KeySpec ks2 = new PBEKeySpec("\u0041\u0042".toCharArray(), new byte[20], 4096, 160); + if (!Arrays.areEqual(ascK, f.generateSecret(ks2).getEncoded())) + { + fail(baseAlg + " wrong PBKDF2 k2 key generated"); + } + f = SecretKeyFactory.getInstance(baseAlg + "AndUTF8", "BC"); + ks1 = new PBEKeySpec("\u0141\u0142".toCharArray(), new byte[20], 4096, 160); + if (!Arrays.areEqual(utf8K, f.generateSecret(ks1).getEncoded())) + { + fail(baseAlg + " wrong PBKDF2 k1 utf8 key generated"); + } + + ks2 = new PBEKeySpec("\u0041\u0042".toCharArray(), new byte[20], 4096, 160); + if (!Arrays.areEqual(ascK, f.generateSecret(ks2).getEncoded())) + { + fail(baseAlg + " wrong PBKDF2 k2 utf8 key generated"); + } + f = SecretKeyFactory.getInstance(baseAlg + "And8BIT", "BC"); + ks1 = new PBEKeySpec("\u0141\u0142".toCharArray(), new byte[20], 4096, 160); + if (!Arrays.areEqual(ascK, f.generateSecret(ks1).getEncoded())) + { + fail(baseAlg + " wrong PBKDF2 k1 8bit key generated"); + } + + ks2 = new PBEKeySpec("\u0041\u0042".toCharArray(), new byte[20], 4096, 160); + if (!Arrays.areEqual(ascK, f.generateSecret(ks2).getEncoded())) + { + fail(baseAlg + " wrong PBKDF2 k2 8bit key generated"); + } + } + + // for regression testing only - don't try this at home. + public void testMixedKeyTypes() + throws Exception + { + String provider = "BC"; + SecretKeyFactory skf = + SecretKeyFactory.getInstance("PBKDF2WITHHMACSHA1", provider); + PBEKeySpec pbeks = new PBEKeySpec("password".toCharArray(), Strings.toByteArray("salt"), 100, 128); + SecretKey secretKey = skf.generateSecret(pbeks); + PBEParameterSpec paramSpec = new PBEParameterSpec(pbeks.getSalt(), pbeks.getIterationCount()); + + // in this case pbeSpec picked up from internal class representing key + Cipher cipher = + Cipher.getInstance("PBEWITHSHAAND128BITAES-CBC-BC", provider); + + try + { + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + fail("no exception"); + } + catch (InvalidKeyException e) + { + isTrue("wrong exception", "Algorithm requires a PBE key suitable for PKCS12".equals(e.getMessage())); + } + } + + public String getName() + { + return "PBETest"; + } + + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PBETest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PEMData.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PEMData.java new file mode 100644 index 000000000..58dcbfdaa --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PEMData.java @@ -0,0 +1,114 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +public class PEMData +{ + public static String CERTIFICATE_1 = + "-----BEGIN X509 CERTIFICATE-----\r" + + "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx\r" + + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY\r" + + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB\r" + + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ\r" + + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2\r" + + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW\r" + + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM\r" + + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l\r" + + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv\r" + + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re\r" + + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO\r" + + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE\r" + + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy\r" + + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0\r" + + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw\r" + + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL\r" + + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4\r" + + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF\r" + + "5/8=\r" + + "-----END X509 CERTIFICATE-----\r"; + + public static String CERTIFICATE_2 = + "-----BEGIN CERTIFICATE-----\n" + + "MIIDXjCCAsegAwIBAgIBBzANBgkqhkiG9w0BAQQFADCBtzELMAkGA1UEBhMCQVUx\n" + + "ETAPBgNVBAgTCFZpY3RvcmlhMRgwFgYDVQQHEw9Tb3V0aCBNZWxib3VybmUxGjAY\n" + + "BgNVBAoTEUNvbm5lY3QgNCBQdHkgTHRkMR4wHAYDVQQLExVDZXJ0aWZpY2F0ZSBB\n" + + "dXRob3JpdHkxFTATBgNVBAMTDENvbm5lY3QgNCBDQTEoMCYGCSqGSIb3DQEJARYZ\n" + + "d2VibWFzdGVyQGNvbm5lY3Q0LmNvbS5hdTAeFw0wMDA2MDIwNzU2MjFaFw0wMTA2\n" + + "MDIwNzU2MjFaMIG4MQswCQYDVQQGEwJBVTERMA8GA1UECBMIVmljdG9yaWExGDAW\n" + + "BgNVBAcTD1NvdXRoIE1lbGJvdXJuZTEaMBgGA1UEChMRQ29ubmVjdCA0IFB0eSBM\n" + + "dGQxFzAVBgNVBAsTDldlYnNlcnZlciBUZWFtMR0wGwYDVQQDExR3d3cyLmNvbm5l\n" + + "Y3Q0LmNvbS5hdTEoMCYGCSqGSIb3DQEJARYZd2VibWFzdGVyQGNvbm5lY3Q0LmNv\n" + + "bS5hdTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArvDxclKAhyv7Q/Wmr2re\n" + + "Gw4XL9Cnh9e+6VgWy2AWNy/MVeXdlxzd7QAuc1eOWQkGQEiLPy5XQtTY+sBUJ3AO\n" + + "Rvd2fEVJIcjf29ey7bYua9J/vz5MG2KYo9/WCHIwqD9mmG9g0xLcfwq/s8ZJBswE\n" + + "7sb85VU+h94PTvsWOsWuKaECAwEAAaN3MHUwJAYDVR0RBB0wG4EZd2VibWFzdGVy\n" + + "QGNvbm5lY3Q0LmNvbS5hdTA6BglghkgBhvhCAQ0ELRYrbW9kX3NzbCBnZW5lcmF0\n" + + "ZWQgY3VzdG9tIHNlcnZlciBjZXJ0aWZpY2F0ZTARBglghkgBhvhCAQEEBAMCBkAw\n" + + "DQYJKoZIhvcNAQEEBQADgYEAotccfKpwSsIxM1Hae8DR7M/Rw8dg/RqOWx45HNVL\n" + + "iBS4/3N/TO195yeQKbfmzbAA2jbPVvIvGgTxPgO1MP4ZgvgRhasaa0qCJCkWvpM4\n" + + "yQf33vOiYQbpv4rTwzU8AmRlBG45WdjyNIigGV+oRc61aKCTnLq7zB8N3z1TF/bF\n" + + "5/8=\n" + + "-----END CERTIFICATE-----\n"; + + public static String CRL_1 = + "-----BEGIN X509 CRL-----\r\n" + + "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT\r\n" + + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy\r\n" + + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw\r\n" + + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw\r\n" + + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw\r\n" + + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw\r\n" + + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw\r\n" + + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw\r\n" + + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw\r\n" + + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw\r\n" + + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF\r\n" + + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ\r\n" + + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt\r\n" + + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v\r\n" + + "-----END X509 CRL-----\r\n"; + + public static String CRL_2 = + "-----BEGIN CRL-----\r\n" + + "MIICjTCCAfowDQYJKoZIhvcNAQECBQAwXzELMAkGA1UEBhMCVVMxIDAeBgNVBAoT\r\n" + + "F1JTQSBEYXRhIFNlY3VyaXR5LCBJbmMuMS4wLAYDVQQLEyVTZWN1cmUgU2VydmVy\r\n" + + "IENlcnRpZmljYXRpb24gQXV0aG9yaXR5Fw05NTA1MDIwMjEyMjZaFw05NTA2MDEw\r\n" + + "MDAxNDlaMIIBaDAWAgUCQQAABBcNOTUwMjAxMTcyNDI2WjAWAgUCQQAACRcNOTUw\r\n" + + "MjEwMDIxNjM5WjAWAgUCQQAADxcNOTUwMjI0MDAxMjQ5WjAWAgUCQQAADBcNOTUw\r\n" + + "MjI1MDA0NjQ0WjAWAgUCQQAAGxcNOTUwMzEzMTg0MDQ5WjAWAgUCQQAAFhcNOTUw\r\n" + + "MzE1MTkxNjU0WjAWAgUCQQAAGhcNOTUwMzE1MTk0MDQxWjAWAgUCQQAAHxcNOTUw\r\n" + + "MzI0MTk0NDMzWjAWAgUCcgAABRcNOTUwMzI5MjAwNzExWjAWAgUCcgAAERcNOTUw\r\n" + + "MzMwMDIzNDI2WjAWAgUCQQAAIBcNOTUwNDA3MDExMzIxWjAWAgUCcgAAHhcNOTUw\r\n" + + "NDA4MDAwMjU5WjAWAgUCcgAAQRcNOTUwNDI4MTcxNzI0WjAWAgUCcgAAOBcNOTUw\r\n" + + "NDI4MTcyNzIxWjAWAgUCcgAATBcNOTUwNTAyMDIxMjI2WjANBgkqhkiG9w0BAQIF\r\n" + + "AAN+AHqOEJXSDejYy0UwxxrH/9+N2z5xu/if0J6qQmK92W0hW158wpJg+ovV3+wQ\r\n" + + "wvIEPRL2rocL0tKfAsVq1IawSJzSNgxG0lrcla3MrJBnZ4GaZDu4FutZh72MR3Gt\r\n" + + "JaAL3iTJHJD55kK2D/VoyY1djlsPuNh6AEgdVwFAyp0v\r\n" + + "-----END CRL-----\r\n"; + + static String ATTRIBUTE_CERTIFICATE_1 = + "-----BEGIN X509 ATTRIBUTE CERTIFICATE-----\r\n" + + "MIIBuDCCASECAQEwZ6BlMGCkXjBcMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhl\r\n" + + "IExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFBy\r\n" + + "aW1hcnkgQ2VydGlmaWNhdGUCARSgYjBgpF4wXDELMAkGA1UEBhMCQVUxKDAmBgNV\r\n" + + "BAoTH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxIzAhBgNVBAsTGkJv\r\n" + + "dW5jeSBQcmltYXJ5IENlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAAgEBMCIYDzIw\r\n" + + "MDUwNjEwMDI0MTMzWhgPMjAwNTA2MTAwMjQzMTNaMBkwFwYDVRhIMRAwDoEMREFV\r\n" + + "MTIzNDU2Nzg5MA0GCSqGSIb3DQEBBQUAA4GBALAYXT9zdxSR5zdPLAon1xIPehgI\r\n" + + "NZhjM7w0uu3OdzSV5sC31X1Kx9vi5RIWiM9VimRTwbQIod9POttD5QMXCwQb/fm7\r\n" + + "eiJqL2YBIXOeClB19VrQe8xQtMFbyuFpDiM7QdvIam9ShZZMEMGjv9QHI64M4b0G\r\n" + + "odUBlSsJwPPQjZSU\r\n" + + "-----END X509 ATTRIBUTE CERTIFICATE-----\r\n"; + + static String ATTRIBUTE_CERTIFICATE_2 = + "-----BEGIN ATTRIBUTE CERTIFICATE-----\r\n" + + "MIIBuDCCASECAQEwZ6BlMGCkXjBcMQswCQYDVQQGEwJBVTEoMCYGA1UEChMfVGhl\r\n" + + "IExlZ2lvbiBvZiB0aGUgQm91bmN5IENhc3RsZTEjMCEGA1UECxMaQm91bmN5IFBy\r\n" + + "aW1hcnkgQ2VydGlmaWNhdGUCARSgYjBgpF4wXDELMAkGA1UEBhMCQVUxKDAmBgNV\r\n" + + "BAoTH1RoZSBMZWdpb24gb2YgdGhlIEJvdW5jeSBDYXN0bGUxIzAhBgNVBAsTGkJv\r\n" + + "dW5jeSBQcmltYXJ5IENlcnRpZmljYXRlMA0GCSqGSIb3DQEBBQUAAgEBMCIYDzIw\r\n" + + "MDUwNjEwMDI0MTMzWhgPMjAwNTA2MTAwMjQzMTNaMBkwFwYDVRhIMRAwDoEMREFV\r\n" + + "MTIzNDU2Nzg5MA0GCSqGSIb3DQEBBQUAA4GBALAYXT9zdxSR5zdPLAon1xIPehgI\r\n" + + "NZhjM7w0uu3OdzSV5sC31X1Kx9vi5RIWiM9VimRTwbQIod9POttD5QMXCwQb/fm7\r\n" + + "eiJqL2YBIXOeClB19VrQe8xQtMFbyuFpDiM7QdvIam9ShZZMEMGjv9QHI64M4b0G\r\n" + + "odUBlSsJwPPQjZSU\r\n" + + "-----END ATTRIBUTE CERTIFICATE-----\r\n"; +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKCS10CertRequestTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKCS10CertRequestTest.java new file mode 100644 index 000000000..0049aae01 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKCS10CertRequestTest.java @@ -0,0 +1,546 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.util.Hashtable; +import java.util.Vector; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.Attribute; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.BasicConstraints; +import com.fr.third.org.bouncycastle.asn1.x509.KeyUsage; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectKeyIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x509.X509Extension; +import com.fr.third.org.bouncycastle.asn1.x509.X509Extensions; +import com.fr.third.org.bouncycastle.asn1.x509.X509Name; +import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.jce.ECGOST3410NamedCurveTable; +import com.fr.third.org.bouncycastle.jce.ECNamedCurveTable; +import com.fr.third.org.bouncycastle.jce.PKCS10CertificationRequest; +import com.fr.third.org.bouncycastle.jce.X509Principal; +import com.fr.third.org.bouncycastle.jce.interfaces.ECPointEncoder; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPrivateKeySpec; +import com.fr.third.org.bouncycastle.jce.spec.ECPublicKeySpec; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + **/ +public class PKCS10CertRequestTest + extends SimpleTest +{ + private byte[] gost3410EC_A = Base64.decode( + "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV" + +"BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ" + +"MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMBBgcqhQMCAh4B" + +"A0MABEBYx0P2D7YuuZo5HgdIAUKAXcLBDZ+4LYFgbKjrfStVfH59lc40BQ2FZ7M703hLpXK8GiBQ" + +"GEYpKaAuQZnMIpByoAAwCAYGKoUDAgIDA0EAgXMcTrhdOY2Er2tHOSAgnMezqrYxocZTWhxmW5Rl" + +"JY6lbXH5rndCn4swFzXU+YhgAsJv1wQBaoZEWRl5WV4/nA=="); + + private byte[] gost3410EC_B = Base64.decode( + "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG" + +"A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1" + +"MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICIwIGByqFAwIC" + +"HgEDQwAEQI5SLoWT7dZVilbV9j5B/fyIDuDs6x4pjqNC2TtFYbpRHrk/Wc5g/mcHvD80tsm5o1C7" + +"7cizNzkvAVUM4VT4Dz6gADAIBgYqhQMCAgMDQQAoT5TwJ8o+bSrxckymyo3diwG7ZbSytX4sRiKy" + +"wXPWRS9LlBvPO2NqwpS2HUnxSU8rzfL9fJcybATf7Yt1OEVq"); + + private byte[] gost3410EC_C = Base64.decode( + "MIIBRDCB9AIBADCBhzEVMBMGA1UEAxMMdGVzdCByZXF1ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBM" + +"dGQxHjAcBgNVBAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYD" + +"VQQGEwJydTEZMBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiMD" + +"BgcqhQMCAh4BA0MABEBcmGh7OmR4iqqj+ycYo1S1fS7r5PhisSQU2Ezuz8wmmmR2zeTZkdMYCOBa" + +"UTMNms0msW3wuYDho7nTDNscHTB5oAAwCAYGKoUDAgIDA0EAVoOMbfyo1Un4Ss7WQrUjHJoiaYW8" + +"Ime5LeGGU2iW3ieAv6es/FdMrwTKkqn5dhd3aL/itFg5oQbhyfXw5yw/QQ=="); + + private byte[] gost3410EC_ExA = Base64.decode( + "MIIBOzCB6wIBADB/MQ0wCwYDVQQDEwR0ZXN0MRUwEwYDVQQKEwxEZW1vcyBDbyBMdGQxHjAcBgNV" + + "BAsTFUNyeXB0b2dyYXBoeSBkaXZpc2lvbjEPMA0GA1UEBxMGTW9zY293MQswCQYDVQQGEwJydTEZ" + + "MBcGCSqGSIb3DQEJARYKc2RiQGRvbC5ydTBjMBwGBiqFAwICEzASBgcqhQMCAiQABgcqhQMCAh4B" + + "A0MABEDkqNT/3f8NHj6EUiWnK4JbVZBh31bEpkwq9z3jf0u8ZndG56Vt+K1ZB6EpFxLT7hSIos0w" + + "weZ2YuTZ4w43OgodoAAwCAYGKoUDAgIDA0EASk/IUXWxoi6NtcUGVF23VRV1L3undB4sRZLp4Vho" + + "gQ7m3CMbZFfJ2cPu6QyarseXGYHmazoirH5lGjEo535c1g=="); + + private byte[] gost3410EC_ExB = Base64.decode( + "MIIBPTCB7QIBADCBgDENMAsGA1UEAxMEdGVzdDEWMBQGA1UEChMNRGVtb3MgQ28gTHRkLjEeMBwG" + + "A1UECxMVQ3J5cHRvZ3JhcGh5IGRpdmlzaW9uMQ8wDQYDVQQHEwZNb3Njb3cxCzAJBgNVBAYTAnJ1" + + "MRkwFwYJKoZIhvcNAQkBFgpzZGJAZG9sLnJ1MGMwHAYGKoUDAgITMBIGByqFAwICJAEGByqFAwIC" + + "HgEDQwAEQMBWYUKPy/1Kxad9ChAmgoSWSYOQxRnXo7KEGLU5RNSXA4qMUvArWzvhav+EYUfTbWLh" + + "09nELDyHt2XQcvgQHnSgADAIBgYqhQMCAgMDQQAdaNhgH/ElHp64mbMaEo1tPCg9Q22McxpH8rCz" + + "E0QBpF4H5mSSQVGI5OAXHToetnNuh7gHHSynyCupYDEHTbkZ"); + + public String getName() + { + return "PKCS10CertRequest"; + } + + private void generationTest(int keySize, String keyName, String sigName, String provider) + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance(keyName, "BC"); + + kpg.initialize(keySize); + + KeyPair kp = kpg.genKeyPair(); + + Hashtable attrs = new Hashtable(); + + attrs.put(X509Principal.C, "AU"); + attrs.put(X509Principal.O, "The Legion of the Bouncy Castle"); + attrs.put(X509Principal.L, "Melbourne"); + attrs.put(X509Principal.ST, "Victoria"); + attrs.put(X509Principal.EmailAddress, "feedback-crypto@bouncycastle.org"); + + Vector order = new Vector(); + + order.addElement(X509Principal.C); + order.addElement(X509Principal.O); + order.addElement(X509Principal.L); + order.addElement(X509Principal.ST); + order.addElement(X509Principal.EmailAddress); + + X509Name subject = new X509Name(order, attrs); + + PKCS10CertificationRequest req1 = new PKCS10CertificationRequest( + sigName, + subject, + kp.getPublic(), + null, + kp.getPrivate(), provider); + + byte[] bytes = req1.getEncoded(); + + PKCS10CertificationRequest req2 = new PKCS10CertificationRequest(bytes); + + if (!req2.verify(provider)) + { + fail(sigName + ": Failed verify check."); + } + + if (!req2.getPublicKey(provider).equals(req1.getPublicKey(provider))) + { + fail(keyName + ": Failed public key check."); + } + } + + /* + * we generate a self signed certificate for the sake of testing - SHA224withECDSA + */ + private void createECRequest(String algorithm, ASN1ObjectIdentifier algOid, ASN1ObjectIdentifier curveOid) + throws Exception + { + ECNamedCurveParameterSpec spec = ECNamedCurveTable.getParameterSpec(curveOid.getId()); + KeyPairGenerator ecGen = KeyPairGenerator.getInstance("ECDSA", "BC"); + + ecGen.initialize(spec); + + // + // set up the keys + // + PrivateKey privKey; + PublicKey pubKey; + + KeyPair pair = ecGen.generateKeyPair(); + + privKey = pair.getPrivate(); + pubKey = pair.getPublic(); + + PKCS10CertificationRequest req = new PKCS10CertificationRequest( + algorithm, new X509Name("CN=XXX"), pubKey, null, privKey); + if (!req.verify()) + { + fail("Failed verify check EC."); + } + + req = new PKCS10CertificationRequest(req.getEncoded()); + if (!req.verify()) + { + fail("Failed verify check EC encoded."); + } + + // + // try with point compression turned off + // + ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED"); + + req = new PKCS10CertificationRequest( + algorithm, new X509Name("CN=XXX"), pubKey, null, privKey); + if (!req.verify()) + { + fail("Failed verify check EC uncompressed."); + } + + req = new PKCS10CertificationRequest(req.getEncoded()); + if (!req.verify()) + { + fail("Failed verify check EC uncompressed encoded."); + } + + if (!req.getSignatureAlgorithm().getAlgorithm().equals(algOid)) + { + fail("ECDSA oid incorrect."); + } + + if (req.getSignatureAlgorithm().getParameters() != null) + { + fail("ECDSA parameters incorrect."); + } + + Signature sig = Signature.getInstance(algorithm, "BC"); + + sig.initVerify(pubKey); + + sig.update(req.getCertificationRequestInfo().getEncoded()); + + if (!sig.verify(req.getSignature().getBytes())) + { + fail("signature not mapped correctly."); + } + } + + private void createECRequest(String algorithm, ASN1ObjectIdentifier algOid) + throws Exception + { + X9ECParameters x9 = com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable.getByName("secp521r1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec spec = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + ECPrivateKeySpec privKeySpec = new ECPrivateKeySpec( + new BigInteger("5769183828869504557786041598510887460263120754767955773309066354712783118202294874205844512909370791582896372147797293913785865682804434049019366394746072023"), // d + spec); + + ECPublicKeySpec pubKeySpec = new ECPublicKeySpec( + curve.decodePoint(Hex.decode("02006BFDD2C9278B63C92D6624F151C9D7A822CC75BD983B17D25D74C26740380022D3D8FAF304781E416175EADF4ED6E2B47142D2454A7AC7801DD803CF44A4D1F0AC")), // Q + spec); + + // + // set up the keys + // + PrivateKey privKey; + PublicKey pubKey; + + KeyFactory fact = KeyFactory.getInstance("ECDSA", "BC"); + + privKey = fact.generatePrivate(privKeySpec); + pubKey = fact.generatePublic(pubKeySpec); + + PKCS10CertificationRequest req = new PKCS10CertificationRequest( + algorithm, new X509Name("CN=XXX"), pubKey, null, privKey); + if (!req.verify()) + { + fail("Failed verify check EC."); + } + + req = new PKCS10CertificationRequest(req.getEncoded()); + if (!req.verify()) + { + fail("Failed verify check EC encoded."); + } + + // + // try with point compression turned off + // + ((ECPointEncoder)pubKey).setPointFormat("UNCOMPRESSED"); + + req = new PKCS10CertificationRequest( + algorithm, new X509Name("CN=XXX"), pubKey, null, privKey); + if (!req.verify()) + { + fail("Failed verify check EC uncompressed."); + } + + req = new PKCS10CertificationRequest(req.getEncoded()); + if (!req.verify()) + { + fail("Failed verify check EC uncompressed encoded."); + } + + if (!req.getSignatureAlgorithm().getAlgorithm().equals(algOid)) + { + fail("ECDSA oid incorrect."); + } + + if (req.getSignatureAlgorithm().getParameters() != null) + { + fail("ECDSA parameters incorrect."); + } + + Signature sig = Signature.getInstance(algorithm, "BC"); + + sig.initVerify(pubKey); + + sig.update(req.getCertificationRequestInfo().getEncoded()); + + if (!sig.verify(req.getSignature().getBytes())) + { + fail("signature not mapped correctly."); + } + } + + private void createECGOSTRequest() + throws Exception + { + String algorithm = "GOST3411withECGOST3410"; + KeyPairGenerator ecGostKpg = KeyPairGenerator.getInstance("ECGOST3410", "BC"); + + ecGostKpg.initialize(ECGOST3410NamedCurveTable.getParameterSpec("GostR3410-2001-CryptoPro-A"), new SecureRandom()); + + // + // set up the keys + // + KeyPair pair = ecGostKpg.generateKeyPair(); + PrivateKey privKey = pair.getPrivate(); + PublicKey pubKey = pair.getPublic(); + + PKCS10CertificationRequest req = new PKCS10CertificationRequest( + algorithm, new X509Name("CN=XXX"), pubKey, null, privKey); + if (!req.verify()) + { + fail("Failed verify check EC."); + } + + req = new PKCS10CertificationRequest(req.getEncoded()); + if (!req.verify()) + { + fail("Failed verify check EC encoded."); + } + + if (!req.getSignatureAlgorithm().getAlgorithm().equals(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_2001)) + { + fail("ECGOST oid incorrect."); + } + + if (req.getSignatureAlgorithm().getParameters() != null) + { + fail("ECGOST parameters incorrect."); + } + + Signature sig = Signature.getInstance(algorithm, "BC"); + + sig.initVerify(pubKey); + + sig.update(req.getCertificationRequestInfo().getEncoded()); + + if (!sig.verify(req.getSignature().getBytes())) + { + fail("signature not mapped correctly."); + } + } + + private void createPSSTest(String algorithm) + throws Exception + { + RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16)); + + RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16), + new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16), + new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16), + new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16), + new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16), + new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16), + new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16)); + + KeyFactory fact = KeyFactory.getInstance("RSA", "BC"); + + PrivateKey privKey = fact.generatePrivate(privKeySpec); + PublicKey pubKey = fact.generatePublic(pubKeySpec); + + PKCS10CertificationRequest req = new PKCS10CertificationRequest( + algorithm, new X509Name("CN=XXX"), pubKey, null, privKey); + if (!req.verify()) + { + fail("Failed verify check PSS."); + } + + req = new PKCS10CertificationRequest(req.getEncoded()); + if (!req.verify()) + { + fail("Failed verify check PSS encoded."); + } + + if (!req.getSignatureAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.id_RSASSA_PSS)) + { + fail("PSS oid incorrect."); + } + + if (req.getSignatureAlgorithm().getParameters() == null) + { + fail("PSS parameters incorrect."); + } + + Signature sig = Signature.getInstance(algorithm, "BC"); + + sig.initVerify(pubKey); + + sig.update(req.getCertificationRequestInfo().getEncoded()); + + if (!sig.verify(req.getSignature().getBytes())) + { + fail("signature not mapped correctly."); + } + } + + // previous code found to cause a NullPointerException + private void nullPointerTest() + throws Exception + { + KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", "BC"); + keyGen.initialize(1024, new SecureRandom()); + KeyPair pair = keyGen.generateKeyPair(); + + Vector oids = new Vector(); + Vector values = new Vector(); + oids.add(X509Extensions.BasicConstraints); + values.add(new X509Extension(true, new DEROctetString(new BasicConstraints(true)))); + oids.add(X509Extensions.KeyUsage); + values.add(new X509Extension(true, new DEROctetString( + new KeyUsage(KeyUsage.keyCertSign | KeyUsage.cRLSign)))); + SubjectKeyIdentifier subjectKeyIdentifier = new SubjectKeyIdentifier(getDigest(SubjectPublicKeyInfo.getInstance(pair.getPublic().getEncoded()))); + X509Extension ski = new X509Extension(false, new DEROctetString(subjectKeyIdentifier)); + oids.add(X509Extensions.SubjectKeyIdentifier); + values.add(ski); + + Attribute attribute = new Attribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, + new DERSet(new X509Extensions(oids, values))); + + PKCS10CertificationRequest p1 = new PKCS10CertificationRequest( + "SHA1WithRSA", new X509Principal("cn=csr"), + pair.getPublic(), new DERSet(attribute), pair.getPrivate(), "BC"); + PKCS10CertificationRequest p2 = new PKCS10CertificationRequest( + "SHA1WithRSA", new X509Principal("cn=csr"), + pair.getPublic(), new DERSet(attribute), pair.getPrivate(), "BC"); + + if (!p1.equals(p2)) + { + fail("cert request comparison failed"); + } + } + + public void performTest() + throws Exception + { + generationTest(512, "RSA", "SHA1withRSA", "BC"); + generationTest(512, "GOST3410", "GOST3411withGOST3410", "BC"); + + if (Security.getProvider("SunRsaSign") != null) + { + generationTest(512, "RSA", "SHA1withRSA", "SunRsaSign"); + } + + // elliptic curve GOST A parameter set + PKCS10CertificationRequest req = new PKCS10CertificationRequest(gost3410EC_A); + if (!req.verify()) + { + fail("Failed verify check gost3410EC_A."); + } + + // elliptic curve GOST B parameter set + req = new PKCS10CertificationRequest(gost3410EC_B); + if (!req.verify()) + { + fail("Failed verify check gost3410EC_B."); + } + + // elliptic curve GOST C parameter set + req = new PKCS10CertificationRequest(gost3410EC_C); + if (!req.verify()) + { + fail("Failed verify check gost3410EC_C."); + } + + // elliptic curve GOST ExA parameter set + req = new PKCS10CertificationRequest(gost3410EC_ExA); + if (!req.verify()) + { + fail("Failed verify check gost3410EC_ExA."); + } + + // elliptic curve GOST ExB parameter set + req = new PKCS10CertificationRequest(gost3410EC_ExB); + if (!req.verify()) + { + fail("Failed verify check gost3410EC_ExA."); + } + + // elliptic curve openSSL + KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC"); + + X9ECParameters x9 = com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable.getByName("prime239v1"); + ECCurve curve = x9.getCurve(); + ECParameterSpec ecSpec = new ECParameterSpec(curve, x9.getG(), x9.getN(), x9.getH()); + + g.initialize(ecSpec, new SecureRandom()); + + KeyPair kp = g.generateKeyPair(); + + req = new PKCS10CertificationRequest( + "ECDSAWITHSHA1", new X509Name("CN=XXX"), kp.getPublic(), null, kp.getPrivate()); + if (!req.verify()) + { + fail("Failed verify check EC."); + } + + createECRequest("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1); + createECRequest("SHA224withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA224); + createECRequest("SHA256withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA256); + createECRequest("SHA384withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA384); + createECRequest("SHA512withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA512); + + createECRequest("SHA1withECDSA", X9ObjectIdentifiers.ecdsa_with_SHA1, new ASN1ObjectIdentifier("1.3.132.0.34")); + + createECGOSTRequest(); + + createPSSTest("SHA1withRSAandMGF1"); + createPSSTest("SHA224withRSAandMGF1"); + createPSSTest("SHA256withRSAandMGF1"); + createPSSTest("SHA384withRSAandMGF1"); + + nullPointerTest(); + } + + private static byte[] getDigest(SubjectPublicKeyInfo spki) + { + Digest digest = new SHA1Digest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + + byte[] bytes = spki.getPublicKeyData().getBytes(); + digest.update(bytes, 0, bytes.length); + digest.doFinal(resBuf, 0); + return resBuf; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PKCS10CertRequestTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java new file mode 100644 index 000000000..0f574da9f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKCS12StoreTest.java @@ -0,0 +1,1591 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.Key; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.Signature; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.util.Enumeration; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.asn1.ASN1StreamParser; +import com.fr.third.org.bouncycastle.asn1.DERBMPString; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DLSequenceParser; +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.ContentInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.EncryptedData; +import com.fr.third.org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.MacData; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.Pfx; +import com.fr.third.org.bouncycastle.asn1.pkcs.SafeBag; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.X500NameBuilder; +import com.fr.third.org.bouncycastle.asn1.x500.style.BCStyle; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.jcajce.PKCS12StoreParameter; +import com.fr.third.org.bouncycastle.jce.PKCS12Util; +import com.fr.third.org.bouncycastle.jce.interfaces.PKCS12BagAttributeCarrier; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.provider.JDKPKCS12StoreParameter; +import com.fr.third.org.bouncycastle.jce.provider.X509CertificateObject; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Exercise the various key stores, making sure we at least get back what we put in! + *

+ * This tests both the PKCS12 key store. + */ +public class PKCS12StoreTest + extends SimpleTest +{ + static char[] passwd = { 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd' }; + + // + // pkcs-12 pfx-pdu + // + byte[] pkcs12 = Base64.decode( + "MIACAQMwgAYJKoZIhvcNAQcBoIAkgAQBMAQBgAQBMAQBgAQBBgQBCQQJKoZI" + + "hvcNAQcBBAGgBAGABAEkBAGABAEEBAEBBAEwBAEEBAEDBAOCAzQEAQQEAQEE" + + "ATAEAQQEAQMEA4IDMAQBBAQBAQQBBgQBBAQBAQQBCwQBBAQBCwQLKoZIhvcN" + + "AQwKAQIEAQQEAQEEAaAEAQQEAQMEA4ICpQQBBAQBAQQBMAQBBAQBAwQDggKh" + + "BAEEBAEBBAEwBAEEBAEBBAEbBAEEBAEBBAEGBAEEBAEBBAEKBAEEBAEKBAoq" + + "hkiG9w0BDAEDBAEEBAEPBA8wDQQIoagiwNZPJR4CAQEEAQQEAQEEAQQEAQQE" + + "AQMEA4ICgAQBBAQDggKABIICgEPG0XlhMFyrs4ZWDrvEzl51ICfXd6K2ql2l" + + "nnxhszUbigtSj6x49VEx4PfOB9fQFeidc5L5An+nKp646NBMIY0UwXGs8BLQ" + + "au59jtOs987+l7QYIvl6fdGUIuLPhVSnZZDyqD+HQjU/0/ccKFHRif4tlEQq" + + "aErvZbFeH0pg4ijf1HfgX6gBJGRKdO+msa4qKGnZdHCSLZehyyxvxAmURetg" + + "yhtEl7RmedTB+4TDs7atekqxkNlD9tfwDUX6sb0IH6qbEA6P/DlVMdaD54Cl" + + "QDxRzOfIIjklZhv5OMFWtPK0aYPcqyxzLpw1qRAyoTVXpidkj/hpIpgCVBP/" + + "k5s2+WdGbLgA/4/zSrF6feRCE5llzM2IGxiHVq4oPzzngl3R+Fi5VCPDMcuW" + + "NRuIOzJA+RNV2NPOE/P3knThDnwiImq+rfxmvZ1u6T06s20RmWK6cxp7fTEw" + + "lQ9BOsv+mmyV8dr6cYJq4IlRzHdFOyEUBDwfHThyribNKKobO50xh2f93xYj" + + "Rn5UMOQBJIe3b7OKZt5HOIMrJSZO02IZgvImi9yQWi96PnWa419D1cAsLWvM" + + "xiN0HqZMbDFfxVM2BZmsxiexLhkHWKwLqfQDzRjJfmVww8fnXpWZhFXKyut9" + + "gMGEyCNoba4RU3QI/wHKWYaK74qtJpsucuLWBH6UcsHsCry6VZkwRxWwC0lb" + + "/F3Bm5UKHax5n9JHJ2amQm9zW3WJ0S5stpPObfmg5ArhbPY+pVOsTqBRlop1" + + "bYJLD/X8Qbs468Bwzej0FhoEU59ZxFrbjLSBsMUYrVrwD83JE9kEazMLVchc" + + "uCB9WT1g0hxYb7VA0BhOrWhL8F5ZH72RMCYLPI0EAQQEAQEEATEEAQQEAQEE" + + "AXgEAQQEAQEEATAEAQQEAQEEAVEEAQQEAQEEAQYEAQQEAQEEAQkEAQQEAQkE" + + "CSqGSIb3DQEJFAQBBAQBAQQBMQQBBAQBAQQBRAQBBAQBAQQBHgQBBAQBAQQB" + + "QgQBBAQBQgRCAEQAYQB2AGkAZAAgAEcALgAgAEgAbwBvAGsAJwBzACAAVgBl" + + "AHIAaQBTAGkAZwBuACwAIABJAG4AYwAuACAASQBEBAEEBAEBBAEwBAEEBAEB" + + "BAEjBAEEBAEBBAEGBAEEBAEBBAEJBAEEBAEJBAkqhkiG9w0BCRUEAQQEAQEE" + + "ATEEAQQEAQEEARYEAQQEAQEEAQQEAQQEAQEEARQEAQQEARQEFKEcMJ798oZL" + + "FkH0OnpbUBnrTLgWBAIAAAQCAAAEAgAABAEwBAGABAEGBAEJBAkqhkiG9w0B" + + "BwYEAaAEAYAEATAEAYAEAQIEAQEEAQAEATAEAYAEAQYEAQkECSqGSIb3DQEH" + + "AQQBMAQBGwQBBgQBCgQKKoZIhvcNAQwBBgQPMA0ECEE7euvmxxwYAgEBBAGg" + + "BAGABAEEBAEIBAgQIWDGlBWxnwQBBAQBCAQI2WsMhavhSCcEAQQEAQgECPol" + + "uHJy9bm/BAEEBAEQBBCiRxtllKXkJS2anKD2q3FHBAEEBAEIBAjKy6BRFysf" + + "7gQBBAQDggMwBIIDMJWRGu2ZLZild3oz7UBdpBDUVMOA6eSoWiRIfVTo4++l" + + "RUBm8TpmmGrVkV32PEoLkoV+reqlyWCvqqSjRzi3epQiVwPQ6PV+ccLqxDhV" + + "pGWDRQ5UttDBC2+u4fUQVZi2Z1i1g2tsk6SzB3MKUCrjoWKvaDUUwXo5k9Vz" + + "qSLWCLTZCjs3RaY+jg3NbLZYtfMDdYovhCU2jMYV9adJ8MxxmJRz+zPWAJph" + + "LH8hhfkKG+wJOSszqk9BqGZUa/mnZyzeQSMTEFga1ZB/kt2e8SZFWrTZEBgJ" + + "oszsL5MObbwMDowNurnZsnS+Mf7xi01LeG0VT1fjd6rn9BzVwuMwhoqyoCNo" + + "ziUqSUyLEwnGTYYpvXLxzhNiYzW8546KdoEKDkEjhfYsc4XqSjm9NYy/BW/M" + + "qR+aL92j8hqnkrWkrWyvocUe3mWaiqt7/oOzNZiMTcV2dgjjh9HfnjSHjFGe" + + "CVhnEWzV7dQIVyc/qvNzOuND8X5IyJ28xb6a/i1vScwGuo/UDgPAaMjGw28f" + + "siOZBShzde0Kj82y8NilfYLHHeIGRW+N/grUFWhW25mAcBReXDd5JwOqM/eF" + + "y+4+zBzlO84ws88T1pkSifwtMldglN0APwr4hvUH0swfiqQOWtwyeM4t+bHd" + + "5buAlXOkSeF5rrLzZ2/Lx+JJmI2pJ/CQx3ej3bxPlx/BmarUGAxaI4le5go4" + + "KNfs4GV8U+dbEHQz+yDYL+ksYNs1eb+DjI2khbl28jhoeAFKBtu2gGOL5M9M" + + "CIP/JDOCHimu1YZRuOTAf6WISnG/0Ri3pYZsgQ0i4cXj+WfYwYVjhKX5AcDj" + + "UKnc4/Cxp+TbbgZqEKRcYVb2q0kOAxkeaNo3WCm+qvUYrwAmKp4nVB+/24rK" + + "khHiyYJQsETxtOEyvJkVxAS01djY4amuJ4jL0sYnXIhW3Ag93eavbzksGT7W" + + "Fg1ywpr1x1xpXWIIuVt1k4e+g9fy7Yx7rx0IK1qCSjNwU3QPWbaef1rp0Q/X" + + "P9IVXYkqo1g/T3SyXqrbZLO+sDjiG4IT3z3fJJqt81sRSVT0QN1ND8l93BG4" + + "QKzghYw8sZ4FwKPtLky1dDcVTgQBBAQBCAQIK/85VMKWDWYEAQQEAQgECGsO" + + "Q85CcFwPBAEEBAEIBAhaup6ot9XnQAQBBAQCgaAEgaCeCMadSm5fkLfhErYQ" + + "DgePZl/rrjP9FQ3VJZ13XrjTSjTRknAbXi0DEu2tvAbmCf0sdoVNuZIZ92W0" + + "iyaa2/A3RHA2RLPNQz5meTi1RE2N361yR0q181dC3ztkkJ8PLyd74nCtgPUX" + + "0JlsvLRrdSjPBpBQ14GiM8VjqeIY7EVFy3vte6IbPzodxaviuSc70iXM4Yko" + + "fQq6oaSjNBFRqkHrBAEEBAEIBAjlIvOf8SnfugQBBAQBCAQIutCF3Jovvl0E" + + "AQQEAQgECO7jxbucdp/3BAEEBAEIBAidxK3XDLj+BwQBBAQBCAQI3m/HMbd3" + + "TwwEAQQEA4ICOASCAjgtoCiMfTkjpCRuMhF5gNLRBiNv+xjg6GvZftR12qiJ" + + "dLeCERI5bvXbh9GD6U+DjTUfhEab/37TbiI7VOFzsI/R137sYy9Tbnu7qkSx" + + "u0bTvyXSSmio6sMRiWIcakmDbv+TDWR/xgtj7+7C6p+1jfUGXn/RjB3vlyjL" + + "Q9lFe5F84qkZjnADo66p9gor2a48fgGm/nkABIUeyzFWCiTp9v6FEzuBfeuP" + + "T9qoKSnCitaXRCru5qekF6L5LJHLNXLtIMSrbO0bS3hZK58FZAUVMaqawesJ" + + "e/sVfQip9x/aFQ6U3KlSpJkmZK4TAqp9jIfxBC8CclbuwmoXPMomiCH57ykr" + + "vkFHOGcxRcCxax5HySCwSyPDr8I4+6Kocty61i/1Xr4xJjb+3oyFStIpB24x" + + "+ALb0Mz6mUa1ls76o+iQv0VM2YFwnx+TC8KC1+O4cNOE/gKeh0ircenVX83h" + + "GNez8C5Ltg81g6p9HqZPc2pkwsneX2sJ4jMsjDhewV7TyyS3x3Uy3vTpZPek" + + "VdjYeVIcgAz8VLJOpsIjyHMB57AyT7Yj87hVVy//VODnE1T88tRXZb+D+fCg" + + "lj2weQ/bZtFzDX0ReiEQP6+yklGah59omeklIy9wctGV1o9GNZnGBSLvQ5NI" + + "61e9zmQTJD2iDjihvQA/6+edKswCjGRX6rMjRWXT5Jv436l75DVoUj09tgR9" + + "ytXSathCjQUL9MNXzUMtr7mgEUPETjM/kYBR7CNrsc+gWTWHYaSWuqKVBAEE" + + "BAEIBAh6slfZ6iqkqwQBBAQBCAQI9McJKl5a+UwEAQQEATgEOBelrmiYMay3" + + "q0OW2x2a8QQodYqdUs1TCUU4JhfFGFRy+g3yU1cP/9ZSI8gcI4skdPc31cFG" + + "grP7BAEEBAEIBAhzv/wSV+RBJQQBBAQBCAQI837ImVqqlr4EAQQEAQgECGeU" + + "gjULLnylBAEEBAEIBAjD3P4hlSBCvQQBBAQBCAQISP/qivIzf50EAQQEAQgE" + + "CKIDMX9PKxICBAEEBAOCBOgEggTocP5VVT1vWvpAV6koZupKN1btJ3C01dR6" + + "16g1zJ5FK5xL1PTdA0r6iAwVtgYdxQYnU8tht3bkNXdPJC1BdsC9oTkBg9Nr" + + "dqlF5cCzXWIezcR3ObjGLpXu49SAHvChH4emT5rytv81MYxZ7bGmlQfp8BNa" + + "0cMZz05A56LXw//WWDEzZcbKSk4tCsfMXBdGk/ngs7aILZ4FGM620PBPtD92" + + "pz2Ui/tUZqtQ0WKdLzwga1E/rl02a/x78/OdlVRNeaIYWJWLmLavX98w0PhY" + + "ha3Tbj/fqq+H3ua6Vv2Ff4VeXazkXpp4tTiqUxhc6aAGiRYckwZaP7OPSbos" + + "RKFlRLVofSGu1IVSKO+7faxV4IrVaAAzqRwLGkpJZLV7NkzkU1BwgvsAZAI4" + + "WClPDF228ygbhLwrSN2NK0s+5bKhTCNAR/LCUf3k7uip3ZSe18IwEkUMWiaZ" + + "ayktcTYn2ZjmfIfV7wIxHgWPkP1DeB+RMS7VZe9zEgJKOA16L+9SNBwJSSs9" + + "5Sb1+nmhquZmnAltsXMgwOrR12JLIgdfyyqGcNq997U0/KuHybqBVDVu0Fyr" + + "6O+q5oRmQZq6rju7h+Hb/ZUqRxRoTTSPjGD4Cu9vUqkoNVgwYOT+88FIMYun" + + "g9eChhio2kwPYwU/9BNGGzh+hAvAKcUpO016mGLImYin+FpQxodJXfpNCFpG" + + "4v4HhIwKh71OOfL6ocM/518dYwuU4Ds2/JrDhYYFsn+KprLftjrnTBnSsfYS" + + "t68b+Xr16qv9r6sseEkXbsaNbrGiZAhfHEVBOxQ4lchHrMp4zpduxG4crmpc" + + "+Jy4SadvS0uaJvADgI03DpsDYffUdriECUqAfOg/Hr7HHyr6Q9XMo1GfIarz" + + "eUHBgi1Ny0nDTWkdb7I3bIajG+Unr3KfK6dZz5Lb3g5NeclU5zintB1045Jr" + + "j9fvGGk0/2lG0n17QViBiOzGs2poTlhn7YxmiskwlkRKVafxPZNPxKILpN9s" + + "YaWGz93qER/pGMJarGJxu8sFi3+yt6FZ4pVPkvKE8JZMEPBBrmH41batS3sw" + + "sfnJ5CicAkwd8bluQpoc6qQd81HdNpS6u7djaRSDwPtYnZWu/8Hhj4DXisje" + + "FJBAjQdn2nK4MV7WKVwr+mNcVgOdc5IuOZbRLOfc3Sff6kYVuQFfcCGgAFpd" + + "nbprF/FnYXR/rghWE7fT1gfzSMNv+z5UjZ5Rtg1S/IQfUM/P7t0UqQ01/w58" + + "bTlMGihTxHiJ4Qf3o5GUzNmAyryLvID+nOFqxpr5es6kqSN4GPRHsmUIpB9t" + + "f9Nw952vhsXI9uVkhQap3JvmdAKJaIyDz6Qi7JBZvhxpghVIDh73BQTaAFP9" + + "5GUcPbYOYJzKaU5MeYEsorGoanSqPDeKDeZxjxJD4xFsqJCoutyssqIxnXUN" + + "Y3Uojbz26IJOhqIBLaUn6QVFX79buWYjJ5ZkDS7D8kq6DZeqZclt5711AO5U" + + "uz/eDSrx3d4iVHR+kSeopxFKsrK+KCH3CbBUMIFGX/GE9WPhDWCtjjNKEe8W" + + "PinQtxvv8MlqGXtv3v7ObJ2BmfIfLD0rh3EB5WuRNKL7Ssxaq14KZGEBvc7G" + + "Fx7jXLOW6ZV3SH+C3deJGlKM2kVhDdIVjjODvQzD8qw8a/ZKqDO5hGGKUTGD" + + "Psdd7O/k/Wfn+XdE+YuKIhcEAQQEAQgECJJCZNJdIshRBAEEBAEIBAiGGrlG" + + "HlKwrAQBBAQBCAQIkdvKinJYjJcEAQQEAUAEQBGiIgN/s1bvPQr+p1aQNh/X" + + "UQFmay6Vm5HIvPhoNrX86gmMjr6/sg28/WCRtSfyuYjwQkK91n7MwFLOBaU3" + + "RrsEAQQEAQgECLRqESFR50+zBAEEBAEIBAguqbAEWMTiPwQBBAQBGAQYKzUv" + + "EetQEAe3cXEGlSsY4a/MNTbzu1WbBAEEBAEIBAiVpOv1dOWZ1AQCAAAEAgAA" + + "BAIAAAQCAAAEAgAABAIAAAAAAAAAADA1MCEwCQYFKw4DAhoFAAQUvMkeVqe6" + + "D4UmMHGEQwcb8O7ZwhgEEGiX9DeqtRwQnVi+iY/6Re8AAA=="); + + byte[] certUTF = Base64.decode( + "MIIGVQIBAzCCBg8GCSqGSIb3DQEHAaCCBgAEggX8MIIF+DCCAsUGCSqGSIb3" + + "DQEHAaCCArYEggKyMIICrjCCAqoGCyqGSIb3DQEMCgEDoIIChTCCAoEGCiqG" + + "SIb3DQEJFgGgggJxBIICbTCCAmkwggHSoAMCAQICAQcwDQYJKoZIhvcNAQEF" + + "BQAwOTEPMA0GA1UEBxMGTGV1dmVuMRkwFwYDVQQKExBVdGltYWNvIFN1YiBD" + + "QSAyMQswCQYDVQQGEwJCRTAeFw05OTEyMzEyMzAwMDBaFw0xOTEyMzEyMzAw" + + "MDBaMFcxCzAJBgNVBAYTAkJFMQ8wDQYDVQQHEwZIYWFjaHQxEDAOBgNVBAoT" + + "B1V0aW1hY28xDDAKBgNVBAsMA1ImRDEXMBUGA1UEAxMOR2VlcnQgRGUgUHJp" + + "bnMwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYGIyhTn/p0IA41ElLD" + + "fZ44PS88AAcDCiOd2DIMLck56ea+5nhI0JLyz1XgPHecc8SLFdl7vSIBA0eb" + + "tm/A7WIqIp0lcvgoyQ0qsak/dvzs+xw6r2xLCVogku4+/To6UebtfRsukXNI" + + "ckP5lWV/Ui4l+XvGdmENlEE9/BvOZIvLAgMBAAGjYzBhMBEGA1UdIwQKMAiA" + + "BlN1YkNBMjAQBgNVHQ4ECQQHVXNlcklEMjAOBgNVHQ8BAf8EBAMCBLAwGQYD" + + "VR0RBBIwEIEOVXNlcklEMkB1dGkuYmUwDwYDVR0TAQH/BAUwAwEBADANBgkq" + + "hkiG9w0BAQUFAAOBgQACS7iLLgMV4O5gFdriI7dqX55l7Qn6HiRNxlSH2kCX" + + "41X82gae4MHFc41qqsC4qm6KZWi1yvTN9XgSBCXTaw1SXGTK7SuNdoYh6ufC" + + "KuAwy5lsaetyARDksRiOIrNV9j+MRIjJMjPNg+S+ysIHTWZo2NTUuVuZ01D2" + + "jDtYPhcDFDESMBAGCSqGSIb3DQEJFTEDBAE3MIIDKwYJKoZIhvcNAQcGoIID" + + "HDCCAxgCAQAwggMRBgkqhkiG9w0BBwEwKAYKKoZIhvcNAQwBAzAaBBS5KxQC" + + "BMuZ1To+yed2j/TT45td6gICCACAggLYxQS+fu7W2sLQTkslI0EoNxLoH/WO" + + "L8NgiIgZ5temV3mgC2q0MxjVVq+SCvG89ZSTfptxOaSmYV772irFdzlrtotZ" + + "wmYk1axuFDYQ1gH0M6i9FWuhOnbk7qHclmOroXqrrbP6g3IsjwztH0+iwBCg" + + "39f63V0rr8DHiu7zZ2hBkU4/RHEsXLjaCBVNTUSssWhVLisLh2sqBJccPC2E" + + "1lw4c4WrshGQ+syLGG38ttFgXT1c+xYNpUKqJiJTLVouOH9kK3nH1hPRHKMN" + + "9CucBdUzibvkcRk1L53F3MfvjhCSNeWEmd9PKN+FtUtzRWQG3L84VGTM37Ws" + + "YcxaDwDFGcw3u1W8WFsCCkjpZecKN8P2Kp/ai/iugcXY77bYwAwpETDvQFvD" + + "nnL9oGi03HYdfeiXglC7x7dlojvnpkXDbE0nJiFwhe8Mxpx8GVlGHtP+siXg" + + "tklubg1eTCSoG9m1rsBJM717ZHXUGf32HNun2dn4vOWGocgBmokZ46KKMb9v" + + "reT39JTxi8Jlp+2cYb6Qr/oBzudR+D4iAiiVhhhEbJKPNHa61YyxF810fNI2" + + "GWlNIyN3KcI8XU6WJutm/0H3X8Y+iCSWrJ2exUktj8GiqNQ6Yx0YgEk9HI7W" + + "t9UVTIsPCgCqrV4SWCOPf6so1JqnpvlPvvNyNxSsAJ7DaJx1+oD2QQfhowk/" + + "bygkKnRo5Y15ThrTsIyQKsJHTIVy+6K5uFZnlT1DGV3DcNpuk3AY26hrAzWO" + + "TuWXsULZe7M6h6U2hTT/eplZ/mwHlXdF1VErIuusaCdkSI0doY4/Q223H40L" + + "BNU3pTezl41PLceSll00WGVr2MunlNeXKnXDJW06lnfs9BmnpV2+Lkfmf30W" + + "Pn4RKJQc+3D3SV4fCoQLIGrKiZLFfEdGJcMlySr+dJYcEtoZPuo6i/hb5xot" + + "le63h65ihNtXlEDrNpYSQqnfhjOzk5/+ZvYEcOtDObEwPTAhMAkGBSsOAwIa" + + "BQAEFMIeDI9l2Da24mtA1fbQIPc6+4dUBBQ8a4lD7j1CA1vRLhdEgPM+5hpD" + + "RgICCAA="); + + byte[] pkcs12noFriendly = Base64.decode( + "MIACAQMwgAYJKoZIhvcNAQcBoIAkgASCBAAwgDCABgkqhkiG9w0BBwGggCSA" + + "BIICvjCCArowggK2BgsqhkiG9w0BDAoBAqCCAqUwggKhMBsGCiqGSIb3DQEM" + + "AQMwDQQIyJDupEHvySECAQEEggKAupvM7RuZL3G4qNeJM3afElt03TVfynRT" + + "xUxAZOfx+zekHJTlnEuHJ+a16cOV6dQUgYfyMw1xcq4E+l59rVeMX9V3Zr0K" + + "tsMN9VYB/9zn62Kw6LQnY0rMlWYf4bt9Ut5ysq0hE5t9FL+NZ5FbFdWBOKsj" + + "/3oC6eNXOkOFyrY2haPJtD1hVHUosrlC0ffecV0YxPDsReeyx0R4CiYZpAUy" + + "ZD7rkxL+mSX7zTsShRiga2Q/NEhC1KZpbhO/qbyOgvH0r7CRumSMvijzDgaV" + + "IGqtrIZ2E2k5kscjcuFTW0x3OZTLAW/UnAh4JXJzC6isbdiWuswbAEBHifUC" + + "rk2f+bDJKe2gkH67J2K0yDQ3YSSibpjDX/bVfbtfmOoggK9MKQwqEeE0nbYE" + + "jzInH2OK5jPtmwppjmVA7i3Uk25w2+z7b/suUbft9hPCNjxFvzdbyCcXK4Vv" + + "xAgEbVWnIkvOQNbyaQi+DEF/4P26GwgJgXuJpMBn0zzsSZSIDLNl8eJHoKp2" + + "ZXknTi0SZkLaYlBxZlNhFoyXLfvQd6TI2aR5aCVqg1aZMBXyOWfz5t0JTVX8" + + "HTIcdXKis91iEsLB7vjcxIOASTAjKARr5tRp6OvaVterAyDOn2awYQJLLic5" + + "pQfditRAlsLkTxlDdu0/QBMXSPptO8g3R+dS7ntvCjXgZZyxpOeKkssS2l5v" + + "/B2EsfKmYA9hU4aBdW1S9o/PcF1wpVqABd8664TGJ77tCAkbdHe0VJ3Bop2X" + + "lNxlWeEeD0v0QUZLqkJoMEwi5SUE6HAWjbqGhRuHyey9E+UsdCVnQ8AxXQzL" + + "2UKOmIrXc6R25GsLPCysXuXPRFBB2Tul0V3re3hPcAAAAAAAADCABgkqhkiG" + + "9w0BBwaggDCAAgEAMIAGCSqGSIb3DQEHATAbBgoqhkiG9w0BDAEGMA0ECDXn" + + "UZu6xckzAgEBoIAEggTYQMbzAoGnRVJMbCaJJUYgaARJ4zMfxt2e12H4pX/e" + + "vnZrR1eKAMck5c2vJoEasr0i2VUcAcK12AntVIEnBwuRBcA2WrZnC28WR+O7" + + "rLdu9ymG2V3zmk66aTizaB6rcHAzs2lD74n+/zJhZNaDMBfu9LzAdWb/u6Rb" + + "AThmbw764Zyv9802pET6xrB8ureffgyvQAdlcGHM+yxaOV3ZEtS0cp7i+pb/" + + "NTiET4jAFoO1tbBrWGJSRrMKvx4ZREppMhG3e/pYglfMFl+1ejbDsOvEUKSt" + + "H+MVrgDgAv4NsUtNmBu+BIIEAIOCjrBSK3brtV0NZOWsa6hZSSGBhflbEY8s" + + "U1bDsgZIW4ZaJJvSYEXLmiWSBOgq9VxojMfjowY+zj6ePJJMyI3E7AcFa+on" + + "zZjeKxkKypER+TtpBeraqUfgf01b6olH8L2i4+1yotCQ0PS+15qRYPK6D+d3" + + "S+R4veOA6wEsNRijVcB3oQsBCi0FVdf+6MVDvjNzBCZXj0heVi+x0EE106Sz" + + "B3HaDbB/KNHMPZvvs3J3z2lWLj5w7YZ9eVmrVJKsgG2HRKxtt2IQquRj4BkS" + + "upFnMTBVgWxXgwXycauC9bgYZurs+DbijqhHfWpUrttDfavsP8aX6+i3gabK" + + "DH4LQRL7xrTcKkcUHxOTcPHLgDPhi+RevkV+BX9tdajbk4tqw1d+0wOkf1pW" + + "aTG8fUp0lUpra7EJ0lGy8t/MB3NEk/5tLk9qA2nsKKdNoEdZWiEBE0fMrH1o" + + "tWJDew3VhspT+Lkor2dLN5ydjcr3wkb76OETPeMxS91onNj5mrAMUBt66vb6" + + "Gx4CL8FTRNZ/l8Kzngzdv9PmmKPTIXbhYbn3XRGg3od2tC/oVfsqYlGAMgFO" + + "STt+BZ1BR9Phyi4jsiy8R0seCEDRWYQLbwgwVj0V8Rx9VptqRoCnB4XhGJoJ" + + "TdAz/MT7KOSxIh2F2FymTJpyImcV6X4Kcj9iY0AZQ4zj712g4yMR6xKGzRu6" + + "oIBDkFW2bdA3Lb9ePpo5GFtNyA7IbggIko6VOeeOKxaq9nALS2gsZc1yaYtp" + + "aKL8kB+dVTCXiLgQniO6eMzgonsuwFnG+42XM1vhEpAvFzeJRC0CYzebEK9n" + + "nGXKCPoqPFuw3gcPMn57NCZJ8MjT/p0wANIEm6AsgqrdFKwTRVJ1ytB/X9Ri" + + "ysmjMBs9zbFKjU9jVDg1vGBNtb7YnYg9IrYHa3e4yTu2wUJKGP2XWHVgjDR7" + + "6RtzlO4ljw0kkSMMEDle2ZbGZ6lVXbFwV0wPNPmGA6+XGJRxcddTnrM6R/41" + + "zqksFLgoNL2BdofMXwv7SzxGyvFhHdRRdBZ5dKj2K9OfXakEcm/asZGu87u8" + + "y9m7Cckw8ilSNPMdvYiFRoThICx9NiwYl1IIKGcWlb9p6RAx6XNSkY6ZZ6pE" + + "Vla1E26rbd7is1ssSeqxLXXV9anuG5HDwMIt+CIbD8fZmNTcWMzZRiaFajvR" + + "gXdyTu/UhVdhiQPF+lrxp4odgF0cXrpcGaKvOtPq04F4ad3O5EkSGucI210Q" + + "pR/jQs07Yp5xDPzsXAb8naHb84FvK1iONAEjWbfhDxqtH7KGrBbW4KEzJrv3" + + "B8GLDp+wOAFjGEdGDPkOx3y2L2HuI1XiS9LwL+psCily/A96OiUyRU8yEz4A" + + "AAAAAAAAAAAEAwAAAAAAAAAAADAtMCEwCQYFKw4DAhoFAAQU1NQjgVRH6Vg3" + + "tTy3wnQisALy9aYECKiM2gZrLi+fAAA="); + + static char[] noFriendlyPassword = "sschette12".toCharArray(); + + byte[] pkcs12StorageIssue = Base64.decode( + "MIIO8QIBAzCCDrEGCSqGSIb3DQEHAaCCDqIEgg6eMIIOmjCCBBMGCSqGSIb3" + + "DQEHAaCCBAQEggQAMIID/DCCA/gGCyqGSIb3DQEMCgECoIICtjCCArIwHAYK" + + "KoZIhvcNAQwBAzAOBAgURJ+/5hA2pgICB9AEggKQYZ4POE8clgH9Bjd1XO8m" + + "sr6NiRBiA08CllHSOn2RzyAgHTa+cKaWrEVVJ9mCd9XveSUCoBF9E1C3jSl0" + + "XIqLNgYd6mWK9BpeMRImM/5crjy///K4ab9kymzkc5qc0pIpdCQCZ04YmtFP" + + "B80VCgyaoh2xoxqgjBCIgdSg5XdepdA5nXkG9EsQ1oVUyCykv20lKgKKRseG" + + "Jo23AX8YUYR7ANqP2gz9lvlX6RBczuoZ62ujopUexiQgt5SZx97sgo3o/b/C" + + "px17A2L4wLdeAYCMCsZhC2UeaqnZCHSsvnPZfRGiuSEGbV5gHLmXszLDaEdQ" + + "Bo873GTpKTTzBfRFzNCtYtZRqh2AUsInWZWQUcCeX6Ogwa0wTonkp18/tqsh" + + "Fj1fVpnsRmjJTTXFxkPtUw5GPJnDAM0t1xqV7kOjN76XnZrMyk2azQ1Mf3Hn" + + "sGpF+VRGH6JtxbM0Jm5zD9uHcmkSfNR3tP/+vHOB1mkIR9tD2cHvBg7pAlPD" + + "RfDVWynhS+UBNlQ0SEM/pgR7PytRSUoKc/hhe3N8VerF7VL3BwWfBLlZFYZH" + + "FvPQg4coxF7+We7nrSQfXvdVBP9Zf0PTdf3pbZelGCPVjOzbzY/o/cB23IwC" + + "ONxlY8SC1nJDXrPZ5sY51cg/qUqor056YqipRlI6I+FoTMmMDKPAiV1V5ibo" + + "DNQJkyv/CAbTX4+oFlxgddTwYcPZgd/GoGjiP9yBHHdRISatHwMcM06CzXJS" + + "s3MhzXWD4aNxvvSpXAngDLdlB7cm4ja2klmMzL7IuxzLXFQFFvYf7IF5I1pC" + + "YZOmTlJgp0efL9bHjuHFnh0S0lPtlGDOjJ/4YpWvSKDplcPiXhaFVjsUtclE" + + "oxCC5xppRm8QWS8xggEtMA0GCSsGAQQBgjcRAjEAMBMGCSqGSIb3DQEJFTEG" + + "BAQBAAAAMGkGCSsGAQQBgjcRATFcHloATQBpAGMAcgBvAHMAbwBmAHQAIABS" + + "AFMAQQAgAFMAQwBoAGEAbgBuAGUAbAAgAEMAcgB5AHAAdABvAGcAcgBhAHAA" + + "aABpAGMAIABQAHIAbwB2AGkAZABlAHIwgZsGCSqGSIb3DQEJFDGBjR6BigA3" + + "AGQAZQBmADUAYgA0ADMANgBjAGEAYgBkADAAMAAyAGQAZAAyADkAMAAzAGIA" + + "MQA2ADgANgBjADcAOQA0ADgAXwA0ADYAZgAyADYAZgBkADQALQA4ADEAMgBk" + + "AC0ANABlAGYAYgAtADgAMAA4ADgALQA0ADUAYQBiADkAMQA5ADEAMAA3AGMA" + + "YzCCCn8GCSqGSIb3DQEHBqCCCnAwggpsAgEAMIIKZQYJKoZIhvcNAQcBMBwG" + + "CiqGSIb3DQEMAQYwDgQIbr2xdnQ9inMCAgfQgIIKOHg9VKz+jlM+3abi3cp6" + + "/XMathxDSEJLrxJs6j5DAVX17S4sw1Q/1pptjdMdd8QtTfUB6JpfgJ5Kpn+h" + + "gZMf6M8wWue0U/RZN0D9w7o+2n+X3ItdEXu80eJVDOm7I2p8qiXtijbMbXRL" + + "Cup1lgfPM5uv2D63/hmWRXLeG8eySrJnKENngpM559V8TI2JcTUBy1ZP3kcH" + + "KbcJ/tVPnIIe4qguxfsTmDtAQviGvWUohbt+RGFmtqfgntK7o6b+S8uRSwEs" + + "fOU/pnVE9M1ugtNJZI/xeGJq6umZWXA/OrAcK7feWUwqRvfivDGQJEoggByd" + + "4/g92PhK1JGkwlCb1HdfhOOKKChowQ4zVvSOm+uBxARGhk2i5uW9I20I0vSJ" + + "px42O2VFVJweOchfp+wBtSHBKYP1ZXyXWMvOtULClosSeesbYMAwvyBfpYEz" + + "3rQt/1iZkqDmEisXk8X1aEKG1KSWaSPyb/+6glWikDm+YdQw3Khu7IZt1l/H" + + "qWGecccel+R9mT4YjRzHlahUYk4U+RNVasVpH1Kxz2j3CZqL+b3jQOwSAPd/" + + "hKI+S/pjIpBPfiC4WxORAzGZzY2j+a79B70h1DO1D9jGur3vJDbdmGBNgs6d" + + "nonE1B527SICcGeXY1MtnZCLOPvySih0AvOekbN9x2CJg+Hp9e7A3Fxni53/" + + "oMLr9wGRRDki72eXCXW98mU8VJofoWYS1/VBLXGf/f+tJ9J02PpzxleqPH9T" + + "4mE+YHnZId6cqjCXmwvMr2cMw2clDVfvkbAJRE3eZHzL7IWSO8+giXzzrTsl" + + "VbMuXVkT4oniTN7TSRsBCT3zVVmCy1QL2hPBD6KsVc+bvLgAHRov84FPrI3f" + + "kY/oJufT36VE34Eu+QjzULlvVsLE3lhjutOerVIGSP//FM4LE99hp214P0JF" + + "DgBK+3J+ihmFdW8hUXOt6BU8/MBeiroiJMWo1/f/XcduekG2ZsdGv+GNPzXI" + + "PyHRpCgAgmck1+qoUPXxHRJuNqv223OZ5MN14X7iLl5OZ+f8IWfxUnZeZ9gj" + + "HNeceElwZ+YOup1CAi3haD9jxRWhZG4NDfB4IYi4Bc/TAkXE3jCPkYEvIbj9" + + "ExaU1Ts0+lqOOcwRmBoYjVrz0xbtfR/OWlopyrDHbeL5iQcQCW/loYRapWCZ" + + "E4ekHknpX9yoAwT355vtTkl0VKXeSZHE8jREhN95aY9zCoLYwbTQDTw7qUR5" + + "UamabLew0oS0XALtuOrfX4OUOZZUstUsGBle/Pw1TE3Bhe1clhrikp0F+Xgb" + + "Xx90KqxZX/36RMnCMAD7/q+57rV7WXp2Y5tT0AUgyUMjy1F1X/b1olUfqO1u" + + "rlWIUTl2znmQ3D9uO3W4ytfgGd5DpKcl2w84MBAT9qGwKuQg/UYKbP4K/+4L" + + "Y1DWCy3utmohQ28IJtlIUkPL1G7lHX1tfq/VA+bRNTJIhMrNn06ZJpuEJHDs" + + "/ferdlMFt/d6MrwVivmPVYkb8mSbHSiI8jZOFE44sA974depsDyXafFaSsl0" + + "bVzqOAu0C/n9dIednU0xxxgDF/djdZ/QhbaDIg2VJf11wx0nw9n76B0+eeyu" + + "QLaapzxCpQNDVOAM9doBb5F1I5pXQHFQqzTNtLmqDC4x0g8IH7asyk5LCglT" + + "b1pwMqPJOL2vGWKRLhPzT+9OfSpCmYGKytf593hmGmwIgEO13hQrw31F5TYt" + + "btkbDr+Q5XilOKEczhEM+Ug7YHU7bxkckOAbxu0YeRp/57GdGLokeLJ0dRlQ" + + "+V2CfQvWJoVC6PS4PUQtjwgK2p/LU10QsEFwM/S621fGq9zGrv7+FPBATRDb" + + "k4E9D/WaRylnW11ZTrOlTchQkoHcOh0xztlFxU8jzuIuDrPQQWkoqdl6B+yf" + + "lykRNJKKxwzFiPl40nLC3nEdIzCEvR4r/9QHiWQxAVSc/wQX+an5vakUmSXS" + + "oLFjgVdY1jmvdsx2r5BQPuOR8ONGmw/muvVSMaHV85brA4uk0lxn00HD9/a0" + + "A1LCeFkabNLn9wJT8RaJeOSNmFFllLR70OHaoPSb3GyzHpvd1e6aeaimdyVH" + + "BQWJ6Ufx+HjbOGuOiN46WyE6Q27dnWxx8qF89dKB4T/J0mEXqueiUjAUnnnR" + + "Cs4zPaX53hmNBdrZGaLs+xNG8xy+iyBUJIWWfQAQjCjfHYlT9nygiUWIbVQq" + + "RHkGkAN62jsSNLgHvWVzQPNNsYq0U8TPhyyci/vc8MJytujjptcz8FPqUjg2" + + "TPv34ef9buErsm4vsdEv/8Z+9aDaNex+O3Lo3N0Aw7M5NcntFBHjFY/nBFNZ" + + "whH5YA4gQ8PLZ5qshlGvb0DFXHV/9zxnsdPkLwH47ERm5IlEAuoaWtZFxg27" + + "BjLfwU1Opk+ybDSb5WZVZrs7ljsU85p3Vaf3a//yoyr9ITYj15tTXxSPoct0" + + "fDUy1I6LjJH/+eZXKA1WSda9mDQlRocvJ0IIIlI4weJpTdm8aHIJ8OngCqOF" + + "TufcSLDM41+nxEK1LqXeAScVy74kVvvqngj6mIrbylrINZOHheEgTXrUWEc0" + + "uXS8l1YqY6K6Ru5km2jVyWi/ujrDGb6QGShC09oiDYUuUGy4gwJ3XLVX/dR3" + + "pmMExohTGiVefFP400wVZaxB9g1BQmjSEZxIaW1U1K6fk8Yni8yWB3/L/PuD" + + "0+OV+98i1sQGaPe35crIpEc7R2XJdngL0Ol1ZuvCIBfy5DQwGIawTtBnjPdi" + + "hy//QTt/isdu7C5pGaJDkZFMrfxMibr6c3xXr7wwR75sTzPNmS8mquEdLsmG" + + "h8gTUnB8/K6V11JtUExMqTimTbUw+j8PggpeBelG36breWJIz1O+dmCTGuLM" + + "x/sK/i8eiUeRvWjqYpq5DYt4URWg2WlcpcKiUxQp07/NMx0svDC+mlQGwMnJ" + + "8KOJMW1qr3TGEJ/VVKKVn6sXn/RxA+VPofYzhwZByRX87XmNdPeQKC2DHQsW" + + "6v83dua5gcnv0cv/smXt7Yr/c12i0fbIaQvj3qjtUCDucjARoBey3eCyG5H6" + + "5VHSsFnPZ2HCTum+jRSw/ENsu/77XU4BIM2fjAfswp7iIr2Xi4OZWKIj6o6q" + + "+fNgnOJjemDYHAFK+hWxClrG8b+9Eaf21o4zcHkhCfBlYv4d+xcZOIDsDPwI" + + "sf+4V+CfoBLALsa2K0pXlPplGom/a8h7CjlyaICbWpEDItqwu7NQwdMRCa7i" + + "yAyM1sVjXUdcZByS1bjOFSeBe7ygAvEl78vApLxqt8Cw11XSsOtmwssecUN/" + + "pb7iHE4OMyOgsYx9u7rZ2hMyl42n3c29IwDYMumiNqk9cwCBpQTJAQEv4VzO" + + "QE5xYDBY9SEozni+4f7B7e2Wj/LOGb3vfNVYGNpDczBFxvr2FXTQla0lNYD/" + + "aePuC++QW4KvwiGL1Zx4Jo0eoDKWYlYj0qiNlQbWfVw+raaaFnlrq+je0W6P" + + "+BrKZCncho145y+CFKRLZrN5yl/cDxwsePMVhAIMr1DzVhgBXzA3MB8wBwYF" + + "Kw4DAhoEFN4Cwj9AtArnRbOIAsRhaaoZlTNJBBTIVPqCrloqLns145CWXjb0" + + "g141BQ=="); + + static char[] storagePassword = "pass".toCharArray(); + + byte[] pkcs12nopass = Base64.decode( + "MIIMvgIBAzCCDIQGCSqGSIb3DQEHAaCCDHUEggxxMIIMbTCCCS8GCSqGSIb3" + + "DQEHBqCCCSAwggkcAgEAMIIJFQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYw" + + "DgQIfnlhuZRR6/YCAggAgIII6DYgeRwq5n9kzvohZ3JuK+fB+9jZ7Or6EGBA" + + "GDxtBfHmSNUBWJEV/I8wV1zrKKoW/CaoZfA61pyrVZRd/roaqBx/koTFoh/g" + + "woyyWTRV9gYTXSVqPQgCH+e2dISAa6UGO+/YOWOOwG2X3t8tS+3FduFQFLt5" + + "cvUP98zENdm57Aef5pKpBSZDLIAoTASfmqwszWABRh2p/wKOHcCQ9Aj2e2vs" + + "pls/ntIv81MqPuxHttwX8e+3dKWGFrJRztLpCD2aua8VkSsHFsPxEHkezX4O" + + "6/VCjMCRFGophTS4dgKKtQIhZ9i/ESlr6sGKgIpyG99ALFpNEhtTKe+T3boE" + + "sEkhGDquSpu4PGz2m0W5sej1DyFkKX4zIbeMDAb1y3O7aP0F+Llo9QSeGsOA" + + "aCwND3NUAKBMOHzwdyNQcuCGCqY8j5rrSt99A5FMs3UVW3XU6hRCx7JlzO05" + + "PNCkcPRSnKSNzBhIR5W0qj4PAZnQTfX+wbtUaDLIqsObX4Muh2l3gl+JmdpO" + + "53U7ILqN8PAPly1eT+fIrUmlMmFhvo6LbTB7B2K728wsA/5wROlud/mOQz4s" + + "quS288YsnVc9ExSZKodWa3Pqcdb/cgKNJYDxrR6/eBHOj+0RLK/1yTK9ghj7" + + "IPYHoEqQbw768WK92RjM+RFGlXASkQhR9y4weWj/388uAWMIbQ+R2Zi4nb31" + + "knjqRPFThysG1bsRL04/9PgysaasfS9KYOeAlLqp+Ar4gJrof5fytBuY+6wm" + + "/J8eEdNw7VPV1cz/4rhrd2sfJQwDEN/iZoy8rTwe7wozpwZI0lwH11BBbav+" + + "1AMfI79jjxhqOeo7uxE2NzUmSd05JYI7a94tcRzGQyGEKpGxYCRamzFW23qb" + + "vG5Hcqi7Tdd7eTxw4c60l/vQLSo38g6ST5yZrK3URLiAtpioPyjrq2jnVfie" + + "QLsiAHhpHF01+t+OcKv3UjwdEyBmQ34h9klwiG7iwBFXZaPXFCF2Np1TqFVG" + + "jjBzmB+hRddEiYwN+XGCKB2Cvgc5ZMQ8LG9jQmEKLmOjuumz1ciAVY2qtl1s" + + "HYSvfNsIAV/gGzHshOVF19JmGtcQt3pMtupoRh+sh8jY2/x5eIKrj2Jx6HPd" + + "p/6IPUr54j0xSd6j7gWuXMj/eKp/utMNuBzAhkydnhXYedvTDYIj7SyPPIHa" + + "qtam8rxTDWn2AOxp7OXTgPmo1GU2zW1OLL1D3MFlS+oaRMfhgNrhW+QP5ay6" + + "ge4QLijpnSM+p0CbFAOClwzgdJV56bBVV09sDqSBXnG9MeEv5nDaH3I+GpPA" + + "UgDkaI4zT61kaGgk0uNMf3czy2ycoQzTx0iHDTXSdSqvUC1yFza8UG4AYaKz" + + "14gtSL7StvZtK0Y8oI084BINI1LgrWyrOLj7vkds4WrKhXm21BtM1GbN/pFh" + + "XI41h+XoD8KnEPqJ36rAgBo1uHqTNJCC7YikDE/dEvq6MkOx+Nug1YZRHEyi" + + "3AHry5u1HJHtxT34HXBwRXvnstuFhvU6cjc1WY1dJhu1p82TGnx7OBo/QbcM" + + "8MRrWmWuU5eW4jWbriGNGYfvZy+tHnGwy0bIeqrsHOG6/JwvfmYYXe64sryH" + + "5Qo96SZtcTJZaNFwuBY+bFUuOWm8YrT1L7Gl2Muf3pEVtNHLeYARBo1jEAym" + + "Cb4jw0oodZqbPKdyyzUZu69fdTJiQkMUcKDfHJEGK0Li9SvtdqJLiiJs57Tb" + + "YfOvn+TIuC40ssJFtmtlGCVH/0vtKLWYeW1NYAMzgI/nlhQ7W6Aroh8sZnqv" + + "SwxeQmRJaVLxiV6YveTKuVlCbqNVLeEtKYAujgnJtPemGCPbwZpwlBw6V+Dz" + + "oXveOBcUqATztWJeNv7RbU0Mk7k057+DNxXBIU+eHRGquyHQSBXxBbA+OFuu" + + "4SPfEAyoYed0HEaoKN9lIsBW1xTROI30MZvaJXvPdLsa8izXGPLnTGmoI+fv" + + "tJ644HtBCCCr3Reu82ZsTSDMxspZ9aa4ro9Oza+R5eULXDhVXedbhJBYiPPo" + + "J37El5lRqOgu2SEilhhVQq3ZCugsinCaY9P/RtWG4CFnH1IcIT5+/mivB48I" + + "2XfH6Xq6ziJdj2/r86mhEnz9sKunNvYPBDGlOvI7xucEf9AiEQoTR1xyFDbW" + + "ljL4BsJqgsHN02LyUzLwqMstwv+/JH1wUuXSK40Kik/N7+jEFW2C+/N8tN7l" + + "RPKSLaTjxVuTfdv/BH1dkV4iGFgpQrdWkWgkb+VZP9xE2mLz715eIAg13x6+" + + "n97tc9Hh375xZJqwr3QyYTXWpsK/vx04RThv8p0qMdqKvf3jVQWwnCnoeBv2" + + "L4h/uisOLY18qka/Y48ttympG+6DpmzXTwD1LycoG2SOWckCMmJhZK40+zr3" + + "NVmWf6iJtbLGMxI/kzTqbTaOfXc2MroertyM1rILRSpgnJFxJfai5Enspr9b" + + "SCwlP718jG2lQsnYlw8CuxoZAiaNy4MmC5Y3qNl3hlcggcHeLodyGkSyRsBg" + + "cEiKSL7JNvqr0X/nUeW28zVxkmQsWlp3KmST8agf+r+sQvw52fXNLdYznGZV" + + "rJrwgNOoRj0Z70MwTns3s/tCqDEsy5Sv/5dZW2uQEe7/wvmsP2WLu73Rwplg" + + "1dwi/Uo9lO9dkEzmoIK5wMPCDINxL1K+0Y79q0tIAEMDgaIxmtRpEh8/TEsA" + + "UwyEErkDsQqgGviH+ePmawJ/yehYHTRfYUgdUflwApJxRx65pDeSYkiYboMU" + + "8WSAQY2nh/p9hLlS4zbz9dCK2tzVyRkJgqNy/c4IpiHEx2l1iipW9vENglqx" + + "dYP4uqD8e3OOLjDQKizWx2t1u7GRwoEVQ3d3QzzOvsRcv7h+6vNsmYqE6phe" + + "wKFZLctpSn21zkyut444ij4sSr1OG68dEXLY0t0mATfTmXXy5GJBsdK/lLfk" + + "YTIPYYeDMle9aEicDqaKqkZUuYPnVchGp8UFMJ3M0n48OMDdDvpzBLTxxZeW" + + "cK5v/m3OEo3jgxy9wXfZdz//J3zXXqvX8LpMy1K9X0uCBTz6ERlawviMQhg1" + + "1okD5zCCAzYGCSqGSIb3DQEHAaCCAycEggMjMIIDHzCCAxsGCyqGSIb3DQEM" + + "CgECoIICpjCCAqIwHAYKKoZIhvcNAQwBAzAOBAj3QoojTSbZqgICCAAEggKA" + + "YOSp5XGdnG1pdm9CfvlAaUSHRCOyNLndoUTqteTZjHTEM9bGwNXAx4/R5H2Q" + + "PnPm5HB/ynVSXX0uKdW6YlbqUyAdV3eqE4X3Nl+K7ZoXmgAFnMr0tveBhT1b" + + "7rTi0TN4twjJzBTkKcxT8XKjvpVizUxGo+Ss5Wk8FrWLHAiC5dZvgRemtGcM" + + "w5S09Pwj+qXpjUhX1pB5/63qWPrjVf+Bfmlz4bWcqogGk0i7eg+OdTeWMrW0" + + "KR9nD1+/uNEyc4FdGtdIPnM+ax0E+vcco0ExQpTXe0xoX4JW7O71d550Wp89" + + "hAVPNrJA5eUbSWNsuz+38gjUJ+4XaAEhcA7HZIp6ZyxtzSJUoh7oqpRktoxu" + + "3cSVqVxIqAEqlNn6j0vbKfW91Od5DI5L+BIxY4xqXS7fdwipj9r6qWA8t9QU" + + "C2r1A+xXpZ4jEh6inHW9qlfACBBrYf8pSDakSR6yTbaA07LExw0IXz5oiQYt" + + "s7yx231CZlOH88bBmruLOIZsJjeg/lf63zI7Gg4F85QG3RqEJnY2pinLUTP7" + + "R62VErFZPc2a85r2dbFH1mSQIj/rT1IKe32zIW8xoHC4VwrPkT3bcLFAu2TH" + + "5k5zSI/gZUKjPDxb2dwLM4pvsj3gJ9vcFZp6BCuLkZc5rd7CyD8HK9PrBLKd" + + "H3Yngy4A08W4U3XUtIux95WE+5O/UEmSF7fr2vT//DwZArGUpBPq4Bikb8cv" + + "0wpOwUv8r0DXveeaPsxdipXlt29Ayywcs6KIidLtCaCX6/0u/XtMsGNFS+ah" + + "OlumTGBFpbLnagvIf0GKNhbg2lTjflACnxIj8d+QWsnrIU1uC1JRRKCnhpi2" + + "veeWd1m8GUb3aTFiMCMGCSqGSIb3DQEJFTEWBBS9g+Xmq/8B462FWFfaLWd/" + + "rlFxOTA7BgkqhkiG9w0BCRQxLh4sAEMAZQByAHQAeQBmAGkAawBhAHQAIAB1" + + "AHoAeQB0AGsAbwB3AG4AaQBrAGEwMTAhMAkGBSsOAwIaBQAEFKJpUOIj0OtI" + + "j2CPp38YIFBEqvjsBAi8G+yhJe3A/wICCAA="); + + private byte[] gostPfx = Base64.decode( + "MIIHEgIBAzCCBssGCSqGSIb3DQEHAaCCBrwEgga4MIIGtDCCBYEGCSqGSIb3" + + "DQEHBqCCBXIwggVuAgEAMIIFZwYJKoZIhvcNAQcBMFUGCSqGSIb3DQEFDTBI" + + "MCcGCSqGSIb3DQEFDDAaBAi114+lRrpkXAICCAAwCgYGKoUDAgIKBQAwHQYG" + + "KoUDAgIVMBMECLEIQPMsz/ZZBgcqhQMCAh8BgIIFAbu13yJiW/BnSKYKbtv9" + + "tDJoTv6l9BVpCCI4tvpzJnMeLBJyVZU4JevcJNii+R1LilVuuB+xc8e7/P4G" + + "6TILWmnnispr9KPRAbYRfoCJOa59+TYJMur58wwDuYgMapQAFzsvpzyUWi62" + + "o3uQbbLKO9hQCeJW2L+K9cbg8k33MjXMLpnblKpqmZbHTmBJDFR3xGw7IEjD" + + "UNqruu7DlHY6jctiVJSii9UNEVetSo9AAzfROxRjROg38VsWxLyO9wEMBv/8" + + "H8ur+zOtmQPGqirNXmN+pa08OvZin9kh7CgswW03xIbfsdGGGLRAWtvCnEwJ" + + "mS2tEfH1SZcuVLpMomhq3FU/jsc12k+vq/jw4I2cmfDL41ieK72bwNj8xUXu" + + "JHeoFSPGX4z+nsJUrFbFG4VBuDs2Y0SCWLyYZvdjvJwYjfqtyi/RoFSZjGHF" + + "crstf9YNQ0vW0efCJ7pUBH44OrbnCx5ng2U5jFm1b3HBIKA2RX+Tlhv14MgT" + + "KSftPZ67eSmgdsyPuQAdMu6fEdBMpVKMNZNRV565690sqi+1jOmH94TUX8XU" + + "2pRQj6eGGLq6lgGnnDabcePUEPXW8zW2KYrDKYJ/1QZmVGldvlqnjZMNhIO+" + + "Afsqax/P8RBjMduGqdilGdRzbN8PdhVaN0Ys+WzFxiS9gtaA2yPzcQuedWDN" + + "T7sIrfIapgFYmmHRQ7ht4AKj+lmOyNadONYw+ww+8RzHB1d2Kk+iXeZCtvH0" + + "XFWJZtuoGKSt/gkI0E2vpDfMbLaczaRC7ityO0iJs25ozP4JhZRBVvOmpxc9" + + "YuIetbTnTf1TLJKXDgt1IwPZeugbofSeiNv117lx8VgtvMYFD4W+WQlB8HnO" + + "C8NOYjkMPElc6PCMB9gGm0cIu1fKLvY8ycLav93JJjdDuC0kgKLb2+8mC5+2" + + "DdMkcfgW6hy4c98xnJs8enCww3A4xkRbMU13zMq70liqmKHV2SSurg5hwUHM" + + "ZthT8p988ZBrnqW24lXfMBqTK4YtIBMeMnvKocYBXr96ig3GfahI1Aj2Bw2e" + + "bpZTVeayYUd+2xX8JJMdqna6Q61AL8/eUhJUETz5+fgQJtPjcKmdJfVHO6nB" + + "vOk1t/rjK17eiXLxHCyvfP+Tw8lSFOhcvr4eIeG8WfsWNRu2eKKosOU7uash" + + "QpnvQieqDeijuRxf+tbbJ5D86inwbJqdxra7wNuZXmiaB9gFDzNbNjhtL+6i" + + "gUyX/iQHKi9bNK+PH6pdH/gkwnG/juhdgqoNY6GRty/LUOPgXD+r5e/ST16R" + + "vnlwrlKp5FzRWBEkem+dhelj3rb+cxKEyvPe3TvIUFcmIlV1VCRQ1fBHtX18" + + "eC3a3GprH8c40z3S/kdyk7GlFQ27DRLka+iDN05b+MP5jlgvfqYBKxwLfeNu" + + "MpxWoCUvYWiQdMih86/l0H+0o5UB8SqRbpuvr6fY910JCk0hDaO1pgB3HlRz" + + "k1vb46pg25heXQm3JmO+ghxjOGliYBWjl8p7AfRS9cjS8ca+X02Mv9Viv7Ce" + + "3+Gz0MVwfK98viJ3CFxkaEBlM2LM0IeUQbkHG+YwYaTSfl4GYyrug4F0ZdrA" + + "KeY9/kIxa/OJxjcIMs2H+2mSpxmrb7ylmHZ2RB8ITiduRVtO091hn/J7N+eT" + + "h6BvLBKIFU+UFUdgjxoDNDk7ao++Mu9T3dQfceFBOYzW9vMQgX30yaPLSdan" + + "ZMAP0VtiNjCCASsGCSqGSIb3DQEHAaCCARwEggEYMIIBFDCCARAGCyqGSIb3" + + "DQEMCgECoIGyMIGvMFUGCSqGSIb3DQEFDTBIMCcGCSqGSIb3DQEFDDAaBAiQ" + + "Owewo16xzQICCAAwCgYGKoUDAgIKBQAwHQYGKoUDAgIVMBMECHSCNJJcQ2VI" + + "BgcqhQMCAh8BBFYCyRRpFtZgnsxeK7ZHT+aOyoVmzhtnLrqoBHgV4nJJW2/e" + + "UcJjc2Rlbzfd+3L/GWcRGF8Bgn+MjiaAqE64Rzaao9t2hc3myw1WrCfPnoEx" + + "VI7OPBM5FzFMMCMGCSqGSIb3DQEJFTEWBBTV7LvI27QWRmHD45X2WKXYs3ct" + + "AzAlBgkqhkiG9w0BCRQxGB4WAGMAcABfAGUAeABwAG8AcgB0AGUAZDA+MC4w" + + "CgYGKoUDAgIJBQAEIJbGZorQsNM63+xozwEI561cTFVCbyHAEEpkvF3eijT8" + + "BAgY5sDtkrVeBQICCAA="); + + byte[] certChainCycle = Base64.decode( + "MIIKEAIBAzCCCcoGCSqGSIb3DQEHAaCCCbsEggm3MIIJszCCAyAGCSqGSIb3" + + "DQEHAaCCAxEEggMNMIIDCTCCAwUGCyqGSIb3DQEMCgECoIICsjCCAq4wKAYK" + + "KoZIhvcNAQwBAzAaBBQesw38x26DXisTDrMMSoAanDOAQgICBAAEggKAja8F" + + "U82RAAxhc36SWNXgWGV4CDSbDLFjlJuuXLTelz77KcX4dqPOQdKakm3OVl96" + + "cbp6mWNSOoo0F8bh/Qu51vayt7hT5NIuI8jJ/Q1FYUffMKRxGt14JwuuTQ8W" + + "5DO3z7422fm/rUu+Nkd6y+Sr0Q3FAE8QH/vNc9aUwusVAihr0AZCdT0/HwxK" + + "AKAXLtMHeTWRpdq3WPSilPEWeeZI9Gk14uKbjEeQIUsa8IujSxTE43XwNRQN" + + "z3Qm4oMxGOZP+DPxuKnj+Ug1OXgX5x+GD2fbwytzss9Isv/Zq8wq0gO3t1Ru" + + "PjpxPt/MH2PxNLe4JJTxg1tIXfNP5ZU1SivcIjGLWWcEu+xADG9uq2eDBOja" + + "mW2ZQ1cInSQw8mKcBbX7aEl0NVadSMfxMZxIw0unmoNEETmScoGr50G4Ha5H" + + "ty1iJLNtI69MUA1c2DsoOqyzlnumTTLwuqsZ/E8rFLfO4sHncMxMRdmCEUjn" + + "N2ZOfRqMrgtSFfBsYQ5YjxJ6CI1DLAJwIJhvx8tZgyGItgiI8pSyG8xsRliI" + + "WPQzocO39zHK0hG6ERGnfJyll62/MlDNl9BqjobswPu97BV9nMtPIl3yVBPa" + + "sZxj5LUPYt5nmBlIjIkT5K4cEOIWHKCHPOnAsk8AGW/vrugBcTsyw9nAsRx+" + + "PbmOmmgyo0g2SiPsUX0fGQIWOBVZNxkGP/E4qgDOFS0YavxrdUd2Bgo9q9Sc" + + "hENPI9wjhPztR2UNLtBviWd8utQJ7NhX+6guWEE4AN6Th/xLb/pe9c0sIsEO" + + "41ViDbu4wDGUz6kw3fpXjIu7i6QKniWXEUL9uuchUgZD1GJHQLhD8xgdR6YQ" + + "5SwfIadoWTFAMBkGCSqGSIb3DQEJFDEMHgoAYwB5AGMAbABlMCMGCSqGSIb3" + + "DQEJFTEWBBRoHxEy+w9gB2sa3ykN2Ok7sb3AajCCBosGCSqGSIb3DQEHBqCC" + + "BnwwggZ4AgEAMIIGcQYJKoZIhvcNAQcBMCgGCiqGSIb3DQEMAQYwGgQU40Mi" + + "gMmdUNKyHyGi8miA/3bKZO0CAgQAgIIGOIk1Ouu1n1yoHWGM7YsLpB5fqK6D" + + "LbhUoxsshDSxqemUX3QDJQVmPC9wQOUp1BUapkfB3uxsM15uUG/EUAPlF3iW" + + "0MKDpmcKTC8y1WzMtgZBmmXwRUbguH2gmn4nd6lI2SkLWQg5boQ47aHjZLO2" + + "MZsH1b/DUoT4m6fSrgsMnIVh03z1Gs2XO+Ky3qXqQJM9T3VtCfmeIJBIM2eP" + + "YqvWfnvoGZZZA+pmqVUSMu6q0U7cDA5CD9zhZ87tZvaJeQ198fVIKpMUHBdf" + + "WRGY/opZh4YTfqn+ZiiysEa9jjjx4hSkxS2XGkyUfwPEx4/1E2AdIBfi3KKW" + + "BSyx8hurMyf89YsjxqJudfCAQI2GdWLDEXwwHMi1mM3wn5NVFzZUqM/u+t2W" + + "f3gJGfykxwECxrn4TmerRJ3znyn7soLPEyy6Pp+JPNLyen3Z8gva5tU7Y2J4" + + "aW6YGbBuQ9iW6QcMA93UtWBMGRAJL1jZ9WDguaTkvH8ffSj90jfu7iTHCm/P" + + "4EEtEV7D4ciyLc5xVyq7gIQnIIViVRifAHyjbazrIFQ2yXYwINAk0yNmDqxu" + + "8W4KNxkhNTGvQP/kkk+oDpSCa7XfxMpny+2BudjEryen2q3skMp3HjU/svHQ" + + "+4Y9kxZ5rVYII9S8TRFmgxiRO7cQCdNEwiZndQVGahjVbLI3Jp3vmQhLg+2l" + + "QF07yT7Q0nxeyhbpDGUEizUyIKzs9Or0DEHbq0StU3YwLgHGLlllARLm0eAO" + + "SVhuxKGATS6GtCb/0jmzV+kX4GrK1Qkmit3Xxt9Lbq9b2v2eSMANqGrGpYyr" + + "ETfJ5Ri/UL0nF7M9+tXrrZam1dEM5nJXR04rXQXjxxIuxsrz5xhvS/I+45RY" + + "VKN9l1yw80wNYJlE3Un/eUxT0szk6XA7eguhB6ULGTZNDUMZdELAtwPcq+E4" + + "4+0oih/XLzo/losH10RZ1bBf58mFVl/SlZ0CDE3x6GnFyH/tyTb6pR3Vre1v" + + "TcBod/rkTyEnkPlFSztbBfCXXIRUcSUcbVXge3Vqn7Orhq1+sb6MPcr88uhU" + + "c9Z6g6oKf1liIhiELpMZ5qG06hTwmMlE8prE0tdReGP/eaS2eCu8MyN70adT" + + "IfW1PAopoZTfDYKxJYdsJUVkUojZUvmJ21sNeNREPaFBbwncHBR/y19afhqE" + + "yyvyzDhDJ1D81TkFUR0OwGk7FvV/5JEQCyJq0wIty9G6mJRbUi2tjCc5WpP7" + + "edDW5PBS/rfJPTDMGLy80LlD+obCTFc0sSaBI+dag02Xmxe31V9c96VPOsFt" + + "GQ532OFwZU52E9zYLQSL8L2sdNlEK+OCvTd1MNVbH6PGBYgxrmoDfNBQlYBh" + + "yX2R9wFClraNUBBV9Dtebb6MSqPW7m8xZWAXCmXkDqR9A9kP6qTMd4X3gSFT" + + "qJaezTWbHH44PTgffpK5A1ZBQj37se82QWtBKNPU14KEVvXcI+uuM/TmoAJY" + + "0hqMeXK/1JfzhxTuJsJl+c45LuGjq9dLY9tgTSqMLeKOqal7sLH1AVs4BCCA" + + "J/sHN5pgOjQNLZ1Zup5mZHXR/ynIhKnpYDADOfnAXLizn/UZZFs5huYJYQEQ" + + "K7zcDuzPuxcmFVqUa4AyL9Ul1N42rBx3VsKZ+pvcBTQU5mWsaYwPFox4wLx0" + + "HITx7v7cFYsqki7IHfgnvpJlIS8hrvqqXHl75b61T7ZfJMJNQjhf29//OZ36" + + "QU4mj7lXwudAe+qAJbn1De5B54dQhtLA7B6sX7/7Sy6xP42QJqXhlWngbhF1" + + "IsrgZZrFPJ7zeaKnjOfrLWr8bs1nthHNNoL4cqlPuYtliUGy5zxj9bpQH8xj" + + "oh8+PjTOT4H57IvUN/US/6R0awy8WafJ211diVjbU2IbjS/P+xa6Xlbaql4Z" + + "KlvXRmoMZNl6xPbJg4x6t2anadNmuS7TXHqfTpp+UxeSsr1phyPmxQZPujZY" + + "BADnjfNhTRi7esePheR/DPaPLwjllhetm+U7s7EZzMCdEcd5RB/jiceqRQ5b" + + "xoqSyvIW1ZcdTzRQEAFAhnMWRdVT0O0KYDATiSVqcBr0b70dIQ0lZvYk/TUy" + + "FdYhRXqC8Gzh8xQZPr3CBGoB02pWpp0Hbb5bHtpf3VnfsEmfwBtRPaEUMD0w" + + "ITAJBgUrDgMCGgUABBSsUQPThQeWi8r3oQZ22tcQW2dDqgQUSOpRzALP2lIV" + + "GOtPKKbIhe5YCbkCAgQA"); + + byte[] gostOpenSSLIntegerDPfx = Base64.decode( + "MIIC/wIBAzCCAsUGCSqGSIb3DQEHAaCCArYEggKyMIICrjCCAc8GCSqGSIb3" + + "DQEHBqCCAcAwggG8AgEAMIIBtQYJKoZIhvcNAQcBMBwGCiqGSIb3DQEMAQYw" + + "DgQIb1OLAOp7o6ACAggAgIIBiFSfDqzkF2Lv9arM6fdxKrixa9Zu8sGkrsbN" + + "1mYEPYRRJFyfTHB2cOn4yl2I6Ldo9m9GKtnTGGYugMTAFLdBNe0f7X0c4fjr" + + "norM2ODUDfzuqI0a54DLwixvV4U9Q0qakLKQJDAHnCSsWu7N8tRktpYt9oIZ" + + "3sVJ9r01+yxBrDOapAqT3UtaFILSiUU94Zdyehu9hmL3cq33s7Y+orfESC8A" + + "O7OYYks7c6sEjNsvUHag2bC3GClzEapiboIs2F2vb12NoiQ0skU3dbO7Jr1T" + + "P6qkjBYFvG31c3vG8pNxJ7iwJr5+FonJ6uVg3y8EmYCROD5Eyd0MeGaa+eBr" + + "z/CPFaaM50NT6RAL3CTmfqOEzOlXE2qyKZiPD65TxowbjYOmDh8Tb/mfOQUK" + + "hx8Tgzttk0CHHHZmUQkMm0RXDj/n07JaeGuQJQ1pK/3Wg7ejfGxj7eFgzmPU" + + "jOhIAAe/fwOkxUC8quv/+db/L+EeSQBSEyacU5MliXwOPVytMUOP4pFMtonw" + + "C6NzBU5JMIHYBgkqhkiG9w0BBwGggcoEgccwgcQwgcEGCyqGSIb3DQEMCgEC" + + "oHIwcDAcBgoqhkiG9w0BDAEDMA4ECF6BMzmkD7DbAgIIAARQlev2YN09882U" + + "niwvu9nMIgS3hmjSlqlpkf5aYQLosSy5eaOWCq0Vskqgv5i+77vKyQYcKOH0" + + "VnQYu98kWUgZy4fNfesufL+m3d29LX/JGdoxPjAXBgkqhkiG9w0BCRQxCh4I" + + "AHQAZQBzAHQwIwYJKoZIhvcNAQkVMRYEFIaC9GvZM/XUGW4U50bkjCfsTrW8" + + "MDEwITAJBgUrDgMCGgUABBT3iAwuHw7KQXrl09gBkHaUVbOoBAQIIm90qua1" + + "2i4CAggA"); + + private static byte[] certsOnly = Base64.decode( + "MIICnwIBAzCCApgGCSqGSIb3DQEHAaCCAokEggKFMIICgTCCAn0GCSqGSIb3" + + "DQEHAaCCAm4EggJqMIICZjCCAmIGCyqGSIb3DQEMCgEDoIICHDCCAhgGCiq" + + "GSIb3DQEJFgGgggIIBIICBDCCAgAwggFpoAMCAQICBHcheqIwDQYJKoZIhv" + + "cNAQELBQAwMjENMAsGA1UEChMERGVtbzENMAsGA1UECxMERGVtbzESMBAGA" + + "1UEAxMJRGVtbyBjZXJ0MCAXDTE5MDgzMTEzMDgzNloYDzIxMDkwNTE5MTMw" + + "ODM2WjAyMQ0wCwYDVQQKEwREZW1vMQ0wCwYDVQQLEwREZW1vMRIwEAYDVQQ" + + "DEwlEZW1vIGNlcnQwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAKOVC4" + + "Qeg0KPAPRB9WcZdvXitiJ+E6rd3czQGNzEFC6FesAllH3PHSWuUZ2YjhiVM" + + "YJyzwVP1II04iCRaIc65R45oVrHZ2ybWAOda2hBtySjQ2pIQQpoKE7nvL3j" + + "JcHoCIBJVf3c3xpfh7RucCOGiZDjU9CYPG8yznsazb5+fPF/AgMBAAGjITA" + + "fMB0GA1UdDgQWBBR/7wUDwa7T0vNzNgjOKdjz2Up9RzANBgkqhkiG9w0BAQ" + + "sFAAOBgQADzPFsaLhVYD/k9qMueYKi8Ftwijr37niF98cgAHEtq6TGsh3Se" + + "8gEK3dNJL18vm7NXgGsl8jUWsE9hCF9ar+/cDZ+KrZlZ5PLfifXJJKFqVAh" + + "sOORef0NRIVcTCoyQTW4pNpNZP9Ul5LJ3iIDjafgJMyEkRbavqdyfSqVTvY" + + "NpjEzMBkGCSqGSIb3DQEJFDEMHgoAYQBsAGkAYQBzMBYGDGCGSAGG+Watyn" + + "sBATEGBgRVHSUA"); + + /** + * we generate a self signed certificate for the sake of testing - RSA + */ + public Certificate createCert( + PublicKey pubKey, + PrivateKey privKey, + String issuerEmail, + String subjectEmail) + throws Exception + { + // + // distinguished name table. + // + X500NameBuilder issuerBldr = new X500NameBuilder(); + + issuerBldr.addRDN(BCStyle.C, "AU"); + issuerBldr.addRDN(BCStyle.O, "The Legion of the Bouncy Castle"); + issuerBldr.addRDN(BCStyle.L, "Melbourne"); + issuerBldr.addRDN(BCStyle.ST, "Victoria"); + issuerBldr.addRDN(BCStyle.EmailAddress, issuerEmail); + + X500NameBuilder subjectBldr = new X500NameBuilder(); + + subjectBldr.addRDN(BCStyle.C, "AU"); + subjectBldr.addRDN(BCStyle.O, "The Legion of the Bouncy Castle"); + subjectBldr.addRDN(BCStyle.L, "Melbourne"); + subjectBldr.addRDN(BCStyle.ST, "Victoria"); + subjectBldr.addRDN(BCStyle.EmailAddress, subjectEmail); + + return TestUtils.createCert(issuerBldr.build(), privKey, subjectBldr.build(), "SHA1withRSA", null, pubKey); + } + + private void testCertsOnly() + throws Exception + { + KeyStore pkcs12 = KeyStore.getInstance("PKCS12", "BC"); + + pkcs12.load(new ByteArrayInputStream(certsOnly), null); + + isTrue(pkcs12.containsAlias("alias")); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + pkcs12.store(bOut, null); + + pkcs12 = KeyStore.getInstance("PKCS12", "BC"); + + pkcs12.load(new ByteArrayInputStream(bOut.toByteArray()), null); + + isTrue(pkcs12.containsAlias("alias")); + + try + { + pkcs12.load(new ByteArrayInputStream(certsOnly), "1".toCharArray()); + fail("no exception"); + } + catch (IOException e) + { + isEquals("password supplied for keystore that does not require one", e.getMessage()); + } + + System.setProperty("com.fr.third.org.bouncycastle.pkcs12.ignore_useless_passwd", "true"); + + pkcs12.load(new ByteArrayInputStream(certsOnly), "1".toCharArray()); + + System.setProperty("com.fr.third.org.bouncycastle.pkcs12.ignore_useless_passwd", "false"); + } + private void testGOSTStore() + throws Exception + { + byte[] data = Hex.decode("deadbeef"); + + KeyStore pkcs12 = KeyStore.getInstance("PKCS12", "BC"); + + pkcs12.load(new ByteArrayInputStream(gostPfx), "1".toCharArray()); + + PrivateKey pk = (PrivateKey)pkcs12.getKey("cp_exported", null); + Certificate[] pubCerts = pkcs12.getCertificateChain("cp_exported"); + + Signature sig = Signature.getInstance("ECGOST3410", "BC"); + + sig.initSign(pk); + + sig.update(data); + + byte[] signature = sig.sign(); + + sig = Signature.getInstance("ECGOST3410", "BC"); + + sig.initVerify(pubCerts[0].getPublicKey()); + + sig.update(data); + + if (!sig.verify(signature)) + { + fail("key test failed in GOST store"); + } + + KeyStore ks = KeyStore.getInstance("PKCS12", "BC"); + + ks.load(new ByteArrayInputStream(gostOpenSSLIntegerDPfx), "password".toCharArray()); + + PrivateKey key = (PrivateKey)ks.getKey("test", "password".toCharArray()); + + X509Certificate cert = (X509Certificate)ks.getCertificate("test"); + + sig.initSign(key); + + sig.update(data); + + signature = sig.sign(); + + sig.initVerify(cert.getPublicKey()); + + sig.update(data); + + if (!sig.verify(signature)) + { + fail("key test failed in 2nd GOST store"); + } + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + pkcs12.store(stream, "2".toCharArray()); + + // confirm mac details consistent + Pfx bag = Pfx.getInstance(stream.toByteArray()); + MacData mData = bag.getMacData(); + + isEquals("mac alg not match", new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3411, DERNull.INSTANCE), mData.getMac().getAlgorithmId()); + isEquals(2048, mData.getIterationCount().intValue()); + isEquals(8, mData.getSalt().length); + + //confirm key recovery + pkcs12 = KeyStore.getInstance("PKCS12", "BC"); + + pkcs12.load(new ByteArrayInputStream(stream.toByteArray()), "2".toCharArray()); + + PrivateKey pk2 = (PrivateKey)pkcs12.getKey("cp_exported", null); + + isEquals(pk, pk2); + } + + public void testPKCS12Store() + throws Exception + { + BigInteger mod = new BigInteger("bb1be8074e4787a8d77967f1575ef72dd7582f9b3347724413c021beafad8f32dba5168e280cbf284df722283dad2fd4abc750e3d6487c2942064e2d8d80641aa5866d1f6f1f83eec26b9b46fecb3b1c9856a303148a5cc899c642fb16f3d9d72f52526c751dc81622c420c82e2cfda70fe8d13f16cc7d6a613a5b2a2b5894d1", 16); + KeyStore store = KeyStore.getInstance("PKCS12", "BC"); + ByteArrayInputStream stream = new ByteArrayInputStream(pkcs12); + + store.load(stream, passwd); + + Enumeration en = store.aliases(); + String pName = null; + + while (en.hasMoreElements()) + { + String n = (String)en.nextElement(); + if (store.isKeyEntry(n)) + { + pName = n; + } + else + { + // the store's we're using here are consistent so this test will pass - it's actually + // possible for this test to fail in other circumstances as PKCS#12 allows certificates + // to be stored multiple times under different aliases. + X509Certificate cert = (X509Certificate)store.getCertificate(n); + + if (!store.getCertificateAlias(cert).equals(n)) + { + fail("certificate alias check fails"); + } + } + } + + PrivateKey key = (PrivateKey)store.getKey(pName, null); + + if (!((RSAPrivateKey)key).getModulus().equals(mod)) + { + fail("Modulus doesn't match."); + } + + Certificate[] ch = store.getCertificateChain(pName); + + if (ch.length != 3) + { + fail("chain was wrong length"); + } + + if (!((X509Certificate)ch[0]).getSerialNumber().equals(new BigInteger("96153094170511488342715101755496684211"))) + { + fail("chain[0] wrong certificate."); + } + + if (!((X509Certificate)ch[1]).getSerialNumber().equals(new BigInteger("279751514312356623147411505294772931957"))) + { + fail("chain[1] wrong certificate."); + } + + if (!((X509Certificate)ch[2]).getSerialNumber().equals(new BigInteger("11341398017"))) + { + fail("chain[2] wrong certificate."); + } + + // + // save test + // + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store.store(bOut, passwd); + + stream = new ByteArrayInputStream(bOut.toByteArray()); + + store.load(stream, passwd); + + key = (PrivateKey)store.getKey(pName, null); + + if (!((RSAPrivateKey)key).getModulus().equals(mod)) + { + fail("Modulus doesn't match."); + } + + // + // save test using LoadStoreParameter + // + bOut = new ByteArrayOutputStream(); + + PKCS12StoreParameter storeParam = new PKCS12StoreParameter(bOut, passwd, true); + + store.store(storeParam); + + byte[] data = bOut.toByteArray(); + + stream = new ByteArrayInputStream(data); + store.load(stream, passwd); + + key = (PrivateKey)store.getKey(pName, null); + + if (!((RSAPrivateKey)key).getModulus().equals(mod)) + { + fail("Modulus doesn't match."); + } + + ASN1Encodable outer = new ASN1StreamParser(data).readObject(); + if (!(outer instanceof DLSequenceParser)) + { + fail("Failed DER encoding test."); + } + + + // + // save test using LoadStoreParameter - old version + // + bOut = new ByteArrayOutputStream(); + + storeParam = new com.fr.third.org.bouncycastle.jcajce.provider.config.PKCS12StoreParameter(bOut, passwd, true); + + store.store(storeParam); + + data = bOut.toByteArray(); + + stream = new ByteArrayInputStream(data); + store.load(stream, passwd); + + key = (PrivateKey)store.getKey(pName, null); + + if (!((RSAPrivateKey)key).getModulus().equals(mod)) + { + fail("Modulus doesn't match."); + } + + outer = new ASN1StreamParser(data).readObject(); + if (!(outer instanceof DLSequenceParser)) + { + fail("Failed DER encoding test."); + } + + // + // save test using LoadStoreParameter + // + bOut = new ByteArrayOutputStream(); + + JDKPKCS12StoreParameter oldParam = new JDKPKCS12StoreParameter(); + oldParam.setOutputStream(bOut); + oldParam.setPassword(passwd); + oldParam.setUseDEREncoding(true); + + store.store(oldParam); + + data = bOut.toByteArray(); + + stream = new ByteArrayInputStream(data); + store.load(stream, passwd); + + key = (PrivateKey)store.getKey(pName, null); + + if (!((RSAPrivateKey)key).getModulus().equals(mod)) + { + fail("Modulus doesn't match."); + } + + outer = new ASN1StreamParser(data).readObject(); + if (!(outer instanceof DLSequenceParser)) + { + fail("Failed DER encoding test."); + } + + // + // delete test + // + store.deleteEntry(pName); + + if (store.getKey(pName, null) != null) + { + fail("Failed deletion test."); + } + + // cert chain test + // + store.setCertificateEntry("testCert", ch[2]); + + if (store.getCertificateChain("testCert") != null) + { + fail("Failed null chain test."); + } + + // + // UTF 8 single cert test + // + store = KeyStore.getInstance("PKCS12", "BC"); + stream = new ByteArrayInputStream(certUTF); + + store.load(stream, "user".toCharArray()); + + if (store.getCertificate("37") == null) + { + fail("Failed to find UTF cert."); + } + + // + // try for a self generated certificate + // + RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16)); + + RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16), + new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16), + new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16), + new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16), + new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16), + new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16), + new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16)); + + // + // set up the keys + // + PrivateKey privKey = null; + PublicKey pubKey = null; + + try + { + KeyFactory fact = KeyFactory.getInstance("RSA", "BC"); + + privKey = fact.generatePrivate(privKeySpec); + pubKey = fact.generatePublic(pubKeySpec); + } + catch (Exception e) + { + fail("error setting up keys - " + e.toString()); + } + + Certificate[] chain = new Certificate[1]; + + chain[0] = createCert(pubKey, privKey, "issuer@bouncycastle.org", "subject@bouncycastle.org"); + + testSupportedTypes(privKey, chain); + + store = KeyStore.getInstance("PKCS12", "BC"); + + store.load(null, null); + + store.setKeyEntry("privateKey", privKey, null, chain); + + if (!store.containsAlias("privateKey") || !store.containsAlias("PRIVATEKEY")) + { + fail("couldn't find alias privateKey"); + } + + if (store.isCertificateEntry("privateKey")) + { + fail("key identified as certificate entry"); + } + + if (!store.isKeyEntry("privateKey") || !store.isKeyEntry("PRIVATEKEY")) + { + fail("key not identified as key entry"); + } + + if (!"privateKey".equals(store.getCertificateAlias(chain[0]))) + { + fail("Did not return alias for key certificate privateKey"); + } + + ByteArrayOutputStream store1Stream = new ByteArrayOutputStream(); + + store.store(store1Stream, passwd); + + testNoExtraLocalKeyID(store1Stream.toByteArray()); + + // + // no friendly name test + // + store = KeyStore.getInstance("PKCS12", "BC"); + stream = new ByteArrayInputStream(pkcs12noFriendly); + + store.load(stream, noFriendlyPassword); + + en = store.aliases(); + pName = null; + + while (en.hasMoreElements()) + { + String n = (String)en.nextElement(); + + if (store.isKeyEntry(n)) + { + pName = n; + } + } + + ch = store.getCertificateChain(pName); + + for (int i = 0; i != ch.length; i++) + { + //System.out.println(ch[i]); + } + + if (ch.length != 1) + { + fail("no cert found in pkcs12noFriendly"); + } + + // + // failure tests + // + ch = store.getCertificateChain("dummy"); + + store.getCertificateChain("DUMMY"); + + store.getCertificate("dummy"); + + store.getCertificate("DUMMY"); + + // + // storage test + // + store = KeyStore.getInstance("PKCS12", "BC"); + stream = new ByteArrayInputStream(pkcs12StorageIssue); + + store.load(stream, storagePassword); + + en = store.aliases(); + pName = null; + + while (en.hasMoreElements()) + { + String n = (String)en.nextElement(); + + if (store.isKeyEntry(n)) + { + pName = n; + } + } + + ch = store.getCertificateChain(pName); + if (ch.length != 2) + { + fail("Certificate chain wrong length"); + } + + store.store(new ByteArrayOutputStream(), storagePassword); + + // + // basic certificate check + // + store.setCertificateEntry("cert", ch[1]); + + if (!store.containsAlias("cert") || !store.containsAlias("CERT")) + { + fail("couldn't find alias cert"); + } + + if (!store.isCertificateEntry("cert") || !store.isCertificateEntry("CERT")) + { + fail("cert not identified as certificate entry"); + } + + if (store.isKeyEntry("cert") || store.isKeyEntry("CERT")) + { + fail("cert identified as key entry"); + } + + if (!store.entryInstanceOf("cert", KeyStore.TrustedCertificateEntry.class)) + { + fail("cert not identified as TrustedCertificateEntry"); + } + + if (!store.entryInstanceOf("CERT", KeyStore.TrustedCertificateEntry.class)) + { + fail("CERT not identified as TrustedCertificateEntry"); + } + + if (store.entryInstanceOf("cert", KeyStore.PrivateKeyEntry.class)) + { + fail("cert identified as key entry via PrivateKeyEntry"); + } + + if (!"cert".equals(store.getCertificateAlias(ch[1]))) + { + fail("Did not return alias for certificate entry"); + } + + // + // test restoring of a certificate with private key originally as a ca certificate + // + store = KeyStore.getInstance("PKCS12", "BC"); + + store.load(null, null); + + store.setCertificateEntry("cert", ch[0]); + + if (!store.containsAlias("cert") || !store.containsAlias("CERT")) + { + fail("restore: couldn't find alias cert"); + } + + if (!store.isCertificateEntry("cert") || !store.isCertificateEntry("CERT")) + { + fail("restore: cert not identified as certificate entry"); + } + + if (store.isKeyEntry("cert") || store.isKeyEntry("CERT")) + { + fail("restore: cert identified as key entry"); + } + + if (store.entryInstanceOf("cert", KeyStore.PrivateKeyEntry.class)) + { + fail("restore: cert identified as key entry via PrivateKeyEntry"); + } + + if (store.entryInstanceOf("CERT", KeyStore.PrivateKeyEntry.class)) + { + fail("restore: cert identified as key entry via PrivateKeyEntry"); + } + + if (!store.entryInstanceOf("cert", KeyStore.TrustedCertificateEntry.class)) + { + fail("restore: cert not identified as TrustedCertificateEntry"); + } + + // + // test of reading incorrect zero-length encoding + // + store = KeyStore.getInstance("PKCS12", "BC"); + stream = new ByteArrayInputStream(pkcs12nopass); + + store.load(stream, "".toCharArray()); + } + + private void testSupportedTypes(PrivateKey privKey, Certificate[] chain) + throws Exception + { + basicStoreTest(privKey, chain, "PKCS12"); + basicStoreTest(privKey, chain, "BCPKCS12"); + basicStoreTest(privKey, chain, "PKCS12-DEF"); + + basicStoreTest(privKey, chain, "PKCS12-3DES-40RC2"); + basicStoreTest(privKey, chain, "PKCS12-3DES-3DES"); + + basicStoreTest(privKey, chain, "PKCS12-DEF-3DES-40RC2"); + basicStoreTest(privKey, chain, "PKCS12-DEF-3DES-3DES"); + } + + private void basicStoreTest(PrivateKey privKey, Certificate[] chain, String type) + throws Exception + { + KeyStore store = KeyStore.getInstance(type, "BC"); + + store.load(null, null); + + store.setKeyEntry("key", privKey, null, chain); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store.store(bOut, passwd); + + store.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + Key k = store.getKey("key", null); + + if (!k.equals(privKey)) + { + fail("private key didn't match"); + } + + Certificate[] c = store.getCertificateChain("key"); + + if (c.length != chain.length || !c[0].equals(chain[0])) + { + fail("certificates didn't match"); + } + + if (type.contains("DEF")) + { + if (c[0] instanceof X509CertificateObject) + { + fail("wrong certificate type found"); + } + } + + // check attributes + PKCS12BagAttributeCarrier b1 = (PKCS12BagAttributeCarrier)k; + PKCS12BagAttributeCarrier b2 = (PKCS12BagAttributeCarrier)chain[0]; + + if (b1.getBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName) != null) + { + DERBMPString name = (DERBMPString)b1.getBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_friendlyName); + + if (!name.equals(new DERBMPString("key"))) + { + fail("friendly name wrong"); + } + } + else + { + fail("no friendly name found on key"); + } + + if (b1.getBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId) != null) + { + ASN1OctetString id = (ASN1OctetString)b1.getBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId); + + if (!id.equals(b2.getBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId))) + { + fail("local key id mismatch"); + } + } + else + { + fail("no local key id found"); + } + + // + // check algorithm types. + // + ASN1InputStream aIn = new ASN1InputStream(bOut.toByteArray()); + + Pfx pfx = Pfx.getInstance(aIn.readObject()); + + ContentInfo cInfo = pfx.getAuthSafe(); + + ASN1OctetString auth = (ASN1OctetString)cInfo.getContent(); + + aIn = new ASN1InputStream(auth.getOctets()); + ASN1Sequence s1 = (ASN1Sequence)aIn.readObject(); + + ContentInfo c1 = ContentInfo.getInstance(s1.getObjectAt(0)); + ContentInfo c2 = ContentInfo.getInstance(s1.getObjectAt(1)); + + aIn = new ASN1InputStream(((ASN1OctetString)c1.getContent()).getOctets()); + + SafeBag sb = SafeBag.getInstance((((ASN1Sequence)aIn.readObject()).getObjectAt(0))); + + EncryptedPrivateKeyInfo encInfo = EncryptedPrivateKeyInfo.getInstance(sb.getBagValue()); + + if (!encInfo.getEncryptionAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC)) + { + fail("key encryption algorithm wrong"); + } + + // check the key encryption + + // check the certificate encryption + EncryptedData cb = EncryptedData.getInstance(c2.getContent()); + + if (type.endsWith("3DES")) + { + if (!cb.getEncryptionAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.pbeWithSHAAnd3_KeyTripleDES_CBC)) + { + fail("expected 3DES found: " + cb.getEncryptionAlgorithm().getAlgorithm()); + } + } + else if (type.endsWith("40RC2")) + { + if (!cb.getEncryptionAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC)) + { + fail("expected 40 bit RC2 found: " + cb.getEncryptionAlgorithm().getAlgorithm()); + } + } + else + { + if (!cb.getEncryptionAlgorithm().getAlgorithm().equals(PKCSObjectIdentifiers.pbeWithSHAAnd40BitRC2_CBC)) + { + fail("expected 40 bit RC2 found: " + cb.getEncryptionAlgorithm().getAlgorithm()); + } + } + } + + private void testNoExtraLocalKeyID(byte[] store1data) + throws Exception + { + KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA", "BC"); + + kpg.initialize(512); + + KeyPair newPair = kpg.genKeyPair(); + + KeyStore store1 = KeyStore.getInstance("PKCS12", "BC"); + + store1.load(new ByteArrayInputStream(store1data), passwd); + + KeyStore store2 = KeyStore.getInstance("PKCS12", "BC"); + + store2.load(null, null); + + PrivateKey k1 = (PrivateKey)store1.getKey("privatekey", null); + Certificate[] chain1 = store1.getCertificateChain("privatekey"); + + Certificate[] chain2 = new Certificate[chain1.length + 1]; + + System.arraycopy(chain1, 0, chain2, 1, chain1.length); + + chain2[0] = createCert(newPair.getPublic(), k1, "subject@bouncycastle.org", "extra@bouncycaste.org"); + + if (((PKCS12BagAttributeCarrier)chain1[0]).getBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId) == null) + { + fail("localKeyID not found initially"); + } + + store2.setKeyEntry("new", newPair.getPrivate(), null, chain2); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + store2.store(bOut, passwd); + + store2.load(new ByteArrayInputStream(bOut.toByteArray()), passwd); + + chain2 = store2.getCertificateChain("new"); + + if (((PKCS12BagAttributeCarrier)chain2[1]).getBagAttribute(PKCSObjectIdentifiers.pkcs_9_at_localKeyId) != null) + { + fail("localKeyID found after save"); + } + } + + private void testChainCycle() + throws Exception + { + KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC"); + + // initialize key store + keyStore.load(new ByteArrayInputStream(certChainCycle), "test".toCharArray()); + + keyStore.getEntry("cycle", new KeyStore.PasswordProtection("test".toCharArray())); + } + + private void testOrphanedCertCleanup() + throws Exception + { + KeyPair kp1 = TestUtils.generateRSAKeyPair(); + KeyPair kp1ca = TestUtils.generateRSAKeyPair(); + KeyPair kp1ee = TestUtils.generateRSAKeyPair(); + + X509Certificate kp1Root = TestUtils.generateRootCert(kp1, new X500Name("CN=KP1 ROOT")); + X509Certificate kp1CA = TestUtils.generateIntermediateCert(kp1ca.getPublic(), new X500Name("CN=KP1 CA"), kp1.getPrivate(), kp1Root); + X509Certificate kp1EE = TestUtils.generateEndEntityCert(kp1ee.getPublic(), new X500Name("CN=KP1 EE"), kp1ca.getPrivate(), kp1CA); + + Certificate[] kp1Chain = new Certificate[] { kp1EE, kp1CA, kp1Root }; + + KeyPair kp2 = TestUtils.generateRSAKeyPair(); + KeyPair kp2ca = TestUtils.generateRSAKeyPair(); + KeyPair kp2ee = TestUtils.generateRSAKeyPair(); + + X509Certificate kp2Root = TestUtils.generateRootCert(kp2, new X500Name("CN=KP2 ROOT")); + X509Certificate kp2CA = TestUtils.generateIntermediateCert(kp2ca.getPublic(), new X500Name("CN=KP2 CA"), kp2.getPrivate(), kp1Root); + X509Certificate kp2EE = TestUtils.generateEndEntityCert(kp2ee.getPublic(), new X500Name("CN=KP2 EE"), kp2ca.getPrivate(), kp1CA); + + Certificate[] kp2Chain = new Certificate[] { kp2EE, kp2CA, kp2Root }; + + KeyPair kp3 = TestUtils.generateRSAKeyPair(); + X509Certificate kp3Root = TestUtils.generateRootCert(kp3, new X500Name("CN=KP3 ROOT")); + + KeyStore keyStore = KeyStore.getInstance("PKCS12", "BC"); + + keyStore.load(null, null); + + keyStore.setKeyEntry("kp1", kp1ee.getPrivate(), null, kp1Chain); + keyStore.setCertificateEntry("kp1root", kp1Root); + keyStore.setKeyEntry("kp2", kp1ee.getPrivate(), null, kp2Chain); + + keyStore.setCertificateEntry("kp3root", kp3Root); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + keyStore.store(bOut, "fred".toCharArray()); + + byte[] baseData = bOut.toByteArray(); + + KeyStore ks1 = KeyStore.getInstance("PKCS12", "BC"); + + ks1.load(new ByteArrayInputStream(baseData), "fred".toCharArray()); + + if (!ks1.containsAlias("kp1") || !ks1.isKeyEntry("kp1") || ks1.getCertificateChain("kp1").length != 3) + { + fail("kp1 missing in ks1"); + } + + ks1.deleteEntry("kp1"); + + ByteArrayOutputStream bOut1 = new ByteArrayOutputStream(); + + ks1.store(bOut1, "fred".toCharArray()); + + KeyStore ks2 = KeyStore.getInstance("PKCS12", "BC"); + + ks2.load(new ByteArrayInputStream(bOut1.toByteArray()), "fred".toCharArray()); + + if (!ks2.containsAlias("kp2") || !ks2.isKeyEntry("kp2") || ks2.getCertificateChain("kp2").length != 3) + { + fail("kp2 missing in ks2"); + } + + if (!ks2.containsAlias("kp1root") || !ks2.isCertificateEntry("kp1root")) + { + fail("kp1root missing in ks2"); + } + + if (!ks2.containsAlias("kp3root") || !ks2.isCertificateEntry("kp3root")) + { + fail("kp3root missing in ks2"); + } + + if (ks2.size() != 3) + { + fail("ks2 wrong size"); + } + + ks2.deleteEntry("kp2"); + + ByteArrayOutputStream bOut2 = new ByteArrayOutputStream(); + + ks2.store(bOut2, "fred".toCharArray()); + + KeyStore ks3 = KeyStore.getInstance("PKCS12", "BC"); + + ks3.load(new ByteArrayInputStream(bOut2.toByteArray()), "fred".toCharArray()); + + if (!ks3.containsAlias("kp1root") || !ks3.isCertificateEntry("kp1root")) + { + fail("kp1root missing in ks3"); + } + + if (!ks3.containsAlias("kp3root") || !ks3.isCertificateEntry("kp3root")) + { + fail("kp3root missing in ks3"); + } + + if (ks3.size() != 2) + { + fail("ks3 wrong size"); + } + } + + private void testIterationCount() + throws Exception + { + System.setProperty("com.fr.third.org.bouncycastle.pkcs12.max_it_count", "10"); + + ByteArrayInputStream stream = new ByteArrayInputStream(pkcs12StorageIssue); + KeyStore store = KeyStore.getInstance("PKCS12", "BC"); + + try + { + store.load(stream, storagePassword); + fail("no exception"); + } + catch (IOException e) + { + isTrue(e.getMessage().endsWith("iteration count 2000 greater than 10")); + } + + System.clearProperty("com.fr.third.org.bouncycastle.pkcs12.max_it_count"); + } + + private void testBCFKSLoad() + throws Exception + { + KeyStore k = KeyStore.getInstance("BCFKS", "BC"); + + try + { + k.load(new ByteArrayInputStream(pkcs12), passwd); + } + catch (IOException e) + { + isTrue("malformed sequence".equals(e.getMessage())); + } + + KeyPair kp1 = TestUtils.generateRSAKeyPair(); + KeyPair kp1ca = TestUtils.generateRSAKeyPair(); + KeyPair kp1ee = TestUtils.generateRSAKeyPair(); + + X509Certificate kp1Root = TestUtils.generateRootCert(kp1, new X500Name("CN=KP1 ROOT")); + X509Certificate kp1CA = TestUtils.generateIntermediateCert(kp1ca.getPublic(), new X500Name("CN=KP1 CA"), kp1.getPrivate(), kp1Root); + X509Certificate kp1EE = TestUtils.generateEndEntityCert(kp1ee.getPublic(), new X500Name("CN=KP1 EE"), kp1ca.getPrivate(), kp1CA); + + Certificate[] kp1Chain = new Certificate[] { kp1EE, kp1CA, kp1Root }; + + KeyPair kp2 = TestUtils.generateRSAKeyPair(); + KeyPair kp2ca = TestUtils.generateRSAKeyPair(); + KeyPair kp2ee = TestUtils.generateRSAKeyPair(); + + X509Certificate kp2Root = TestUtils.generateRootCert(kp2, new X500Name("CN=KP2 ROOT")); + X509Certificate kp2CA = TestUtils.generateIntermediateCert(kp2ca.getPublic(), new X500Name("CN=KP2 CA"), kp2.getPrivate(), kp1Root); + X509Certificate kp2EE = TestUtils.generateEndEntityCert(kp2ee.getPublic(), new X500Name("CN=KP2 EE"), kp2ca.getPrivate(), kp1CA); + + Certificate[] kp2Chain = new Certificate[] { kp2EE, kp2CA, kp2Root }; + + KeyPair kp3 = TestUtils.generateRSAKeyPair(); + X509Certificate kp3Root = TestUtils.generateRootCert(kp3, new X500Name("CN=KP3 ROOT")); + + KeyStore keyStore = KeyStore.getInstance("BCFKS", "BC"); + + keyStore.load(null, null); + + keyStore.setKeyEntry("kp1", kp1ee.getPrivate(), null, kp1Chain); + keyStore.setCertificateEntry("kp1root", kp1Root); + keyStore.setKeyEntry("kp2", kp1ee.getPrivate(), null, kp2Chain); + + keyStore.setCertificateEntry("kp3root", kp3Root); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + keyStore.store(bOut, "fred".toCharArray()); + + KeyStore k12 = KeyStore.getInstance("PKCS12", "BC"); + + try + { + k12.load(new ByteArrayInputStream(bOut.toByteArray()), "fred".toCharArray()); + } + catch (IOException e) + { + isTrue("illegal object in getInstance: com.fr.third.org.bouncycastle.asn1.DLSequence".equals(e.getMessage())); + } + } + + public String getName() + { + return "PKCS12Store"; + } + + public void performTest() + throws Exception + { + testIterationCount(); + testPKCS12Store(); + testGOSTStore(); + testChainCycle(); + testBCFKSLoad(); + testCertsOnly(); + + // converter tests + + KeyStore kS = KeyStore.getInstance("PKCS12", "BC"); + + byte[] data = PKCS12Util.convertToDefiniteLength(pkcs12); + kS.load(new ByteArrayInputStream(data), passwd); // check MAC + + ASN1Encodable obj = new ASN1StreamParser(data).readObject(); + if (!(obj instanceof DLSequenceParser)) + { + fail("Failed DER conversion test."); + } + + data = PKCS12Util.convertToDefiniteLength(pkcs12, passwd, "BC"); + kS.load(new ByteArrayInputStream(data), passwd); //check MAC + + obj = new ASN1StreamParser(data).readObject(); + if (!(obj instanceof DLSequenceParser)) + { + fail("Failed deep DER conversion test - outer."); + } + + Pfx pfx = Pfx.getInstance(obj); + + obj = new ASN1StreamParser(ASN1OctetString.getInstance(pfx.getAuthSafe().getContent()).getOctets()).readObject(); + if (!(obj instanceof DLSequenceParser)) + { + fail("Failed deep DER conversion test - inner."); + } + + testOrphanedCertCleanup(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PKCS12StoreTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKIXNameConstraintsTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKIXNameConstraintsTest.java new file mode 100644 index 000000000..a68f711e1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKIXNameConstraintsTest.java @@ -0,0 +1,472 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x500.style.RFC4519Style; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralSubtree; +import com.fr.third.org.bouncycastle.asn1.x509.OtherName; +import com.fr.third.org.bouncycastle.jce.provider.PKIXNameConstraintValidator; +import com.fr.third.org.bouncycastle.jce.provider.PKIXNameConstraintValidatorException; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * Test class for {@link PKIXNameConstraintValidator}. + *

+ * The field testXYZ is the name to test. + *

+ * The field testXYZIsConstraint must be tested if it is permitted and excluded. + *

+ * The field testXYZIsNotConstraint must be tested if it is not permitted and + * not excluded. + *

+ * Furthermore there are tests for the intersection and union of test names. + * + */ +public class PKIXNameConstraintsTest + extends SimpleTest +{ + + private final static String testEmail = "test@abc.test.com"; + + private final static String testEmailIsConstraint[] = + { "test@abc.test.com", "abc.test.com", ".test.com" }; + + private final static String testEmailIsNotConstraint[] = + { ".abc.test.com", "www.test.com", "test1@abc.test.com", "bc.test.com" }; + + private final static String email1[] = + { "test@test.com", "test@test.com", "test@test.com", "test@abc.test.com", + "test@test.com", "test@test.com", ".test.com", ".test.com", + ".test.com", ".test.com", "test.com", "abc.test.com", + "abc.test1.com", "test.com", "test.com", ".test.com" }; + + private final static String email2[] = + { "test@test.abc.com", "test@test.com", ".test.com", ".test.com", + "test.com", "test1.com", "test@test.com", ".test.com", + ".test1.com", "test.com", "test.com", ".test.com", ".test.com", + "test1.com", ".test.com", "abc.test.com" }; + + private final static String emailintersect[] = + { null, "test@test.com", null, "test@abc.test.com", "test@test.com", null, + null, ".test.com", null, null, "test.com", "abc.test.com", null, + null, null, "abc.test.com" }; + + private final static String emailunion[][] = + { + { "test@test.com", "test@test.abc.com" }, + { "test@test.com" }, + { "test@test.com", ".test.com" }, + { ".test.com" }, + { "test.com" }, + { "test@test.com", "test1.com" }, + { ".test.com", "test@test.com" }, + { ".test.com" }, + { ".test.com", ".test1.com" }, + { ".test.com", "test.com" }, + { "test.com" }, + { ".test.com" }, + { ".test.com", "abc.test1.com" }, + { "test1.com", "test.com" }, + { ".test.com", "test.com" }, + { ".test.com" } }; + + private final static String[] dn1 = + { "O=test org, OU=test org unit, CN=John Doe" }; + + private final static String[] dn2 = + { "O=test org, OU=test org unit" }; + + private final static String[][] dnUnion = + { + { "O=test org, OU=test org unit" } }; + + private final static String[] dnIntersection = + { "O=test org, OU=test org unit, CN=John Doe" }; + + // Note: In BC text conversion is ISO format - IETF starts at the back. + private final static String testDN = "O=test org, OU=test org unit, CN=John Doe"; + + private final static String testDNIsConstraint[] = + { + "O=test org, OU=test org unit", + "O=test org, OU=test org unit, CN=John Doe", + }; + + private final static String testDNIsNotConstraint[] = + { + "O=test org, OU=test org unit, CN=John Doe2", + "O=test org, OU=test org unit2", + "O=test org, OU=test org unit, CN=John Doe, L=USA" + }; + + private final static String testDNS = "abc.test.com"; + + private final static String testDNSIsConstraint[] = + { "test.com", "abc.test.com", "test.com" }; + + private final static String testDNSIsNotConstraint[] = + { "wwww.test.com", "ww.test.com", "www.test.com" }; + + private final static String dns1[] = + { "www.test.de", "www.test1.de", "www.test.de" }; + + private final static String dns2[] = + { "test.de", "www.test.de", "www.test.de" }; + + private final static String dnsintersect[] = + { "www.test.de", null, null }; + + private final static String dnsunion[][] = + { + { "test.de" }, + { "www.test1.de", "www.test.de" }, + { "www.test.de" } }; + + private final static String testURI = "http://karsten:password@abc.test.com:8080"; + + private final static String testURIIsConstraint[] = + { "abc.test.com", ".test.com" }; + + private final static String testURIIsNotConstraint[] = + { "xyz.test.com", ".abc.test.com" }; + + private final static String uri1[] = + { "www.test.de", ".test.de", "test1.de", ".test.de" }; + + private final static String uri2[] = + { "test.de", "www.test.de", "test1.de", ".test.de" }; + + private final static String uriintersect[] = + { null, "www.test.de", "test1.de", ".test.de" }; + + private final static String uriunion[][] = + { + { "www.test.de", "test.de" }, + { ".test.de" }, + { "test1.de" }, + { ".test.de" } }; + + private final static byte[] testIP = + + { (byte) 192, (byte) 168, 1, 2 }; + + private final static byte[][] testIPIsConstraint = + { + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 0 }, + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 4 } }; + + private final static byte[][] testIPIsNotConstraint = + { + { (byte) 192, (byte) 168, 3, 1, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 2 }, + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, (byte) 0xFF, 3 } }; + + private final static byte[][] ip1 = + { + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFE, (byte) 0xFF }, + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF }, + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0x00 } }; + + private final static byte[][] ip2 = + { + { (byte) 192, (byte) 168, 0, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFC, 3 }, + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF }, + { (byte) 192, (byte) 168, 0, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0x00 } }; + + private final static byte[][] ipintersect = + { + { (byte) 192, (byte) 168, 0, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFE, (byte) 0xFF }, + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF }, null }; + + private final static byte[][][] ipunion = + { + { + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFE, (byte) 0xFF }, + { (byte) 192, (byte) 168, 0, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFC, 3 } }, + { + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0xFF } }, + { + { (byte) 192, (byte) 168, 1, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0x00 }, + { (byte) 192, (byte) 168, 0, 1, (byte) 0xFF, (byte) 0xFF, + (byte) 0xFF, (byte) 0x00 } } }; + + public String getName() + { + return "PKIXNameConstraintsTest"; + } + + public void performTest() throws Exception + { + testConstraints(GeneralName.rfc822Name, testEmail, + testEmailIsConstraint, testEmailIsNotConstraint, email1, email2, + emailunion, emailintersect); + testConstraints(GeneralName.dNSName, testDNS, testDNSIsConstraint, + testDNSIsNotConstraint, dns1, dns2, dnsunion, dnsintersect); + testConstraints(GeneralName.directoryName, testDN, testDNIsConstraint, + testDNIsNotConstraint, dn1, dn2, dnUnion, dnIntersection); + testConstraints(GeneralName.uniformResourceIdentifier, testURI, + testURIIsConstraint, testURIIsNotConstraint, uri1, uri2, uriunion, + uriintersect); + testConstraints(GeneralName.iPAddress, testIP, testIPIsConstraint, + testIPIsNotConstraint, ip1, ip2, ipunion, ipintersect); + + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(GeneralName.directoryName, new X500Name(RFC4519Style.INSTANCE, "ou=permittedSubtree1, o=Test Certificates 2011, c=US")))); + constraintValidator.checkPermitted(new GeneralName(GeneralName.directoryName, new X500Name(RFC4519Style.INSTANCE, "cn=Valid DN nameConstraints EE Certificate Test1, ou=permittedSubtree1, o=Test Certificates 2011, c=US"))); + + GeneralName name = new GeneralName(GeneralName.otherName, new OtherName(new ASN1ObjectIdentifier("1.1"), DERNull.INSTANCE)); + GeneralSubtree subtree = new GeneralSubtree(name); + + PKIXNameConstraintValidator validator = new PKIXNameConstraintValidator(); + validator.intersectPermittedSubtree(subtree); + } + + /** + * Tests string based GeneralNames for inclusion or exclusion. + * + * @param nameType The {@link GeneralName} type to test. + * @param testName The name to test. + * @param testNameIsConstraint The names where testName must + * be included and excluded. + * @param testNameIsNotConstraint The names where testName + * must not be excluded and included. + * @param testNames1 Operand 1 of test names to use for union and + * intersection testing. + * @param testNames2 Operand 2 of test names to use for union and + * intersection testing. + * @param testUnion The union results. + * @param testInterSection The intersection results. + * @throws Exception If an unexpected exception occurs. + */ + private void testConstraints( + int nameType, + String testName, + String[] testNameIsConstraint, + String[] testNameIsNotConstraint, + String[] testNames1, + String[] testNames2, + String[][] testUnion, + String[] testInterSection) throws Exception + { + for (int i = 0; i < testNameIsConstraint.length; i++) + { + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(nameType, testNameIsConstraint[i]))); + constraintValidator.checkPermitted(new GeneralName(nameType, testName)); + } + for (int i = 0; i < testNameIsNotConstraint.length; i++) + { + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(nameType, testNameIsNotConstraint[i]))); + try + { + constraintValidator.checkPermitted(new GeneralName(nameType, testName)); + fail("not permitted name allowed: " + nameType); + } + catch (PKIXNameConstraintValidatorException e) + { + // expected + } + } + for (int i = 0; i < testNameIsConstraint.length; i++) + { + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.addExcludedSubtree(new GeneralSubtree(new GeneralName( + nameType, testNameIsConstraint[i]))); + try + { + constraintValidator.checkExcluded(new GeneralName(nameType, testName)); + fail("excluded name missed: " + nameType); + } + catch (PKIXNameConstraintValidatorException e) + { + // expected + } + } + for (int i = 0; i < testNameIsNotConstraint.length; i++) + { + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.addExcludedSubtree(new GeneralSubtree(new GeneralName( + nameType, testNameIsNotConstraint[i]))); + constraintValidator.checkExcluded(new GeneralName(nameType, testName)); + } + for (int i = 0; i < testNames1.length; i++) + { + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.addExcludedSubtree(new GeneralSubtree(new GeneralName( + nameType, testNames1[i]))); + constraintValidator.addExcludedSubtree(new GeneralSubtree(new GeneralName( + nameType, testNames2[i]))); + PKIXNameConstraintValidator constraints2 = new PKIXNameConstraintValidator(); + for (int j = 0; j < testUnion[i].length; j++) + { + constraints2.addExcludedSubtree(new GeneralSubtree( + new GeneralName(nameType, testUnion[i][j]))); + } + if (!constraints2.equals(constraintValidator)) + { + fail("union wrong: " + nameType); + } + constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(nameType, testNames1[i]))); + constraintValidator.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(nameType, testNames2[i]))); + constraints2 = new PKIXNameConstraintValidator(); + if (testInterSection[i] != null) + { + constraints2.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(nameType, testInterSection[i]))); + } + else + { + constraints2.intersectEmptyPermittedSubtree(nameType); + } + if (!constraints2.equals(constraintValidator)) + { + fail("intersection wrong: " + nameType); + } + } + } + + /** + * Tests byte array based GeneralNames for inclusion or exclusion. + * + * @param nameType The {@link GeneralName} type to test. + * @param testName The name to test. + * @param testNameIsConstraint The names where testName must + * be included and excluded. + * @param testNameIsNotConstraint The names where testName + * must not be excluded and included. + * @param testNames1 Operand 1 of test names to use for union and + * intersection testing. + * @param testNames2 Operand 2 of test names to use for union and + * intersection testing. + * @param testUnion The union results. + * @param testInterSection The intersection results. + * @throws Exception If an unexpected exception occurs. + */ + private void testConstraints( + int nameType, + byte[] testName, + byte[][] testNameIsConstraint, + byte[][] testNameIsNotConstraint, + byte[][] testNames1, + byte[][] testNames2, + byte[][][] testUnion, + byte[][] testInterSection) throws Exception + { + for (int i = 0; i < testNameIsConstraint.length; i++) + { + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(nameType, new DEROctetString( + testNameIsConstraint[i])))); + constraintValidator.checkPermitted(new GeneralName(nameType, + new DEROctetString(testName))); + } + for (int i = 0; i < testNameIsNotConstraint.length; i++) + { + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(nameType, new DEROctetString( + testNameIsNotConstraint[i])))); + try + { + constraintValidator.checkPermitted(new GeneralName(nameType, + new DEROctetString(testName))); + fail("not permitted name allowed: " + nameType); + } + catch (PKIXNameConstraintValidatorException e) + { + // expected + } + } + for (int i = 0; i < testNameIsConstraint.length; i++) + { + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.addExcludedSubtree(new GeneralSubtree(new GeneralName( + nameType, new DEROctetString(testNameIsConstraint[i])))); + try + { + constraintValidator.checkExcluded(new GeneralName(nameType, + new DEROctetString(testName))); + fail("excluded name missed: " + nameType); + } + catch (PKIXNameConstraintValidatorException e) + { + // expected + } + } + for (int i = 0; i < testNameIsNotConstraint.length; i++) + { + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.addExcludedSubtree(new GeneralSubtree(new GeneralName( + nameType, new DEROctetString(testNameIsNotConstraint[i])))); + constraintValidator.checkExcluded(new GeneralName(nameType, + new DEROctetString(testName))); + } + for (int i = 0; i < testNames1.length; i++) + { + PKIXNameConstraintValidator constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.addExcludedSubtree(new GeneralSubtree(new GeneralName( + nameType, new DEROctetString(testNames1[i])))); + constraintValidator.addExcludedSubtree(new GeneralSubtree(new GeneralName( + nameType, new DEROctetString(testNames2[i])))); + PKIXNameConstraintValidator constraints2 = new PKIXNameConstraintValidator(); + for (int j = 0; j < testUnion[i].length; j++) + { + constraints2.addExcludedSubtree(new GeneralSubtree( + new GeneralName(nameType, new DEROctetString( + testUnion[i][j])))); + } + if (!constraints2.equals(constraintValidator)) + { + fail("union wrong: " + nameType); + } + constraintValidator = new PKIXNameConstraintValidator(); + constraintValidator.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(nameType, new DEROctetString(testNames1[i])))); + constraintValidator.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(nameType, new DEROctetString(testNames2[i])))); + constraints2 = new PKIXNameConstraintValidator(); + if (testInterSection[i] != null) + { + constraints2.intersectPermittedSubtree(new GeneralSubtree( + new GeneralName(nameType, new DEROctetString( + testInterSection[i])))); + } + else + { + constraints2.intersectEmptyPermittedSubtree(nameType); + } + + if (!constraints2.equals(constraintValidator)) + { + fail("intersection wrong: " + nameType); + } + } + } + + public static void main(String[] args) + { + runTest(new PKIXNameConstraintsTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKIXPolicyMappingTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKIXPolicyMappingTest.java new file mode 100644 index 000000000..0aca72270 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKIXPolicyMappingTest.java @@ -0,0 +1,460 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.Security; +import java.security.cert.CertPathBuilder; +import java.security.cert.CertStore; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXBuilderParameters; +import java.security.cert.PKIXCertPathBuilderResult; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.util.Date; +import java.util.HashSet; +import java.util.Hashtable; +import java.util.Set; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.x509.BasicConstraints; +import com.fr.third.org.bouncycastle.asn1.x509.CertificatePolicies; +import com.fr.third.org.bouncycastle.asn1.x509.PolicyInformation; +import com.fr.third.org.bouncycastle.asn1.x509.PolicyMappings; +import com.fr.third.org.bouncycastle.asn1.x509.X509Extensions; +import com.fr.third.org.bouncycastle.jce.X509Principal; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; +import com.fr.third.org.bouncycastle.x509.X509V3CertificateGenerator; + +public class PKIXPolicyMappingTest + extends SimpleTest +{ + static X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator(); + + public String getName() + { + return "PKIXPolicyMapping"; + } + + /** + * TrustAnchor's Cert + */ + private X509Certificate createTrustCert( + PublicKey pubKey, + PrivateKey privKey) + throws Exception + { + String issuer = "C=JP, O=policyMappingAdditionalTest, OU=trustAnchor"; + String subject = "C=JP, O=policyMappingAdditionalTest, OU=trustAnchor"; + v3CertGen.setSerialNumber(BigInteger.valueOf(10)); + v3CertGen.setIssuerDN(new X509Principal(issuer)); + v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30)); + v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30))); + v3CertGen.setSubjectDN(new X509Principal(subject)); + v3CertGen.setPublicKey(pubKey); + v3CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption"); + X509Certificate cert = v3CertGen.generate(privKey); + return cert; + } + + /** + * intermediate cert + */ + private X509Certificate createIntmedCert( + PublicKey pubKey, + PrivateKey caPrivKey, + PublicKey caPubKey, + CertificatePolicies policies, + Hashtable policyMap) + throws Exception + { + String issuer = "C=JP, O=policyMappingAdditionalTest, OU=trustAnchor"; + String subject = "C=JP, O=policyMappingAdditionalTest, OU=intmedCA"; + v3CertGen.reset(); + v3CertGen.setSerialNumber(BigInteger.valueOf(20)); + v3CertGen.setIssuerDN(new X509Principal(issuer)); + v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30)); + v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30))); + v3CertGen.setSubjectDN(new X509Principal(subject)); + v3CertGen.setPublicKey(pubKey); + v3CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption"); + v3CertGen.addExtension(X509Extensions.CertificatePolicies, true, policies); + v3CertGen.addExtension(X509Extensions.BasicConstraints, true, new BasicConstraints(true)); + v3CertGen.addExtension(X509Extensions.PolicyMappings, true, new PolicyMappings(policyMap)); + X509Certificate cert = v3CertGen.generate(caPrivKey); + return cert; + } + + /** + * endEntity cert + */ + private X509Certificate createEndEntityCert( + PublicKey pubKey, + PrivateKey caPrivKey, + PublicKey caPubKey, + ASN1EncodableVector policies) + throws Exception + { + String issuer = "C=JP, O=policyMappingAdditionalTest, OU=intMedCA"; + String subject = "C=JP, O=policyMappingAdditionalTest, OU=endEntity"; + v3CertGen.reset(); + v3CertGen.setSerialNumber(BigInteger.valueOf(20)); + v3CertGen.setIssuerDN(new X509Principal(issuer)); + v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30)); + v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 30))); + v3CertGen.setSubjectDN(new X509Principal(subject)); + v3CertGen.setPublicKey(pubKey); + v3CertGen.setSignatureAlgorithm("SHA1WithRSAEncryption"); + v3CertGen.addExtension(X509Extensions.CertificatePolicies,true,new DERSequence(policies)); + X509Certificate cert = v3CertGen.generate(caPrivKey); + return cert; + } + + private String testPolicies( + int index, + X509Certificate trustCert, + X509Certificate intCert, + X509Certificate endCert, + Set requirePolicies, + boolean okay) + throws IOException, InvalidAlgorithmParameterException, NoSuchAlgorithmException, NoSuchProviderException + { + Set trust = new HashSet(); + trust.add(new TrustAnchor(trustCert, null)); + X509CertSelector targetConstraints = new X509CertSelector(); + targetConstraints.setSubject(endCert.getSubjectX500Principal().getEncoded()); + PKIXBuilderParameters params = new PKIXBuilderParameters(trust, targetConstraints); + + Set certs = new HashSet(); + certs.add(intCert); + certs.add(endCert); + CollectionCertStoreParameters pr = new CollectionCertStoreParameters(certs); + CertStore store = CertStore.getInstance("Collection",pr); + params.addCertStore(store); + + params.setRevocationEnabled(false); + if (requirePolicies != null) + { + params.setExplicitPolicyRequired(true); + params.setInitialPolicies(requirePolicies); + } + + CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX","BC"); +// CertPathBuilder cpb = CertPathBuilder.getInstance("PKIX","SUN"); + PKIXCertPathBuilderResult result = null; + try + { + result = (PKIXCertPathBuilderResult)cpb.build(params); + + if (!okay) + { + fail(index + ": path validated when failure expected."); + } + +// if (result.getPolicyTree() != null) +// { +// System.out.println("OK"); +// System.out.println("policy: " + result.getPolicyTree()); +// } +// else +// { +// System.out.println("OK: policy tree = null"); +// } + + return ""; + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + if (okay) + { + fail(index + ": path failed to validate when success expected."); + } + + Throwable ee = e.getCause(); + if (ee != null) + { + return ee.getMessage(); + } + + return e.getMessage(); + } + } + + public void performTest() + throws Exception + { + // + // personal keys + // + RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16)); + + RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16), + new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16), + new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16), + new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16), + new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16), + new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16), + new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16)); + + // + // intermediate keys. + // + RSAPublicKeySpec intPubKeySpec = new RSAPublicKeySpec( + new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16), + new BigInteger("ffff", 16)); + + + RSAPrivateCrtKeySpec intPrivKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("8de0d113c5e736969c8d2b047a243f8fe18edad64cde9e842d3669230ca486f7cfdde1f8eec54d1905fff04acc85e61093e180cadc6cea407f193d44bb0e9449b8dbb49784cd9e36260c39e06a947299978c6ed8300724e887198cfede20f3fbde658fa2bd078be946a392bd349f2b49c486e20c405588e306706c9017308e69", 16), + new BigInteger("ffff", 16), + new BigInteger("7deb1b194a85bcfd29cf871411468adbc987650903e3bacc8338c449ca7b32efd39ffc33bc84412fcd7df18d23ce9d7c25ea910b1ae9985373e0273b4dca7f2e0db3b7314056ac67fd277f8f89cf2fd73c34c6ca69f9ba477143d2b0e2445548aa0b4a8473095182631da46844c356f5e5c7522eb54b5a33f11d730ead9c0cff", 16), + new BigInteger("ef4cede573cea47f83699b814de4302edb60eefe426c52e17bd7870ec7c6b7a24fe55282ebb73775f369157726fcfb988def2b40350bdca9e5b418340288f649", 16), + new BigInteger("97c7737d1b9a0088c3c7b528539247fd2a1593e7e01cef18848755be82f4a45aa093276cb0cbf118cb41117540a78f3fc471ba5d69f0042274defc9161265721", 16), + new BigInteger("6c641094e24d172728b8da3c2777e69adfd0839085be7e38c7c4a2dd00b1ae969f2ec9d23e7e37090fcd449a40af0ed463fe1c612d6810d6b4f58b7bfa31eb5f", 16), + new BigInteger("70b7123e8e69dfa76feb1236d0a686144b00e9232ed52b73847e74ef3af71fb45ccb24261f40d27f98101e230cf27b977a5d5f1f15f6cf48d5cb1da2a3a3b87f", 16), + new BigInteger("e38f5750d97e270996a286df2e653fd26c242106436f5bab0f4c7a9e654ce02665d5a281f2c412456f2d1fa26586ef04a9adac9004ca7f913162cb28e13bf40d", 16)); + + // + // ca keys + // + RSAPublicKeySpec caPubKeySpec = new RSAPublicKeySpec( + new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16), + new BigInteger("11", 16)); + + RSAPrivateCrtKeySpec caPrivKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("b259d2d6e627a768c94be36164c2d9fc79d97aab9253140e5bf17751197731d6f7540d2509e7b9ffee0a70a6e26d56e92d2edd7f85aba85600b69089f35f6bdbf3c298e05842535d9f064e6b0391cb7d306e0a2d20c4dfb4e7b49a9640bdea26c10ad69c3f05007ce2513cee44cfe01998e62b6c3637d3fc0391079b26ee36d5", 16), + new BigInteger("11", 16), + new BigInteger("92e08f83cc9920746989ca5034dcb384a094fb9c5a6288fcc4304424ab8f56388f72652d8fafc65a4b9020896f2cde297080f2a540e7b7ce5af0b3446e1258d1dd7f245cf54124b4c6e17da21b90a0ebd22605e6f45c9f136d7a13eaac1c0f7487de8bd6d924972408ebb58af71e76fd7b012a8d0e165f3ae2e5077a8648e619", 16), + new BigInteger("f75e80839b9b9379f1cf1128f321639757dba514642c206bbbd99f9a4846208b3e93fbbe5e0527cc59b1d4b929d9555853004c7c8b30ee6a213c3d1bb7415d03", 16), + new BigInteger("b892d9ebdbfc37e397256dd8a5d3123534d1f03726284743ddc6be3a709edb696fc40c7d902ed804c6eee730eee3d5b20bf6bd8d87a296813c87d3b3cc9d7947", 16), + new BigInteger("1d1a2d3ca8e52068b3094d501c9a842fec37f54db16e9a67070a8b3f53cc03d4257ad252a1a640eadd603724d7bf3737914b544ae332eedf4f34436cac25ceb5", 16), + new BigInteger("6c929e4e81672fef49d9c825163fec97c4b7ba7acb26c0824638ac22605d7201c94625770984f78a56e6e25904fe7db407099cad9b14588841b94f5ab498dded", 16), + new BigInteger("dae7651ee69ad1d081ec5e7188ae126f6004ff39556bde90e0b870962fa7b926d070686d8244fe5a9aa709a95686a104614834b0ada4b10f53197a5cb4c97339", 16)); + + // + // set up the keys + // + KeyFactory fact = KeyFactory.getInstance("RSA", "BC"); + PrivateKey caPrivKey = fact.generatePrivate(caPrivKeySpec); + PublicKey caPubKey = fact.generatePublic(caPubKeySpec); + PrivateKey intPrivKey = fact.generatePrivate(intPrivKeySpec); + PublicKey intPubKey = fact.generatePublic(intPubKeySpec); + PrivateKey privKey = fact.generatePrivate(privKeySpec); + PublicKey pubKey = fact.generatePublic(pubKeySpec); + + X509Certificate trustCert = createTrustCert(caPubKey, caPrivKey); + CertificatePolicies intPolicies = null; + Hashtable map = null; + ASN1EncodableVector policies = null; + Set requirePolicies = null; + X509Certificate intCert = null; + X509Certificate endCert = null; + + /** + * valid test_00 + */ + intPolicies = new CertificatePolicies(new PolicyInformation(new ASN1ObjectIdentifier("2.5.29.32.0"))); + map = new Hashtable(); + map.put("2.16.840.1.101.3.2.1.48.1","2.16.840.1.101.3.2.1.48.2"); + intCert = createIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map); + + if (!"CertificatePolicies: [Policy information: 2.5.29.32.0]".equals(intPolicies.toString())) + { + fail("1st toString() test"); + } + + policies = new ASN1EncodableVector(); + policies.add(new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.2"))); + endCert = createEndEntityCert(pubKey, intPrivKey, intPubKey, policies); + + requirePolicies = null; + String msg = testPolicies(0, trustCert, intCert, endCert, requirePolicies, true); + checkMessage(0, msg, ""); + + /** + * test_01 + */ + intPolicies = new CertificatePolicies(new PolicyInformation(new ASN1ObjectIdentifier("2.5.29.32.0"))); + map = new Hashtable(); + map.put("2.16.840.1.101.3.2.1.48.1","2.16.840.1.101.3.2.1.48.2"); + intCert = createIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map); + + policies = new ASN1EncodableVector(); + policies.add(new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.2"))); + endCert = createEndEntityCert(pubKey, intPrivKey, intPubKey, policies); + + requirePolicies = new HashSet(); + requirePolicies.add("2.16.840.1.101.3.2.1.48.1"); + msg = testPolicies(1, trustCert, intCert, endCert, requirePolicies, true); + checkMessage(1, msg, ""); + + /** + * test_02 + */ + intPolicies = new CertificatePolicies(new PolicyInformation(new ASN1ObjectIdentifier("2.5.29.32.0"))); + map = new Hashtable(); + map.put("2.16.840.1.101.3.2.1.48.1","2.16.840.1.101.3.2.1.48.2"); + intCert = createIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map); + + policies = new ASN1EncodableVector(); + policies.add(new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.2"))); + endCert = createEndEntityCert(pubKey, intPrivKey, intPubKey, policies); + + requirePolicies = new HashSet(); + requirePolicies.add("2.5.29.32.0"); + msg = testPolicies(2, trustCert, intCert, endCert, requirePolicies, true); + checkMessage(2, msg, ""); + + /** + * test_03 + */ + intPolicies = new CertificatePolicies(new PolicyInformation[] + { new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.3")), + new PolicyInformation(new ASN1ObjectIdentifier("2.5.29.32.0")) }); + + if (!"CertificatePolicies: [Policy information: 2.16.840.1.101.3.2.1.48.3, Policy information: 2.5.29.32.0]".equals(intPolicies.toString())) + { + fail("2nd toString() test"); + } + + map = new Hashtable(); + map.put("2.16.840.1.101.3.2.1.48.1","2.16.840.1.101.3.2.1.48.2"); + intCert = createIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map); + + policies = new ASN1EncodableVector(); + policies.add(new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.2"))); + endCert = createEndEntityCert(pubKey, intPrivKey, intPubKey, policies); + + requirePolicies = new HashSet(); + requirePolicies.add("2.16.840.1.101.3.2.1.48.1"); + msg = testPolicies(3, trustCert, intCert, endCert, requirePolicies, true); + checkMessage(3, msg, ""); + + /** + * test_04 + */ + intPolicies = new CertificatePolicies(new PolicyInformation[] + { new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.3")), + new PolicyInformation(new ASN1ObjectIdentifier("2.5.29.32.0")) } ); + map = new Hashtable(); + map.put("2.16.840.1.101.3.2.1.48.1", "2.16.840.1.101.3.2.1.48.2"); + intCert = createIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map); + + policies = new ASN1EncodableVector(); + policies.add(new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.3"))); + endCert = createEndEntityCert(pubKey, intPrivKey, intPubKey, policies); + + requirePolicies = new HashSet(); + requirePolicies.add("2.16.840.1.101.3.2.1.48.3"); + msg = testPolicies(4, trustCert, intCert, endCert, requirePolicies, true); + checkMessage(4, msg, ""); + + /** + * test_05 + */ + intPolicies = new CertificatePolicies(new PolicyInformation(new ASN1ObjectIdentifier("2.5.29.32.0"))); + map = new Hashtable(); + map.put("2.16.840.1.101.3.2.1.48.1", "2.16.840.1.101.3.2.1.48.2"); + intCert = createIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map); + + policies = new ASN1EncodableVector(); + policies.add(new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.2"))); + endCert = createEndEntityCert(pubKey, intPrivKey, intPubKey, policies); + + requirePolicies = new HashSet(); + requirePolicies.add("2.16.840.1.101.3.2.1.48.2"); + msg = testPolicies(5, trustCert, intCert, endCert, requirePolicies, false); + checkMessage(5, msg, "Path processing failed on policy."); + + /** + * test_06 + */ + intPolicies = new CertificatePolicies(new PolicyInformation(new ASN1ObjectIdentifier("2.5.29.32.0"))); + map = new Hashtable(); + map.put("2.16.840.1.101.3.2.1.48.1", "2.16.840.1.101.3.2.1.48.2"); + intCert = createIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map); + + policies = new ASN1EncodableVector(); + policies.add(new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.1"))); + endCert = createEndEntityCert(pubKey, intPrivKey, intPubKey, policies); + + requirePolicies = new HashSet(); + requirePolicies.add("2.16.840.1.101.3.2.1.48.1"); + msg = testPolicies(6, trustCert, intCert, endCert, requirePolicies, true); + checkMessage(6, msg, ""); + + /** + * test_07 + */ + intPolicies = new CertificatePolicies(new PolicyInformation(new ASN1ObjectIdentifier("2.5.29.32.0"))); + map = new Hashtable(); + map.put("2.16.840.1.101.3.2.1.48.1", "2.16.840.1.101.3.2.1.48.2"); + intCert = createIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map); + + policies = new ASN1EncodableVector(); + policies.add(new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.2"))); + endCert = createEndEntityCert(pubKey, intPrivKey, intPubKey, policies); + + requirePolicies = new HashSet(); + requirePolicies.add("2.16.840.1.101.3.2.1.48.3"); + msg = testPolicies(7, trustCert, intCert, endCert, requirePolicies, false); + checkMessage(7, msg, "Path processing failed on policy."); + + /** + * test_08 + */ + intPolicies = new CertificatePolicies(new PolicyInformation(new ASN1ObjectIdentifier("2.5.29.32.0"))); + map = new Hashtable(); + map.put("2.16.840.1.101.3.2.1.48.1", "2.16.840.1.101.3.2.1.48.2"); + intCert = createIntmedCert(intPubKey, caPrivKey, caPubKey, intPolicies, map); + + policies = new ASN1EncodableVector(); + policies.add(new PolicyInformation(new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.3"))); + endCert = createEndEntityCert(pubKey, intPrivKey, intPubKey, policies); + + requirePolicies = new HashSet(); + requirePolicies.add("2.16.840.1.101.3.2.1.48.1"); + msg = testPolicies(8, trustCert, intCert, endCert, requirePolicies, false); + checkMessage(8, msg, "Path processing failed on policy."); + } + + + private void checkMessage( + int index, + String msg, + String expected) + { + if (!msg.equals(expected)) + { + fail("test " + index + " failed got: " + msg + " expected: " + expected); + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PKIXPolicyMappingTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKIXTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKIXTest.java new file mode 100644 index 000000000..cf4da282c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PKIXTest.java @@ -0,0 +1,248 @@ + +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.security.Security; +import java.security.cert.CertificateFactory; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class PKIXTest + implements Test +{ + /* + * The following certs and crls are described in: + * http://www.ietf.org/internet-drafts/draft-ietf-pkix-new-part1-08.txt + * + * This section contains four examples: three certificates and a CRL. + * The first two certificates and the CRL comprise a minimal + * certification path. + * + * Section C.1 contains an annotated hex dump of a "self-signed" + * certificate issued by a CA whose distinguished name is + * cn=us,o=gov,ou=nist. The certificate contains a DSA public key with + * parameters, and is signed by the corresponding DSA private key. + * + * Section C.2 contains an annotated hex dump of an end entity + * certificate. The end entity certificate contains a DSA public key, + * and is signed by the private key corresponding to the "self-signed" + * certificate in section C.1. + * + * Section C.3 contains a dump of an end entity certificate which + * contains an RSA public key and is signed with RSA and MD5. This + * certificate is not part of the minimal certification path. + * + * Section C.4 contains an annotated hex dump of a CRL. The CRL is + * issued by the CA whose distinguished name is cn=us,o=gov,ou=nist and + * the list of revoked certificates includes the end entity certificate + * presented in C.2. + */ + + /** + * C.1 Certificate + * + * This section contains an annotated hex dump of a 699 byte version 3 + * certificate. The certificate contains the following information: + * (a) the serial number is 23 (17 hex); + * (b) the certificate is signed with DSA and the SHA-1 hash algorithm; + * (c) the issuer's distinguished name is OU=NIST; O=gov; C=US + * (d) and the subject's distinguished name is OU=NIST; O=gov; C=US + * (e) the certificate was issued on June 30, 1997 and will expire on + * December 31, 1997; + * (f) the certificate contains a 1024 bit DSA public key with + * parameters; + * (g) the certificate contains a subject key identifier extension + * generated using method (1) of section 4.2.1.2; and + * (h) the certificate is a CA certificate (as indicated through the + * basic constraints extension.) + */ + static byte[] rootCertBin = Hex.decode( + "308202bb3082027ba003020102020111300906072a8648ce380403302a310b30" + + "09060355040613025553310c300a060355040a1303676f76310d300b06035504" + + "0b13044e495354301e170d3937303633303030303030305a170d393731323331" + + "3030303030305a302a310b3009060355040613025553310c300a060355040a13" + + "03676f76310d300b060355040b13044e495354308201b83082012c06072a8648" + + "ce3804013082011f02818100b68b0f942b9acea525c6f2edfcfb9532ac011233" + + "b9e01cad909bbc48549ef394773c2c713555e6fe4f22cbd5d83e8993334dfcbd" + + "4f41643ea29870ec31b450deebf198280ac93e44b3fd22979683d018a3e3bd35" + + "5bffeea321726a7b96dab93f1e5a90af24d620f00d21a7d402b91afcac21fb9e" + + "949e4b42459e6ab24863fe43021500b20db0b101df0c6624fc1392ba55f77d57" + + "7481e5028181009abf46b1f53f443dc9a565fb91c08e47f10ac30147c2444236" + + "a99281de57c5e0688658007b1ff99b77a1c510a580917851513cf6fcfccc46c6" + + "817892843df4933d0c387e1a5b994eab1464f60c21224e28089c92b9669f40e8" + + "95f6d5312aef39a262c7b26d9e58c43aa81181846daff8b419b4c211aed0223b" + + "aa207fee1e57180381850002818100b59e1f490447d1dbf53addca0475e8dd75" + + "f69b8ab197d6596982d3034dfd3b365f4af2d14ec107f5d12ad378776356ea96" + + "614d420b7a1dfbab91a4cedeef77c8e5ef20aea62848afbe69c36aa530f2c2b9" + + "d9822b7dd9c4841fde0de854d71b992eb3d088f6d6639ba7e20e82d43b8a681b" + + "065631590b49eb99a5d581417bc955a3323030301d0603551d0e0416041486ca" + + "a5228162efad0a89bcad72412c2949f48656300f0603551d130101ff04053003" + + "0101ff300906072a8648ce380403032f00302c0214431bcf292545c04e52e77d" + + "d6fcb1664c83cf2d7702140b5b9a241198e8f3869004f608a9e18da5cc3ad4"); + + + /** + * C.2 Certificate + * + * This section contains an annotated hex dump of a 730 byte version 3 + * certificate. The certificate contains the following information: + * (a the serial number is 18 (12 hex); + * (b) the certificate is signed with DSA and the SHA-1 hash algorithm; + * (c) the issuer's distinguished name is OU=nist; O=gov; C=US + * (d) and the subject's distinguished name is CN=Tim Polk; OU=nist; + * O=gov; C=US + * (e) the certificate was valid from July 30, 1997 through December 1, + * 1997; + * (f) the certificate contains a 1024 bit DSA public key; + * (g) the certificate is an end entity certificate, as the basic + * constraints extension is not present; + * (h) the certificate contains an authority key identifier extension + * matching the subject key identifier of the certificate in Appendix + * C.1; and + * (i) the certificate includes one alternative name - an RFC 822 + * address of "wpolk@nist.gov". + */ + static byte[] userCert1Bin = Hex.decode( + "308202da30820299a003020102020112300906072a8648ce380403302a310b30" + + "09060355040613025553310c300a060355040a1303676f76310d300b06035504" + + "0b13044e495354301e170d3937303733303030303030305a170d393731323031" + + "3030303030305a303d310b3009060355040613025553310c300a060355040a13" + + "03676f76310d300b060355040b13044e4953543111300f060355040313085469" + + "6d20506f6c6b308201b73082012c06072a8648ce3804013082011f02818100b6" + + "8b0f942b9acea525c6f2edfcfb9532ac011233b9e01cad909bbc48549ef39477" + + "3c2c713555e6fe4f22cbd5d83e8993334dfcbd4f41643ea29870ec31b450deeb" + + "f198280ac93e44b3fd22979683d018a3e3bd355bffeea321726a7b96dab93f1e" + + "5a90af24d620f00d21a7d402b91afcac21fb9e949e4b42459e6ab24863fe4302" + + "1500b20db0b101df0c6624fc1392ba55f77d577481e5028181009abf46b1f53f" + + "443dc9a565fb91c08e47f10ac30147c2444236a99281de57c5e0688658007b1f" + + "f99b77a1c510a580917851513cf6fcfccc46c6817892843df4933d0c387e1a5b" + + "994eab1464f60c21224e28089c92b9669f40e895f6d5312aef39a262c7b26d9e" + + "58c43aa81181846daff8b419b4c211aed0223baa207fee1e5718038184000281" + + "8030b675f77c2031ae38bb7e0d2baba09c4bdf20d524133ccd98e55f6cb7c1ba" + + "4abaa9958053f00d72dc3337f4010bf5041f9d2e1f62d8843a9b25095a2dc846" + + "8e2bd4f50d3bc72dc66cb998c1253a444e8eca9561357cce15315c23131ea205" + + "d17a241ccbd3720990ff9b9d28c0a10aec469f0db8d0dcd018a62b5ef98fb595" + + "bea33e303c30190603551d1104123010810e77706f6c6b406e6973742e676f76" + + "301f0603551d2304183016801486caa5228162efad0a89bcad72412c2949f486" + + "56300906072a8648ce380403033000302d02143697cbe3b42ce1bb61a9d3cc24" + + "cc22929ff4f587021500abc979afd2161ca9e368a91410b4a02eff225a73"); + + + /** + * C.3 End Entity Certificate Using RSA + * + * This section contains an annotated hex dump of a 654 byte version 3 + * certificate. The certificate contains the following information: + * (a) the serial number is 256; + * (b) the certificate is signed with RSA and the SHA-1 hash algorithm; + * (c) the issuer's distinguished name is OU=NIST; O=gov; C=US + * (d) and the subject's distinguished name is CN=Tim Polk; OU=NIST; + * O=gov; C=US + * (e) the certificate was issued on May 21, 1996 at 09:58:26 and + * expired on May 21, 1997 at 09:58:26; + * (f) the certificate contains a 1024 bit RSA public key; + * (g) the certificate is an end entity certificate (not a CA + * certificate); + * (h) the certificate includes an alternative subject name of + * "" and an + * alternative issuer name of "" - both are URLs; + * (i) the certificate include an authority key identifier extension + * and a certificate policies extension psecifying the policy OID + * 2.16.840.1.101.3.2.1.48.9; and + * (j) the certificate includes a critical key usage extension + * specifying that the public key is intended for verification of + * digital signatures. + */ + static byte[] userCert2Bin = Hex.decode( + "3082028e308201f7a00302010202020100300d06092a864886f70d0101050500" + + "302a310b3009060355040613025553310c300a060355040b1303676f76310d30" + + "0b060355040a13044e495354301e170d3936303532313039353832365a170d39" + + "37303532313039353832365a303d310b3009060355040613025553310c300a06" + + "0355040b1303676f76310d300b060355040a13044e4953543111300f06035504" + + "03130854696d20506f6c6b30819f300d06092a864886f70d010101050003818d" + + "0030818902818100e16ae4033097023cf410f3b51e4d7f147bf6f5d078e9a48a" + + "f0a375ecedb656967f8899859af23e687787eb9ed19fc0b417dcab8923a41d7e" + + "16234c4fa84df531b87caae31a4909f44b26db2767308212014ae91ab6c10c53" + + "8b6cfc2f7a43ec33367e32b27bd5aacf0114c612ec13f22d147a8b215814134c" + + "46a39af21695ff230203010001a381af3081ac303f0603551d11043830368634" + + "687474703a2f2f7777772e69746c2e6e6973742e676f762f6469763839332f73" + + "746166662f706f6c6b2f696e6465782e68746d6c301f0603551d120418301686" + + "14687474703a2f2f7777772e6e6973742e676f762f301f0603551d2304183016" + + "80140868af8533c8394a7af882938e706a4a20842c3230170603551d20041030" + + "0e300c060a60864801650302013009300e0603551d0f0101ff04040302078030" + + "0d06092a864886f70d0101050500038181008e8e3656788bbfa13975172ee310" + + "dc832b6834521cf66c1d525e5420105e4ca940f94b729e82b961dceb32a5bdb1" + + "b148f99b01bbebaf9b83f6528cb06d7cd09a39543e6d206fcdd0debe275f204f" + + "b6ab0df5b7e1bab4dfdf3dd4f6ed01fb6ecb9859ac41fb489c1ff65b46e029e2" + + "76ecc43a0afc92c5c0d2a9c9d32952876533"); + + /** + * This section contains an annotated hex dump of a version 2 CRL with + * one extension (cRLNumber). The CRL was issued by OU=NIST; O=gov; C=US + * on August 7, 1997; the next scheduled issuance was September 7, 1997. + * The CRL includes one revoked certificates: serial number 18 (12 hex), + * which was revoked on July 31, 1997 due to keyCompromise. The CRL + * itself is number 18, and it was signed with DSA and SHA-1. + */ + static byte[] crlBin = Hex.decode( + "3081cb30818c020101300906072a8648ce380403302a310b3009060355040613025553310c300a060355040a1303676f76310d300b060355040b13044e495354170d3937303830373030303030305a170d3937303930373030303030305a30223020020112170d3937303733313030303030305a300c300a0603551d1504030a0101a00e300c300a0603551d14040302010c300906072a8648ce380403032f00302c0214224e9f43ba950634f2bb5e65dba68005c03a29470214591a57c982d7022114c3d40b321b9616b11f465a"); + + + public TestResult perform() + { + try + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate rootCert = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(rootCertBin)); + X509Certificate userCert1 = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(userCert1Bin)); + X509Certificate userCert2 = (X509Certificate)cf.generateCertificate(new ByteArrayInputStream(userCert2Bin)); + X509CRL crl = (X509CRL)cf.generateCRL(new ByteArrayInputStream(crlBin)); + rootCert.verify(rootCert.getPublicKey(), "BC"); + userCert1.verify(rootCert.getPublicKey(), "BC"); + + crl.verify(rootCert.getPublicKey(), "BC"); + + if (!crl.isRevoked(userCert1)) + { + return new SimpleTestResult(false, this.getName() + ": usercert1 not revoked."); + } + + if (crl.isRevoked(userCert2)) + { + return new SimpleTestResult(false, this.getName() + ": usercert2 revoked."); + } + + } + catch (Exception e) + { + return new SimpleTestResult(false, this.getName() + ": exception - " + e.toString()); + } + + return new SimpleTestResult(true, this.getName() + ": Okay"); + } + + public String getName() + { + return "PKIX"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + Test test = new PKIXTest(); + TestResult result = test.perform(); + + System.out.println(result.toString()); + } + +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PSSTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PSSTest.java new file mode 100644 index 000000000..765270de8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/PSSTest.java @@ -0,0 +1,359 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.ProviderException; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PSSParameterSpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPublicKeySpec; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomData; + +public class PSSTest + extends SimpleTest +{ + private class FixedRandom + extends SecureRandom + { + byte[] vals; + + FixedRandom( + byte[] vals) + { + this.vals = vals; + } + + public void nextBytes( + byte[] bytes) + { + System.arraycopy(vals, 0, bytes, 0, vals.length); + } + } + + private boolean arrayEquals( + byte[] a, + byte[] b) + { + if (a.length != b.length) + { + return false; + } + + for (int i = 0; i != a.length; i++) + { + if (a[i] != b[i]) + { + return false; + } + } + + return true; + } + + + private RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16)); + + private RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",16), + new BigInteger("010001",16), + new BigInteger("33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",16), + new BigInteger("e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",16), + new BigInteger("b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",16), + new BigInteger("28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",16), + new BigInteger("1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",16), + new BigInteger("27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",16)); + + // PSSExample1.1 + + private byte[] msg1a = Hex.decode("cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0"); + + private byte[] slt1a = Hex.decode("dee959c7e06411361420ff80185ed57f3e6776af"); + + private byte[] sig1a = Hex.decode("9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c"); + + private byte[] sig1b = Hex.decode("96ea348db4db2947aee807bd687411a880913706f21b383a1002b97e43656e5450a9d1812efbedd1ed159f8307986adf48bada66a8efd14bd9e2f6f6f458e73b50c8ce6e3079011c5b4bd1600a2601a66198a1582574a43f13e0966c6c2337e6ca0886cd9e1b1037aeadef1382117d22b35e7e4403f90531c8cfccdf223f98e4"); + + private byte[] sig1c = Hex.decode("9e64cc1062c537b142480bc5af407b55904ead970e20e0f8f6664279c96c6da6b03522160f224a85cc413dfe6bd00621485b665abac6d90ff38c9af06f4ddd6c7c81540439e5795601a1343d9feb465712ff8a5f5150391522fb5a9b8e2225a555f4efaa5e5c0ed7a19b27074c2d9f6dbbd0c893ba02c4a35b115d337bccd7a2"); + + public void performTest() throws Exception + { + KeyFactory fact = KeyFactory.getInstance("RSA", "BC"); + + PrivateKey privKey = fact.generatePrivate(privKeySpec); + PublicKey pubKey = fact.generatePublic(pubKeySpec); + + Signature s = Signature.getInstance("SHA1withRSA/PSS", "BC"); + + s.initSign(privKey, new FixedRandom(slt1a)); + s.update(msg1a); + byte[] sig = s.sign(); + + if (!arrayEquals(sig1a, sig)) + { + fail("PSS Sign test expected " + new String(Hex.encode(sig1a)) + " got " + new String(Hex.encode(sig))); + } + + s = Signature.getInstance("SHA1withRSAandMGF1", "BC"); + + s.initVerify(pubKey); + s.update(msg1a); + if (!s.verify(sig1a)) + { + fail("SHA1 signature verification failed"); + } + + s = Signature.getInstance("SHA1withRSAandMGF1", "BC"); + + s.setParameter(PSSParameterSpec.DEFAULT); + + s.initVerify(pubKey); + s.update(msg1a); + if (!s.verify(sig1a)) + { + fail("SHA1 signature verification with default parameters failed"); + } + + AlgorithmParameters pss = s.getParameters(); + if (!arrayEquals(pss.getEncoded(), new byte[] { 0x30, 0x00 })) + { + fail("failed default encoding test."); + } + + s = Signature.getInstance("SHA256withRSA/PSS", "BC"); + + s.initSign(privKey, new FixedRandom(slt1a)); + s.update(msg1a); + sig = s.sign(); + + pss = s.getParameters(); + + if (!arrayEquals(sig1b, sig)) + { + fail("PSS Sign test expected " + new String(Hex.encode(sig1b)) + " got " + new String(Hex.encode(sig))); + } + + AlgorithmParameters pParams = AlgorithmParameters.getInstance("PSS", "BC"); + + pParams.init(pss.getEncoded()); + + PSSParameterSpec spec = (PSSParameterSpec)pParams.getParameterSpec(PSSParameterSpec.class); + + isTrue("Digest mismatch", "SHA-256".equals(spec.getDigestAlgorithm())); + isTrue("MGF alg mismatch", PSSParameterSpec.DEFAULT.getMGFAlgorithm().equals(spec.getMGFAlgorithm())); + isTrue("MGF Digest mismatch", "SHA-256".equals(((MGF1ParameterSpec)spec.getMGFParameters()).getDigestAlgorithm())); + + s = Signature.getInstance("SHA256withRSAandMGF1", "BC"); + + s.setParameter(pss.getParameterSpec(PSSParameterSpec.class)); + + s.initVerify(pubKey); + s.update(msg1a); + if (!s.verify(sig1b)) + { + fail("SHA256 signature verification failed"); + } + + // set parameter after sig intialisation + s = Signature.getInstance("RSAPSS", "BC"); + + s.initVerify(pubKey); + + s.setParameter(pss.getParameterSpec(PSSParameterSpec.class)); + + s.update(msg1a); + if (!s.verify(sig1b)) + { + fail("SHA256 signature verification failed"); + } + + s = Signature.getInstance("RSASSA-PSS", "BC"); + + s.initSign(privKey); + + s.setParameter(pss.getParameterSpec(PSSParameterSpec.class)); + + s.update(msg1a); + + sig = s.sign(); + + s.initVerify(pubKey); + + s.update(msg1a); + + if (!s.verify(sig)) + { + fail("SHA256 signature verification failed (setParameter)"); + } + + s = Signature.getInstance("RSASSA-PSS", "BC"); + + s.initSign(privKey); + + s.setParameter(pss.getParameterSpec(PSSParameterSpec.class)); + + s.update(msg1a); + + try + { + s.setParameter(pss.getParameterSpec(PSSParameterSpec.class)); + fail("no exception - setParameter byte[]"); + } + catch (ProviderException e) + { + isEquals("cannot call setParameter in the middle of update", e.getMessage()); + } + + s.initSign(privKey); + + s.update(msg1a[0]); + + try + { + s.setParameter(pss.getParameterSpec(PSSParameterSpec.class)); + fail("no exception - setParameter byte"); + } + catch (ProviderException e) + { + isEquals("cannot call setParameter in the middle of update", e.getMessage()); + } + + // + // 512 test -with zero salt length + // + s = Signature.getInstance("SHA512withRSAandMGF1", "BC"); + + s.setParameter(new PSSParameterSpec("SHA-512", "MGF1", new MGF1ParameterSpec("SHA-512"), 0, 1)); + s.initSign(privKey); + + s.update(msg1a); + sig = s.sign(); + + pss = s.getParameters(); + + if (!arrayEquals(sig1c, sig)) + { + fail("PSS Sign test expected " + new String(Hex.encode(sig1c)) + " got " + new String(Hex.encode(sig))); + } + + pParams = AlgorithmParameters.getInstance("PSS", "BC"); + + pParams.init(pss.getEncoded()); + + spec = (PSSParameterSpec)pParams.getParameterSpec(PSSParameterSpec.class); + + isTrue("Digest mismatch", "SHA-512".equals(spec.getDigestAlgorithm())); + isTrue("MGF alg mismatch", PSSParameterSpec.DEFAULT.getMGFAlgorithm().equals(spec.getMGFAlgorithm())); + isTrue("MGF Digest mismatch", "SHA-512".equals(((MGF1ParameterSpec)spec.getMGFParameters()).getDigestAlgorithm())); + + s = Signature.getInstance("SHA512withRSAandMGF1", "BC"); + + s.setParameter(pss.getParameterSpec(PSSParameterSpec.class)); + + s.initVerify(pubKey); + s.update(msg1a); + if (!s.verify(sig1c)) + { + fail("SHA512 signature verification failed"); + } + + + s = Signature.getInstance(PKCSObjectIdentifiers.id_RSASSA_PSS.getId(), "BC"); + + s.setParameter(pss.getParameterSpec(PSSParameterSpec.class)); + + s.initVerify(pubKey); + s.update(msg1a); + if (!s.verify(sig1c)) + { + fail("SHA512 signature verification failed"); + } + + SecureRandom random = new SecureRandom(); + + // Note: PSS minimum key size determined by hash/salt lengths + PrivateKey priv2048Key = fact.generatePrivate(RSATest.priv2048KeySpec); + PublicKey pub2048Key = fact.generatePublic(RSATest.pub2048KeySpec); + + rawModeTest("SHA1withRSA/PSS", X509ObjectIdentifiers.id_SHA1, priv2048Key, pub2048Key, random); + rawModeTest("SHA224withRSA/PSS", NISTObjectIdentifiers.id_sha224, priv2048Key, pub2048Key, random); + rawModeTest("SHA256withRSA/PSS", NISTObjectIdentifiers.id_sha256, priv2048Key, pub2048Key, random); + rawModeTest("SHA384withRSA/PSS", NISTObjectIdentifiers.id_sha384, priv2048Key, pub2048Key, random); + rawModeTest("SHA512withRSA/PSS", NISTObjectIdentifiers.id_sha512, priv2048Key, pub2048Key, random); + } + + private void rawModeTest(String sigName, ASN1ObjectIdentifier digestOID, + PrivateKey privKey, PublicKey pubKey, SecureRandom random) throws Exception + { + byte[] sampleMessage = new byte[1000 + random.nextInt(100)]; + random.nextBytes(sampleMessage); + + Signature normalSig = Signature.getInstance(sigName, "BC"); + + PSSParameterSpec spec = (PSSParameterSpec)normalSig.getParameters().getParameterSpec(PSSParameterSpec.class); + + // Make sure we generate the same 'random' salt for both normal and raw signers + int saltLen = spec.getSaltLength(); + byte[] fixedRandomBytes = new byte[saltLen]; + random.nextBytes(fixedRandomBytes); + + normalSig.initSign(privKey, new TestRandomData(fixedRandomBytes)); + normalSig.update(sampleMessage); + byte[] normalResult = normalSig.sign(); + + MessageDigest digest = MessageDigest.getInstance(digestOID.getId(), "BC"); + byte[] hash = digest.digest(sampleMessage); + + Signature rawSig = Signature.getInstance("RAWRSASSA-PSS", "BC"); + + // Need to init the params explicitly to avoid having a 'raw' variety of every PSS algorithm + rawSig.setParameter(spec); + + rawSig.initSign(privKey, new TestRandomData(fixedRandomBytes)); + rawSig.update(hash); + byte[] rawResult = rawSig.sign(); + + if (!Arrays.areEqual(normalResult, rawResult)) + { + fail("raw mode signature differs from normal one"); + } + + rawSig.initVerify(pubKey); + rawSig.update(hash); + + if (!rawSig.verify(rawResult)) + { + fail("raw mode signature verification failed"); + } + } + + public String getName() + { + return "PSSTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new PSSTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/Poly1305Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/Poly1305Test.java new file mode 100644 index 000000000..4014b083c --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/Poly1305Test.java @@ -0,0 +1,191 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.NoSuchAlgorithmException; +import java.security.Security; +import java.util.ArrayList; +import java.util.List; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.crypto.generators.Poly1305KeyGenerator; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestFailedException; + +public class Poly1305Test + extends SimpleTest +{ + private static final byte[] MASTER_KEY = Hex + .decode("01bcb20bfc8b6e03609ddd09f44b060f"+"95cc0e44d0b79a8856afcae1bec4fe3c"); + + public String getName() + { + return "Poly1305"; + } + + public void performTest() + throws Exception + { + checkRawPoly1305(); + checkRegistrations(); + } + + private void checkRegistrations() + throws Exception + { + List missingMacs = new ArrayList(); + List missingKeyGens = new ArrayList(); + + String[] ciphers = new String[]{"AES", "NOEKEON", "Twofish", "CAST6", "SEED", "Serpent", "SM4", "RC6", "CAMELLIA"}; + String[] macs = new String[]{ + "4bb5e21dd13001ed5faccfcfdaf8a854", + "6d601be3d5ebbb9972a64ed3223d913d", + "211195296d9afc7b35a1223a79487c87", + "f328857a1b653684e73760c804c55b1d", + "21cd8adb23ca84eb4dbb12780595bf28", + "c218102702d8a2ee5c9ef9000e91454d", + "9bb04be6a1c314a9054ae3c94d3c941b", + "db86de7b1fcae429753d68b1263d7ca0", + "11918174f33a2f278fb86554da094112"}; + + for (int i = 0; i < ciphers.length; i++) + { + String cipherName = ciphers[i]; + Cipher cipher; + try + { + cipher = Cipher.getInstance(cipherName, "BC"); + } + catch (Exception e) + { + System.err.println(cipherName + ": " + e.getMessage()); + continue; + } + int blocksize; + try + { + blocksize = cipher.getBlockSize(); + } + catch (Exception e) + { + System.err.println(cipherName + ": " + e.getMessage()); + continue; + } + // Poly1305 is defined over 128 bit block ciphers + if (blocksize == 16) + { + String macName = "Poly1305-" + cipherName; + String macNameAlt = "Poly1305" + cipherName; + + // Check we have a Poly1305 registered for each name + checkMac(macName, missingMacs, missingKeyGens, macs[i]); + checkMac(macNameAlt, missingMacs, missingKeyGens, macs[i]); + } + } + if (missingMacs.size() != 0) + { + fail("Did not find Poly1305 registrations for the following ciphers: " + missingMacs); + } + if (missingKeyGens.size() != 0) + { + fail("Did not find Poly1305 KeyGenerator registrations for the following macs: " + missingKeyGens); + } + } + + private void checkRawPoly1305() + throws Exception + { + checkMac("Poly1305", "e8bd1466eaf442dd71598370c1e34392"); + } + + private void checkMac(String name, String macOutput) + throws Exception + { + KeyGenerator kg = KeyGenerator.getInstance(name); + SecretKey key = kg.generateKey(); + + try + { + Poly1305KeyGenerator.checkKey(key.getEncoded()); + } + catch (IllegalArgumentException e) + { + fail("Generated key for algo " + name + " does not match required Poly1305 format."); + } + + Mac mac = Mac.getInstance(name); + mac.init(new SecretKeySpec(MASTER_KEY, name)); + mac.update(new byte[128]); + byte[] bytes = mac.doFinal(); + + if (!Arrays.areEqual(bytes, Hex.decode(macOutput))) + { + fail("wrong mac value computed for " + name, macOutput, new String(Hex.encode(bytes))); + } + } + + private void checkMac(String name, List missingMacs, List missingKeyGens, String macOutput) + { + try + { + try + { + KeyGenerator kg = KeyGenerator.getInstance(name); + SecretKey key = kg.generateKey(); + + try + { + Poly1305KeyGenerator.checkKey(key.getEncoded()); + } + catch (IllegalArgumentException e) + { + fail("Generated key for algo " + name + " does not match required Poly1305 format."); + } + + try + { + Mac mac = Mac.getInstance(name); + mac.init(new SecretKeySpec(MASTER_KEY, name), new IvParameterSpec(new byte[16])); + mac.update(new byte[128]); + byte[] bytes = mac.doFinal(); + + if (!Arrays.areEqual(bytes, Hex.decode(macOutput))) + { + fail("wrong mac value computed for " + name, macOutput, new String(Hex.encode(bytes))); + } + } + catch (NoSuchAlgorithmException e) + { + missingMacs.add(name); + } + + } + catch (NoSuchAlgorithmException e) + { + missingKeyGens.add(name); + } + } + catch (TestFailedException e) + { + throw e; + } + catch (Exception e) + { + fail("Unexpected error", e); + } + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new Poly1305Test()); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/RSATest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/RSATest.java new file mode 100644 index 000000000..3ca8c6b27 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/RSATest.java @@ -0,0 +1,941 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.math.BigInteger; +import java.security.AlgorithmParameters; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.MGF1ParameterSpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAKeyGenParameterSpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPrivateKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.HashSet; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.spec.OAEPParameterSpec; +import javax.crypto.spec.PSource; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.pkcs.RSAESOAEPparams; +import com.fr.third.org.bouncycastle.asn1.teletrust.TeleTrusTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.DigestInfo; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x509.X509ObjectIdentifiers; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class RSATest + extends SimpleTest +{ + /** + * a fake random number generator - we just want to make sure the random numbers + * aren't random so that we get the same output, while still getting to test the + * key generation facilities. + */ + private class FixedSecureRandom + extends SecureRandom + { + byte[] seed = { + (byte)0xaa, (byte)0xfd, (byte)0x12, (byte)0xf6, (byte)0x59, + (byte)0xca, (byte)0xe6, (byte)0x34, (byte)0x89, (byte)0xb4, + (byte)0x79, (byte)0xe5, (byte)0x07, (byte)0x6d, (byte)0xde, + (byte)0xc2, (byte)0xf0, (byte)0x6c, (byte)0xb5, (byte)0x8f + }; + + public void nextBytes( + byte[] bytes) + { + int offset = 0; + + while ((offset + seed.length) < bytes.length) + { + System.arraycopy(seed, 0, bytes, offset, seed.length); + offset += seed.length; + } + + System.arraycopy(seed, 0, bytes, offset, bytes.length - offset); + } + } + + private RSAPublicKeySpec pubKeySpec = new RSAPublicKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16)); + + private RSAPrivateCrtKeySpec privKeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("b4a7e46170574f16a97082b22be58b6a2a629798419be12872a4bdba626cfae9900f76abfb12139dce5de56564fab2b6543165a040c606887420e33d91ed7ed7", 16), + new BigInteger("11", 16), + new BigInteger("9f66f6b05410cd503b2709e88115d55daced94d1a34d4e32bf824d0dde6028ae79c5f07b580f5dce240d7111f7ddb130a7945cd7d957d1920994da389f490c89", 16), + new BigInteger("c0a0758cdf14256f78d4708c86becdead1b50ad4ad6c5c703e2168fbf37884cb", 16), + new BigInteger("f01734d7960ea60070f1b06f2bb81bfac48ff192ae18451d5e56c734a5aab8a5", 16), + new BigInteger("b54bb9edff22051d9ee60f9351a48591b6500a319429c069a3e335a1d6171391", 16), + new BigInteger("d3d83daf2a0cecd3367ae6f8ae1aeb82e9ac2f816c6fc483533d8297dd7884cd", 16), + new BigInteger("b8f52fc6f38593dabb661d3f50f8897f8106eee68b1bce78a95b132b4e5b5d19", 16)); + + private RSAPublicKeySpec isoPubKeySpec = new RSAPublicKeySpec( + new BigInteger("0100000000000000000000000000000000bba2d15dbb303c8a21c5ebbcbae52b7125087920dd7cdf358ea119fd66fb064012ec8ce692f0a0b8e8321b041acd40b7", 16), + new BigInteger("03", 16)); + + private RSAPrivateKeySpec isoPrivKeySpec = new RSAPrivateKeySpec( + new BigInteger("0100000000000000000000000000000000bba2d15dbb303c8a21c5ebbcbae52b7125087920dd7cdf358ea119fd66fb064012ec8ce692f0a0b8e8321b041acd40b7", 16), + new BigInteger("2aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaac9f0783a49dd5f6c5af651f4c9d0dc9281c96a3f16a85f9572d7cc3f2d0f25a9dbf1149e4cdc32273faadd3fda5dcda7", 16)); + + static RSAPublicKeySpec pub2048KeySpec = new RSAPublicKeySpec( + new BigInteger("a7295693155b1813bb84877fb45343556e0568043de5910872a3a518cc11e23e2db74eaf4545068c4e3d258a2718fbacdcc3eafa457695b957e88fbf110aed049a992d9c430232d02f3529c67a3419935ea9b569f85b1bcd37de6b899cd62697e843130ff0529d09c97d813cb15f293751ff56f943fbdabb63971cc7f4f6d5bff1594416b1f5907bde5a84a44f9802ef29b43bda1960f948f8afb8766c1ab80d32eec88ed66d0b65aebe44a6d0b3c5e0ab051aaa1b912fbcc17b8e751ddecc5365b6db6dab0020c3057db4013a51213a5798a3aab67985b0f4d88627a54a0f3f0285fbcb4afdfeb65cb153af66825656d43238b75503231500753f4e421e3c57", 16), + new BigInteger("10001", 16)); + + static RSAPrivateCrtKeySpec priv2048KeySpec = new RSAPrivateCrtKeySpec( + new BigInteger("a7295693155b1813bb84877fb45343556e0568043de5910872a3a518cc11e23e2db74eaf4545068c4e3d258a2718fbacdcc3eafa457695b957e88fbf110aed049a992d9c430232d02f3529c67a3419935ea9b569f85b1bcd37de6b899cd62697e843130ff0529d09c97d813cb15f293751ff56f943fbdabb63971cc7f4f6d5bff1594416b1f5907bde5a84a44f9802ef29b43bda1960f948f8afb8766c1ab80d32eec88ed66d0b65aebe44a6d0b3c5e0ab051aaa1b912fbcc17b8e751ddecc5365b6db6dab0020c3057db4013a51213a5798a3aab67985b0f4d88627a54a0f3f0285fbcb4afdfeb65cb153af66825656d43238b75503231500753f4e421e3c57", 16), + new BigInteger("10001", 16), + new BigInteger("65dad56ac7df7abb434e4cb5eeadb16093aa6da7f0033aad3815289b04757d32bfee6ade7749c8e4a323b5050a2fb9e2a99e23469e1ed4ba5bab54336af20a5bfccb8b3424cc6923db2ffca5787ed87aa87aa614cd04cedaebc8f623a2d2063017910f436dff18bb06f01758610787f8b258f0a8efd8bd7de30007c47b2a1031696c7d6523bc191d4d918927a7e0b09584ed205bd2ff4fc4382678df82353f7532b3bbb81d69e3f39070aed3fb64fce032a089e8e64955afa5213a6eb241231bd98d702fba725a9b205952fda186412d9e0d9344d2998c455ad8c2bae85ee672751466d5288304032b5b7e02f7e558c7af82c7fbf58eea0bb4ef0f001e6cd0a9", 16), + new BigInteger("d4fd9ac3474fb83aaf832470643609659e511b322632b239b688f3cd2aad87527d6cf652fb9c9ca67940e84789444f2e99b0cb0cfabbd4de95396106c865f38e2fb7b82b231260a94df0e01756bf73ce0386868d9c41645560a81af2f53c18e4f7cdf3d51d80267372e6e0216afbf67f655c9450769cca494e4f6631b239ce1b", 16), + new BigInteger("c8eaa0e2a1b3a4412a702bccda93f4d150da60d736c99c7c566fdea4dd1b401cbc0d8c063daaf0b579953d36343aa18b33dbf8b9eae94452490cc905245f8f7b9e29b1a288bc66731a29e1dd1a45c9fd7f8238ff727adc49fff73991d0dc096206b9d3a08f61e7462e2b804d78cb8c5eccdb9b7fbd2ad6a8fea46c1053e1be75", 16), + new BigInteger("10edcb544421c0f9e123624d1099feeb35c72a8b34e008ac6fa6b90210a7543f293af4e5299c8c12eb464e70092805c7256e18e5823455ba0f504d36f5ccacac1b7cd5c58ff710f9c3f92646949d88fdd1e7ea5fed1081820bb9b0d2a8cd4b093fecfdb96dabd6e28c3a6f8c186dc86cddc89afd3e403e0fcf8a9e0bcb27af0b", 16), + new BigInteger("97fc25484b5a415eaa63c03e6efa8dafe9a1c8b004d9ee6e80548fefd6f2ce44ee5cb117e77e70285798f57d137566ce8ea4503b13e0f1b5ed5ca6942537c4aa96b2a395782a4cb5b58d0936e0b0fa63b1192954d39ced176d71ef32c6f42c84e2e19f9d4dd999c2151b032b97bd22aa73fd8c5bcd15a2dca4046d5acc997021", 16), + new BigInteger("4bb8064e1eff7e9efc3c4578fcedb59ca4aef0993a8312dfdcb1b3decf458aa6650d3d0866f143cbf0d3825e9381181170a0a1651eefcd7def786b8eb356555d9fa07c85b5f5cbdd74382f1129b5e36b4166b6cc9157923699708648212c484958351fdc9cf14f218dbe7fbf7cbd93a209a4681fe23ceb44bab67d66f45d1c9d", 16)); + + public void performTest() + throws Exception + { + KeyFactory fact; + byte[] input = new byte[] + { (byte)0x54, (byte)0x85, (byte)0x9b, (byte)0x34, (byte)0x2c, (byte)0x49, (byte)0xea, (byte)0x2a }; + byte[][] output = new byte[][] + { + Hex.decode("8b427f781a2e59dd9def386f1956b996ee07f48c96880e65a368055ed8c0a8831669ef7250b40918b2b1d488547e72c84540e42bd07b03f14e226f04fbc2d929"), + Hex.decode("2ec6e1a1711b6c7b8cd3f6a25db21ab8bb0a5f1d6df2ef375fa708a43997730ffc7c98856dbbe36edddcdd1b2d2a53867d8355af94fea3aeec128da908e08f4c"), + Hex.decode("0850ac4e5a8118323200c8ed1e5aaa3d5e635172553ccac66a8e4153d35c79305c4440f11034ab147fccce21f18a50cf1c0099c08a577eb68237a91042278965"), + Hex.decode("1c9649bdccb51056751fe43837f4eb43bada472accf26f65231666d5de7d11950d8379b3596dfdf75c6234274896fa8d18ad0865d3be2ac4d6687151abdf01e93941dcef18fa63186c9351d1506c89d09733c5ff4304208c812bdd21a50f56fde115e629e0e973721c9fcc87e89295a79853dee613962a0b2f2fc57163fd99057a3c776f13c20c26407eb8863998d7e53b543ba8d0a295a9a68d1a149833078c9809ad6a6dad7fc22a95ad615a73138c54c018f40d99bf8eeecd45f5be526f2d6b01aeb56381991c1ab31a2e756f15e052b9cd5638b2eff799795c5bae493307d5eb9f8c21d438de131fe505a4e7432547ab19224094f9e4be1968bd0793b79d"), + Hex.decode("4c4afc0c24dddaedd4f9a3b23be30d35d8e005ffd36b3defc5d18acc830c3ed388ce20f43a00e614fd087c814197bc9fc2eff9ad4cc474a7a2ef3ed9c0f0a55eb23371e41ee8f2e2ed93ea3a06ca482589ab87e0d61dcffda5eea1241408e43ea1108726cdb87cc3aa5e9eaaa9f72507ca1352ac54a53920c94dccc768147933d8c50aefd9d1da10522a40133cd33dbc0524669e70f771a88d65c4716d471cd22b08b9f01f24e4e9fc7ffbcfa0e0a7aed47b345826399b26a73be112eb9c5e06fc6742fc3d0ef53d43896403c5105109cfc12e6deeaf4a48ba308e039774b9bdb31a9b9e133c81c321630cf0b4b2d1f90717b24c3268e1fea681ea9cdc709342"), + Hex.decode("06b5b26bd13515f799e5e37ca43cace15cd82fd4bf36b25d285a6f0998d97c8cb0755a28f0ae66618b1cd03e27ac95eaaa4882bc6dc0078cd457d4f7de4154173a9c7a838cfc2ac2f74875df462aae0cfd341645dc51d9a01da9bdb01507f140fa8a016534379d838cc3b2a53ac33150af1b242fc88013cb8d914e66c8182864ee6de88ce2879d4c05dd125409620a96797c55c832fb2fb31d4310c190b8ed2c95fdfda2ed87f785002faaec3f35ec05cf70a3774ce185e4882df35719d582dd55ac31257344a9cba95189dcbea16e8c6cb7a235a0384bc83b6183ca8547e670fe33b1b91725ae0c250c9eca7b5ba78bd77145b70270bf8ac31653006c02ca9c"), + Hex.decode("135f1be3d045526235bf9d5e43499d4ee1bfdf93370769ae56e85dbc339bc5b7ea3bee49717497ee8ac3f7cd6adb6fc0f17812390dcd65ac7b87fef7970d9ff9"), + Hex.decode("03c05add1e030178c352face07cafc9447c8f369b8f95125c0d311c16b6da48ca2067104cce6cd21ae7b163cd18ffc13001aecebdc2eb02b9e92681f84033a98"), + Hex.decode("00319bb9becb49f3ed1bca26d0fcf09b0b0a508e4d0bd43b350f959b72cd25b3af47d608fdcd248eada74fbe19990dbeb9bf0da4b4e1200243a14e5cab3f7e610c") + }; + SecureRandom rand = new FixedSecureRandom(); + + + fact = KeyFactory.getInstance("RSA", "BC"); + + PrivateKey privKey = fact.generatePrivate(privKeySpec); + PublicKey pubKey = fact.generatePublic(pubKeySpec); + + PrivateKey priv2048Key = fact.generatePrivate(priv2048KeySpec); + PublicKey pub2048Key = fact.generatePublic(pub2048KeySpec); + + // + // key without CRT coefficients + // + PrivateKeyInfo keyInfo = PrivateKeyInfo.getInstance(privKey.getEncoded()); + BigInteger zero = BigInteger.valueOf(0); + PKCS8EncodedKeySpec noCrtSpec = new PKCS8EncodedKeySpec(new PrivateKeyInfo(keyInfo.getPrivateKeyAlgorithm(), + new com.fr.third.org.bouncycastle.asn1.pkcs.RSAPrivateKey(privKeySpec.getModulus(), privKeySpec.getPublicExponent(), privKeySpec.getPrivateExponent(), zero, zero, zero, zero, zero)).getEncoded()); + + PrivateKey noCrtKey = fact.generatePrivate(noCrtSpec); + if (noCrtKey instanceof RSAPrivateCrtKey) + { + fail("private key without CRT coefficients returned as CRT key"); + } + + // + // No Padding + // + Cipher c = Cipher.getInstance("RSA", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + byte[] out = c.doFinal(input); + + if (!areEqual(out, output[0])) + { + fail("NoPadding test failed on encrypt expected " + new String(Hex.encode(output[0])) + " got " + new String(Hex.encode(out))); + } + + c.init(Cipher.DECRYPT_MODE, privKey); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("NoPadding test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + // + // No Padding - incremental + // + c = Cipher.getInstance("RSA", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + c.update(input); + + out = c.doFinal(); + + if (!areEqual(out, output[0])) + { + fail("NoPadding test failed on encrypt expected " + new String(Hex.encode(output[0])) + " got " + new String(Hex.encode(out))); + } + + c.init(Cipher.DECRYPT_MODE, privKey); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("NoPadding test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + // + // No Padding - incremental - explicit use of NONE in mode. + // + c = Cipher.getInstance("RSA/NONE/NoPadding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + c.update(input); + + out = c.doFinal(); + + if (!areEqual(out, output[0])) + { + fail("NoPadding test failed on encrypt expected " + new String(Hex.encode(output[0])) + " got " + new String(Hex.encode(out))); + } + + c.init(Cipher.DECRYPT_MODE, privKey); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("NoPadding test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + // + // No Padding - maximum length + // + c = Cipher.getInstance("RSA", "BC"); + + byte[] modBytes = ((RSAPublicKey)pubKey).getModulus().toByteArray(); + byte[] maxInput = new byte[modBytes.length - 1]; + + maxInput[0] |= 0x7f; + + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + out = c.doFinal(maxInput); + + c.init(Cipher.DECRYPT_MODE, privKey); + + out = c.doFinal(out); + + if (!areEqual(out, maxInput)) + { + fail("NoPadding test failed on decrypt expected " + new String(Hex.encode(maxInput)) + " got " + new String(Hex.encode(out))); + } + + // + // PKCS1 V 1.5 + // + c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + out = c.doFinal(input); + + if (!areEqual(out, output[1])) + { + fail("PKCS1 test failed on encrypt expected " + new String(Hex.encode(output[1])) + " got " + new String(Hex.encode(out))); + } + + c.init(Cipher.DECRYPT_MODE, privKey); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("PKCS1 test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + // + // PKCS1 V 1.5 - NONE + // + c = Cipher.getInstance("RSA/NONE/PKCS1Padding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + out = c.doFinal(input); + + if (!areEqual(out, output[1])) + { + fail("PKCS1 test failed on encrypt expected " + new String(Hex.encode(output[1])) + " got " + new String(Hex.encode(out))); + } + + c.init(Cipher.DECRYPT_MODE, privKey); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("PKCS1 test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + // + // OAEP - SHA1 + // + c = Cipher.getInstance("RSA/NONE/OAEPPadding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + out = c.doFinal(input); + + if (!areEqual(out, output[2])) + { + fail("OAEP test failed on encrypt expected " + new String(Hex.encode(output[2])) + " got " + new String(Hex.encode(out))); + } + + c = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC"); + + c.init(Cipher.DECRYPT_MODE, privKey); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("OAEP test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + AlgorithmParameters oaepP = c.getParameters(); + + if (!areEqual(oaepP.getEncoded(), + new RSAESOAEPparams( + new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE)), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]))).getEncoded())) + { + fail("OAEP test failed default sha-1 parameters"); + } + + // + // OAEP - SHA224 + // + c = Cipher.getInstance("RSA/NONE/OAEPWithSHA224AndMGF1Padding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pub2048Key, rand); + + out = c.doFinal(input); + + if (!areEqual(out, output[3])) + { + fail("OAEP SHA-224 test failed on encrypt expected " + new String(Hex.encode(output[2])) + " got " + new String(Hex.encode(out))); + } + + c.init(Cipher.DECRYPT_MODE, priv2048Key); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("OAEP SHA-224 test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + oaepP = c.getParameters(); + + if (!areEqual(oaepP.getEncoded(), + new RSAESOAEPparams( + new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha224, DERNull.INSTANCE)), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]))).getEncoded())) + { + fail("OAEP test failed default sha-224 parameters"); + } + + // + // OAEP - SHA 256 + // + c = Cipher.getInstance("RSA/NONE/OAEPWithSHA256AndMGF1Padding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pub2048Key, rand); + + out = c.doFinal(input); + + if (!areEqual(out, output[4])) + { + fail("OAEP SHA-256 test failed on encrypt expected " + new String(Hex.encode(output[2])) + " got " + new String(Hex.encode(out))); + } + + c.init(Cipher.DECRYPT_MODE, priv2048Key); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("OAEP SHA-256 test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + oaepP = c.getParameters(); + + if (!areEqual(oaepP.getEncoded(), + new RSAESOAEPparams( + new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE)), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]))).getEncoded())) + { + fail("OAEP test failed default sha-256 parameters"); + } + + // + // OAEP - SHA 384 + // + c = Cipher.getInstance("RSA/NONE/OAEPWithSHA384AndMGF1Padding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pub2048Key, rand); + + out = c.doFinal(input); + + if (!areEqual(out, output[5])) + { + fail("OAEP SHA-384 test failed on encrypt expected " + new String(Hex.encode(output[2])) + " got " + new String(Hex.encode(out))); + } + + c.init(Cipher.DECRYPT_MODE, priv2048Key); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("OAEP SHA-384 test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + oaepP = c.getParameters(); + + if (!areEqual(oaepP.getEncoded(), + new RSAESOAEPparams( + new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha384, DERNull.INSTANCE)), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]))).getEncoded())) + { + fail("OAEP test failed default sha-384 parameters"); + } + + // + // OAEP - MD5 + // + c = Cipher.getInstance("RSA/NONE/OAEPWithMD5AndMGF1Padding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + out = c.doFinal(input); + + if (!areEqual(out, output[6])) + { + fail("OAEP MD5 test failed on encrypt expected " + new String(Hex.encode(output[2])) + " got " + new String(Hex.encode(out))); + } + + c.init(Cipher.DECRYPT_MODE, privKey); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("OAEP MD5 test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + oaepP = c.getParameters(); + + if (!areEqual(oaepP.getEncoded(), + new RSAESOAEPparams( + new AlgorithmIdentifier(PKCSObjectIdentifiers.md5, DERNull.INSTANCE), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, new AlgorithmIdentifier(PKCSObjectIdentifiers.md5, DERNull.INSTANCE)), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]))).getEncoded())) + { + fail("OAEP test failed default md5 parameters"); + } + + // + // OAEP - SHA1 with default parameters + // + c = Cipher.getInstance("RSA/NONE/OAEPPadding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey, OAEPParameterSpec.DEFAULT, rand); + + out = c.doFinal(input); + + if (!areEqual(out, output[2])) + { + fail("OAEP test failed on encrypt expected " + new String(Hex.encode(output[2])) + " got " + new String(Hex.encode(out))); + } + + c = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC"); + + c.init(Cipher.DECRYPT_MODE, privKey); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("OAEP test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + oaepP = c.getParameters(); + + if (!areEqual(oaepP.getEncoded(), new byte[] { 0x30, 0x00 })) + { + fail("OAEP test failed default parameters"); + } + + // + // OAEP - SHA1 with specified string + // + c = Cipher.getInstance("RSA/NONE/OAEPPadding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey, new OAEPParameterSpec("SHA1", "MGF1", new MGF1ParameterSpec("SHA1"), new PSource.PSpecified(new byte[] { 1, 2, 3, 4, 5 })), rand); + + out = c.doFinal(input); + + oaepP = c.getParameters(); + + if (!areEqual(oaepP.getEncoded(), + new RSAESOAEPparams( + new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1, DERNull.INSTANCE)), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[] { 1, 2, 3, 4, 5 }))).getEncoded())) + { + fail("OAEP test failed changed sha-1 parameters"); + } + + if (!areEqual(out, output[7])) + { + fail("OAEP test failed on encrypt expected " + new String(Hex.encode(output[2])) + " got " + new String(Hex.encode(out))); + } + + c = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC"); + + c.init(Cipher.DECRYPT_MODE, privKey, oaepP); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("OAEP test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + // + // ISO9796-1 + // + byte[] isoInput = Hex.decode("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"); + PrivateKey isoPrivKey = fact.generatePrivate(isoPrivKeySpec); + PublicKey isoPubKey = fact.generatePublic(isoPubKeySpec); + + c = Cipher.getInstance("RSA/NONE/ISO9796-1Padding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, isoPrivKey); + + out = c.doFinal(isoInput); + + if (!areEqual(out, output[8])) + { + fail("ISO9796-1 test failed on encrypt expected " + new String(Hex.encode(output[3])) + " got " + new String(Hex.encode(out))); + } + + c.init(Cipher.DECRYPT_MODE, isoPubKey); + + out = c.doFinal(out); + + if (!areEqual(out, isoInput)) + { + fail("ISO9796-1 test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + // + // + // generation with parameters test. + // + KeyPairGenerator keyPairGen = + KeyPairGenerator.getInstance("RSA", "BC"); + + // + // 768 bit RSA with e = 2^16-1 + // + keyPairGen.initialize( + new RSAKeyGenParameterSpec(768, + BigInteger.valueOf(65537)), + new SecureRandom()); + + KeyPair kp = keyPairGen.generateKeyPair(); + + pubKey = kp.getPublic(); + privKey = kp.getPrivate(); + + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + out = c.doFinal(input); + + c.init(Cipher.DECRYPT_MODE, privKey); + + out = c.doFinal(out); + + if (!areEqual(out, input)) + { + fail("key generation test failed on decrypt expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(out))); + } + + // + // comparison check + // + KeyFactory keyFact = KeyFactory.getInstance("RSA", "BC"); + + RSAPrivateCrtKey crtKey = (RSAPrivateCrtKey)keyFact.translateKey(privKey); + + if (!privKey.equals(crtKey)) + { + fail("private key equality check failed"); + } + + crtKey = (RSAPrivateCrtKey)keyFact.generatePrivate(new PKCS8EncodedKeySpec(privKey.getEncoded())); + + if (!privKey.equals(crtKey)) + { + fail("private key equality check failed"); + } + + crtKey = (RSAPrivateCrtKey)serializeDeserialize(privKey); + + if (!privKey.equals(crtKey)) + { + fail("private key equality check failed"); + } + + if (privKey.hashCode() != crtKey.hashCode()) + { + fail("private key hashCode check failed"); + } + + RSAPublicKey copyKey = (RSAPublicKey)keyFact.translateKey(pubKey); + + if (!pubKey.equals(copyKey)) + { + fail("public key equality check failed"); + } + + copyKey = (RSAPublicKey)keyFact.generatePublic(new X509EncodedKeySpec(pubKey.getEncoded())); + + if (!pubKey.equals(copyKey)) + { + fail("public key equality check failed"); + } + + copyKey = (RSAPublicKey)serializeDeserialize(pubKey); + + if (!pubKey.equals(copyKey)) + { + fail("public key equality check failed"); + } + + if (pubKey.hashCode() != copyKey.hashCode()) + { + fail("public key hashCode check failed"); + } + + // + // test an OAEP key + // + SubjectPublicKeyInfo oaepKey = new SubjectPublicKeyInfo(new AlgorithmIdentifier(PKCSObjectIdentifiers.id_RSAES_OAEP, new RSAESOAEPparams()), + SubjectPublicKeyInfo.getInstance(pubKey.getEncoded()).parsePublicKey()); + + copyKey = (RSAPublicKey)serializeDeserialize(keyFact.generatePublic(new X509EncodedKeySpec(oaepKey.getEncoded()))); + + if (!pubKey.equals(copyKey)) + { + fail("public key equality check failed"); + } + + if (pubKey.hashCode() != copyKey.hashCode()) + { + fail("public key hashCode check failed"); + } + + if (!Arrays.areEqual(copyKey.getEncoded(), oaepKey.getEncoded())) + { + fail("encoding does not match"); + } + + oaepCompatibilityTest("SHA-1", priv2048Key, pub2048Key); + // TODO: oaepCompatibilityTest("SHA-224", priv2048Key, pub2048Key); commented out as fails in JDK 1.7 + oaepCompatibilityTest("SHA-256", priv2048Key, pub2048Key); + oaepCompatibilityTest("SHA-384", priv2048Key, pub2048Key); + oaepCompatibilityTest("SHA-512", priv2048Key, pub2048Key); + + SecureRandom random = new SecureRandom(); + rawModeTest("SHA1withRSA", X509ObjectIdentifiers.id_SHA1, priv2048Key, pub2048Key, random); + rawModeTest("MD5withRSA", PKCSObjectIdentifiers.md5, priv2048Key, pub2048Key, random); + rawModeTest("RIPEMD128withRSA", TeleTrusTObjectIdentifiers.ripemd128, priv2048Key, pub2048Key, random); + + // init reset test + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + out = c.update(new byte[40]); + + c.init(Cipher.ENCRYPT_MODE, pubKey, rand); + + out = c.update(new byte[40]); + + testGetExceptionsPKCS1(); + zeroMessageTest(); + + oaepDigestCheck("SHA3-224", NISTObjectIdentifiers.id_sha3_224, pub2048Key, priv2048Key, rand, Hex.decode("2aa7812d4f7b7766f8625feb58481ef5b5fa6dfafbea543e4bbba89d6708f4900fc9fd55d5c2b83fefefc67e2ba7a4222217efaa9b9d31920bdcd78733319aca910dfd118aae5e901a6d27a56e37b1a6f86e7404f82da248e77845e58b789f10a1af8a1208f77dda384692609339346c4ea57928b890042e7d70b1d5817f8978dcbc9cd2fcdde37a0a41a52dbef701ddc859a5d58efd10aa5bd8d205c10154db906540bf20dedcff721df11a456df201cb9cbbd092a89a1eb3f11e7e34003d7070e02c8db54e5498e7ee262fb9178f5eb85d1db66baafe0a66e8283df9c41bded218e5d906d28f08803deb3cbd1a92777d55fe56ff022a47f673cac2ca145973")); + oaepDigestCheck("SHA3-256", NISTObjectIdentifiers.id_sha3_256, pub2048Key, priv2048Key, rand, Hex.decode("4460e68586ac0ca1832274919c6b9159d40ea1d383a32ca28f0e1a81962289c8c904fa117d90afd7bfefa51b6889d2d999efb72bafd4beb5594bb08f62532ecb077e4968f43e70673341e60649ed64ac49cf1a2396a64577767d8958217a251938a7ac1bbc1aec9c9197a2eb9a375c74a01097fe3717c8bde04f8a20df85ef10a59070970a4a6470131654cecb641d46e464f17ddfe7e0595025bf25f025edbd56b19487cfc87de1642ca5190f289cf78e2c4b1cf90e73ffae331581c23febcf490c32299f2e5bd5a354a0cc996cc692b5a318777d17e734b3c487ad615df7af0fc361af564e6970ee0aa9b140634cdcf1eda91d1a1156326caaa608c4d43ee4")); + oaepDigestCheck("SHA3-384", NISTObjectIdentifiers.id_sha3_384, pub2048Key, priv2048Key, rand, Hex.decode("1b9f490569bddac8ea77e3bec8d6d38b159cb88545de86065dbc8757b35fdeb0cce90eaf93ec6d69d691c590fc3feec9974b80e0c0068929c77533be2066b4002ad6d195e473f72e8581255b8d2dfff016ff27ed50e6d3e63cfaf50851b2d43833eea8dab3b4506f517875659099815a96be6e8fd2dc1417c6e3ffadcfd3f494a5544267688d114d3eeaf43ea954686656afb7a3dc2f8a4cdc5d7b90a97acbbe32ff17b3d26d7eb2a4fbc847d49cc8cb8f837646613d1b5a78096cf3f48acf4be95205e0c4cb283447029eae1442fe3813a017604dfd59a9e841473f4d8914860f785fb2194b21cba47cd401bc32720f3df373e59336c3d64c61babd474b4bbe")); + oaepDigestCheck("SHA3-512", NISTObjectIdentifiers.id_sha3_512, pub2048Key, priv2048Key, rand, Hex.decode("7b7870bb5ae52276a8b06b59f7321043afb1fa4e5dbca9f14bcce9efaacded531f090646ab0f8701b012cc93c51e0a8591043e6457cde1950f4ffc8ad87d946622ea48a70f95f40c22d88679eb92c10c19db487fd64857d723daf4ccfe749fdd05e6c0be28de57e09d3b5a0981322b6cc7a9743a50eec355a7af5bdcdcddc5e279ad90f599b68c47fdb39916c7a597cf989169e8667fd8602e88c9c128085d0e158ea75eeb37919a91cdf3f2cd5394adaadc4a2f25a6222d2637cb464841dc5820e54843495cb97af6b19edc72f137123813f5d78503232f79e4f617be3a9f09b0206634a2ecfe457dbd71d2d3d8e3dbca486e75e543f559dcea3112ad50a21d")); + } + + public void oaepDigestCheck(String digest, ASN1ObjectIdentifier oid, PublicKey pubKey, PrivateKey privKey, SecureRandom rand, byte[] expected) + throws Exception + { + byte[] input = new byte[] + {(byte)0x54, (byte)0x85, (byte)0x9b, (byte)0x34, (byte)0x2c, (byte)0x49, (byte)0xea, (byte)0x2a}; + + Cipher c = Cipher.getInstance("RSA/NONE/OAEPPadding", "BC"); + + c.init(Cipher.ENCRYPT_MODE, pubKey, new OAEPParameterSpec(digest, "MGF1", new MGF1ParameterSpec(digest), PSource.PSpecified.DEFAULT), rand); + + byte[] out = c.doFinal(input); + + isTrue("OAEP decrypt failed", Arrays.areEqual(expected, out)); + + AlgorithmParameters oaepP = c.getParameters(); + + if (!areEqual(oaepP.getEncoded(), + new RSAESOAEPparams( + new AlgorithmIdentifier(oid, DERNull.INSTANCE), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_mgf1, new AlgorithmIdentifier(oid, DERNull.INSTANCE)), + new AlgorithmIdentifier(PKCSObjectIdentifiers.id_pSpecified, new DEROctetString(new byte[0]))).getEncoded())) + { + fail("OAEP test failed changed parameters for " + digest); + } + + c = Cipher.getInstance("RSA/NONE/OAEPWith" + digest + "AndMGF1Padding", "BC"); + + c.init(Cipher.DECRYPT_MODE, privKey); + + byte[] dec = c.doFinal(out); + + isTrue("OAEP decrypt failed", Arrays.areEqual(input, dec)); + + AlgorithmParameters parameters = AlgorithmParameters.getInstance("OAEP", "BC"); + + parameters.init(oaepP.getEncoded()); + + OAEPParameterSpec spec = (OAEPParameterSpec)parameters.getParameterSpec(OAEPParameterSpec.class); + + isTrue("Digest mismatch", digest.equals(spec.getDigestAlgorithm())); + isTrue("MGF alg mismatch", OAEPParameterSpec.DEFAULT.getMGFAlgorithm().equals(spec.getMGFAlgorithm())); + isTrue("MGF Digest mismatch", digest.equals(((MGF1ParameterSpec)spec.getMGFParameters()).getDigestAlgorithm())); + + } + + public void testGetExceptionsPKCS1() + throws Exception + { + KeyPairGenerator keygen = KeyPairGenerator.getInstance("RSA", "BC"); + keygen.initialize(1024); + KeyPair keypair = keygen.genKeyPair(); + SecureRandom rand = new SecureRandom(); + Cipher c = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC"); + byte[] ciphertext = new byte[1024 / 8]; + HashSet exceptions = new HashSet(); + final int SAMPLES = 1000; + for (int i = 0; i < SAMPLES; i++) + { + rand.nextBytes(ciphertext); + ciphertext[0] = (byte)0; + try + { + c.init(Cipher.DECRYPT_MODE, keypair.getPrivate()); + c.doFinal(ciphertext); + } + catch (Exception ex) + { + String message = ex.toString(); + exceptions.add(message); + } + } + isTrue("exception count wrong", 1 == exceptions.size()); + } + + public void zeroMessageTest() + throws Exception + { + KeyPairGenerator kgen = KeyPairGenerator.getInstance("RSA", "BC"); + + RSAKeyGenParameterSpec rsaSpec = new RSAKeyGenParameterSpec(2048, RSAKeyGenParameterSpec.F4); + + kgen.initialize(rsaSpec); + + KeyPair kp = kgen.generateKeyPair(); + + byte[] plain = new byte[0]; + + Cipher rsaCipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC"); + rsaCipher.init(Cipher.ENCRYPT_MODE, kp.getPublic()); + byte[] encrypted = rsaCipher.doFinal(plain); + + rsaCipher = Cipher.getInstance("RSA/NONE/OAEPWithSHA1AndMGF1Padding", "BC"); + rsaCipher.init(Cipher.DECRYPT_MODE, kp.getPrivate()); + byte[] decrypted = rsaCipher.doFinal(encrypted); + + isTrue("zero mismatch", Arrays.areEqual(plain, decrypted)); + } + + private void oaepCompatibilityTest(String digest, PrivateKey privKey, PublicKey pubKey) + throws Exception + { + if (Security.getProvider("SunJCE") == null || Security.getProvider("SunRsaSign") == null) + { + return; + } + + KeyFactory fact = KeyFactory.getInstance("RSA", "SunRsaSign"); + PrivateKey priv2048Key = fact.generatePrivate(priv2048KeySpec); + PublicKey pub2048Key = fact.generatePublic(pub2048KeySpec); + + byte[] data = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; + + Cipher sCipher; + try + { + sCipher = Cipher.getInstance("RSA/ECB/OAEPWith" + digest + "AndMGF1Padding", "SunJCE"); + } + catch (NoSuchAlgorithmException e) + { + return; + } + catch (NoSuchPaddingException e) + { + return; + } + + sCipher.init(Cipher.ENCRYPT_MODE, pub2048Key); + + byte[] enctext = sCipher.doFinal(data); + + Cipher bcCipher = Cipher.getInstance("RSA/ECB/OAEPWith" + digest + "AndMGF1Padding", "BC"); + + bcCipher.init(Cipher.DECRYPT_MODE, privKey, new OAEPParameterSpec(digest, "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)); + + byte[] plaintext = bcCipher.doFinal(enctext); + + if (!Arrays.areEqual(plaintext, data)) + { + fail("data did not decrypt first time"); + } + + bcCipher.init(Cipher.ENCRYPT_MODE, pubKey, new OAEPParameterSpec(digest, "MGF1", MGF1ParameterSpec.SHA1, PSource.PSpecified.DEFAULT)); + + enctext = bcCipher.doFinal(data); + + sCipher.init(Cipher.DECRYPT_MODE, priv2048Key); + + plaintext = sCipher.doFinal(enctext); + + if (!Arrays.areEqual(plaintext, data)) + { + fail("data did not decrypt second time"); + } + } + + private void rawModeTest(String sigName, ASN1ObjectIdentifier digestOID, + PrivateKey privKey, PublicKey pubKey, SecureRandom random) throws Exception + { + byte[] sampleMessage = new byte[1000 + random.nextInt(100)]; + random.nextBytes(sampleMessage); + + Signature normalSig = Signature.getInstance(sigName, "BC"); + normalSig.initSign(privKey); + normalSig.update(sampleMessage); + byte[] normalResult = normalSig.sign(); + + MessageDigest digest = MessageDigest.getInstance(digestOID.getId(), "BC"); + byte[] hash = digest.digest(sampleMessage); + byte[] digInfo = derEncode(digestOID, hash); + + Signature rawSig = Signature.getInstance("RSA", "BC"); + rawSig.initSign(privKey); + rawSig.update(digInfo); + byte[] rawResult = rawSig.sign(); + + if (!Arrays.areEqual(normalResult, rawResult)) + { + fail("raw mode signature differs from normal one"); + } + + rawSig.initVerify(pubKey); + rawSig.update(digInfo); + + if (!rawSig.verify(rawResult)) + { + fail("raw mode signature verification failed"); + } + } + + private Object serializeDeserialize(Object o) + throws Exception + { + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + ObjectOutputStream oOut = new ObjectOutputStream(bOut); + + oOut.writeObject(o); + oOut.close(); + + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(bOut.toByteArray())); + + return oIn.readObject(); + } + + private byte[] derEncode(ASN1ObjectIdentifier oid, byte[] hash) throws IOException + { + AlgorithmIdentifier algId = new AlgorithmIdentifier(oid, DERNull.INSTANCE); + DigestInfo dInfo = new DigestInfo(algId, hash); + + return dInfo.getEncoded(ASN1Encoding.DER); + } + + public String getName() + { + return "RSATest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new RSATest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/RegressionTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/RegressionTest.java new file mode 100644 index 000000000..b8a680911 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/RegressionTest.java @@ -0,0 +1,102 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Security; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.Test; + +public class RegressionTest +{ + public static Test[] tests = { + new FIPSDESTest(), + new DESedeTest(), + new AESTest(), + new CamelliaTest(), + new SEEDTest(), + new AESSICTest(), + new GOST28147Test(), + new PBETest(), + new BlockCipherTest(), + new MacTest(), + new HMacTest(), + new SealedTest(), + new RSATest(), + new DHTest(), + new DHIESTest(), + new DSATest(), + new ImplicitlyCaTest(), + new ECNRTest(), + new ECIESTest(), + new ECIESVectorTest(), + new ECDSA5Test(), + new GOST3410Test(), + new ElGamalTest(), + new IESTest(), + new SigTest(), + new CertTest(), + new PKCS10CertRequestTest(), + new EncryptedPrivateKeyInfoTest(), + new KeyStoreTest(), + new PKCS12StoreTest(), + new DigestTest(), + new PSSTest(), + new WrapTest(), + new DoFinalTest(), + new CipherStreamTest(), + new CipherStreamTest2(), + new NamedCurveTest(), + new PKIXTest(), + new NetscapeCertRequestTest(), + new X509StreamParserTest(), + new X509CertificatePairTest(), + new CertPathTest(), + new CertStoreTest(), + new CertPathValidatorTest(), + new CertPathBuilderTest(), + new ECEncodingTest(), + new AlgorithmParametersTest(), + new NISTCertPathTest(), + new PKIXPolicyMappingTest(), + new SlotTwoTest(), + new PKIXNameConstraintsTest(), + new MultiCertStoreTest(), + new NoekeonTest(), + new SerialisationTest(), + new SigNameTest(), + new MQVTest(), + new CMacTest(), + new GMacTest(), + new OCBTest(), + new DSTU4145Test(), + new CRL5Test(), + new Poly1305Test(), + new SipHashTest(), + new KeccakTest(), + new SkeinTest(), + new Shacal2Test(), + new DetDSATest(), + new ThreefishTest(), + new SM2SignatureTest(), + new SM4Test(), + new TLSKDFTest(), + new BCFKSStoreTest(), + new DSTU7624Test(), + new GOST3412Test(), + new GOST3410KeyPairTest(), + new EdECTest(), + new OpenSSHSpecTests(), + new SM2CipherTest(), + new ZucTest(), + new ChaCha20Poly1305Test() + }; + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + System.out.println("Testing " + Security.getProvider("BC").getInfo() + " version: " + Security.getProvider("BC").getVersion()); + + SimpleTest.runTests(tests); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SEEDTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SEEDTest.java new file mode 100644 index 000000000..61c231692 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SEEDTest.java @@ -0,0 +1,175 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import com.fr.third.org.bouncycastle.asn1.kisa.KISAObjectIdentifiers; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.spec.SecretKeySpec; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.Security; + +/** + * basic test class for SEED + */ +public class SEEDTest + extends BaseBlockCipherTest +{ + static String[] cipherTests = + { + "128", + "28DBC3BC49FFD87DCFA509B11D422BE7", + "B41E6BE2EBA84A148E2EED84593C5EC7", + "9B9B7BFCD1813CB95D0B3618F40F5122" + }; + + public SEEDTest() + { + super("SEED"); + } + + public void test( + int strength, + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "SEED"); + + in = Cipher.getInstance("SEED/ECB/NoPadding", "BC"); + out = Cipher.getInstance("SEED/ECB/NoPadding", "BC"); + + try + { + out.init(Cipher.ENCRYPT_MODE, key); + } + catch (Exception e) + { + fail("SEED failed initialisation - " + e.toString(), e); + } + + try + { + in.init(Cipher.DECRYPT_MODE, key); + } + catch (Exception e) + { + fail("SEED failed initialisation - " + e.toString(), e); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail("SEED failed encryption - " + e.toString(), e); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("SEED failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + } + catch (Exception e) + { + fail("SEED failed encryption - " + e.toString(), e); + } + + if (!areEqual(bytes, input)) + { + fail("SEED failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + public void performTest() + throws Exception + { + for (int i = 0; i != cipherTests.length; i += 4) + { + test(Integer.parseInt(cipherTests[i]), + Hex.decode(cipherTests[i + 1]), + Hex.decode(cipherTests[i + 2]), + Hex.decode(cipherTests[i + 3])); + } + + byte[] kek1 = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] in1 = Hex.decode("00112233445566778899aabbccddeeff"); + byte[] out1 = Hex.decode("bf71f77138b5afea05232a8dad54024e812dc8dd7d132559"); + + wrapTest(1, "SEEDWrap", kek1, in1, out1); + + String[] oids = { + KISAObjectIdentifiers.id_seedCBC.getId() + }; + + String[] names = { + "SEED/CBC/PKCS7Padding" + }; + + oidTest(oids, names, 1); + + String[] wrapOids = { + KISAObjectIdentifiers.id_npki_app_cmsSeed_wrap.getId() + }; + + wrapOidTest(wrapOids, "SEEDWrap"); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new SEEDTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SM2CipherTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SM2CipherTest.java new file mode 100644 index 000000000..113eca024 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SM2CipherTest.java @@ -0,0 +1,118 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Security; + +import javax.crypto.Cipher; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.gm.GMObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.params.ECDomainParameters; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; + +public class SM2CipherTest + extends SimpleTest +{ + public String getName() + { + return "SM2Cipher"; + } + + public void performTest() + throws Exception + { + BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); + BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); + BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); + BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_H = ECConstants.ONE; + BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); + BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); + + ECCurve curve = new ECCurve.Fp(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); + + ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY); + ECDomainParameters domainParams = new ECDomainParameters(curve, g, SM2_ECC_N); + + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("EC", "BC"); + + ECParameterSpec aKeyGenParams = new ECParameterSpec(domainParams.getCurve(), domainParams.getG(), domainParams.getN(), domainParams.getH()); + + keyPairGenerator.initialize(aKeyGenParams, new TestRandomBigInteger("1649AB77A00637BD5E2EFE283FBF353534AA7F7CB89463F208DDBC2920BB0DA0", 16)); + + KeyPair aKp = keyPairGenerator.generateKeyPair(); + + Cipher sm2Engine = Cipher.getInstance("SM2", "BC"); + + byte[] m = Strings.toByteArray("encryption standard"); + + sm2Engine.init(Cipher.ENCRYPT_MODE, aKp.getPublic(), new TestRandomBigInteger("4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", 16)); + + byte[] enc = sm2Engine.doFinal(m); + + isTrue("enc wrong", Arrays.areEqual(Hex.decode( + "04245C26 FB68B1DD DDB12C4B 6BF9F2B6 D5FE60A3 83B0D18D 1C4144AB F17F6252" + + "E776CB92 64C2A7E8 8E52B199 03FDC473 78F605E3 6811F5C0 7423A24B 84400F01" + + "B8650053 A89B41C4 18B0C3AA D00D886C 00286467 9C3D7360 C30156FA B7C80A02" + + "76712DA9 D8094A63 4B766D3A 285E0748 0653426D"), enc)); + + sm2Engine.init(Cipher.DECRYPT_MODE, aKp.getPrivate()); + + byte[] dec = sm2Engine.doFinal(enc); + + isTrue("dec wrong", Arrays.areEqual(m, dec)); + + testAlgorithm(aKp, "SM2", GMObjectIdentifiers.sm2encrypt_with_sm3); + testAlgorithm(aKp, "SM2withSM3", GMObjectIdentifiers.sm2encrypt_with_sm3); + testAlgorithm(aKp, "SM2withBlake2b", GMObjectIdentifiers.sm2encrypt_with_blake2b512); + testAlgorithm(aKp, "SM2withBlake2s", GMObjectIdentifiers.sm2encrypt_with_blake2s256); + testAlgorithm(aKp, "SM2withMD5", GMObjectIdentifiers.sm2encrypt_with_md5); + testAlgorithm(aKp, "SM2withRIPEMD160", GMObjectIdentifiers.sm2encrypt_with_rmd160); + testAlgorithm(aKp, "SM2withWhirlpool", GMObjectIdentifiers.sm2encrypt_with_whirlpool); + testAlgorithm(aKp, "SM2withSHA1", GMObjectIdentifiers.sm2encrypt_with_sha1); + testAlgorithm(aKp, "SM2withSHA224", GMObjectIdentifiers.sm2encrypt_with_sha224); + testAlgorithm(aKp, "SM2withSHA256", GMObjectIdentifiers.sm2encrypt_with_sha256); + testAlgorithm(aKp, "SM2withSHA384", GMObjectIdentifiers.sm2encrypt_with_sha384); + testAlgorithm(aKp, "SM2withSHA512", GMObjectIdentifiers.sm2encrypt_with_sha512); + } + + private void testAlgorithm(KeyPair kp, String name, ASN1ObjectIdentifier oid) + throws Exception + { + Cipher sm2Engine1 = Cipher.getInstance(name, "BC"); + Cipher sm2Engine2 = Cipher.getInstance(oid.getId(), "BC"); + + byte[] m = Strings.toByteArray("encryption standard"); + + sm2Engine1.init(Cipher.ENCRYPT_MODE, kp.getPublic(), new TestRandomBigInteger("4C62EEFD6ECFC2B95B92FD6C3D9575148AFA17425546D49018E5388D49DD7B4F", 16)); + + byte[] enc = sm2Engine1.doFinal(m); + + isTrue(enc.length == sm2Engine1.getOutputSize(m.length)); + + sm2Engine2.init(Cipher.DECRYPT_MODE, kp.getPrivate()); + + byte[] dec = sm2Engine2.doFinal(enc); + + isTrue("dec wrong", Arrays.areEqual(m, dec)); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new SM2CipherTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SM2SignatureTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SM2SignatureTest.java new file mode 100644 index 000000000..bb0f6ed59 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SM2SignatureTest.java @@ -0,0 +1,108 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.Security; +import java.security.Signature; + +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.ASN1Sequence; +import com.fr.third.org.bouncycastle.jcajce.spec.SM2ParameterSpec; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECParameterSpec; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.TestRandomBigInteger; + +public class SM2SignatureTest + extends SimpleTest +{ + public String getName() + { + return "SM2"; + } + + private void doSignerTestFp() + throws Exception + { + BigInteger SM2_ECC_P = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DE457283915C45517D722EDB8B08F1DFC3", 16); + BigInteger SM2_ECC_A = new BigInteger("787968B4FA32C3FD2417842E73BBFEFF2F3C848B6831D7E0EC65228B3937E498", 16); + BigInteger SM2_ECC_B = new BigInteger("63E4C6D3B23B0C849CF84241484BFE48F61D59A5B16BA06E6E12D1DA27C5249A", 16); + BigInteger SM2_ECC_N = new BigInteger("8542D69E4C044F18E8B92435BF6FF7DD297720630485628D5AE74EE7C32E79B7", 16); + BigInteger SM2_ECC_H = ECConstants.ONE; + BigInteger SM2_ECC_GX = new BigInteger("421DEBD61B62EAB6746434EBC3CC315E32220B3BADD50BDC4C4E6C147FEDD43D", 16); + BigInteger SM2_ECC_GY = new BigInteger("0680512BCBB42C07D47349D2153B70C4E5D7FDFCBFA36EA1A85841B9E46E09A2", 16); + + ECCurve curve = new ECCurve.Fp(SM2_ECC_P, SM2_ECC_A, SM2_ECC_B, SM2_ECC_N, SM2_ECC_H); + + ECPoint g = curve.createPoint(SM2_ECC_GX, SM2_ECC_GY); + + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(new ECParameterSpec(curve, g, SM2_ECC_N), new TestRandomBigInteger("128B2FA8BD433C6C068C8D803DFF79792A519A55171B1B650C23661D15897263", 16)); + + KeyPair kp = kpGen.generateKeyPair(); + + Signature signer = Signature.getInstance("SM3withSM2", "BC"); + + signer.setParameter(new SM2ParameterSpec(Strings.toByteArray("ALICE123@YAHOO.COM"))); + + // repetition test + final int times = 2; + String random = ""; + for (int i = 0; i < times; i++) { + random += "6CB28D99385C175C94F94E934817663FC176D925DD72B727260DBAAE1FB2F96F"; + } + signer.initSign(kp.getPrivate(), + new TestRandomBigInteger(random, 16)); + + byte[] msg = Strings.toByteArray("message digest"); + + Signature verifier = Signature.getInstance("SM3withSM2", "BC"); + + verifier.setParameter(new SM2ParameterSpec(Strings.toByteArray("ALICE123@YAHOO.COM"))); + + verifier.initVerify(kp.getPublic()); + + for (int i = 0; i < times; i++) { + signer.update(msg, 0, msg.length); + + byte[] sig = signer.sign(); + + BigInteger[] rs = decode(sig); + + isTrue("r wrong", rs[0].equals(new BigInteger("40F1EC59F793D9F49E09DCEF49130D4194F79FB1EED2CAA55BACDB49C4E755D1", 16))); + isTrue("s wrong", rs[1].equals(new BigInteger("6FC6DAC32C5D5CF10C77DFB20F7C2EB667A457872FB09EC56327A67EC7DEEBE7", 16))); + + verifier.update(msg, 0, msg.length); + + isTrue("verification failed i=" + i, verifier.verify(sig)); + } + } + + private static BigInteger[] decode(byte[] sig) + { + ASN1Sequence s = ASN1Sequence.getInstance(sig); + + return new BigInteger[] { ASN1Integer.getInstance(s.getObjectAt(0)).getValue(), + ASN1Integer.getInstance(s.getObjectAt(1)).getValue() }; + } + + public void performTest() + throws Exception + { + doSignerTestFp(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new SM2SignatureTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SM4Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SM4Test.java new file mode 100644 index 000000000..14e1897ef --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SM4Test.java @@ -0,0 +1,153 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; + +/** + * basic test class for SM4 + */ +public class SM4Test + extends BaseBlockCipherTest +{ + static String[] cipherTests = + { + "128", + "0123456789abcdeffedcba9876543210", + "0123456789abcdeffedcba9876543210", + "681edf34d206965e86b3e94f536e4246" + }; + + public SM4Test() + { + super("SM4"); + } + + public void test( + int strength, + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "SM4"); + + in = Cipher.getInstance("SM4/ECB/NoPadding", "BC"); + out = Cipher.getInstance("SM4/ECB/NoPadding", "BC"); + + try + { + out.init(Cipher.ENCRYPT_MODE, key); + } + catch (Exception e) + { + fail("SM4 failed initialisation - " + e.toString(), e); + } + + try + { + in.init(Cipher.DECRYPT_MODE, key); + } + catch (Exception e) + { + fail("SM4 failed initialisation - " + e.toString(), e); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail("SM4 failed encryption - " + e.toString(), e); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("SM4 failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + } + catch (Exception e) + { + fail("SM4 failed encryption - " + e.toString(), e); + } + + if (!areEqual(bytes, input)) + { + fail("SM4 failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + public void performTest() + throws Exception + { + for (int i = 0; i != cipherTests.length; i += 4) + { + test(Integer.parseInt(cipherTests[i]), + Hex.decode(cipherTests[i + 1]), + Hex.decode(cipherTests[i + 2]), + Hex.decode(cipherTests[i + 3])); + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new SM4Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SealedTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SealedTest.java new file mode 100644 index 000000000..f7f50e228 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SealedTest.java @@ -0,0 +1,79 @@ + +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Key; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.SealedObject; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class SealedTest + implements Test +{ + final static String provider = "BC"; + + public String getName() + { + return "SealedObject"; + } + + public TestResult perform() + { + try + { + KeyGenerator keyGen = KeyGenerator.getInstance("DES", provider); + Key key = keyGen.generateKey(); + Cipher c = Cipher.getInstance("DES/ECB/PKCS5Padding", provider); + + c.init(Cipher.ENCRYPT_MODE, key); + String object = "Hello world"; + SealedObject so = new SealedObject(object, c); + c.init(Cipher.DECRYPT_MODE, key); + + Object o = so.getObject(c); + if (!o.equals(object)) + { + return new SimpleTestResult(false, "Result object 1 not equal" + + "orig: " + object + " res: " + o); + } + + o = so.getObject(key); + if (!o.equals(object)) + { + return new SimpleTestResult(false, "Result object 2 not equal" + + "orig: " + object + " res: " + o); + } + + o = so.getObject(key, provider); + if (!o.equals(object)) + { + return new SimpleTestResult(false, "Result object 3 not equal" + + "orig: " + object + " res: " + o); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + + ": failed excpetion - " + e.toString(), e); + } + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + Test test = new SealedTest(); + TestResult result = test.perform(); + + System.out.println(result.toString()); + } +} + diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SerialisationTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SerialisationTest.java new file mode 100644 index 000000000..1b78020b0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SerialisationTest.java @@ -0,0 +1,342 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.math.BigInteger; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPublicKey; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; + +import com.fr.third.org.bouncycastle.jce.interfaces.ElGamalPrivateKey; +import com.fr.third.org.bouncycastle.jce.interfaces.ElGamalPublicKey; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SerialisationTest + extends SimpleTest +{ + private static BigInteger mod = new BigInteger("69919157209851583596607278525201743749468350078269839551939850344506918649679"); + private static BigInteger pubExp = new BigInteger("65537"); + private static BigInteger privExp = new BigInteger("6387323103214694462561419908301918608189256611651974386490887304224030221257"); + private static BigInteger crtExp = new BigInteger("49050879172577973803420172068797326635"); + private static BigInteger p = new BigInteger("272712035519670228866910009292918035133"); + private static BigInteger q = new BigInteger("256384567247338962716621434774670631163"); + private static BigInteger expP = new BigInteger("121540093892892992427860713054115232161"); + private static BigInteger expQ = new BigInteger("169333445127196347119779037859859594883"); + + private static byte[] rsaPub = Base64.decode( + "rO0ABXNyAC1vcmcuYm91bmN5Y2FzdGxlLmpjZS5wcm92aWRlci5KQ0VSU0FQdWJsaWNLZXklImoOW/pshAIAAkwAB21vZHV" + + "sdXN0ABZMamF2YS9tYXRoL0JpZ0ludGVnZXI7TAAOcHVibGljRXhwb25lbnRxAH4AAXhwc3IAFGphdmEubWF0aC5CaWdJbn" + + "RlZ2VyjPyfH6k7+x0DAAZJAAhiaXRDb3VudEkACWJpdExlbmd0aEkAE2ZpcnN0Tm9uemVyb0J5dGVOdW1JAAxsb3dlc3RTZ" + + "XRCaXRJAAZzaWdudW1bAAltYWduaXR1ZGV0AAJbQnhyABBqYXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cP//////////" + + "/////v////4AAAABdXIAAltCrPMX+AYIVOACAAB4cAAAACCalNcvvJNMM944KWzzuH2MXkKbiW10OEzGQb9B9MM/T3hzcQB" + + "+AAP///////////////7////+AAAAAXVxAH4ABwAAAAMBAAF4"); + + private static byte[] rsaPriv = Base64.decode( + "rO0ABXNyADFvcmcuYm91bmN5Y2FzdGxlLmpjZS5wcm92aWRlci5KQ0VSU0FQcml2YXRlQ3J0S2V5bLqHzgJzVS4CAAZMAA5" + + "jcnRDb2VmZmljaWVudHQAFkxqYXZhL21hdGgvQmlnSW50ZWdlcjtMAA5wcmltZUV4cG9uZW50UHEAfgABTAAOcHJpbWVFeH" + + "BvbmVudFFxAH4AAUwABnByaW1lUHEAfgABTAAGcHJpbWVRcQB+AAFMAA5wdWJsaWNFeHBvbmVudHEAfgABeHIALm9yZy5ib" + + "3VuY3ljYXN0bGUuamNlLnByb3ZpZGVyLkpDRVJTQVByaXZhdGVLZXlG6wnAB89BHAMABEwAB21vZHVsdXNxAH4AAUwAEHBr" + + "Y3MxMkF0dHJpYnV0ZXN0ABVMamF2YS91dGlsL0hhc2h0YWJsZTtMAA5wa2NzMTJPcmRlcmluZ3QAEkxqYXZhL3V0aWwvVmV" + + "jdG9yO0wAD3ByaXZhdGVFeHBvbmVudHEAfgABeHBzcgAUamF2YS5tYXRoLkJpZ0ludGVnZXKM/J8fqTv7HQMABkkACGJpdE" + + "NvdW50SQAJYml0TGVuZ3RoSQATZmlyc3ROb256ZXJvQnl0ZU51bUkADGxvd2VzdFNldEJpdEkABnNpZ251bVsACW1hZ25pd" + + "HVkZXQAAltCeHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhw///////////////+/////gAAAAF1cgACW0Ks8xf4" + + "BghU4AIAAHhwAAAAIJqU1y+8k0wz3jgpbPO4fYxeQpuJbXQ4TMZBv0H0wz9PeHNyABNqYXZhLnV0aWwuSGFzaHRhYmxlE7s" + + "PJSFK5LgDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAACHcIAAAACwAAAAB4c3IAEGphdmEudXRpbC5WZW" + + "N0b3LZl31bgDuvAQMAA0kAEWNhcGFjaXR5SW5jcmVtZW50SQAMZWxlbWVudENvdW50WwALZWxlbWVudERhdGF0ABNbTGphd" + + "mEvbGFuZy9PYmplY3Q7eHAAAAAAAAAAAHVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB4cAAAAApwcHBwcHBw" + + "cHBweHNxAH4ABv///////////////v////4AAAABdXEAfgAKAAAAIA4fGMVoocAtYNiamDRvnzBmMv/l8FibkQsOUJjxrmP" + + "JeHhzcQB+AAb///////////////7////+AAAAAXVxAH4ACgAAABAk5tsPIq2YfF0nfLPvAKUreHNxAH4ABv////////////" + + "///v////4AAAABdXEAfgAKAAAAEFtvxUfS67k0bWmAU9/geaF4c3EAfgAG///////////////+/////gAAAAF1cQB+AAoAA" + + "AAQf2RvbOpsxhCjGK1vhd7+g3hzcQB+AAb///////////////7////+AAAAAXVxAH4ACgAAABDNKm1zRn/cYal03dRjdxK9" + + "eHNxAH4ABv///////////////v////4AAAABdXEAfgAKAAAAEMDh3xza3MJ4XNak/35BYPt4c3EAfgAG///////////////" + + "+/////gAAAAF1cQB+AAoAAAADAQABeA=="); + + private static byte[] rsaPub2 = Base64.decode( + "rO0ABXNyAD5vcmcuYm91bmN5Y2FzdGxlLmpjYWpjZS5wcm92aWRlci5hc3ltbWV0cmljLnJzYS5CQ1JTQVB1YmxpY0tleS" + + "Uiag5b+myEAgACTAAHbW9kdWx1c3QAFkxqYXZhL21hdGgvQmlnSW50ZWdlcjtMAA5wdWJsaWNFeHBvbmVudHEAfgABeHBz" + + "cgAUamF2YS5tYXRoLkJpZ0ludGVnZXKM/J8fqTv7HQMABkkACGJpdENvdW50SQAJYml0TGVuZ3RoSQATZmlyc3ROb256ZXJvQnl0ZU51bUkADGxvd2VzdFNldEJpdEkABnNpZ251bVsACW1hZ25pdHVkZXQAAltCeHIAEGphdmEubGFuZy5OdW1iZXKGrJUdC5TgiwIAAHhw///////////////+/////gAAAAF1cgACW0Ks8xf4BghU4AIAAHhwAAAAIJqU1y+8k0wz3jgpbPO4fYxeQpuJbXQ4TMZBv0H0wz9PeHNxAH4AA////////////////v////4AAAABdXEAfgAHAAAAAwEAAXg="); + + private static BigInteger elGamalY = new BigInteger("89822212135401014750127909969755994242838935150891306006689219384134393835581"); + private static BigInteger elGamalX = new BigInteger("23522982289275336984843296896007818700866293719703239515258104457243931686357"); + private static BigInteger elGamalG = new BigInteger("29672625807664138507782226105202719390719480236799714903174779490259822385963"); + private static BigInteger elGamalP = new BigInteger("98263422916834911205348180460395783697757584103849580149025105739079617780363"); + + private static byte[] elGamalPub = Base64.decode( + "rO0ABXNyADFvcmcuYm91bmN5Y2FzdGxlLmpjZS5wcm92aWRlci5KQ0VFbEdhbWFsUHVibGljS2V5eOnUVVUsZjQDAAJMAAZ" + + "lbFNwZWN0ADBMb3JnL2JvdW5jeWNhc3RsZS9qY2Uvc3BlYy9FbEdhbWFsUGFyYW1ldGVyU3BlYztMAAF5dAAWTGphdmEvbW" + + "F0aC9CaWdJbnRlZ2VyO3hwc3IAFGphdmEubWF0aC5CaWdJbnRlZ2VyjPyfH6k7+x0DAAZJAAhiaXRDb3VudEkACWJpdExlb" + + "md0aEkAE2ZpcnN0Tm9uemVyb0J5dGVOdW1JAAxsb3dlc3RTZXRCaXRJAAZzaWdudW1bAAltYWduaXR1ZGV0AAJbQnhyABBq" + + "YXZhLmxhbmcuTnVtYmVyhqyVHQuU4IsCAAB4cP///////////////v////4AAAABdXIAAltCrPMX+AYIVOACAAB4cAAAACD" + + "GlZIJNbVQCnj4wiR0o8gGbKtJEWJBllz8NAELXcqwPXhzcQB+AAT///////////////7////+AAAAAXVxAH4ACAAAACDZPy" + + "BetQ1Ed8NUnTfXb+MBhFVK1KRe2LzQP7oVz2Kai3hzcQB+AAT///////////////7////+AAAAAXVxAH4ACAAAACBBmhxth" + + "0FhU4SsG01Wjyi1dlZFZvOy1zFC12XRGO8bK3h4"); + + private static byte[] elGamalPriv = Base64.decode( + "rO0ABXNyADJvcmcuYm91bmN5Y2FzdGxlLmpjZS5wcm92aWRlci5KQ0VFbEdhbWFsUHJpdmF0ZUtleULhxV+2vMBOAwAETAA" + + "GZWxTcGVjdAAwTG9yZy9ib3VuY3ljYXN0bGUvamNlL3NwZWMvRWxHYW1hbFBhcmFtZXRlclNwZWM7TAAQcGtjczEyQXR0cm" + + "lidXRlc3QAFUxqYXZhL3V0aWwvSGFzaHRhYmxlO0wADnBrY3MxMk9yZGVyaW5ndAASTGphdmEvdXRpbC9WZWN0b3I7TAABe" + + "HQAFkxqYXZhL21hdGgvQmlnSW50ZWdlcjt4cHNyABRqYXZhLm1hdGguQmlnSW50ZWdlcoz8nx+pO/sdAwAGSQAIYml0Q291" + + "bnRJAAliaXRMZW5ndGhJABNmaXJzdE5vbnplcm9CeXRlTnVtSQAMbG93ZXN0U2V0Qml0SQAGc2lnbnVtWwAJbWFnbml0dWR" + + "ldAACW0J4cgAQamF2YS5sYW5nLk51bWJlcoaslR0LlOCLAgAAeHD///////////////7////+AAAAAXVyAAJbQqzzF/gGCF" + + "TgAgAAeHAAAAAgNAGJQeYfM6ToYoA3ePFdEe7yh8hKecr+WZA0AwxrtdV4c3EAfgAG///////////////+/////gAAAAF1c" + + "QB+AAoAAAAg2T8gXrUNRHfDVJ0312/jAYRVStSkXti80D+6Fc9imot4c3EAfgAG///////////////+/////gAAAAF1cQB+" + + "AAoAAAAgQZocbYdBYVOErBtNVo8otXZWRWbzstcxQtdl0RjvGyt4eA=="); + + private static BigInteger dhY = new BigInteger("1925747248304483170395506065378568192931506039297732684689153183373019672434"); + private static BigInteger dhX = new BigInteger("3"); + private static BigInteger dhG = new BigInteger("3493483775405590747011712302510626058005717040655777294576367636428413099058"); + private static BigInteger dhP = new BigInteger("106557663805518855012633095511067237673895862256610675920943888960856082029127"); + + private static byte[] dhPub = Base64.decode( + "rO0ABXNyACxvcmcuYm91bmN5Y2FzdGxlLmpjZS5wcm92aWRlci5KQ0VESFB1YmxpY0tlefz+KCkPI+T8AwACTAAGZGhTcGV" + + "jdAAjTGphdmF4L2NyeXB0by9zcGVjL0RIUGFyYW1ldGVyU3BlYztMAAF5dAAWTGphdmEvbWF0aC9CaWdJbnRlZ2VyO3hwc3" + + "IAFGphdmEubWF0aC5CaWdJbnRlZ2VyjPyfH6k7+x0DAAZJAAhiaXRDb3VudEkACWJpdExlbmd0aEkAE2ZpcnN0Tm9uemVyb" + + "0J5dGVOdW1JAAxsb3dlc3RTZXRCaXRJAAZzaWdudW1bAAltYWduaXR1ZGV0AAJbQnhyABBqYXZhLmxhbmcuTnVtYmVyhqyV" + + "HQuU4IsCAAB4cP///////////////v////4AAAABdXIAAltCrPMX+AYIVOACAAB4cAAAACAEQe8vYXxZPS5oAUy0e0yRYxK" + + "EAO3GjhMWZKNw8flvcnhzcQB+AAT///////////////7////+AAAAAXVxAH4ACAAAACDrlYAb5zOABHPgsK6oIKtMFgPD3v" + + "nbTosOnokaSVsaR3hzcQB+AAT///////////////7////+AAAAAXVxAH4ACAAAACAHuT3jEhOVRGfaKdFOX6J2vDYxiMPQW" + + "ljjL/3Xz85cMnh3BAAAAAB4"); + + private static byte[] dhPriv = Base64.decode( + "rO0ABXNyAC1vcmcuYm91bmN5Y2FzdGxlLmpjZS5wcm92aWRlci5KQ0VESFByaXZhdGVLZXkEURpYQRlitAMABEwABmRoU3B" + + "lY3QAI0xqYXZheC9jcnlwdG8vc3BlYy9ESFBhcmFtZXRlclNwZWM7TAAQcGtjczEyQXR0cmlidXRlc3QAFUxqYXZhL3V0aW" + + "wvSGFzaHRhYmxlO0wADnBrY3MxMk9yZGVyaW5ndAASTGphdmEvdXRpbC9WZWN0b3I7TAABeHQAFkxqYXZhL21hdGgvQmlnS" + + "W50ZWdlcjt4cHNyABRqYXZhLm1hdGguQmlnSW50ZWdlcoz8nx+pO/sdAwAGSQAIYml0Q291bnRJAAliaXRMZW5ndGhJABNm" + + "aXJzdE5vbnplcm9CeXRlTnVtSQAMbG93ZXN0U2V0Qml0SQAGc2lnbnVtWwAJbWFnbml0dWRldAACW0J4cgAQamF2YS5sYW5" + + "nLk51bWJlcoaslR0LlOCLAgAAeHD///////////////7////+AAAAAXVyAAJbQqzzF/gGCFTgAgAAeHAAAAABA3hzcQB+AA" + + "b///////////////7////+AAAAAXVxAH4ACgAAACDrlYAb5zOABHPgsK6oIKtMFgPD3vnbTosOnokaSVsaR3hzcQB+AAb//" + + "/////////////7////+AAAAAXVxAH4ACgAAACAHuT3jEhOVRGfaKdFOX6J2vDYxiMPQWljjL/3Xz85cMnh3BAAAAAB4"); + + private static BigInteger dsaY = new BigInteger("6189794363048388077684611193598066807847399153242870209962581468350882042922904596556915269714052441467859854436813271130403014368908908961326314287317209"); + private static BigInteger dsaX = new BigInteger("45673695048287886591258561084679393738177012644"); + private static BigInteger dsaG = new BigInteger("3245524385217980657302535456606469153364622623109429686740209357408427939040123729832874550911504858612362156241316117434271994372338032643547044203024422"); + private static BigInteger dsaP = new BigInteger("8836853285188714261909188099204635517862922237850722644742752953058083563923137941667883080809922365262319540202714582925718707421743492259382127680083261"); + + private static byte[] dsaPub = Base64.decode( + "rO0ABXNyAC1vcmcuYm91bmN5Y2FzdGxlLmpjZS5wcm92aWRlci5KREtEU0FQdWJsaWNLZXkYUfY34kLIBwMAAkwAB2RzYVN" + + "wZWN0ACRMamF2YS9zZWN1cml0eS9pbnRlcmZhY2VzL0RTQVBhcmFtcztMAAF5dAAWTGphdmEvbWF0aC9CaWdJbnRlZ2VyO3" + + "hwc3IAFGphdmEubWF0aC5CaWdJbnRlZ2VyjPyfH6k7+x0DAAZJAAhiaXRDb3VudEkACWJpdExlbmd0aEkAE2ZpcnN0Tm9ue" + + "mVyb0J5dGVOdW1JAAxsb3dlc3RTZXRCaXRJAAZzaWdudW1bAAltYWduaXR1ZGV0AAJbQnhyABBqYXZhLmxhbmcuTnVtYmVy" + + "hqyVHQuU4IsCAAB4cP///////////////v////4AAAABdXIAAltCrPMX+AYIVOACAAB4cAAAAEB2LxWpG2UqKz0HcWZwDii" + + "fO0+3sXqWwmnAnHw8HbPRbtJUozr0As4FX7loWxvWyV+CJDse2KwdxISyMmq6hMDZeHNxAH4ABP///////////////v////" + + "4AAAABdXEAfgAIAAAAQKi5o5xNZaCAFFAV6dWnHHjG0TVoA7d34RUNF0GhquH6BH/W3BvW4fy428+NPnCgUvJM9iLBTpuBn" + + "oepupEE1T14c3EAfgAE///////////////+/////gAAAAF1cQB+AAgAAAAU/tVyr5rbnY4WkK7C6NK21c9jn8V4c3EAfgAE" + + "///////////////+/////gAAAAF1cQB+AAgAAABAPffK8RBcfUspb5PsGDyjZf4Tqcmo5UhuaABmUnq8Vqb3P7jc1+LNaTh" + + "mUJSnjWQ4+kyCeeJgPH9d3iBd5blQJnh4"); + + private static byte[] dsaPriv = Base64.decode( + "rO0ABXNyAC5vcmcuYm91bmN5Y2FzdGxlLmpjZS5wcm92aWRlci5KREtEU0FQcml2YXRlS2V5vxcJOSU9rboDAANMAAthdHR" + + "yQ2FycmllcnQAPUxvcmcvYm91bmN5Y2FzdGxlL2pjZS9wcm92aWRlci9QS0NTMTJCYWdBdHRyaWJ1dGVDYXJyaWVySW1wbD" + + "tMAAdkc2FTcGVjdAAkTGphdmEvc2VjdXJpdHkvaW50ZXJmYWNlcy9EU0FQYXJhbXM7TAABeHQAFkxqYXZhL21hdGgvQmlnS" + + "W50ZWdlcjt4cHNyABRqYXZhLm1hdGguQmlnSW50ZWdlcoz8nx+pO/sdAwAGSQAIYml0Q291bnRJAAliaXRMZW5ndGhJABNm" + + "aXJzdE5vbnplcm9CeXRlTnVtSQAMbG93ZXN0U2V0Qml0SQAGc2lnbnVtWwAJbWFnbml0dWRldAACW0J4cgAQamF2YS5sYW5" + + "nLk51bWJlcoaslR0LlOCLAgAAeHD///////////////7////+AAAAAXVyAAJbQqzzF/gGCFTgAgAAeHAAAAAUCAAUTkau3a" + + "uChEXbN4isGH4aY6R4c3EAfgAF///////////////+/////gAAAAF1cQB+AAkAAABAqLmjnE1loIAUUBXp1acceMbRNWgDt" + + "3fhFQ0XQaGq4foEf9bcG9bh/Ljbz40+cKBS8kz2IsFOm4Geh6m6kQTVPXhzcQB+AAX///////////////7////+AAAAAXVx" + + "AH4ACQAAABT+1XKvmtudjhaQrsLo0rbVz2OfxXhzcQB+AAX///////////////7////+AAAAAXVxAH4ACQAAAEA998rxEFx" + + "9Sylvk+wYPKNl/hOpyajlSG5oAGZSerxWpvc/uNzX4s1pOGZQlKeNZDj6TIJ54mA8f13eIF3luVAmeHNyABNqYXZhLnV0aW" + + "wuSGFzaHRhYmxlE7sPJSFK5LgDAAJGAApsb2FkRmFjdG9ySQAJdGhyZXNob2xkeHA/QAAAAAAACHcIAAAACwAAAAB4c3IAE" + + "GphdmEudXRpbC5WZWN0b3LZl31bgDuvAQMAA0kAEWNhcGFjaXR5SW5jcmVtZW50SQAMZWxlbWVudENvdW50WwALZWxlbWVu" + + "dERhdGF0ABNbTGphdmEvbGFuZy9PYmplY3Q7eHAAAAAAAAAAAHVyABNbTGphdmEubGFuZy5PYmplY3Q7kM5YnxBzKWwCAAB" + + "4cAAAAApwcHBwcHBwcHBweHg="); + + public String getName() + { + return "Serialisation"; + } + + public void performTest() throws Exception + { + rsaTest(); + elGamalTest(); + dhTest(); + dsaTest(); + } + + private void rsaTest() + throws IOException, ClassNotFoundException + { + RSAPublicKey pub = (RSAPublicKey)readObject(rsaPub); + + if (!mod.equals(pub.getModulus())) + { + fail("public key modulus mismatch"); + } + if (!pubExp.equals(pub.getPublicExponent())) + { + fail("public key exponent mismatch"); + } + + RSAPublicKey pub2 = (RSAPublicKey)readObject(rsaPub2); + + if (!mod.equals(pub2.getModulus())) + { + fail("public key 2 modulus mismatch"); + } + if (!pubExp.equals(pub2.getPublicExponent())) + { + fail("public key 2 exponent mismatch"); + } + + RSAPrivateCrtKey priv = (RSAPrivateCrtKey)readObject(rsaPriv); + + if (!mod.equals(priv.getModulus())) + { + fail("private key modulus mismatch"); + } + if (!privExp.equals(priv.getPrivateExponent())) + { + fail("private key exponent mismatch"); + } + if (!p.equals(priv.getPrimeP())) + { + fail("private key p mismatch"); + } + if (!q.equals(priv.getPrimeQ())) + { + fail("private key q mismatch"); + } + if (!expP.equals(priv.getPrimeExponentP())) + { + fail("private key p exponent mismatch"); + } + if (!expQ.equals(priv.getPrimeExponentQ())) + { + fail("private key q exponent mismatch"); + } + if (!crtExp.equals(priv.getCrtCoefficient())) + { + fail("private key crt exponent mismatch"); + } + } + + private void elGamalTest() + throws IOException, ClassNotFoundException + { + ElGamalPublicKey pub = (ElGamalPublicKey)readObject(elGamalPub); + + if (!elGamalY.equals(pub.getY())) + { + fail("public key y mismatch"); + } + if (!elGamalG.equals(pub.getParameters().getG())) + { + fail("public key g mismatch"); + } + if (!elGamalP.equals(pub.getParameters().getP())) + { + fail("public key p mismatch"); + } + + ElGamalPrivateKey priv = (ElGamalPrivateKey)readObject(elGamalPriv); + + if (!elGamalX.equals(priv.getX())) + { + fail("private key x mismatch"); + } + if (!elGamalG.equals(priv.getParameters().getG())) + { + fail("private key g mismatch"); + } + if (!elGamalP.equals(priv.getParameters().getP())) + { + fail("private key p mismatch"); + } + } + + private void dhTest() + throws IOException, ClassNotFoundException + { + DHPublicKey pub = (DHPublicKey)readObject(dhPub); + + if (!dhY.equals(pub.getY())) + { + fail("dh public key y mismatch"); + } + if (!dhG.equals(pub.getParams().getG())) + { + fail("dh public key g mismatch"); + } + if (!dhP.equals(pub.getParams().getP())) + { + fail("dh public key p mismatch"); + } + if (0 != pub.getParams().getL()) + { + fail("dh public key l mismatch"); + } + + DHPrivateKey priv = (DHPrivateKey)readObject(dhPriv); + + if (!dhX.equals(priv.getX())) + { + fail("dh private key x mismatch"); + } + if (!dhG.equals(priv.getParams().getG())) + { + fail("dh private key g mismatch"); + } + if (!dhP.equals(priv.getParams().getP())) + { + fail("dh private key p mismatch"); + } + if (0 != priv.getParams().getL()) + { + fail("dh private key l mismatch"); + } + } + + private void dsaTest() + throws IOException, ClassNotFoundException + { + DSAPublicKey pub = (DSAPublicKey)readObject(dsaPub); + + if (!dsaY.equals(pub.getY())) + { + fail("dsa public key y mismatch"); + } + if (!dsaG.equals(pub.getParams().getG())) + { + fail("dsa public key g mismatch"); + } + if (!dsaP.equals(pub.getParams().getP())) + { + fail("dsa public key p mismatch"); + } + + DSAPrivateKey priv = (DSAPrivateKey)readObject(dsaPriv); + + if (!dsaX.equals(priv.getX())) + { + fail("dsa private key x mismatch"); + } + if (!dsaG.equals(priv.getParams().getG())) + { + fail("dsa private key g mismatch"); + } + if (!dsaP.equals(priv.getParams().getP())) + { + fail("dsa private key p mismatch"); + } + } + + private Object readObject(byte[] key) + throws IOException, ClassNotFoundException + { + ObjectInputStream oIn = new ObjectInputStream(new ByteArrayInputStream(key)); + + return oIn.readObject(); + } + + public static void main( + String[] args) + { + runTest(new SerialisationTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/Shacal2Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/Shacal2Test.java new file mode 100644 index 000000000..0f15c371f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/Shacal2Test.java @@ -0,0 +1,205 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.IOException; +import java.security.Key; +import java.security.SecureRandom; +import java.security.Security; +import java.security.spec.KeySpec; + +import javax.crypto.Cipher; +import javax.crypto.CipherInputStream; +import javax.crypto.CipherOutputStream; +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.PBEKeySpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +/** + * basic test class for the Shacal2 cipher, vector from NESSIE (Test vectors set 8, vector# 0) + */ +public class Shacal2Test + extends SimpleTest +{ + static String[] cipherTests = + { + "512", + "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F", + "98BCC10405AB0BFC686BECECAAD01AC19B452511BCEB9CB094F905C51CA45430", + "00112233445566778899AABBCCDDEEFF102132435465768798A9BACBDCEDFE0F", + + }; + + public String getName() + { + return "Shacal2"; + } + + private static final int KEY_SIZE_BITS = 512; + + private static final byte[] TEST_BYTES = new byte[1536]; + + private static final char[] TEST_PASSWORD = new char[1536]; + + static + { + new SecureRandom().nextBytes(TEST_BYTES); + int total = TEST_PASSWORD.length; + for (char c = 'A'; c <= 'Z' && total > 0; TEST_PASSWORD[TEST_PASSWORD.length - total] = c, c++, total--) + { + ; + } + } + + private void blockTest() + throws Exception + { + final byte[] salt = new byte[KEY_SIZE_BITS / 8]; + new SecureRandom().nextBytes(salt); + + final KeySpec keySpec = new PBEKeySpec(TEST_PASSWORD, salt, 262144, KEY_SIZE_BITS); + final SecretKey secretKey = new SecretKeySpec(SecretKeyFactory.getInstance("PBKDF2", "BC"). + generateSecret(keySpec).getEncoded(), "Shacal2"); + + final Cipher cipher = Cipher.getInstance("Shacal2/CBC/ISO10126Padding", "BC"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + + final byte[] iv = cipher.getIV(); + final byte[] ciphertext = cipher.doFinal(TEST_BYTES); + + cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); + + final byte[] cleartext = cipher.doFinal(ciphertext); + + if (!Arrays.areEqual(TEST_BYTES, cleartext)) + { + fail("Invalid cleartext."); + } + } + + public void testECB( + int strength, + byte[] keyBytes, + byte[] input, + byte[] output) + throws Exception + { + Key key; + Cipher in, out; + CipherInputStream cIn; + CipherOutputStream cOut; + ByteArrayInputStream bIn; + ByteArrayOutputStream bOut; + + key = new SecretKeySpec(keyBytes, "Shacal2"); + + in = Cipher.getInstance("Shacal2/ECB/NoPadding", "BC"); + out = Cipher.getInstance("Shacal2/ECB/NoPadding", "BC"); + try + { + out.init(Cipher.ENCRYPT_MODE, key); + } + catch (Exception e) + { + fail("Shacal2 failed initialisation - " + e.toString(), e); + } + + try + { + in.init(Cipher.DECRYPT_MODE, key); + } + catch (Exception e) + { + fail("Shacal2 failed initialisation - " + e.toString(), e); + } + + // + // encryption pass + // + bOut = new ByteArrayOutputStream(); + + cOut = new CipherOutputStream(bOut, out); + + try + { + for (int i = 0; i != input.length / 2; i++) + { + cOut.write(input[i]); + } + cOut.write(input, input.length / 2, input.length - input.length / 2); + cOut.close(); + } + catch (IOException e) + { + fail("Shacal2 failed encryption - " + e.toString(), e); + } + + byte[] bytes; + + bytes = bOut.toByteArray(); + + if (!areEqual(bytes, output)) + { + fail("Shacal2 failed encryption - expected " + new String(Hex.encode(output)) + " got " + new String(Hex.encode(bytes))); + } + + // + // decryption pass + // + bIn = new ByteArrayInputStream(bytes); + + cIn = new CipherInputStream(bIn, in); + + try + { + DataInputStream dIn = new DataInputStream(cIn); + + bytes = new byte[input.length]; + + for (int i = 0; i != input.length / 2; i++) + { + bytes[i] = (byte)dIn.read(); + } + dIn.readFully(bytes, input.length / 2, bytes.length - input.length / 2); + } + catch (Exception e) + { + fail("Shacal2 failed encryption - " + e.toString(), e); + } + + if (!areEqual(bytes, input)) + { + fail("Shacal2 failed decryption - expected " + new String(Hex.encode(input)) + " got " + new String(Hex.encode(bytes))); + } + } + + public void performTest() + throws Exception + { + for (int i = 0; i != cipherTests.length; i += 4) + { + testECB(Integer.parseInt(cipherTests[i]), + Hex.decode(cipherTests[i + 1]), + Hex.decode(cipherTests[i + 2]), + Hex.decode(cipherTests[i + 3])); + } + + blockTest(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new Shacal2Test()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SigNameTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SigNameTest.java new file mode 100644 index 000000000..88d281333 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SigNameTest.java @@ -0,0 +1,98 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; +import java.security.Signature; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SigNameTest + extends SimpleTest +{ + private void checkName(String name) + throws NoSuchProviderException, NoSuchAlgorithmException + { + if (!name.equals(Signature.getInstance(name, "BC").getAlgorithm())) + { + fail("name misatch on " + name); + } + } + + public void performTest() + throws Exception + { + checkName("SHA1withRSA"); + checkName("SHA224withRSA"); + checkName("SHA256withRSA"); + checkName("SHA384withRSA"); + checkName("SHA512withRSA"); + + checkName("SHA3-224withRSA"); + checkName("SHA3-256withRSA"); + checkName("SHA3-384withRSA"); + checkName("SHA3-512withRSA"); + + checkName("MD2withRSA"); + checkName("MD4withRSA"); + checkName("MD5withRSA"); + checkName("RIPEMD160withRSA"); + checkName("RIPEMD128withRSA"); + checkName("RIPEMD256withRSA"); + + checkName("SHA1withDSA"); + checkName("SHA224withDSA"); + checkName("SHA256withDSA"); + checkName("SHA384withDSA"); + checkName("SHA512withDSA"); + checkName("NONEwithDSA"); + checkName("SHA1withECDSA"); + checkName("SHA224withECDSA"); + checkName("SHA256withECDSA"); + checkName("SHA384withECDSA"); + checkName("SHA512withECDSA"); + checkName("RIPEMD160withECDSA"); + checkName("SHA1withECNR"); + checkName("SHA224withECNR"); + checkName("SHA256withECNR"); + checkName("SHA384withECNR"); + checkName("SHA512withECNR"); + + checkName("SHA1withRSAandMGF1"); + checkName("SHA1withRSAandMGF1"); + checkName("SHA224withRSAandMGF1"); + checkName("SHA256withRSAandMGF1"); + checkName("SHA384withRSAandMGF1"); + checkName("SHA512withRSAandMGF1"); + + checkName("GOST3411withGOST3410"); + checkName("GOST3411withECGOST3410"); + + checkName("SHA1withRSA/ISO9796-2"); + checkName("MD5withRSA/ISO9796-2"); + checkName("RIPEMD160withRSA/ISO9796-2"); + + checkName("RIPEMD128withRSA/X9.31"); + checkName("RIPEMD160withRSA/X9.31"); + checkName("SHA1withRSA/X9.31"); + checkName("SHA224withRSA/X9.31"); + checkName("SHA256withRSA/X9.31"); + checkName("SHA384withRSA/X9.31"); + checkName("SHA512withRSA/X9.31"); + checkName("WhirlpoolwithRSA/X9.31"); + } + + public String getName() + { + return "SigNameTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new SigNameTest()); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SigTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SigTest.java new file mode 100644 index 000000000..6c78c0fcf --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SigTest.java @@ -0,0 +1,534 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; +import java.security.SignatureException; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.RSAPrivateKeySpec; +import java.security.spec.RSAPublicKeySpec; + +import javax.crypto.Cipher; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x509.DigestInfo; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SigTest + extends SimpleTest +{ + /** + * signature with a "forged signature" (sig block not at end of plain text) + */ + private void testBadSig(PrivateKey priv, PublicKey pub) throws Exception + { + MessageDigest sha1 = MessageDigest.getInstance("SHA1", "BC"); + Cipher signer = Cipher.getInstance("RSA/ECB/PKCS1Padding", "BC"); + + signer.init(Cipher.ENCRYPT_MODE, priv); + + byte[] block = new byte[signer.getBlockSize()]; + + sha1.update((byte)0); + + byte[] sigHeader = Hex.decode("3021300906052b0e03021a05000414"); + System.arraycopy(sigHeader, 0, block, 0, sigHeader.length); + + byte[] dig = sha1.digest(); + + System.arraycopy(dig, 0, block, sigHeader.length, dig.length); + + System.arraycopy(sigHeader, 0, block, + sigHeader.length + dig.length, sigHeader.length); + + byte[] sig = signer.doFinal(block); + + Signature verifier = Signature.getInstance("SHA1WithRSA", "BC"); + + verifier.initVerify(pub); + + verifier.update((byte)0); + + if (verifier.verify(sig)) + { + fail("bad signature passed"); + } + } + + public void performTest() + throws Exception + { + Signature sig = Signature.getInstance("SHA1WithRSAEncryption", "BC"); + KeyPairGenerator fact; + KeyPair keyPair; + byte[] data = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 }; + + fact = KeyPairGenerator.getInstance("RSA", "BC"); + + fact.initialize(768, new SecureRandom()); + + keyPair = fact.generateKeyPair(); + + PrivateKey signingKey = keyPair.getPrivate(); + PublicKey verifyKey = keyPair.getPublic(); + + testBadSig(signingKey, verifyKey); + + sig.initSign(signingKey); + + sig.update(data); + + byte[] sigBytes = sig.sign(); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail("SHA1 verification failed"); + } + + sig = Signature.getInstance("MD2WithRSAEncryption", "BC"); + + sig.initSign(signingKey); + + sig.update(data); + + sigBytes = sig.sign(); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail("MD2 verification failed"); + } + + sig = Signature.getInstance("MD5WithRSAEncryption", "BC"); + + sig.initSign(signingKey); + + sig.update(data); + + sigBytes = sig.sign(); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail("MD5 verification failed"); + } + + sig = Signature.getInstance("RIPEMD160WithRSAEncryption", "BC"); + + sig.initSign(signingKey); + + sig.update(data); + + sigBytes = sig.sign(); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail("RIPEMD160 verification failed"); + } + + // + // RIPEMD-128 + // + sig = Signature.getInstance("RIPEMD128WithRSAEncryption", "BC"); + + sig.initSign(signingKey); + + sig.update(data); + + sigBytes = sig.sign(); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail("RIPEMD128 verification failed"); + } + + // + // RIPEMD256 + // + sig = Signature.getInstance("RIPEMD256WithRSAEncryption", "BC"); + + sig.initSign(signingKey); + + sig.update(data); + + sigBytes = sig.sign(); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail("RIPEMD256 verification failed"); + } + + // + // ISO Sigs. + // + sig = Signature.getInstance("MD5WithRSA/ISO9796-2", "BC"); + + sig.initSign(signingKey); + + sig.update(data); + + sigBytes = sig.sign(); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail("MD5/ISO verification failed"); + } + + sig = Signature.getInstance("SHA1WithRSA/ISO9796-2", "BC"); + + sig.initSign(signingKey); + + sig.update(data); + + sigBytes = sig.sign(); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail("SHA1/ISO verification failed"); + } + + tryRsaPkcs15Sig("SHA224WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224); + tryRsaPkcs15Sig("SHA256WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256); + tryRsaPkcs15Sig("SHA384WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384); + tryRsaPkcs15Sig("SHA512WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512); + tryRsaPkcs15Sig("SHA512(224)WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_224WithRSAEncryption, NISTObjectIdentifiers.id_sha512_224); + tryRsaPkcs15Sig("SHA512(256)WithRSA", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_256WithRSAEncryption, NISTObjectIdentifiers.id_sha512_256); + tryRsaPkcs15Sig("SHA224WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha224WithRSAEncryption, NISTObjectIdentifiers.id_sha224); + tryRsaPkcs15Sig("SHA256WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha256WithRSAEncryption, NISTObjectIdentifiers.id_sha256); + tryRsaPkcs15Sig("SHA384WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha384WithRSAEncryption, NISTObjectIdentifiers.id_sha384); + tryRsaPkcs15Sig("SHA512WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512WithRSAEncryption, NISTObjectIdentifiers.id_sha512); + tryRsaPkcs15Sig("SHA512(224)WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_224WithRSAEncryption, NISTObjectIdentifiers.id_sha512_224); + tryRsaPkcs15Sig("SHA512(256)WithRSAEncryption", data, signingKey, verifyKey, PKCSObjectIdentifiers.sha512_256WithRSAEncryption, NISTObjectIdentifiers.id_sha512_256); + + tryRsaPkcs15Sig("SHA3-224WithRSA", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224, NISTObjectIdentifiers.id_sha3_224); + tryRsaPkcs15Sig("SHA3-256WithRSA", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256, NISTObjectIdentifiers.id_sha3_256); + tryRsaPkcs15Sig("SHA3-384WithRSA", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_384, NISTObjectIdentifiers.id_sha3_384); + tryRsaPkcs15Sig("SHA3-512WithRSA", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_512, NISTObjectIdentifiers.id_sha3_512); + tryRsaPkcs15Sig("SHA3-224WithRSAEncryption", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_224, NISTObjectIdentifiers.id_sha3_224); + tryRsaPkcs15Sig("SHA3-256WithRSAEncryption", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_256, NISTObjectIdentifiers.id_sha3_256); + tryRsaPkcs15Sig("SHA3-384WithRSAEncryption", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_384, NISTObjectIdentifiers.id_sha3_384); + tryRsaPkcs15Sig("SHA3-512WithRSAEncryption", data, signingKey, verifyKey, NISTObjectIdentifiers.id_rsassa_pkcs1_v1_5_with_sha3_512, NISTObjectIdentifiers.id_sha3_512); + + trySig("SHA1WithRSAAndMGF1", data, signingKey, verifyKey); + trySig("SHA224WithRSAAndMGF1", data, signingKey, verifyKey); + trySig("SHA256WithRSAAndMGF1", data, signingKey, verifyKey); + //trySig("SHA384WithRSAAndMGF1", data, signingKey, verifyKey); + //trySig("SHA512WithRSAAndMGF1", data, signingKey, verifyKey); + trySig("SHA512(224)WithRSAAndMGF1", data, signingKey, verifyKey); + trySig("SHA512(256)WithRSAAndMGF1", data, signingKey, verifyKey); + + trySig("SHA3-224WithRSAAndMGF1", data, signingKey, verifyKey); + trySig("SHA3-256WithRSAAndMGF1", data, signingKey, verifyKey); +// trySig("SHA3-384WithRSAAndMGF1", data, signingKey, verifyKey); +// trySig("SHA3-512WithRSAAndMGF1", data, signingKey, verifyKey); + + trySig("SHA1WithRSA/ISO9796-2", data, signingKey, verifyKey); + trySig("SHA224WithRSA/ISO9796-2", data, signingKey, verifyKey); + trySig("SHA256withRSA/ISO9796-2", data, signingKey, verifyKey); + trySig("SHA384WithRSA/ISO9796-2", data, signingKey, verifyKey); + trySig("SHA512WithRSA/ISO9796-2", data, signingKey, verifyKey); + trySig("SHA512(224)WithRSA/ISO9796-2", data, signingKey, verifyKey); + trySig("SHA512(256)WithRSA/ISO9796-2", data, signingKey, verifyKey); + trySig("WhirlpoolWithRSA/ISO9796-2", data, signingKey, verifyKey); + trySig("RIPEMD160WithRSA/ISO9796-2", data, signingKey, verifyKey); + + trySig("RIPEMD128WithRSA/X9.31", data, signingKey, verifyKey); + trySig("RIPEMD160WithRSA/X9.31", data, signingKey, verifyKey); + trySig("SHA1WithRSA/X9.31", data, signingKey, verifyKey); + trySig("SHA224WithRSA/X9.31", data, signingKey, verifyKey); + trySig("SHA256withRSA/X9.31", data, signingKey, verifyKey); + trySig("SHA384WithRSA/X9.31", data, signingKey, verifyKey); + trySig("SHA512WithRSA/X9.31", data, signingKey, verifyKey); + trySig("SHA512(224)WithRSA/X9.31", data, signingKey, verifyKey); + trySig("SHA512(256)WithRSA/X9.31", data, signingKey, verifyKey); + trySig("WhirlpoolWithRSA/X9.31", data, signingKey, verifyKey); + + KeyFactory keyFact = KeyFactory.getInstance("RSA", "BC"); + + BigInteger mod = new BigInteger("f6b18dfb2eb944d8df7e8b8077f8857ffa7a4192ea10cdd87edf7839872d50029ed86fc17c8b90bef725517b7f2f6403559957d0d4220ed8283ebde769d9f7024b84654d7b398d64b582520e6b7a7e07c1aea5eedbfac0474ac239a5ceb6e5e7", 16); + + RSAPublicKey vKey = (RSAPublicKey)keyFact.generatePublic(new RSAPublicKeySpec(mod, new BigInteger("10001", 16))); + RSAPrivateKey sKey = (RSAPrivateKey)keyFact.generatePrivate(new RSAPrivateKeySpec(mod, new BigInteger("6af2b6d6fa7e9f76560e0a747b8e66720129175c95d50b289c784d2ac38bc5701d653fade64cab47dee572d9d35dbc414be785166afe59a4dd3e7b5a19e756ed83c56319ece6a3a8a4e8d982526361bb133d49a27c4299a5d717189ebd9159a1", 16))); + + trySig("SHA1WithRSA/X9.31", data, sKey, vKey); + + shouldPassSignatureX931Test1(); + shouldPassSignatureX931Test2(); + shouldPassSignatureX931Test3(); + + // + // standard vector test - B.1.3 RIPEMD160, implicit. + // + mod = new BigInteger("ffffffff78f6c55506c59785e871211ee120b0b5dd644aa796d82413a47b24573f1be5745b5cd9950f6b389b52350d4e01e90009669a8720bf265a2865994190a661dea3c7828e2e7ca1b19651adc2d5", 16); + BigInteger pub = new BigInteger("03", 16); + BigInteger pri = new BigInteger("2aaaaaaa942920e38120ee965168302fd0301d73a4e60c7143ceb0adf0bf30b9352f50e8b9e4ceedd65343b2179005b2f099915e4b0c37e41314bb0821ad8330d23cba7f589e0f129b04c46b67dfce9d", 16); + + KeyFactory f = KeyFactory.getInstance("RSA", "BC"); + + PrivateKey privKey = f.generatePrivate(new RSAPrivateKeySpec(mod, pri)); + PublicKey pubKey = f.generatePublic(new RSAPublicKeySpec(mod, pub)); + byte[] testSig = Hex.decode("5cf9a01854dbacaec83aae8efc563d74538192e95466babacd361d7c86000fe42dcb4581e48e4feb862d04698da9203b1803b262105104d510b365ee9c660857ba1c001aa57abfd1c8de92e47c275cae"); + + data = Hex.decode("fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210fedcba9876543210"); + + sig = Signature.getInstance("RIPEMD160WithRSA/ISO9796-2", "BC"); + + sig.initSign(privKey); + + sig.update(data); + + sigBytes = sig.sign(); + + if (!Arrays.areEqual(testSig, sigBytes)) + { + fail("SigTest: failed ISO9796-2 generation Test"); + } + + sig.initVerify(pubKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail("RIPEMD160/ISO verification failed"); + } + } + + private void trySig(String algorithm, byte[] data, PrivateKey signingKey, PublicKey verifyKey) + throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException + { + Signature sig; + byte[] sigBytes; + sig = Signature.getInstance(algorithm, "BC"); + + sig.initSign(signingKey); + + sig.update(data); + + sigBytes = sig.sign(); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail(algorithm + " verification failed"); + } + } + + private void tryRsaPkcs15Sig(String algorithm, byte[] data, PrivateKey signingKey, PublicKey verifyKey, ASN1ObjectIdentifier sigOid, ASN1ObjectIdentifier hashOid) + throws Exception + { + Signature sig; + byte[] sigBytes; + sig = Signature.getInstance(algorithm, "BC"); + + sig.initSign(signingKey); + + sig.update(data); + + sigBytes = sig.sign(); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail(algorithm + " verification failed"); + } + + Cipher c = Cipher.getInstance("RSA/NONE/PKCS1Padding", "BC"); + + c.init(Cipher.DECRYPT_MODE, verifyKey); + + DigestInfo digInfo = DigestInfo.getInstance(c.doFinal(sigBytes)); + + isTrue("digest alg not match", digInfo.getAlgorithmId().getAlgorithm().equals(hashOid)); + + sig = Signature.getInstance(sigOid.getId(), "BC"); + + sig.initSign(signingKey); + + sig.update(data); + + isTrue("sig not matched", Arrays.areEqual(sigBytes, sig.sign())); + + sig.initVerify(verifyKey); + + sig.update(data); + + if (!sig.verify(sigBytes)) + { + fail(algorithm + " oid verification failed"); + } + } + + private void shouldPassSignatureX931Test1() + throws Exception + { + BigInteger n = new BigInteger("c9be1b28f8caccca65d86cc3c9bbcc13eccc059df3b80bd2292b811eff3aa0dd75e1e85c333b8e3fa9bed53bb20f5359ff4e6900c5e9a388e3a4772a583a79e2299c76582c2b27694b65e9ba22e66bfb817f8b70b22206d7d8ae488c86dbb7137c26d5eff9b33c90e6cee640630313b7a715802e15142fef498c404a8de19674974785f0f852e2d470fe85a2e54ffca9f5851f672b71df691785a5cdabe8f14aa628942147de7593b2cf962414a5b59c632c4e14f1768c0ab2e9250824beea60a3529f11bf5e070ce90a47686eb0be1086fb21f0827f55295b4a48307db0b048c05a4aec3f488c576ca6f1879d354224c7e84cbcd8e76dd217a3de54dba73c35", 16); + BigInteger e = new BigInteger("e75b1b", 16); + byte[] msg = Hex.decode("5bb0d1c0ef9b5c7af2477fe08d45523d3842a4b2db943f7033126c2a7829bacb3d2cfc6497ec91688189e81b7f8742488224ba320ce983ce9480722f2cc5bc42611f00bb6311884f660ccc244788378673532edb05284fd92e83f6f6dab406209032e6af9a33c998677933e32d6fb95fd27408940d7728f9c9c40267ca1d20ce"); + byte[] sig = Hex.decode("0fe8bb8e3109a1eb7489ef35bf4c1a0780071da789c8bd226a4170538eafefdd30b732d628f0e87a0b9450051feae9754d4fb61f57862d10f0bacc4f660d13281d0cd1141c006ade5186ff7d961a4c6cd0a4b352fc1295c5afd088f80ac1f8e192ef116a010a442655fe8ff5eeacea15807906fb0f0dfa86e680d4c005872357f7ece9aa4e20b15d5f709b30f08648ecaa34f2fbf54eb6b414fa2ff6f87561f70163235e69ccb4ac82a2e46d3be214cc2ef5263b569b2d8fd839b21a9e102665105ea762bda25bb446cfd831487a6b846100dee113ae95ae64f4af22c428c87bab809541c962bb3a56d4c86588e0af4ebc7fcc66dadced311051356d3ea745f7"); + + RSAPublicKeySpec rsaPublic = new RSAPublicKeySpec(n, e); + Signature signer = Signature.getInstance("SHA1withRSA/X9.31", "BC"); + + signer.initVerify(KeyFactory.getInstance("RSA", "BC").generatePublic(rsaPublic)); + + signer.update(msg, 0, msg.length); + + if (!signer.verify(sig)) + { + fail("RSA X931 verify test 1 failed."); + } + } + + private void shouldPassSignatureX931Test2() + throws Exception + { + BigInteger n = new BigInteger("b746ba6c3c0be64bbe33aa55b2929b0af4e86d773d44bfe5914db9287788c4663984b61a418d2eecca30d752ff6b620a07ec72eeb2b422d2429da352407b99982800b9dd7697be6a7b1baa98ca5f4fc2fe33400f20b9dba337ac25c987804165d4a6e0ee4d18eabd6de5abdfe578cae6713ff91d16c80a5bb20217fe614d9509e75a43e1825327b9da8f0a9f6eeaa1c04b69fb4bacc073569fff4ab491becbe6d0441d437fc3fa823239c4a0f75321666b68dd3f66e2dd394089a15bcc288a68a4eb0a48e17d639743b9dea0a91cc35820544732aff253f8ca9967c609dc01c2f8cd0313a7a91cfa94ff74289a1d2b6f19d1811f4b9a65f4cce9e5759b4cc64f", 16); + BigInteger e = new BigInteger("dcbbdb", 16); + byte[] msg = Hex.decode("a5d3c8a060f897bbbc20ae0955052f37fbc70986b6e11c65075c9f457142bfa93856897c69020aa81a91b5e4f39e05cdeecc63395ab849c8262ca8bc5c96870aecb8edb0aba0024a9bdb71e06de6100344e5c318bc979ef32b8a49a8278ba99d4861bce42ebbc5c8c666aaa6cac39aff8779f2cae367620f9edd4cb1d80b6c8c"); + byte[] sig = Hex.decode("39fbbd1804c689a533b0043f84da0f06081038c0fbf31e443e46a05e58f50de5198bbca40522afefaba3aed7082a6cb93b1da39f1f5a42246bf64930781948d300549bef0f8d554ecfca60a1b1ecba95a7014ee4545ad4f0c4e3a31942c6738b4ccd6244b6a21267dadf0826a5f713f13b1f5a9ab8501d957a26d4948278ac67851071a315674bdab173bfef2c2690c8373da6bf3d69f30c0e5da8883de872f59521b40793854085641adf98d13db991c5d0a8aaa0222934fa33332e90ef0b954e195cb267d6ffb36c96e14d1ec7b915a87598b4461a3146566354dc2ae748c84ee0cd46543b53ebff8cdf47725b280a1f799fb6ebb4a31ad2bdd5178250f83a"); + + RSAPublicKeySpec rsaPublic = new RSAPublicKeySpec(n, e); + Signature signer = Signature.getInstance("SHA224withRSA/X9.31", "BC"); + + signer.initVerify(KeyFactory.getInstance("RSA", "BC").generatePublic(rsaPublic)); + + signer.update(msg, 0, msg.length); + + if (!signer.verify(sig)) + { + fail("RSA X931 verify test 2 failed."); + } + } + + private void shouldPassSignatureX931Test3() + throws Exception + { + BigInteger n = new BigInteger("dcb5686a3d2063a3f9cf7b9b32d2d3765b4c449b09b4960245a9111cd3b0cbd3260496885b8e1fa5db33b03efcc759d9c1afe29d93c6faebc7e0efada334b5b9a29655e2da2c8f11103d8203be311feab7ae88e9f1b2ec7d8fc655d77202b1681dd9717ec0f525b35584987e19539635a1ed23ca482a00149c609a23dc1645fd", 16); + BigInteger e = new BigInteger("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dc9f7", 16); + BigInteger d = new BigInteger("189d6345099098992e0c9ca5f281e1338092342fa0acc85cc2a111f30f9bd2fb4753cd1a48ef0ddca9bf1af33ec76fb2e23a9fb4896c26f2235b516f7c05ef7ae81e70f4b491a5fedba9b935e9c76d761a813ce7776ff8a1e5efe1166ff2eca26aa900da88c908d51af9de26977fe39719cc781df32216fa41b838f0c63803c3", 16); + + RSAPublicKeySpec rsaPublic = new RSAPublicKeySpec(n, e); + RSAPrivateKeySpec rsaPriv = new RSAPrivateKeySpec(n, d); + + PrivateKey privateKey = KeyFactory.getInstance("RSA", "BC").generatePrivate(rsaPriv); + PublicKey publicKey = KeyFactory.getInstance("RSA", "BC").generatePublic(rsaPublic); + + + byte[] msg = Hex.decode("911475c6e210ef4ac65b6fe8d2bfe5e01b959771b137c4ef69b88716e0d2ff9ebc1fad0f358c1dd7d50cc99a7b893ac9a6207076f08d8467d9e48c69c683bfe64a44dabaa3f7c243880f6ab7229bf7bb587822314fc5de5131983bfb2eef8b4bc1eac36f353724b567cd1ae8cddd64ddb7057549d5c81ad5fa3b5e751f00abf5"); + byte[] sig = Hex.decode("02c50ec0ac8a7f38ef5630c396964d6a6daaa7e3083ab5b57fa2a2632f3b70e2e85c8456cd774d45d7e44fcb063f0f04fff9f1e3adfda11272535a92cb59320b190b5ee4261f23d6ceaa925df3a7bfa42e26bf61ea9645d9d64b3c90a820802768a6e209c9f83705375a3867afccc037e8242a98fa4c3db6b2d9877754d47289"); + + doGenVerify("SHA1withRSA/X9.31", privateKey, publicKey, msg, sig); + + msg = Hex.decode("911475c6e210ef4ac65b6fe8d2bfe5e01b959771b137c4ef69b88716e0d2ff9ebc1fad0f358c1dd7d50cc99a7b893ac9a6207076f08d8467d9e48c69c683bfe64a44dabaa3f7c243880f6ab7229bf7bb587822314fc5de5131983bfb2eef8b4bc1eac36f353724b567cd1ae8cddd64ddb7057549d5c81ad5fa3b5e751f00abf5"); + sig = Hex.decode("2e2e279850ce21e34228a8e810d3ba835c51932e03c5e8886e99036f25a9a43aa5e33168274b7bfc1745ce8fc7ff3335f0927920f09fe9d4a6fac5e546eaf5aedc7e11ba75d33ae1487857b017930e69ec63a10971ca062c0e24f5b08226e59446d02a7827ceecbbcf6ecf0ffa7b3dff3e1a76b5f7432f804a4aa858e18877a5"); + + doGenVerify("SHA224withRSA/X9.31", privateKey, publicKey, msg, sig); + + msg = Hex.decode("911475c6e210ef4ac65b6fe8d2bfe5e01b959771b137c4ef69b88716e0d2ff9ebc1fad0f358c1dd7d50cc99a7b893ac9a6207076f08d8467d9e48c69c683bfe64a44dabaa3f7c243880f6ab7229bf7bb587822314fc5de5131983bfb2eef8b4bc1eac36f353724b567cd1ae8cddd64ddb7057549d5c81ad5fa3b5e751f00abf5"); + sig = Hex.decode("4f917837c2aedfb13e8c039cb076e399de39c2a964e418ad541745ff8062ca967d2ce6d51190732d3db089e48e31e95746f306314468c7d2248ace2cfbf4d67c59629a6e61813d52c1a84ea9d21a73b0afa7e871217f2ebeffeaa1268278edfcb7f2f98d1d32ef835123906e8d5f896d1af6877e304a39b03cf014ddaf850911"); + + doGenVerify("SHA256withRSA/X9.31", privateKey, publicKey, msg, sig); + + msg = Hex.decode("7d1f36e728dd03b07825c5dcdf6ea933136e1eb819dd8a8aa27c3b0c9b56a0440045b981f1b9cc4107b55a51e81a5136192883cc1442572d9bf1bed44b2c690374d73a612889f8e8929246fe893dd6e26552da4a12dfbb4b63380e78a83dc44e82dba0d0f6d6ef6ec1c5732beb5ea0ff9ff30b7a3a3d1faba2591140d91017ee"); + sig = Hex.decode("1210a59883326234d363155876818f43bdbe7ba758c44104ad771984636e13ecfbad97beb138a836b2d94dafd910ecb5b6ba7de6125a15f683af96220b3370e92ea2e1fb22fcd5e83def31728d9196b59308eb4498dadeddad66e26152b456e613ecc5fc8a7ed33f0608ea1ef886949f3741ab8c41ee453de877e5acea33a557"); + + doGenVerify("SHA384withRSA/X9.31", privateKey, publicKey, msg, sig); + + msg = Hex.decode("911475c6e210ef4ac65b6fe8d2bfe5e01b959771b137c4ef69b88716e0d2ff9ebc1fad0f358c1dd7d50cc99a7b893ac9a6207076f08d8467d9e48c69c683bfe64a44dabaa3f7c243880f6ab7229bf7bb587822314fc5de5131983bfb2eef8b4bc1eac36f353724b567cd1ae8cddd64ddb7057549d5c81ad5fa3b5e751f00abf5"); + sig = Hex.decode("154bbde6991b6c8c137a62595619e0038e6787703568a213cff95dac33bc871f7a45f8a3471b823451d1262f7a8932f11d5f93cadbc63daf840e0bbd7d317b57d385be706b58670afac7f055f67d8834f574863b1e295b2a85905bb9926f3114be2be59ad7782321578a451b91587bda7cd6a5051c0fd934af28d5d479463642"); + + doGenVerify("SHA512withRSA/X9.31", privateKey, publicKey, msg, sig); + } + + private void doGenVerify(String algorithm, PrivateKey privateKey, PublicKey publicKey, byte[] msg, byte[] sig) + throws NoSuchAlgorithmException, NoSuchProviderException, InvalidKeyException, SignatureException + { + Signature signer = Signature.getInstance(algorithm, "BC"); + + signer.initSign(privateKey); + + signer.update(msg, 0, msg.length); + + byte[] s = signer.sign(); + + if (!Arrays.areEqual(sig, s)) + { + fail(algorithm + " sig test 3 failed."); + } + + signer.initVerify(publicKey); + + signer.update(msg, 0, msg.length); + + if (!signer.verify(sig)) + { + fail(algorithm + " verify test 3 failed."); + } + } + + public String getName() + { + return "SigTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new SigTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SignatureTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SignatureTest.java new file mode 100644 index 000000000..5ee6b2fa8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SignatureTest.java @@ -0,0 +1,177 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.Security; +import java.security.Signature; + +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.jce.spec.ECNamedCurveGenParameterSpec; +import com.fr.third.org.bouncycastle.jce.spec.GOST3410ParameterSpec; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SignatureTest + extends SimpleTest +{ + private static final byte[] DATA = Hex.decode("00000000deadbeefbeefdeadffffffff00000000"); + + private void checkSig(KeyPair kp, String name) + throws Exception + { + Signature sig = Signature.getInstance(name, "BC"); + + sig.initSign(kp.getPrivate()); + sig.update(DATA); + + byte[] signature1 = sig.sign(); + + sig.update(DATA); + + byte[] signature2 = sig.sign(); + + sig.initVerify(kp.getPublic()); + + sig.update(DATA); + if (!sig.verify(signature1)) + { + fail("did not verify: " + name); + } + + // After verify, should be reusable as if we are after initVerify + sig.update(DATA); + if (!sig.verify(signature1)) + { + fail("second verify failed: " + name); + } + + sig.update(DATA); + if (!sig.verify(signature2)) + { + fail("second verify failed (2): " + name); + } + } + + public void performTest() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(2048); + + KeyPair kp = kpGen.generateKeyPair(); + + checkSig(kp, "SHA1withRSA"); + checkSig(kp, "SHA224withRSA"); + checkSig(kp, "SHA256withRSA"); + checkSig(kp, "SHA384withRSA"); + checkSig(kp, "SHA512withRSA"); + + checkSig(kp, "SHA3-224withRSA"); + checkSig(kp, "SHA3-256withRSA"); + checkSig(kp, "SHA3-384withRSA"); + checkSig(kp, "SHA3-512withRSA"); + + checkSig(kp, "MD2withRSA"); + checkSig(kp, "MD4withRSA"); + checkSig(kp, "MD5withRSA"); + checkSig(kp, "RIPEMD160withRSA"); + checkSig(kp, "RIPEMD128withRSA"); + checkSig(kp, "RIPEMD256withRSA"); + + checkSig(kp, "SHA1withRSAandMGF1"); + checkSig(kp, "SHA1withRSAandMGF1"); + checkSig(kp, "SHA224withRSAandMGF1"); + checkSig(kp, "SHA256withRSAandMGF1"); + checkSig(kp, "SHA384withRSAandMGF1"); + checkSig(kp, "SHA512withRSAandMGF1"); + + checkSig(kp, "SHA1withRSA/ISO9796-2"); + checkSig(kp, "MD5withRSA/ISO9796-2"); + checkSig(kp, "RIPEMD160withRSA/ISO9796-2"); + +// checkSig(kp, "SHA1withRSA/ISO9796-2PSS"); +// checkSig(kp, "MD5withRSA/ISO9796-2PSS"); +// checkSig(kp, "RIPEMD160withRSA/ISO9796-2PSS"); + + checkSig(kp, "RIPEMD128withRSA/X9.31"); + checkSig(kp, "RIPEMD160withRSA/X9.31"); + checkSig(kp, "SHA1withRSA/X9.31"); + checkSig(kp, "SHA224withRSA/X9.31"); + checkSig(kp, "SHA256withRSA/X9.31"); + checkSig(kp, "SHA384withRSA/X9.31"); + checkSig(kp, "SHA512withRSA/X9.31"); + checkSig(kp, "WhirlpoolwithRSA/X9.31"); + + kpGen = KeyPairGenerator.getInstance("DSA", "BC"); + + kpGen.initialize(2048); + + kp = kpGen.generateKeyPair(); + + checkSig(kp, "SHA1withDSA"); + checkSig(kp, "SHA224withDSA"); + checkSig(kp, "SHA256withDSA"); + checkSig(kp, "SHA384withDSA"); + checkSig(kp, "SHA512withDSA"); + checkSig(kp, "NONEwithDSA"); + + kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(256); + + kp = kpGen.generateKeyPair(); + + checkSig(kp, "SHA1withECDSA"); + checkSig(kp, "SHA224withECDSA"); + checkSig(kp, "SHA256withECDSA"); + checkSig(kp, "SHA384withECDSA"); + checkSig(kp, "SHA512withECDSA"); + checkSig(kp, "RIPEMD160withECDSA"); + + kpGen = KeyPairGenerator.getInstance("EC", "BC"); + + kpGen.initialize(521); + + kp = kpGen.generateKeyPair(); + + checkSig(kp, "SHA1withECNR"); + checkSig(kp, "SHA224withECNR"); + checkSig(kp, "SHA256withECNR"); + checkSig(kp, "SHA384withECNR"); + checkSig(kp, "SHA512withECNR"); + + kpGen = KeyPairGenerator.getInstance("ECGOST3410", "BC"); + + kpGen.initialize(new ECNamedCurveGenParameterSpec("GostR3410-2001-CryptoPro-A"), new SecureRandom()); + + kp = kpGen.generateKeyPair(); + + checkSig(kp, "GOST3411withECGOST3410"); + + kpGen = KeyPairGenerator.getInstance("GOST3410", "BC"); + + GOST3410ParameterSpec gost3410P = new GOST3410ParameterSpec(CryptoProObjectIdentifiers.gostR3410_94_CryptoPro_A.getId()); + + kpGen.initialize(gost3410P); + + kp = kpGen.generateKeyPair(); + + checkSig(kp, "GOST3411withGOST3410"); + } + + public String getName() + { + return "SigNameTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new SignatureTest()); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SipHashTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SipHashTest.java new file mode 100644 index 000000000..ce6020e99 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SipHashTest.java @@ -0,0 +1,129 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Security; + +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SipHashTest + extends SimpleTest +{ + public void performTest() + throws Exception + { + testMac(); + testKeyGenerator(); + } + + private void testKeyGenerator() + throws NoSuchAlgorithmException, + NoSuchProviderException + { + testKeyGen("SipHash"); + testKeyGen("SipHash-2-4"); + testKeyGen("SipHash-4-8"); + } + + private void testKeyGen(String algorithm) + throws NoSuchAlgorithmException, + NoSuchProviderException + { + KeyGenerator kg = KeyGenerator.getInstance(algorithm, "BC"); + + SecretKey key = kg.generateKey(); + + if (!key.getAlgorithm().equalsIgnoreCase("SipHash")) + { + fail("Unexpected algorithm name in key", "SipHash", key.getAlgorithm()); + } + if (key.getEncoded().length != 16) + { + fail("Expected 128 bit key"); + } + } + + private void testMac() + throws NoSuchAlgorithmException, + NoSuchProviderException, + InvalidKeyException + { + byte[] key = Hex.decode("000102030405060708090a0b0c0d0e0f"); + byte[] input = Hex.decode("000102030405060708090a0b0c0d0e"); + + byte[] expected = Hex.decode("e545be4961ca29a1"); + + Mac mac = Mac.getInstance("SipHash", "BC"); + + mac.init(new SecretKeySpec(key, "SipHash")); + + mac.update(input, 0, input.length); + + byte[] result = mac.doFinal(); + + if (!Arrays.areEqual(expected, result)) + { + fail("Result does not match expected value for doFinal()"); + } + + mac.init(new SecretKeySpec(key, "SipHash-2-4")); + + mac.update(input, 0, input.length); + + result = mac.doFinal(); + if (!Arrays.areEqual(expected, result)) + { + fail("Result does not match expected value for second doFinal()"); + } + + mac = Mac.getInstance("SipHash-2-4", "BC"); + + mac.init(new SecretKeySpec(key, "SipHash-2-4")); + + mac.update(input, 0, input.length); + + result = mac.doFinal(); + if (!Arrays.areEqual(expected, result)) + { + fail("Result does not match expected value for alias"); + } + + // SipHash 4-8 + expected = Hex.decode("e0a6a97dd589d383"); + + mac = Mac.getInstance("SipHash-4-8", "BC"); + + mac.init(new SecretKeySpec(key, "SipHash")); + + mac.update(input, 0, input.length); + + result = mac.doFinal(); + + if (!Arrays.areEqual(expected, result)) + { + fail("Result does not match expected value for SipHash 4-8"); + } + } + + public String getName() + { + return "SipHash"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new SipHashTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SkeinTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SkeinTest.java new file mode 100644 index 000000000..7ee9508b5 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SkeinTest.java @@ -0,0 +1,316 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.MessageDigest; +import java.security.Security; + +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jcajce.spec.SkeinParameterSpec; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SkeinTest + extends SimpleTest +{ + final static String provider = "BC"; + + static private byte[] nullMsg = new byte[0]; + + static private String[][] nullVectors = + { + { "Skein-256-128", "07e8ff2191c5052e1a25914c7c213078" }, + { "Skein-256-160", "ff800bed6d2044ee9d604a674e3fda50d9b24a72" }, + { "Skein-256-224", "0fadf1fa39e3837a95b3660b4184d9c2f3cfc94b55d8e7a083278bf8" }, + { "Skein-256-256", "c8877087da56e072870daa843f176e9453115929094c3a40c463a196c29bf7ba" }, + { "Skein-512-128", "7c9aff5c3738e3faadc7a5265768def1" }, + { "Skein-512-160", "49daf1ccebb3544bc93cb5019ba91b0eea8876ee" }, + { "Skein-512-224", "1541ae9fc3ebe24eb758ccb1fd60c2c31a9ebfe65b220086e7819e25" }, + { "Skein-512-256", "39ccc4554a8b31853b9de7a1fe638a24cce6b35a55f2431009e18780335d2621" }, + { "Skein-512-384", "dd5aaf4589dc227bd1eb7bc68771f5baeaa3586ef6c7680167a023ec8ce26980f06c4082c488b4ac9ef313f8cbe70808" }, + { "Skein-512-512", "bc5b4c50925519c290cc634277ae3d6257212395cba733bbad37a4af0fa06af41fca7903d06564fea7a2d3730dbdb80c1f85562dfcc070334ea4d1d9e72cba7a" }, + { "Skein-1024-384", "1fdb081963b960e89eaa11b87dda55e8a55a3e1066b30e38d8ae2a45242f7dadfaf06d80ca8a73cd8242ce5eab84c164" }, + { "Skein-1024-512", "e2943eb0bc0efabd49503a76edf7cfcf072db25bad94ed44fe537284163f3119c47ac6f78699b4272255966e0aba65c75a0a64bd23df6996d1bc3174afd9fa8b" }, + { "Skein-1024-1024", "0fff9563bb3279289227ac77d319b6fff8d7e9f09da1247b72a0a265cd6d2a62645ad547ed8193db48cff847c06494a03f55666d3b47eb4c20456c9373c86297d630d5578ebd34cb40991578f9f52b18003efa35d3da6553ff35db91b81ab890bec1b189b7f52cb2a783ebb7d823d725b0b4a71f6824e88f68f982eefc6d19c6" }, + }; + + static private byte[] shortMsg = Hex.decode("fbd17c26b61a82e12e125f0d459b96c91ab4837dff22b39b78439430cdfc5dc8" + + "78bb393a1a5f79bef30995a85a12923339ba8ab7d8fc6dc5fec6f4ed22c122bb" + + "e7eb61981892966de5cef576f71fc7a80d14dab2d0c03940b95b9fb3a727c66a" + + "6e1ff0dc311b9aa21a3054484802154c1826c2a27a0914152aeb76f1168d4410"); + + static private String[][] shortVectors = + { + { "Skein-256-128", "9703382ea27dc2913e9d02cd976c582f" }, + { "Skein-256-160", "0cd491b7715704c3a15a45a1ca8d93f8f646d3a1" }, + { "Skein-256-224", "afd1e2d0f5b6cd4e1f8b3935fa2497d27ee97e72060adac099543487" }, + { "Skein-256-256", "4de6fe2bfdaa3717a4261030ef0e044ced9225d066354610842a24a3eafd1dcf" }, + { "Skein-512-128", "c901b1c04af3da4dce05d7975c419224" }, + { "Skein-512-160", "ef03079d61b57c6047e15fa2b35b46fa24279539" }, + { "Skein-512-224", "d9e3219b214e15246a2038f76a573e018ef69b385b3bd0576b558231" }, + { "Skein-512-256", "809dd3f763a11af90912bbb92bc0d94361cbadab10142992000c88b4ceb88648" }, + { "Skein-512-384", "825f5cbd5da8807a7b4d3e7bd9cd089ca3a256bcc064cd73a9355bf3ae67f2bf93ac7074b3b19907a0665ba3a878b262" }, + { "Skein-512-512", "1a0d5abf4432e7c612d658f8dcfa35b0d1ab68b8d6bd4dd115c23cc57b5c5bcdde9bff0ece4208596e499f211bc07594d0cb6f3c12b0e110174b2a9b4b2cb6a9" }, + { "Skein-1024-384", "9c3d0648c11f31c18395d5e6c8ebd73f43d189843fc45235e2c35e345e12d62bc21a41f65896ddc6a04969654c2e2ce9" }, + { "Skein-1024-512", "5d0416f49c2d08dfd40a1446169dc6a1d516e23b8b853be4933513051de8d5c26baccffb08d3b16516ba3c6ccf3e9a6c78fff6ef955f2dbc56e1459a7cdba9a5" }, + { "Skein-1024-1024", "96ca81f586c825d0360aef5acaec49ad55289e1797072eee198b64f349ce65b6e6ed804fe38f05135fe769cc56240ddda5098f620865ce4a4278c77fa2ec6bc31c0f354ca78c7ca81665bfcc5dc54258c3b8310ed421d9157f36c093814d9b25103d83e0ddd89c52d0050e13a64c6140e6388431961685734b1f138fe2243086" }, + }; + + static private String[][] shortMacVectors = + { + { "Skein-Mac-256-128", "738f8b23541d50f691ab60af664c1583" }, + { "Skein-Mac-256-160", "fe07fe50f99b7683bc16980041d8c045857f1189" }, + { "Skein-Mac-256-224", "0bc19b185f5bfe50f0dba7ab49cd8ca9440260edd5a392d4bdcd2216" }, + { "Skein-Mac-256-256", "9837ba53d23afcdabd9fcd614ce9e51c0ebecec7a210df4d3724ed591f026ef1" }, + { "Skein-Mac-512-128", "6d34f46f2033947da7a9dfb068f4102d" }, + { "Skein-Mac-512-160", "83cb2effecaa60674c2f9fb2fb6771a9899708ba" }, + { "Skein-Mac-512-224", "e5f83c032875451f31977cd649c866708cb283a509e99cdfd4d995c5" }, + { "Skein-Mac-512-256", "ed5507ec551ec944c6ed531990c32907eca885dd3af3d50dd09f1dbef422bb11" }, + { "Skein-Mac-512-384", "b8f84a212723b92a591d6dc145c1655c70df710e9f3365064abdf79e9288dced2f0f895d81f465c811f1207b43b8cfce" }, + { "Skein-Mac-512-512", "d13ba582467096a0f862114d97baa218512f39c82c984aa29deee724950d7f0929f726173dd42bc35566b0dbfbf5d2a1552ba6f132de301846714215b64e7f82" }, + { "Skein-Mac-1024-384", "490dbbd049403e602ee3535181a70ee2eb5ade6d83b519953dd0d93c45729f098b679efcd64b5e3f03cd2fa9f1e70d69" }, + { "Skein-Mac-1024-512", "ce7f1052fa486309d73058d1d4986f886d966a849c72d196bb2b97fc9fb0b1e69f43a521ebd979f5a5581bd12a0dbd0d1ee27af0929881f1d35c875cc0542ecf" }, + { "Skein-Mac-1024-1024", "60cd8c755b331bcefe97be5a9fe6f63146d12520ca7b20dbc5c5370dae2ff9815c95fab564329a01eced76f0ecb1944ad52a74e89fa1b6cdcdcee4c71c2c18909c4d1324d279fac5ca2280eea0fa70521cf4ea8c616a3ac6082c2244bec5c1ab3a173faf29d84bec7fb852e278ed57785535c979b33b81465c437cd998c04b95" }, + }; + + static private String[][] shortHMacVectors = + { + { "HMAC-Skein-256-128", "926a445d5218605286dfe0542a437012" }, + { "HMAC-Skein-256-160", "5ebc30295e4562a879f94db531ada465073b8bb7" }, + { "HMAC-Skein-256-224", "a05b3cfc6b86fda7f5dcf0afbb707dc745fa55279a3f80e2c9977ff1" }, + { "HMAC-Skein-256-256", "51741f6e8ebf133216ac8e05c7a75a6339351fd2dcc4db04e418521c628a2111" }, + { "HMAC-Skein-512-128", "ad51f8c7b1b347fe52f0f5c71ae9b8eb" }, + { "HMAC-Skein-512-160", "e0d06c2d406f32bb14dbb2129176219b62d4f89f" }, + { "HMAC-Skein-512-224", "e7e5327e2aaa88d0038049e8112db31df223be4c31da24abf03731a8" }, + { "HMAC-Skein-512-256", "30177414f6e35019cacc2e3ae474b25765e6e0e541e16d754c3dad19df763ab0" }, + { "HMAC-Skein-512-384", "7f0ba3c1c642cf09eb03d0e3760fe172f22fb263006b1fba5bdea1bfaf6e971c17e039abb0030d1a40ac94a747732cce" }, + { "HMAC-Skein-512-512", "70d864e7f6cbd446778914a951d1961e646ee17a3da8eae551d29f4fafc540b0457cc9f8064c511b80dc29f8369fb5dc258559542abb5342c4892f22934bf5f1" }, + { "HMAC-Skein-1024-384", "e7d3465b30b5089e24244e747a91f7cb255596b49843466497c07e120c5c2232f51151b185a1e8a5610f041a85cc59ee" }, + { "HMAC-Skein-1024-512", "c428059ae2d17ba13e461384c4a64cb0be694909e7a04e4983a4fc16476d644c7764e0019b33ea2a8719f731a579f4f7015da7ec1bc56a4920071ac41da836fe" }, + { "HMAC-Skein-1024-1024", "3ebd13ec7bf1533c343ac78e1b5146225ce7629787f3997b646139c1b80d6f54cd562b7625419ede8710d76410dfb8617514ca3f7abf17657d2bc96722071adb2a6ecd9795a1ef5e4734b450d588efcbc3220faf53c880e61438bb953e024e48db6a745d2368375ac792be858cd01915e28590d4d6d599be95f6e6ceed7d7d91" }, + }; + + static private byte[] shortMacMessage = Hex.decode("d3090c72167517f7"); + static private byte[] shortMacKey = Hex.decode("cb41f1706cde09651203c2d0efbaddf8"); + + static private byte[] keyIdentifier = "asecretkey".getBytes(); + static private byte[] keyIdentifierVector = Hex.decode("ca9970a83997e1c346c4348b54cfc9ba7e19bfba"); + + public String getName() + { + return "Skein"; + } + + void test(String type, String algorithm, byte[] message, String expected) throws Exception + { + MessageDigest digest = MessageDigest.getInstance(algorithm, provider); + + byte[] result = digest.digest(message); + byte[] result2 = digest.digest(message); + + // test zero results valid + if (!MessageDigest.isEqual(result, Hex.decode(expected))) + { + fail(type + " result not equal for " + algorithm, expected, new String(Hex.encode(result))); + } + + // test one digest the same message with the same instance + if (!MessageDigest.isEqual(result, result2)) + { + fail(type + " result object 1 not equal"); + } + + if (!MessageDigest.isEqual(result, Hex.decode(expected))) + { + fail(type + " result object 1 not equal"); + } + + // test two, single byte updates + for (int i = 0; i < message.length; i++) + { + digest.update(message[i]); + } + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail(type + " result object 2 not equal"); + } + + // test three, two half updates + digest.update(message, 0, message.length / 2); + digest.update(message, message.length / 2, message.length - message.length / 2); + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail(type + " result object 3 not equal"); + } + + // test four, clone test + digest.update(message, 0, message.length / 2); + MessageDigest d = (MessageDigest)digest.clone(); + digest.update(message, message.length / 2, message.length - message.length / 2); + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail(type + " result object 4(a) not equal"); + } + + d.update(message, message.length / 2, message.length - message.length / 2); + result2 = d.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail(type + " result object 4(b) not equal"); + } + + // test five, check reset() method + digest.update(message, 0, message.length / 2); + digest.reset(); + digest.update(message, 0, message.length / 2); + digest.update(message, message.length / 2, message.length - message.length / 2); + result2 = digest.digest(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail(type + " result object 5 not equal"); + } + } + + private void testMac(String algorithm, byte[] message, byte[] key, String expected) throws Exception + { + Mac mac = Mac.getInstance(algorithm, provider); + + mac.init(new SecretKeySpec(key, algorithm)); + + byte[] result = mac.doFinal(message); + byte[] result2 = mac.doFinal(message); + + // test zero results valid + if (!MessageDigest.isEqual(result, Hex.decode(expected))) + { + fail("null result not equal for " + algorithm, expected, new String(Hex.encode(result))); + } + + // test one digest the same message with the same instance + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 1 not equal"); + } + + if (!MessageDigest.isEqual(result, Hex.decode(expected))) + { + fail("Result object 1 not equal"); + } + + // test two, single byte updates + for (int i = 0; i < message.length; i++) + { + mac.update(message[i]); + } + result2 = mac.doFinal(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 2 not equal"); + } + + // test three, two half updates + mac.update(message, 0, message.length / 2); + mac.update(message, message.length / 2, message.length - message.length / 2); + result2 = mac.doFinal(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 3 not equal"); + } + + // test five, check reset() method + mac.update(message, 0, message.length / 2); + mac.reset(); + mac.update(message, 0, message.length / 2); + mac.update(message, message.length / 2, message.length - message.length / 2); + result2 = mac.doFinal(); + + if (!MessageDigest.isEqual(result, result2)) + { + fail("Result object 5 not equal"); + } + + // test six, check KeyGenerator + KeyGenerator generator = KeyGenerator.getInstance(algorithm, provider); + + mac = Mac.getInstance(algorithm, provider); + final SecretKey generatedKey = generator.generateKey(); + if (generatedKey.getEncoded().length != mac.getMacLength()) + { + fail("Default mac key length for " + algorithm); + } + mac.init(generatedKey); + mac.update(message); + mac.doFinal(); + } + + private void testParameters() throws Exception + { + Mac mac = Mac.getInstance("Skein-Mac-512-160", provider); + + // test six, init using SkeinParameters + mac.init(new SecretKeySpec(shortMacKey, "Skein-Mac-512-160"), + new SkeinParameterSpec.Builder().setKeyIdentifier(keyIdentifier).build()); + byte[] result = mac.doFinal(shortMacMessage); + + if (!MessageDigest.isEqual(result, keyIdentifierVector)) + { + fail("Mac with key identifier failed.", new String(Hex.encode(keyIdentifierVector)), new String(Hex.encode(result))); + } + } + + private void testMacKeyGenerators(String algorithm) throws Exception + { + KeyGenerator gen = KeyGenerator.getInstance(algorithm); + + int outputSize = Integer.parseInt(algorithm.substring(algorithm.lastIndexOf('-') + 1)); + SecretKey key = gen.generateKey(); + + if (key.getEncoded().length != (outputSize / 8)) { + fail(algorithm + " key length should be equal to output size " + (outputSize) + ", but was " + key.getEncoded().length * 8); + } + } + + public void performTest() throws Exception + { + for (int i = 0; i < nullVectors.length; i++) + { + test("Null message", nullVectors[i][0], nullMsg, nullVectors[i][1]); + } + for (int i = 0; i < shortVectors.length; i++) + { + test("Short message", shortVectors[i][0], shortMsg, shortVectors[i][1]); + } + for (int i = 0; i < shortMacVectors.length; i++) + { + testMac(shortMacVectors[i][0], shortMacMessage, shortMacKey, shortMacVectors[i][1]); + testMacKeyGenerators(shortMacVectors[i][0]); + } + + for (int i = 0; i < shortHMacVectors.length; i++) + { + testMac(shortHMacVectors[i][0], shortMacMessage, shortMacKey, shortHMacVectors[i][1]); + testMacKeyGenerators(shortHMacVectors[i][0]); + } + testParameters(); + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new SkeinTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SlotTwoTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SlotTwoTest.java new file mode 100644 index 000000000..841009c63 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/SlotTwoTest.java @@ -0,0 +1,90 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Key; +import java.security.SecureRandom; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.spec.IvParameterSpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class SlotTwoTest + extends SimpleTest +{ + byte[] plainData = "abcdefghijklmnopqrstuvwxyz".getBytes(); + + public String getName() + { + return "SlotTwo"; + } + + public void performTest() + throws Exception + { + Security.removeProvider("BC"); + Security.insertProviderAt(new BouncyCastleProvider(), 2); + + KeyGenerator keyGen = KeyGenerator.getInstance("DESede", "BC"); + + keyGen.init(new SecureRandom()); + + Key key = keyGen.generateKey(); + + testDesEde(key, "ECB", "PKCS7Padding"); + testDesEde(key, "CBC", "PKCS7Padding"); + testDesEde(key, "CTR", "NoPadding"); + testDesEde(key, "CTR", "PKCS7Padding"); + testDesEde(key, "OFB", "PKCS7Padding"); + testDesEde(key, "CFB", "PKCS7Padding"); + + Security.removeProvider("BC"); + Security.addProvider(new BouncyCastleProvider()); + } + + private void testDesEde( + Key key, + String mode, + String padding) + throws Exception + { + Cipher encrypt = Cipher.getInstance("DESede/" + mode + "/" + padding, "BC"); + Cipher decrypt = Cipher.getInstance("DESede/" + mode + "/" + padding); + + if (!decrypt.getProvider().getName().equals("BC")) + { + fail("BC provider not returned for DESede/" + mode + "/" + padding + " got " + decrypt.getProvider().getName()); + } + + encrypt.init(Cipher.ENCRYPT_MODE, key); + + byte[] encryptedBytes = encrypt.doFinal(plainData); + byte[] ivBytes = encrypt.getIV(); + + if (ivBytes != null) + { + IvParameterSpec ivp = new IvParameterSpec(ivBytes); + + decrypt.init(Cipher.DECRYPT_MODE, key, ivp); + } + else + { + decrypt.init(Cipher.DECRYPT_MODE, key); + } + + byte[] plainBytes = decrypt.doFinal(encryptedBytes, 0, encryptedBytes.length); + + if (!areEqual(plainData, plainBytes)) + { + fail("decryption test failed."); + } + } + + public static void main( + String[] args) + { + runTest(new SlotTwoTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/TLSKDFTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/TLSKDFTest.java new file mode 100644 index 000000000..4b793d62a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/TLSKDFTest.java @@ -0,0 +1,159 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Security; + +import javax.crypto.SecretKey; +import javax.crypto.SecretKeyFactory; + +import com.fr.third.org.bouncycastle.jcajce.spec.TLSKeyMaterialSpec; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class TLSKDFTest + extends SimpleTest +{ + public String getName() + { + return "TLSKDF"; + } + + private void testTls10() + throws Exception + { + byte[] pre_master_secret = Hex.decode("bded7fa5c1699c010be23dd06ada3a48349f21e5f86263d512c0c5cc379f0e780ec55d9844b2f1db02a96453513568d0"); + byte[] serverHello_random = Hex.decode("135e4d557fdf3aa6406d82975d5c606a9734c9334b42136e96990fbd5358cdb2"); + byte[] clientHello_random = Hex.decode("e5acaf549cd25c22d964c0d930fa4b5261d2507fad84c33715b7b9a864020693"); + byte[] server_random = Hex.decode("67267e650eb32444119d222a368c191af3082888dc35afe8368e638c828874be"); + byte[] client_random = Hex.decode("d58a7b1cd4fedaa232159df652ce188f9d997e061b9bf48e83b62990440931f6"); + byte[] master_secret = Hex.decode("2f6962dfbc744c4b2138bb6b3d33054c5ecc14f24851d9896395a44ab3964efc2090c5bf51a0891209f46c1e1e998f62"); + byte[] key_block = Hex.decode("3088825988e77fce68d19f756e18e43eb7fe672433504feaf99b3c503d9091b164f166db301d70c9fc0870b4a94563907bee1a61fb786cb717576890bcc51cb9ead97e01d0a2fea99c953377b195205ff07b369589178796edc963fd80fdbe518a2fc1c35c18ae8d"); + + SecretKeyFactory kFact = SecretKeyFactory.getInstance("TLS10KDF", "BC"); + + SecretKey keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(pre_master_secret, TLSKeyMaterialSpec.MASTER_SECRET, master_secret.length, clientHello_random, serverHello_random)); + + isTrue("name mismatch (10): " + keyMaterial.getAlgorithm(), keyMaterial.getAlgorithm().equals("TLS10KDF")); + + isTrue("key block error (pre)", Arrays.areEqual(master_secret, keyMaterial.getEncoded())); + + keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(master_secret, TLSKeyMaterialSpec.KEY_EXPANSION, key_block.length, server_random, client_random)); + + isTrue("key block error", Arrays.areEqual(key_block, keyMaterial.getEncoded())); + } + + private void testTls11() + throws Exception + { + byte[] pre_master_secret = Hex.decode("bded7fa5c1699c010be23dd06ada3a48349f21e5f86263d512c0c5cc379f0e780ec55d9844b2f1db02a96453513568d0"); + byte[] serverHello_random = Hex.decode("135e4d557fdf3aa6406d82975d5c606a9734c9334b42136e96990fbd5358cdb2"); + byte[] clientHello_random = Hex.decode("e5acaf549cd25c22d964c0d930fa4b5261d2507fad84c33715b7b9a864020693"); + byte[] server_random = Hex.decode("67267e650eb32444119d222a368c191af3082888dc35afe8368e638c828874be"); + byte[] client_random = Hex.decode("d58a7b1cd4fedaa232159df652ce188f9d997e061b9bf48e83b62990440931f6"); + byte[] master_secret = Hex.decode("2f6962dfbc744c4b2138bb6b3d33054c5ecc14f24851d9896395a44ab3964efc2090c5bf51a0891209f46c1e1e998f62"); + byte[] key_block = Hex.decode("3088825988e77fce68d19f756e18e43eb7fe672433504feaf99b3c503d9091b164f166db301d70c9fc0870b4a94563907bee1a61fb786cb717576890bcc51cb9ead97e01d0a2fea99c953377b195205ff07b369589178796edc963fd80fdbe518a2fc1c35c18ae8d"); + + SecretKeyFactory kFact = SecretKeyFactory.getInstance("TLS11KDF", "BC"); + + SecretKey keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(pre_master_secret, TLSKeyMaterialSpec.MASTER_SECRET, master_secret.length, clientHello_random, serverHello_random)); + + isTrue("name mismatch (11): " + keyMaterial.getAlgorithm(), keyMaterial.getAlgorithm().equals("TLS11KDF")); + + isTrue("key block error (pre)", Arrays.areEqual(master_secret, keyMaterial.getEncoded())); + + keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(master_secret, TLSKeyMaterialSpec.KEY_EXPANSION, key_block.length, server_random, client_random)); + + isTrue("key block error", Arrays.areEqual(key_block, keyMaterial.getEncoded())); + } + + private void testTls12Sha256() + throws Exception + { + byte[] pre_master_secret = Hex.decode("f8938ecc9edebc5030c0c6a441e213cd24e6f770a50dda07876f8d55da062bcadb386b411fd4fe4313a604fce6c17fbc"); + byte[] serverHello_random = Hex.decode("f6c9575ed7ddd73e1f7d16eca115415812a43c2b747daaaae043abfb50053fce"); + byte[] clientHello_random = Hex.decode("36c129d01a3200894b9179faac589d9835d58775f9b5ea3587cb8fd0364cae8c"); + byte[] server_random = Hex.decode("ae6c806f8ad4d80784549dff28a4b58fd837681a51d928c3e30ee5ff14f39868"); + byte[] client_random = Hex.decode("62e1fd91f23f558a605f28478c58cf72637b89784d959df7e946d3f07bd1b616"); + byte[] master_secret = Hex.decode("202c88c00f84a17a20027079604787461176455539e705be730890602c289a5001e34eeb3a043e5d52a65e66125188bf"); + byte[] key_block = Hex.decode("d06139889fffac1e3a71865f504aa5d0d2a2e89506c6f2279b670c3e1b74f531016a2530c51a3a0f7e1d6590d0f0566b2f387f8d11fd4f731cdd572d2eae927f6f2f81410b25e6960be68985add6c38445ad9f8c64bf8068bf9a6679485d966f1ad6f68b43495b10a683755ea2b858d70ccac7ec8b053c6bd41ca299d4e51928"); + + SecretKeyFactory kFact = SecretKeyFactory.getInstance("TLS12withSHA256KDF", "BC"); + + SecretKey keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(pre_master_secret, TLSKeyMaterialSpec.MASTER_SECRET, master_secret.length, clientHello_random, serverHello_random)); + + isTrue("name mismatch (12-256)", keyMaterial.getAlgorithm().equals("TLS12withSHA256KDF")); + + isTrue("key block error (pre)", Arrays.areEqual(master_secret, keyMaterial.getEncoded())); + + keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(master_secret, TLSKeyMaterialSpec.KEY_EXPANSION, key_block.length, server_random, client_random)); + + isTrue("key block error", Arrays.areEqual(key_block, keyMaterial.getEncoded())); + } + + private void testTls12Sha384() + throws Exception + { + byte[] pre_master_secret = Hex.decode("a5e2642633f5b8c81ad3fe0c2fe3a8e5ef806b06121dd10df4bb0fe857bfdcf522558e05d2682c9a80c741a3aab1716f"); + byte[] serverHello_random = Hex.decode("cb6e0b3eb02976b6466dfa9651c2919414f1648fd3a7838d02153e5bd39535b6"); + byte[] clientHello_random = Hex.decode("abe4bf5527429ac8eb13574d2709e8012bd1a113c6d3b1d3aa2c3840518778ac"); + byte[] server_random = Hex.decode("1b1c8568344a65c30828e7483c0e353e2c68641c9551efae6927d9cd627a107c"); + byte[] client_random = Hex.decode("954b5fe1849c2ede177438261f099a2fcd884d001b9fe1de754364b1f6a6dd8e"); + byte[] master_secret = Hex.decode("b4d49bfa87747fe815457bc3da15073d6ac73389e703079a3503c09e14bd559a5b3c7c601c7365f6ea8c68d3d9596827"); + byte[] key_block = Hex.decode("10fd89ef689c7ef033387b8a8f3e5e8e7c11f680f6bdd71fbac3246a73e98d45d03185dde686e6b2369e4503e9dc5a6d2cee3e2bf2fa3f41d3de57dff3e197c8a9d5f74cc2d277119d894f8584b07a0a5822f0bd68b3433ec6adaf5c9406c5f3ddbb71bbe17ce98f3d4d5893d3179ef369f57aad908e2bf710639100c3ce7e0c"); + + SecretKeyFactory kFact = SecretKeyFactory.getInstance("TLS12withSHA384KDF", "BC"); + + SecretKey keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(pre_master_secret, TLSKeyMaterialSpec.MASTER_SECRET, master_secret.length, clientHello_random, serverHello_random)); + + isTrue("name mismatch (12-384)", keyMaterial.getAlgorithm().equals("TLS12withSHA384KDF")); + + isTrue("key block error (pre)", Arrays.areEqual(master_secret, keyMaterial.getEncoded())); + + keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(master_secret, TLSKeyMaterialSpec.KEY_EXPANSION, key_block.length, server_random, client_random)); + + isTrue("key block error", Arrays.areEqual(key_block, keyMaterial.getEncoded())); + } + + private void testTls12Sha512() + throws Exception + { + byte[] pre_master_secret = Hex.decode("dfef39af25c12663a91ee5d27042b9644a16ef55b81055d1bd7dcb0b8f06eb001708cdefcf82591defca1a6f1ac693ab"); + byte[] serverHello_random = Hex.decode("e2339a6c681eb30808883971b1ce5b9b1ece0f3d011a96a7fff1f5f9d80ffd4b"); + byte[] clientHello_random = Hex.decode("78bc5298dfe9cf8ed336c2e2f0f6b46e2456f39f35f1143cd21eaa16277025b2"); + byte[] server_random = Hex.decode("11cfbd3b45e5e917c4edbabc27b9feac833bbbacabd079465b2759fab3063330"); + byte[] client_random = Hex.decode("b5c41ac5ebd55d136d916547fee741bc1b509f766d50b29d7378b0cebace3c8a"); + byte[] master_secret = Hex.decode("a70c5fe8d34b645a20ce98969bd30858e729c77c8a5f05d3e289219d6b5752b75b75e1ca00d3329658d7f188ed1ab7e0"); + byte[] key_block = Hex.decode("a56650076e6bdaad7e1ea42d68a0f5ffead9b6b5232ba538767e4cc6a3ae9abcae897b068645496cd620f865ce0879081a98901fb98b112ce1f00165e7d6b3288eb4d4ed9811fdbbc24e290b8e448c71da72498449ea67cfdafd66adc31a89d83cc44cf01c749fb531494ff8cb9a677762a7220e32b7f251fde09841bf97110e"); + + SecretKeyFactory kFact = SecretKeyFactory.getInstance("TLS12withSHA512KDF", "BC"); + + SecretKey keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(pre_master_secret, TLSKeyMaterialSpec.MASTER_SECRET, master_secret.length, clientHello_random, serverHello_random)); + + isTrue("name mismatch (12-512)", keyMaterial.getAlgorithm().equals("TLS12withSHA512KDF")); + + isTrue("key block error (pre)", Arrays.areEqual(master_secret, keyMaterial.getEncoded())); + + keyMaterial = kFact.generateSecret(new TLSKeyMaterialSpec(master_secret, TLSKeyMaterialSpec.KEY_EXPANSION, key_block.length, server_random, client_random)); + + isTrue("key block error", Arrays.areEqual(key_block, keyMaterial.getEncoded())); + } + + public void performTest() + throws Exception + { + testTls10(); + testTls11(); + testTls12Sha256(); + testTls12Sha384(); + testTls12Sha512(); + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new TLSKDFTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/TestUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/TestUtils.java new file mode 100644 index 000000000..d15631ef8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/TestUtils.java @@ -0,0 +1,457 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.io.ByteArrayInputStream; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateExpiredException; +import java.security.cert.CertificateFactory; +import java.security.cert.CertificateNotYetValidException; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1Integer; +import com.fr.third.org.bouncycastle.asn1.DERBitString; +import com.fr.third.org.bouncycastle.asn1.DERNull; +import com.fr.third.org.bouncycastle.asn1.DERSequence; +import com.fr.third.org.bouncycastle.asn1.cryptopro.CryptoProObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.x500.X500Name; +import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.AuthorityKeyIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.BasicConstraints; +import com.fr.third.org.bouncycastle.asn1.x509.CRLNumber; +import com.fr.third.org.bouncycastle.asn1.x509.CRLReason; +import com.fr.third.org.bouncycastle.asn1.x509.Certificate; +import com.fr.third.org.bouncycastle.asn1.x509.Extension; +import com.fr.third.org.bouncycastle.asn1.x509.Extensions; +import com.fr.third.org.bouncycastle.asn1.x509.ExtensionsGenerator; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralName; +import com.fr.third.org.bouncycastle.asn1.x509.GeneralNames; +import com.fr.third.org.bouncycastle.asn1.x509.KeyUsage; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectKeyIdentifier; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x509.TBSCertificate; +import com.fr.third.org.bouncycastle.asn1.x509.Time; +import com.fr.third.org.bouncycastle.asn1.x509.V1TBSCertificateGenerator; +import com.fr.third.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator; +import com.fr.third.org.bouncycastle.asn1.x509.X509Extensions; +import com.fr.third.org.bouncycastle.asn1.x9.X9ObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA1Digest; +import com.fr.third.org.bouncycastle.jce.PrincipalUtil; +import com.fr.third.org.bouncycastle.x509.X509V2CRLGenerator; +import com.fr.third.org.bouncycastle.x509.extension.AuthorityKeyIdentifierStructure; + +/** + * Test Utils + */ +class TestUtils +{ + private static AtomicLong serialNumber = new AtomicLong(System.currentTimeMillis()); + private static Map algIds = new HashMap(); + + static + { + algIds.put("GOST3411withGOST3410", new AlgorithmIdentifier(CryptoProObjectIdentifiers.gostR3411_94_with_gostR3410_94)); + algIds.put("SHA1withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha1WithRSAEncryption, DERNull.INSTANCE)); + algIds.put("SHA256withRSA", new AlgorithmIdentifier(PKCSObjectIdentifiers.sha256WithRSAEncryption, DERNull.INSTANCE)); + algIds.put("SHA1withECDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA1)); + algIds.put("SHA256withECDSA", new AlgorithmIdentifier(X9ObjectIdentifiers.ecdsa_with_SHA256)); + } + + public static X509Certificate createSelfSignedCert(String dn, String sigName, KeyPair keyPair) + throws Exception + { + return createSelfSignedCert(new X500Name(dn), sigName, keyPair); + } + + public static X509Certificate createSelfSignedCert(X500Name dn, String sigName, KeyPair keyPair) + throws Exception + { + V1TBSCertificateGenerator certGen = new V1TBSCertificateGenerator(); + + long time = System.currentTimeMillis(); + + certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement())); + certGen.setIssuer(dn); + certGen.setSubject(dn); + certGen.setStartDate(new Time(new Date(time - 5000))); + certGen.setEndDate(new Time(new Date(time + 30 * 60 * 1000))); + certGen.setSignature((AlgorithmIdentifier)algIds.get(sigName)); + certGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded())); + + Signature sig = Signature.getInstance(sigName, "BC"); + + sig.initSign(keyPair.getPrivate()); + + sig.update(certGen.generateTBSCertificate().getEncoded(ASN1Encoding.DER)); + + TBSCertificate tbsCert = certGen.generateTBSCertificate(); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCert); + v.add((AlgorithmIdentifier)algIds.get(sigName)); + v.add(new DERBitString(sig.sign())); + + return (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER))); + } + + public static X509Certificate createCert(X500Name signerName, PrivateKey signerKey, String dn, String sigName, Extensions extensions, PublicKey pubKey) + throws Exception + { + return createCert(signerName, signerKey, new X500Name(dn), sigName, extensions, pubKey); + } + + public static X509Certificate createCert(X500Name signerName, PrivateKey signerKey, X500Name dn, String sigName, Extensions extensions, PublicKey pubKey) + throws Exception + { + V3TBSCertificateGenerator certGen = new V3TBSCertificateGenerator(); + + long time = System.currentTimeMillis(); + + certGen.setSerialNumber(new ASN1Integer(serialNumber.getAndIncrement())); + certGen.setIssuer(signerName); + certGen.setSubject(dn); + certGen.setStartDate(new Time(new Date(time - 5000))); + certGen.setEndDate(new Time(new Date(time + 30 * 60 * 1000))); + certGen.setSignature((AlgorithmIdentifier)algIds.get(sigName)); + certGen.setSubjectPublicKeyInfo(SubjectPublicKeyInfo.getInstance(pubKey.getEncoded())); + certGen.setExtensions(extensions); + + Signature sig = Signature.getInstance(sigName, "BC"); + + sig.initSign(signerKey); + + sig.update(certGen.generateTBSCertificate().getEncoded(ASN1Encoding.DER)); + + TBSCertificate tbsCert = certGen.generateTBSCertificate(); + + ASN1EncodableVector v = new ASN1EncodableVector(); + + v.add(tbsCert); + v.add((AlgorithmIdentifier)algIds.get(sigName)); + v.add(new DERBitString(sig.sign())); + + return (X509Certificate)CertificateFactory.getInstance("X.509", "BC").generateCertificate(new ByteArrayInputStream(new DERSequence(v).getEncoded(ASN1Encoding.DER))); + } + + /** + * Create a random 1024 bit RSA key pair + */ + public static KeyPair generateRSAKeyPair() + throws Exception + { + KeyPairGenerator kpGen = KeyPairGenerator.getInstance("RSA", "BC"); + + kpGen.initialize(1024, new SecureRandom()); + + return kpGen.generateKeyPair(); + } + + public static X509Certificate generateRootCert(KeyPair pair) + throws Exception + { + return createSelfSignedCert("CN=Test CA Certificate", "SHA256withRSA", pair); + } + + public static X509Certificate generateRootCert(KeyPair pair, X500Name dn) + throws Exception + { + return createSelfSignedCert(dn, "SHA256withRSA", pair); + } + + public static X509Certificate generateIntermediateCert(PublicKey intKey, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + return generateIntermediateCert( + intKey, new X500Name("CN=Test Intermediate Certificate"), caKey, caCert); + } + + public static X509Certificate generateIntermediateCert(PublicKey intKey, X500Name subject, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + Certificate caCertLw = Certificate.getInstance(caCert.getEncoded()); + + ExtensionsGenerator extGen = new ExtensionsGenerator(); + + extGen.addExtension(Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifier(getDigest(caCertLw.getSubjectPublicKeyInfo()), + new GeneralNames(new GeneralName(caCertLw.getIssuer())), + caCertLw.getSerialNumber().getValue())); + extGen.addExtension(Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(getDigest(SubjectPublicKeyInfo.getInstance(intKey.getEncoded())))); + extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0)); + extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); + + return createCert( + caCertLw.getSubject(), + caKey, subject, "SHA256withRSA", extGen.generate(), intKey); + } + + public static X509Certificate generateEndEntityCert(PublicKey intKey, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + return generateEndEntityCert( + intKey, new X500Name("CN=Test End Certificate"), caKey, caCert); + } + + public static X509Certificate generateEndEntityCert(PublicKey entityKey, X500Name subject, PrivateKey caKey, X509Certificate caCert) + throws Exception + { + Certificate caCertLw = Certificate.getInstance(caCert.getEncoded()); + + ExtensionsGenerator extGen = new ExtensionsGenerator(); + + extGen.addExtension(Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifier(getDigest(caCertLw.getSubjectPublicKeyInfo()), + new GeneralNames(new GeneralName(caCertLw.getIssuer())), + caCertLw.getSerialNumber().getValue())); + extGen.addExtension(Extension.subjectKeyIdentifier, false, new SubjectKeyIdentifier(getDigest(entityKey.getEncoded()))); + extGen.addExtension(Extension.basicConstraints, true, new BasicConstraints(0)); + extGen.addExtension(Extension.keyUsage, true, new KeyUsage(KeyUsage.digitalSignature | KeyUsage.keyCertSign | KeyUsage.cRLSign)); + + return createCert( + caCertLw.getSubject(), + caKey, subject, "SHA256withRSA", extGen.generate(), entityKey); + } + + public static X509CRL createCRL( + X509Certificate caCert, + PrivateKey caKey, + BigInteger serialNumber) + throws Exception + { + X509V2CRLGenerator crlGen = new X509V2CRLGenerator(); + Date now = new Date(); + BigInteger revokedSerialNumber = BigInteger.valueOf(2); + + crlGen.setIssuerDN(PrincipalUtil.getSubjectX509Principal(caCert)); + + crlGen.setThisUpdate(now); + crlGen.setNextUpdate(new Date(now.getTime() + 100000)); + crlGen.setSignatureAlgorithm("SHA256WithRSAEncryption"); + + crlGen.addCRLEntry(serialNumber, now, CRLReason.privilegeWithdrawn); + + crlGen.addExtension(Extension.authorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(caCert)); + crlGen.addExtension(Extension.cRLNumber, false, new CRLNumber(BigInteger.valueOf(1))); + + return crlGen.generate(caKey, "BC"); + } + + public static X509Certificate createExceptionCertificate(boolean exceptionOnEncode) + { + return new ExceptionCertificate(exceptionOnEncode); + } + + public static X500Name getCertIssuer(X509Certificate x509Certificate) + throws CertificateEncodingException + { + return TBSCertificate.getInstance(x509Certificate.getTBSCertificate()).getIssuer(); + } + + public static X500Name getCertSubject(X509Certificate x509Certificate) + throws CertificateEncodingException + { + return TBSCertificate.getInstance(x509Certificate.getTBSCertificate()).getSubject(); + } + + private static class ExceptionCertificate + extends X509Certificate + { + private boolean _exceptionOnEncode; + + public ExceptionCertificate(boolean exceptionOnEncode) + { + _exceptionOnEncode = exceptionOnEncode; + } + + public void checkValidity() + throws CertificateExpiredException, CertificateNotYetValidException + { + throw new CertificateNotYetValidException(); + } + + public void checkValidity(Date date) + throws CertificateExpiredException, CertificateNotYetValidException + { + throw new CertificateExpiredException(); + } + + public int getVersion() + { + return 0; + } + + public BigInteger getSerialNumber() + { + return null; + } + + public Principal getIssuerDN() + { + return null; + } + + public Principal getSubjectDN() + { + return null; + } + + public Date getNotBefore() + { + return null; + } + + public Date getNotAfter() + { + return null; + } + + public byte[] getTBSCertificate() + throws CertificateEncodingException + { + throw new CertificateEncodingException(); + } + + public byte[] getSignature() + { + return new byte[0]; + } + + public String getSigAlgName() + { + return null; + } + + public String getSigAlgOID() + { + return null; + } + + public byte[] getSigAlgParams() + { + return new byte[0]; + } + + public boolean[] getIssuerUniqueID() + { + return new boolean[0]; + } + + public boolean[] getSubjectUniqueID() + { + return new boolean[0]; + } + + public boolean[] getKeyUsage() + { + return new boolean[0]; + } + + public int getBasicConstraints() + { + return 0; + } + + public byte[] getEncoded() + throws CertificateEncodingException + { + if (_exceptionOnEncode) + { + throw new CertificateEncodingException(); + } + + return new byte[0]; + } + + public void verify(PublicKey key) + throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException + { + throw new CertificateException(); + } + + public void verify(PublicKey key, String sigProvider) + throws CertificateException, NoSuchAlgorithmException, InvalidKeyException, NoSuchProviderException, SignatureException + { + throw new CertificateException(); + } + + public String toString() + { + return null; + } + + public PublicKey getPublicKey() + { + return null; + } + + public boolean hasUnsupportedCriticalExtension() + { + return false; + } + + public Set getCriticalExtensionOIDs() + { + return null; + } + + public Set getNonCriticalExtensionOIDs() + { + return null; + } + + public byte[] getExtensionValue(String oid) + { + return new byte[0]; + } + + } + + private static byte[] getDigest(SubjectPublicKeyInfo spki) + { + return getDigest(spki.getPublicKeyData().getBytes()); + } + + private static byte[] getDigest(byte[] bytes) + { + Digest digest = new SHA1Digest(); + byte[] resBuf = new byte[digest.getDigestSize()]; + + digest.update(bytes, 0, bytes.length); + digest.doFinal(resBuf, 0); + return resBuf; + } + + private static class AtomicLong + { + private long value; + + public AtomicLong(long value) + { + this.value = value; + } + + public synchronized long getAndIncrement() + { + return value++; + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ThreefishTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ThreefishTest.java new file mode 100644 index 000000000..c8aa6de49 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ThreefishTest.java @@ -0,0 +1,80 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; + +public class ThreefishTest + extends SimpleTest +{ + + private static final byte[] SECRET_KEY_1024 = + { + -15, -32, 56, 110, 22, -42, -26, 34, 25, 17, -83, -2, -78, 112, 49, 127, -4, 70, -110, -21, -10, -114, -82, -122, + 78, 53, -105, -44, 34, 45, -102, -19, -30, 73, 87, 19, 25, -92, -64, -72, 11, 125, -92, -124, -126, -70, -92, 54, + 46, 3, 86, -108, 71, -42, 44, -110, -36, -31, -48, -84, -19, 102, 124, -118, 17, -84, -119, 126, 37, -8, -13, 21, + -4, 86, 104, -85, -44, 82, 60, -61, -95, -9, -92, 68, -123, -111, -53, -36, -47, 36, -92, 121, 95, 25, 73, 124, + -13, -7, -106, -32, 75, -30, -25, -95, 120, 88, 2, 55, 68, -113, -60, 104, 59, 57, -86, -79, -110, -126, -44, + -18, 73, -37, -128, -40, -62, -15, 23, 87 + }; + + private static final byte[] TEST_BYTES = new byte[1536]; + + public String getName() + { + return "Threefish"; + } + + public void performTest() + throws Exception + { + // padding test at 128 pad bytes. + + final SecretKey secretKey = new SecretKeySpec(SECRET_KEY_1024, "Threefish-1024"); + + Cipher cipher = Cipher.getInstance("Threefish-1024/CBC/ISO10126Padding", "BC"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey, new IvParameterSpec(new byte[128])); + + byte[] iv = cipher.getIV(); + byte[] ciphertext = cipher.doFinal(TEST_BYTES); + + cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); + + byte[] cleartext = cipher.doFinal(ciphertext); + + if (!Arrays.areEqual(TEST_BYTES, cleartext)) + { + fail("Invalid cleartext - ISO10126Padding."); + } + + cipher = Cipher.getInstance("Threefish-1024/CBC/PKCS7Padding", "BC"); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + + iv = cipher.getIV(); + ciphertext = cipher.doFinal(TEST_BYTES); + + cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); + + cleartext = cipher.doFinal(ciphertext); + + if (!Arrays.areEqual(TEST_BYTES, cleartext)) + { + fail("Invalid cleartext - PKCS7."); + } + } + + public static void main(final String[] args) + throws Exception + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new ThreefishTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/WrapTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/WrapTest.java new file mode 100644 index 000000000..e8d058c15 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/WrapTest.java @@ -0,0 +1,76 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.Key; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.MessageDigest; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTestResult; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class WrapTest + implements Test +{ + public TestResult perform() + { + try + { + Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding", "BC"); + KeyPairGenerator fact = KeyPairGenerator.getInstance("RSA", "BC"); + fact.initialize(512, new SecureRandom()); + + KeyPair keyPair = fact.generateKeyPair(); + + PrivateKey priKey = keyPair.getPrivate(); + PublicKey pubKey = keyPair.getPublic(); + + KeyGenerator keyGen = KeyGenerator.getInstance("DES", "BC"); + Key wrapKey = keyGen.generateKey(); + cipher.init(Cipher.WRAP_MODE, wrapKey); + byte[] wrappedKey = cipher.wrap(priKey); + + cipher.init(Cipher.UNWRAP_MODE, wrapKey); + Key key = cipher.unwrap(wrappedKey, "RSA", Cipher.PRIVATE_KEY); + + if (!MessageDigest.isEqual(priKey.getEncoded(), key.getEncoded())) + { + return new SimpleTestResult(false, "Unwrapped key does not match"); + } + + return new SimpleTestResult(true, getName() + ": Okay"); + } + catch (Exception e) + { + return new SimpleTestResult(false, getName() + ": exception - " + e.toString(), e); + } + } + + public String getName() + { + return "WrapTest"; + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + Test test = new WrapTest(); + TestResult result = test.perform(); + + System.out.println(result.toString()); + if (result.getException() != null) + { + result.getException().printStackTrace(); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/X509CertificatePairTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/X509CertificatePairTest.java new file mode 100644 index 000000000..8660afd70 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/X509CertificatePairTest.java @@ -0,0 +1,147 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.x509.X509CertificatePair; + +import java.io.ByteArrayInputStream; +import java.security.Security; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; + +public class X509CertificatePairTest + extends SimpleTest +{ + public void performTest() + throws Exception + { + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + + X509Certificate rootCert = (X509Certificate)cf.generateCertificate( + new ByteArrayInputStream(CertPathTest.rootCertBin)); + X509Certificate interCert = (X509Certificate)cf.generateCertificate( + new ByteArrayInputStream(CertPathTest.interCertBin)); + X509Certificate finalCert = (X509Certificate)cf.generateCertificate( + new ByteArrayInputStream(CertPathTest.finalCertBin)); + + + X509CertificatePair pair1 = new X509CertificatePair(rootCert, interCert); + X509CertificatePair pair2 = new X509CertificatePair(rootCert, interCert); + X509CertificatePair pair3 = new X509CertificatePair(interCert, finalCert); + X509CertificatePair pair4 = new X509CertificatePair(rootCert, finalCert); + X509CertificatePair pair5 = new X509CertificatePair(rootCert, null); + X509CertificatePair pair6 = new X509CertificatePair(rootCert, null); + X509CertificatePair pair7 = new X509CertificatePair(null, rootCert); + X509CertificatePair pair8 = new X509CertificatePair(null, rootCert); + + if (!pair1.equals(pair2)) + { + fail("pair1 pair2 equality test"); + } + + if (!pair5.equals(pair6)) + { + fail("pair1 pair2 equality test"); + } + + if (!pair7.equals(pair8)) + { + fail("pair1 pair2 equality test"); + } + + if (pair1.equals(null)) + { + fail("pair1 null equality test"); + } + + if (pair1.hashCode() != pair2.hashCode()) + { + fail("pair1 pair2 hashCode equality test"); + } + + if (pair1.equals(pair3)) + { + fail("pair1 pair3 inequality test"); + } + + if (pair1.equals(pair4)) + { + fail("pair1 pair4 inequality test"); + } + + if (pair1.equals(pair5)) + { + fail("pair1 pair5 inequality test"); + } + + if (pair1.equals(pair7)) + { + fail("pair1 pair7 inequality test"); + } + + if (pair5.equals(pair1)) + { + fail("pair5 pair1 inequality test"); + } + + if (pair7.equals(pair1)) + { + fail("pair7 pair1 inequality test"); + } + + if (pair1.getForward() != rootCert) + { + fail("pair1 forward test"); + } + + if (pair1.getReverse() != interCert) + { + fail("pair1 reverse test"); + } + + if (!areEqual(pair1.getEncoded(), pair2.getEncoded())) + { + fail("encoding check"); + } + + pair4 = new X509CertificatePair(rootCert, TestUtils.createExceptionCertificate(false)); + + try + { + pair4.getEncoded(); + + fail("no exception on bad getEncoded()"); + } + catch (CertificateEncodingException e) + { + // expected + } + + pair4 = new X509CertificatePair(rootCert, TestUtils.createExceptionCertificate(true)); + + try + { + pair4.getEncoded(); + + fail("no exception on exception getEncoded()"); + } + catch (CertificateEncodingException e) + { + // expected + } + } + + public String getName() + { + return "X509CertificatePair"; + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new X509CertificatePairTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/X509LDAPCertStoreTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/X509LDAPCertStoreTest.java new file mode 100644 index 000000000..c0869ee6e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/X509LDAPCertStoreTest.java @@ -0,0 +1,467 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import com.fr.third.org.bouncycastle.jce.PrincipalUtil; +import com.fr.third.org.bouncycastle.jce.X509LDAPCertStoreParameters; +import com.fr.third.org.bouncycastle.jce.X509Principal; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.x509.X509CRLStoreSelector; +import com.fr.third.org.bouncycastle.x509.X509CertStoreSelector; +import com.fr.third.org.bouncycastle.x509.X509Store; + +import java.io.ByteArrayInputStream; +import java.security.Security; +import java.security.cert.CRLException; +import java.security.cert.CertStore; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509CRL; +import java.security.cert.X509CRLSelector; +import java.security.cert.X509CertSelector; +import java.security.cert.X509Certificate; +import java.util.Collection; +import java.util.Collections; +import java.util.Iterator; + +public class X509LDAPCertStoreTest extends SimpleTest +{ + private static final byte cert1[] = Base64 + .decode("MIIDyTCCAzKgAwIBAgIEL64+8zANBgkqhkiG9w0BAQUFADBVMQswCQYDVQQGEwJE" + + "RTEcMBoGA1UEChQTRGV1dHNjaGUgVGVsZWtvbSBBRzEoMAwGBwKCBgEKBxQTATEw" + + "GAYDVQQDFBFUVEMgVGVzdCBDQSAxMTpQTjAeFw0wMzAzMjUxNDM1MzFaFw0wNjAz" + + "MjUxNDM1MzFaMGIxCzAJBgNVBAYTAkRFMRswGQYDVQQKDBJHRlQgU29sdXRpb25z" + + "IEdtYkgxEjAQBgNVBAsMCUhZUEFSQ0hJVjEWMBQGA1UEAwwNRGllZ2UsIFNpbW9u" + + "ZTEKMAgGA1UEBRMBMTCBoDANBgkqhkiG9w0BAQEFAAOBjgAwgYoCgYEAiEYsFbs4" + + "FesQpMjBkzJB92c0p8tJ02nbCNA5l17VVbbrv6/twnQHW4kgA+9lZlXfzI8iunT1" + + "KuiwVupWObHgFaGPkelIN/qIbuwbQzh7T+IUKdKETE12Lc+xk9YvQ6mJVgosmwpr" + + "nMMjezymh8DjPhe7MC7/H3AotrHVNM3mEJcCBEAAAIGjggGWMIIBkjAfBgNVHSME" + + "GDAWgBTQc8wTeltcAM3iTE63fk/wTA+IJTAdBgNVHQ4EFgQUq6ChBvXPiqhMHLS3" + + "kiKpSeGWDz4wDgYDVR0PAQH/BAQDAgQwMB8GA1UdEQQYMBaBFHNpbW9uZS5kaWVn" + + "ZUBnZnQuY29tMIHoBgNVHR8EgeAwgd0wgdqgaqBohjVsZGFwOi8vcGtzbGRhcC50" + + "dHRjLmRlOjM4OS9jPWRlLG89RGV1dHNjaGUgVGVsZWtvbSBBR4YvaHR0cDovL3d3" + + "dy50dHRjLmRlL3RlbGVzZWMvc2VydmxldC9kb3dubG9hZF9jcmyibKRqMGgxCzAJ" + + "BgNVBAYTAkRFMRwwGgYDVQQKFBNEZXV0c2NoZSBUZWxla29tIEFHMTswDAYHAoIG" + + "AQoHFBMBMTArBgNVBAMUJFRlbGVTZWMgRGlyZWN0b3J5IFNlcnZpY2UgU2lnRyAx" + + "MDpQTjA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly93d3cudHR0" + + "Yy5kZS9vY3NwcjANBgkqhkiG9w0BAQUFAAOBgQBCPudAtrP9Bx7GRhHQgYS6kaoN" + + "vYb/yDss86pyn0uiFuwT+mT1popcAfxPo2yxL0jqqlsDNFBC2hJob5rjihsKPmqV" + + "rSaW0VJu/zBihsX7hLKOVMf5gvUYMS5ulq/bp8jOj8a+5SmxVY+WWZVFghWjISse" + + "T3WABdTS9S3zjnQiyg=="); + + private static final byte[] directCRL = Base64 + .decode("MIIGXTCCBckCAQEwCgYGKyQDAwECBQAwdDELMAkGA1UEBhMCREUxHDAaBgNVBAoU" + + "E0RldXRzY2hlIFRlbGVrb20gQUcxFzAVBgNVBAsUDlQtVGVsZVNlYyBUZXN0MS4w" + + "DAYHAoIGAQoHFBMBMTAeBgNVBAMUF1QtVGVsZVNlYyBUZXN0IERJUiA4OlBOFw0w" + + "NjA4MDQwODQ1MTRaFw0wNjA4MDQxNDQ1MTRaMIIElTAVAgQvrj/pFw0wMzA3MjIw" + + "NTQxMjhaMBUCBC+uP+oXDTAzMDcyMjA1NDEyOFowFQIEL64/5xcNMDQwNDA1MTMx" + + "ODE3WjAVAgQvrj/oFw0wNDA0MDUxMzE4MTdaMBUCBC+uP+UXDTAzMDExMzExMTgx" + + "MVowFQIEL64/5hcNMDMwMTEzMTExODExWjAVAgQvrj/jFw0wMzAxMTMxMTI2NTZa" + + "MBUCBC+uP+QXDTAzMDExMzExMjY1NlowFQIEL64/4hcNMDQwNzEzMDc1ODM4WjAV" + + "AgQvrj/eFw0wMzAyMTcwNjMzMjVaMBUCBC+uP98XDTAzMDIxNzA2MzMyNVowFQIE" + + "L64/0xcNMDMwMjE3MDYzMzI1WjAVAgQvrj/dFw0wMzAxMTMxMTI4MTRaMBUCBC+u" + + "P9cXDTAzMDExMzExMjcwN1owFQIEL64/2BcNMDMwMTEzMTEyNzA3WjAVAgQvrj/V" + + "Fw0wMzA0MzAxMjI3NTNaMBUCBC+uP9YXDTAzMDQzMDEyMjc1M1owFQIEL64/xhcN" + + "MDMwMjEyMTM0NTQwWjAVAgQvrj/FFw0wMzAyMTIxMzQ1NDBaMBUCBC+uP8IXDTAz" + + "MDIxMjEzMDkxNlowFQIEL64/wRcNMDMwMjEyMTMwODQwWjAVAgQvrj++Fw0wMzAy" + + "MTcwNjM3MjVaMBUCBC+uP70XDTAzMDIxNzA2MzcyNVowFQIEL64/sBcNMDMwMjEy" + + "MTMwODU5WjAVAgQvrj+vFw0wMzAyMTcwNjM3MjVaMBUCBC+uP5MXDTAzMDQxMDA1" + + "MjYyOFowFQIEL64/khcNMDMwNDEwMDUyNjI4WjAVAgQvrj8/Fw0wMzAyMjYxMTA0" + + "NDRaMBUCBC+uPz4XDTAzMDIyNjExMDQ0NFowFQIEL64+zRcNMDMwNTIwMDUyNzM2" + + "WjAVAgQvrj7MFw0wMzA1MjAwNTI3MzZaMBUCBC+uPjwXDTAzMDYxNzEwMzQxNlow" + + "FQIEL64+OxcNMDMwNjE3MTAzNDE2WjAVAgQvrj46Fw0wMzA2MTcxMDM0MTZaMBUC" + + "BC+uPjkXDTAzMDYxNzEzMDEwMFowFQIEL64+OBcNMDMwNjE3MTMwMTAwWjAVAgQv" + + "rj43Fw0wMzA2MTcxMzAxMDBaMBUCBC+uPjYXDTAzMDYxNzEzMDEwMFowFQIEL64+" + + "MxcNMDMwNjE3MTAzNzQ5WjAVAgQvrj4xFw0wMzA2MTcxMDQyNThaMBUCBC+uPjAX" + + "DTAzMDYxNzEwNDI1OFowFQIEL649qRcNMDMxMDIyMTEzMjI0WjAVAgQvrjyyFw0w" + + "NTAzMTEwNjQ0MjRaMBUCBC+uPKsXDTA0MDQwMjA3NTQ1M1owFQIEL6466BcNMDUw" + + "MTI3MTIwMzI0WjAVAgQvrjq+Fw0wNTAyMTYwNzU3MTZaMBUCBC+uOqcXDTA1MDMx" + + "MDA1NTkzNVowFQIEL646PBcNMDUwNTExMTA0OTQ2WjAVAgQvrG3VFw0wNTExMTEx" + + "MDAzMjFaMBUCBC+uLmgXDTA2MDEyMzEwMjU1NVowFQIEL64mxxcNMDYwODAxMDk0" + + "ODQ0WqCBijCBhzALBgNVHRQEBAICEQwwHwYDVR0jBBgwFoAUA1vI26YMj3njkfCU" + + "IXbo244kLjkwVwYDVR0SBFAwToZMbGRhcDovL3Brc2xkYXAudHR0Yy5kZS9vdT1U" + + "LVRlbGVTZWMgVGVzdCBESVIgODpQTixvPURldXRzY2hlIFRlbGVrb20gQUcsYz1k" + + "ZTAKBgYrJAMDAQIFAAOBgQArj4eMlbAwuA2aS5O4UUUHQMKKdK/dtZi60+LJMiMY" + + "ojrMIf4+ZCkgm1Ca0Cd5T15MJxVHhh167Ehn/Hd48pdnAP6Dfz/6LeqkIHGWMHR+" + + "z6TXpwWB+P4BdUec1ztz04LypsznrHcLRa91ixg9TZCb1MrOG+InNhleRs1ImXk8" + + "MQ=="); + + private static final String ldapURL1 = "ldap://pksldap.tttc.de:389"; + + private static final X509LDAPCertStoreParameters params1 = new X509LDAPCertStoreParameters.Builder( + ldapURL1, "o=Deutsche Telekom AG, c=DE"). + setAACertificateSubjectAttributeName("ou cn"). + setAttributeAuthorityRevocationListIssuerAttributeName("cn"). + setAttributeCertificateAttributeSubjectAttributeName("cn"). + setAttributeCertificateRevocationListIssuerAttributeName("cn"). + setAttributeDescriptorCertificateSubjectAttributeName("ou cn"). + setAuthorityRevocationListIssuerAttributeName("cn"). + setCACertificateSubjectAttributeName("ou cn"). + setCertificateRevocationListIssuerAttributeName("cn"). + setCrossCertificateSubjectAttributeName("cn"). + setDeltaRevocationListIssuerAttributeName("cn"). + setSearchForSerialNumberIn("cn") + .build(); + + private static final String ldapURL2 = "ldap://directory.d-trust.de:389"; + + private static final X509LDAPCertStoreParameters params2 = new X509LDAPCertStoreParameters.Builder( + ldapURL2, "o=D-Trust GmbH, c=DE"). + setAACertificateSubjectAttributeName("cn o"). + setAttributeAuthorityRevocationListIssuerAttributeName("cn"). + setAttributeCertificateAttributeSubjectAttributeName("cn"). + setAttributeCertificateRevocationListIssuerAttributeName("cn"). + setAttributeDescriptorCertificateSubjectAttributeName("cn o"). + setAuthorityRevocationListIssuerAttributeName("cn"). + setCACertificateSubjectAttributeName("cn o"). + setCertificateRevocationListIssuerAttributeName("cn"). + setCrossCertificateSubjectAttributeName("cn o"). + setDeltaRevocationListIssuerAttributeName("cn"). + setSearchForSerialNumberIn("uid") + .build(); + + private static final byte[] cert2 = Base64 + .decode("MIIEADCCAuigAwIBAgIDAJ/QMA0GCSqGSIb3DQEBBQUAMD8xCzAJBgNVBAYTAkRF" + + "MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxGTAXBgNVBAMMEEQtVFJVU1QgRGVtbyBD" + + "QTEwHhcNMDYwMzAyMTYxNTU3WhcNMDgwMzEyMTYxNTU3WjB+MQswCQYDVQQGEwJE" + + "RTEUMBIGA1UECgwLTXVzdGVyIEdtYkgxFzAVBgNVBAMMDk1heCBNdXN0ZXJtYW5u" + + "MRMwEQYDVQQEDApNdXN0ZXJtYW5uMQwwCgYDVQQqDANNYXgxHTAbBgNVBAUTFERU" + + "UldFMTQxMjk5NDU1MTgwMTIxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC" + + "AQEAjLDFeviSZDEZgLzTdptU4biPgNV7SvLqsNholfqkyQm2r5WSghGZSjhKYIne" + + "qKmZ08W59a51bGqDEsifYR7Tw9JC/AhH19fyK01+1ZAXHalgVthaRtLw31lcoTVJ" + + "R7j9fvrnW0sMPVP4m5gePb3P5/pYHVmN1MjdPIm38us5aJOytOO5Li2IwQIG0t4M" + + "bEC6/1horBR5TgRl7ACamrdaPHOvO1QVweOqYU7uVxLgDTK4mSV6heyrisFMfkbj" + + "7jT/c44kXM7dtgNcmESINudu6bnqaB1CxOFTJ/Jzv81R5lf7pBX2LOG1Bu94Yw2x" + + "cHUVROs2UWY8kQrNUozsBHzQ0QIDAKq5o4HFMIHCMBMGA1UdIwQMMAqACEITKrPL" + + "WuYiMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEFBQcwAYYXaHR0cDovL29jc3AuZC10" + + "cnVzdC5uZXQwEAYDVR0gBAkwBzAFBgMqAwQwEQYDVR0OBAoECEvE8bXFHkFLMA4G" + + "A1UdDwEB/wQEAwIGQDAPBgUrJAgDCAQGDARUZXN0MB8GA1UdEQQYMBaBFG0ubXVz" + + "dGVybWFubkB0ZXN0LmRlMA8GBSskCAMPBAYMBFRlc3QwDQYJKoZIhvcNAQEFBQAD" + + "ggEBADD/X+UZZN30nCBDzJ7MtmgwvMBVDAU6HkPlzfyn9pxIKFrq3uR9wcY2pedM" + + "yQQk0NpTDCIhAYIjAHysMue0ViQnW5qq8uUCFn0+fsgMqqTQNRmE4NIqUrnYO40g" + + "WjcepCEApkTqGf3RFaDMf9zpRvj9qUx18De+V0GC22uD2vPKpqRcvS2dSw6pHBW2" + + "NwEU+RgNhoPXrHt332PEYdwO0zOL7eSLBD9AmkpP2uDjpMQ02Lu9kXG6OOfanwfS" + + "jHioCvDXyl5pwSHwrHNWQRb5dLF12Fg41LMapDwR7awAKE9h6qHBonvCMBPMvqrr" + + "NktqQcoQkluR9MItONJI5XHADtU="); + + private static final String ldapURL3 = "ldap://dir.signtrust.de:389"; + + private static final X509LDAPCertStoreParameters params3 = new X509LDAPCertStoreParameters.Builder( + ldapURL3, "o=Deutsche Post AG, c=de"). + setAACertificateSubjectAttributeName("ou"). + setAttributeAuthorityRevocationListIssuerAttributeName("cn"). + setAttributeCertificateAttributeSubjectAttributeName("cn"). + setAttributeCertificateRevocationListIssuerAttributeName("o"). + setAttributeDescriptorCertificateSubjectAttributeName("ou"). + setAuthorityRevocationListIssuerAttributeName("o"). + setCACertificateSubjectAttributeName("ou"). + setCertificateRevocationListIssuerAttributeName("o"). + setCrossCertificateSubjectAttributeName("o"). + setDeltaRevocationListIssuerAttributeName("o"). + setSearchForSerialNumberIn("serialNumber") + .build(); + + private static final byte[] cert3 = Base64 + .decode("MIICwDCCAimgAwIBAgIBKzANBgkqhkiG9w0BAQUFADA6MRAwDgYDVQQDEwdQQ0Ex" + + "OlBOMRkwFwYDVQQKExBEZXV0c2NoZSBQb3N0IEFHMQswCQYDVQQGEwJERTAeFw0w" + + "MDA0MTkyMjAwMDBaFw0wMzA0MTkyMjAwMDBaMIGOMRAwDgYDVQQEFAdN5G5jaGVy" + + "MQ4wDAYDVQQqEwVLbGF1czEWMBQGA1UEAxQNS2xhdXMgTeRuY2hlcjEVMBMGA1UE" + + "CRMMV2llc2Vuc3RyLiAzMQ4wDAYDVQQREwU2MzMyOTESMBAGA1UEBxMJRWdlbHNi" + + "YWNoMQswCQYDVQQGEwJERTEKMAgGA1UEBRMBMTCBnzANBgkqhkiG9w0BAQEFAAOB" + + "jQAwgYkCgYEAn7z6Ba9wpv/mNBIaricY/d0KpxGpqGAXdqKlvqkk/seJEoBLvmL7" + + "wZz88RPELQqzDhc4oXYohS2dh3NHus9FpSPMq0JzKAcE3ArrVDxwtXtlcwN2v7iS" + + "TcHurgLOb9C/r8JdsMHNgwHMkkdp96cJk/sioyP5sLPYmgWxg1JH0vMCAwEAAaOB" + + "gDB+MAwGA1UdEwEB/wQCMAAwDwYDVR0PAQH/BAUDAwfAADBKBgNVHSMEQzBBoTyk" + + "OjEQMA4GA1UEAxMHUENBMTpQTjEZMBcGA1UEChMQRGV1dHNjaGUgUG9zdCBBRzEL" + + "MAkGA1UEBhMCREWCAQEwEQYDVR0OBAoECEAeJ6R3USjxMA0GCSqGSIb3DQEBBQUA" + + "A4GBADMRtdiQJF2fg7IcedTjnAW+QGl/wNSKy7A4oaBQeahcruo+hzH+ZU+DsiSu" + + "TJZaf2X1eUUEPmV+5zZlopGa3HvFfgmIYIXBw9ZO3Qb/HWGsPNgW0yg5eXEGwNEt" + + "vV85BTMGuMjiuDw841IuAZaMKqOKnVXHmd2pLJz7Wv0MLJhw"); + + private static final byte[] caCert3 = Base64 + .decode("MIICUjCCAb6gAwIBAgIDD2ptMAoGBiskAwMBAgUAMG8xCzAJBgNVBAYTAkRFMT0w" + + "OwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0" + + "aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjRSLUNBIDE6UE4w" + + "IhgPMjAwMDA0MTIwODIyMDNaGA8yMDA0MDQxMjA4MjIwM1owWzELMAkGA1UEBhMC" + + "REUxGTAXBgNVBAoUEERldXRzY2hlIFBvc3QgQUcxMTAMBgcCggYBCgcUEwExMCEG" + + "A1UEAxQaQ0EgREVSIERFVVRTQ0hFTiBQT1NUIDU6UE4wgZ8wDQYJKoZIhvcNAQEB" + + "BQADgY0AMIGJAoGBAIH3c+gig1KkY5ceR6n/AMq+xz7hi3f0PMdpwIe2v2w6Hu5k" + + "jipe++NvU3r6wakIY2royHl3gKWrExOisBico9aQmn8lMJnWZ7SUbB+WpRn0mAWN" + + "ZM9YT+/U5hRCffeeuLWClzrbScaWnAeaaI0G+N/QKnSSjrV/l64jogyADWCTAgMB" + + "AAGjEjAQMA4GA1UdDwEB/wQEAwIBBjAKBgYrJAMDAQIFAAOBgQAaV5WClEneXk9s" + + "LO8zTQAsf4KvDaLd1BFcFeYM7kLLRHKeWQ0MAd0xkuAMme5NVwWNpNZP74B4HX7Q" + + "/Q0h/wo/9LTgQaxw52lLs4Ml0HUyJbSFjoQ+sqgjg2fGNGw7aGkVNY5dQTAy8oSv" + + "iG8mxTsQ7Fxaush3cIB0qDDwXar/hg=="); + + private static final byte[] crossCert3 = Base64 + .decode("MIICVDCCAcCgAwIBAgIDDIOsMAoGBiskAwMBAgUAMG8xCzAJBgNVBAYTAkRFMT0w" + + "OwYDVQQKFDRSZWd1bGllcnVuZ3NiZWjIb3JkZSBmyHVyIFRlbGVrb21tdW5pa2F0" + + "aW9uIHVuZCBQb3N0MSEwDAYHAoIGAQoHFBMBMTARBgNVBAMUCjRSLUNBIDE6UE4w" + + "IhgPMjAwMDAzMjIwOTQzNTBaGA8yMDA0MDEyMTE2MDQ1M1owbzELMAkGA1UEBhMC" + + "REUxPTA7BgNVBAoUNFJlZ3VsaWVydW5nc2JlaMhvcmRlIGbIdXIgVGVsZWtvbW11" + + "bmlrYXRpb24gdW5kIFBvc3QxITAMBgcCggYBCgcUEwExMBEGA1UEAxQKNVItQ0Eg" + + "MTpQTjCBoTANBgkqhkiG9w0BAQEFAAOBjwAwgYsCgYEAih5BUycfBpqKhU8RDsaS" + + "vV5AtzWeXQRColL9CH3t0DKnhjKAlJ8iccFtJNv+d3bh8bb9sh0maRSo647xP7hs" + + "HTjKgTE4zM5BYNfXvST79OtcMgAzrnDiGjQIIWv8xbfV1MqxxdtZJygrwzRMb9jG" + + "CAGoJEymoyzAMNG7tSdBWnUCBQDAAAABMAoGBiskAwMBAgUAA4GBAIBWrl6aEy4d" + + "2d6U/924YK8Tv9oChmaKVhklkiTzcKv1N8dhLnLTibq4/stop03CY3rKU4X5aTfu" + + "0J77FIV1Poy9jLT5Tm1NBpi71m4uO3AUoSeyhJXGQGsYFjAc3URqkznbTL/nr9re" + + "IoBhf6u9cX+idnN6Uy1q+j/LOrcy3zgj"); + + public void performTest() throws Exception + { + certStoretest(); + x509StoreTest(); + } + + private void certStoretest() throws Exception + { + CertStore cs = CertStore.getInstance("X509LDAP", params1, "BC"); + X509CertSelector sl = new X509CertSelector(); + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + X509Certificate xcert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream(cert1)); + sl.setCertificate(xcert); + Collection coll = cs.getCertificates(sl); + if (coll.isEmpty() || !coll.iterator().next().equals(xcert)) + { + fail("certificate could not be picked from LDAP directory."); + } + + // System.out.println(coll.toArray()[0]); + + sl.setCertificate(null); + sl.setSubject(getSubject(xcert).getEncoded()); + coll = cs.getCertificates(sl); + if (coll.isEmpty() || !coll.iterator().next().equals(xcert)) + { + fail("certificate could not be picked from LDAP directory."); + } + X509CRLSelector sl2 = new X509CRLSelector(); + X509CRL crl = (X509CRL)cf.generateCRL(new + ByteArrayInputStream(directCRL)); + sl2.addIssuerName(getCRLIssuer(crl).getEncoded()); + coll = cs.getCRLs(sl2); + if (!coll.iterator().hasNext()) + { + fail("CRL could not be picked from LDAP directory."); + } + // System.out.println(coll.toArray()[0]); + + cs = CertStore.getInstance("X509LDAP", params2, "BC"); + sl = new X509CertSelector(); + xcert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream(cert2)); + sl.setCertificate(xcert); + coll = cs.getCertificates(sl); + if (coll.isEmpty() || !coll.iterator().next().equals(xcert)) + { + fail("Certificate could not be picked from LDAP directory."); + } + + // System.out.println(coll.toArray()[0]); + + cs = CertStore.getInstance("X509LDAP", params3, "BC"); + sl = new X509CertSelector(); + xcert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream(cert3)); + sl.setCertificate(xcert); + coll = cs.getCertificates(sl); + if (coll.isEmpty() || !coll.iterator().next().equals(xcert)) + { + fail("Certificate could not be picked from LDAP directory."); + } + + // System.out.println(coll.toArray()[0]); + + xcert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream(caCert3)); + sl = new X509CertSelector(); + sl.setSubject(getSubject(xcert).getEncoded()); + coll = cs.getCertificates(sl); + boolean found = false; + if (coll.isEmpty()) + { + fail("Certificate could not be picked from LDAP directory."); + } + + for (Iterator it = coll.iterator(); it.hasNext();) + { + if (it.next().equals(xcert)) + { + found = true; + break; + } + } + if (!found) + { + fail("Certificate could not be picked from LDAP directory."); + } + + // System.out.println(coll.toArray()[0]); + + sl = new X509CertSelector(); + xcert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream(crossCert3)); + sl = new X509CertSelector(); + sl.setSubject(getSubject(xcert).getEncoded()); + coll = cs.getCertificates(sl); + if (coll.isEmpty()) + { + fail("Cross certificate pair could not be picked from LDAP directory."); + } + found = false; + for (Iterator it = coll.iterator(); it.hasNext();) + { + if (it.next().equals(xcert)) + { + found = true; + break; + } + } + if (!found) + { + fail("Cross certificate pair could not be picked from LDAP directory."); + } + + // System.out.println(coll.toArray()[0]); + } + + private void x509StoreTest() throws Exception + { + X509Store cs = X509Store.getInstance("CERTIFICATE/LDAP", params1, "BC"); + + X509CertStoreSelector sl = new X509CertStoreSelector(); + CertificateFactory cf = CertificateFactory.getInstance("X.509", "BC"); + X509Certificate xcert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream(cert1)); + sl.setCertificate(xcert); + Collection coll = cs.getMatches(sl); + if (coll.isEmpty() || !coll.iterator().next().equals(xcert)) + { + fail("certificate could not be picked from LDAP directory."); + } + + // System.out.println(coll.toArray()[0]); + + sl.setCertificate(null); + sl.setSubject(getSubject(xcert).getEncoded()); + coll = cs.getMatches(sl); + if (coll.isEmpty() || !coll.iterator().next().equals(xcert)) + { + fail("certificate could not be picked from LDAP directory."); + } + X509CRLStoreSelector sl2 = new X509CRLStoreSelector(); + X509CRL crl = (X509CRL)cf.generateCRL(new + ByteArrayInputStream(directCRL)); + sl2.setIssuers(Collections.singleton(crl.getIssuerX500Principal())); + cs = X509Store.getInstance("CRL/LDAP", params1, "BC"); + coll = cs.getMatches(sl2); + if (!coll.iterator().hasNext()) + { + fail("CRL could not be picked from LDAP directory."); + } + // System.out.println(coll.toArray()[0]); + + cs = X509Store.getInstance("CERTIFICATE/LDAP", params2, "BC"); + sl = new X509CertStoreSelector(); + xcert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream(cert2)); + sl.setCertificate(xcert); + coll = cs.getMatches(sl); + if (coll.isEmpty() || !coll.iterator().next().equals(xcert)) + { + fail("Certificate could not be picked from LDAP directory."); + } + + // System.out.println(coll.toArray()[0]); + + cs = X509Store.getInstance("CERTIFICATE/LDAP", params3, "BC"); + sl = new X509CertStoreSelector(); + xcert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream(cert3)); + sl.setCertificate(xcert); + coll = cs.getMatches(sl); + if (coll.isEmpty() || !coll.iterator().next().equals(xcert)) + { + fail("Certificate could not be picked from LDAP directory."); + } + + // System.out.println(coll.toArray()[0]); + + xcert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream(caCert3)); + sl = new X509CertStoreSelector(); + sl.setSubject(getSubject(xcert).getEncoded()); + coll = cs.getMatches(sl); + boolean found = false; + if (coll.isEmpty()) + { + fail("Certificate could not be picked from LDAP directory."); + } + + for (Iterator it = coll.iterator(); it.hasNext();) + { + if (it.next().equals(xcert)) + { + found = true; + break; + } + } + if (!found) + { + fail("Certificate could not be picked from LDAP directory."); + } + + // System.out.println(coll.toArray()[0]); + + sl = new X509CertStoreSelector(); + xcert = (X509Certificate)cf + .generateCertificate(new ByteArrayInputStream(crossCert3)); + sl.setSubject(getSubject(xcert).getEncoded()); + coll = cs.getMatches(sl); + if (coll.isEmpty()) + { + fail("Cross certificate pair could not be picked from LDAP directory."); + } + found = false; + for (Iterator it = coll.iterator(); it.hasNext();) + { + if (it.next().equals(xcert)) + { + found = true; + break; + } + } + if (!found) + { + fail("Cross certificate pair could not be picked from LDAP directory."); + } + + // System.out.println(coll.toArray()[0]); + + } + + private X509Principal getSubject(X509Certificate cert) + throws CertificateEncodingException + { + return PrincipalUtil.getSubjectX509Principal(cert); + } + + private X509Principal getCRLIssuer(X509CRL crl) + throws CRLException + { + return PrincipalUtil.getIssuerX509Principal(crl); + } + + public String getName() + { + return "LDAPCertStoreTest"; + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + runTest(new X509LDAPCertStoreTest()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/X509StreamParserTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/X509StreamParserTest.java new file mode 100644 index 000000000..ea0d8d0b0 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/X509StreamParserTest.java @@ -0,0 +1,360 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; +import com.fr.third.org.bouncycastle.asn1.ASN1InputStream; +import com.fr.third.org.bouncycastle.asn1.DERSet; +import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; +import com.fr.third.org.bouncycastle.asn1.cms.CMSObjectIdentifiers; +import com.fr.third.org.bouncycastle.asn1.cms.ContentInfo; +import com.fr.third.org.bouncycastle.asn1.cms.SignedData; +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.encoders.Base64; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.x509.X509AttributeCertificate; +import com.fr.third.org.bouncycastle.x509.X509CertificatePair; +import com.fr.third.org.bouncycastle.x509.X509StreamParser; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.security.Security; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.Collection; + +public class X509StreamParserTest + extends SimpleTest +{ + byte[] attrCert = Base64.decode( + "MIIHQDCCBqkCAQEwgZChgY2kgYowgYcxHDAaBgkqhkiG9w0BCQEWDW1sb3JjaEB2" + + "dC5lZHUxHjAcBgNVBAMTFU1hcmt1cyBMb3JjaCAobWxvcmNoKTEbMBkGA1UECxMS" + + "VmlyZ2luaWEgVGVjaCBVc2VyMRAwDgYDVQQLEwdDbGFzcyAyMQswCQYDVQQKEwJ2" + + "dDELMAkGA1UEBhMCVVMwgYmkgYYwgYMxGzAZBgkqhkiG9w0BCQEWDHNzaGFoQHZ0" + + "LmVkdTEbMBkGA1UEAxMSU3VtaXQgU2hhaCAoc3NoYWgpMRswGQYDVQQLExJWaXJn" + + "aW5pYSBUZWNoIFVzZXIxEDAOBgNVBAsTB0NsYXNzIDExCzAJBgNVBAoTAnZ0MQsw" + + "CQYDVQQGEwJVUzANBgkqhkiG9w0BAQQFAAIBBTAiGA8yMDAzMDcxODE2MDgwMloY" + + "DzIwMDMwNzI1MTYwODAyWjCCBU0wggVJBgorBgEEAbRoCAEBMYIFORaCBTU8UnVs" + + "ZSBSdWxlSWQ9IkZpbGUtUHJpdmlsZWdlLVJ1bGUiIEVmZmVjdD0iUGVybWl0Ij4K" + + "IDxUYXJnZXQ+CiAgPFN1YmplY3RzPgogICA8U3ViamVjdD4KICAgIDxTdWJqZWN0" + + "TWF0Y2ggTWF0Y2hJZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5j" + + "dGlvbjpzdHJpbmctZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlw" + + "ZT0iaHR0cDovL3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjc3RyaW5nIj4KICAg" + + "ICAgIENOPU1hcmt1cyBMb3JjaDwvQXR0cmlidXRlVmFsdWU+CiAgICAgPFN1Ympl" + + "Y3RBdHRyaWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFt" + + "ZXM6dGM6eGFjbWw6MS4wOnN1YmplY3Q6c3ViamVjdC1pZCIgRGF0YVR5cGU9Imh0" + + "dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hI3N0cmluZyIgLz4gCiAgICA8" + + "L1N1YmplY3RNYXRjaD4KICAgPC9TdWJqZWN0PgogIDwvU3ViamVjdHM+CiAgPFJl" + + "c291cmNlcz4KICAgPFJlc291cmNlPgogICAgPFJlc291cmNlTWF0Y2ggTWF0Y2hJ" + + "ZD0idXJuOm9hc2lzOm5hbWVzOnRjOnhhY21sOjEuMDpmdW5jdGlvbjpzdHJpbmct" + + "ZXF1YWwiPgogICAgIDxBdHRyaWJ1dGVWYWx1ZSBEYXRhVHlwZT0iaHR0cDovL3d3" + + "dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIj4KICAgICAgaHR0cDovL3p1" + + "bmkuY3MudnQuZWR1PC9BdHRyaWJ1dGVWYWx1ZT4KICAgICA8UmVzb3VyY2VBdHRy" + + "aWJ1dGVEZXNpZ25hdG9yIEF0dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6" + + "eGFjbWw6MS4wOnJlc291cmNlOnJlc291cmNlLWlkIiBEYXRhVHlwZT0iaHR0cDov" + + "L3d3dy53My5vcmcvMjAwMS9YTUxTY2hlbWEjYW55VVJJIiAvPiAKICAgIDwvUmVz" + + "b3VyY2VNYXRjaD4KICAgPC9SZXNvdXJjZT4KICA8L1Jlc291cmNlcz4KICA8QWN0" + + "aW9ucz4KICAgPEFjdGlvbj4KICAgIDxBY3Rpb25NYXRjaCBNYXRjaElkPSJ1cm46" + + "b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmZ1bmN0aW9uOnN0cmluZy1lcXVhbCI+" + + "CiAgICAgPEF0dHJpYnV0ZVZhbHVlIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9y" + + "Zy8yMDAxL1hNTFNjaGVtYSNzdHJpbmciPgpEZWxlZ2F0ZSBBY2Nlc3MgICAgIDwv" + + "QXR0cmlidXRlVmFsdWU+CgkgIDxBY3Rpb25BdHRyaWJ1dGVEZXNpZ25hdG9yIEF0" + + "dHJpYnV0ZUlkPSJ1cm46b2FzaXM6bmFtZXM6dGM6eGFjbWw6MS4wOmFjdGlvbjph" + + "Y3Rpb24taWQiIERhdGFUeXBlPSJodHRwOi8vd3d3LnczLm9yZy8yMDAxL1hNTFNj" + + "aGVtYSNzdHJpbmciIC8+IAogICAgPC9BY3Rpb25NYXRjaD4KICAgPC9BY3Rpb24+" + + "CiAgPC9BY3Rpb25zPgogPC9UYXJnZXQ+CjwvUnVsZT4KMA0GCSqGSIb3DQEBBAUA" + + "A4GBAGiJSM48XsY90HlYxGmGVSmNR6ZW2As+bot3KAfiCIkUIOAqhcphBS23egTr" + + "6asYwy151HshbPNYz+Cgeqs45KkVzh7bL/0e1r8sDVIaaGIkjHK3CqBABnfSayr3" + + "Rd1yBoDdEv8Qb+3eEPH6ab9021AsLEnJ6LWTmybbOpMNZ3tv"); + + public void performTest() + throws Exception + { + X509StreamParser parser = X509StreamParser.getInstance("Certificate", "BC"); + + parser.init(new ByteArrayInputStream(CertPathTest.rootCertBin)); + X509Certificate rootCert = (X509Certificate)parser.read(); + + parser = X509StreamParser.getInstance("CRL", "BC"); + + parser.init(new ByteArrayInputStream(CertPathTest.rootCrlBin)); + + + X509CRL rootCrl = (X509CRL)parser.read(); + + parser = X509StreamParser.getInstance("AttributeCertificate", "BC"); + + parser.init(new ByteArrayInputStream(attrCert)); + + X509AttributeCertificate aCert = (X509AttributeCertificate)parser.read(); + + ByteArrayOutputStream bOut = new ByteArrayOutputStream(); + + bOut.write(CertPathTest.rootCertBin); + bOut.write(CertPathTest.interCertBin); + bOut.write(CertPathTest.finalCertBin); + + parser = X509StreamParser.getInstance("Certificate", "BC"); + + parser.init(bOut.toByteArray()); + + Collection res = parser.readAll(); + + if (res.size() != 3) + { + fail("wrong number of certificates found"); + } + + bOut = new ByteArrayOutputStream(); + + bOut.write(CertPathTest.rootCrlBin); + bOut.write(CertPathTest.interCrlBin); + + parser = X509StreamParser.getInstance("CRL", "BC"); + + parser.init(bOut.toByteArray()); + + res = parser.readAll(); + + if (res.size() != 2) + { + fail("wrong number of CRLs found"); + } + + bOut = new ByteArrayOutputStream(); + + bOut.write(attrCert); + bOut.write(attrCert); + + parser = X509StreamParser.getInstance("AttributeCertificate", "BC"); + + parser.init(bOut.toByteArray()); + + res = parser.readAll(); + + if (res.size() != 2) + { + fail("wrong number of Attribute Certificates found"); + } + + // + // PEM tests + // + parser = X509StreamParser.getInstance("Certificate", "BC"); + + parser.init(PEMData.CERTIFICATE_1.getBytes("US-ASCII")); + + res = parser.readAll(); + + if (res.size() != 1) + { + fail("wrong number of Certificates found"); + } + + parser = X509StreamParser.getInstance("Certificate", "BC"); + + parser.init(PEMData.CERTIFICATE_2.getBytes("US-ASCII")); + + res = parser.readAll(); + + if (res.size() != 1) + { + fail("wrong number of Certificates found"); + } + + parser = X509StreamParser.getInstance("CRL", "BC"); + + parser.init(PEMData.CRL_1.getBytes("US-ASCII")); + + res = parser.readAll(); + + if (res.size() != 1) + { + fail("wrong number of CRLs found"); + } + + parser = X509StreamParser.getInstance("CRL", "BC"); + + parser.init(PEMData.CRL_2.getBytes("US-ASCII")); + + res = parser.readAll(); + + if (res.size() != 1) + { + fail("wrong number of CRLs found"); + } + + parser = X509StreamParser.getInstance("AttributeCertificate", "BC"); + + parser.init(PEMData.ATTRIBUTE_CERTIFICATE_1.getBytes("US-ASCII")); + + res = parser.readAll(); + + if (res.size() != 1) + { + fail("wrong number of Attribute Certificates found"); + } + + parser = X509StreamParser.getInstance("AttributeCertificate", "BC"); + + parser.init(PEMData.ATTRIBUTE_CERTIFICATE_2.getBytes("US-ASCII")); + + res = parser.readAll(); + + if (res.size() != 1) + { + fail("wrong number of Attribute Certificates found"); + } + + ASN1EncodableVector certs = new ASN1EncodableVector(); + + certs.add(new ASN1InputStream(CertPathTest.rootCertBin).readObject()); + certs.add(new DERTaggedObject(false, 2, new ASN1InputStream(attrCert).readObject())); + + ASN1EncodableVector crls = new ASN1EncodableVector(); + + crls.add(new ASN1InputStream(CertPathTest.rootCrlBin).readObject()); + + // + // cross certificate pairs + // + parser = X509StreamParser.getInstance("CertificatePair", "BC"); + + parser.init(new X509CertificatePair(rootCert, rootCert).getEncoded()); + + res = parser.readAll(); + + if (res.size() != 1) + { + fail("wrong number of CertificatePairs found"); + } + + // + // PKCS7 + // + SignedData sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(certs), new DERSet(crls), new DERSet()); + + ContentInfo info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData); + + parser = X509StreamParser.getInstance("Certificate", "BC"); + + parser.init(info.getEncoded()); + + res = parser.readAll(); + + if (res.size() != 1) + { + fail("wrong number of Certificates found"); + } + + parser = X509StreamParser.getInstance("CRL", "BC"); + + parser.init(info.getEncoded()); + + res = parser.readAll(); + + if (res.size() != 1) + { + fail("wrong number of CRLs found"); + } + + parser = X509StreamParser.getInstance("AttributeCertificate", "BC"); + + parser.init(info.getEncoded()); + + res = parser.readAll(); + + if (res.size() != 1) + { + fail("wrong number of Attribute Certificates found"); + } + + // data with no certificates or CRLs + + sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), new DERSet(), new DERSet(), new DERSet()); + + info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData); + + parser = X509StreamParser.getInstance("Certificate", "BC"); + + parser.init(info.getEncoded()); + + res = parser.readAll(); + + if (res.size() != 0) + { + fail("wrong number of Certificates found - expected 0"); + } + + parser = X509StreamParser.getInstance("CRL", "BC"); + + parser.init(info.getEncoded()); + + res = parser.readAll(); + + if (res.size() != 0) + { + fail("wrong number of CRLs found - expected 0"); + } + + parser = X509StreamParser.getInstance("AttributeCertificate", "BC"); + + parser.init(info.getEncoded()); + + res = parser.readAll(); + + if (res.size() != 0) + { + fail("wrong number of Attribute Certificates found - expected 0"); + } + + // data with absent certificates and CRLs + sigData = new SignedData(new DERSet(), new ContentInfo(CMSObjectIdentifiers.data, null), null, null, new DERSet()); + + info = new ContentInfo(CMSObjectIdentifiers.signedData, sigData); + + parser = X509StreamParser.getInstance("Certificate", "BC"); + + parser.init(info.getEncoded()); + + res = parser.readAll(); + + if (res.size() != 0) + { + fail("wrong number of Certificates found - expected 0"); + } + + parser = X509StreamParser.getInstance("CRL", "BC"); + + parser.init(info.getEncoded()); + + res = parser.readAll(); + + if (res.size() != 0) + { + fail("wrong number of CRLs found - expected 0"); + } + + parser = X509StreamParser.getInstance("AttributeCertificate", "BC"); + + parser.init(info.getEncoded()); + + res = parser.readAll(); + + if (res.size() != 0) + { + fail("wrong number of Attribute Certificates found - expected 0"); + } + } + + public String getName() + { + return "X509StreamParser"; + } + + public static void main(String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + runTest(new X509StreamParserTest()); + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ZucTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ZucTest.java new file mode 100644 index 000000000..8a10e102e --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/ZucTest.java @@ -0,0 +1,296 @@ +package com.fr.third.org.bouncycastle.jce.provider.test; + +import java.security.AlgorithmParameters; +import java.security.Security; + +import javax.crypto.Cipher; +import javax.crypto.KeyGenerator; +import javax.crypto.Mac; +import javax.crypto.SecretKey; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.jce.provider.BouncyCastleProvider; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; +import com.fr.third.org.bouncycastle.util.encoders.Hex; +import com.fr.third.org.bouncycastle.util.test.SimpleTest; +import com.fr.third.org.bouncycastle.util.test.Test; +import com.fr.third.org.bouncycastle.util.test.TestResult; + +public class ZucTest + extends SimpleTest +{ + private static final String KEY128_1 = + "00000000000000000000000000000000"; + private static final String KEY128_2 = + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + private static final String KEY256_1 = + "00000000000000000000000000000000" + + "00000000000000000000000000000000"; + private static final String KEY256_2 = + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" + + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + + private static final String IV128_1 = "00000000000000000000000000000000"; + private static final String IV128_2 = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"; + private static final String IV200_1 = "00000000000000000000000000000000000000000000000000"; + private static final String IV200_2 = "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF3F3F3F3F3F3F3F3F"; + + private final TestCase ZUC128_TEST1 = new TestCase(KEY128_1, IV128_1, + "27bede74018082da87d4e5b69f18bf6632070e0f39b7b692b4673edc3184a48e27636f4414510d62cc15cfe194ec4f6d4b8c8fcc630648badf41b6f9d16a36ca" + ); + private final TestCase ZUC128_TEST2 = new TestCase(KEY128_2, IV128_2, + "0657cfa07096398b734b6cb4883eedf4257a76eb97595208d884adcdb1cbffb8e0f9d15846a0eed015328503351138f740d079af17296c232c4f022d6e4acac6" + ); + private final TestCase ZUC256_TEST1 = new TestCase(KEY256_1, IV200_1, + "58d03ad62e032ce2dafc683a39bdcb0352a2bc67f1b7de74163ce3a101ef55589639d75b95fa681b7f090df756391ccc903b7612744d544c17bc3fad8b163b08" + ); + private final TestCase ZUC256_TEST2 = new TestCase(KEY256_2, IV200_2, + "3356cbaed1a1c18b6baa4ffe343f777c9e15128f251ab65b949f7b26ef7157f296dd2fa9df95e3ee7a5be02ec32ba585505af316c2f9ded27cdbd935e441ce11" + ); + + private final TestCase MAC128_TEST1 = new TestCase(KEY128_1, IV128_1, "508dd5ff"); + private final TestCase MAC128_TEST2 = new TestCase(KEY128_1, IV128_1, "fbed4c12"); + private final TestCase MAC256_TEST1 = new TestCase(KEY256_1, IV200_1, "d85e54bbcb9600967084c952a1654b26"); + private final TestCase MAC256_TEST2 = new TestCase(KEY256_1, IV200_1, "df1e8307b31cc62beca1ac6f8190c22f"); + private final TestCase MAC256_64_TEST1 = new TestCase(KEY256_1, IV200_1, "673e54990034d38c"); + private final TestCase MAC256_64_TEST2 = new TestCase(KEY256_1, IV200_1, "130dc225e72240cc"); + private final TestCase MAC256_32_TEST1 = new TestCase(KEY256_1, IV200_1, "9b972a74"); + private final TestCase MAC256_32_TEST2 = new TestCase(KEY256_1, IV200_1, "8754f5cf"); + + public String getName() + { + return "Zuc"; + } + + /** + * Test the Cipher against the results. + * + * @param pCipher the cipher to test. + * @param pTestCase the testCase + */ + void testCipher(final Cipher pCipher, + final TestCase pTestCase) + throws Exception + { + /* Access the expected bytes */ + final byte[] myExpected = Hex.decode(pTestCase.theExpected); + + /* Create the output buffer */ + final byte[] myOutput = new byte[myExpected.length]; + + /* Access plainText or nulls */ + final byte[] myData = pTestCase.thePlainText != null + ? Hex.decode(pTestCase.thePlainText) + : new byte[myExpected.length]; + + /* Access the key and the iv */ + final SecretKey myKey = new SecretKeySpec(Hex.decode(pTestCase.theKey), pCipher.getAlgorithm()); + final byte[] myIV = Hex.decode(pTestCase.theIV); + + /* Initialise the cipher and create the keyStream */ + pCipher.init(Cipher.ENCRYPT_MODE, myKey, new IvParameterSpec(myIV)); + + pCipher.doFinal(myData, 0, myData.length, myOutput, 0); + + /* Check the encryption */ + isTrue("Encryption mismatch", Arrays.areEqual(myExpected, myOutput)); + + AlgorithmParameters algParams = AlgorithmParameters.getInstance(pCipher.getAlgorithm(), "BC"); + + algParams.init(new IvParameterSpec(myIV)); + + pCipher.init(Cipher.DECRYPT_MODE, myKey, algParams); + + pCipher.doFinal(myData, 0, myData.length, myOutput, 0); + } + + /** + * Test the Mac against the results. + * + * @param pMac the mac to test. + * @param pOnes use all ones as data? + * @param pTestCase the testCase + */ + void testMac(final Mac pMac, + final boolean pOnes, + final TestCase pTestCase) + throws Exception + { + /* Access the expected bytes */ + final byte[] myExpected = Hex.decode(pTestCase.theExpected); + + /* Create the output buffer and the data */ + final byte[] myOutput = new byte[pMac.getMacLength()]; + + isTrue("Mac length mismatch", myExpected.length == myOutput.length); + + final byte[] myData = new byte[(pOnes ? 4000 : 400) / 8]; + Arrays.fill(myData, (byte)(pOnes ? 0x11 : 0)); + + /* Access the key and the iv */ + final SecretKey myKey = new SecretKeySpec(Hex.decode(pTestCase.theKey), pMac.getAlgorithm()); + final byte[] myIV = Hex.decode(pTestCase.theIV); + + /* Initialise the cipher and create the keyStream */ + pMac.init(myKey, new IvParameterSpec(myIV)); + pMac.update(myData, 0, myData.length); + pMac.doFinal(myOutput, 0); + + /* Check the mac */ + isTrue("Mac mismatch", Arrays.areEqual(myExpected, myOutput)); + + /* Check doFinal reset */ + pMac.update(myData, 0, myData.length); + pMac.doFinal(myOutput, 0); + + isTrue("DoFinal Mac mismatch", Arrays.areEqual(myExpected, myOutput)); + + /* Check reset() */ + pMac.update(myData, 0, myData.length); + + pMac.reset(); + + pMac.update(myData, 0, myData.length); + pMac.doFinal(myOutput, 0); + + isTrue("Reset Mac mismatch", Arrays.areEqual(myExpected, myOutput)); + } + + private void simpleTest(Cipher zuc) + throws Exception + { + KeyGenerator kGen = KeyGenerator.getInstance(zuc.getAlgorithm(), "BC"); + byte[] msg = Strings.toByteArray("Hello, world!"); + SecretKey k = kGen.generateKey(); + + zuc.init(Cipher.ENCRYPT_MODE, k); + + byte[] enc = zuc.doFinal(msg); + + byte[] iv = zuc.getIV(); + AlgorithmParameters algParam = zuc.getParameters(); + + zuc.init(Cipher.DECRYPT_MODE, k, new IvParameterSpec(iv)); + + byte[] dec = zuc.doFinal(enc); + + areEqual(msg, dec); + + zuc.init(Cipher.DECRYPT_MODE, k, algParam); + + dec = zuc.doFinal(enc); + + areEqual(msg, dec); + } + + public void performTest() + throws Exception + { + final Cipher zuc128 = Cipher.getInstance("Zuc-128", "BC"); + testCipher(zuc128, ZUC128_TEST1); + testCipher(zuc128, ZUC128_TEST2); + + simpleTest(zuc128); + + final Cipher zuc256 = Cipher.getInstance("Zuc-256", "BC"); + testCipher(zuc256, ZUC256_TEST1); + testCipher(zuc256, ZUC256_TEST2); + + simpleTest(zuc256); + + final Mac mac128 = Mac.getInstance("Zuc-128", "BC"); + + // check reset + mac128.reset(); + + testMac(mac128, false, MAC128_TEST1); + testMac(mac128, true, MAC128_TEST2); + + final Mac mac256 = Mac.getInstance("Zuc-256", "BC"); + + // check reset + mac256.reset(); + + testMac(mac256, false, MAC256_TEST1); + testMac(mac256, true, MAC256_TEST2); + + final Mac mac256_128 = Mac.getInstance("Zuc-256-128", "BC"); + + testMac(mac256_128, false, MAC256_TEST1); + testMac(mac256_128, true, MAC256_TEST2); + + final Mac mac256_64 = Mac.getInstance("Zuc-256-64", "BC"); + + testMac(mac256_64, false, MAC256_64_TEST1); + testMac(mac256_64, true, MAC256_64_TEST2); + + final Mac mac256_32 = Mac.getInstance("Zuc-256-32", "BC"); + + testMac(mac256_32, false, MAC256_32_TEST1); + testMac(mac256_32, true, MAC256_32_TEST2); + } + + /** + * The TestCase. + */ + private static class TestCase + { + /** + * The testCase. + */ + private final String theKey; + private final String theIV; + private final String thePlainText; + private final String theExpected; + + /** + * Constructor. + * + * @param pKey the key + * @param pIV the IV + * @param pExpected the expected results. + */ + TestCase(final String pKey, + final String pIV, + final String pExpected) + { + this(pKey, pIV, null, pExpected); + } + + /** + * Constructor. + * + * @param pKey the key + * @param pIV the IV + * @param pPlain the plainText + * @param pExpected the expected results. + */ + TestCase(final String pKey, + final String pIV, + final String pPlain, + final String pExpected) + { + theKey = pKey; + theIV = pIV; + thePlainText = pPlain; + theExpected = pExpected; + } + } + + public static void main( + String[] args) + { + Security.addProvider(new BouncyCastleProvider()); + + Test test = new ZucTest(); + TestResult result = test.perform(); + + System.out.println(result.toString()); + if (result.getException() != null) + { + result.getException().printStackTrace(); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/nist/PKITSTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/nist/PKITSTest.java new file mode 100644 index 000000000..3c4aae647 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/provider/test/nist/PKITSTest.java @@ -0,0 +1,467 @@ +package com.fr.third.org.bouncycastle.jce.provider.test.nist; + +import java.io.InputStream; +import java.security.cert.CertPath; +import java.security.cert.CertPathValidator; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertStore; +import java.security.cert.Certificate; +import java.security.cert.CertificateFactory; +import java.security.cert.CollectionCertStoreParameters; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.GregorianCalendar; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; +import com.fr.third.org.bouncycastle.asn1.ASN1Encoding; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.x509.BasicConstraints; +import com.fr.third.org.bouncycastle.asn1.x509.Extension; +import com.fr.third.org.bouncycastle.asn1.x509.KeyUsage; +import com.fr.third.org.bouncycastle.asn1.x509.TBSCertificate; +import com.fr.third.org.bouncycastle.jcajce.PKIXExtendedParameters; + +/** + * Utility class to support PKITS testing of the Cert Path library and associated functions. + */ + +class PKITSTest +{ + private Set trustAnchors = new HashSet(); + private ArrayList certs = new ArrayList(); + private ArrayList crls = new ArrayList(); + private Set policies = new HashSet(); + + // + // Global to save reloading. + // + private static final Map certBuffer = new HashMap(); + private static final Map crlBuffer = new HashMap(); + + private CertPath certPath; + private CertStore certStore; + private PKIXCertPathValidatorResult validatorResult; + private X509Certificate endCert; + private Boolean explicitPolicyRequired; + private Boolean inhibitAnyPolicy; + private Boolean policyMappingInhibited; + private boolean deltaCRLsEnabled; + + + private HashMap certsByName = new HashMap(); + private HashMap crlsByName = new HashMap(); + + + private static final HashMap policiesByName = new HashMap(); + + static + { + policiesByName.put("anyPolicy", new ASN1ObjectIdentifier("2.5.29.32.0")); + policiesByName.put("NIST-test-policy-1", new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.1")); + policiesByName.put("NIST-test-policy-2", new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.2")); + policiesByName.put("NIST-test-policy-3", new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.3")); + policiesByName.put("NIST-test-policy-4", new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.4")); + policiesByName.put("NIST-test-policy-5", new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.5")); + policiesByName.put("NIST-test-policy-6", new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.6")); + policiesByName.put("NIST-test-policy-7", new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.7")); + policiesByName.put("NIST-test-policy-8", new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.8")); + policiesByName.put("NIST-test-policy-9", new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.9")); + policiesByName.put("NIST-test-policy-10", new ASN1ObjectIdentifier("2.16.840.1.101.3.2.1.48.10")); + } + + + public static ASN1ObjectIdentifier[] resolvePolicyOid(String... nistNames) + { + ASN1ObjectIdentifier[] oids = new ASN1ObjectIdentifier[nistNames.length]; + + int c = 0; + for (String name : nistNames) + { + ASN1ObjectIdentifier oid = policiesByName.get(name); + + if (oid == null) + { + oid = new ASN1ObjectIdentifier(name); + } + oids[c++] = oid; + } + + return oids; + } + + + public PKITSTest() + throws Exception + { + trustAnchors.add(getTrustAnchor("TrustAnchorRootCertificate")); + withCrls("TrustAnchorRootCRL"); + } + + PKITSTest enableDeltaCRLs(boolean enabled) + { + this.deltaCRLsEnabled = enabled; + + return this; + } + + PKITSTest withCrls(String... crls) + throws Exception + { + for (String name : crls) + { + name = name.replace(" ", "").replace("-", ""); + this.crls.add(loadCrl(name)); + } + return this; + } + + PKITSTest withCACert(String... certs) + { + for (String name : certs) + { + name = name.replace(" ", "").replace("-", ""); + this.certs.add(loadCert(name)); + } + return this; + } + + + public PKITSTest withPolicyByName(String... policies) + { + withPolicyByOids(resolvePolicyOid(policies)); + return this; + } + + + public PKITSTest withExplicitPolicyRequired(boolean required) + { + this.explicitPolicyRequired = required; + return this; + } + + public PKITSTest withPolicyByOids(ASN1ObjectIdentifier... policies) + { + + for (ASN1ObjectIdentifier policy : policies) + { + this.policies.add(policy.toString()); + } + + return this; + } + + + PKIXCertPathValidatorResult doTest() + throws Exception + { + List certsAndCrls = new ArrayList(); + + certsAndCrls.add(endCert); + certsAndCrls.addAll(certs); + + certPath = CertificateFactory.getInstance("X.509", "BC").generateCertPath(certsAndCrls); + + certsAndCrls.addAll(crls); + + certStore = CertStore.getInstance("Collection", new CollectionCertStoreParameters(certsAndCrls), "BC"); + + CertPathValidator validator = CertPathValidator.getInstance("PKIX", "BC"); + PKIXParameters params = new PKIXParameters(trustAnchors); + + params.addCertStore(certStore); + params.setRevocationEnabled(true); + params.setDate(new GregorianCalendar(2010, 1, 1).getTime()); + + if (explicitPolicyRequired != null) + { + params.setExplicitPolicyRequired(explicitPolicyRequired); + } + + if (inhibitAnyPolicy != null) + { + params.setAnyPolicyInhibited(inhibitAnyPolicy); + } + + if (policyMappingInhibited != null) + { + params.setPolicyMappingInhibited(policyMappingInhibited); + } + + if (!policies.isEmpty()) + { + params.setExplicitPolicyRequired(true); + params.setInitialPolicies(policies); + } + + PKIXExtendedParameters.Builder extParams = new PKIXExtendedParameters.Builder(params); + + extParams.setUseDeltasEnabled(deltaCRLsEnabled); + + validatorResult = (PKIXCertPathValidatorResult)validator.validate(certPath, extParams.build()); + + return validatorResult; + } + + void doExceptionTest( + int index, + String message) + throws Exception + { + try + { + doTest(); + + throw new RuntimeException("path accepted when should be rejected"); + } + catch (CertPathValidatorException e) + { + if (index != e.getIndex()) + { + throw new RuntimeException("Index did not match: " + index + " got " + e.getIndex()); + } + + if (!message.equals(e.getMessage())) + { + throw new RuntimeException("Message did not match: '" + message + "', got '" + e.getMessage() + "'"); + } + } + } + + X509Certificate pathCert(int index) + { + List certificates = certPath.getCertificates(); + if (index >= certificates.size()) + { + throw new IllegalArgumentException("Index " + index + " exceeds available certificates in path, " + certificates.size()); + } + + return (X509Certificate)certificates.get(index); + } + + TBSCertificate pathTBSCert(int index) + throws Exception + { + List certificates = certPath.getCertificates(); + if (index >= certificates.size()) + { + throw new IllegalArgumentException("Index " + index + " exceeds available certificates in path, " + certificates.size()); + } + + X509Certificate cert = (X509Certificate)certificates.get(index); + + + return TBSCertificate.getInstance(cert.getTBSCertificate()); + } + + /** + * Test a certificate in the path has the folling usage + * + * @param certIndex The certificate index. + * @param usage An integer build from KeyUsage class constants, eg KeyUsage.cRLSign | KeyUsage.keyCertSign + * @return true if all are found. + * @throws Exception + */ + public boolean certHasKeyUsage(int certIndex, int usage) + throws Exception + { + KeyUsage ku = KeyUsage.fromExtensions(pathTBSCert(certIndex).getExtensions()); + + return ku.hasUsages(usage); + } + + public BasicConstraints certBasicConstraints(int certIndex) + throws Exception + { + return BasicConstraints.fromExtensions(pathTBSCert(certIndex).getExtensions()); + } + + + public Set getTrustAnchors() + { + return trustAnchors; + } + + public ArrayList getCerts() + { + return certs; + } + + public ArrayList getCrls() + { + return crls; + } + + public Set getPolicies() + { + return policies; + } + + public static Map getCertBuffer() + { + return certBuffer; + } + + public static Map getCrlBuffer() + { + return crlBuffer; + } + + public CertPath getCertPath() + { + return certPath; + } + + public CertStore getCertStore() + { + return certStore; + } + + public PKIXCertPathValidatorResult getValidatorResult() + { + return validatorResult; + } + + public X509Certificate getEndCert() + { + return endCert; + } + + private X509Certificate loadCert( + final String certName) + { + X509Certificate cert; + synchronized (certBuffer) + { + cert = (X509Certificate)certBuffer.get(certName); + } + + if (cert != null) + { + certsByName.put(certName, cert); + return cert; + } + + try + { + String path = getPkitsHome() + "/certs/" + certName + ".crt"; + InputStream in = this.getClass().getResourceAsStream(path); + + if (in == null) + { + throw new RuntimeException("Could not find: " + path); + } + + + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + cert = (X509Certificate)fact.generateCertificate(in); + + synchronized (certBuffer) + { + certsByName.put(certName, cert); + certBuffer.put(certName, cert); + } + return cert; + } + catch (Exception e) + { + throw new IllegalStateException("exception loading certificate " + certName + ": " + e); + } + } + + private X509CRL loadCrl( + String crlName) + throws Exception + { + X509CRL crl; + synchronized (crlBuffer) + { + crl = (X509CRL)crlBuffer.get(crlName); + } + if (crl != null) + { + crlsByName.put(crlName, crl); + return crl; + } + + try + { + InputStream in = this.getClass().getResourceAsStream(getPkitsHome() + "/crls/" + crlName + ".crl"); + + CertificateFactory fact = CertificateFactory.getInstance("X.509", "BC"); + + crl = (X509CRL)fact.generateCRL(in); + + synchronized (crlBuffer) + { + crlsByName.put(crlName, crl); + crlBuffer.put(crlName, crl); + } + + + return crl; + } + catch (Exception e) + { + throw new IllegalStateException("exception loading CRL: " + crlName); + } + } + + private TrustAnchor getTrustAnchor(String trustAnchorName) + throws Exception + { + X509Certificate cert = loadCert(trustAnchorName); + byte[] extBytes = cert.getExtensionValue(Extension.nameConstraints.getId()); + + if (extBytes != null) + { + ASN1Encodable extValue = ASN1Primitive.fromByteArray(ASN1OctetString.getInstance(extBytes).getOctets()); + + return new TrustAnchor(cert, extValue.toASN1Primitive().getEncoded(ASN1Encoding.DER)); + } + + return new TrustAnchor(cert, null); + } + + + private String getPkitsHome() + { + return "/PKITS"; + } + + public PKITSTest withEndEntity(String endCert) + { + endCert = endCert.replace(" ", "").replace("-", ""); + this.endCert = loadCert(endCert); + return this; + } + + public boolean endCertMatchesPathCert(int certIndex) + { + return endCert.equals(this.pathCert(certIndex)); + } + + public PKITSTest withInhibitAnyPolicy(boolean inhibitAnyPolicy) + { + this.inhibitAnyPolicy = inhibitAnyPolicy; + return this; + } + + public PKITSTest withPolicyMappingInhibited(boolean policyMappingInhibited) + { + this.policyMappingInhibited = policyMappingInhibited; + return this; + } + +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/spec/OpenSSHPrivateKeySpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/spec/OpenSSHPrivateKeySpec.java new file mode 100644 index 000000000..6da9e24bd --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/spec/OpenSSHPrivateKeySpec.java @@ -0,0 +1,32 @@ +package com.fr.third.org.bouncycastle.jce.spec; + +/** + * OpenSSHPrivateKeySpec holds and encoded OpenSSH private key. + * The format of the key can be either ASN.1 or OpenSSH. + * @deprecated use com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec + */ +public class OpenSSHPrivateKeySpec + extends com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPrivateKeySpec +{ + /** + * Accept an encoded key and determine the format. + *

+ * The encoded key should be the Base64 decoded blob between the "---BEGIN and ---END" markers. + * This constructor will endeavour to find the OpenSSH format magic value. If it can not then it + * will default to ASN.1. It does not attempt to validate the ASN.1 + *

+ * Example: + * OpenSSHPrivateKeySpec privSpec = new OpenSSHPrivateKeySpec(rawPriv); + *

+ * KeyFactory kpf = KeyFactory.getInstance("RSA", "BC"); + * PrivateKey prk = kpf.generatePrivate(privSpec); + *

+ * OpenSSHPrivateKeySpec rcPrivateSpec = kpf.getKeySpec(prk, OpenSSHPrivateKeySpec.class); + * + * @param encodedKey The encoded key. + */ + public OpenSSHPrivateKeySpec(byte[] encodedKey) + { + super(encodedKey); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/spec/OpenSSHPublicKeySpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/spec/OpenSSHPublicKeySpec.java new file mode 100644 index 000000000..f6dd3c48a --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/jce/spec/OpenSSHPublicKeySpec.java @@ -0,0 +1,22 @@ +package com.fr.third.org.bouncycastle.jce.spec; + +/** + * Holds an OpenSSH encoded public key. + * @deprecated use com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec + */ +public class OpenSSHPublicKeySpec + extends com.fr.third.org.bouncycastle.jcajce.spec.OpenSSHPublicKeySpec +{ + /** + * Construct and instance and determine the OpenSSH public key type. + * The current types are ssh-rsa, ssh-ed25519, ssh-dss and ecdsa-* + *

+ * It does not validate the key beyond identifying the type. + * + * @param encodedKey + */ + public OpenSSHPublicKeySpec(byte[] encodedKey) + { + super(encodedKey); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/AbstractECLookupTable.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/AbstractECLookupTable.java new file mode 100644 index 000000000..6139eeabc --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/AbstractECLookupTable.java @@ -0,0 +1,10 @@ +package com.fr.third.org.bouncycastle.math.ec; + +public abstract class AbstractECLookupTable + implements ECLookupTable +{ + public ECPoint lookupVar(int index) + { + return lookup(index); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECAlgorithms.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECAlgorithms.java index 57a14f8ba..bbac92090 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECAlgorithms.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECAlgorithms.java @@ -3,9 +3,11 @@ package com.fr.third.org.bouncycastle.math.ec; import java.math.BigInteger; import com.fr.third.org.bouncycastle.math.ec.endo.ECEndomorphism; +import com.fr.third.org.bouncycastle.math.ec.endo.EndoUtil; import com.fr.third.org.bouncycastle.math.ec.endo.GLVEndomorphism; import com.fr.third.org.bouncycastle.math.field.FiniteField; import com.fr.third.org.bouncycastle.math.field.PolynomialExtensionField; +import com.fr.third.org.bouncycastle.math.raw.Nat; public class ECAlgorithms { @@ -280,46 +282,63 @@ public class ECAlgorithms { boolean negK = k.signum() < 0, negL = l.signum() < 0; - k = k.abs(); - l = l.abs(); + BigInteger kAbs = k.abs(), lAbs = l.abs(); + + int minWidthP = WNafUtil.getWindowSize(kAbs.bitLength(), 8); + int minWidthQ = WNafUtil.getWindowSize(lAbs.bitLength(), 8); - int widthP = Math.max(2, Math.min(16, WNafUtil.getWindowSize(k.bitLength()))); - int widthQ = Math.max(2, Math.min(16, WNafUtil.getWindowSize(l.bitLength()))); + WNafPreCompInfo infoP = WNafUtil.precompute(P, minWidthP, true); + WNafPreCompInfo infoQ = WNafUtil.precompute(Q, minWidthQ, true); + + // When P, Q are 'promoted' (i.e. reused several times), switch to fixed-point algorithm + { + ECCurve c = P.getCurve(); + int combSize = FixedPointUtil.getCombSize(c); + if (!negK && !negL + && k.bitLength() <= combSize && l.bitLength() <= combSize + && infoP.isPromoted() && infoQ.isPromoted()) + { + return implShamirsTrickFixedPoint(P, k, Q, l); + } + } - WNafPreCompInfo infoP = WNafUtil.precompute(P, widthP, true); - WNafPreCompInfo infoQ = WNafUtil.precompute(Q, widthQ, true); + int widthP = Math.min(8, infoP.getWidth()); + int widthQ = Math.min(8, infoQ.getWidth()); ECPoint[] preCompP = negK ? infoP.getPreCompNeg() : infoP.getPreComp(); ECPoint[] preCompQ = negL ? infoQ.getPreCompNeg() : infoQ.getPreComp(); ECPoint[] preCompNegP = negK ? infoP.getPreComp() : infoP.getPreCompNeg(); ECPoint[] preCompNegQ = negL ? infoQ.getPreComp() : infoQ.getPreCompNeg(); - byte[] wnafP = WNafUtil.generateWindowNaf(widthP, k); - byte[] wnafQ = WNafUtil.generateWindowNaf(widthQ, l); + byte[] wnafP = WNafUtil.generateWindowNaf(widthP, kAbs); + byte[] wnafQ = WNafUtil.generateWindowNaf(widthQ, lAbs); return implShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ); } - static ECPoint implShamirsTrickWNaf(ECPoint P, BigInteger k, ECPointMap pointMapQ, BigInteger l) + static ECPoint implShamirsTrickWNaf(ECEndomorphism endomorphism, ECPoint P, BigInteger k, BigInteger l) { boolean negK = k.signum() < 0, negL = l.signum() < 0; k = k.abs(); l = l.abs(); - int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(Math.max(k.bitLength(), l.bitLength())))); + int minWidth = WNafUtil.getWindowSize(Math.max(k.bitLength(), l.bitLength()), 8); + + WNafPreCompInfo infoP = WNafUtil.precompute(P, minWidth, true); + ECPoint Q = EndoUtil.mapPoint(endomorphism, P); + WNafPreCompInfo infoQ = WNafUtil.precomputeWithPointMap(Q, endomorphism.getPointMap(), infoP, true); - ECPoint Q = WNafUtil.mapPointWithPrecomp(P, width, true, pointMapQ); - WNafPreCompInfo infoP = WNafUtil.getWNafPreCompInfo(P); - WNafPreCompInfo infoQ = WNafUtil.getWNafPreCompInfo(Q); + int widthP = Math.min(8, infoP.getWidth()); + int widthQ = Math.min(8, infoQ.getWidth()); ECPoint[] preCompP = negK ? infoP.getPreCompNeg() : infoP.getPreComp(); ECPoint[] preCompQ = negL ? infoQ.getPreCompNeg() : infoQ.getPreComp(); ECPoint[] preCompNegP = negK ? infoP.getPreComp() : infoP.getPreCompNeg(); ECPoint[] preCompNegQ = negL ? infoQ.getPreComp() : infoQ.getPreCompNeg(); - byte[] wnafP = WNafUtil.generateWindowNaf(width, k); - byte[] wnafQ = WNafUtil.generateWindowNaf(width, l); + byte[] wnafP = WNafUtil.generateWindowNaf(widthP, k); + byte[] wnafQ = WNafUtil.generateWindowNaf(widthQ, l); return implShamirsTrickWNaf(preCompP, preCompNegP, wnafP, preCompQ, preCompNegQ, wnafQ); } @@ -388,8 +407,12 @@ public class ECAlgorithms { BigInteger ki = ks[i]; negs[i] = ki.signum() < 0; ki = ki.abs(); - int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(ki.bitLength()))); - infos[i] = WNafUtil.precompute(ps[i], width, true); + int minWidth = WNafUtil.getWindowSize(ki.bitLength(), 8); + WNafPreCompInfo info = WNafUtil.precompute(ps[i], minWidth, true); + + int width = Math.min(8, info.getWidth()); + + infos[i] = info; wnafs[i] = WNafUtil.generateWindowNaf(width, ki); } @@ -410,25 +433,24 @@ public class ECAlgorithms abs[j++] = ab[1]; } - ECPointMap pointMap = glvEndomorphism.getPointMap(); if (glvEndomorphism.hasEfficientPointMap()) { - return ECAlgorithms.implSumOfMultiplies(ps, pointMap, abs); + return implSumOfMultiplies(glvEndomorphism, ps, abs); } ECPoint[] pqs = new ECPoint[len << 1]; for (int i = 0, j = 0; i < len; ++i) { - ECPoint p = ps[i], q = pointMap.map(p); + ECPoint p = ps[i]; + ECPoint q = EndoUtil.mapPoint(glvEndomorphism, p); pqs[j++] = p; pqs[j++] = q; } - - return ECAlgorithms.implSumOfMultiplies(pqs, abs); + return implSumOfMultiplies(pqs, abs); } - static ECPoint implSumOfMultiplies(ECPoint[] ps, ECPointMap pointMap, BigInteger[] ks) + static ECPoint implSumOfMultiplies(ECEndomorphism endomorphism, ECPoint[] ps, BigInteger[] ks) { int halfCount = ps.length, fullCount = halfCount << 1; @@ -436,6 +458,8 @@ public class ECAlgorithms WNafPreCompInfo[] infos = new WNafPreCompInfo[fullCount]; byte[][] wnafs = new byte[fullCount][]; + ECPointMap pointMap = endomorphism.getPointMap(); + for (int i = 0; i < halfCount; ++i) { int j0 = i << 1, j1 = j0 + 1; @@ -443,13 +467,20 @@ public class ECAlgorithms BigInteger kj0 = ks[j0]; negs[j0] = kj0.signum() < 0; kj0 = kj0.abs(); BigInteger kj1 = ks[j1]; negs[j1] = kj1.signum() < 0; kj1 = kj1.abs(); - int width = Math.max(2, Math.min(16, WNafUtil.getWindowSize(Math.max(kj0.bitLength(), kj1.bitLength())))); + int minWidth = WNafUtil.getWindowSize(Math.max(kj0.bitLength(), kj1.bitLength()), 8); + + ECPoint P = ps[i]; + WNafPreCompInfo infoP = WNafUtil.precompute(P, minWidth, true); + ECPoint Q = EndoUtil.mapPoint(endomorphism, P); + WNafPreCompInfo infoQ = WNafUtil.precomputeWithPointMap(Q, pointMap, infoP, true); + + int widthP = Math.min(8, infoP.getWidth()); + int widthQ = Math.min(8, infoQ.getWidth()); - ECPoint P = ps[i], Q = WNafUtil.mapPointWithPrecomp(P, width, true, pointMap); - infos[j0] = WNafUtil.getWNafPreCompInfo(P); - infos[j1] = WNafUtil.getWNafPreCompInfo(Q); - wnafs[j0] = WNafUtil.generateWindowNaf(width, kj0); - wnafs[j1] = WNafUtil.generateWindowNaf(width, kj1); + infos[j0] = infoP; + infos[j1] = infoQ; + wnafs[j0] = WNafUtil.generateWindowNaf(widthP, kj0); + wnafs[j1] = WNafUtil.generateWindowNaf(widthQ, kj1); } return implSumOfMultiplies(negs, infos, wnafs); @@ -508,4 +539,77 @@ public class ECAlgorithms return R; } + + private static ECPoint implShamirsTrickFixedPoint(ECPoint p, BigInteger k, ECPoint q, BigInteger l) + { + ECCurve c = p.getCurve(); + int combSize = FixedPointUtil.getCombSize(c); + + if (k.bitLength() > combSize || l.bitLength() > combSize) + { + /* + * TODO The comb works best when the scalars are less than the (possibly unknown) order. + * Still, if we want to handle larger scalars, we could allow customization of the comb + * size, or alternatively we could deal with the 'extra' bits either by running the comb + * multiple times as necessary, or by using an alternative multiplier as prelude. + */ + throw new IllegalStateException("fixed-point comb doesn't support scalars larger than the curve order"); + } + + FixedPointPreCompInfo infoP = FixedPointUtil.precompute(p); + FixedPointPreCompInfo infoQ = FixedPointUtil.precompute(q); + + ECLookupTable lookupTableP = infoP.getLookupTable(); + ECLookupTable lookupTableQ = infoQ.getLookupTable(); + + int widthP = infoP.getWidth(); + int widthQ = infoQ.getWidth(); + + // TODO This shouldn't normally happen, but a better "solution" is desirable anyway + if (widthP != widthQ) + { + FixedPointCombMultiplier m = new FixedPointCombMultiplier(); + ECPoint r1 = m.multiply(p, k); + ECPoint r2 = m.multiply(q, l); + return r1.add(r2); + } + + int width = widthP; + + int d = (combSize + width - 1) / width; + + ECPoint R = c.getInfinity(); + + int fullComb = d * width; + int[] K = Nat.fromBigInteger(fullComb, k); + int[] L = Nat.fromBigInteger(fullComb, l); + + int top = fullComb - 1; + for (int i = 0; i < d; ++i) + { + int secretIndexK = 0, secretIndexL = 0; + + for (int j = top - i; j >= 0; j -= d) + { + int secretBitK = K[j >>> 5] >>> (j & 0x1F); + secretIndexK ^= secretBitK >>> 1; + secretIndexK <<= 1; + secretIndexK ^= secretBitK; + + int secretBitL = L[j >>> 5] >>> (j & 0x1F); + secretIndexL ^= secretBitL >>> 1; + secretIndexL <<= 1; + secretIndexL ^= secretBitL; + } + + ECPoint addP = lookupTableP.lookupVar(secretIndexK); + ECPoint addQ = lookupTableQ.lookupVar(secretIndexL); + + ECPoint T = addP.add(addQ); + + R = R.twicePlus(T); + } + + return R.add(infoP.getOffset()).add(infoQ.getOffset()); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECCurve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECCurve.java index a0213f9a5..d06cf9d1e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECCurve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECCurve.java @@ -122,39 +122,16 @@ public abstract class ECCurve return p; } - /** - * @deprecated per-point compression property will be removed, use {@link #validatePoint(BigInteger, BigInteger)} - * and refer {@link ECPoint#getEncoded(boolean)} - */ - public ECPoint validatePoint(BigInteger x, BigInteger y, boolean withCompression) - { - ECPoint p = createPoint(x, y, withCompression); - if (!p.isValid()) - { - throw new IllegalArgumentException("Invalid point coordinates"); - } - return p; - } - public ECPoint createPoint(BigInteger x, BigInteger y) { - return createPoint(x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, use {@link #createPoint(BigInteger, BigInteger)} - * and refer {@link ECPoint#getEncoded(boolean)} - */ - public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression) - { - return createRawPoint(fromBigInteger(x), fromBigInteger(y), withCompression); + return createRawPoint(fromBigInteger(x), fromBigInteger(y)); } protected abstract ECCurve cloneCurve(); - protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression); + protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y); - protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression); + protected abstract ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs); protected ECMultiplier createDefaultMultiplier() { @@ -246,7 +223,7 @@ public abstract class ECCurve // TODO Default behaviour could be improved if the two curves have the same coordinate system by copying any Z coordinates. p = p.normalize(); - return createPoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger(), p.withCompression); + return createPoint(p.getXCoord().toBigInteger(), p.getYCoord().toBigInteger()); } /** @@ -416,9 +393,7 @@ public abstract class ECCurve BigInteger X = BigIntegers.fromUnsignedByteArray(encoded, 1, expectedLength); p = decompressPoint(yTilde, X); - - // TODO Skip curve equation check? - if (!p.isValid()) + if (!p.implIsValid(true, true)) { throw new IllegalArgumentException("Invalid point"); } @@ -494,7 +469,7 @@ public abstract class ECCurve } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -519,7 +494,26 @@ public abstract class ECCurve pos += (FE_BYTES * 2); } - return createRawPoint(fromBigInteger(new BigInteger(1, x)), fromBigInteger(new BigInteger(1, y)), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + byte[] x = new byte[FE_BYTES], y = new byte[FE_BYTES]; + int pos = index * FE_BYTES * 2; + + for (int j = 0; j < FE_BYTES; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_BYTES + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(byte[] x, byte[] y) + { + return createRawPoint(fromBigInteger(new BigInteger(1, x)), fromBigInteger(new BigInteger(1, y))); } }; } @@ -611,7 +605,7 @@ public abstract class ECCurve y = y.negate(); } - return this.createRawPoint(x, y, true); + return this.createRawPoint(x, y); } } @@ -639,7 +633,7 @@ public abstract class ECCurve this.q = q; this.r = ECFieldElement.Fp.calculateResidue(q); - this.infinity = new ECPoint.Fp(this, null, null, false); + this.infinity = new ECPoint.Fp(this, null, null); this.a = fromBigInteger(a); this.b = fromBigInteger(b); @@ -662,7 +656,7 @@ public abstract class ECCurve this.q = q; this.r = r; - this.infinity = new ECPoint.Fp(this, null, null, false); + this.infinity = new ECPoint.Fp(this, null, null); this.a = a; this.b = b; @@ -705,14 +699,14 @@ public abstract class ECCurve return new ECFieldElement.Fp(this.q, this.r, x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new ECPoint.Fp(this, x, y, withCompression); + return new ECPoint.Fp(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new ECPoint.Fp(this, x, y, zs, withCompression); + return new ECPoint.Fp(this, x, y, zs); } public ECPoint importPoint(ECPoint p) @@ -727,8 +721,7 @@ public abstract class ECCurve return new ECPoint.Fp(this, fromBigInteger(p.x.toBigInteger()), fromBigInteger(p.y.toBigInteger()), - new ECFieldElement[]{ fromBigInteger(p.zs[0].toBigInteger()) }, - p.withCompression); + new ECFieldElement[]{ fromBigInteger(p.zs[0].toBigInteger()) }); default: break; } @@ -797,7 +790,7 @@ public abstract class ECCurve return x != null && x.signum() >= 0 && x.bitLength() <= this.getFieldSize(); } - public ECPoint createPoint(BigInteger x, BigInteger y, boolean withCompression) + public ECPoint createPoint(BigInteger x, BigInteger y) { ECFieldElement X = this.fromBigInteger(x), Y = this.fromBigInteger(y); @@ -824,7 +817,7 @@ public abstract class ECCurve // ECFieldElement Z = X; // X = X.square(); // Y = Y.add(X); -// return createRawPoint(X, Y, new ECFieldElement[]{ Z }, withCompression); +// return createRawPoint(X, Y, new ECFieldElement[]{ Z }); // } else { @@ -839,7 +832,7 @@ public abstract class ECCurve } } - return this.createRawPoint(X, Y, withCompression); + return this.createRawPoint(X, Y); } /** @@ -891,7 +884,7 @@ public abstract class ECCurve throw new IllegalArgumentException("Invalid point compression"); } - return this.createRawPoint(x, y, true); + return this.createRawPoint(x, y); } /** @@ -905,6 +898,27 @@ public abstract class ECCurve */ protected ECFieldElement solveQuadraticEquation(ECFieldElement beta) { + ECFieldElement.AbstractF2m betaF2m = (ECFieldElement.AbstractF2m)beta; + + boolean fastTrace = betaF2m.hasFastTrace(); + if (fastTrace && 0 != betaF2m.trace()) + { + return null; + } + + int m = this.getFieldSize(); + + // For odd m, use the half-trace + if (0 != (m & 1)) + { + ECFieldElement r = betaF2m.halfTrace(); + if (fastTrace || r.square().add(r).add(beta).isZero()) + { + return r; + } + return null; + } + if (beta.isZero()) { return beta; @@ -912,7 +926,6 @@ public abstract class ECCurve ECFieldElement gamma, z, zeroElement = this.fromBigInteger(ECConstants.ZERO); - int m = this.getFieldSize(); Random rand = new Random(); do { @@ -1130,7 +1143,7 @@ public abstract class ECCurve this.order = order; this.cofactor = cofactor; - this.infinity = new ECPoint.F2m(this, null, null, false); + this.infinity = new ECPoint.F2m(this, null, null); this.a = fromBigInteger(a); this.b = fromBigInteger(b); this.coord = F2M_DEFAULT_COORDS; @@ -1147,7 +1160,7 @@ public abstract class ECCurve this.order = order; this.cofactor = cofactor; - this.infinity = new ECPoint.F2m(this, null, null, false); + this.infinity = new ECPoint.F2m(this, null, null); this.a = a; this.b = b; this.coord = F2M_DEFAULT_COORDS; @@ -1191,14 +1204,14 @@ public abstract class ECCurve return new ECFieldElement.F2m(this.m, this.k1, this.k2, this.k3, x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new ECPoint.F2m(this, x, y, withCompression); + return new ECPoint.F2m(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new ECPoint.F2m(this, x, y, zs, withCompression); + return new ECPoint.F2m(this, x, y, zs); } public ECPoint getInfinity() @@ -1252,7 +1265,7 @@ public abstract class ECCurve } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -1277,7 +1290,28 @@ public abstract class ECCurve pos += (FE_LONGS * 2); } - return createRawPoint(new ECFieldElement.F2m(m, ks, new LongArray(x)), new ECFieldElement.F2m(m, ks, new LongArray(y)), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat.create64(FE_LONGS), y = Nat.create64(FE_LONGS); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + ECFieldElement.F2m X = new ECFieldElement.F2m(m, ks, new LongArray(x)); + ECFieldElement.F2m Y = new ECFieldElement.F2m(m, ks, new LongArray(y)); + return createRawPoint(X, Y); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECFieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECFieldElement.java index e8b61326d..9198905b5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECFieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECFieldElement.java @@ -7,6 +7,7 @@ import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.util.Arrays; import com.fr.third.org.bouncycastle.util.BigIntegers; +import com.fr.third.org.bouncycastle.util.Integers; public abstract class ECFieldElement implements ECConstants @@ -24,6 +25,11 @@ public abstract class ECFieldElement public abstract ECFieldElement invert(); public abstract ECFieldElement sqrt(); + public ECFieldElement() + { + + } + public int bitLength() { return toBigInteger().bitLength(); @@ -499,33 +505,65 @@ public abstract class ECFieldElement { public ECFieldElement halfTrace() { - int m = getFieldSize(); + int m = this.getFieldSize(); if ((m & 1) == 0) { throw new IllegalStateException("Half-trace only defined for odd m"); } - ECFieldElement fe = this; - ECFieldElement ht = fe; - for (int i = 2; i < m; i += 2) +// ECFieldElement ht = this; +// for (int i = 1; i < m; i += 2) +// { +// ht = ht.squarePow(2).add(this); +// } + + int n = (m + 1) >>> 1; + int k = 31 - Integers.numberOfLeadingZeros(n); + int nk = 1; + + ECFieldElement ht = this; + while (k > 0) { - fe = fe.squarePow(2); - ht = ht.add(fe); + ht = ht.squarePow(nk << 1).add(ht); + nk = n >>> --k; + if (0 != (nk & 1)) + { + ht = ht.squarePow(2).add(this); + } } return ht; } + public boolean hasFastTrace() + { + return false; + } + public int trace() { - int m = getFieldSize(); - ECFieldElement fe = this; - ECFieldElement tr = fe; - for (int i = 1; i < m; ++i) + int m = this.getFieldSize(); + +// ECFieldElement tr = this; +// for (int i = 1; i < m; ++i) +// { +// tr = tr.square().add(this); +// } + + int k = 31 - Integers.numberOfLeadingZeros(m); + int mk = 1; + + ECFieldElement tr = this; + while (k > 0) { - fe = fe.square(); - tr = tr.add(fe); + tr = tr.squarePow(mk).add(tr); + mk = m >>> --k; + if (0 != (mk & 1)) + { + tr = tr.square().add(this); + } } + if (tr.isZero()) { return 0; @@ -687,7 +725,9 @@ public abstract class ECFieldElement * @throws IllegalArgumentException if a and b * are not elements of the same field * F2m (having the same - * representation). + * representation). + * + * @deprecated Will be removed */ public static void checkFieldElements( ECFieldElement a, diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECLookupTable.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECLookupTable.java index 3ca246a88..fc2a7e006 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECLookupTable.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECLookupTable.java @@ -4,4 +4,5 @@ public interface ECLookupTable { int getSize(); ECPoint lookup(int index); + ECPoint lookupVar(int index); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECPoint.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECPoint.java index 15a178ed8..7ed6f0117 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECPoint.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ECPoint.java @@ -8,7 +8,7 @@ import java.util.Hashtable; */ public abstract class ECPoint { - protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0]; + protected final static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0]; protected static ECFieldElement[] getInitialZCoords(ECCurve curve) { @@ -46,8 +46,6 @@ public abstract class ECPoint protected ECFieldElement y; protected ECFieldElement[] zs; - protected boolean withCompression; - // Hashtable is (String -> PreCompInfo) protected Hashtable preCompTable = null; @@ -260,7 +258,7 @@ public abstract class ECPoint protected ECPoint createScaledPoint(ECFieldElement sx, ECFieldElement sy) { - return this.getCurve().createRawPoint(getRawXCoord().multiply(sx), getRawYCoord().multiply(sy), this.withCompression); + return this.getCurve().createRawPoint(getRawXCoord().multiply(sx), getRawYCoord().multiply(sy)); } public boolean isInfinity() @@ -268,25 +266,17 @@ public abstract class ECPoint return x == null || y == null || (zs.length > 0 && zs[0].isZero()); } - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public boolean isCompressed() - { - return this.withCompression; - } - public boolean isValid() { - return implIsValid(true); + return implIsValid(false, true); } boolean isValidPartial() { - return implIsValid(false); + return implIsValid(false, false); } - boolean implIsValid(final boolean checkOrder) + boolean implIsValid(final boolean decompressed, final boolean checkOrder) { if (isInfinity()) { @@ -309,7 +299,7 @@ public abstract class ECPoint } if (!info.hasCurveEquationPassed()) { - if (!satisfiesCurveEquation()) + if (!decompressed && !satisfiesCurveEquation()) { info.reportFailed(); return info; @@ -336,14 +326,28 @@ public abstract class ECPoint { return isInfinity() ? this - : getCurve().createRawPoint(getRawXCoord().multiply(scale), getRawYCoord(), getRawZCoords(), this.withCompression); + : getCurve().createRawPoint(getRawXCoord().multiply(scale), getRawYCoord(), getRawZCoords()); + } + + public ECPoint scaleXNegateY(ECFieldElement scale) + { + return isInfinity() + ? this + : getCurve().createRawPoint(getRawXCoord().multiply(scale), getRawYCoord().negate(), getRawZCoords()); } public ECPoint scaleY(ECFieldElement scale) { return isInfinity() ? this - : getCurve().createRawPoint(getRawXCoord(), getRawYCoord().multiply(scale), getRawZCoords(), this.withCompression); + : getCurve().createRawPoint(getRawXCoord(), getRawYCoord().multiply(scale), getRawZCoords()); + } + + public ECPoint scaleYNegateX(ECFieldElement scale) + { + return isInfinity() + ? this + : getCurve().createRawPoint(getRawXCoord().negate(), getRawYCoord().multiply(scale), getRawZCoords()); } public boolean equals(ECPoint other) @@ -449,15 +453,6 @@ public abstract class ECPoint return sb.toString(); } - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - * @return a byte encoding. - */ - public byte[] getEncoded() - { - return getEncoded(this.withCompression); - } - /** * Get an encoding of the point value, optionally in compressed format. * @@ -613,38 +608,19 @@ public abstract class ECPoint */ public static class Fp extends AbstractFp { - /** - * Create a point that encodes with or without point compression. - * - * @param curve the curve to use - * @param x affine x co-ordinate - * @param y affine y co-ordinate - * @param withCompression if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + Fp(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + Fp(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() { - return new ECPoint.Fp(null, this.getAffineXCoord(), this.getAffineYCoord(), false); + return new ECPoint.Fp(null, this.getAffineXCoord(), this.getAffineYCoord()); } public ECFieldElement getZCoord(int index) @@ -701,7 +677,7 @@ public abstract class ECPoint ECFieldElement X3 = gamma.square().subtract(X1).subtract(X2); ECFieldElement Y3 = gamma.multiply(X1.subtract(X3)).subtract(Y1); - return new ECPoint.Fp(curve, X3, Y3, this.withCompression); + return new ECPoint.Fp(curve, X3, Y3); } case ECCurve.COORD_HOMOGENEOUS: @@ -743,7 +719,7 @@ public abstract class ECPoint ECFieldElement Y3 = vSquaredV2.subtract(A).multiplyMinusProduct(u, u2, vCubed); ECFieldElement Z3 = vCubed.multiply(w); - return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } case ECCurve.COORD_JACOBIAN: @@ -866,7 +842,7 @@ public abstract class ECPoint zs = new ECFieldElement[]{ Z3 }; } - return new ECPoint.Fp(curve, X3, Y3, zs, this.withCompression); + return new ECPoint.Fp(curve, X3, Y3, zs); } default: @@ -905,7 +881,7 @@ public abstract class ECPoint ECFieldElement X3 = gamma.square().subtract(two(X1)); ECFieldElement Y3 = gamma.multiply(X1.subtract(X3)).subtract(Y1); - return new ECPoint.Fp(curve, X3, Y3, this.withCompression); + return new ECPoint.Fp(curve, X3, Y3); } case ECCurve.COORD_HOMOGENEOUS: @@ -935,7 +911,7 @@ public abstract class ECPoint ECFieldElement _4sSquared = Z1IsOne ? two(_2t) : _2s.square(); ECFieldElement Z3 = two(_4sSquared).multiply(s); - return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } case ECCurve.COORD_JACOBIAN: @@ -994,7 +970,7 @@ public abstract class ECPoint // Alternative calculation of Z3 using fast square // ECFieldElement Z3 = doubleProductFromSquares(Y1, Z1, Y1Squared, Z1Squared); - return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new ECPoint.Fp(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } case ECCurve.COORD_JACOBIAN_MODIFIED: @@ -1073,7 +1049,7 @@ public abstract class ECPoint ECFieldElement X4 = (L2.subtract(L1)).multiply(L1.add(L2)).add(X2); ECFieldElement Y4 = (X1.subtract(X4)).multiply(L2).subtract(Y1); - return new ECPoint.Fp(curve, X4, Y4, this.withCompression); + return new ECPoint.Fp(curve, X4, Y4); } case ECCurve.COORD_JACOBIAN_MODIFIED: { @@ -1126,7 +1102,7 @@ public abstract class ECPoint ECFieldElement X4 = (L2.subtract(L1)).multiply(L1.add(L2)).add(X1); ECFieldElement Y4 = (X1.subtract(X4)).multiply(L2).subtract(Y1); - return new ECPoint.Fp(curve, X4, Y4, this.withCompression); + return new ECPoint.Fp(curve, X4, Y4); } case ECCurve.COORD_JACOBIAN_MODIFIED: { @@ -1222,15 +1198,15 @@ public abstract class ECPoint { case ECCurve.COORD_AFFINE: ECFieldElement zInv = Z1.invert(), zInv2 = zInv.square(), zInv3 = zInv2.multiply(zInv); - return new Fp(curve, X1.multiply(zInv2), Y1.multiply(zInv3), this.withCompression); + return new Fp(curve, X1.multiply(zInv2), Y1.multiply(zInv3)); case ECCurve.COORD_HOMOGENEOUS: X1 = X1.multiply(Z1); Z1 = Z1.multiply(Z1.square()); - return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1 }, this.withCompression); + return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1 }); case ECCurve.COORD_JACOBIAN: - return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1 }, this.withCompression); + return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1 }); case ECCurve.COORD_JACOBIAN_MODIFIED: - return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1, W1 }, this.withCompression); + return new Fp(curve, X1, Y1, new ECFieldElement[]{ Z1, W1 }); default: throw new IllegalStateException("unsupported coordinate system"); } @@ -1278,10 +1254,10 @@ public abstract class ECPoint if (ECCurve.COORD_AFFINE != coord) { - return new ECPoint.Fp(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new ECPoint.Fp(curve, this.x, this.y.negate(), this.zs); } - return new ECPoint.Fp(curve, this.x, this.y.negate(), this.withCompression); + return new ECPoint.Fp(curve, this.x, this.y.negate()); } protected ECFieldElement calculateJacobianModifiedW(ECFieldElement Z, ECFieldElement ZSquared) @@ -1337,7 +1313,7 @@ public abstract class ECPoint ECFieldElement W3 = calculateW ? two(_8T.multiply(W1)) : null; ECFieldElement Z3 = Z1.isOne() ? _2Y1 : _2Y1.multiply(Z1); - return new ECPoint.Fp(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }, this.withCompression); + return new ECPoint.Fp(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }); } } @@ -1427,35 +1403,46 @@ public abstract class ECPoint if (ECConstants.TWO.equals(cofactor)) { /* - * Check that the trace of (X + A) is 0, then there exists a solution to L^2 + L = X + A, - * and so a halving is possible, so this point is the double of another. + * Check that 0 == Tr(X + A); then there exists a solution to L^2 + L = X + A, and + * so a halving is possible, so this point is the double of another. + * + * Note: Tr(A) == 1 for cofactor 2 curves. */ ECPoint N = this.normalize(); ECFieldElement X = N.getAffineXCoord(); - ECFieldElement rhs = X.add(curve.getA()); - return ((ECFieldElement.AbstractF2m)rhs).trace() == 0; + return 0 != ((ECFieldElement.AbstractF2m)X).trace(); } if (ECConstants.FOUR.equals(cofactor)) { /* * Solve L^2 + L = X + A to find the half of this point, if it exists (fail if not). - * Generate both possibilities for the square of the half-point's x-coordinate (w), - * and check if Tr(w + A) == 0 for at least one; then a second halving is possible - * (see comments for cofactor 2 above), so this point is four times another. * - * Note: Tr(x^2) == Tr(x). + * Note: Tr(A) == 0 for cofactor 4 curves. */ ECPoint N = this.normalize(); ECFieldElement X = N.getAffineXCoord(); - ECFieldElement lambda = ((ECCurve.AbstractF2m)curve).solveQuadraticEquation(X.add(curve.getA())); - if (lambda == null) + ECFieldElement L = ((ECCurve.AbstractF2m)curve).solveQuadraticEquation(X.add(curve.getA())); + if (null == L) { return false; } - ECFieldElement w = X.multiply(lambda).add(N.getAffineYCoord()); - ECFieldElement t = w.add(curve.getA()); - return ((ECFieldElement.AbstractF2m)t).trace() == 0 - || ((ECFieldElement.AbstractF2m)(t.add(X))).trace() == 0; + + /* + * A solution exists, therefore 0 == Tr(X + A) == Tr(X). + */ + ECFieldElement Y = N.getAffineYCoord(); + ECFieldElement T = X.multiply(L).add(Y); + + /* + * Either T or (T + X) is the square of a half-point's x coordinate (hx). In either + * case, the half-point can be halved again when 0 == Tr(hx + A). + * + * Note: Tr(hx + A) == Tr(hx) == Tr(hx^2) == Tr(T) == Tr(T + X) + * + * Check that 0 == Tr(T); then there exists a solution to L^2 + L = hx + A, and so a + * second halving is possible and this point is four times some other. + */ + return 0 == ((ECFieldElement.AbstractF2m)T).trace(); } return super.satisfiesOrder(); @@ -1480,7 +1467,7 @@ public abstract class ECPoint ECFieldElement X2 = X.multiply(scale); ECFieldElement L2 = L.add(X).divide(scale).add(X2); - return this.getCurve().createRawPoint(X, L2, this.getRawZCoords(), this.withCompression); // earlier JDK + return this.getCurve().createRawPoint(X, L2, this.getRawZCoords()); // earlier JDK } case ECCurve.COORD_LAMBDA_PROJECTIVE: { @@ -1492,7 +1479,7 @@ public abstract class ECPoint ECFieldElement L2 = L.add(X).add(X2); ECFieldElement Z2 = Z.multiply(scale); - return this.getCurve().createRawPoint(X2, L2, new ECFieldElement[]{ Z2 }, this.withCompression); // earlier JDK + return this.getCurve().createRawPoint(X2, L2, new ECFieldElement[]{ Z2 }); // earlier JDK } default: { @@ -1501,6 +1488,11 @@ public abstract class ECPoint } } + public ECPoint scaleXNegateY(ECFieldElement scale) + { + return scaleX(scale); + } + public ECPoint scaleY(ECFieldElement scale) { if (this.isInfinity()) @@ -1520,7 +1512,7 @@ public abstract class ECPoint // Y is actually Lambda (X + Y/X) here ECFieldElement L2 = L.add(X).multiply(scale).add(X); - return this.getCurve().createRawPoint(X, L2, this.getRawZCoords(), this.withCompression); // earlier JDK + return this.getCurve().createRawPoint(X, L2, this.getRawZCoords()); // earlier JDK } default: { @@ -1529,6 +1521,11 @@ public abstract class ECPoint } } + public ECPoint scaleYNegateX(ECFieldElement scale) + { + return scaleY(scale); + } + public ECPoint subtract(ECPoint b) { if (b.isInfinity()) @@ -1558,14 +1555,14 @@ public abstract class ECPoint case ECCurve.COORD_LAMBDA_AFFINE: { ECFieldElement Y1 = this.y; - return (ECPoint.AbstractF2m)curve.createRawPoint(X1.square(), Y1.square(), this.withCompression); + return (ECPoint.AbstractF2m)curve.createRawPoint(X1.square(), Y1.square()); } case ECCurve.COORD_HOMOGENEOUS: case ECCurve.COORD_LAMBDA_PROJECTIVE: { ECFieldElement Y1 = this.y, Z1 = this.zs[0]; return (ECPoint.AbstractF2m)curve.createRawPoint(X1.square(), Y1.square(), - new ECFieldElement[]{ Z1.square() }, this.withCompression); + new ECFieldElement[]{ Z1.square() }); } default: { @@ -1592,14 +1589,14 @@ public abstract class ECPoint case ECCurve.COORD_LAMBDA_AFFINE: { ECFieldElement Y1 = this.y; - return (ECPoint.AbstractF2m)curve.createRawPoint(X1.squarePow(pow), Y1.squarePow(pow), this.withCompression); + return (ECPoint.AbstractF2m)curve.createRawPoint(X1.squarePow(pow), Y1.squarePow(pow)); } case ECCurve.COORD_HOMOGENEOUS: case ECCurve.COORD_LAMBDA_PROJECTIVE: { ECFieldElement Y1 = this.y, Z1 = this.zs[0]; return (ECPoint.AbstractF2m)curve.createRawPoint(X1.squarePow(pow), Y1.squarePow(pow), - new ECFieldElement[]{ Z1.squarePow(pow) }, this.withCompression); + new ECFieldElement[]{ Z1.squarePow(pow) }); } default: { @@ -1614,52 +1611,23 @@ public abstract class ECPoint */ public static class F2m extends AbstractF2m { - /** - * @param curve base curve - * @param x x point - * @param y y point - * @param withCompression true if encode with point compression. - * - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + F2m(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - if (x != null) - { - // Check if x and y are elements of the same field - ECFieldElement.F2m.checkFieldElements(this.x, this.y); - - // Check if x and a are elements of the same field - if (curve != null) - { - ECFieldElement.F2m.checkFieldElements(this.x, this.curve.getA()); - } - } - - this.withCompression = withCompression; - // checkCurveEquation(); } - F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + F2m(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - this.withCompression = withCompression; - // checkCurveEquation(); } protected ECPoint detach() { - return new ECPoint.F2m(null, this.getAffineXCoord(), this.getAffineYCoord(), false); // earlier JDK + return new ECPoint.F2m(null, this.getAffineXCoord(), this.getAffineYCoord()); // earlier JDK } public ECFieldElement getYCoord() @@ -1762,7 +1730,7 @@ public abstract class ECPoint ECFieldElement X3 = L.square().add(L).add(dx).add(curve.getA()); ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); - return new ECPoint.F2m(curve, X3, Y3, this.withCompression); + return new ECPoint.F2m(curve, X3, Y3); } case ECCurve.COORD_HOMOGENEOUS: { @@ -1799,7 +1767,7 @@ public abstract class ECPoint ECFieldElement Y3 = U.multiplyPlusProduct(X1, V, Y1).multiplyPlusProduct(VSqZ2, uv, A); ECFieldElement Z3 = VCu.multiply(W); - return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } case ECCurve.COORD_LAMBDA_PROJECTIVE: { @@ -1859,7 +1827,7 @@ public abstract class ECPoint X3 = L.square().add(L).add(X1).add(curve.getA()); if (X3.isZero()) { - return new ECPoint.F2m(curve, X3, curve.getB().sqrt(), this.withCompression); + return new ECPoint.F2m(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -1876,7 +1844,7 @@ public abstract class ECPoint X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new ECPoint.F2m(curve, X3, curve.getB().sqrt(), this.withCompression); + return new ECPoint.F2m(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -1894,7 +1862,7 @@ public abstract class ECPoint } } - return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }); } default: { @@ -1932,7 +1900,7 @@ public abstract class ECPoint ECFieldElement X3 = L1.square().add(L1).add(curve.getA()); ECFieldElement Y3 = X1.squarePlusProduct(X3, L1.addOne()); - return new ECPoint.F2m(curve, X3, Y3, this.withCompression); + return new ECPoint.F2m(curve, X3, Y3); } case ECCurve.COORD_HOMOGENEOUS: { @@ -1953,7 +1921,7 @@ public abstract class ECPoint ECFieldElement Y3 = X1Sq.square().multiplyPlusProduct(V, h, sv); ECFieldElement Z3 = V.multiply(vSquared); - return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new ECPoint.F2m(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } case ECCurve.COORD_LAMBDA_PROJECTIVE: { @@ -1967,7 +1935,7 @@ public abstract class ECPoint ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq); if (T.isZero()) { - return new ECPoint.F2m(curve, T, curve.getB().sqrt(), withCompression); + return new ECPoint.F2m(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -2004,7 +1972,7 @@ public abstract class ECPoint L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); } - return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }); } default: { @@ -2072,14 +2040,14 @@ public abstract class ECPoint if (A.isZero()) { - return new ECPoint.F2m(curve, A, curve.getB().sqrt(), withCompression); + return new ECPoint.F2m(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new ECPoint.F2m(curve, X3, L3, new ECFieldElement[]{ Z3 }); } default: { @@ -2106,23 +2074,23 @@ public abstract class ECPoint case ECCurve.COORD_AFFINE: { ECFieldElement Y = this.y; - return new ECPoint.F2m(curve, X, Y.add(X), this.withCompression); + return new ECPoint.F2m(curve, X, Y.add(X)); } case ECCurve.COORD_HOMOGENEOUS: { ECFieldElement Y = this.y, Z = this.zs[0]; - return new ECPoint.F2m(curve, X, Y.add(X), new ECFieldElement[]{ Z }, this.withCompression); + return new ECPoint.F2m(curve, X, Y.add(X), new ECFieldElement[]{ Z }); } case ECCurve.COORD_LAMBDA_AFFINE: { ECFieldElement L = this.y; - return new ECPoint.F2m(curve, X, L.addOne(), this.withCompression); + return new ECPoint.F2m(curve, X, L.addOne()); } case ECCurve.COORD_LAMBDA_PROJECTIVE: { // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new ECPoint.F2m(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new ECPoint.F2m(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } default: { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/FixedPointCombMultiplier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/FixedPointCombMultiplier.java index 40ae302ef..5932217c1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/FixedPointCombMultiplier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/FixedPointCombMultiplier.java @@ -40,8 +40,10 @@ public class FixedPointCombMultiplier extends AbstractECMultiplier for (int j = top - i; j >= 0; j -= d) { + int secretBit = K[j >>> 5] >>> (j & 0x1F); + secretIndex ^= secretBit >>> 1; secretIndex <<= 1; - secretIndex |= Nat.getBit(K, j); + secretIndex ^= secretBit; } ECPoint add = lookupTable.lookup(secretIndex); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/FixedPointUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/FixedPointUtil.java index 1df3598b2..ffd7791a7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/FixedPointUtil.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/FixedPointUtil.java @@ -28,7 +28,7 @@ public class FixedPointUtil FixedPointPreCompInfo existingFP = (existing instanceof FixedPointPreCompInfo) ? (FixedPointPreCompInfo)existing : null; int bits = getCombSize(c); - int minWidth = bits > 257 ? 6 : 5; + int minWidth = bits > 250 ? 6 : 5; int n = 1 << minWidth; if (checkExisting(existingFP, n)) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/GLVMultiplier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/GLVMultiplier.java index f2170b1af..f816d85f0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/GLVMultiplier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/GLVMultiplier.java @@ -2,6 +2,7 @@ package com.fr.third.org.bouncycastle.math.ec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.endo.EndoUtil; import com.fr.third.org.bouncycastle.math.ec.endo.GLVEndomorphism; public class GLVMultiplier extends AbstractECMultiplier @@ -31,12 +32,13 @@ public class GLVMultiplier extends AbstractECMultiplier BigInteger[] ab = glvEndomorphism.decomposeScalar(k.mod(n)); BigInteger a = ab[0], b = ab[1]; - ECPointMap pointMap = glvEndomorphism.getPointMap(); if (glvEndomorphism.hasEfficientPointMap()) { - return ECAlgorithms.implShamirsTrickWNaf(p, a, pointMap, b); + return ECAlgorithms.implShamirsTrickWNaf(glvEndomorphism, p, a, b); } - return ECAlgorithms.implShamirsTrickWNaf(p, a, pointMap.map(p), b); + ECPoint q = EndoUtil.mapPoint(glvEndomorphism, p); + + return ECAlgorithms.implShamirsTrickWNaf(p, a, q, b); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ScaleXNegateYPointMap.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ScaleXNegateYPointMap.java new file mode 100644 index 000000000..492be623d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ScaleXNegateYPointMap.java @@ -0,0 +1,16 @@ +package com.fr.third.org.bouncycastle.math.ec; + +public class ScaleXNegateYPointMap implements ECPointMap +{ + protected final ECFieldElement scale; + + public ScaleXNegateYPointMap(ECFieldElement scale) + { + this.scale = scale; + } + + public ECPoint map(ECPoint p) + { + return p.scaleXNegateY(scale); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ScaleYNegateXPointMap.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ScaleYNegateXPointMap.java new file mode 100644 index 000000000..ac22e9844 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/ScaleYNegateXPointMap.java @@ -0,0 +1,16 @@ +package com.fr.third.org.bouncycastle.math.ec; + +public class ScaleYNegateXPointMap implements ECPointMap +{ + protected final ECFieldElement scale; + + public ScaleYNegateXPointMap(ECFieldElement scale) + { + this.scale = scale; + } + + public ECPoint map(ECPoint p) + { + return p.scaleYNegateX(scale); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/SimpleLookupTable.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/SimpleLookupTable.java index 118dfac4a..f1184b7da 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/SimpleLookupTable.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/SimpleLookupTable.java @@ -1,7 +1,7 @@ package com.fr.third.org.bouncycastle.math.ec; public class SimpleLookupTable - implements ECLookupTable + extends AbstractECLookupTable { private static ECPoint[] copy(ECPoint[] points, int off, int len) { @@ -12,7 +12,7 @@ public class SimpleLookupTable } return result; } - + private final ECPoint[] points; public SimpleLookupTable(ECPoint[] points, int off, int len) @@ -26,6 +26,11 @@ public class SimpleLookupTable } public ECPoint lookup(int index) + { + throw new UnsupportedOperationException("Constant-time lookup not supported"); + } + + public ECPoint lookupVar(int index) { return points[index]; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafL2RMultiplier.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafL2RMultiplier.java index 2e5dd5a8e..fad8ab41a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafL2RMultiplier.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafL2RMultiplier.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.util.Integers; + /** * Class implementing the WNAF (Window Non-Adjacent Form) multiplication * algorithm. @@ -17,12 +19,12 @@ public class WNafL2RMultiplier extends AbstractECMultiplier */ protected ECPoint multiplyPositive(ECPoint p, BigInteger k) { - // Clamp the window width in the range [2, 16] - int width = Math.max(2, Math.min(16, getWindowSize(k.bitLength()))); + int minWidth = WNafUtil.getWindowSize(k.bitLength()); - WNafPreCompInfo wnafPreCompInfo = WNafUtil.precompute(p, width, true); - ECPoint[] preComp = wnafPreCompInfo.getPreComp(); - ECPoint[] preCompNeg = wnafPreCompInfo.getPreCompNeg(); + WNafPreCompInfo info = WNafUtil.precompute(p, minWidth, true); + ECPoint[] preComp = info.getPreComp(); + ECPoint[] preCompNeg = info.getPreCompNeg(); + int width = info.getWidth(); int[] wnaf = WNafUtil.generateCompactWindowNaf(width, k); @@ -45,7 +47,7 @@ public class WNafL2RMultiplier extends AbstractECMultiplier // Optimization can only be used for values in the lower half of the table if ((n << 2) < (1 << width)) { - int highest = LongArray.bitLengths[n]; + int highest = 32 - Integers.numberOfLeadingZeros(n); // TODO Get addition/doubling cost ratio from curve and compare to 'scale' to see if worth substituting? int scale = width - highest; @@ -82,15 +84,4 @@ public class WNafL2RMultiplier extends AbstractECMultiplier return R; } - - /** - * Determine window width to use for a scalar multiplication of the given size. - * - * @param bits the bit-length of the scalar to multiply by - * @return the window size to use - */ - protected int getWindowSize(int bits) - { - return WNafUtil.getWindowSize(bits); - } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafPreCompInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafPreCompInfo.java index 6641162c8..fe05c7e05 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafPreCompInfo.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafPreCompInfo.java @@ -6,6 +6,10 @@ package com.fr.third.org.bouncycastle.math.ec; */ public class WNafPreCompInfo implements PreCompInfo { + volatile int promotionCountdown = 4; + + protected int confWidth = -1; + /** * Array holding the precomputed ECPoints used for a Window * NAF multiplication. @@ -24,6 +28,43 @@ public class WNafPreCompInfo implements PreCompInfo */ protected ECPoint twice = null; + protected int width = -1; + + int decrementPromotionCountdown() + { + int t = promotionCountdown; + if (t > 0) + { + promotionCountdown = --t; + } + return t; + } + + int getPromotionCountdown() + { + return promotionCountdown; + } + + void setPromotionCountdown(int promotionCountdown) + { + this.promotionCountdown = promotionCountdown; + } + + public boolean isPromoted() + { + return promotionCountdown <= 0; + } + + public int getConfWidth() + { + return confWidth; + } + + public void setConfWidth(int confWidth) + { + this.confWidth = confWidth; + } + public ECPoint[] getPreComp() { return preComp; @@ -53,4 +94,14 @@ public class WNafPreCompInfo implements PreCompInfo { this.twice = twice; } + + public int getWidth() + { + return width; + } + + public void setWidth(int width) + { + this.width = width; + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafUtil.java index 9f78f2400..d1aa5112e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafUtil.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/WNafUtil.java @@ -7,11 +7,54 @@ public abstract class WNafUtil public static final String PRECOMP_NAME = "bc_wnaf"; private static final int[] DEFAULT_WINDOW_SIZE_CUTOFFS = new int[]{ 13, 41, 121, 337, 897, 2305 }; + private static final int MAX_WIDTH = 16; private static final byte[] EMPTY_BYTES = new byte[0]; private static final int[] EMPTY_INTS = new int[0]; private static final ECPoint[] EMPTY_POINTS = new ECPoint[0]; + public static void configureBasepoint(ECPoint p) + { + final ECCurve c = p.getCurve(); + if (null == c) + { + return; + } + + BigInteger n = c.getOrder(); + int bits = (null == n) ? c.getFieldSize() + 1 : n.bitLength(); + final int confWidth = Math.min(MAX_WIDTH, getWindowSize(bits) + 3); + + c.precompute(p, PRECOMP_NAME, new PreCompCallback() + { + public PreCompInfo precompute(PreCompInfo existing) + { + WNafPreCompInfo existingWNaf = (existing instanceof WNafPreCompInfo) ? (WNafPreCompInfo)existing : null; + + if (null != existingWNaf && existingWNaf.getConfWidth() == confWidth) + { + existingWNaf.setPromotionCountdown(0); + return existingWNaf; + } + + WNafPreCompInfo result = new WNafPreCompInfo(); + + result.setPromotionCountdown(0); + result.setConfWidth(confWidth); + + if (null != existingWNaf) + { + result.setPreComp(existingWNaf.getPreComp()); + result.setPreCompNeg(existingWNaf.getPreCompNeg()); + result.setTwice(existingWNaf.getTwice()); + result.setWidth(existingWNaf.getWidth()); + } + + return result; + } + }); + } + public static int[] generateCompactNaf(BigInteger k) { if ((k.bitLength() >>> 16) != 0) @@ -315,7 +358,19 @@ public abstract class WNafUtil */ public static int getWindowSize(int bits) { - return getWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS); + return getWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS, MAX_WIDTH); + } + + /** + * Determine window width to use for a scalar multiplication of the given size. + * + * @param bits the bit-length of the scalar to multiply by + * @param maxWidth the maximum window width to return + * @return the window size to use + */ + public static int getWindowSize(int bits, int maxWidth) + { + return getWindowSize(bits, DEFAULT_WINDOW_SIZE_CUTOFFS, maxWidth); } /** @@ -326,6 +381,19 @@ public abstract class WNafUtil * @return the window size to use */ public static int getWindowSize(int bits, int[] windowSizeCutoffs) + { + return getWindowSize(bits, windowSizeCutoffs, MAX_WIDTH); + } + + /** + * Determine window width to use for a scalar multiplication of the given size. + * + * @param bits the bit-length of the scalar to multiply by + * @param windowSizeCutoffs a monotonically increasing list of bit sizes at which to increment the window width + * @param maxWidth the maximum window width to return + * @return the window size to use + */ + public static int getWindowSize(int bits, int[] windowSizeCutoffs, int maxWidth) { int w = 0; for (; w < windowSizeCutoffs.length; ++w) @@ -335,14 +403,18 @@ public abstract class WNafUtil break; } } - return w + 2; + + return Math.max(2, Math.min(maxWidth, w + 2)); } - public static ECPoint mapPointWithPrecomp(ECPoint p, final int width, final boolean includeNegated, + /** + * @deprecated + */ + public static ECPoint mapPointWithPrecomp(ECPoint p, final int minWidth, final boolean includeNegated, final ECPointMap pointMap) { final ECCurve c = p.getCurve(); - final WNafPreCompInfo wnafPreCompP = precompute(p, width, includeNegated); + final WNafPreCompInfo infoP = precompute(p, minWidth, includeNegated); ECPoint q = pointMap.map(p); c.precompute(q, PRECOMP_NAME, new PreCompCallback() @@ -351,20 +423,23 @@ public abstract class WNafUtil { WNafPreCompInfo result = new WNafPreCompInfo(); - ECPoint twiceP = wnafPreCompP.getTwice(); - if (twiceP != null) + result.setConfWidth(infoP.getConfWidth()); + + ECPoint twiceP = infoP.getTwice(); + if (null != twiceP) { ECPoint twiceQ = pointMap.map(twiceP); result.setTwice(twiceQ); } - ECPoint[] preCompP = wnafPreCompP.getPreComp(); + ECPoint[] preCompP = infoP.getPreComp(); ECPoint[] preCompQ = new ECPoint[preCompP.length]; for (int i = 0; i < preCompP.length; ++i) { preCompQ[i] = pointMap.map(preCompP[i]); } result.setPreComp(preCompQ); + result.setWidth(infoP.getWidth()); if (includeNegated) { @@ -383,7 +458,7 @@ public abstract class WNafUtil return q; } - public static WNafPreCompInfo precompute(final ECPoint p, final int width, final boolean includeNegated) + public static WNafPreCompInfo precompute(final ECPoint p, final int minWidth, final boolean includeNegated) { final ECCurve c = p.getCurve(); @@ -393,25 +468,38 @@ public abstract class WNafUtil { WNafPreCompInfo existingWNaf = (existing instanceof WNafPreCompInfo) ? (WNafPreCompInfo)existing : null; - int reqPreCompLen = 1 << Math.max(0, width - 2); + int width = Math.max(2, Math.min(MAX_WIDTH, minWidth)); + int reqPreCompLen = 1 << (width - 2); - if (checkExisting(existingWNaf, reqPreCompLen, includeNegated)) + if (checkExisting(existingWNaf, width, reqPreCompLen, includeNegated)) { + existingWNaf.decrementPromotionCountdown(); return existingWNaf; } + WNafPreCompInfo result = new WNafPreCompInfo(); + ECPoint[] preComp = null, preCompNeg = null; ECPoint twiceP = null; - if (existingWNaf != null) + if (null != existingWNaf) { + int promotionCountdown = existingWNaf.decrementPromotionCountdown(); + result.setPromotionCountdown(promotionCountdown); + + int confWidth = existingWNaf.getConfWidth(); + result.setConfWidth(confWidth); + preComp = existingWNaf.getPreComp(); preCompNeg = existingWNaf.getPreCompNeg(); twiceP = existingWNaf.getTwice(); } + width = Math.min(MAX_WIDTH, Math.max(result.getConfWidth(), width)); + reqPreCompLen = 1 << (width - 2); + int iniPreCompLen = 0; - if (preComp == null) + if (null == preComp) { preComp = EMPTY_POINTS; } @@ -446,7 +534,7 @@ public abstract class WNafUtil else { ECPoint isoTwiceP = twiceP, last = preComp[curPreCompLen - 1]; - if (isoTwiceP == null) + if (null == isoTwiceP) { isoTwiceP = preComp[0].twice(); twiceP = isoTwiceP; @@ -506,7 +594,7 @@ public abstract class WNafUtil if (includeNegated) { int pos; - if (preCompNeg == null) + if (null == preCompNeg) { pos = 0; preCompNeg = new ECPoint[reqPreCompLen]; @@ -527,23 +615,96 @@ public abstract class WNafUtil } } - WNafPreCompInfo result = new WNafPreCompInfo(); result.setPreComp(preComp); result.setPreCompNeg(preCompNeg); result.setTwice(twiceP); + result.setWidth(width); + return result; + } + + private boolean checkExisting(WNafPreCompInfo existingWNaf, int width, int reqPreCompLen, boolean includeNegated) + { + return null != existingWNaf + && existingWNaf.getWidth() >= Math.max(existingWNaf.getConfWidth(), width) + && checkTable(existingWNaf.getPreComp(), reqPreCompLen) + && (!includeNegated || checkTable(existingWNaf.getPreCompNeg(), reqPreCompLen)); + } + + private boolean checkTable(ECPoint[] table, int reqLen) + { + return null != table && table.length >= reqLen; + } + }); + } + + public static WNafPreCompInfo precomputeWithPointMap(final ECPoint p, final ECPointMap pointMap, final WNafPreCompInfo fromWNaf, + final boolean includeNegated) + { + final ECCurve c = p.getCurve(); + + return (WNafPreCompInfo)c.precompute(p, PRECOMP_NAME, new PreCompCallback() + { + public PreCompInfo precompute(PreCompInfo existing) + { + WNafPreCompInfo existingWNaf = (existing instanceof WNafPreCompInfo) ? (WNafPreCompInfo)existing : null; + + int width = fromWNaf.getWidth(); + int reqPreCompLen = fromWNaf.getPreComp().length; + + if (checkExisting(existingWNaf, width, reqPreCompLen, includeNegated)) + { + existingWNaf.decrementPromotionCountdown(); + return existingWNaf; + } + + /* + * TODO Ideally this method would support incremental calculation, but given the + * existing use-cases it would be of little-to-no benefit. + */ + WNafPreCompInfo result = new WNafPreCompInfo(); + + result.setPromotionCountdown(fromWNaf.getPromotionCountdown()); + + ECPoint twiceFrom = fromWNaf.getTwice(); + if (null != twiceFrom) + { + ECPoint twice = pointMap.map(twiceFrom); + result.setTwice(twice); + } + + ECPoint[] preCompFrom = fromWNaf.getPreComp(); + ECPoint[] preComp = new ECPoint[preCompFrom.length]; + for (int i = 0; i < preCompFrom.length; ++i) + { + preComp[i] = pointMap.map(preCompFrom[i]); + } + result.setPreComp(preComp); + result.setWidth(width); + + if (includeNegated) + { + ECPoint[] preCompNeg = new ECPoint[preComp.length]; + for (int i = 0; i < preCompNeg.length; ++i) + { + preCompNeg[i] = preComp[i].negate(); + } + result.setPreCompNeg(preCompNeg); + } + return result; } - private boolean checkExisting(WNafPreCompInfo existingWNaf, int reqPreCompLen, boolean includeNegated) + private boolean checkExisting(WNafPreCompInfo existingWNaf, int width, int reqPreCompLen, boolean includeNegated) { - return existingWNaf != null + return null != existingWNaf + && existingWNaf.getWidth() >= width && checkTable(existingWNaf.getPreComp(), reqPreCompLen) && (!includeNegated || checkTable(existingWNaf.getPreCompNeg(), reqPreCompLen)); } private boolean checkTable(ECPoint[] table, int reqLen) { - return table != null && table.length >= reqLen; + return null != table && table.length >= reqLen; } }); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519.java index 26026525b..86392da8a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.djb; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; @@ -11,9 +13,14 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class Curve25519 extends ECCurve.AbstractFp { - public static final BigInteger q = Nat256.toBigInteger(Curve25519Field.P); + public static final BigInteger q = Curve25519FieldElement.Q; - private static final int Curve25519_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED; + private static final BigInteger C_a = new BigInteger(1, Hex.decodeStrict("2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA984914A144")); + private static final BigInteger C_b = new BigInteger(1, Hex.decodeStrict("7B425ED097B425ED097B425ED097B425ED097B425ED097B4260B5E9C7710C864")); + + private static final int CURVE25519_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED; + private static final ECFieldElement[] CURVE25519_AFFINE_ZS = new ECFieldElement[] { + new Curve25519FieldElement(ECConstants.ONE), new Curve25519FieldElement(C_a) }; protected Curve25519Point infinity; @@ -23,14 +30,12 @@ public class Curve25519 extends ECCurve.AbstractFp this.infinity = new Curve25519Point(this, null, null); - this.a = fromBigInteger(new BigInteger(1, - Hex.decode("2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA984914A144"))); - this.b = fromBigInteger(new BigInteger(1, - Hex.decode("7B425ED097B425ED097B425ED097B425ED097B425ED097B4260B5E9C7710C864"))); - this.order = new BigInteger(1, Hex.decode("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED")); + this.a = fromBigInteger(C_a); + this.b = fromBigInteger(C_b); + this.order = new BigInteger(1, Hex.decodeStrict("1000000000000000000000000000000014DEF9DEA2F79CD65812631A5CF5D3ED")); this.cofactor = BigInteger.valueOf(8); - this.coord = Curve25519_DEFAULT_COORDS; + this.coord = CURVE25519_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -64,14 +69,14 @@ public class Curve25519 extends ECCurve.AbstractFp return new Curve25519FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new Curve25519Point(this, x, y, withCompression); + return new Curve25519Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new Curve25519Point(this, x, y, zs, withCompression); + return new Curve25519Point(this, x, y, zs); } public ECPoint getInfinity() @@ -94,7 +99,7 @@ public class Curve25519 extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -119,7 +124,26 @@ public class Curve25519 extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new Curve25519FieldElement(x), new Curve25519FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat256.create(), y = Nat256.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new Curve25519FieldElement(x), new Curve25519FieldElement(y), CURVE25519_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java index ac39fe80a..d244ee653 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519FieldElement.java @@ -9,7 +9,7 @@ import com.fr.third.org.bouncycastle.util.Arrays; public class Curve25519FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = Curve25519.q; + public static final BigInteger Q = Nat256.toBigInteger(Curve25519Field.P); // Calculated as ECConstants.TWO.modPow(Q.shiftRight(2), Q) private static final int[] PRECOMP_POW2 = new int[]{ 0x4a0ea0b0, 0xc4ee1b27, 0xad2fe478, 0x2f431806, diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java index a3ff53abc..4daf6dc2a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/djb/Curve25519Point.java @@ -7,47 +7,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat256; public class Curve25519Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve the curve to use - * @param x affine x co-ordinate - * @param y affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve the curve to use - * @param x affine x co-ordinate - * @param y affine y co-ordinate - * @param withCompression if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + Curve25519Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -191,7 +158,7 @@ public class Curve25519Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[]{ Z3, W3 }; - return new Curve25519Point(curve, X3, Y3, zs, this.withCompression); + return new Curve25519Point(curve, X3, Y3, zs); } public ECPoint twice() @@ -259,7 +226,7 @@ public class Curve25519Point extends ECPoint.AbstractFp return this; } - return new Curve25519Point(this.getCurve(), this.x, this.y.negate(), this.zs, this.withCompression); + return new Curve25519Point(this.getCurve(), this.x, this.y.negate(), this.zs); } protected Curve25519FieldElement calculateJacobianModifiedW(Curve25519FieldElement Z, int[] ZSquared) @@ -343,6 +310,6 @@ public class Curve25519Point extends ECPoint.AbstractFp Curve25519Field.twice(W3.x, W3.x); } - return new Curve25519Point(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }, this.withCompression); + return new Curve25519Point(this.getCurve(), X3, Y3, new ECFieldElement[]{ Z3, W3 }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1Curve.java index 8d02e0c32..7f7a405f0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.gm; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; @@ -11,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SM2P256V1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF")); + public static final BigInteger q = SM2P256V1FieldElement.Q; private static final int SM2P256V1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SM2P256V1_AFFINE_ZS = new ECFieldElement[] { new SM2P256V1FieldElement(ECConstants.ONE) }; protected SM2P256V1Point infinity; @@ -25,10 +27,10 @@ public class SM2P256V1Curve extends ECCurve.AbstractFp this.infinity = new SM2P256V1Point(this, null, null); this.a = fromBigInteger(new BigInteger(1, - Hex.decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"))); + Hex.decodeStrict("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFC"))); this.b = fromBigInteger(new BigInteger(1, - Hex.decode("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"))); - this.order = new BigInteger(1, Hex.decode("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123")); + Hex.decodeStrict("28E9FA9E9D9F5E344D5A9E4BCF6509A7F39789F515AB8F92DDBCBD414D940E93"))); + this.order = new BigInteger(1, Hex.decodeStrict("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFF7203DF6B21C6052B53BBF40939D54123")); this.cofactor = BigInteger.valueOf(1); this.coord = SM2P256V1_DEFAULT_COORDS; @@ -65,14 +67,14 @@ public class SM2P256V1Curve extends ECCurve.AbstractFp return new SM2P256V1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SM2P256V1Point(this, x, y, withCompression); + return new SM2P256V1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SM2P256V1Point(this, x, y, zs, withCompression); + return new SM2P256V1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -95,7 +97,7 @@ public class SM2P256V1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -120,7 +122,26 @@ public class SM2P256V1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SM2P256V1FieldElement(x), new SM2P256V1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat256.create(), y = Nat256.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SM2P256V1FieldElement(x), new SM2P256V1FieldElement(y), SM2P256V1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1FieldElement.java index 501b24060..d63d72c2e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat256; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SM2P256V1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SM2P256V1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000FFFFFFFFFFFFFFFF")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1Point.java index 16bdfa6a8..5f424ede2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/gm/SM2P256V1Point.java @@ -8,55 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat256; public class SM2P256V1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SM2P256V1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -186,7 +145,7 @@ public class SM2P256V1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; - return new SM2P256V1Point(curve, X3, Y3, zs, this.withCompression); + return new SM2P256V1Point(curve, X3, Y3, zs); } public ECPoint twice() @@ -258,7 +217,7 @@ public class SM2P256V1Point extends ECPoint.AbstractFp SM2P256V1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SM2P256V1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SM2P256V1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -303,6 +262,6 @@ public class SM2P256V1Point extends ECPoint.AbstractFp return this; } - return new SM2P256V1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SM2P256V1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Curve.java index c05bf61f2..7fe5823a1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; @@ -11,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP128R1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF")); + public static final BigInteger q = SecP128R1FieldElement.Q; - private static final int SecP128R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final int SECP128R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP128R1_AFFINE_ZS = new ECFieldElement[] { new SecP128R1FieldElement(ECConstants.ONE) }; protected SecP128R1Point infinity; @@ -25,13 +27,13 @@ public class SecP128R1Curve extends ECCurve.AbstractFp this.infinity = new SecP128R1Point(this, null, null); this.a = fromBigInteger(new BigInteger(1, - Hex.decode("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC"))); + Hex.decodeStrict("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC"))); this.b = fromBigInteger(new BigInteger(1, - Hex.decode("E87579C11079F43DD824993C2CEE5ED3"))); - this.order = new BigInteger(1, Hex.decode("FFFFFFFE0000000075A30D1B9038A115")); + Hex.decodeStrict("E87579C11079F43DD824993C2CEE5ED3"))); + this.order = new BigInteger(1, Hex.decodeStrict("FFFFFFFE0000000075A30D1B9038A115")); this.cofactor = BigInteger.valueOf(1); - this.coord = SecP128R1_DEFAULT_COORDS; + this.coord = SECP128R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -65,14 +67,14 @@ public class SecP128R1Curve extends ECCurve.AbstractFp return new SecP128R1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP128R1Point(this, x, y, withCompression); + return new SecP128R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP128R1Point(this, x, y, zs, withCompression); + return new SecP128R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -95,7 +97,7 @@ public class SecP128R1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -120,7 +122,26 @@ public class SecP128R1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP128R1FieldElement(x), new SecP128R1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat128.create(), y = Nat128.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP128R1FieldElement(x), new SecP128R1FieldElement(y), SECP128R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Field.java index a2d564cba..95644b2a9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Field.java @@ -137,6 +137,11 @@ public class SecP128R1Field x = (int)c; } + + if ((z[3] >>> 1) >= P3s1 && Nat128.gte(z, P)) + { + addPInvTo(z); + } } public static void square(int[] x, int[] z) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1FieldElement.java index 9736dbbf8..5f513249c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat128; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP128R1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP128R1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Point.java index a69dd931b..e790ec2c1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP128R1Point.java @@ -8,55 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat128; public class SecP128R1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecP128R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -186,7 +145,7 @@ public class SecP128R1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; - return new SecP128R1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP128R1Point(curve, X3, Y3, zs); } public ECPoint twice() @@ -258,7 +217,7 @@ public class SecP128R1Point extends ECPoint.AbstractFp SecP128R1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP128R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecP128R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -303,6 +262,6 @@ public class SecP128R1Point extends ECPoint.AbstractFp return this; } - return new SecP128R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP128R1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160K1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160K1Curve.java index 35653289f..47ec5bcd3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160K1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160K1Curve.java @@ -2,6 +2,7 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -12,9 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP160K1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = SecP160R2Curve.q; + public static final BigInteger q = SecP160R2FieldElement.Q; private static final int SECP160K1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP160K1_AFFINE_ZS = new ECFieldElement[] { new SecP160R2FieldElement(ECConstants.ONE) }; protected SecP160K1Point infinity; @@ -26,7 +28,7 @@ public class SecP160K1Curve extends ECCurve.AbstractFp this.a = fromBigInteger(ECConstants.ZERO); this.b = fromBigInteger(BigInteger.valueOf(7)); - this.order = new BigInteger(1, Hex.decode("0100000000000000000001B8FA16DFAB9ACA16B6B3")); + this.order = new BigInteger(1, Hex.decodeStrict("0100000000000000000001B8FA16DFAB9ACA16B6B3")); this.cofactor = BigInteger.valueOf(1); this.coord = SECP160K1_DEFAULT_COORDS; } @@ -62,14 +64,14 @@ public class SecP160K1Curve extends ECCurve.AbstractFp return new SecP160R2FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP160K1Point(this, x, y, withCompression); + return new SecP160K1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP160K1Point(this, x, y, zs, withCompression); + return new SecP160K1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -92,7 +94,7 @@ public class SecP160K1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -117,7 +119,26 @@ public class SecP160K1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP160R2FieldElement(x), new SecP160R2FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat160.create(), y = Nat160.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP160R2FieldElement(x), new SecP160R2FieldElement(y), SECP160K1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160K1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160K1Point.java index 4e3ad0eda..4b08ebc83 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160K1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160K1Point.java @@ -8,56 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat160; public class SecP160K1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, - boolean withCompression) + SecP160K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -188,7 +146,7 @@ public class SecP160K1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[] { Z3 }; - return new SecP160K1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP160K1Point(curve, X3, Y3, zs); } // B.3 pg 62 @@ -248,7 +206,7 @@ public class SecP160K1Point extends ECPoint.AbstractFp SecP160R2Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP160K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression); + return new SecP160K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -293,6 +251,6 @@ public class SecP160K1Point extends ECPoint.AbstractFp return this; } - return new SecP160K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP160K1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1Curve.java index 7f4eedd56..8c4d8d270 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; @@ -11,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP160R1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF")); + public static final BigInteger q = SecP160R1FieldElement.Q; - private static final int SecP160R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final int SECP160R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP160R1_AFFINE_ZS = new ECFieldElement[] { new SecP160R1FieldElement(ECConstants.ONE) }; protected SecP160R1Point infinity; @@ -25,13 +27,13 @@ public class SecP160R1Curve extends ECCurve.AbstractFp this.infinity = new SecP160R1Point(this, null, null); this.a = fromBigInteger(new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC"))); + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC"))); this.b = fromBigInteger(new BigInteger(1, - Hex.decode("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45"))); - this.order = new BigInteger(1, Hex.decode("0100000000000000000001F4C8F927AED3CA752257")); + Hex.decodeStrict("1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45"))); + this.order = new BigInteger(1, Hex.decodeStrict("0100000000000000000001F4C8F927AED3CA752257")); this.cofactor = BigInteger.valueOf(1); - this.coord = SecP160R1_DEFAULT_COORDS; + this.coord = SECP160R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -65,14 +67,14 @@ public class SecP160R1Curve extends ECCurve.AbstractFp return new SecP160R1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP160R1Point(this, x, y, withCompression); + return new SecP160R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP160R1Point(this, x, y, zs, withCompression); + return new SecP160R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -95,7 +97,7 @@ public class SecP160R1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -120,7 +122,26 @@ public class SecP160R1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP160R1FieldElement(x), new SecP160R1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat160.create(), y = Nat160.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP160R1FieldElement(x), new SecP160R1FieldElement(y), SECP160R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1FieldElement.java index b63bfb893..336e895c2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat160; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP160R1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP160R1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1Point.java index 2225cf2bb..4c9265f1a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R1Point.java @@ -8,55 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat160; public class SecP160R1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecP160R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -186,7 +145,7 @@ public class SecP160R1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; - return new SecP160R1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP160R1Point(curve, X3, Y3, zs); } public ECPoint twice() @@ -258,7 +217,7 @@ public class SecP160R1Point extends ECPoint.AbstractFp SecP160R1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP160R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecP160R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -303,6 +262,6 @@ public class SecP160R1Point extends ECPoint.AbstractFp return this; } - return new SecP160R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP160R1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2Curve.java index 70dfcc4fd..21d6e7bdf 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; @@ -11,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP160R2Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73")); + public static final BigInteger q = SecP160R2FieldElement.Q; - private static final int SecP160R2_DEFAULT_COORDS = COORD_JACOBIAN; + private static final int SECP160R2_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP160R2_AFFINE_ZS = new ECFieldElement[] { new SecP160R2FieldElement(ECConstants.ONE) }; protected SecP160R2Point infinity; @@ -25,13 +27,13 @@ public class SecP160R2Curve extends ECCurve.AbstractFp this.infinity = new SecP160R2Point(this, null, null); this.a = fromBigInteger(new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70"))); + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70"))); this.b = fromBigInteger(new BigInteger(1, - Hex.decode("B4E134D3FB59EB8BAB57274904664D5AF50388BA"))); - this.order = new BigInteger(1, Hex.decode("0100000000000000000000351EE786A818F3A1A16B")); + Hex.decodeStrict("B4E134D3FB59EB8BAB57274904664D5AF50388BA"))); + this.order = new BigInteger(1, Hex.decodeStrict("0100000000000000000000351EE786A818F3A1A16B")); this.cofactor = BigInteger.valueOf(1); - this.coord = SecP160R2_DEFAULT_COORDS; + this.coord = SECP160R2_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -65,14 +67,14 @@ public class SecP160R2Curve extends ECCurve.AbstractFp return new SecP160R2FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP160R2Point(this, x, y, withCompression); + return new SecP160R2Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP160R2Point(this, x, y, zs, withCompression); + return new SecP160R2Point(this, x, y, zs); } public ECPoint getInfinity() @@ -95,7 +97,7 @@ public class SecP160R2Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -120,7 +122,26 @@ public class SecP160R2Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP160R2FieldElement(x), new SecP160R2FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat160.create(), y = Nat160.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP160R2FieldElement(x), new SecP160R2FieldElement(y), SECP160R2_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2FieldElement.java index 40735c718..238d11adf 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat160; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP160R2FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP160R2Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2Point.java index 83930016e..95e6fc646 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP160R2Point.java @@ -8,55 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat160; public class SecP160R2Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecP160R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -186,7 +145,7 @@ public class SecP160R2Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; - return new SecP160R2Point(curve, X3, Y3, zs, this.withCompression); + return new SecP160R2Point(curve, X3, Y3, zs); } public ECPoint twice() @@ -258,7 +217,7 @@ public class SecP160R2Point extends ECPoint.AbstractFp SecP160R2Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP160R2Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecP160R2Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -303,6 +262,6 @@ public class SecP160R2Point extends ECPoint.AbstractFp return this; } - return new SecP160R2Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP160R2Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java index 81d006df8..a4334dd6f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1Curve.java @@ -2,6 +2,7 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -12,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP192K1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37")); + public static final BigInteger q = SecP192K1FieldElement.Q; - private static final int SecP192K1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final int SECP192K1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP192K1_AFFINE_ZS = new ECFieldElement[] { new SecP192K1FieldElement(ECConstants.ONE) }; protected SecP192K1Point infinity; @@ -27,10 +28,10 @@ public class SecP192K1Curve extends ECCurve.AbstractFp this.a = fromBigInteger(ECConstants.ZERO); this.b = fromBigInteger(BigInteger.valueOf(3)); - this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D")); + this.order = new BigInteger(1, Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D")); this.cofactor = BigInteger.valueOf(1); - this.coord = SecP192K1_DEFAULT_COORDS; + this.coord = SECP192K1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -64,14 +65,14 @@ public class SecP192K1Curve extends ECCurve.AbstractFp return new SecP192K1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP192K1Point(this, x, y, withCompression); + return new SecP192K1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP192K1Point(this, x, y, zs, withCompression); + return new SecP192K1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -94,7 +95,7 @@ public class SecP192K1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -119,7 +120,26 @@ public class SecP192K1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP192K1FieldElement(x), new SecP192K1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat192.create(), y = Nat192.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP192K1FieldElement(x), new SecP192K1FieldElement(y), SECP192K1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java index 5c79a6f58..3f3e32676 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat192; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP192K1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP192K1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java index f3f9ca06f..1965fe105 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192K1Point.java @@ -8,56 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat192; public class SecP192K1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, - boolean withCompression) + SecP192K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -188,7 +146,7 @@ public class SecP192K1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[] { Z3 }; - return new SecP192K1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP192K1Point(curve, X3, Y3, zs); } // B.3 pg 62 @@ -248,7 +206,7 @@ public class SecP192K1Point extends ECPoint.AbstractFp SecP192K1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP192K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression); + return new SecP192K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -293,6 +251,6 @@ public class SecP192K1Point extends ECPoint.AbstractFp return this; } - return new SecP192K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP192K1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java index 00f99e63e..b2615b750 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; @@ -11,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP192R1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF")); + public static final BigInteger q = SecP192R1FieldElement.Q; - private static final int SecP192R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final int SECP192R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP192R1_AFFINE_ZS = new ECFieldElement[] { new SecP192R1FieldElement(ECConstants.ONE) }; protected SecP192R1Point infinity; @@ -25,13 +27,13 @@ public class SecP192R1Curve extends ECCurve.AbstractFp this.infinity = new SecP192R1Point(this, null, null); this.a = fromBigInteger(new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC"))); + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC"))); this.b = fromBigInteger(new BigInteger(1, - Hex.decode("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"))); - this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831")); + Hex.decodeStrict("64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1"))); + this.order = new BigInteger(1, Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831")); this.cofactor = BigInteger.valueOf(1); - this.coord = SecP192R1_DEFAULT_COORDS; + this.coord = SECP192R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -65,14 +67,14 @@ public class SecP192R1Curve extends ECCurve.AbstractFp return new SecP192R1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP192R1Point(this, x, y, withCompression); + return new SecP192R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP192R1Point(this, x, y, zs, withCompression); + return new SecP192R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -95,7 +97,7 @@ public class SecP192R1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -120,7 +122,26 @@ public class SecP192R1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP192R1FieldElement(x), new SecP192R1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat192.create(), y = Nat192.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP192R1FieldElement(x), new SecP192R1FieldElement(y), SECP192R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java index c71eeff05..a86af15f8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat192; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP192R1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP192R1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java index 0d3774a38..d0852b4cd 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP192R1Point.java @@ -8,55 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat192; public class SecP192R1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecP192R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -187,7 +146,7 @@ public class SecP192R1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; - return new SecP192R1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP192R1Point(curve, X3, Y3, zs); } // B.3 pg 62 @@ -260,7 +219,7 @@ public class SecP192R1Point extends ECPoint.AbstractFp SecP192R1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP192R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecP192R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -305,6 +264,6 @@ public class SecP192R1Point extends ECPoint.AbstractFp return this; } - return new SecP192R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP192R1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java index 5ebda3d64..169f887ee 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1Curve.java @@ -2,6 +2,7 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -12,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP224K1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D")); + public static final BigInteger q = SecP224K1FieldElement.Q; private static final int SECP224K1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP224K1_AFFINE_ZS = new ECFieldElement[] { new SecP224K1FieldElement(ECConstants.ONE) }; protected SecP224K1Point infinity; @@ -27,7 +28,7 @@ public class SecP224K1Curve extends ECCurve.AbstractFp this.a = fromBigInteger(ECConstants.ZERO); this.b = fromBigInteger(BigInteger.valueOf(5)); - this.order = new BigInteger(1, Hex.decode("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7")); + this.order = new BigInteger(1, Hex.decodeStrict("010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7")); this.cofactor = BigInteger.valueOf(1); this.coord = SECP224K1_DEFAULT_COORDS; } @@ -63,14 +64,14 @@ public class SecP224K1Curve extends ECCurve.AbstractFp return new SecP224K1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP224K1Point(this, x, y, withCompression); + return new SecP224K1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP224K1Point(this, x, y, zs, withCompression); + return new SecP224K1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -93,7 +94,7 @@ public class SecP224K1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -118,7 +119,33 @@ public class SecP224K1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP224K1FieldElement(x), new SecP224K1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat224.create(), y = Nat224.create(); + int pos = 0; + + for (int i = 0; i < len; ++i) + { + int MASK = ((i ^ index) - 1) >> 31; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] ^= table[pos + j] & MASK; + y[j] ^= table[pos + FE_INTS + j] & MASK; + } + + pos += (FE_INTS * 2); + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP224K1FieldElement(x), new SecP224K1FieldElement(y), SECP224K1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java index b7c91180e..e02f8ca0a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat224; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP224K1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP224K1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D")); // Calculated as ECConstants.TWO.modPow(Q.shiftRight(2), Q) private static final int[] PRECOMP_POW2 = new int[]{ 0x33bfd202, 0xdcfad133, 0x2287624a, 0xc3811ba8, diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java index 77c461510..17e96706b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224K1Point.java @@ -8,56 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat224; public class SecP224K1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, - boolean withCompression) + SecP224K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -188,7 +146,7 @@ public class SecP224K1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[] { Z3 }; - return new SecP224K1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP224K1Point(curve, X3, Y3, zs); } // B.3 pg 62 @@ -248,7 +206,7 @@ public class SecP224K1Point extends ECPoint.AbstractFp SecP224K1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP224K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression); + return new SecP224K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -293,6 +251,6 @@ public class SecP224K1Point extends ECPoint.AbstractFp return this; } - return new SecP224K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP224K1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java index 688d9824d..98d0d1ff9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; @@ -11,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP224R1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001")); + public static final BigInteger q = SecP224R1FieldElement.Q; - private static final int SecP224R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final int SECP224R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP224R1_AFFINE_ZS = new ECFieldElement[] { new SecP224R1FieldElement(ECConstants.ONE) }; protected SecP224R1Point infinity; @@ -25,13 +27,13 @@ public class SecP224R1Curve extends ECCurve.AbstractFp this.infinity = new SecP224R1Point(this, null, null); this.a = fromBigInteger(new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"))); + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE"))); this.b = fromBigInteger(new BigInteger(1, - Hex.decode("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"))); - this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D")); + Hex.decodeStrict("B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4"))); + this.order = new BigInteger(1, Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D")); this.cofactor = BigInteger.valueOf(1); - this.coord = SecP224R1_DEFAULT_COORDS; + this.coord = SECP224R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -65,14 +67,14 @@ public class SecP224R1Curve extends ECCurve.AbstractFp return new SecP224R1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP224R1Point(this, x, y, withCompression); + return new SecP224R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP224R1Point(this, x, y, zs, withCompression); + return new SecP224R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -95,7 +97,7 @@ public class SecP224R1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -120,7 +122,26 @@ public class SecP224R1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP224R1FieldElement(x), new SecP224R1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat224.create(), y = Nat224.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP224R1FieldElement(x), new SecP224R1FieldElement(y), SECP224R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java index 69b5ed989..de3efdfe6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1FieldElement.java @@ -7,10 +7,12 @@ import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.math.raw.Nat224; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP224R1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP224R1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java index c8629d819..25906febe 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP224R1Point.java @@ -8,55 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat224; public class SecP224R1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecP224R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -186,7 +145,7 @@ public class SecP224R1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; - return new SecP224R1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP224R1Point(curve, X3, Y3, zs); } public ECPoint twice() @@ -258,7 +217,7 @@ public class SecP224R1Point extends ECPoint.AbstractFp SecP224R1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP224R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecP224R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -303,6 +262,6 @@ public class SecP224R1Point extends ECPoint.AbstractFp return this; } - return new SecP224R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP224R1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java index bb369d336..aa69d5e02 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1Curve.java @@ -2,6 +2,7 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -12,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP256K1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F")); + public static final BigInteger q = SecP256K1FieldElement.Q; private static final int SECP256K1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP256K1_AFFINE_ZS = new ECFieldElement[] { new SecP256K1FieldElement(ECConstants.ONE) }; protected SecP256K1Point infinity; @@ -27,7 +28,7 @@ public class SecP256K1Curve extends ECCurve.AbstractFp this.a = fromBigInteger(ECConstants.ZERO); this.b = fromBigInteger(BigInteger.valueOf(7)); - this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")); + this.order = new BigInteger(1, Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141")); this.cofactor = BigInteger.valueOf(1); this.coord = SECP256K1_DEFAULT_COORDS; } @@ -63,14 +64,14 @@ public class SecP256K1Curve extends ECCurve.AbstractFp return new SecP256K1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP256K1Point(this, x, y, withCompression); + return new SecP256K1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP256K1Point(this, x, y, zs, withCompression); + return new SecP256K1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -93,7 +94,7 @@ public class SecP256K1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -118,7 +119,26 @@ public class SecP256K1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP256K1FieldElement(x), new SecP256K1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat256.create(), y = Nat256.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP256K1FieldElement(x), new SecP256K1FieldElement(y), SECP256K1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java index 6ec250518..715bcba70 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat256; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP256K1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP256K1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java index 6a772f78f..9a1843f2f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256K1Point.java @@ -8,56 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat256; public class SecP256K1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, - boolean withCompression) + SecP256K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -188,7 +146,7 @@ public class SecP256K1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[] { Z3 }; - return new SecP256K1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP256K1Point(curve, X3, Y3, zs); } // B.3 pg 62 @@ -248,7 +206,7 @@ public class SecP256K1Point extends ECPoint.AbstractFp SecP256K1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP256K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }, this.withCompression); + return new SecP256K1Point(curve, X3, Y3, new ECFieldElement[] { Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -293,6 +251,6 @@ public class SecP256K1Point extends ECPoint.AbstractFp return this; } - return new SecP256K1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP256K1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java index 2d08d658e..2e747ca8d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; @@ -11,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP256R1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")); + public static final BigInteger q = SecP256R1FieldElement.Q; - private static final int SecP256R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final int SECP256R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP256R1_AFFINE_ZS = new ECFieldElement[] { new SecP256R1FieldElement(ECConstants.ONE) }; protected SecP256R1Point infinity; @@ -25,13 +27,13 @@ public class SecP256R1Curve extends ECCurve.AbstractFp this.infinity = new SecP256R1Point(this, null, null); this.a = fromBigInteger(new BigInteger(1, - Hex.decode("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"))); + Hex.decodeStrict("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"))); this.b = fromBigInteger(new BigInteger(1, - Hex.decode("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"))); - this.order = new BigInteger(1, Hex.decode("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")); + Hex.decodeStrict("5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"))); + this.order = new BigInteger(1, Hex.decodeStrict("FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551")); this.cofactor = BigInteger.valueOf(1); - this.coord = SecP256R1_DEFAULT_COORDS; + this.coord = SECP256R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -65,14 +67,14 @@ public class SecP256R1Curve extends ECCurve.AbstractFp return new SecP256R1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP256R1Point(this, x, y, withCompression); + return new SecP256R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP256R1Point(this, x, y, zs, withCompression); + return new SecP256R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -95,7 +97,7 @@ public class SecP256R1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -120,7 +122,26 @@ public class SecP256R1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP256R1FieldElement(x), new SecP256R1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat256.create(), y = Nat256.create(); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP256R1FieldElement(x), new SecP256R1FieldElement(y), SECP256R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java index b7fd28ef3..7372b3d81 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat256; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP256R1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP256R1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java index f09106dce..4d03df7e7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP256R1Point.java @@ -8,55 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat256; public class SecP256R1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecP256R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -186,7 +145,7 @@ public class SecP256R1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; - return new SecP256R1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP256R1Point(curve, X3, Y3, zs); } public ECPoint twice() @@ -258,7 +217,7 @@ public class SecP256R1Point extends ECPoint.AbstractFp SecP256R1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP256R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecP256R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -303,6 +262,6 @@ public class SecP256R1Point extends ECPoint.AbstractFp return this; } - return new SecP256R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP256R1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java index cd9e0d214..7f50f24e2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; @@ -11,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP384R1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF")); + public static final BigInteger q = SecP384R1FieldElement.Q; - private static final int SecP384R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final int SECP384R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP384R1_AFFINE_ZS = new ECFieldElement[] { new SecP384R1FieldElement(ECConstants.ONE) }; protected SecP384R1Point infinity; @@ -25,13 +27,13 @@ public class SecP384R1Curve extends ECCurve.AbstractFp this.infinity = new SecP384R1Point(this, null, null); this.a = fromBigInteger(new BigInteger(1, - Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"))); + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC"))); this.b = fromBigInteger(new BigInteger(1, - Hex.decode("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"))); - this.order = new BigInteger(1, Hex.decode("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973")); + Hex.decodeStrict("B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF"))); + this.order = new BigInteger(1, Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973")); this.cofactor = BigInteger.valueOf(1); - this.coord = SecP384R1_DEFAULT_COORDS; + this.coord = SECP384R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -65,14 +67,14 @@ public class SecP384R1Curve extends ECCurve.AbstractFp return new SecP384R1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP384R1Point(this, x, y, withCompression); + return new SecP384R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP384R1Point(this, x, y, zs, withCompression); + return new SecP384R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -95,7 +97,7 @@ public class SecP384R1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -120,7 +122,26 @@ public class SecP384R1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP384R1FieldElement(x), new SecP384R1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat.create(FE_INTS), y = Nat.create(FE_INTS); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP384R1FieldElement(x), new SecP384R1FieldElement(y), SECP384R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java index 617d16708..84349001e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP384R1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP384R1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java index 145fe1e6a..15b14185c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP384R1Point.java @@ -8,55 +8,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat384; public class SecP384R1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecP384R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -187,7 +146,7 @@ public class SecP384R1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; - return new SecP384R1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP384R1Point(curve, X3, Y3, zs); } public ECPoint twice() @@ -259,7 +218,7 @@ public class SecP384R1Point extends ECPoint.AbstractFp SecP384R1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP384R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecP384R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -304,6 +263,6 @@ public class SecP384R1Point extends ECPoint.AbstractFp return this; } - return new SecP384R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP384R1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java index 295db64e8..571eee306 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; @@ -11,10 +13,10 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP521R1Curve extends ECCurve.AbstractFp { - public static final BigInteger q = new BigInteger(1, - Hex.decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); + public static final BigInteger q = SecP521R1FieldElement.Q; - private static final int SecP521R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final int SECP521R1_DEFAULT_COORDS = COORD_JACOBIAN; + private static final ECFieldElement[] SECP521R1_AFFINE_ZS = new ECFieldElement[] { new SecP521R1FieldElement(ECConstants.ONE) }; protected SecP521R1Point infinity; @@ -25,13 +27,13 @@ public class SecP521R1Curve extends ECCurve.AbstractFp this.infinity = new SecP521R1Point(this, null, null); this.a = fromBigInteger(new BigInteger(1, - Hex.decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"))); + Hex.decodeStrict("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC"))); this.b = fromBigInteger(new BigInteger(1, - Hex.decode("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"))); - this.order = new BigInteger(1, Hex.decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409")); + Hex.decodeStrict("0051953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00"))); + this.order = new BigInteger(1, Hex.decodeStrict("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409")); this.cofactor = BigInteger.valueOf(1); - this.coord = SecP521R1_DEFAULT_COORDS; + this.coord = SECP521R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -65,14 +67,14 @@ public class SecP521R1Curve extends ECCurve.AbstractFp return new SecP521R1FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecP521R1Point(this, x, y, withCompression); + return new SecP521R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecP521R1Point(this, x, y, zs, withCompression); + return new SecP521R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -95,7 +97,7 @@ public class SecP521R1Curve extends ECCurve.AbstractFp } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -120,7 +122,26 @@ public class SecP521R1Curve extends ECCurve.AbstractFp pos += (FE_INTS * 2); } - return createRawPoint(new SecP521R1FieldElement(x), new SecP521R1FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + int[] x = Nat.create(FE_INTS), y = Nat.create(FE_INTS); + int pos = index * FE_INTS * 2; + + for (int j = 0; j < FE_INTS; ++j) + { + x[j] ^= table[pos + j]; + y[j] ^= table[pos + FE_INTS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(int[] x, int[] y) + { + return createRawPoint(new SecP521R1FieldElement(x), new SecP521R1FieldElement(y), SECP521R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java index b2717d4a7..79d98d163 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1FieldElement.java @@ -6,10 +6,12 @@ import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.raw.Mod; import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecP521R1FieldElement extends ECFieldElement.AbstractFp { - public static final BigInteger Q = SecP521R1Curve.q; + public static final BigInteger Q = new BigInteger(1, + Hex.decodeStrict("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")); protected int[] x; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java index 4e8e036de..43b10a630 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecP521R1Point.java @@ -7,55 +7,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat; public class SecP521R1Point extends ECPoint.AbstractFp { - /** - * Create a point which encodes with point compression. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * Create a point that encodes with or without point compresion. - * - * @param curve - * the curve to use - * @param x - * affine x co-ordinate - * @param y - * affine y co-ordinate - * @param withCompression - * if true encode with point compression - * - * @deprecated per-point compression property will be removed, refer - * {@link #getEncoded(boolean)} - */ - public SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecP521R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -182,7 +141,7 @@ public class SecP521R1Point extends ECPoint.AbstractFp ECFieldElement[] zs = new ECFieldElement[]{ Z3 }; - return new SecP521R1Point(curve, X3, Y3, zs, this.withCompression); + return new SecP521R1Point(curve, X3, Y3, zs); } public ECPoint twice() @@ -253,7 +212,7 @@ public class SecP521R1Point extends ECPoint.AbstractFp SecP521R1Field.multiply(Z3.x, Z1.x, Z3.x); } - return new SecP521R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecP521R1Point(curve, X3, Y3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -328,6 +287,6 @@ public class SecP521R1Point extends ECPoint.AbstractFp return this; } - return new SecP521R1Point(curve, this.x, this.y.negate(), this.zs, this.withCompression); + return new SecP521R1Point(curve, this.x, this.y.negate(), this.zs); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113Field.java index a4164c20e..81900975a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113Field.java @@ -3,6 +3,7 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; import com.fr.third.org.bouncycastle.math.raw.Interleave; +import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.math.raw.Nat128; public class SecT113Field @@ -30,11 +31,30 @@ public class SecT113Field z[1] = x[1]; } + private static void addTo(long[] x, long[] z) + { + z[0] ^= x[0]; + z[1] ^= x[1]; + } + public static long[] fromBigInteger(BigInteger x) { - long[] z = Nat128.fromBigInteger64(x); - reduce15(z, 0); - return z; + return Nat.fromBigInteger64(113, x); + } + + public static void halfTrace(long[] x, long[] z) + { + long[] tt = Nat128.createExt64(); + + Nat128.copy64(x, z); + for (int i = 1; i < 113; i += 2) + { + implSquare(z, tt); + reduce(tt, z); + implSquare(z, tt); + reduce(tt, z); + addTo(x, z); + } } public static void invert(long[] x, long[] z) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113FieldElement.java index 67bf157ca..ef65638db 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113FieldElement.java @@ -159,6 +159,18 @@ public class SecT113FieldElement extends ECFieldElement.AbstractF2m return new SecT113FieldElement(z); } + public ECFieldElement halfTrace() + { + long[] z = Nat128.create64(); + SecT113Field.halfTrace(x, z); + return new SecT113FieldElement(z); + } + + public boolean hasFastTrace() + { + return true; + } + public int trace() { return SecT113Field.trace(x); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R1Curve.java index d398997df..c460fec2f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -12,7 +14,8 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT113R1Curve extends AbstractF2m { - private static final int SecT113R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT113R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT113R1_AFFINE_ZS = new ECFieldElement[] { new SecT113FieldElement(ECConstants.ONE) }; protected SecT113R1Point infinity; @@ -22,12 +25,12 @@ public class SecT113R1Curve extends AbstractF2m this.infinity = new SecT113R1Point(this, null, null); - this.a = fromBigInteger(new BigInteger(1, Hex.decode("003088250CA6E7C7FE649CE85820F7"))); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("00E8BEE4D3E2260744188BE0E9C723"))); - this.order = new BigInteger(1, Hex.decode("0100000000000000D9CCEC8A39E56F")); + this.a = fromBigInteger(new BigInteger(1, Hex.decodeStrict("003088250CA6E7C7FE649CE85820F7"))); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("00E8BEE4D3E2260744188BE0E9C723"))); + this.order = new BigInteger(1, Hex.decodeStrict("0100000000000000D9CCEC8A39E56F")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT113R1_DEFAULT_COORDS; + this.coord = SECT113R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT113R1Curve extends AbstractF2m return new SecT113FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT113R1Point(this, x, y, withCompression); + return new SecT113R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT113R1Point(this, x, y, zs, withCompression); + return new SecT113R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT113R1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT113R1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT113FieldElement(x), new SecT113FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat128.create64(), y = Nat128.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT113FieldElement(x), new SecT113FieldElement(y), SECT113R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R1Point.java index b804d708b..a18ec7b76 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT113R1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT113R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT113R1Point extends AbstractF2m X3 = L.square().add(L).add(X1).add(curve.getA()); if (X3.isZero()) { - return new SecT113R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT113R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT113R1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT113R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT113R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT113R1Point extends AbstractF2m } } - return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -214,7 +194,7 @@ public class SecT113R1Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq); if (T.isZero()) { - return new SecT113R1Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT113R1Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -223,7 +203,7 @@ public class SecT113R1Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -278,14 +258,14 @@ public class SecT113R1Point extends AbstractF2m if (A.isZero()) { - return new SecT113R1Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT113R1Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT113R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -303,6 +283,6 @@ public class SecT113R1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT113R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT113R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R2Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R2Curve.java index 0999f92d4..0f9c92778 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R2Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R2Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -12,7 +14,8 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT113R2Curve extends AbstractF2m { - private static final int SecT113R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT113R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT113R2_AFFINE_ZS = new ECFieldElement[] { new SecT113FieldElement(ECConstants.ONE) }; protected SecT113R2Point infinity; @@ -22,12 +25,12 @@ public class SecT113R2Curve extends AbstractF2m this.infinity = new SecT113R2Point(this, null, null); - this.a = fromBigInteger(new BigInteger(1, Hex.decode("00689918DBEC7E5A0DD6DFC0AA55C7"))); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("0095E9A9EC9B297BD4BF36E059184F"))); - this.order = new BigInteger(1, Hex.decode("010000000000000108789B2496AF93")); + this.a = fromBigInteger(new BigInteger(1, Hex.decodeStrict("00689918DBEC7E5A0DD6DFC0AA55C7"))); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("0095E9A9EC9B297BD4BF36E059184F"))); + this.order = new BigInteger(1, Hex.decodeStrict("010000000000000108789B2496AF93")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT113R2_DEFAULT_COORDS; + this.coord = SECT113R2_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT113R2Curve extends AbstractF2m return new SecT113FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT113R2Point(this, x, y, withCompression); + return new SecT113R2Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT113R2Point(this, x, y, zs, withCompression); + return new SecT113R2Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT113R2Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT113R2Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT113FieldElement(x), new SecT113FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat128.create64(), y = Nat128.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT113FieldElement(x), new SecT113FieldElement(y), SECT113R2_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R2Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R2Point.java index 9a2888517..af44b9421 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R2Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT113R2Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT113R2Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT113R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT113R2Point extends AbstractF2m X3 = L.square().add(L).add(X1).add(curve.getA()); if (X3.isZero()) { - return new SecT113R2Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT113R2Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT113R2Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT113R2Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT113R2Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT113R2Point extends AbstractF2m } } - return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -214,7 +194,7 @@ public class SecT113R2Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq); if (T.isZero()) { - return new SecT113R2Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT113R2Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -223,7 +203,7 @@ public class SecT113R2Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -278,14 +258,14 @@ public class SecT113R2Point extends AbstractF2m if (A.isZero()) { - return new SecT113R2Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT113R2Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT113R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -303,6 +283,6 @@ public class SecT113R2Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT113R2Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT113R2Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131Field.java index c7b89c9d5..2621fe0a4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131Field.java @@ -36,11 +36,31 @@ public class SecT131Field z[2] = x[2]; } + private static void addTo(long[] x, long[] z) + { + z[0] ^= x[0]; + z[1] ^= x[1]; + z[2] ^= x[2]; + } + public static long[] fromBigInteger(BigInteger x) { - long[] z = Nat192.fromBigInteger64(x); - reduce61(z, 0); - return z; + return Nat.fromBigInteger64(131, x); + } + + public static void halfTrace(long[] x, long[] z) + { + long[] tt = Nat.create64(5); + + Nat192.copy64(x, z); + for (int i = 1; i < 131; i += 2) + { + implSquare(z, tt); + reduce(tt, z); + implSquare(z, tt); + reduce(tt, z); + addTo(x, z); + } } public static void invert(long[] x, long[] z) @@ -326,7 +346,6 @@ public class SecT131Field { Interleave.expand64To128(x[0], zz, 0); Interleave.expand64To128(x[1], zz, 2); - zz[4] = Interleave.expand8to16((int)x[2]) & 0xFFFFFFFFL; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131FieldElement.java index 826a53b4e..9dbf18548 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131FieldElement.java @@ -160,6 +160,18 @@ public class SecT131FieldElement extends ECFieldElement.AbstractF2m return new SecT131FieldElement(z); } + public ECFieldElement halfTrace() + { + long[] z = Nat192.create64(); + SecT131Field.halfTrace(x, z); + return new SecT131FieldElement(z); + } + + public boolean hasFastTrace() + { + return true; + } + public int trace() { return SecT131Field.trace(x); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R1Curve.java index 80717c759..cdbf033b7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -12,7 +14,8 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT131R1Curve extends AbstractF2m { - private static final int SecT131R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT131R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT131R1_AFFINE_ZS = new ECFieldElement[] { new SecT131FieldElement(ECConstants.ONE) }; protected SecT131R1Point infinity; @@ -22,12 +25,12 @@ public class SecT131R1Curve extends AbstractF2m this.infinity = new SecT131R1Point(this, null, null); - this.a = fromBigInteger(new BigInteger(1, Hex.decode("07A11B09A76B562144418FF3FF8C2570B8"))); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("0217C05610884B63B9C6C7291678F9D341"))); - this.order = new BigInteger(1, Hex.decode("0400000000000000023123953A9464B54D")); + this.a = fromBigInteger(new BigInteger(1, Hex.decodeStrict("07A11B09A76B562144418FF3FF8C2570B8"))); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("0217C05610884B63B9C6C7291678F9D341"))); + this.order = new BigInteger(1, Hex.decodeStrict("0400000000000000023123953A9464B54D")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT131R1_DEFAULT_COORDS; + this.coord = SECT131R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT131R1Curve extends AbstractF2m return new SecT131FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT131R1Point(this, x, y, withCompression); + return new SecT131R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT131R1Point(this, x, y, zs, withCompression); + return new SecT131R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT131R1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT131R1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT131FieldElement(x), new SecT131FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat192.create64(), y = Nat192.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT131FieldElement(x), new SecT131FieldElement(y), SECT131R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R1Point.java index afaa0badb..126d7cdf8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT131R1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT131R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT131R1Point extends AbstractF2m X3 = L.square().add(L).add(X1).add(curve.getA()); if (X3.isZero()) { - return new SecT131R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT131R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT131R1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT131R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT131R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT131R1Point extends AbstractF2m } } - return new SecT131R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT131R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -214,7 +194,7 @@ public class SecT131R1Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq); if (T.isZero()) { - return new SecT131R1Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT131R1Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -223,7 +203,7 @@ public class SecT131R1Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT131R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT131R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -278,14 +258,14 @@ public class SecT131R1Point extends AbstractF2m if (A.isZero()) { - return new SecT131R1Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT131R1Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT131R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT131R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -303,6 +283,6 @@ public class SecT131R1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT131R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT131R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R2Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R2Curve.java index 3230a3bcc..11091bf4a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R2Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R2Curve.java @@ -2,17 +2,20 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; -import com.fr.third.org.bouncycastle.math.raw.Nat192; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.raw.Nat192; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT131R2Curve extends AbstractF2m { - private static final int SecT131R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT131R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT131R2_AFFINE_ZS = new ECFieldElement[] { new SecT131FieldElement(ECConstants.ONE) }; protected SecT131R2Point infinity; @@ -22,12 +25,12 @@ public class SecT131R2Curve extends AbstractF2m this.infinity = new SecT131R2Point(this, null, null); - this.a = fromBigInteger(new BigInteger(1, Hex.decode("03E5A88919D7CAFCBF415F07C2176573B2"))); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("04B8266A46C55657AC734CE38F018F2192"))); - this.order = new BigInteger(1, Hex.decode("0400000000000000016954A233049BA98F")); + this.a = fromBigInteger(new BigInteger(1, Hex.decodeStrict("03E5A88919D7CAFCBF415F07C2176573B2"))); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("04B8266A46C55657AC734CE38F018F2192"))); + this.order = new BigInteger(1, Hex.decodeStrict("0400000000000000016954A233049BA98F")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT131R2_DEFAULT_COORDS; + this.coord = SECT131R2_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT131R2Curve extends AbstractF2m return new SecT131FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT131R2Point(this, x, y, withCompression); + return new SecT131R2Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT131R2Point(this, x, y, zs, withCompression); + return new SecT131R2Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT131R2Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT131R2Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT131FieldElement(x), new SecT131FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat192.create64(), y = Nat192.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT131FieldElement(x), new SecT131FieldElement(y), SECT131R2_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R2Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R2Point.java index 4836a5f7a..cecce9b83 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R2Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT131R2Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT131R2Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT131R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT131R2Point extends AbstractF2m X3 = L.square().add(L).add(X1).add(curve.getA()); if (X3.isZero()) { - return new SecT131R2Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT131R2Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT131R2Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT131R2Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT131R2Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT131R2Point extends AbstractF2m } } - return new SecT131R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT131R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -214,7 +194,7 @@ public class SecT131R2Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq); if (T.isZero()) { - return new SecT131R2Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT131R2Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -223,7 +203,7 @@ public class SecT131R2Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT131R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT131R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -278,14 +258,14 @@ public class SecT131R2Point extends AbstractF2m if (A.isZero()) { - return new SecT131R2Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT131R2Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT131R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT131R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -303,6 +283,6 @@ public class SecT131R2Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT131R2Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT131R2Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163Field.java index 0df3448f5..77391e71a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163Field.java @@ -3,6 +3,7 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; import com.fr.third.org.bouncycastle.math.raw.Interleave; +import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.math.raw.Nat192; public class SecT163Field @@ -36,11 +37,31 @@ public class SecT163Field z[2] = x[2]; } + private static void addTo(long[] x, long[] z) + { + z[0] ^= x[0]; + z[1] ^= x[1]; + z[2] ^= x[2]; + } + public static long[] fromBigInteger(BigInteger x) { - long[] z = Nat192.fromBigInteger64(x); - reduce29(z, 0); - return z; + return Nat.fromBigInteger64(163, x); + } + + public static void halfTrace(long[] x, long[] z) + { + long[] tt = Nat192.createExt64(); + + Nat192.copy64(x, z); + for (int i = 1; i < 163; i += 2) + { + implSquare(z, tt); + reduce(tt, z); + implSquare(z, tt); + reduce(tt, z); + addTo(x, z); + } } public static void invert(long[] x, long[] z) @@ -333,9 +354,6 @@ public class SecT163Field { Interleave.expand64To128(x[0], zz, 0); Interleave.expand64To128(x[1], zz, 2); - - long x2 = x[2]; - zz[4] = Interleave.expand32to64((int)x2); - zz[5] = Interleave.expand8to16((int)(x2 >>> 32)) & 0xFFFFFFFFL; + Interleave.expand64To128(x[2], zz, 4); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163FieldElement.java index c9a00bd90..92fdb2a1e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163FieldElement.java @@ -159,6 +159,18 @@ public class SecT163FieldElement extends ECFieldElement.AbstractF2m return new SecT163FieldElement(z); } + public ECFieldElement halfTrace() + { + long[] z = Nat192.create64(); + SecT163Field.halfTrace(x, z); + return new SecT163FieldElement(z); + } + + public boolean hasFastTrace() + { + return true; + } + public int trace() { return SecT163Field.trace(x); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163K1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163K1Curve.java index 6b8531ca2..8f2b02fe5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163K1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163K1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -14,7 +16,8 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT163K1Curve extends AbstractF2m { - private static final int SecT163K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT163K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT163K1_AFFINE_ZS = new ECFieldElement[] { new SecT163FieldElement(ECConstants.ONE) }; protected SecT163K1Point infinity; @@ -26,10 +29,10 @@ public class SecT163K1Curve extends AbstractF2m this.a = fromBigInteger(BigInteger.valueOf(1)); this.b = this.a; - this.order = new BigInteger(1, Hex.decode("04000000000000000000020108A2E0CC0D99F8A5EF")); + this.order = new BigInteger(1, Hex.decodeStrict("04000000000000000000020108A2E0CC0D99F8A5EF")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT163K1_DEFAULT_COORDS; + this.coord = SECT163K1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -63,14 +66,14 @@ public class SecT163K1Curve extends AbstractF2m return new SecT163FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT163K1Point(this, x, y, withCompression); + return new SecT163K1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT163K1Point(this, x, y, zs, withCompression); + return new SecT163K1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -123,7 +126,7 @@ public class SecT163K1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -148,7 +151,26 @@ public class SecT163K1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat192.create64(), y = Nat192.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), SECT163K1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163K1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163K1Point.java index b398173ab..0c52375cc 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163K1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163K1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT163K1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT163K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT163K1Point extends AbstractF2m X3 = L.square().add(L).add(X1).addOne(); if (X3.isZero()) { - return new SecT163K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT163K1Point(curve, X3, curve.getB()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT163K1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT163K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT163K1Point(curve, X3, curve.getB()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT163K1Point extends AbstractF2m } } - return new SecT163K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT163K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -212,7 +192,7 @@ public class SecT163K1Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(Z1Sq); if (T.isZero()) { - return new SecT163K1Point(curve, T, curve.getB(), withCompression); + return new SecT163K1Point(curve, T, curve.getB()); } ECFieldElement X3 = T.square(); @@ -221,7 +201,7 @@ public class SecT163K1Point extends AbstractF2m ECFieldElement t1 = L1.add(X1).square(); ECFieldElement L3 = t1.add(T).add(Z1Sq).multiply(t1).add(X3); - return new SecT163K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT163K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -276,14 +256,14 @@ public class SecT163K1Point extends AbstractF2m if (A.isZero()) { - return new SecT163K1Point(curve, A, curve.getB(), withCompression); + return new SecT163K1Point(curve, A, curve.getB()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2.addOne(), Z3); - return new SecT163K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT163K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -301,6 +281,6 @@ public class SecT163K1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT163K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT163K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R1Curve.java index 2f064dabe..15022fbf6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R1Curve.java @@ -2,17 +2,20 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; -import com.fr.third.org.bouncycastle.math.raw.Nat192; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.raw.Nat192; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT163R1Curve extends AbstractF2m { - private static final int SecT163R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT163R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT163R1_AFFINE_ZS = new ECFieldElement[] { new SecT163FieldElement(ECConstants.ONE) }; protected SecT163R1Point infinity; @@ -22,12 +25,12 @@ public class SecT163R1Curve extends AbstractF2m this.infinity = new SecT163R1Point(this, null, null); - this.a = fromBigInteger(new BigInteger(1, Hex.decode("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2"))); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9"))); - this.order = new BigInteger(1, Hex.decode("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B")); + this.a = fromBigInteger(new BigInteger(1, Hex.decodeStrict("07B6882CAAEFA84F9554FF8428BD88E246D2782AE2"))); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9"))); + this.order = new BigInteger(1, Hex.decodeStrict("03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT163R1_DEFAULT_COORDS; + this.coord = SECT163R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT163R1Curve extends AbstractF2m return new SecT163FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT163R1Point(this, x, y, withCompression); + return new SecT163R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT163R1Point(this, x, y, zs, withCompression); + return new SecT163R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT163R1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT163R1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat192.create64(), y = Nat192.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), SECT163R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R1Point.java index 8a8da0787..55c99cd68 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT163R1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT163R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT163R1Point extends AbstractF2m X3 = L.square().add(L).add(X1).add(curve.getA()); if (X3.isZero()) { - return new SecT163R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT163R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT163R1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT163R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT163R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT163R1Point extends AbstractF2m } } - return new SecT163R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT163R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -214,7 +194,7 @@ public class SecT163R1Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq); if (T.isZero()) { - return new SecT163R1Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT163R1Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -223,7 +203,7 @@ public class SecT163R1Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT163R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT163R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -278,14 +258,14 @@ public class SecT163R1Point extends AbstractF2m if (A.isZero()) { - return new SecT163R1Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT163R1Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT163R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT163R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -303,6 +283,6 @@ public class SecT163R1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT163R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT163R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R2Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R2Curve.java index 510665c37..05a0e101c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R2Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R2Curve.java @@ -2,17 +2,20 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; -import com.fr.third.org.bouncycastle.math.raw.Nat192; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.raw.Nat192; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT163R2Curve extends AbstractF2m { - private static final int SecT163R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT163R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT163R2_AFFINE_ZS = new ECFieldElement[] { new SecT163FieldElement(ECConstants.ONE) }; protected SecT163R2Point infinity; @@ -23,11 +26,11 @@ public class SecT163R2Curve extends AbstractF2m this.infinity = new SecT163R2Point(this, null, null); this.a = fromBigInteger(BigInteger.valueOf(1)); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("020A601907B8C953CA1481EB10512F78744A3205FD"))); - this.order = new BigInteger(1, Hex.decode("040000000000000000000292FE77E70C12A4234C33")); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("020A601907B8C953CA1481EB10512F78744A3205FD"))); + this.order = new BigInteger(1, Hex.decodeStrict("040000000000000000000292FE77E70C12A4234C33")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT163R2_DEFAULT_COORDS; + this.coord = SECT163R2_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT163R2Curve extends AbstractF2m return new SecT163FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT163R2Point(this, x, y, withCompression); + return new SecT163R2Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT163R2Point(this, x, y, zs, withCompression); + return new SecT163R2Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT163R2Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT163R2Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat192.create64(), y = Nat192.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT163FieldElement(x), new SecT163FieldElement(y), SECT163R2_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R2Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R2Point.java index e13a270ce..3d68baf31 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R2Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT163R2Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT163R2Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT163R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT163R2Point extends AbstractF2m X3 = L.square().add(L).add(X1).addOne(); if (X3.isZero()) { - return new SecT163R2Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT163R2Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT163R2Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT163R2Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT163R2Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT163R2Point extends AbstractF2m } } - return new SecT163R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT163R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -212,7 +192,7 @@ public class SecT163R2Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(Z1Sq); if (T.isZero()) { - return new SecT163R2Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT163R2Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -221,7 +201,7 @@ public class SecT163R2Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT163R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT163R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -275,14 +255,14 @@ public class SecT163R2Point extends AbstractF2m if (A.isZero()) { - return new SecT163R2Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT163R2Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2.addOne(), Z3); - return new SecT163R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT163R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -300,6 +280,6 @@ public class SecT163R2Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT163R2Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT163R2Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193Field.java index bd1f29d44..3796001ba 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193Field.java @@ -3,6 +3,7 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; import com.fr.third.org.bouncycastle.math.raw.Interleave; +import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.math.raw.Nat256; public class SecT193Field @@ -37,11 +38,32 @@ public class SecT193Field z[3] = x[3]; } + private static void addTo(long[] x, long[] z) + { + z[0] ^= x[0]; + z[1] ^= x[1]; + z[2] ^= x[2]; + z[3] ^= x[3]; + } + public static long[] fromBigInteger(BigInteger x) { - long[] z = Nat256.fromBigInteger64(x); - reduce63(z, 0); - return z; + return Nat.fromBigInteger64(193, x); + } + + public static void halfTrace(long[] x, long[] z) + { + long[] tt = Nat256.createExt64(); + + Nat256.copy64(x, z); + for (int i = 1; i < 193; i += 2) + { + implSquare(z, tt); + reduce(tt, z); + implSquare(z, tt); + reduce(tt, z); + addTo(x, z); + } } public static void invert(long[] x, long[] z) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193FieldElement.java index 0ba1fbae2..fb9fcb2cb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193FieldElement.java @@ -159,6 +159,18 @@ public class SecT193FieldElement extends ECFieldElement.AbstractF2m return new SecT193FieldElement(z); } + public ECFieldElement halfTrace() + { + long[] z = Nat256.create64(); + SecT193Field.halfTrace(x, z); + return new SecT193FieldElement(z); + } + + public boolean hasFastTrace() + { + return true; + } + public int trace() { return SecT193Field.trace(x); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R1Curve.java index f424411a4..4a0b05add 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -12,7 +14,8 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT193R1Curve extends AbstractF2m { - private static final int SecT193R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT193R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT193R1_AFFINE_ZS = new ECFieldElement[] { new SecT193FieldElement(ECConstants.ONE) }; protected SecT193R1Point infinity; @@ -22,12 +25,12 @@ public class SecT193R1Curve extends AbstractF2m this.infinity = new SecT193R1Point(this, null, null); - this.a = fromBigInteger(new BigInteger(1, Hex.decode("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01"))); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814"))); - this.order = new BigInteger(1, Hex.decode("01000000000000000000000000C7F34A778F443ACC920EBA49")); + this.a = fromBigInteger(new BigInteger(1, Hex.decodeStrict("0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01"))); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814"))); + this.order = new BigInteger(1, Hex.decodeStrict("01000000000000000000000000C7F34A778F443ACC920EBA49")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT193R1_DEFAULT_COORDS; + this.coord = SECT193R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT193R1Curve extends AbstractF2m return new SecT193FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT193R1Point(this, x, y, withCompression); + return new SecT193R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT193R1Point(this, x, y, zs, withCompression); + return new SecT193R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT193R1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT193R1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT193FieldElement(x), new SecT193FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat256.create64(), y = Nat256.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT193FieldElement(x), new SecT193FieldElement(y), SECT193R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R1Point.java index 87611e11f..5e797b6d2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT193R1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT193R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT193R1Point extends AbstractF2m X3 = L.square().add(L).add(X1).add(curve.getA()); if (X3.isZero()) { - return new SecT193R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT193R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT193R1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT193R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT193R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT193R1Point extends AbstractF2m } } - return new SecT193R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT193R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -214,7 +194,7 @@ public class SecT193R1Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq); if (T.isZero()) { - return new SecT193R1Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT193R1Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -223,7 +203,7 @@ public class SecT193R1Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT193R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT193R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -278,14 +258,14 @@ public class SecT193R1Point extends AbstractF2m if (A.isZero()) { - return new SecT193R1Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT193R1Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT193R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT193R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -303,6 +283,6 @@ public class SecT193R1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT193R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT193R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R2Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R2Curve.java index 8d4bf0220..6dd39bb3c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R2Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R2Curve.java @@ -2,17 +2,20 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; -import com.fr.third.org.bouncycastle.math.raw.Nat256; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.raw.Nat256; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT193R2Curve extends AbstractF2m { - private static final int SecT193R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT193R2_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT193R2_AFFINE_ZS = new ECFieldElement[] { new SecT193FieldElement(ECConstants.ONE) }; protected SecT193R2Point infinity; @@ -22,12 +25,12 @@ public class SecT193R2Curve extends AbstractF2m this.infinity = new SecT193R2Point(this, null, null); - this.a = fromBigInteger(new BigInteger(1, Hex.decode("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B"))); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE"))); - this.order = new BigInteger(1, Hex.decode("010000000000000000000000015AAB561B005413CCD4EE99D5")); + this.a = fromBigInteger(new BigInteger(1, Hex.decodeStrict("0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B"))); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE"))); + this.order = new BigInteger(1, Hex.decodeStrict("010000000000000000000000015AAB561B005413CCD4EE99D5")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT193R2_DEFAULT_COORDS; + this.coord = SECT193R2_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT193R2Curve extends AbstractF2m return new SecT193FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT193R2Point(this, x, y, withCompression); + return new SecT193R2Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT193R2Point(this, x, y, zs, withCompression); + return new SecT193R2Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT193R2Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT193R2Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT193FieldElement(x), new SecT193FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat256.create64(), y = Nat256.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] ^= table[pos + j]; + y[j] ^= table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT193FieldElement(x), new SecT193FieldElement(y), SECT193R2_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R2Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R2Point.java index 380671bff..44c958527 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R2Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT193R2Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT193R2Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT193R2Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT193R2Point extends AbstractF2m X3 = L.square().add(L).add(X1).add(curve.getA()); if (X3.isZero()) { - return new SecT193R2Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT193R2Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT193R2Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT193R2Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT193R2Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT193R2Point extends AbstractF2m } } - return new SecT193R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT193R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -214,7 +194,7 @@ public class SecT193R2Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(aZ1Sq); if (T.isZero()) { - return new SecT193R2Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT193R2Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -223,7 +203,7 @@ public class SecT193R2Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT193R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT193R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -278,14 +258,14 @@ public class SecT193R2Point extends AbstractF2m if (A.isZero()) { - return new SecT193R2Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT193R2Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT193R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT193R2Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -303,6 +283,6 @@ public class SecT193R2Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT193R2Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT193R2Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233Field.java index 3581d7f8c..e9c692a3c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233Field.java @@ -3,6 +3,7 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; import com.fr.third.org.bouncycastle.math.raw.Interleave; +import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.math.raw.Nat256; public class SecT233Field @@ -38,11 +39,32 @@ public class SecT233Field z[3] = x[3]; } + private static void addTo(long[] x, long[] z) + { + z[0] ^= x[0]; + z[1] ^= x[1]; + z[2] ^= x[2]; + z[3] ^= x[3]; + } + public static long[] fromBigInteger(BigInteger x) { - long[] z = Nat256.fromBigInteger64(x); - reduce23(z, 0); - return z; + return Nat.fromBigInteger64(233, x); + } + + public static void halfTrace(long[] x, long[] z) + { + long[] tt = Nat256.createExt64(); + + Nat256.copy64(x, z); + for (int i = 1; i < 233; i += 2) + { + implSquare(z, tt); + reduce(tt, z); + implSquare(z, tt); + reduce(tt, z); + addTo(x, z); + } } public static void invert(long[] x, long[] z) @@ -310,9 +332,6 @@ public class SecT233Field Interleave.expand64To128(x[0], zz, 0); Interleave.expand64To128(x[1], zz, 2); Interleave.expand64To128(x[2], zz, 4); - - long x3 = x[3]; - zz[6] = Interleave.expand32to64((int)x3); - zz[7] = Interleave.expand16to32((int)(x3 >>> 32)) & 0xFFFFFFFFL; + Interleave.expand64To128(x[3], zz, 6); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233FieldElement.java index 1d1f12837..2eb76860d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233FieldElement.java @@ -159,6 +159,18 @@ public class SecT233FieldElement extends ECFieldElement.AbstractF2m return new SecT233FieldElement(z); } + public ECFieldElement halfTrace() + { + long[] z = Nat256.create64(); + SecT233Field.halfTrace(x, z); + return new SecT233FieldElement(z); + } + + public boolean hasFastTrace() + { + return true; + } + public int trace() { return SecT233Field.trace(x); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233K1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233K1Curve.java index 43f576e4c..7f6ae976e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233K1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233K1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -14,7 +16,8 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT233K1Curve extends AbstractF2m { - private static final int SecT233K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT233K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT233K1_AFFINE_ZS = new ECFieldElement[] { new SecT233FieldElement(ECConstants.ONE) }; protected SecT233K1Point infinity; @@ -26,10 +29,10 @@ public class SecT233K1Curve extends AbstractF2m this.a = fromBigInteger(BigInteger.valueOf(0)); this.b = fromBigInteger(BigInteger.valueOf(1)); - this.order = new BigInteger(1, Hex.decode("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF")); + this.order = new BigInteger(1, Hex.decodeStrict("8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF")); this.cofactor = BigInteger.valueOf(4); - this.coord = SecT233K1_DEFAULT_COORDS; + this.coord = SECT233K1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -63,14 +66,14 @@ public class SecT233K1Curve extends AbstractF2m return new SecT233FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT233K1Point(this, x, y, withCompression); + return new SecT233K1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT233K1Point(this, x, y, zs, withCompression); + return new SecT233K1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -123,7 +126,7 @@ public class SecT233K1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -148,7 +151,26 @@ public class SecT233K1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT233FieldElement(x), new SecT233FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat256.create64(), y = Nat256.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT233FieldElement(x), new SecT233FieldElement(y), SECT233K1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233K1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233K1Point.java index 49ecc400a..25afe7b15 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233K1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233K1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT233K1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT233K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT233K1Point extends AbstractF2m X3 = L.square().add(L).add(X1); if (X3.isZero()) { - return new SecT233K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT233K1Point(curve, X3, curve.getB()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT233K1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT233K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT233K1Point(curve, X3, curve.getB()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT233K1Point extends AbstractF2m } } - return new SecT233K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT233K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -220,7 +200,7 @@ public class SecT233K1Point extends AbstractF2m if (T.isZero()) { - return new SecT233K1Point(curve, T, curve.getB(), withCompression); + return new SecT233K1Point(curve, T, curve.getB()); } ECFieldElement X3 = T.square(); @@ -230,7 +210,7 @@ public class SecT233K1Point extends AbstractF2m ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.square(); ECFieldElement L3 = t1.add(T).add(Z1Sq).multiply(t1).add(t2).add(X3).add(Z3); - return new SecT233K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT233K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -286,14 +266,14 @@ public class SecT233K1Point extends AbstractF2m if (A.isZero()) { - return new SecT233K1Point(curve, A, curve.getB(), withCompression); + return new SecT233K1Point(curve, A, curve.getB()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT233K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT233K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -311,6 +291,6 @@ public class SecT233K1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT233K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT233K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233R1Curve.java index 4ccf1e068..edd6f1c06 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233R1Curve.java @@ -2,17 +2,20 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; -import com.fr.third.org.bouncycastle.math.raw.Nat256; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.raw.Nat256; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT233R1Curve extends AbstractF2m { - private static final int SecT233R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT233R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT233R1_AFFINE_ZS = new ECFieldElement[] { new SecT233FieldElement(ECConstants.ONE) }; protected SecT233R1Point infinity; @@ -23,11 +26,11 @@ public class SecT233R1Curve extends AbstractF2m this.infinity = new SecT233R1Point(this, null, null); this.a = fromBigInteger(BigInteger.valueOf(1)); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD"))); - this.order = new BigInteger(1, Hex.decode("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7")); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD"))); + this.order = new BigInteger(1, Hex.decodeStrict("01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT233R1_DEFAULT_COORDS; + this.coord = SECT233R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT233R1Curve extends AbstractF2m return new SecT233FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT233R1Point(this, x, y, withCompression); + return new SecT233R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT233R1Point(this, x, y, zs, withCompression); + return new SecT233R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT233R1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT233R1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT233FieldElement(x), new SecT233FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat256.create64(), y = Nat256.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT233FieldElement(x), new SecT233FieldElement(y), SECT233R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233R1Point.java index b1b567d00..bfa91c19c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT233R1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT233R1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT233R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT233R1Point extends AbstractF2m X3 = L.square().add(L).add(X1).addOne(); if (X3.isZero()) { - return new SecT233R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT233R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT233R1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT233R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT233R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT233R1Point extends AbstractF2m } } - return new SecT233R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT233R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -212,7 +192,7 @@ public class SecT233R1Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(Z1Sq); if (T.isZero()) { - return new SecT233R1Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT233R1Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -221,7 +201,7 @@ public class SecT233R1Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT233R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT233R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -275,14 +255,14 @@ public class SecT233R1Point extends AbstractF2m if (A.isZero()) { - return new SecT233R1Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT233R1Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2.addOne(), Z3); - return new SecT233R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT233R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -300,6 +280,6 @@ public class SecT233R1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT233R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT233R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239Field.java index cacb2ce18..f606cf3f6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239Field.java @@ -3,6 +3,7 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; import com.fr.third.org.bouncycastle.math.raw.Interleave; +import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.math.raw.Nat256; public class SecT239Field @@ -38,11 +39,32 @@ public class SecT239Field z[3] = x[3]; } + private static void addTo(long[] x, long[] z) + { + z[0] ^= x[0]; + z[1] ^= x[1]; + z[2] ^= x[2]; + z[3] ^= x[3]; + } + public static long[] fromBigInteger(BigInteger x) { - long[] z = Nat256.fromBigInteger64(x); - reduce17(z, 0); - return z; + return Nat.fromBigInteger64(239, x); + } + + public static void halfTrace(long[] x, long[] z) + { + long[] tt = Nat256.createExt64(); + + Nat256.copy64(x, z); + for (int i = 1; i < 239; i += 2) + { + implSquare(z, tt); + reduce(tt, z); + implSquare(z, tt); + reduce(tt, z); + addTo(x, z); + } } public static void invert(long[] x, long[] z) @@ -321,9 +343,6 @@ public class SecT239Field Interleave.expand64To128(x[0], zz, 0); Interleave.expand64To128(x[1], zz, 2); Interleave.expand64To128(x[2], zz, 4); - - long x3 = x[3]; - zz[6] = Interleave.expand32to64((int)x3); - zz[7] = Interleave.expand16to32((int)(x3 >>> 32)) & 0xFFFFFFFFL; + Interleave.expand64To128(x[3], zz, 6); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239FieldElement.java index 1773ca048..3e39d3acb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239FieldElement.java @@ -159,6 +159,18 @@ public class SecT239FieldElement extends ECFieldElement.AbstractF2m return new SecT239FieldElement(z); } + public ECFieldElement halfTrace() + { + long[] z = Nat256.create64(); + SecT239Field.halfTrace(x, z); + return new SecT239FieldElement(z); + } + + public boolean hasFastTrace() + { + return true; + } + public int trace() { return SecT239Field.trace(x); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239K1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239K1Curve.java index f45213e79..3a6f1cba8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239K1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239K1Curve.java @@ -2,19 +2,22 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; -import com.fr.third.org.bouncycastle.math.raw.Nat256; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECMultiplier; import com.fr.third.org.bouncycastle.math.ec.ECPoint; import com.fr.third.org.bouncycastle.math.ec.WTauNafMultiplier; +import com.fr.third.org.bouncycastle.math.raw.Nat256; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT239K1Curve extends AbstractF2m { - private static final int SecT239K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT239K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT239K1_AFFINE_ZS = new ECFieldElement[] { new SecT239FieldElement(ECConstants.ONE) }; protected SecT239K1Point infinity; @@ -26,10 +29,10 @@ public class SecT239K1Curve extends AbstractF2m this.a = fromBigInteger(BigInteger.valueOf(0)); this.b = fromBigInteger(BigInteger.valueOf(1)); - this.order = new BigInteger(1, Hex.decode("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5")); + this.order = new BigInteger(1, Hex.decodeStrict("2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5")); this.cofactor = BigInteger.valueOf(4); - this.coord = SecT239K1_DEFAULT_COORDS; + this.coord = SECT239K1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -63,14 +66,14 @@ public class SecT239K1Curve extends AbstractF2m return new SecT239FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT239K1Point(this, x, y, withCompression); + return new SecT239K1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT239K1Point(this, x, y, zs, withCompression); + return new SecT239K1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -123,7 +126,7 @@ public class SecT239K1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -148,7 +151,26 @@ public class SecT239K1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT239FieldElement(x), new SecT239FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat256.create64(), y = Nat256.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT239FieldElement(x), new SecT239FieldElement(y), SECT239K1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239K1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239K1Point.java index e310b1189..8f5987ae8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239K1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT239K1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT239K1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT239K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT239K1Point extends AbstractF2m X3 = L.square().add(L).add(X1); if (X3.isZero()) { - return new SecT239K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT239K1Point(curve, X3, curve.getB()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT239K1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT239K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT239K1Point(curve, X3, curve.getB()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT239K1Point extends AbstractF2m } } - return new SecT239K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT239K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -221,7 +201,7 @@ public class SecT239K1Point extends AbstractF2m if (T.isZero()) { - return new SecT239K1Point(curve, T, curve.getB(), withCompression); + return new SecT239K1Point(curve, T, curve.getB()); } ECFieldElement X3 = T.square(); @@ -231,7 +211,7 @@ public class SecT239K1Point extends AbstractF2m ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.square(); ECFieldElement L3 = t1.add(T).add(Z1Sq).multiply(t1).add(t2).add(X3).add(Z3); - return new SecT239K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT239K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -287,14 +267,14 @@ public class SecT239K1Point extends AbstractF2m if (A.isZero()) { - return new SecT239K1Point(curve, A, curve.getB(), withCompression); + return new SecT239K1Point(curve, A, curve.getB()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT239K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT239K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -312,6 +292,6 @@ public class SecT239K1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT239K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT239K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283Field.java index a3a7bfb54..fb38b9d27 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283Field.java @@ -44,11 +44,33 @@ public class SecT283Field z[4] = x[4]; } + private static void addTo(long[] x, long[] z) + { + z[0] ^= x[0]; + z[1] ^= x[1]; + z[2] ^= x[2]; + z[3] ^= x[3]; + z[4] ^= x[4]; + } + public static long[] fromBigInteger(BigInteger x) { - long[] z = Nat320.fromBigInteger64(x); - reduce37(z, 0); - return z; + return Nat.fromBigInteger64(283, x); + } + + public static void halfTrace(long[] x, long[] z) + { + long[] tt = Nat.create64(9); + + Nat320.copy64(x, z); + for (int i = 1; i < 283; i += 2) + { + implSquare(z, tt); + reduce(tt, z); + implSquare(z, tt); + reduce(tt, z); + addTo(x, z); + } } public static void invert(long[] x, long[] z) @@ -395,10 +417,10 @@ public class SecT283Field protected static void implSquare(long[] x, long[] zz) { - for (int i = 0; i < 4; ++i) - { - Interleave.expand64To128(x[i], zz, i << 1); - } + Interleave.expand64To128(x[0], zz, 0); + Interleave.expand64To128(x[1], zz, 2); + Interleave.expand64To128(x[2], zz, 4); + Interleave.expand64To128(x[3], zz, 6); zz[8] = Interleave.expand32to64((int)x[4]); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283FieldElement.java index 31264aec6..89b87fe82 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283FieldElement.java @@ -160,6 +160,18 @@ public class SecT283FieldElement extends ECFieldElement.AbstractF2m return new SecT283FieldElement(z); } + public ECFieldElement halfTrace() + { + long[] z = Nat320.create64(); + SecT283Field.halfTrace(x, z); + return new SecT283FieldElement(z); + } + + public boolean hasFastTrace() + { + return true; + } + public int trace() { return SecT283Field.trace(x); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283K1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283K1Curve.java index 0c25c094b..40dcd7002 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283K1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283K1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -14,7 +16,8 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT283K1Curve extends AbstractF2m { - private static final int SecT283K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT283K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT283K1_AFFINE_ZS = new ECFieldElement[] { new SecT283FieldElement(ECConstants.ONE) }; protected SecT283K1Point infinity; @@ -26,10 +29,10 @@ public class SecT283K1Curve extends AbstractF2m this.a = fromBigInteger(BigInteger.valueOf(0)); this.b = fromBigInteger(BigInteger.valueOf(1)); - this.order = new BigInteger(1, Hex.decode("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61")); + this.order = new BigInteger(1, Hex.decodeStrict("01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61")); this.cofactor = BigInteger.valueOf(4); - this.coord = SecT283K1_DEFAULT_COORDS; + this.coord = SECT283K1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -63,14 +66,14 @@ public class SecT283K1Curve extends AbstractF2m return new SecT283FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT283K1Point(this, x, y, withCompression); + return new SecT283K1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT283K1Point(this, x, y, zs, withCompression); + return new SecT283K1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -123,7 +126,7 @@ public class SecT283K1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -148,7 +151,26 @@ public class SecT283K1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT283FieldElement(x), new SecT283FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat320.create64(), y = Nat320.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT283FieldElement(x), new SecT283FieldElement(y), SECT283K1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283K1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283K1Point.java index 3a239f38c..2ec780a0c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283K1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283K1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT283K1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT283K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT283K1Point extends AbstractF2m X3 = L.square().add(L).add(X1); if (X3.isZero()) { - return new SecT283K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT283K1Point(curve, X3, curve.getB()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT283K1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT283K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT283K1Point(curve, X3, curve.getB()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT283K1Point extends AbstractF2m } } - return new SecT283K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT283K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -221,7 +201,7 @@ public class SecT283K1Point extends AbstractF2m if (T.isZero()) { - return new SecT283K1Point(curve, T, curve.getB(), withCompression); + return new SecT283K1Point(curve, T, curve.getB()); } ECFieldElement X3 = T.square(); @@ -231,7 +211,7 @@ public class SecT283K1Point extends AbstractF2m ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.square(); ECFieldElement L3 = t1.add(T).add(Z1Sq).multiply(t1).add(t2).add(X3).add(Z3); - return new SecT283K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT283K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -287,14 +267,14 @@ public class SecT283K1Point extends AbstractF2m if (A.isZero()) { - return new SecT283K1Point(curve, A, curve.getB(), withCompression); + return new SecT283K1Point(curve, A, curve.getB()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT283K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT283K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -312,6 +292,6 @@ public class SecT283K1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT283K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT283K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283R1Curve.java index 8dbca3f9d..8886cfd15 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283R1Curve.java @@ -2,17 +2,20 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; -import com.fr.third.org.bouncycastle.math.raw.Nat320; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.raw.Nat320; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT283R1Curve extends AbstractF2m { - private static final int SecT283R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT283R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT283R1_AFFINE_ZS = new ECFieldElement[] { new SecT283FieldElement(ECConstants.ONE) }; protected SecT283R1Point infinity; @@ -23,11 +26,11 @@ public class SecT283R1Curve extends AbstractF2m this.infinity = new SecT283R1Point(this, null, null); this.a = fromBigInteger(BigInteger.valueOf(1)); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5"))); - this.order = new BigInteger(1, Hex.decode("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307")); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5"))); + this.order = new BigInteger(1, Hex.decodeStrict("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT283R1_DEFAULT_COORDS; + this.coord = SECT283R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT283R1Curve extends AbstractF2m return new SecT283FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT283R1Point(this, x, y, withCompression); + return new SecT283R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT283R1Point(this, x, y, zs, withCompression); + return new SecT283R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT283R1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT283R1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT283FieldElement(x), new SecT283FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat320.create64(), y = Nat320.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT283FieldElement(x), new SecT283FieldElement(y), SECT283R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283R1Point.java index 71785569f..180738b8c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT283R1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT283R1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT283R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT283R1Point extends AbstractF2m X3 = L.square().add(L).add(X1).addOne(); if (X3.isZero()) { - return new SecT283R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT283R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT283R1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT283R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT283R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT283R1Point extends AbstractF2m } } - return new SecT283R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT283R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -212,7 +192,7 @@ public class SecT283R1Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(Z1Sq); if (T.isZero()) { - return new SecT283R1Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT283R1Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -221,7 +201,7 @@ public class SecT283R1Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT283R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT283R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -275,14 +255,14 @@ public class SecT283R1Point extends AbstractF2m if (A.isZero()) { - return new SecT283R1Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT283R1Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2.addOne(), Z3); - return new SecT283R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT283R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -300,6 +280,6 @@ public class SecT283R1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT283R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT283R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409Field.java index 48283c9b3..308740210 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409Field.java @@ -41,11 +41,35 @@ public class SecT409Field z[6] = x[6]; } + private static void addTo(long[] x, long[] z) + { + z[0] ^= x[0]; + z[1] ^= x[1]; + z[2] ^= x[2]; + z[3] ^= x[3]; + z[4] ^= x[4]; + z[5] ^= x[5]; + z[6] ^= x[6]; + } + public static long[] fromBigInteger(BigInteger x) { - long[] z = Nat448.fromBigInteger64(x); - reduce39(z, 0); - return z; + return Nat.fromBigInteger64(409, x); + } + + public static void halfTrace(long[] x, long[] z) + { + long[] tt = Nat.create64(13); + + Nat448.copy64(x, z); + for (int i = 1; i < 409; i += 2) + { + implSquare(z, tt); + reduce(tt, z); + implSquare(z, tt); + reduce(tt, z); + addTo(x, z); + } } public static void invert(long[] x, long[] z) @@ -324,10 +348,12 @@ public class SecT409Field protected static void implSquare(long[] x, long[] zz) { - for (int i = 0; i < 6; ++i) - { - Interleave.expand64To128(x[i], zz, i << 1); - } + Interleave.expand64To128(x[0], zz, 0); + Interleave.expand64To128(x[1], zz, 2); + Interleave.expand64To128(x[2], zz, 4); + Interleave.expand64To128(x[3], zz, 6); + Interleave.expand64To128(x[4], zz, 8); + Interleave.expand64To128(x[5], zz, 10); zz[12] = Interleave.expand32to64((int)x[6]); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409FieldElement.java index 68ba00cb1..03b703ba6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409FieldElement.java @@ -160,6 +160,18 @@ public class SecT409FieldElement extends ECFieldElement.AbstractF2m return new SecT409FieldElement(z); } + public ECFieldElement halfTrace() + { + long[] z = Nat448.create64(); + SecT409Field.halfTrace(x, z); + return new SecT409FieldElement(z); + } + + public boolean hasFastTrace() + { + return true; + } + public int trace() { return SecT409Field.trace(x); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409K1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409K1Curve.java index ff7ae2bd5..4302c07ac 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409K1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409K1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -14,7 +16,8 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT409K1Curve extends AbstractF2m { - private static final int SecT409K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT409K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT409K1_AFFINE_ZS = new ECFieldElement[] { new SecT409FieldElement(ECConstants.ONE) }; protected SecT409K1Point infinity; @@ -26,10 +29,10 @@ public class SecT409K1Curve extends AbstractF2m this.a = fromBigInteger(BigInteger.valueOf(0)); this.b = fromBigInteger(BigInteger.valueOf(1)); - this.order = new BigInteger(1, Hex.decode("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF")); + this.order = new BigInteger(1, Hex.decodeStrict("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF")); this.cofactor = BigInteger.valueOf(4); - this.coord = SecT409K1_DEFAULT_COORDS; + this.coord = SECT409K1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -63,14 +66,14 @@ public class SecT409K1Curve extends AbstractF2m return new SecT409FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT409K1Point(this, x, y, withCompression); + return new SecT409K1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT409K1Point(this, x, y, zs, withCompression); + return new SecT409K1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -123,7 +126,7 @@ public class SecT409K1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -148,7 +151,26 @@ public class SecT409K1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT409FieldElement(x), new SecT409FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat448.create64(), y = Nat448.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT409FieldElement(x), new SecT409FieldElement(y), SECT409K1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409K1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409K1Point.java index 742be9173..f3e82402a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409K1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409K1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT409K1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT409K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT409K1Point extends AbstractF2m X3 = L.square().add(L).add(X1); if (X3.isZero()) { - return new SecT409K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT409K1Point(curve, X3, curve.getB()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT409K1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT409K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT409K1Point(curve, X3, curve.getB()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT409K1Point extends AbstractF2m } } - return new SecT409K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT409K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -221,7 +201,7 @@ public class SecT409K1Point extends AbstractF2m if (T.isZero()) { - return new SecT409K1Point(curve, T, curve.getB(), withCompression); + return new SecT409K1Point(curve, T, curve.getB()); } ECFieldElement X3 = T.square(); @@ -231,7 +211,7 @@ public class SecT409K1Point extends AbstractF2m ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.square(); ECFieldElement L3 = t1.add(T).add(Z1Sq).multiply(t1).add(t2).add(X3).add(Z3); - return new SecT409K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT409K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -287,14 +267,14 @@ public class SecT409K1Point extends AbstractF2m if (A.isZero()) { - return new SecT409K1Point(curve, A, curve.getB(), withCompression); + return new SecT409K1Point(curve, A, curve.getB()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT409K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT409K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -312,6 +292,6 @@ public class SecT409K1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT409K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT409K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409R1Curve.java index f6ae84ec5..29d8e2931 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409R1Curve.java @@ -2,17 +2,20 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; -import com.fr.third.org.bouncycastle.math.raw.Nat448; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.raw.Nat448; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT409R1Curve extends AbstractF2m { - private static final int SecT409R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT409R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT409R1_AFFINE_ZS = new ECFieldElement[] { new SecT409FieldElement(ECConstants.ONE) }; protected SecT409R1Point infinity; @@ -23,11 +26,11 @@ public class SecT409R1Curve extends AbstractF2m this.infinity = new SecT409R1Point(this, null, null); this.a = fromBigInteger(BigInteger.valueOf(1)); - this.b = fromBigInteger(new BigInteger(1, Hex.decode("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F"))); - this.order = new BigInteger(1, Hex.decode("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173")); + this.b = fromBigInteger(new BigInteger(1, Hex.decodeStrict("0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F"))); + this.order = new BigInteger(1, Hex.decodeStrict("010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT409R1_DEFAULT_COORDS; + this.coord = SECT409R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -56,14 +59,14 @@ public class SecT409R1Curve extends AbstractF2m return new SecT409FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT409R1Point(this, x, y, withCompression); + return new SecT409R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT409R1Point(this, x, y, zs, withCompression); + return new SecT409R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -116,7 +119,7 @@ public class SecT409R1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -141,7 +144,26 @@ public class SecT409R1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT409FieldElement(x), new SecT409FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat448.create64(), y = Nat448.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT409FieldElement(x), new SecT409FieldElement(y), SECT409R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409R1Point.java index a0b7ce318..175af3b34 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT409R1Point.java @@ -8,34 +8,14 @@ import com.fr.third.org.bouncycastle.math.ec.ECPoint.AbstractF2m; public class SecT409R1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT409R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -150,7 +130,7 @@ public class SecT409R1Point extends AbstractF2m X3 = L.square().add(L).add(X1).addOne(); if (X3.isZero()) { - return new SecT409R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT409R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -167,7 +147,7 @@ public class SecT409R1Point extends AbstractF2m X3 = AU1.multiply(AU2); if (X3.isZero()) { - return new SecT409R1Point(curve, X3, curve.getB().sqrt(), this.withCompression); + return new SecT409R1Point(curve, X3, curve.getB().sqrt()); } ECFieldElement ABZ2 = A.multiply(B); @@ -185,7 +165,7 @@ public class SecT409R1Point extends AbstractF2m } } - return new SecT409R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT409R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -212,7 +192,7 @@ public class SecT409R1Point extends AbstractF2m ECFieldElement T = L1.square().add(L1Z1).add(Z1Sq); if (T.isZero()) { - return new SecT409R1Point(curve, T, curve.getB().sqrt(), withCompression); + return new SecT409R1Point(curve, T, curve.getB().sqrt()); } ECFieldElement X3 = T.square(); @@ -221,7 +201,7 @@ public class SecT409R1Point extends AbstractF2m ECFieldElement X1Z1 = Z1IsOne ? X1 : X1.multiply(Z1); ECFieldElement L3 = X1Z1.squarePlusProduct(T, L1Z1).add(X3).add(Z3); - return new SecT409R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT409R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -275,14 +255,14 @@ public class SecT409R1Point extends AbstractF2m if (A.isZero()) { - return new SecT409R1Point(curve, A, curve.getB().sqrt(), withCompression); + return new SecT409R1Point(curve, A, curve.getB().sqrt()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2.addOne(), Z3); - return new SecT409R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT409R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -300,6 +280,6 @@ public class SecT409R1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT409R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT409R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571Field.java index eb8e03fc1..700f17f15 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571Field.java @@ -64,11 +64,32 @@ public class SecT571Field } } + private static void addTo(long[] x, long[] z) + { + for (int i = 0; i < 9; ++i) + { + z[i] ^= x[i]; + } + } + public static long[] fromBigInteger(BigInteger x) { - long[] z = Nat576.fromBigInteger64(x); - reduce5(z, 0); - return z; + return Nat.fromBigInteger64(571, x); + } + + public static void halfTrace(long[] x, long[] z) + { + long[] tt = Nat576.createExt64(); + + Nat576.copy64(x, z); + for (int i = 1; i < 571; i += 2) + { + implSquare(z, tt); + reduce(tt, z); + implSquare(z, tt); + reduce(tt, z); + addTo(x, z); + } } public static void invert(long[] x, long[] z) @@ -361,9 +382,14 @@ public class SecT571Field protected static void implSquare(long[] x, long[] zz) { - for (int i = 0; i < 9; ++i) - { - Interleave.expand64To128(x[i], zz, i << 1); - } + Interleave.expand64To128(x[0], zz, 0); + Interleave.expand64To128(x[1], zz, 2); + Interleave.expand64To128(x[2], zz, 4); + Interleave.expand64To128(x[3], zz, 6); + Interleave.expand64To128(x[4], zz, 8); + Interleave.expand64To128(x[5], zz, 10); + Interleave.expand64To128(x[6], zz, 12); + Interleave.expand64To128(x[7], zz, 14); + Interleave.expand64To128(x[8], zz, 16); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571FieldElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571FieldElement.java index b47c139e9..7a5deb6b4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571FieldElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571FieldElement.java @@ -159,6 +159,18 @@ public class SecT571FieldElement extends ECFieldElement.AbstractF2m return new SecT571FieldElement(z); } + public ECFieldElement halfTrace() + { + long[] z = Nat576.create64(); + SecT571Field.halfTrace(x, z); + return new SecT571FieldElement(z); + } + + public boolean hasFastTrace() + { + return true; + } + public int trace() { return SecT571Field.trace(x); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571K1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571K1Curve.java index 3bf3cddd9..93aed667c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571K1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571K1Curve.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; @@ -14,7 +16,8 @@ import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT571K1Curve extends AbstractF2m { - private static final int SecT571K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT571K1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT571K1_AFFINE_ZS = new ECFieldElement[] { new SecT571FieldElement(ECConstants.ONE) }; protected SecT571K1Point infinity; @@ -26,10 +29,10 @@ public class SecT571K1Curve extends AbstractF2m this.a = fromBigInteger(BigInteger.valueOf(0)); this.b = fromBigInteger(BigInteger.valueOf(1)); - this.order = new BigInteger(1, Hex.decode("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001")); + this.order = new BigInteger(1, Hex.decodeStrict("020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001")); this.cofactor = BigInteger.valueOf(4); - this.coord = SecT571K1_DEFAULT_COORDS; + this.coord = SECT571K1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -63,14 +66,14 @@ public class SecT571K1Curve extends AbstractF2m return new SecT571FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT571K1Point(this, x, y, withCompression); + return new SecT571K1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT571K1Point(this, x, y, zs, withCompression); + return new SecT571K1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -123,7 +126,7 @@ public class SecT571K1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -148,7 +151,26 @@ public class SecT571K1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT571FieldElement(x), new SecT571FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat576.create64(), y = Nat576.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT571FieldElement(x), new SecT571FieldElement(y), SECT571K1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571K1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571K1Point.java index 947363746..e253f3bdb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571K1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571K1Point.java @@ -9,34 +9,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat576; public class SecT571K1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT571K1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -169,7 +149,7 @@ public class SecT571K1Point extends AbstractF2m X3 = (SecT571FieldElement)L.square().add(L).add(X1); if (X3.isZero()) { - return new SecT571K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT571K1Point(curve, X3, curve.getB()); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -193,7 +173,7 @@ public class SecT571K1Point extends AbstractF2m if (X3.isZero()) { - return new SecT571K1Point(curve, X3, curve.getB(), this.withCompression); + return new SecT571K1Point(curve, X3, curve.getB()); } Z3 = new SecT571FieldElement(t3); @@ -221,7 +201,7 @@ public class SecT571K1Point extends AbstractF2m } } - return new SecT571K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT571K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -257,7 +237,7 @@ public class SecT571K1Point extends AbstractF2m if (T.isZero()) { - return new SecT571K1Point(curve, T, curve.getB(), withCompression); + return new SecT571K1Point(curve, T, curve.getB()); } ECFieldElement X3 = T.square(); @@ -267,7 +247,7 @@ public class SecT571K1Point extends AbstractF2m ECFieldElement t2 = Z1IsOne ? Z1 : Z1Sq.square(); ECFieldElement L3 = t1.add(T).add(Z1Sq).multiply(t1).add(t2).add(X3).add(Z3); - return new SecT571K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT571K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -323,14 +303,14 @@ public class SecT571K1Point extends AbstractF2m if (A.isZero()) { - return new SecT571K1Point(curve, A, curve.getB(), withCompression); + return new SecT571K1Point(curve, A, curve.getB()); } ECFieldElement X3 = A.square().multiply(X2Z1Sq); ECFieldElement Z3 = A.multiply(B).multiply(Z1Sq); ECFieldElement L3 = A.add(B).square().multiplyPlusProduct(T, L2plus1, Z3); - return new SecT571K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT571K1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -348,6 +328,6 @@ public class SecT571K1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT571K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT571K1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571R1Curve.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571R1Curve.java index 4f690488d..d780a85bd 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571R1Curve.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571R1Curve.java @@ -2,22 +2,25 @@ package com.fr.third.org.bouncycastle.math.ec.custom.sec; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.math.ec.AbstractECLookupTable; +import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECCurve.AbstractF2m; -import com.fr.third.org.bouncycastle.math.raw.Nat576; import com.fr.third.org.bouncycastle.math.ec.ECFieldElement; import com.fr.third.org.bouncycastle.math.ec.ECLookupTable; import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.raw.Nat576; import com.fr.third.org.bouncycastle.util.encoders.Hex; public class SecT571R1Curve extends AbstractF2m { - private static final int SecT571R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final int SECT571R1_DEFAULT_COORDS = COORD_LAMBDA_PROJECTIVE; + private static final ECFieldElement[] SECT571R1_AFFINE_ZS = new ECFieldElement[] { new SecT571FieldElement(ECConstants.ONE) }; protected SecT571R1Point infinity; static final SecT571FieldElement SecT571R1_B = new SecT571FieldElement( - new BigInteger(1, Hex.decode("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A"))); + new BigInteger(1, Hex.decodeStrict("02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A"))); static final SecT571FieldElement SecT571R1_B_SQRT = (SecT571FieldElement)SecT571R1_B.sqrt(); public SecT571R1Curve() @@ -28,10 +31,10 @@ public class SecT571R1Curve extends AbstractF2m this.a = fromBigInteger(BigInteger.valueOf(1)); this.b = SecT571R1_B; - this.order = new BigInteger(1, Hex.decode("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47")); + this.order = new BigInteger(1, Hex.decodeStrict("03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47")); this.cofactor = BigInteger.valueOf(2); - this.coord = SecT571R1_DEFAULT_COORDS; + this.coord = SECT571R1_DEFAULT_COORDS; } protected ECCurve cloneCurve() @@ -60,14 +63,14 @@ public class SecT571R1Curve extends AbstractF2m return new SecT571FieldElement(x); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y) { - return new SecT571R1Point(this, x, y, withCompression); + return new SecT571R1Point(this, x, y); } - protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + protected ECPoint createRawPoint(ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { - return new SecT571R1Point(this, x, y, zs, withCompression); + return new SecT571R1Point(this, x, y, zs); } public ECPoint getInfinity() @@ -120,7 +123,7 @@ public class SecT571R1Curve extends AbstractF2m } } - return new ECLookupTable() + return new AbstractECLookupTable() { public int getSize() { @@ -145,7 +148,26 @@ public class SecT571R1Curve extends AbstractF2m pos += (FE_LONGS * 2); } - return createRawPoint(new SecT571FieldElement(x), new SecT571FieldElement(y), false); + return createPoint(x, y); + } + + public ECPoint lookupVar(int index) + { + long[] x = Nat576.create64(), y = Nat576.create64(); + int pos = index * FE_LONGS * 2; + + for (int j = 0; j < FE_LONGS; ++j) + { + x[j] = table[pos + j]; + y[j] = table[pos + FE_LONGS + j]; + } + + return createPoint(x, y); + } + + private ECPoint createPoint(long[] x, long[] y) + { + return createRawPoint(new SecT571FieldElement(x), new SecT571FieldElement(y), SECT571R1_AFFINE_ZS); } }; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571R1Point.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571R1Point.java index 3d1e57acf..55e2c6bcf 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571R1Point.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/custom/sec/SecT571R1Point.java @@ -10,34 +10,14 @@ import com.fr.third.org.bouncycastle.math.raw.Nat576; public class SecT571R1Point extends AbstractF2m { - /** - * @deprecated Use ECCurve.createPoint to construct points - */ - public SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) - { - this(curve, x, y, false); - } - - /** - * @deprecated per-point compression property will be removed, refer {@link #getEncoded(boolean)} - */ - public SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, boolean withCompression) + SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y) { super(curve, x, y); - - if ((x == null) != (y == null)) - { - throw new IllegalArgumentException("Exactly one of the field elements is null"); - } - - this.withCompression = withCompression; } - SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs, boolean withCompression) + SecT571R1Point(ECCurve curve, ECFieldElement x, ECFieldElement y, ECFieldElement[] zs) { super(curve, x, y, zs); - - this.withCompression = withCompression; } protected ECPoint detach() @@ -170,7 +150,7 @@ public class SecT571R1Point extends AbstractF2m X3 = (SecT571FieldElement)L.square().add(L).add(X1).addOne(); if (X3.isZero()) { - return new SecT571R1Point(curve, X3, SecT571R1Curve.SecT571R1_B_SQRT, this.withCompression); + return new SecT571R1Point(curve, X3, SecT571R1Curve.SecT571R1_B_SQRT); } ECFieldElement Y3 = L.multiply(X1.add(X3)).add(X3).add(Y1); @@ -194,7 +174,7 @@ public class SecT571R1Point extends AbstractF2m if (X3.isZero()) { - return new SecT571R1Point(curve, X3, SecT571R1Curve.SecT571R1_B_SQRT, this.withCompression); + return new SecT571R1Point(curve, X3, SecT571R1Curve.SecT571R1_B_SQRT); } Z3 = new SecT571FieldElement(t3); @@ -222,7 +202,7 @@ public class SecT571R1Point extends AbstractF2m } } - return new SecT571R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT571R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twice() @@ -265,7 +245,7 @@ public class SecT571R1Point extends AbstractF2m if (Nat576.isZero64(T)) { - return new SecT571R1Point(curve, new SecT571FieldElement(T), SecT571R1Curve.SecT571R1_B_SQRT, withCompression); + return new SecT571R1Point(curve, new SecT571FieldElement(T), SecT571R1Curve.SecT571R1_B_SQRT); } long[] tt = Nat576.createExt64(); @@ -295,7 +275,7 @@ public class SecT571R1Point extends AbstractF2m SecT571Field.addBothTo(X3.x, Z3.x, t2); SecT571FieldElement L3 = new SecT571FieldElement(t2); - return new SecT571R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT571R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint twicePlus(ECPoint b) @@ -377,7 +357,7 @@ public class SecT571R1Point extends AbstractF2m if (Nat576.isZero64(A)) { - return new SecT571R1Point(curve, new SecT571FieldElement(A), SecT571R1Curve.SecT571R1_B_SQRT, withCompression); + return new SecT571R1Point(curve, new SecT571FieldElement(A), SecT571R1Curve.SecT571R1_B_SQRT); } SecT571FieldElement X3 = new SecT571FieldElement(); @@ -398,7 +378,7 @@ public class SecT571R1Point extends AbstractF2m SecT571Field.multiplyAddToExt(t4, Z3.x, tt); SecT571Field.reduce(tt, L3.x); - return new SecT571R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }, this.withCompression); + return new SecT571R1Point(curve, X3, L3, new ECFieldElement[]{ Z3 }); } public ECPoint negate() @@ -416,6 +396,6 @@ public class SecT571R1Point extends AbstractF2m // L is actually Lambda (X + Y/X) here ECFieldElement L = this.y, Z = this.zs[0]; - return new SecT571R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }, this.withCompression); + return new SecT571R1Point(curve, X, L.add(Z), new ECFieldElement[]{ Z }); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/EndoPreCompInfo.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/EndoPreCompInfo.java new file mode 100644 index 000000000..b03355340 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/EndoPreCompInfo.java @@ -0,0 +1,31 @@ +package com.fr.third.org.bouncycastle.math.ec.endo; + +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.ec.PreCompInfo; + +public class EndoPreCompInfo implements PreCompInfo +{ + protected ECEndomorphism endomorphism; + + protected ECPoint mappedPoint; + + public ECEndomorphism getEndomorphism() + { + return endomorphism; + } + + public void setEndomorphism(ECEndomorphism endomorphism) + { + this.endomorphism = endomorphism; + } + + public ECPoint getMappedPoint() + { + return mappedPoint; + } + + public void setMappedPoint(ECPoint mappedPoint) + { + this.mappedPoint = mappedPoint; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/EndoUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/EndoUtil.java new file mode 100644 index 000000000..67b7ca2d1 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/EndoUtil.java @@ -0,0 +1,73 @@ +package com.fr.third.org.bouncycastle.math.ec.endo; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.math.ec.ECConstants; +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPoint; +import com.fr.third.org.bouncycastle.math.ec.PreCompCallback; +import com.fr.third.org.bouncycastle.math.ec.PreCompInfo; + +public abstract class EndoUtil +{ + public static final String PRECOMP_NAME = "bc_endo"; + + public static BigInteger[] decomposeScalar(ScalarSplitParameters p, BigInteger k) + { + int bits = p.getBits(); + BigInteger b1 = calculateB(k, p.getG1(), bits); + BigInteger b2 = calculateB(k, p.getG2(), bits); + + BigInteger a = k.subtract((b1.multiply(p.getV1A())).add(b2.multiply(p.getV2A()))); + BigInteger b = (b1.multiply(p.getV1B())).add(b2.multiply(p.getV2B())).negate(); + + return new BigInteger[]{ a, b }; + } + + public static ECPoint mapPoint(final ECEndomorphism endomorphism, final ECPoint p) + { + final ECCurve c = p.getCurve(); + + EndoPreCompInfo precomp = (EndoPreCompInfo)c.precompute(p, PRECOMP_NAME, new PreCompCallback() + { + public PreCompInfo precompute(PreCompInfo existing) + { + EndoPreCompInfo existingEndo = (existing instanceof EndoPreCompInfo) ? (EndoPreCompInfo)existing : null; + + if (checkExisting(existingEndo, endomorphism)) + { + return existingEndo; + } + + ECPoint mappedPoint = endomorphism.getPointMap().map(p); + + EndoPreCompInfo result = new EndoPreCompInfo(); + result.setEndomorphism(endomorphism); + result.setMappedPoint(mappedPoint); + return result; + } + + private boolean checkExisting(EndoPreCompInfo existingEndo, ECEndomorphism endomorphism) + { + return null != existingEndo + && existingEndo.getEndomorphism() == endomorphism + && existingEndo.getMappedPoint() != null; + } + }); + + return precomp.getMappedPoint(); + } + + private static BigInteger calculateB(BigInteger k, BigInteger g, int t) + { + boolean negative = (g.signum() < 0); + BigInteger b = k.multiply(g.abs()); + boolean extra = b.testBit(t - 1); + b = b.shiftRight(t); + if (extra) + { + b = b.add(ECConstants.ONE); + } + return negative ? b.negate() : b; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeAEndomorphism.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeAEndomorphism.java new file mode 100644 index 000000000..1189472e6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeAEndomorphism.java @@ -0,0 +1,40 @@ +package com.fr.third.org.bouncycastle.math.ec.endo; + +import java.math.BigInteger; + +import com.fr.third.org.bouncycastle.math.ec.ECCurve; +import com.fr.third.org.bouncycastle.math.ec.ECPointMap; +import com.fr.third.org.bouncycastle.math.ec.ScaleYNegateXPointMap; + +public class GLVTypeAEndomorphism implements GLVEndomorphism +{ + protected final GLVTypeAParameters parameters; + protected final ECPointMap pointMap; + + public GLVTypeAEndomorphism(ECCurve curve, GLVTypeAParameters parameters) + { + /* + * NOTE: 'curve' MUST only be used to create a suitable ECFieldElement. Due to the way + * ECCurve configuration works, 'curve' will not be the actual instance of ECCurve that the + * endomorphism is being used with. + */ + + this.parameters = parameters; + this.pointMap = new ScaleYNegateXPointMap(curve.fromBigInteger(parameters.getI())); + } + + public BigInteger[] decomposeScalar(BigInteger k) + { + return EndoUtil.decomposeScalar(parameters.getSplitParams(), k); + } + + public ECPointMap getPointMap() + { + return pointMap; + } + + public boolean hasEfficientPointMap() + { + return true; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeAParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeAParameters.java new file mode 100644 index 000000000..f0ee9cda6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeAParameters.java @@ -0,0 +1,31 @@ +package com.fr.third.org.bouncycastle.math.ec.endo; + +import java.math.BigInteger; + +public class GLVTypeAParameters +{ + protected final BigInteger i, lambda; + protected final ScalarSplitParameters splitParams; + + public GLVTypeAParameters(BigInteger i, BigInteger lambda, ScalarSplitParameters splitParams) + { + this.i = i; + this.lambda = lambda; + this.splitParams = splitParams; + } + + public BigInteger getI() + { + return i; + } + + public BigInteger getLambda() + { + return lambda; + } + + public ScalarSplitParameters getSplitParams() + { + return splitParams; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java index c9113d9b0..158a841c7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeBEndomorphism.java @@ -2,35 +2,30 @@ package com.fr.third.org.bouncycastle.math.ec.endo; import java.math.BigInteger; -import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; import com.fr.third.org.bouncycastle.math.ec.ECPointMap; import com.fr.third.org.bouncycastle.math.ec.ScaleXPointMap; public class GLVTypeBEndomorphism implements GLVEndomorphism { - protected final ECCurve curve; protected final GLVTypeBParameters parameters; protected final ECPointMap pointMap; public GLVTypeBEndomorphism(ECCurve curve, GLVTypeBParameters parameters) { - this.curve = curve; + /* + * NOTE: 'curve' MUST only be used to create a suitable ECFieldElement. Due to the way + * ECCurve configuration works, 'curve' will not be the actual instance of ECCurve that the + * endomorphism is being used with. + */ + this.parameters = parameters; this.pointMap = new ScaleXPointMap(curve.fromBigInteger(parameters.getBeta())); } public BigInteger[] decomposeScalar(BigInteger k) { - int bits = parameters.getBits(); - BigInteger b1 = calculateB(k, parameters.getG1(), bits); - BigInteger b2 = calculateB(k, parameters.getG2(), bits); - - GLVTypeBParameters p = parameters; - BigInteger a = k.subtract((b1.multiply(p.getV1A())).add(b2.multiply(p.getV2A()))); - BigInteger b = (b1.multiply(p.getV1B())).add(b2.multiply(p.getV2B())).negate(); - - return new BigInteger[]{ a, b }; + return EndoUtil.decomposeScalar(parameters.getSplitParams(), k); } public ECPointMap getPointMap() @@ -42,17 +37,4 @@ public class GLVTypeBEndomorphism implements GLVEndomorphism { return true; } - - protected BigInteger calculateB(BigInteger k, BigInteger g, int t) - { - boolean negative = (g.signum() < 0); - BigInteger b = k.multiply(g.abs()); - boolean extra = b.testBit(t - 1); - b = b.shiftRight(t); - if (extra) - { - b = b.add(ECConstants.ONE); - } - return negative ? b.negate() : b; - } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java index bf4f47f00..66a9f6393 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/GLVTypeBParameters.java @@ -4,35 +4,25 @@ import java.math.BigInteger; public class GLVTypeBParameters { - private static void checkVector(BigInteger[] v, String name) - { - if (v == null || v.length != 2 || v[0] == null || v[1] == null) - { - throw new IllegalArgumentException("'" + name + "' must consist of exactly 2 (non-null) values"); - } - } - - protected final BigInteger beta; - protected final BigInteger lambda; - protected final BigInteger v1A, v1B, v2A, v2B; - protected final BigInteger g1, g2; - protected final int bits; + protected final BigInteger beta, lambda; + protected final ScalarSplitParameters splitParams; + /** + * @deprecated Use constructor taking a {@link ScalarSplitParameters} instead. + */ public GLVTypeBParameters(BigInteger beta, BigInteger lambda, BigInteger[] v1, BigInteger[] v2, BigInteger g1, BigInteger g2, int bits) { - checkVector(v1, "v1"); - checkVector(v2, "v2"); + this.beta = beta; + this.lambda = lambda; + this.splitParams = new ScalarSplitParameters(v1, v2, g1, g2, bits); + } + public GLVTypeBParameters(BigInteger beta, BigInteger lambda, ScalarSplitParameters splitParams) + { this.beta = beta; this.lambda = lambda; - this.v1A = v1[0]; - this.v1B = v1[1]; - this.v2A = v2[0]; - this.v2B = v2[1]; - this.g1 = g1; - this.g2 = g2; - this.bits = bits; + this.splitParams = splitParams; } public BigInteger getBeta() @@ -45,54 +35,64 @@ public class GLVTypeBParameters return lambda; } - /** - * @deprecated Use {@link #getV1A()} and {@link #getV1B()} instead. - */ - public BigInteger[] getV1() + public ScalarSplitParameters getSplitParams() { - return new BigInteger[]{ v1A, v1B }; + return splitParams; } + /** + * @deprecated Access via {@link #getSplitParams()} instead. + */ public BigInteger getV1A() { - return v1A; + return getSplitParams().getV1A(); } + /** + * @deprecated Access via {@link #getSplitParams()} instead. + */ public BigInteger getV1B() { - return v1B; + return getSplitParams().getV1B(); } /** - * @deprecated Use {@link #getV2A()} and {@link #getV2B()} instead. + * @deprecated Access via {@link #getSplitParams()} instead. */ - public BigInteger[] getV2() - { - return new BigInteger[]{ v2A, v2B }; - } - public BigInteger getV2A() { - return v2A; + return getSplitParams().getV2A(); } + /** + * @deprecated Access via {@link #getSplitParams()} instead. + */ public BigInteger getV2B() { - return v2B; + return getSplitParams().getV2B(); } + /** + * @deprecated Access via {@link #getSplitParams()} instead. + */ public BigInteger getG1() { - return g1; + return getSplitParams().getG1(); } + /** + * @deprecated Access via {@link #getSplitParams()} instead. + */ public BigInteger getG2() { - return g2; + return getSplitParams().getG2(); } + /** + * @deprecated Access via {@link #getSplitParams()} instead. + */ public int getBits() { - return bits; + return getSplitParams().getBits(); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/ScalarSplitParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/ScalarSplitParameters.java new file mode 100644 index 000000000..6784548a9 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/endo/ScalarSplitParameters.java @@ -0,0 +1,68 @@ +package com.fr.third.org.bouncycastle.math.ec.endo; + +import java.math.BigInteger; + +public class ScalarSplitParameters +{ + private static void checkVector(BigInteger[] v, String name) + { + if (v == null || v.length != 2 || v[0] == null || v[1] == null) + { + throw new IllegalArgumentException("'" + name + "' must consist of exactly 2 (non-null) values"); + } + } + + protected final BigInteger v1A, v1B, v2A, v2B; + protected final BigInteger g1, g2; + protected final int bits; + + public ScalarSplitParameters(BigInteger[] v1, BigInteger[] v2, BigInteger g1, + BigInteger g2, int bits) + { + checkVector(v1, "v1"); + checkVector(v2, "v2"); + + this.v1A = v1[0]; + this.v1B = v1[1]; + this.v2A = v2[0]; + this.v2B = v2[1]; + this.g1 = g1; + this.g2 = g2; + this.bits = bits; + } + + public BigInteger getV1A() + { + return v1A; + } + + public BigInteger getV1B() + { + return v1B; + } + + public BigInteger getV2A() + { + return v2A; + } + + public BigInteger getV2B() + { + return v2B; + } + + public BigInteger getG1() + { + return g1; + } + + public BigInteger getG2() + { + return g2; + } + + public int getBits() + { + return bits; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X25519.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X25519.java index 04cb1ee5d..64c1df862 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X25519.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X25519.java @@ -1,18 +1,32 @@ package com.fr.third.org.bouncycastle.math.ec.rfc7748; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed25519; +import com.fr.third.org.bouncycastle.util.Arrays; + public abstract class X25519 { + public static class Friend + { + private static final Friend INSTANCE = new Friend(); + private Friend() {} + } + + public static final int POINT_SIZE = 32; + public static final int SCALAR_SIZE = 32; + private static final int C_A = 486662; private static final int C_A24 = (C_A + 2)/4; - // 0x1 -// private static final int[] S_x = new int[] { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; +// private static final int[] SQRT_NEG_486664 = { 0x03457E06, 0x03812ABF, 0x01A82CC6, 0x028A5BE8, 0x018B43A7, +// 0x03FC4F7E, 0x02C23700, 0x006BBD27, 0x03A30500, 0x001E4DDB }; - // 0x215132111D8354CB52385F46DCA2B71D440F6A51EB4D1207816B1E0137D48290 - private static final int[] PsubS_x = new int[]{ 0x03D48290, 0x02C7804D, 0x01207816, 0x028F5A68, 0x00881ED4, 0x00A2B71D, - 0x0217D1B7, 0x014CB523, 0x0088EC1A, 0x0042A264 }; - - private static int[] precompBase = null; + public static boolean calculateAgreement(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff) + { + scalarMult(k, kOff, u, uOff, r, rOff); + return !Arrays.areAllZeroes(r, rOff, POINT_SIZE); + } private static int decode32(byte[] bs, int off) { @@ -35,6 +49,20 @@ public abstract class X25519 n[7] |= 0x40000000; } + public static void generatePrivateKey(SecureRandom random, byte[] k) + { + random.nextBytes(k); + + k[0] &= 0xF8; + k[SCALAR_SIZE - 1] &= 0x7F; + k[SCALAR_SIZE - 1] |= 0x40; + } + + public static void generatePublicKey(byte[] k, int kOff, byte[] r, int rOff) + { + scalarMultBase(k, kOff, r, rOff); + } + private static void pointDouble(int[] x, int[] z) { int[] A = X25519Field.create(); @@ -50,69 +78,9 @@ public abstract class X25519 X25519Field.mul(z, A, z); } - public synchronized static void precompute() + public static void precompute() { - if (precompBase != null) - { - return; - } - - precompBase = new int[X25519Field.SIZE * 252]; - - int[] xs = precompBase; - int[] zs = new int[X25519Field.SIZE * 251]; - - int[] x = X25519Field.create(); x[0] = 9; - int[] z = X25519Field.create(); z[0] = 1; - - int[] n = X25519Field.create(); - int[] d = X25519Field.create(); - - X25519Field.apm(x, z, n, d); - - int[] c = X25519Field.create(); X25519Field.copy(d, 0, c, 0); - - int off = 0; - for (;;) - { - X25519Field.copy(n, 0, xs, off); - - if (off == (X25519Field.SIZE * 251)) - { - break; - } - - pointDouble(x, z); - - X25519Field.apm(x, z, n, d); - X25519Field.mul(n, c, n); - X25519Field.mul(c, d, c); - - X25519Field.copy(d, 0, zs, off); - - off += X25519Field.SIZE; - } - - int[] u = X25519Field.create(); - X25519Field.inv(c, u); - - for (;;) - { - X25519Field.copy(xs, off, x, 0); - - X25519Field.mul(x, u, x); -// X25519Field.normalize(x); - X25519Field.copy(x, 0, precompBase, off); - - if (off == 0) - { - break; - } - - off -= X25519Field.SIZE; - X25519Field.copy(zs, off, z, 0); - X25519Field.mul(u, z, u); - } + Ed25519.precompute(); } public static void scalarMult(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff) @@ -178,60 +146,17 @@ public abstract class X25519 public static void scalarMultBase(byte[] k, int kOff, byte[] r, int rOff) { - precompute(); - - int[] n = new int[8]; decodeScalar(k, kOff, n); - - int[] x0 = X25519Field.create(); -// int[] x1 = X25519Field.create(); X25519Field.copy(S_x, 0, x1, 0); - int[] x1 = X25519Field.create(); x1[0] = 1; - int[] z1 = X25519Field.create(); z1[0] = 1; - int[] x2 = X25519Field.create(); X25519Field.copy(PsubS_x, 0, x2, 0); - int[] z2 = X25519Field.create(); z2[0] = 1; - - int[] A = x1; - int[] B = z1; - int[] C = x0; - int[] D = A; - int[] E = B; + int[] y = X25519Field.create(); + int[] z = X25519Field.create(); -// assert n[7] >>> 30 == 1; + Ed25519.scalarMultBaseYZ(Friend.INSTANCE, k, kOff, y, z); - int off = 0, bit = 3, swap = 1; - do - { - X25519Field.copy(precompBase, off, x0, 0); - off += X25519Field.SIZE; - - int word = bit >>> 5, shift = bit & 0x1F; - int kt = (n[word] >>> shift) & 1; - swap ^= kt; - X25519Field.cswap(swap, x1, x2); - X25519Field.cswap(swap, z1, z2); - swap = kt; - - X25519Field.apm(x1, z1, A, B); - X25519Field.mul(x0, B, C); - X25519Field.carry(A); - X25519Field.apm(A, C, D, E); - X25519Field.sqr(D, D); - X25519Field.sqr(E, E); - X25519Field.mul(z2, D, x1); - X25519Field.mul(x2, E, z1); - } - while (++bit < 255); - -// assert swap == 1; - - for (int i = 0; i < 3; ++i) - { - pointDouble(x1, z1); - } + X25519Field.apm(z, y, y, z); - X25519Field.inv(z1, z1); - X25519Field.mul(x1, z1, x1); + X25519Field.inv(z, z); + X25519Field.mul(y, z, y); - X25519Field.normalize(x1); - X25519Field.encode(x1, r, rOff); + X25519Field.normalize(y); + X25519Field.encode(y, r, rOff); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X25519Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X25519Field.java index 945cf1112..15b177c17 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X25519Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X25519Field.java @@ -11,7 +11,7 @@ public abstract class X25519Field private static final int[] ROOT_NEG_ONE = new int[]{ 0x020EA0B0, 0x0386C9D2, 0x00478C4E, 0x0035697F, 0x005E8630, 0x01FBD7A7, 0x0340264F, 0x01F0B2B4, 0x00027E0E, 0x00570649 }; - private X25519Field() {} + protected X25519Field() {} public static void add(int[] x, int[] y, int[] z) { @@ -64,6 +64,18 @@ public abstract class X25519Field z[5] = z5; z[6] = z6; z[7] = z7; z[8] = z8; z[9] = z9; } + public static void cmov(int cond, int[] x, int xOff, int[] z, int zOff) + { +// assert 0 == cond || -1 == cond; + + for (int i = 0; i < SIZE; ++i) + { + int z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + z_i ^= (diff & cond); + z[zOff + i] = z_i; + } + } + public static void cnegate(int negate, int[] z) { // assert negate >>> 1 == 0; @@ -175,14 +187,20 @@ public abstract class X25519Field mul(t, x2, z); } - public static boolean isZeroVar(int[] x) + public static int isZero(int[] x) { int d = 0; for (int i = 0; i < SIZE; ++i) { d |= x[i]; } - return d == 0; + d = (d >>> 1) | (d & 1); + return (d - 1) >> 31; + } + + public static boolean isZeroVar(int[] x) + { + return 0 != isZero(x); } public static void mul(int[] x, int y, int[] z) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X448.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X448.java index e1580ebd9..a2868ff0a 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X448.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X448.java @@ -1,21 +1,33 @@ package com.fr.third.org.bouncycastle.math.ec.rfc7748; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.math.ec.rfc8032.Ed448; +import com.fr.third.org.bouncycastle.util.Arrays; + public abstract class X448 { + public static class Friend + { + private static final Friend INSTANCE = new Friend(); + private Friend() {} + } + + public static final int POINT_SIZE = 56; + public static final int SCALAR_SIZE = 56; + private static final int C_A = 156326; private static final int C_A24 = (C_A + 2)/4; - // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE - private static final int[] S_x = new int[]{ 0x0FFFFFFE, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, - 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFE, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, 0x0FFFFFFF, - 0x0FFFFFFF }; +// private static final int[] SQRT_156324 = { 0x0551B193, 0x07A21E17, 0x0E635AD3, 0x00812ABB, 0x025B3F99, 0x01605224, +// 0x0AF8CB32, 0x0D2E7D68, 0x06BA50FD, 0x08E55693, 0x0CB08EB4, 0x02ABEBC1, 0x051BA0BB, 0x02F8812E, 0x0829B611, +// 0x0BA4D3A0 }; - // 0xF0FAB725013244423ACF03881AFFEB7BDACDD1031C81B9672954459D84C1F823F1BD65643ACE1B5123AC33FF1C69BAF8ACB1197DC99D2720 - private static final int[] PsubS_x = new int[]{ 0x099d2720, 0x0b1197dc, 0x09baf8ac, 0x033ff1c6, 0x0b5123ac, - 0x0643ace1, 0x03f1bd65, 0x084c1f82, 0x0954459d, 0x081b9672, 0x0dd1031c, 0x0eb7bdac, 0x03881aff, 0x0423acf0, - 0x05013244, 0x0f0fab72 }; - - private static int[] precompBase = null; + public static boolean calculateAgreement(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff) + { + scalarMult(k, kOff, u, uOff, r, rOff); + return !Arrays.areAllZeroes(r, rOff, POINT_SIZE); + } private static int decode32(byte[] bs, int off) { @@ -37,6 +49,19 @@ public abstract class X448 n[13] |= 0x80000000; } + public static void generatePrivateKey(SecureRandom random, byte[] k) + { + random.nextBytes(k); + + k[0] &= 0xFC; + k[SCALAR_SIZE - 1] |= 0x80; + } + + public static void generatePublicKey(byte[] k, int kOff, byte[] r, int rOff) + { + scalarMultBase(k, kOff, r, rOff); + } + private static void pointDouble(int[] x, int[] z) { int[] A = X448Field.create(); @@ -54,73 +79,9 @@ public abstract class X448 X448Field.mul(z, A, z); } - public synchronized static void precompute() + public static void precompute() { - if (precompBase != null) - { - return; - } - - precompBase = new int[X448Field.SIZE * 446]; - - int[] xs = precompBase; - int[] zs = new int[X448Field.SIZE * 445]; - - int[] x = X448Field.create(); x[0] = 5; - int[] z = X448Field.create(); z[0] = 1; - - int[] n = X448Field.create(); - int[] d = X448Field.create(); - -// X448Field.apm(x, z, n, d); - X448Field.add(x, z, n); - X448Field.sub(x, z, d); - - int[] c = X448Field.create(); X448Field.copy(d, 0, c, 0); - - int off = 0; - for (;;) - { - X448Field.copy(n, 0, xs, off); - - if (off == (X448Field.SIZE * 445)) - { - break; - } - - pointDouble(x, z); - -// X448Field.apm(x, z, n, d); - X448Field.add(x, z, n); - X448Field.sub(x, z, d); - X448Field.mul(n, c, n); - X448Field.mul(c, d, c); - - X448Field.copy(d, 0, zs, off); - - off += X448Field.SIZE; - } - - int[] u = X448Field.create(); - X448Field.inv(c, u); - - for (;;) - { - X448Field.copy(xs, off, x, 0); - - X448Field.mul(x, u, x); -// X448Field.normalize(x); - X448Field.copy(x, 0, precompBase, off); - - if (off == 0) - { - break; - } - - off -= X448Field.SIZE; - X448Field.copy(zs, off, z, 0); - X448Field.mul(u, z, u); - } + Ed448.precompute(); } public static void scalarMult(byte[] k, int kOff, byte[] u, int uOff, byte[] r, int rOff) @@ -193,63 +154,16 @@ public abstract class X448 public static void scalarMultBase(byte[] k, int kOff, byte[] r, int rOff) { - precompute(); - - int[] n = new int[14]; decodeScalar(k, kOff, n); - - int[] x0 = X448Field.create(); - int[] x1 = X448Field.create(); X448Field.copy(S_x, 0, x1, 0); - int[] z1 = X448Field.create(); z1[0] = 1; - int[] x2 = X448Field.create(); X448Field.copy(PsubS_x, 0, x2, 0); - int[] z2 = X448Field.create(); z2[0] = 1; - - int[] A = X448Field.create(); - int[] B = z1; - int[] C = x0; - int[] D = x1; - int[] E = B; - -// assert n[13] >>> 31 == 1; - - int off = 0, bit = 2, swap = 1; - do - { - X448Field.copy(precompBase, off, x0, 0); - off += X448Field.SIZE; + int[] x = X448Field.create(); + int[] y = X448Field.create(); - int word = bit >>> 5, shift = bit & 0x1F; - int kt = (n[word] >>> shift) & 1; - swap ^= kt; - X448Field.cswap(swap, x1, x2); - X448Field.cswap(swap, z1, z2); - swap = kt; - -// X448Field.apm(x1, z1, A, B); - X448Field.add(x1, z1, A); - X448Field.sub(x1, z1, B); - X448Field.mul(x0, B, C); - X448Field.carry(A); -// X448Field.apm(A, C, D, E); - X448Field.add(A, C, D); - X448Field.sub(A, C, E); - X448Field.sqr(D, D); - X448Field.sqr(E, E); - X448Field.mul(z2, D, x1); - X448Field.mul(x2, E, z1); - } - while (++bit < 448); - -// assert swap == 1; - - for (int i = 0; i < 2; ++i) - { - pointDouble(x1, z1); - } + Ed448.scalarMultBaseXY(Friend.INSTANCE, k, kOff, x, y); - X448Field.inv(z1, z1); - X448Field.mul(x1, z1, x1); + X448Field.inv(x, x); + X448Field.mul(x, y, x); + X448Field.sqr(x, x); - X448Field.normalize(x1); - X448Field.encode(x1, r, rOff); + X448Field.normalize(x); + X448Field.encode(x, r, rOff); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X448Field.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X448Field.java index 56dc69eed..aa04e9e05 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X448Field.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc7748/X448Field.java @@ -1,14 +1,13 @@ package com.fr.third.org.bouncycastle.math.ec.rfc7748; -import com.fr.third.org.bouncycastle.math.raw.Nat; - public abstract class X448Field { public static final int SIZE = 16; private static final int M28 = 0x0FFFFFFF; + private static final long U32 = 0xFFFFFFFFL; - private X448Field() {} + protected X448Field() {} public static void add(int[] x, int[] y, int[] z) { @@ -70,6 +69,18 @@ public abstract class X448Field z[8] = z8; z[9] = z9; z[10] = z10; z[11] = z11; z[12] = z12; z[13] = z13; z[14] = z14; z[15] = z15; } + public static void cmov(int cond, int[] x, int xOff, int[] z, int zOff) + { +// assert 0 == cond || -1 == cond; + + for (int i = 0; i < SIZE; ++i) + { + int z_i = z[zOff + i], diff = z_i ^ x[xOff + i]; + z_i ^= (diff & cond); + z[zOff + i] = z_i; + } + } + public static void cnegate(int negate, int[] z) { // assert negate >>> 1 == 0; @@ -77,7 +88,7 @@ public abstract class X448Field int[] t = create(); sub(t, z, t); - Nat.cmov(SIZE, negate, t, 0, z, 0); + cmov(-negate, t, 0, z, 0); } public static void copy(int[] x, int xOff, int[] z, int zOff) @@ -148,7 +159,6 @@ public abstract class X448Field int hi = decode24(bs, off + 4); z[zOff] = lo & M28; z[zOff + 1] = (lo >>> 28) | (hi << 4); - } public static void encode(int[] x, byte[] z , int zOff) @@ -197,14 +207,20 @@ public abstract class X448Field mul(t, x, z); } - public static boolean isZeroVar(int[] x) + public static int isZero(int[] x) { int d = 0; for (int i = 0; i < SIZE; ++i) { d |= x[i]; } - return d == 0; + d = (d >>> 1) | (d & 1); + return (d - 1) >> 31; + } + + public static boolean isZeroVar(int[] x) + { + return 0 != isZero(x); } public static void mul(int[] x, int y, int[] z) @@ -677,7 +693,7 @@ public abstract class X448Field int u4_2 = u4 * 2; int u5_2 = u5 * 2; int u6_2 = u6 * 2; - + int s0 = x0 + u0; int s1 = x1 + u1; int s2 = x2 + u2; @@ -687,6 +703,12 @@ public abstract class X448Field int s6 = x6 + u6; int s7 = x7 + u7; + /* + * NOTE: Currently s1_2 and/or s5_2 might reach 0x80000000 (because our carry chains land at + * x[1], x[5], x[9], x[13]). So extra care is needed to ensure they are treated as unsigned + * multiplicands below. To avoid depending on the precise carry chains, we assume this + * affects all the s?_2 variables. + */ int s0_2 = s0 * 2; int s1_2 = s1 * 2; int s2_2 = s2 * 2; @@ -709,9 +731,9 @@ public abstract class X448Field + (long)u5 * u3_2 + (long)u4 * u4; long h0 = (long)s0 * s0; - long h8 = (long)s7 * s1_2 - + (long)s6 * s2_2 - + (long)s5 * s3_2 + long h8 = (long)s7 * (s1_2 & U32) + + (long)s6 * (s2_2 & U32) + + (long)s5 * (s3_2 & U32) + (long)s4 * s4; c = f0 + g0 + h8 - f8; @@ -727,10 +749,10 @@ public abstract class X448Field long g9 = (long)u7 * u2_2 + (long)u6 * u3_2 + (long)u5 * u4_2; - long h1 = (long)s1 * s0_2; - long h9 = (long)s7 * s2_2 - + (long)s6 * s3_2 - + (long)s5 * s4_2; + long h1 = (long)s1 * (s0_2 & U32); + long h9 = (long)s7 * (s2_2 & U32) + + (long)s6 * (s3_2 & U32) + + (long)s5 * (s4_2 & U32); c += f1 + g1 + h9 - f9; z1 = (int)c & M28; c >>>= 28; @@ -747,10 +769,10 @@ public abstract class X448Field long g10 = (long)u7 * u3_2 + (long)u6 * u4_2 + (long)u5 * u5; - long h2 = (long)s2 * s0_2 + long h2 = (long)s2 * (s0_2 & U32) + (long)s1 * s1; - long h10 = (long)s7 * s3_2 - + (long)s6 * s4_2 + long h10 = (long)s7 * (s3_2 & U32) + + (long)s6 * (s4_2 & U32) + (long)s5 * s5; c += f2 + g2 + h10 - f10; @@ -766,10 +788,10 @@ public abstract class X448Field + (long)u2 * u1_2; long g11 = (long)u7 * u4_2 + (long)u6 * u5_2; - long h3 = (long)s3 * s0_2 - + (long)s2 * s1_2; - long h11 = (long)s7 * s4_2 - + (long)s6 * s5_2; + long h3 = (long)s3 * (s0_2 & U32) + + (long)s2 * (s1_2 & U32); + long h11 = (long)s7 * (s4_2 & U32) + + (long)s6 * (s5_2 & U32); c += f3 + g3 + h11 - f11; z3 = (int)c & M28; c >>>= 28; @@ -786,10 +808,10 @@ public abstract class X448Field + (long)u2 * u2; long g12 = (long)u7 * u5_2 + (long)u6 * u6; - long h4 = (long)s4 * s0_2 - + (long)s3 * s1_2 + long h4 = (long)s4 * (s0_2 & U32) + + (long)s3 * (s1_2 & U32) + (long)s2 * s2; - long h12 = (long)s7 * s5_2 + long h12 = (long)s7 * (s5_2 & U32) + (long)s6 * s6; c += f4 + g4 + h12 - f12; @@ -805,10 +827,10 @@ public abstract class X448Field + (long)u4 * u1_2 + (long)u3 * u2_2; long g13 = (long)u7 * u6_2; - long h5 = (long)s5 * s0_2 - + (long)s4 * s1_2 - + (long)s3 * s2_2; - long h13 = (long)s7 * s6_2; + long h5 = (long)s5 * (s0_2 & U32) + + (long)s4 * (s1_2 & U32) + + (long)s3 * (s2_2 & U32); + long h13 = (long)s7 * (s6_2 & U32); c += f5 + g5 + h13 - f13; z5 = (int)c & M28; c >>>= 28; @@ -825,9 +847,9 @@ public abstract class X448Field + (long)u4 * u2_2 + (long)u3 * u3; long g14 = (long)u7 * u7; - long h6 = (long)s6 * s0_2 - + (long)s5 * s1_2 - + (long)s4 * s2_2 + long h6 = (long)s6 * (s0_2 & U32) + + (long)s5 * (s1_2 & U32) + + (long)s4 * (s2_2 & U32) + (long)s3 * s3; long h14 = (long)s7 * s7; @@ -844,10 +866,10 @@ public abstract class X448Field + (long)u6 * u1_2 + (long)u5 * u2_2 + (long)u4 * u3_2; - long h7 = (long)s7 * s0_2 - + (long)s6 * s1_2 - + (long)s5 * s2_2 - + (long)s4 * s3_2; + long h7 = (long)s7 * (s0_2 & U32) + + (long)s6 * (s1_2 & U32) + + (long)s5 * (s2_2 & U32) + + (long)s4 * (s3_2 & U32); c += f7 + g7; z7 = (int)c & M28; c >>>= 28; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc8032/Ed25519.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc8032/Ed25519.java index c3aa64783..6181c3255 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc8032/Ed25519.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc8032/Ed25519.java @@ -1,14 +1,28 @@ package com.fr.third.org.bouncycastle.math.ec.rfc8032; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.math.ec.rfc7748.X25519; import com.fr.third.org.bouncycastle.math.ec.rfc7748.X25519Field; import com.fr.third.org.bouncycastle.math.raw.Interleave; import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.math.raw.Nat256; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Strings; public abstract class Ed25519 { + // -x^2 + y^2 == 1 + 0x52036CEE2B6FFE738CC740797779E89800700A4D4141D8AB75EB4DCA135978A3 * x^2 * y^2 + + public static final class Algorithm + { + public static final int Ed25519 = 0; + public static final int Ed25519ctx = 1; + public static final int Ed25519ph = 2; + } + private static final long M28L = 0x0FFFFFFFL; private static final long M32L = 0xFFFFFFFFL; @@ -16,11 +30,12 @@ public abstract class Ed25519 private static final int SCALAR_INTS = 8; private static final int SCALAR_BYTES = SCALAR_INTS * 4; + public static final int PREHASH_SIZE = 64; public static final int PUBLIC_KEY_SIZE = POINT_BYTES; public static final int SECRET_KEY_SIZE = 32; public static final int SIGNATURE_SIZE = POINT_BYTES + SCALAR_BYTES; -// private static final byte[] DOM2_PREFIX = Strings.toByteArray("SigEd25519 no Ed25519 collisions"); + private static final byte[] DOM2_PREFIX = Strings.toByteArray("SigEd25519 no Ed25519 collisions"); private static final int[] P = new int[]{ 0xFFFFFFED, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, 0x7FFFFFFF }; private static final int[] L = new int[]{ 0x5CF5D3ED, 0x5812631A, 0xA2F79CD6, 0x14DEF9DE, 0x00000000, 0x00000000, 0x00000000, 0x10000000 }; @@ -50,10 +65,26 @@ public abstract class Ed25519 private static final int PRECOMP_POINTS = 1 << (PRECOMP_TEETH - 1); private static final int PRECOMP_MASK = PRECOMP_POINTS - 1; + private static final Object precompLock = new Object(); // TODO[ed25519] Convert to PointPrecomp private static PointExt[] precompBaseTable = null; private static int[] precompBase = null; + private static class PointAccum + { + int[] x = X25519Field.create(); + int[] y = X25519Field.create(); + int[] z = X25519Field.create(); + int[] u = X25519Field.create(); + int[] v = X25519Field.create(); + } + + private static class PointAffine + { + int[] x = X25519Field.create(); + int[] y = X25519Field.create(); + } + private static class PointExt { int[] x = X25519Field.create(); @@ -85,6 +116,52 @@ public abstract class Ed25519 return reduceScalar(result); } + private static boolean checkContextVar(byte[] ctx , byte phflag) + { + return ctx == null && phflag == 0x00 + || ctx != null && ctx.length < 256; + } + + private static int checkPoint(int[] x, int[] y) + { + int[] t = X25519Field.create(); + int[] u = X25519Field.create(); + int[] v = X25519Field.create(); + + X25519Field.sqr(x, u); + X25519Field.sqr(y, v); + X25519Field.mul(u, v, t); + X25519Field.sub(v, u, v); + X25519Field.mul(t, C_d, t); + X25519Field.addOne(t); + X25519Field.sub(t, v, t); + X25519Field.normalize(t); + + return X25519Field.isZero(t); + } + + private static int checkPoint(int[] x, int[] y, int[] z) + { + int[] t = X25519Field.create(); + int[] u = X25519Field.create(); + int[] v = X25519Field.create(); + int[] w = X25519Field.create(); + + X25519Field.sqr(x, u); + X25519Field.sqr(y, v); + X25519Field.sqr(z, w); + X25519Field.mul(u, v, t); + X25519Field.sub(v, u, v); + X25519Field.mul(v, w, v); + X25519Field.sqr(w, w); + X25519Field.mul(t, C_d, t); + X25519Field.add(t, w, t); + X25519Field.sub(t, v, t); + X25519Field.normalize(t); + + return X25519Field.isZero(t); + } + private static boolean checkPointVar(byte[] p) { int[] t = new int[8]; @@ -100,6 +177,16 @@ public abstract class Ed25519 return !Nat256.gte(n, L); } + private static Digest createDigest() + { + return new SHA512Digest(); + } + + public static Digest createPrehash() + { + return createDigest(); + } + private static int decode24(byte[] bs, int off) { int n = bs[ off] & 0xFF; @@ -125,7 +212,7 @@ public abstract class Ed25519 } } - private static boolean decodePointVar(byte[] p, int pOff, boolean negate, PointExt r) + private static boolean decodePointVar(byte[] p, int pOff, boolean negate, PointAffine r) { byte[] py = Arrays.copyOfRange(p, pOff, pOff + POINT_BYTES); if (!checkPointVar(py)) @@ -162,7 +249,6 @@ public abstract class Ed25519 X25519Field.negate(r.x, r.x); } - pointExtendXY(r); return true; } @@ -171,6 +257,17 @@ public abstract class Ed25519 decode32(k, kOff, n, 0, SCALAR_INTS); } + private static void dom2(Digest d, byte phflag, byte[] ctx) + { + if (ctx != null) + { + d.update(DOM2_PREFIX, 0, DOM2_PREFIX.length); + d.update(phflag); + d.update((byte)ctx.length); + d.update(ctx, 0, ctx.length); + } + } + private static void encode24(int n, byte[] bs, int off) { bs[ off] = (byte)(n ); @@ -192,7 +289,7 @@ public abstract class Ed25519 encode24((int)(n >>> 32), bs, off + 4); } - private static void encodePoint(PointExt p, byte[] r, int rOff) + private static int encodePoint(PointAccum p, byte[] r, int rOff) { int[] x = X25519Field.create(); int[] y = X25519Field.create(); @@ -203,13 +300,22 @@ public abstract class Ed25519 X25519Field.normalize(x); X25519Field.normalize(y); + int result = checkPoint(x, y); + X25519Field.encode(y, r, rOff); r[rOff + POINT_BYTES - 1] |= ((x[0] & 1) << 7); + + return result; + } + + public static void generatePrivateKey(SecureRandom random, byte[] k) + { + random.nextBytes(k); } public static void generatePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff) { - SHA512Digest d = new SHA512Digest(); + Digest d = createDigest(); byte[] h = new byte[d.getDigestSize()]; d.update(sk, skOff, SECRET_KEY_SIZE); @@ -221,9 +327,15 @@ public abstract class Ed25519 scalarMultBaseEncoded(s, pk, pkOff); } + private static int getWindow4(int[] x, int n) + { + int w = n >>> 3, b = (n & 7) << 2; + return (x[w] >>> b) & 15; + } + private static byte[] getWNAF(int[] n, int width) { -// assert n[SCALAR_INTS - 1] >>> 31 == 0; +// assert n[SCALAR_INTS - 1] >>> 28 == 0; int[] t = new int[SCALAR_INTS * 2]; { @@ -237,7 +349,7 @@ public abstract class Ed25519 } } - byte[] ws = new byte[256]; + byte[] ws = new byte[253]; final int pow2 = 1 << width; final int mask = pow2 - 1; @@ -274,8 +386,10 @@ public abstract class Ed25519 return ws; } - private static void implSign(SHA512Digest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + private static void implSign(Digest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { + dom2(d, phflag, ctx); d.update(h, SCALAR_BYTES, SCALAR_BYTES); d.update(m, mOff, mLen); d.doFinal(h, 0); @@ -284,8 +398,9 @@ public abstract class Ed25519 byte[] R = new byte[POINT_BYTES]; scalarMultBaseEncoded(r, R, 0); + dom2(d, phflag, ctx); d.update(R, 0, POINT_BYTES); - d.update(pk, 0, POINT_BYTES); + d.update(pk, pkOff, POINT_BYTES); d.update(m, mOff, mLen); d.doFinal(h, 0); @@ -296,7 +411,128 @@ public abstract class Ed25519 System.arraycopy(S, 0, sig, sigOff + POINT_BYTES, SCALAR_BYTES); } - private static void pointAddVar(boolean negate, PointExt p, PointExt r) + private static void implSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, + byte[] sig, int sigOff) + { + if (!checkContextVar(ctx, phflag)) + { + throw new IllegalArgumentException("ctx"); + } + + Digest d = createDigest(); + byte[] h = new byte[d.getDigestSize()]; + + d.update(sk, skOff, SECRET_KEY_SIZE); + d.doFinal(h, 0); + + byte[] s = new byte[SCALAR_BYTES]; + pruneScalar(h, 0, s); + + byte[] pk = new byte[POINT_BYTES]; + scalarMultBaseEncoded(s, pk, 0); + + implSign(d, h, s, pk, 0, ctx, phflag, m, mOff, mLen, sig, sigOff); + } + + private static void implSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + if (!checkContextVar(ctx, phflag)) + { + throw new IllegalArgumentException("ctx"); + } + + Digest d = createDigest(); + byte[] h = new byte[d.getDigestSize()]; + + d.update(sk, skOff, SECRET_KEY_SIZE); + d.doFinal(h, 0); + + byte[] s = new byte[SCALAR_BYTES]; + pruneScalar(h, 0, s); + + implSign(d, h, s, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } + + private static boolean implVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen) + { + if (!checkContextVar(ctx, phflag)) + { + throw new IllegalArgumentException("ctx"); + } + + byte[] R = Arrays.copyOfRange(sig, sigOff, sigOff + POINT_BYTES); + byte[] S = Arrays.copyOfRange(sig, sigOff + POINT_BYTES, sigOff + SIGNATURE_SIZE); + + if (!checkPointVar(R)) + { + return false; + } + if (!checkScalarVar(S)) + { + return false; + } + + PointAffine pA = new PointAffine(); + if (!decodePointVar(pk, pkOff, true, pA)) + { + return false; + } + + Digest d = createDigest(); + byte[] h = new byte[d.getDigestSize()]; + + dom2(d, phflag, ctx); + d.update(R, 0, POINT_BYTES); + d.update(pk, pkOff, POINT_BYTES); + d.update(m, mOff, mLen); + d.doFinal(h, 0); + + byte[] k = reduceScalar(h); + + int[] nS = new int[SCALAR_INTS]; + decodeScalar(S, 0, nS); + + int[] nA = new int[SCALAR_INTS]; + decodeScalar(k, 0, nA); + + PointAccum pR = new PointAccum(); + scalarMultStrausVar(nS, nA, pA, pR); + + byte[] check = new byte[POINT_BYTES]; + return 0 != encodePoint(pR, check, 0) && Arrays.areEqual(check, R); + } + + private static void pointAdd(PointExt p, PointAccum r) + { + int[] A = X25519Field.create(); + int[] B = X25519Field.create(); + int[] C = X25519Field.create(); + int[] D = X25519Field.create(); + int[] E = r.u; + int[] F = X25519Field.create(); + int[] G = X25519Field.create(); + int[] H = r.v; + + X25519Field.apm(r.y, r.x, B, A); + X25519Field.apm(p.y, p.x, D, C); + X25519Field.mul(A, C, A); + X25519Field.mul(B, D, B); + X25519Field.mul(r.u, r.v, C); + X25519Field.mul(C, p.t, C); + X25519Field.mul(C, C_d2, C); + X25519Field.mul(r.z, p.z, D); + X25519Field.add(D, D, D); + X25519Field.apm(B, A, H, E); + X25519Field.apm(D, C, G, F); + X25519Field.carry(G); + X25519Field.mul(E, F, r.x); + X25519Field.mul(G, H, r.y); + X25519Field.mul(F, G, r.z); + } + + private static void pointAdd(PointExt p, PointExt r) { int[] A = X25519Field.create(); int[] B = X25519Field.create(); @@ -307,6 +543,34 @@ public abstract class Ed25519 int[] G = X25519Field.create(); int[] H = X25519Field.create(); + X25519Field.apm(p.y, p.x, B, A); + X25519Field.apm(r.y, r.x, D, C); + X25519Field.mul(A, C, A); + X25519Field.mul(B, D, B); + X25519Field.mul(p.t, r.t, C); + X25519Field.mul(C, C_d2, C); + X25519Field.mul(p.z, r.z, D); + X25519Field.add(D, D, D); + X25519Field.apm(B, A, H, E); + X25519Field.apm(D, C, G, F); + X25519Field.carry(G); + X25519Field.mul(E, F, r.x); + X25519Field.mul(G, H, r.y); + X25519Field.mul(F, G, r.z); + X25519Field.mul(E, H, r.t); + } + + private static void pointAddVar(boolean negate, PointExt p, PointAccum r) + { + int[] A = X25519Field.create(); + int[] B = X25519Field.create(); + int[] C = X25519Field.create(); + int[] D = X25519Field.create(); + int[] E = r.u; + int[] F = X25519Field.create(); + int[] G = X25519Field.create(); + int[] H = r.v; + int[] c, d, f, g; if (negate) { @@ -321,7 +585,8 @@ public abstract class Ed25519 X25519Field.apm(p.y, p.x, d, c); X25519Field.mul(A, C, A); X25519Field.mul(B, D, B); - X25519Field.mul(r.t, p.t, C); + X25519Field.mul(r.u, r.v, C); + X25519Field.mul(C, p.t, C); X25519Field.mul(C, C_d2, C); X25519Field.mul(r.z, p.z, D); X25519Field.add(D, D, D); @@ -331,51 +596,119 @@ public abstract class Ed25519 X25519Field.mul(E, F, r.x); X25519Field.mul(G, H, r.y); X25519Field.mul(F, G, r.z); - X25519Field.mul(E, H, r.t); } - private static void pointAddPrecomp(PointPrecomp p, PointExt r) + private static void pointAddVar(boolean negate, PointExt p, PointExt q, PointExt r) { int[] A = X25519Field.create(); int[] B = X25519Field.create(); int[] C = X25519Field.create(); + int[] D = X25519Field.create(); int[] E = X25519Field.create(); int[] F = X25519Field.create(); int[] G = X25519Field.create(); int[] H = X25519Field.create(); + int[] c, d, f, g; + if (negate) + { + c = D; d = C; f = G; g = F; + } + else + { + c = C; d = D; f = F; g = G; + } + + X25519Field.apm(p.y, p.x, B, A); + X25519Field.apm(q.y, q.x, d, c); + X25519Field.mul(A, C, A); + X25519Field.mul(B, D, B); + X25519Field.mul(p.t, q.t, C); + X25519Field.mul(C, C_d2, C); + X25519Field.mul(p.z, q.z, D); + X25519Field.add(D, D, D); + X25519Field.apm(B, A, H, E); + X25519Field.apm(D, C, g, f); + X25519Field.carry(g); + X25519Field.mul(E, F, r.x); + X25519Field.mul(G, H, r.y); + X25519Field.mul(F, G, r.z); + X25519Field.mul(E, H, r.t); + } + + private static void pointAddPrecomp(PointPrecomp p, PointAccum r) + { + int[] A = X25519Field.create(); + int[] B = X25519Field.create(); + int[] C = X25519Field.create(); + int[] E = r.u; + int[] F = X25519Field.create(); + int[] G = X25519Field.create(); + int[] H = r.v; + X25519Field.apm(r.y, r.x, B, A); X25519Field.mul(A, p.ymx_h, A); X25519Field.mul(B, p.ypx_h, B); - X25519Field.mul(r.t, p.xyd, C); + X25519Field.mul(r.u, r.v, C); + X25519Field.mul(C, p.xyd, C); X25519Field.apm(B, A, H, E); X25519Field.apm(r.z, C, G, F); X25519Field.carry(G); X25519Field.mul(E, F, r.x); X25519Field.mul(G, H, r.y); X25519Field.mul(F, G, r.z); - X25519Field.mul(E, H, r.t); + } + + private static PointExt pointCopy(PointAccum p) + { + PointExt r = new PointExt(); + X25519Field.copy(p.x, 0, r.x, 0); + X25519Field.copy(p.y, 0, r.y, 0); + X25519Field.copy(p.z, 0, r.z, 0); + X25519Field.mul(p.u, p.v, r.t); + return r; + } + + private static PointExt pointCopy(PointAffine p) + { + PointExt r = new PointExt(); + X25519Field.copy(p.x, 0, r.x, 0); + X25519Field.copy(p.y, 0, r.y, 0); + pointExtendXY(r); + return r; } private static PointExt pointCopy(PointExt p) { PointExt r = new PointExt(); + pointCopy(p, r); + return r; + } + + private static void pointCopy(PointAffine p, PointAccum r) + { + X25519Field.copy(p.x, 0, r.x, 0); + X25519Field.copy(p.y, 0, r.y, 0); + pointExtendXY(r); + } + + private static void pointCopy(PointExt p, PointExt r) + { X25519Field.copy(p.x, 0, r.x, 0); X25519Field.copy(p.y, 0, r.y, 0); X25519Field.copy(p.z, 0, r.z, 0); X25519Field.copy(p.t, 0, r.t, 0); - return r; } - private static void pointDouble(PointExt r) + private static void pointDouble(PointAccum r) { int[] A = X25519Field.create(); int[] B = X25519Field.create(); int[] C = X25519Field.create(); - int[] E = X25519Field.create(); + int[] E = r.u; int[] F = X25519Field.create(); int[] G = X25519Field.create(); - int[] H = X25519Field.create(); + int[] H = r.v; X25519Field.sqr(r.x, A); X25519Field.sqr(r.y, B); @@ -390,7 +723,13 @@ public abstract class Ed25519 X25519Field.mul(E, F, r.x); X25519Field.mul(G, H, r.y); X25519Field.mul(F, G, r.z); - X25519Field.mul(E, H, r.t); + } + + private static void pointExtendXY(PointAccum p) + { + X25519Field.one(p.z); + X25519Field.copy(p.x, 0, p.u, 0); + X25519Field.copy(p.y, 0, p.v, 0); } private static void pointExtendXY(PointExt p) @@ -408,28 +747,101 @@ public abstract class Ed25519 for (int i = 0; i < PRECOMP_POINTS; ++i) { - int mask = ((i ^ index) - 1) >> 31; - Nat.cmov(X25519Field.SIZE, mask, precompBase, off, p.ypx_h, 0); off += X25519Field.SIZE; - Nat.cmov(X25519Field.SIZE, mask, precompBase, off, p.ymx_h, 0); off += X25519Field.SIZE; - Nat.cmov(X25519Field.SIZE, mask, precompBase, off, p.xyd, 0); off += X25519Field.SIZE; + int cond = ((i ^ index) - 1) >> 31; + X25519Field.cmov(cond, precompBase, off, p.ypx_h, 0); off += X25519Field.SIZE; + X25519Field.cmov(cond, precompBase, off, p.ymx_h, 0); off += X25519Field.SIZE; + X25519Field.cmov(cond, precompBase, off, p.xyd, 0); off += X25519Field.SIZE; + } + } + + private static void pointLookup(int[] x, int n, int[] table, PointExt r) + { + int w = getWindow4(x, n); + + int sign = (w >>> (PRECOMP_TEETH - 1)) ^ 1; + int abs = (w ^ -sign) & PRECOMP_MASK; + +// assert sign == 0 || sign == 1; +// assert 0 <= abs && abs < PRECOMP_POINTS; + + for (int i = 0, off = 0; i < PRECOMP_POINTS; ++i) + { + int cond = ((i ^ abs) - 1) >> 31; + X25519Field.cmov(cond, table, off, r.x, 0); off += X25519Field.SIZE; + X25519Field.cmov(cond, table, off, r.y, 0); off += X25519Field.SIZE; + X25519Field.cmov(cond, table, off, r.z, 0); off += X25519Field.SIZE; + X25519Field.cmov(cond, table, off, r.t, 0); off += X25519Field.SIZE; + } + + X25519Field.cnegate(sign, r.x); + X25519Field.cnegate(sign, r.t); + } + + private static void pointLookup(int[] table, int index, PointExt r) + { + int off = X25519Field.SIZE * 4 * index; + + X25519Field.copy(table, off, r.x, 0); off += X25519Field.SIZE; + X25519Field.copy(table, off, r.y, 0); off += X25519Field.SIZE; + X25519Field.copy(table, off, r.z, 0); off += X25519Field.SIZE; + X25519Field.copy(table, off, r.t, 0); + } + + private static int[] pointPrecomp(PointAffine p, int count) + { +// assert count > 0; + + PointExt q = pointCopy(p); + PointExt d = pointCopy(q); + pointAdd(q, d); + + int[] table = X25519Field.createTable(count * 4); + int off = 0; + + int i = 0; + for (;;) + { + X25519Field.copy(q.x, 0, table, off); off += X25519Field.SIZE; + X25519Field.copy(q.y, 0, table, off); off += X25519Field.SIZE; + X25519Field.copy(q.z, 0, table, off); off += X25519Field.SIZE; + X25519Field.copy(q.t, 0, table, off); off += X25519Field.SIZE; + + if (++i == count) + { + break; + } + + pointAdd(d, q); } + + return table; } private static PointExt[] pointPrecompVar(PointExt p, int count) { - PointExt d = pointCopy(p); - pointDouble(d); +// assert count > 0; + + PointExt d = new PointExt(); + pointAddVar(false, p, p, d); PointExt[] table = new PointExt[count]; table[0] = pointCopy(p); for (int i = 1; i < count; ++i) { - table[i] = pointCopy(table[i - 1]); - pointAddVar(false, d, table[i]); + pointAddVar(false, table[i - 1], d, table[i] = new PointExt()); } return table; } + private static void pointSetNeutral(PointAccum p) + { + X25519Field.zero(p.x); + X25519Field.one(p.y); + X25519Field.one(p.z); + X25519Field.zero(p.u); + X25519Field.one(p.v); + } + private static void pointSetNeutral(PointExt p) { X25519Field.zero(p.x); @@ -438,88 +850,102 @@ public abstract class Ed25519 X25519Field.zero(p.t); } - public synchronized static void precompute() + public static void precompute() { - if (precompBase != null) + synchronized (precompLock) { - return; - } - - PointExt p = new PointExt(); - X25519Field.copy(B_x, 0, p.x, 0); - X25519Field.copy(B_y, 0, p.y, 0); - pointExtendXY(p); + if (precompBase != null) + { + return; + } - precompBaseTable = pointPrecompVar(p, 1 << (WNAF_WIDTH_BASE - 2)); + // Precomputed table for the base point in verification ladder + { + PointExt b = new PointExt(); + X25519Field.copy(B_x, 0, b.x, 0); + X25519Field.copy(B_y, 0, b.y, 0); + pointExtendXY(b); - precompBase = new int[PRECOMP_BLOCKS * PRECOMP_POINTS * 3 * X25519Field.SIZE]; + precompBaseTable = pointPrecompVar(b, 1 << (WNAF_WIDTH_BASE - 2)); + } - int off = 0; - for (int b = 0; b < PRECOMP_BLOCKS; ++b) - { - PointExt[] ds = new PointExt[PRECOMP_TEETH]; + PointAccum p = new PointAccum(); + X25519Field.copy(B_x, 0, p.x, 0); + X25519Field.copy(B_y, 0, p.y, 0); + pointExtendXY(p); - PointExt sum = new PointExt(); - pointSetNeutral(sum); + precompBase = X25519Field.createTable(PRECOMP_BLOCKS * PRECOMP_POINTS * 3); - for (int t = 0; t < PRECOMP_TEETH; ++t) + int off = 0; + for (int b = 0; b < PRECOMP_BLOCKS; ++b) { - pointAddVar(true, p, sum); - pointDouble(p); + PointExt[] ds = new PointExt[PRECOMP_TEETH]; - ds[t] = pointCopy(p); + PointExt sum = new PointExt(); + pointSetNeutral(sum); - for (int s = 1; s < PRECOMP_SPACING; ++s) + for (int t = 0; t < PRECOMP_TEETH; ++t) { + PointExt q = pointCopy(p); + pointAddVar(true, sum, q, sum); pointDouble(p); + + ds[t] = pointCopy(p); + + if (b + t != PRECOMP_BLOCKS + PRECOMP_TEETH - 2) + { + for (int s = 1; s < PRECOMP_SPACING; ++s) + { + pointDouble(p); + } + } } - } - PointExt[] points = new PointExt[PRECOMP_POINTS]; - int k = 0; - points[k++] = sum; + PointExt[] points = new PointExt[PRECOMP_POINTS]; + int k = 0; + points[k++] = sum; - for (int t = 0; t < (PRECOMP_TEETH - 1); ++t) - { - int size = 1 << t; - for (int j = 0; j < size; ++j) + for (int t = 0; t < (PRECOMP_TEETH - 1); ++t) { - points[k] = pointCopy(points[k - size]); - pointAddVar(false, ds[t], points[k++]); + int size = 1 << t; + for (int j = 0; j < size; ++j, ++k) + { + pointAddVar(false, points[k - size], ds[t], points[k] = new PointExt()); + } } - } -// assert k == POINTS; +// assert k == PRECOMP_POINTS; - for (int i = 0; i < PRECOMP_POINTS; ++i) - { - PointExt q = points[i]; + for (int i = 0; i < PRECOMP_POINTS; ++i) + { + PointExt q = points[i]; - int[] x = X25519Field.create(); - int[] y = X25519Field.create(); + int[] x = X25519Field.create(); + int[] y = X25519Field.create(); - X25519Field.add(q.z, q.z, x); - // TODO[ed25519] Batch inversion - X25519Field.inv(x, y); - X25519Field.mul(q.x, y, x); - X25519Field.mul(q.y, y, y); + X25519Field.add(q.z, q.z, x); + // TODO[ed25519] Batch inversion + X25519Field.inv(x, y); + X25519Field.mul(q.x, y, x); + X25519Field.mul(q.y, y, y); - PointPrecomp r = new PointPrecomp(); - X25519Field.apm(y, x, r.ypx_h, r.ymx_h); - X25519Field.mul(x, y, r.xyd); - X25519Field.mul(r.xyd, C_d4, r.xyd); + PointPrecomp r = new PointPrecomp(); + X25519Field.apm(y, x, r.ypx_h, r.ymx_h); + X25519Field.mul(x, y, r.xyd); + X25519Field.mul(r.xyd, C_d4, r.xyd); - X25519Field.normalize(r.ypx_h); - X25519Field.normalize(r.ymx_h); -// X25519Field.normalize(r.xyd); + X25519Field.normalize(r.ypx_h); + X25519Field.normalize(r.ymx_h); +// X25519Field.normalize(r.xyd); - X25519Field.copy(r.ypx_h, 0, precompBase, off); off += X25519Field.SIZE; - X25519Field.copy(r.ymx_h, 0, precompBase, off); off += X25519Field.SIZE; - X25519Field.copy(r.xyd, 0, precompBase, off); off += X25519Field.SIZE; + X25519Field.copy(r.ypx_h, 0, precompBase, off); off += X25519Field.SIZE; + X25519Field.copy(r.ymx_h, 0, precompBase, off); off += X25519Field.SIZE; + X25519Field.copy(r.xyd, 0, precompBase, off); off += X25519Field.SIZE; + } } - } -// assert off == precompBase.length; +// assert off == precompBase.length; + } } private static void pruneScalar(byte[] n, int nOff, byte[] r) @@ -667,7 +1093,55 @@ public abstract class Ed25519 return r; } - private static void scalarMultBase(byte[] k, PointExt r) + private static void scalarMult(byte[] k, PointAffine p, PointAccum r) + { + precompute(); + + int[] n = new int[SCALAR_INTS]; + decodeScalar(k, 0, n); + +// assert 0 == (n[0] & 7); +// assert 1 == n[SCALAR_INTS - 1] >>> 30; + + Nat.shiftDownBits(SCALAR_INTS, n, 3, 1); + +// int c1 = Nat.cadd(SCALAR_INTS, ~n[0] & 1, n, L, n); assert c1 == 0; + Nat.cadd(SCALAR_INTS, ~n[0] & 1, n, L, n); +// int c2 = Nat.shiftDownBit(SCALAR_INTS, n, 0); assert c2 == (1 << 31); + Nat.shiftDownBit(SCALAR_INTS, n, 0); + +// assert 1 == n[SCALAR_INTS - 1] >>> 28; + + pointCopy(p, r); + + int[] table = pointPrecomp(p, 8); + + PointExt q = new PointExt(); + + // Replace first 4 doublings (2^4 * P) with 1 addition (P + 15 * P) + pointLookup(table, 7, q); + pointAdd(q, r); + + int w = 62; + for (;;) + { + pointLookup(n, w, table, q); + pointAdd(q, r); + + pointDouble(r); + pointDouble(r); + pointDouble(r); + + if (--w < 0) + { + break; + } + + pointDouble(r); + } + } + + private static void scalarMultBase(byte[] k, PointAccum r) { precompute(); @@ -722,12 +1196,38 @@ public abstract class Ed25519 private static void scalarMultBaseEncoded(byte[] k, byte[] r, int rOff) { - PointExt p = new PointExt(); + PointAccum p = new PointAccum(); scalarMultBase(k, p); - encodePoint(p, r, rOff); + if (0 == encodePoint(p, r, rOff)) + { + throw new IllegalStateException(); + } + } + + /** + * NOTE: Only for use by X25519 + */ + public static void scalarMultBaseYZ(X25519.Friend friend, byte[] k, int kOff, int[] y, int[] z) + { + if (null == friend) + { + throw new NullPointerException("This method is only for use by X25519"); + } + + byte[] n = new byte[SCALAR_BYTES]; + pruneScalar(k, kOff, n); + + PointAccum p = new PointAccum(); + scalarMultBase(n, p); + if (0 == checkPoint(p.x, p.y, p.z)) + { + throw new IllegalStateException(); + } + X25519Field.copy(p.y, 0, y, 0); + X25519Field.copy(p.z, 0, z, 0); } - private static void scalarMultStraussVar(int[] nb, int[] np, PointExt p, PointExt r) + private static void scalarMultStrausVar(int[] nb, int[] np, PointAffine p, PointAccum r) { precompute(); @@ -736,17 +1236,11 @@ public abstract class Ed25519 byte[] ws_b = getWNAF(nb, WNAF_WIDTH_BASE); byte[] ws_p = getWNAF(np, width); - PointExt[] tp = pointPrecompVar(p, 1 << (width - 2)); + PointExt[] tp = pointPrecompVar(pointCopy(p), 1 << (width - 2)); pointSetNeutral(r); - int bit = 255; - while (bit > 0 && (ws_b[bit] | ws_p[bit]) == 0) - { - --bit; - } - - for (;;) + for (int bit = 252;;) { int wb = ws_b[bit]; if (wb != 0) @@ -777,77 +1271,106 @@ public abstract class Ed25519 public static void sign(byte[] sk, int skOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { - SHA512Digest d = new SHA512Digest(); - byte[] h = new byte[d.getDigestSize()]; + byte[] ctx = null; + byte phflag = 0x00; - d.update(sk, skOff, SECRET_KEY_SIZE); - d.doFinal(h, 0); + implSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } - byte[] s = new byte[SCALAR_BYTES]; - pruneScalar(h, 0, s); + public static void sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + byte[] ctx = null; + byte phflag = 0x00; - byte[] pk = new byte[POINT_BYTES]; - scalarMultBaseEncoded(s, pk, 0); + implSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } + + public static void sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + byte phflag = 0x00; - implSign(d, h, s, pk, 0, m, mOff, mLen, sig, sigOff); + implSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff); } - public static void sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + public static void sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { - SHA512Digest d = new SHA512Digest(); - byte[] h = new byte[d.getDigestSize()]; + byte phflag = 0x00; - d.update(sk, skOff, SECRET_KEY_SIZE); - d.doFinal(h, 0); + implSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } - byte[] s = new byte[SCALAR_BYTES]; - pruneScalar(h, 0, s); + public static void signPrehash(byte[] sk, int skOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff) + { + byte phflag = 0x01; - implSign(d, h, s, pk, pkOff, m, mOff, mLen, sig, sigOff); + implSign(sk, skOff, ctx, phflag, ph, phOff, PREHASH_SIZE, sig, sigOff); } - public static boolean verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen) + public static void signPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff) { - byte[] R = Arrays.copyOfRange(sig, sigOff, sigOff + POINT_BYTES); - byte[] S = Arrays.copyOfRange(sig, sigOff + POINT_BYTES, sigOff + SIGNATURE_SIZE); + byte phflag = 0x01; - if (!checkPointVar(R)) - { - return false; - } - if (!checkScalarVar(S)) + implSign(sk, skOff, pk, pkOff, ctx, phflag, ph, phOff, PREHASH_SIZE, sig, sigOff); + } + + public static void signPrehash(byte[] sk, int skOff, byte[] ctx, Digest ph, byte[] sig, int sigOff) + { + byte[] m = new byte[PREHASH_SIZE]; + if (PREHASH_SIZE != ph.doFinal(m, 0)) { - return false; + throw new IllegalArgumentException("ph"); } - PointExt pA = new PointExt(); - if (!decodePointVar(pk, pkOff, true, pA)) + byte phflag = 0x01; + + implSign(sk, skOff, ctx, phflag, m, 0, m.length, sig, sigOff); + } + + public static void signPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, Digest ph, byte[] sig, int sigOff) + { + byte[] m = new byte[PREHASH_SIZE]; + if (PREHASH_SIZE != ph.doFinal(m, 0)) { - return false; + throw new IllegalArgumentException("ph"); } - SHA512Digest d = new SHA512Digest(); - byte[] h = new byte[d.getDigestSize()]; + byte phflag = 0x01; - d.update(R, 0, POINT_BYTES); - d.update(pk, pkOff, POINT_BYTES); - d.update(m, mOff, mLen); - d.doFinal(h, 0); + implSign(sk, skOff, pk, pkOff, ctx, phflag, m, 0, m.length, sig, sigOff); + } - byte[] k = reduceScalar(h); + public static boolean verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] m, int mOff, int mLen) + { + byte[] ctx = null; + byte phflag = 0x00; - int[] nS = new int[SCALAR_INTS]; - decodeScalar(S, 0, nS); + return implVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen); + } - int[] nA = new int[SCALAR_INTS]; - decodeScalar(k, 0, nA); + public static boolean verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen) + { + byte phflag = 0x00; + + return implVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen); + } - PointExt pR = new PointExt(); - scalarMultStraussVar(nS, nA, pA, pR); + public static boolean verifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff) + { + byte phflag = 0x01; - byte[] check = new byte[POINT_BYTES]; - encodePoint(pR, check, 0); + return implVerify(sig, sigOff, pk, pkOff, ctx, phflag, ph, phOff, PREHASH_SIZE); + } + + public static boolean verifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, Digest ph) + { + byte[] m = new byte[PREHASH_SIZE]; + if (PREHASH_SIZE != ph.doFinal(m, 0)) + { + throw new IllegalArgumentException("ph"); + } + + byte phflag = 0x01; - return Arrays.areEqual(check, R); + return implVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, 0, m.length); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc8032/Ed448.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc8032/Ed448.java index 2a3d3aa4e..3a6f9d952 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc8032/Ed448.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/rfc8032/Ed448.java @@ -1,6 +1,10 @@ package com.fr.third.org.bouncycastle.math.ec.rfc8032; +import java.security.SecureRandom; + +import com.fr.third.org.bouncycastle.crypto.Xof; import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest; +import com.fr.third.org.bouncycastle.math.ec.rfc7748.X448; import com.fr.third.org.bouncycastle.math.ec.rfc7748.X448Field; import com.fr.third.org.bouncycastle.math.raw.Nat; import com.fr.third.org.bouncycastle.util.Arrays; @@ -8,6 +12,14 @@ import com.fr.third.org.bouncycastle.util.Strings; public abstract class Ed448 { + // x^2 + y^2 == 1 - 39081 * x^2 * y^2 + + public static final class Algorithm + { + public static final int Ed448 = 0; + public static final int Ed448ph = 1; + } + private static final long M26L = 0x03FFFFFFL; private static final long M28L = 0x0FFFFFFFL; private static final long M32L = 0xFFFFFFFFL; @@ -16,6 +28,7 @@ public abstract class Ed448 private static final int SCALAR_INTS = 14; private static final int SCALAR_BYTES = SCALAR_INTS * 4 + 1; + public static final int PREHASH_SIZE = 64; public static final int PUBLIC_KEY_SIZE = POINT_BYTES; public static final int SECRET_KEY_SIZE = 57; public static final int SIGNATURE_SIZE = POINT_BYTES + SCALAR_BYTES; @@ -59,6 +72,7 @@ public abstract class Ed448 private static final int PRECOMP_POINTS = 1 << (PRECOMP_TEETH - 1); private static final int PRECOMP_MASK = PRECOMP_POINTS - 1; + private static final Object precompLock = new Object(); // TODO[ed448] Convert to PointPrecomp private static PointExt[] precompBaseTable = null; private static int[] precompBase = null; @@ -97,6 +111,46 @@ public abstract class Ed448 return ctx != null && ctx.length < 256; } + private static int checkPoint(int[] x, int[] y) + { + int[] t = X448Field.create(); + int[] u = X448Field.create(); + int[] v = X448Field.create(); + + X448Field.sqr(x, u); + X448Field.sqr(y, v); + X448Field.mul(u, v, t); + X448Field.add(u, v, u); + X448Field.mul(t, -C_d, t); + X448Field.subOne(t); + X448Field.add(t, u, t); + X448Field.normalize(t); + + return X448Field.isZero(t); + } + + private static int checkPoint(int[] x, int[] y, int[] z) + { + int[] t = X448Field.create(); + int[] u = X448Field.create(); + int[] v = X448Field.create(); + int[] w = X448Field.create(); + + X448Field.sqr(x, u); + X448Field.sqr(y, v); + X448Field.sqr(z, w); + X448Field.mul(u, v, t); + X448Field.add(u, v, u); + X448Field.mul(u, w, u); + X448Field.sqr(w, w); + X448Field.mul(t, -C_d, t); + X448Field.sub(t, w, t); + X448Field.add(t, u, t); + X448Field.normalize(t); + + return X448Field.isZero(t); + } + private static boolean checkPointVar(byte[] p) { if ((p[POINT_BYTES - 1] & 0x7F) != 0x00) @@ -121,6 +175,16 @@ public abstract class Ed448 return !Nat.gte(SCALAR_INTS, n, L); } + public static Xof createPrehash() + { + return createXof(); + } + + private static Xof createXof() + { + return new SHAKEDigest(256); + } + private static int decode16(byte[] bs, int off) { int n = bs[off] & 0xFF; @@ -202,7 +266,7 @@ public abstract class Ed448 decode32(k, kOff, n, 0, SCALAR_INTS); } - private static void dom4(SHAKEDigest d, byte x, byte[] y) + private static void dom4(Xof d, byte x, byte[] y) { d.update(DOM4_PREFIX, 0, DOM4_PREFIX.length); d.update(x); @@ -231,7 +295,7 @@ public abstract class Ed448 encode24((int)(n >>> 32), bs, off + 4); } - private static void encodePoint(PointExt p, byte[] r, int rOff) + private static int encodePoint(PointExt p, byte[] r, int rOff) { int[] x = X448Field.create(); int[] y = X448Field.create(); @@ -242,13 +306,22 @@ public abstract class Ed448 X448Field.normalize(x); X448Field.normalize(y); + int result = checkPoint(x, y); + X448Field.encode(y, r, rOff); r[rOff + POINT_BYTES - 1] = (byte)((x[0] & 1) << 7); + + return result; + } + + public static void generatePrivateKey(SecureRandom random, byte[] k) + { + random.nextBytes(k); } public static void generatePublicKey(byte[] sk, int skOff, byte[] pk, int pkOff) { - SHAKEDigest d = new SHAKEDigest(256); + Xof d = createXof(); byte[] h = new byte[SCALAR_BYTES * 2]; d.update(sk, skOff, SECRET_KEY_SIZE); @@ -257,12 +330,18 @@ public abstract class Ed448 byte[] s = new byte[SCALAR_BYTES]; pruneScalar(h, 0, s); - scalarMultBaseEncodedVar(s, pk, pkOff); + scalarMultBaseEncoded(s, pk, pkOff); + } + + private static int getWindow4(int[] x, int n) + { + int w = n >>> 3, b = (n & 7) << 2; + return (x[w] >>> b) & 15; } private static byte[] getWNAF(int[] n, int width) { -// assert n[SCALAR_INTS - 1] >>> 31 == 0; +// assert n[SCALAR_INTS - 1] >>> 30 == 0; int[] t = new int[SCALAR_INTS * 2]; { @@ -276,7 +355,7 @@ public abstract class Ed448 } } - byte[] ws = new byte[448]; + byte[] ws = new byte[447]; final int pow2 = 1 << width; final int mask = pow2 - 1; @@ -313,10 +392,9 @@ public abstract class Ed448 return ws; } - private static void implSignVar(SHAKEDigest d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + private static void implSign(Xof d, byte[] h, byte[] s, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { - byte phflag = 0x00; - dom4(d, phflag, ctx); d.update(h, SCALAR_BYTES, SCALAR_BYTES); d.update(m, mOff, mLen); @@ -324,7 +402,7 @@ public abstract class Ed448 byte[] r = reduceScalar(h); byte[] R = new byte[POINT_BYTES]; - scalarMultBaseEncodedVar(r, R, 0); + scalarMultBaseEncoded(r, R, 0); dom4(d, phflag, ctx); d.update(R, 0, POINT_BYTES); @@ -339,6 +417,134 @@ public abstract class Ed448 System.arraycopy(S, 0, sig, sigOff + POINT_BYTES, SCALAR_BYTES); } + private static void implSign(byte[] sk, int skOff, byte[] ctx, byte phflag, byte[] m, int mOff, int mLen, + byte[] sig, int sigOff) + { + if (!checkContextVar(ctx)) + { + throw new IllegalArgumentException("ctx"); + } + + Xof d = createXof(); + byte[] h = new byte[SCALAR_BYTES * 2]; + + d.update(sk, skOff, SECRET_KEY_SIZE); + d.doFinal(h, 0, h.length); + + byte[] s = new byte[SCALAR_BYTES]; + pruneScalar(h, 0, s); + + byte[] pk = new byte[POINT_BYTES]; + scalarMultBaseEncoded(s, pk, 0); + + implSign(d, h, s, pk, 0, ctx, phflag, m, mOff, mLen, sig, sigOff); + } + + private static void implSign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen, byte[] sig, int sigOff) + { + if (!checkContextVar(ctx)) + { + throw new IllegalArgumentException("ctx"); + } + + Xof d = createXof(); + byte[] h = new byte[SCALAR_BYTES * 2]; + + d.update(sk, skOff, SECRET_KEY_SIZE); + d.doFinal(h, 0, h.length); + + byte[] s = new byte[SCALAR_BYTES]; + pruneScalar(h, 0, s); + + implSign(d, h, s, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } + + private static boolean implVerify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte phflag, + byte[] m, int mOff, int mLen) + { + if (!checkContextVar(ctx)) + { + throw new IllegalArgumentException("ctx"); + } + + byte[] R = Arrays.copyOfRange(sig, sigOff, sigOff + POINT_BYTES); + byte[] S = Arrays.copyOfRange(sig, sigOff + POINT_BYTES, sigOff + SIGNATURE_SIZE); + + if (!checkPointVar(R)) + { + return false; + } + if (!checkScalarVar(S)) + { + return false; + } + + PointExt pA = new PointExt(); + if (!decodePointVar(pk, pkOff, true, pA)) + { + return false; + } + + Xof d = createXof(); + byte[] h = new byte[SCALAR_BYTES * 2]; + + dom4(d, phflag, ctx); + d.update(R, 0, POINT_BYTES); + d.update(pk, pkOff, POINT_BYTES); + d.update(m, mOff, mLen); + d.doFinal(h, 0, h.length); + + byte[] k = reduceScalar(h); + + int[] nS = new int[SCALAR_INTS]; + decodeScalar(S, 0, nS); + + int[] nA = new int[SCALAR_INTS]; + decodeScalar(k, 0, nA); + + PointExt pR = new PointExt(); + scalarMultStrausVar(nS, nA, pA, pR); + + byte[] check = new byte[POINT_BYTES]; + return 0 != encodePoint(pR, check, 0) && Arrays.areEqual(check, R); + } + + private static void pointAdd(PointExt p, PointExt r) + { + int[] A = X448Field.create(); + int[] B = X448Field.create(); + int[] C = X448Field.create(); + int[] D = X448Field.create(); + int[] E = X448Field.create(); + int[] F = X448Field.create(); + int[] G = X448Field.create(); + int[] H = X448Field.create(); + + X448Field.mul(p.z, r.z, A); + X448Field.sqr(A, B); + X448Field.mul(p.x, r.x, C); + X448Field.mul(p.y, r.y, D); + X448Field.mul(C, D, E); + X448Field.mul(E, -C_d, E); +// X448Field.apm(B, E, F, G); + X448Field.add(B, E, F); + X448Field.sub(B, E, G); + X448Field.add(p.x, p.y, B); + X448Field.add(r.x, r.y, E); + X448Field.mul(B, E, H); +// X448Field.apm(D, C, B, E); + X448Field.add(D, C, B); + X448Field.sub(D, C, E); + X448Field.carry(B); + X448Field.sub(H, B, H); + X448Field.mul(H, A, H); + X448Field.mul(E, A, E); + X448Field.mul(F, H, r.x); + X448Field.mul(E, G, r.y); + X448Field.mul(F, G, r.z); + } + private static void pointAddVar(boolean negate, PointExt p, PointExt r) { int[] A = X448Field.create(); @@ -421,10 +627,15 @@ public abstract class Ed448 private static PointExt pointCopy(PointExt p) { PointExt r = new PointExt(); + pointCopy(p, r); + return r; + } + + private static void pointCopy(PointExt p, PointExt r) + { X448Field.copy(p.x, 0, r.x, 0); X448Field.copy(p.y, 0, r.y, 0); X448Field.copy(p.z, 0, r.z, 0); - return r; } private static void pointDouble(PointExt r) @@ -467,14 +678,66 @@ public abstract class Ed448 for (int i = 0; i < PRECOMP_POINTS; ++i) { - int mask = ((i ^ index) - 1) >> 31; - Nat.cmov(X448Field.SIZE, mask, precompBase, off, p.x, 0); off += X448Field.SIZE; - Nat.cmov(X448Field.SIZE, mask, precompBase, off, p.y, 0); off += X448Field.SIZE; + int cond = ((i ^ index) - 1) >> 31; + X448Field.cmov(cond, precompBase, off, p.x, 0); off += X448Field.SIZE; + X448Field.cmov(cond, precompBase, off, p.y, 0); off += X448Field.SIZE; + } + } + + private static void pointLookup(int[] x, int n, int[] table, PointExt r) + { + int w = getWindow4(x, n); + + int sign = (w >>> (4 - 1)) ^ 1; + int abs = (w ^ -sign) & 7; + +// assert sign == 0 || sign == 1; +// assert 0 <= abs && abs < 8; + + for (int i = 0, off = 0; i < 8; ++i) + { + int cond = ((i ^ abs) - 1) >> 31; + X448Field.cmov(cond, table, off, r.x, 0); off += X448Field.SIZE; + X448Field.cmov(cond, table, off, r.y, 0); off += X448Field.SIZE; + X448Field.cmov(cond, table, off, r.z, 0); off += X448Field.SIZE; } + + X448Field.cnegate(sign, r.x); + } + + private static int[] pointPrecomp(PointExt p, int count) + { +// assert count > 0; + + PointExt q = pointCopy(p); + PointExt d = pointCopy(q); + pointDouble(d); + + int[] table = X448Field.createTable(count * 3); + int off = 0; + + int i = 0; + for (;;) + { + X448Field.copy(q.x, 0, table, off); off += X448Field.SIZE; + X448Field.copy(q.y, 0, table, off); off += X448Field.SIZE; + X448Field.copy(q.z, 0, table, off); off += X448Field.SIZE; + + if (++i == count) + { + break; + } + + pointAdd(d, q); + } + + return table; } private static PointExt[] pointPrecompVar(PointExt p, int count) { +// assert count > 0; + PointExt d = pointCopy(p); pointDouble(d); @@ -495,85 +758,91 @@ public abstract class Ed448 X448Field.one(p.z); } - public synchronized static void precompute() + public static void precompute() { - if (precompBase != null) + synchronized (precompLock) { - return; - } - - PointExt p = new PointExt(); - X448Field.copy(B_x, 0, p.x, 0); - X448Field.copy(B_y, 0, p.y, 0); - pointExtendXY(p); + if (precompBase != null) + { + return; + } - precompBaseTable = pointPrecompVar(p, 1 << (WNAF_WIDTH_BASE - 2)); + PointExt p = new PointExt(); + X448Field.copy(B_x, 0, p.x, 0); + X448Field.copy(B_y, 0, p.y, 0); + pointExtendXY(p); - precompBase = new int[PRECOMP_BLOCKS * PRECOMP_POINTS * 2 * X448Field.SIZE]; + precompBaseTable = pointPrecompVar(p, 1 << (WNAF_WIDTH_BASE - 2)); - int off = 0; - for (int b = 0; b < PRECOMP_BLOCKS; ++b) - { - PointExt[] ds = new PointExt[PRECOMP_TEETH]; + precompBase = X448Field.createTable(PRECOMP_BLOCKS * PRECOMP_POINTS * 2); - PointExt sum = new PointExt(); - pointSetNeutral(sum); - - for (int t = 0; t < PRECOMP_TEETH; ++t) + int off = 0; + for (int b = 0; b < PRECOMP_BLOCKS; ++b) { - pointAddVar(true, p, sum); - pointDouble(p); + PointExt[] ds = new PointExt[PRECOMP_TEETH]; - ds[t] = pointCopy(p); + PointExt sum = new PointExt(); + pointSetNeutral(sum); - for (int s = 1; s < PRECOMP_SPACING; ++s) + for (int t = 0; t < PRECOMP_TEETH; ++t) { + pointAddVar(true, p, sum); pointDouble(p); + + ds[t] = pointCopy(p); + + if (b + t != PRECOMP_BLOCKS + PRECOMP_TEETH - 2) + { + for (int s = 1; s < PRECOMP_SPACING; ++s) + { + pointDouble(p); + } + } } - } - PointExt[] points = new PointExt[PRECOMP_POINTS]; - int k = 0; - points[k++] = sum; + PointExt[] points = new PointExt[PRECOMP_POINTS]; + int k = 0; + points[k++] = sum; - for (int t = 0; t < (PRECOMP_TEETH - 1); ++t) - { - int size = 1 << t; - for (int j = 0; j < size; ++j) + for (int t = 0; t < (PRECOMP_TEETH - 1); ++t) { - points[k] = pointCopy(points[k - size]); - pointAddVar(false, ds[t], points[k++]); + int size = 1 << t; + for (int j = 0; j < size; ++j, ++k) + { + points[k] = pointCopy(points[k - size]); + pointAddVar(false, ds[t], points[k]); + } } - } -// assert k == POINTS; +// assert k == PRECOMP_POINTS; - for (int i = 0; i < PRECOMP_POINTS; ++i) - { - PointExt q = points[i]; - // TODO[ed448] Batch inversion - X448Field.inv(q.z, q.z); - X448Field.mul(q.x, q.z, q.x); - X448Field.mul(q.y, q.z, q.y); + for (int i = 0; i < PRECOMP_POINTS; ++i) + { + PointExt q = points[i]; + // TODO[ed448] Batch inversion + X448Field.inv(q.z, q.z); + X448Field.mul(q.x, q.z, q.x); + X448Field.mul(q.y, q.z, q.y); -// X448Field.normalize(q.x); -// X448Field.normalize(q.y); +// X448Field.normalize(q.x); +// X448Field.normalize(q.y); - X448Field.copy(q.x, 0, precompBase, off); off += X448Field.SIZE; - X448Field.copy(q.y, 0, precompBase, off); off += X448Field.SIZE; + X448Field.copy(q.x, 0, precompBase, off); off += X448Field.SIZE; + X448Field.copy(q.y, 0, precompBase, off); off += X448Field.SIZE; + } } - } -// assert off == precompBase.length; +// assert off == precompBase.length; + } } private static void pruneScalar(byte[] n, int nOff, byte[] r) { - System.arraycopy(n, nOff, r, 0, SCALAR_BYTES); + System.arraycopy(n, nOff, r, 0, SCALAR_BYTES - 1); r[0] &= 0xFC; r[SCALAR_BYTES - 2] |= 0x80; - r[SCALAR_BYTES - 1] &= 0x00; + r[SCALAR_BYTES - 1] = 0x00; } private static byte[] reduceScalar(byte[] n) @@ -853,6 +1122,48 @@ public abstract class Ed448 return r; } + private static void scalarMult(byte[] k, PointExt p, PointExt r) + { + precompute(); + + int[] n = new int[SCALAR_INTS]; + decodeScalar(k, 0, n); + +// assert 0 == (n[0] & 3); +// assert 1 == n[SCALAR_INTS - 1] >>> 31; + + Nat.shiftDownBits(SCALAR_INTS, n, 2, 0); + + // Recode the scalar into signed-digit form + { +// int c1 = Nat.cadd(SCALAR_INTS, ~n[0] & 1, n, L, n); assert c1 == 0; + Nat.cadd(SCALAR_INTS, ~n[0] & 1, n, L, n); +// int c2 = Nat.shiftDownBit(SCALAR_INTS, n, 1); assert c2 == (1 << 31); + Nat.shiftDownBit(SCALAR_INTS, n, 1); + } + + int[] table = pointPrecomp(p, 8); + + pointLookup(n, 111, table, r); + + PointExt q = new PointExt(); + for (int w = 110; w >= 0; --w) + { + for (int i = 0; i < 4; ++i) + { + pointDouble(r); + } + + pointLookup(n, w, table, q); + pointAdd(q, r); + } + + for (int i = 0; i < 2; ++i) + { + pointDouble(r); + } + } + private static void scalarMultBase(byte[] k, PointExt r) { precompute(); @@ -881,8 +1192,9 @@ public abstract class Ed448 int w = 0; for (int t = 0; t < PRECOMP_TEETH; ++t) { - int tBit = (n[tPos >>> 5] >>> (tPos & 0x1F)) & 1; - w |= tBit << t; + int tBit = n[tPos >>> 5] >>> (tPos & 0x1F); + w &= ~(1 << t); + w ^= (tBit << t); tPos += PRECOMP_SPACING; } @@ -908,14 +1220,40 @@ public abstract class Ed448 } } - private static void scalarMultBaseEncodedVar(byte[] k, byte[] r, int rOff) + private static void scalarMultBaseEncoded(byte[] k, byte[] r, int rOff) { PointExt p = new PointExt(); scalarMultBase(k, p); - encodePoint(p, r, rOff); + if (0 == encodePoint(p, r, rOff)) + { + throw new IllegalStateException(); + } + } + + /** + * NOTE: Only for use by X448 + */ + public static void scalarMultBaseXY(X448.Friend friend, byte[] k, int kOff, int[] x, int[] y) + { + if (null == friend) + { + throw new NullPointerException("This method is only for use by X448"); + } + + byte[] n = new byte[SCALAR_BYTES]; + pruneScalar(k, kOff, n); + + PointExt p = new PointExt(); + scalarMultBase(n, p); + if (0 == checkPoint(p.x, p.y, p.z)) + { + throw new IllegalStateException(); + } + X448Field.copy(p.x, 0, x, 0); + X448Field.copy(p.y, 0, y, 0); } - private static void scalarMultStraussVar(int[] nb, int[] np, PointExt p, PointExt r) + private static void scalarMultStrausVar(int[] nb, int[] np, PointExt p, PointExt r) { precompute(); @@ -928,13 +1266,7 @@ public abstract class Ed448 pointSetNeutral(r); - int bit = 447; - while (bit > 0 && (ws_b[bit] | ws_p[bit]) == 0) - { - --bit; - } - - for (;;) + for (int bit = 446;;) { int wb = ws_b[bit]; if (wb != 0) @@ -965,95 +1297,82 @@ public abstract class Ed448 public static void sign(byte[] sk, int skOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { - if (!checkContextVar(ctx)) - { - throw new IllegalArgumentException("ctx"); - } - - SHAKEDigest d = new SHAKEDigest(256); - byte[] h = new byte[SCALAR_BYTES * 2]; - - d.update(sk, skOff, SECRET_KEY_SIZE); - d.doFinal(h, 0, h.length); - - byte[] s = new byte[SCALAR_BYTES]; - pruneScalar(h, 0, s); - - byte[] pk = new byte[POINT_BYTES]; - scalarMultBaseEncodedVar(s, pk, 0); + byte phflag = 0x00; - implSignVar(d, h, s, pk, 0, ctx, m, mOff, mLen, sig, sigOff); + implSign(sk, skOff, ctx, phflag, m, mOff, mLen, sig, sigOff); } public static void sign(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen, byte[] sig, int sigOff) { - if (!checkContextVar(ctx)) - { - throw new IllegalArgumentException("ctx"); - } + byte phflag = 0x00; - SHAKEDigest d = new SHAKEDigest(256); - byte[] h = new byte[SCALAR_BYTES * 2]; + implSign(sk, skOff, pk, pkOff, ctx, phflag, m, mOff, mLen, sig, sigOff); + } - d.update(sk, skOff, SECRET_KEY_SIZE); - d.doFinal(h, 0, h.length); + public static void signPrehash(byte[] sk, int skOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff) + { + byte phflag = 0x01; - byte[] s = new byte[SCALAR_BYTES]; - pruneScalar(h, 0, s); + implSign(sk, skOff, ctx, phflag, ph, phOff, PREHASH_SIZE, sig, sigOff); + } - implSignVar(d, h, s, pk, pkOff, ctx, m, mOff, mLen, sig, sigOff); + public static void signPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff, byte[] sig, int sigOff) + { + byte phflag = 0x01; + + implSign(sk, skOff, pk, pkOff, ctx, phflag, ph, phOff, PREHASH_SIZE, sig, sigOff); } - public static boolean verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen) + public static void signPrehash(byte[] sk, int skOff, byte[] ctx, Xof ph, byte[] sig, int sigOff) { - if (!checkContextVar(ctx)) + byte[] m = new byte[PREHASH_SIZE]; + if (PREHASH_SIZE != ph.doFinal(m, 0, PREHASH_SIZE)) { - throw new IllegalArgumentException("ctx"); + throw new IllegalArgumentException("ph"); } - byte[] R = Arrays.copyOfRange(sig, sigOff, sigOff + POINT_BYTES); - byte[] S = Arrays.copyOfRange(sig, sigOff + POINT_BYTES, sigOff + SIGNATURE_SIZE); + byte phflag = 0x01; - if (!checkPointVar(R)) - { - return false; - } - if (!checkScalarVar(S)) - { - return false; - } + implSign(sk, skOff, ctx, phflag, m, 0, m.length, sig, sigOff); + } - PointExt pA = new PointExt(); - if (!decodePointVar(pk, pkOff, true, pA)) + public static void signPrehash(byte[] sk, int skOff, byte[] pk, int pkOff, byte[] ctx, Xof ph, byte[] sig, int sigOff) + { + byte[] m = new byte[PREHASH_SIZE]; + if (PREHASH_SIZE != ph.doFinal(m, 0, PREHASH_SIZE)) { - return false; + throw new IllegalArgumentException("ph"); } - byte phflag = 0x00; + byte phflag = 0x01; - SHAKEDigest d = new SHAKEDigest(256); - byte[] h = new byte[SCALAR_BYTES * 2]; + implSign(sk, skOff, pk, pkOff, ctx, phflag, m, 0, m.length, sig, sigOff); + } - dom4(d, phflag, ctx); - d.update(R, 0, POINT_BYTES); - d.update(pk, pkOff, POINT_BYTES); - d.update(m, mOff, mLen); - d.doFinal(h, 0, h.length); + public static boolean verify(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] m, int mOff, int mLen) + { + byte phflag = 0x00; - byte[] k = reduceScalar(h); + return implVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, mOff, mLen); + } - int[] nS = new int[SCALAR_INTS]; - decodeScalar(S, 0, nS); + public static boolean verifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, byte[] ph, int phOff) + { + byte phflag = 0x01; - int[] nA = new int[SCALAR_INTS]; - decodeScalar(k, 0, nA); + return implVerify(sig, sigOff, pk, pkOff, ctx, phflag, ph, phOff, PREHASH_SIZE); + } - PointExt pR = new PointExt(); - scalarMultStraussVar(nS, nA, pA, pR); + public static boolean verifyPrehash(byte[] sig, int sigOff, byte[] pk, int pkOff, byte[] ctx, Xof ph) + { + byte[] m = new byte[PREHASH_SIZE]; + if (PREHASH_SIZE != ph.doFinal(m, 0, PREHASH_SIZE)) + { + throw new IllegalArgumentException("ph"); + } - byte[] check = new byte[POINT_BYTES]; - encodePoint(pR, check, 0); + byte phflag = 0x01; - return Arrays.areEqual(check, R); + return implVerify(sig, sigOff, pk, pkOff, ctx, phflag, m, 0, m.length); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java index c6d307489..9974d6241 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/tools/DiscoverEndomorphisms.java @@ -2,9 +2,15 @@ package com.fr.third.org.bouncycastle.math.ec.tools; import java.math.BigInteger; import java.security.SecureRandom; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.SortedSet; +import java.util.TreeSet; import com.fr.third.org.bouncycastle.asn1.x9.ECNamedCurveTable; import com.fr.third.org.bouncycastle.asn1.x9.X9ECParameters; +import com.fr.third.org.bouncycastle.crypto.ec.CustomNamedCurves; import com.fr.third.org.bouncycastle.math.ec.ECAlgorithms; import com.fr.third.org.bouncycastle.math.ec.ECConstants; import com.fr.third.org.bouncycastle.math.ec.ECCurve; @@ -18,15 +24,23 @@ public class DiscoverEndomorphisms public static void main(String[] args) { - if (args.length < 1) + if (args.length > 0) { - System.err.println("Expected a list of curve names as arguments"); - return; + for (int i = 0; i < args.length; ++i) + { + discoverEndomorphisms(args[i]); + } } - - for (int i = 0; i < args.length; ++i) + else { - discoverEndomorphisms(args[i]); + SortedSet curveNames = new TreeSet(enumToList(ECNamedCurveTable.getNames())); + curveNames.addAll(enumToList(CustomNamedCurves.getNames())); + + Iterator it = curveNames.iterator(); + while (it.hasNext()) + { + discoverEndomorphisms((String)it.next()); + } } } @@ -37,58 +51,116 @@ public class DiscoverEndomorphisms throw new NullPointerException("x9"); } + discoverEndomorphisms(x9, ""); + } + + private static void discoverEndomorphisms(String curveName) + { + X9ECParameters x9 = CustomNamedCurves.getByName(curveName); + if (x9 == null) + { + x9 = ECNamedCurveTable.getByName(curveName); + if (x9 == null) + { + System.err.println("Unknown curve: " + curveName); + return; + } + } + +// System.out.println("[" + curveName + "]"); + discoverEndomorphisms(x9, curveName); + } + + private static void discoverEndomorphisms(X9ECParameters x9, String displayName) + { ECCurve c = x9.getCurve(); + if (ECAlgorithms.isFpCurve(c)) { BigInteger characteristic = c.getField().getCharacteristic(); + if (c.getB().isZero() && characteristic.mod(ECConstants.FOUR).equals(ECConstants.ONE)) + { + System.out.println("Curve '" + displayName + "' has a 'GLV Type A' endomorphism with these parameters:"); + printGLVTypeAParameters(x9); + } + if (c.getA().isZero() && characteristic.mod(ECConstants.THREE).equals(ECConstants.ONE)) { - System.out.println("Curve has a 'GLV Type B' endomorphism with these parameters:"); + System.out.println("Curve '" + displayName + "' has a 'GLV Type B' endomorphism with these parameters:"); printGLVTypeBParameters(x9); } } } - private static void discoverEndomorphisms(String curveName) + private static void printGLVTypeAParameters(X9ECParameters x9) { - X9ECParameters x9 = ECNamedCurveTable.getByName(curveName); - if (x9 == null) + // x^2 + 1 = 0 mod n + BigInteger[] lambdas = solveQuadraticEquation(x9.getN(), + ECConstants.ONE, ECConstants.ZERO, ECConstants.ONE); + + /* + * The 'i' values are field elements of order 4. There are only two such values besides 1 + * and -1, each corresponding to one choice for 'lambda'. + */ + ECFieldElement[] iValues = findNonTrivialOrder4FieldElements(x9.getCurve()); + + printGLVTypeAParameters(x9, lambdas[0], iValues); + System.out.println("OR"); + printGLVTypeAParameters(x9, lambdas[1], iValues); + } + + private static void printGLVTypeAParameters(X9ECParameters x9, BigInteger lambda, ECFieldElement[] iValues) + { + /* + * Check the basic premise of the endomorphism: that multiplying a point by lambda negates the x-coordinate + */ + ECPoint G = x9.getG().normalize(); + ECPoint mapG = G.multiply(lambda).normalize(); + if (!G.getXCoord().negate().equals(mapG.getXCoord())) { - System.err.println("Unknown curve: " + curveName); - return; + throw new IllegalStateException("Derivation of GLV Type A parameters failed unexpectedly"); } - ECCurve c = x9.getCurve(); - if (ECAlgorithms.isFpCurve(c)) + /* + * Determine which of the i values corresponds with this choice of lambda, by checking that it scales + * the y-coordinate the same way a point-multiplication by lambda does. + */ + ECFieldElement i = iValues[0]; + if (!G.getYCoord().multiply(i).equals(mapG.getYCoord())) { - BigInteger characteristic = c.getField().getCharacteristic(); - - if (c.getA().isZero() && characteristic.mod(ECConstants.THREE).equals(ECConstants.ONE)) + i = iValues[1]; + if (!G.getYCoord().multiply(i).equals(mapG.getYCoord())) { - System.out.println("Curve '" + curveName + "' has a 'GLV Type B' endomorphism with these parameters:"); - printGLVTypeBParameters(x9); + throw new IllegalStateException("Derivation of GLV Type A parameters failed unexpectedly"); } } + + printProperty("Point map", "lambda * (x, y) = (-x, i * y)"); + printProperty("i", i.toBigInteger().toString(radix)); + printProperty("lambda", lambda.toString(radix)); + + printScalarDecompositionParameters(x9.getN(), lambda); } private static void printGLVTypeBParameters(X9ECParameters x9) { // x^2 + x + 1 = 0 mod n - BigInteger[] lambdas = solveQuadraticEquation(x9.getN(), ECConstants.ONE, ECConstants.ONE); + BigInteger[] lambdas = solveQuadraticEquation(x9.getN(), + ECConstants.ONE, ECConstants.ONE, ECConstants.ONE); /* - * The 'Beta' values are field elements of order 3. There are only two such values besides 1, each corresponding - * to one choice for 'Lambda'. + * The 'beta' values are field elements of order 3. There are only two such values besides + * 1, each corresponding to one choice for 'lambda'. */ - ECFieldElement[] betas = findBetaValues(x9.getCurve()); + ECFieldElement[] betaValues = findNonTrivialOrder3FieldElements(x9.getCurve()); - printGLVTypeBParameters(x9, lambdas[0], betas); + printGLVTypeBParameters(x9, lambdas[0], betaValues); System.out.println("OR"); - printGLVTypeBParameters(x9, lambdas[1], betas); + printGLVTypeBParameters(x9, lambdas[1], betaValues); } - private static void printGLVTypeBParameters(X9ECParameters x9, BigInteger lambda, ECFieldElement[] betas) + private static void printGLVTypeBParameters(X9ECParameters x9, BigInteger lambda, ECFieldElement[] betaValues) { /* * Check the basic premise of the endomorphism: that multiplying a point by lambda preserves the y-coordinate @@ -104,20 +176,41 @@ public class DiscoverEndomorphisms * Determine which of the beta values corresponds with this choice of lambda, by checking that it scales * the x-coordinate the same way a point-multiplication by lambda does. */ - ECFieldElement beta = betas[0]; + ECFieldElement beta = betaValues[0]; if (!G.getXCoord().multiply(beta).equals(mapG.getXCoord())) { - beta = betas[1]; + beta = betaValues[1]; if (!G.getXCoord().multiply(beta).equals(mapG.getXCoord())) { throw new IllegalStateException("Derivation of GLV Type B parameters failed unexpectedly"); } } + printProperty("Point map", "lambda * (x, y) = (beta * x, y)"); + printProperty("beta", beta.toBigInteger().toString(radix)); + printProperty("lambda", lambda.toString(radix)); + + printScalarDecompositionParameters(x9.getN(), lambda); + } + + private static void printProperty(String name, Object value) + { + StringBuffer sb = new StringBuffer(" "); + sb.append(name); + while (sb.length() < 20) + { + sb.append(' '); + } + sb.append(": "); + sb.append(value.toString()); + System.out.println(sb.toString()); + } + + private static void printScalarDecompositionParameters(BigInteger n, BigInteger lambda) + { /* - * Now search for parameters to allow efficient decomposition of full-length scalars + * Search for parameters to allow efficient decomposition of full-length scalars */ - BigInteger n = x9.getN(); BigInteger[] v1 = null; BigInteger[] v2 = null; @@ -195,8 +288,6 @@ public class DiscoverEndomorphisms BigInteger g1 = roundQuotient(v2[1].shiftLeft(bits), d); BigInteger g2 = roundQuotient(v1[1].shiftLeft(bits), d).negate(); - printProperty("Beta", beta.toBigInteger().toString(radix)); - printProperty("Lambda", lambda.toString(radix)); printProperty("v1", "{ " + v1[0].toString(radix) + ", " + v1[1].toString(radix) + " }"); printProperty("v2", "{ " + v2[0].toString(radix) + ", " + v2[1].toString(radix) + " }"); printProperty("d", d.toString(radix)); @@ -205,19 +296,6 @@ public class DiscoverEndomorphisms printProperty("(OPT) bits", Integer.toString(bits)); } - private static void printProperty(String name, Object value) - { - StringBuffer sb = new StringBuffer(" "); - sb.append(name); - while (sb.length() < 20) - { - sb.append(' '); - } - sb.append("= "); - sb.append(value.toString()); - System.out.println(sb.toString()); - } - private static boolean areRelativelyPrime(BigInteger a, BigInteger b) { return a.gcd(b).equals(ECConstants.ONE); @@ -230,6 +308,16 @@ public class DiscoverEndomorphisms return order(i1, i2); } + private static ArrayList enumToList(Enumeration en) + { + ArrayList rv = new ArrayList(); + while (en.hasMoreElements()) + { + rv.add(en.nextElement()); + } + return rv; + } + private static BigInteger[] extEuclidBezout(BigInteger[] ab) { boolean swap = ab[0].compareTo(ab[1]) < 0; @@ -369,28 +457,25 @@ public class DiscoverEndomorphisms return negative ? result.negate() : result; } - private static BigInteger[] solveQuadraticEquation(BigInteger n, BigInteger r, BigInteger s) + private static BigInteger[] solveQuadraticEquation(BigInteger n, BigInteger a, BigInteger b, BigInteger c) { - BigInteger det = r.multiply(r).subtract(s.shiftLeft(2)).mod(n); - - BigInteger root1 = new ECFieldElement.Fp(n, det).sqrt().toBigInteger(), root2 = n.subtract(root1); - if (root1.testBit(0)) - { - root2 = root2.add(n); - } - else + BigInteger det = b.multiply(b).subtract(a.multiply(c).shiftLeft(2)).mod(n); + ECFieldElement rootFE = new ECFieldElement.Fp(n, det).sqrt(); + if (rootFE == null) { - root1 = root1.add(n); + throw new IllegalStateException("Solving quadratic equation failed unexpectedly"); } -// assert root1.testBit(0); -// assert root2.testBit(0); + BigInteger root = rootFE.toBigInteger(); + BigInteger invDenom = a.shiftLeft(1).modInverse(n); + + BigInteger s1 = root.subtract(b).multiply(invDenom).mod(n); + BigInteger s2 = root.negate().subtract(b).multiply(invDenom).mod(n); - // NOTE: implicit -1 of the low-bits - return new BigInteger[]{ root1.shiftRight(1), root2.shiftRight(1) }; + return new BigInteger[]{ s1, s2 }; } - private static ECFieldElement[] findBetaValues(ECCurve c) + private static ECFieldElement[] findNonTrivialOrder3FieldElements(ECCurve c) { BigInteger q = c.getField().getCharacteristic(); BigInteger e = q.divide(ECConstants.THREE); @@ -410,6 +495,17 @@ public class DiscoverEndomorphisms return new ECFieldElement[]{ beta, beta.square() }; } + private static ECFieldElement[] findNonTrivialOrder4FieldElements(ECCurve c) + { + ECFieldElement i = c.fromBigInteger(ECConstants.ONE).negate().sqrt(); + if (i == null) + { + throw new IllegalStateException("Calculation of non-trivial order-4 field elements failed unexpectedly"); + } + + return new ECFieldElement[]{ i, i.negate() }; + } + private static BigInteger isqrt(BigInteger x) { BigInteger g0 = x.shiftRight(x.bitLength() / 2); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/tools/TraceOptimizer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/tools/TraceOptimizer.java index 0dbec6006..48dd45670 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/tools/TraceOptimizer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/ec/tools/TraceOptimizer.java @@ -69,13 +69,24 @@ public class TraceOptimizer { for (int i = 0; i < m; ++i) { - BigInteger zi = ONE.shiftLeft(i); - ECFieldElement fe = c.fromBigInteger(zi); - int tr = calculateTrace(fe); - if (tr != 0) + if (0 == (i & 1) && 0 != i) { - nonZeroTraceBits.add(Integers.valueOf(i)); - System.out.print(" " + i); + if (nonZeroTraceBits.contains(Integers.valueOf(i >>> 1))) + { + nonZeroTraceBits.add(Integers.valueOf(i)); + System.out.print(" " + i); + } + } + else + { + BigInteger zi = ONE.shiftLeft(i); + ECFieldElement fe = c.fromBigInteger(zi); + int tr = calculateTrace(fe); + if (tr != 0) + { + nonZeroTraceBits.add(Integers.valueOf(i)); + System.out.print(" " + i); + } } } System.out.println(); @@ -111,19 +122,37 @@ public class TraceOptimizer private static int calculateTrace(ECFieldElement fe) { +// int m = fe.getFieldSize(); +// ECFieldElement tr = fe; +// for (int i = 1; i < m; ++i) +// { +// tr = tr.square().add(fe); +// } + int m = fe.getFieldSize(); + int k = 31 - Integers.numberOfLeadingZeros(m); + int mk = 1; + ECFieldElement tr = fe; - for (int i = 1; i < m; ++i) + while (k > 0) + { + tr = tr.squarePow(mk).add(tr); + mk = m >>> --k; + if (0 != (mk & 1)) + { + tr = tr.square().add(fe); + } + } + + if (tr.isZero()) { - fe = fe.square(); - tr = tr.add(fe); + return 0; } - BigInteger b = tr.toBigInteger(); - if (b.bitLength() > 1) + if (tr.isOne()) { - throw new IllegalStateException(); + return 1; } - return b.intValue(); + throw new IllegalStateException("Internal error in trace calculation"); } private static ArrayList enumToList(Enumeration en) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Mod.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Mod.java index 3b5ccbf55..5848526a3 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Mod.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Mod.java @@ -2,8 +2,6 @@ package com.fr.third.org.bouncycastle.math.raw; import java.util.Random; -import com.fr.third.org.bouncycastle.util.Pack; - public abstract class Mod { public static int inverse32(int d) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat.java index 7d27cb895..8082a0e63 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat.java @@ -160,6 +160,31 @@ public abstract class Nat return (int)c; } + public static int addTo(int len, int[] x, int xOff, int[] z, int zOff, int cIn) + { + long c = cIn & M; + for (int i = 0; i < len; ++i) + { + c += (x[xOff + i] & M) + (z[zOff + i] & M); + z[zOff + i] = (int)c; + c >>>= 32; + } + return (int)c; + } + + public static int addToEachOther(int len, int[] u, int uOff, int[] v, int vOff) + { + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (u[uOff + i] & M) + (v[vOff + i] & M); + u[uOff + i] = (int)c; + v[vOff + i] = (int)c; + c >>>= 32; + } + return (int)c; + } + public static int addWordAt(int len, int x, int[] z, int zPos) { // assert zPos <= (len - 1); @@ -246,6 +271,23 @@ public abstract class Nat System.arraycopy(x, xOff, z, zOff, len); } + public static long[] copy64(int len, long[] x) + { + long[] z = new long[len]; + System.arraycopy(x, 0, z, 0, len); + return z; + } + + public static void copy64(int len, long[] x, long[] z) + { + System.arraycopy(x, 0, z, 0, len); + } + + public static void copy64(int len, long[] x, int xOff, long[] z, int zOff) + { + System.arraycopy(x, xOff, z, zOff, len); + } + public static int[] create(int len) { return new int[len]; @@ -269,6 +311,19 @@ public abstract class Nat return (int)c; } + public static int csub(int len, int mask, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + long MASK = -(mask & 1) & M; + long c = 0; + for (int i = 0; i < len; ++i) + { + c += (x[xOff + i] & M) - (y[yOff + i] & MASK); + z[zOff + i] = (int)c; + c >>= 32; + } + return (int)c; + } + public static int dec(int len, int[] z) { for (int i = 0; i < len; ++i) @@ -328,6 +383,20 @@ public abstract class Nat return -1; } + public static boolean diff(int len, int[] x, int xOff, int[] y, int yOff, int[] z, int zOff) + { + boolean pos = gte(len, x, xOff, y, yOff); + if (pos) + { + sub(len, x, xOff, y, yOff, z, zOff); + } + else + { + sub(len, y, yOff, x, xOff, z, zOff); + } + return pos; + } + public static boolean eq(int len, int[] x, int[] y) { for (int i = len - 1; i >= 0; --i) @@ -358,6 +427,24 @@ public abstract class Nat return z; } + public static long[] fromBigInteger64(int bits, BigInteger x) + { + if (x.signum() < 0 || x.bitLength() > bits) + { + throw new IllegalArgumentException(); + } + + int len = (bits + 63) >> 6; + long[] z = create64(len); + int i = 0; + while (x.signum() != 0) + { + z[i++] = x.longValue(); + x = x.shiftRight(64); + } + return z; + } + public static int getBit(int[] x, int bit) { if (bit == 0) @@ -387,6 +474,20 @@ public abstract class Nat return true; } + public static boolean gte(int len, int[] x, int xOff, int[] y, int yOff) + { + for (int i = len - 1; i >= 0; --i) + { + int x_i = x[xOff + i] ^ Integer.MIN_VALUE; + int y_i = y[yOff + i] ^ Integer.MIN_VALUE; + if (x_i < y_i) + return false; + if (x_i > y_i) + return true; + } + return true; + } + public static int inc(int len, int[] z) { for (int i = 0; i < len; ++i) @@ -494,15 +595,25 @@ public abstract class Nat } } + public static void mul(int[] x, int xOff, int xLen, int[] y, int yOff, int yLen, int[] zz, int zzOff) + { + zz[zzOff + yLen] = mulWord(yLen, x[xOff], y, yOff, zz, zzOff); + + for (int i = 1; i < xLen; ++i) + { + zz[zzOff + i + yLen] = mulWordAddTo(yLen, x[xOff + i], y, yOff, zz, zzOff + i); + } + } + public static int mulAddTo(int len, int[] x, int[] y, int[] zz) { long zc = 0; for (int i = 0; i < len; ++i) { - long c = mulWordAddTo(len, x[i], y, 0, zz, i) & M; - c += zc + (zz[i + len] & M); - zz[i + len] = (int)c; - zc = c >>> 32; + zc += mulWordAddTo(len, x[i], y, 0, zz, i) & M; + zc += zz[i + len] & M; + zz[i + len] = (int)zc; + zc >>>= 32; } return (int)zc; } @@ -512,10 +623,10 @@ public abstract class Nat long zc = 0; for (int i = 0; i < len; ++i) { - long c = mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff) & M; - c += zc + (zz[zzOff + len] & M); - zz[zzOff + len] = (int)c; - zc = c >>> 32; + zc += mulWordAddTo(len, x[xOff + i], y, yOff, zz, zzOff) & M; + zc += zz[zzOff + len] & M; + zz[zzOff + len] = (int)zc; + zc >>>= 32; ++zzOff; } return (int)zc; @@ -847,11 +958,18 @@ public abstract class Nat } while (j > 0); + long d = 0L; + int zzPos = 2; + for (int i = 1; i < len; ++i) { - c = squareWordAdd(x, i, zz); - addWordAt(extLen, c, zz, i << 1); + d += squareWordAddTo(x, i, zz) & M; + d += zz[zzPos] & M; + zz[zzPos++] = (int)d; d >>>= 32; + d += zz[zzPos] & M; + zz[zzPos++] = (int)d; d >>>= 32; } +// assert 0L == d; shiftUpBit(extLen, zz, x[0] << 31); } @@ -871,15 +989,25 @@ public abstract class Nat } while (j > 0); + long d = 0L; + int zzPos = zzOff + 2; + for (int i = 1; i < len; ++i) { - c = squareWordAdd(x, xOff, i, zz, zzOff); - addWordAt(extLen, c, zz, zzOff, i << 1); + d += squareWordAddTo(x, xOff, i, zz, zzOff) & M; + d += zz[zzPos] & M; + zz[zzPos++] = (int)d; d >>>= 32; + d += zz[zzPos] & M; + zz[zzPos++] = (int)d; d >>>= 32; } +// assert 0L == d; shiftUpBit(extLen, zz, zzOff, x[xOff] << 31); } + /** + * @deprecated Use {@link #squareWordAddTo(int[], int, int[])} instead. + */ public static int squareWordAdd(int[] x, int xPos, int[] z) { long c = 0, xVal = x[xPos] & M; @@ -894,6 +1022,9 @@ public abstract class Nat return (int)c; } + /** + * @deprecated Use {@link #squareWordAddTo(int[], int, int, int[], int) instead. + */ public static int squareWordAdd(int[] x, int xOff, int xPos, int[] z, int zOff) { long c = 0, xVal = x[xOff + xPos] & M; @@ -909,6 +1040,35 @@ public abstract class Nat return (int)c; } + public static int squareWordAddTo(int[] x, int xPos, int[] z) + { + long c = 0, xVal = x[xPos] & M; + int i = 0; + do + { + c += xVal * (x[i] & M) + (z[xPos + i] & M); + z[xPos + i] = (int)c; + c >>>= 32; + } + while (++i < xPos); + return (int)c; + } + + public static int squareWordAddTo(int[] x, int xOff, int xPos, int[] z, int zOff) + { + long c = 0, xVal = x[xOff + xPos] & M; + int i = 0; + do + { + c += xVal * (x[xOff + i] & M) + (z[xPos + zOff] & M); + z[xPos + zOff] = (int)c; + c >>>= 32; + ++zOff; + } + while (++i < xPos); + return (int)c; + } + public static int sub(int len, int[] x, int[] y, int[] z) { long c = 0; @@ -1129,6 +1289,14 @@ public abstract class Nat } } + public static void zero(int len, int[] z, int zOff) + { + for (int i = 0; i < len; ++i) + { + z[zOff + i] = 0; + } + } + public static void zero64(int len, long[] z) { for (int i = 0; i < len; ++i) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat128.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat128.java index 98231f5a4..9ac64f76d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat128.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat128.java @@ -431,9 +431,10 @@ public abstract class Nat128 c += x_i * y_3 + (zz[i + 3] & M); zz[i + 3] = (int)c; c >>>= 32; - c += zc + (zz[i + 4] & M); - zz[i + 4] = (int)c; - zc = c >>> 32; + + zc += c + (zz[i + 4] & M); + zz[i + 4] = (int)zc; + zc >>>= 32; } return (int)zc; } @@ -461,9 +462,10 @@ public abstract class Nat128 c += x_i * y_3 + (zz[zzOff + 3] & M); zz[zzOff + 3] = (int)c; c >>>= 32; - c += zc + (zz[zzOff + 4] & M); - zz[zzOff + 4] = (int)c; - zc = c >>> 32; + + zc += c + (zz[zzOff + 4] & M); + zz[zzOff + 4] = (int)zc; + zc >>>= 32; ++zzOff; } return (int)zc; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat160.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat160.java index 84cb9d55c..96f3aa609 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat160.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat160.java @@ -388,9 +388,10 @@ public abstract class Nat160 c += x_i * y_4 + (zz[i + 4] & M); zz[i + 4] = (int)c; c >>>= 32; - c += zc + (zz[i + 5] & M); - zz[i + 5] = (int)c; - zc = c >>> 32; + + zc += c + (zz[i + 5] & M); + zz[i + 5] = (int)zc; + zc >>>= 32; } return (int)zc; } @@ -422,9 +423,10 @@ public abstract class Nat160 c += x_i * y_4 + (zz[zzOff + 4] & M); zz[zzOff + 4] = (int)c; c >>>= 32; - c += zc + (zz[zzOff + 5] & M); - zz[zzOff + 5] = (int)c; - zc = c >>> 32; + + zc += c + (zz[zzOff + 5] & M); + zz[zzOff + 5] = (int)zc; + zc >>>= 32; ++zzOff; } return (int)zc; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat192.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat192.java index fcee716f5..e4212b820 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat192.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat192.java @@ -505,9 +505,10 @@ public abstract class Nat192 c += x_i * y_5 + (zz[i + 5] & M); zz[i + 5] = (int)c; c >>>= 32; - c += zc + (zz[i + 6] & M); - zz[i + 6] = (int)c; - zc = c >>> 32; + + zc += c + (zz[i + 6] & M); + zz[i + 6] = (int)zc; + zc >>>= 32; } return (int)zc; } @@ -543,9 +544,10 @@ public abstract class Nat192 c += x_i * y_5 + (zz[zzOff + 5] & M); zz[zzOff + 5] = (int)c; c >>>= 32; - c += zc + (zz[zzOff + 6] & M); - zz[zzOff + 6] = (int)c; - zc = c >>> 32; + + zc += c + (zz[zzOff + 6] & M); + zz[zzOff + 6] = (int)zc; + zc >>>= 32; ++zzOff; } return (int)zc; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat224.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat224.java index 28d2b371b..5634aa86d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat224.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat224.java @@ -514,9 +514,10 @@ public abstract class Nat224 c += x_i * y_6 + (zz[i + 6] & M); zz[i + 6] = (int)c; c >>>= 32; - c += zc + (zz[i + 7] & M); - zz[i + 7] = (int)c; - zc = c >>> 32; + + zc += c + (zz[i + 7] & M); + zz[i + 7] = (int)zc; + zc >>>= 32; } return (int)zc; } @@ -556,9 +557,10 @@ public abstract class Nat224 c += x_i * y_6 + (zz[zzOff + 6] & M); zz[zzOff + 6] = (int)c; c >>>= 32; - c += zc + (zz[zzOff + 7] & M); - zz[zzOff + 7] = (int)c; - zc = c >>> 32; + + zc += c + (zz[zzOff + 7] & M); + zz[zzOff + 7] = (int)zc; + zc >>>= 32; ++zzOff; } return (int)zc; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat256.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat256.java index 8c1a4468c..42a1d5846 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat256.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/math/raw/Nat256.java @@ -639,9 +639,10 @@ public abstract class Nat256 c += x_i * y_7 + (zz[i + 7] & M); zz[i + 7] = (int)c; c >>>= 32; - c += zc + (zz[i + 8] & M); - zz[i + 8] = (int)c; - zc = c >>> 32; + + zc += c + (zz[i + 8] & M); + zz[i + 8] = (int)zc; + zc >>>= 32; } return (int)zc; } @@ -685,9 +686,10 @@ public abstract class Nat256 c += x_i * y_7 + (zz[zzOff + 7] & M); zz[zzOff + 7] = (int)c; c >>>= 32; - c += zc + (zz[zzOff + 8] & M); - zz[zzOff + 8] = (int)c; - zc = c >>> 32; + + zc += c + (zz[zzOff + 8] & M); + zz[zzOff + 8] = (int)zc; + zc >>>= 32; ++zzOff; } return (int)zc; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/GMSSPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/GMSSPrivateKey.java index 00c1ed842..45c68292f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/GMSSPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/GMSSPrivateKey.java @@ -1,6 +1,5 @@ package com.fr.third.org.bouncycastle.pqc.asn1; -import java.math.BigInteger; import java.util.Vector; import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; @@ -1295,16 +1294,9 @@ public class GMSSPrivateKey private static int checkBigIntegerInIntRange(ASN1Encodable a) { - BigInteger b = ((ASN1Integer)a).getValue(); - if ((b.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) || - (b.compareTo(BigInteger.valueOf(Integer.MIN_VALUE)) < 0)) - { - throw new IllegalArgumentException("BigInteger not in Range: " + b.toString()); - } - return b.intValue(); + return ((ASN1Integer)a).intValueExact(); } - public ASN1Primitive toASN1Primitive() { return this.primitive; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java index 12329e582..cbb0a903d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McElieceCCA2PrivateKey.java @@ -54,11 +54,9 @@ public class McElieceCCA2PrivateKey private McElieceCCA2PrivateKey(ASN1Sequence seq) { - BigInteger bigN = ((ASN1Integer)seq.getObjectAt(0)).getValue(); - n = bigN.intValue(); + n = ((ASN1Integer)seq.getObjectAt(0)).intValueExact(); - BigInteger bigK = ((ASN1Integer)seq.getObjectAt(1)).getValue(); - k = bigK.intValue(); + k = ((ASN1Integer)seq.getObjectAt(1)).intValueExact(); encField = ((ASN1OctetString)seq.getObjectAt(2)).getOctets(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java index d57a6f734..bc05da332 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McElieceCCA2PublicKey.java @@ -31,11 +31,9 @@ public class McElieceCCA2PublicKey private McElieceCCA2PublicKey(ASN1Sequence seq) { - BigInteger bigN = ((ASN1Integer)seq.getObjectAt(0)).getValue(); - n = bigN.intValue(); + n = ((ASN1Integer)seq.getObjectAt(0)).intValueExact(); - BigInteger bigT = ((ASN1Integer)seq.getObjectAt(1)).getValue(); - t = bigT.intValue(); + t = ((ASN1Integer)seq.getObjectAt(1)).intValueExact(); g = new GF2Matrix(((ASN1OctetString)seq.getObjectAt(2)).getOctets()); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java index 78b7e8a20..a7427c52e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McEliecePrivateKey.java @@ -53,11 +53,9 @@ public class McEliecePrivateKey private McEliecePrivateKey(ASN1Sequence seq) { - BigInteger bigN = ((ASN1Integer)seq.getObjectAt(0)).getValue(); - n = bigN.intValue(); + n = ((ASN1Integer)seq.getObjectAt(0)).intValueExact(); - BigInteger bigK = ((ASN1Integer)seq.getObjectAt(1)).getValue(); - k = bigK.intValue(); + k = ((ASN1Integer)seq.getObjectAt(1)).intValueExact(); encField = ((ASN1OctetString)seq.getObjectAt(2)).getOctets(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McEliecePublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McEliecePublicKey.java index 2bd93cce3..f774c396d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McEliecePublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/McEliecePublicKey.java @@ -28,11 +28,9 @@ public class McEliecePublicKey private McEliecePublicKey(ASN1Sequence seq) { - BigInteger bigN = ((ASN1Integer)seq.getObjectAt(0)).getValue(); - n = bigN.intValue(); + n = ((ASN1Integer)seq.getObjectAt(0)).intValueExact(); - BigInteger bigT = ((ASN1Integer)seq.getObjectAt(1)).getValue(); - t = bigT.intValue(); + t = ((ASN1Integer)seq.getObjectAt(1)).intValueExact(); g = new GF2Matrix(((ASN1OctetString)seq.getObjectAt(2)).getOctets()); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java index 790742d45..1bc75b4f5 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/PQCObjectIdentifiers.java @@ -59,17 +59,68 @@ public interface PQCObjectIdentifiers * XMSS */ public static final ASN1ObjectIdentifier xmss = BCObjectIdentifiers.xmss; - public static final ASN1ObjectIdentifier xmss_with_SHA256 = BCObjectIdentifiers.xmss_with_SHA256; - public static final ASN1ObjectIdentifier xmss_with_SHA512 = BCObjectIdentifiers.xmss_with_SHA512; - public static final ASN1ObjectIdentifier xmss_with_SHAKE128 = BCObjectIdentifiers.xmss_with_SHAKE128; - public static final ASN1ObjectIdentifier xmss_with_SHAKE256 = BCObjectIdentifiers.xmss_with_SHAKE256; + public static final ASN1ObjectIdentifier xmss_SHA256ph = BCObjectIdentifiers.xmss_SHA256ph; + public static final ASN1ObjectIdentifier xmss_SHA512ph = BCObjectIdentifiers.xmss_SHA512ph; + public static final ASN1ObjectIdentifier xmss_SHAKE128ph = BCObjectIdentifiers.xmss_SHAKE128ph; + public static final ASN1ObjectIdentifier xmss_SHAKE256ph = BCObjectIdentifiers.xmss_SHAKE256ph; + public static final ASN1ObjectIdentifier xmss_SHA256 = BCObjectIdentifiers.xmss_SHA256; + public static final ASN1ObjectIdentifier xmss_SHA512 = BCObjectIdentifiers.xmss_SHA512; + public static final ASN1ObjectIdentifier xmss_SHAKE128 = BCObjectIdentifiers.xmss_SHAKE128; + public static final ASN1ObjectIdentifier xmss_SHAKE256 = BCObjectIdentifiers.xmss_SHAKE256; + /** * XMSS^MT */ - public static final ASN1ObjectIdentifier xmss_mt = BCObjectIdentifiers.xmss_mt; - public static final ASN1ObjectIdentifier xmss_mt_with_SHA256 = BCObjectIdentifiers.xmss_mt_with_SHA256; - public static final ASN1ObjectIdentifier xmss_mt_with_SHA512 = BCObjectIdentifiers.xmss_mt_with_SHA512; - public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE128 = BCObjectIdentifiers.xmss_mt_with_SHAKE128; - public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE256 = BCObjectIdentifiers.xmss_mt_with_SHAKE256; + public static final ASN1ObjectIdentifier xmss_mt = BCObjectIdentifiers.xmss_mt; + public static final ASN1ObjectIdentifier xmss_mt_SHA256ph = BCObjectIdentifiers.xmss_mt_SHA256ph; + public static final ASN1ObjectIdentifier xmss_mt_SHA512ph = BCObjectIdentifiers.xmss_mt_SHA512ph; + public static final ASN1ObjectIdentifier xmss_mt_SHAKE128ph = BCObjectIdentifiers.xmss_mt_SHAKE128ph; + public static final ASN1ObjectIdentifier xmss_mt_SHAKE256ph = BCObjectIdentifiers.xmss_mt_SHAKE256ph; + public static final ASN1ObjectIdentifier xmss_mt_SHA256 = BCObjectIdentifiers.xmss_mt_SHA256; + public static final ASN1ObjectIdentifier xmss_mt_SHA512 = BCObjectIdentifiers.xmss_mt_SHA512; + public static final ASN1ObjectIdentifier xmss_mt_SHAKE128 = BCObjectIdentifiers.xmss_mt_SHAKE128; + public static final ASN1ObjectIdentifier xmss_mt_SHAKE256 = BCObjectIdentifiers.xmss_mt_SHAKE256; + + // old OIDs. + /** + * @deprecated use xmss_SHA256ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHA256 = xmss_SHA256ph; + /** + * @deprecated use xmss_SHA512ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHA512 = xmss_SHA512ph; + /** + * @deprecated use xmss_SHAKE128ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHAKE128 = xmss_SHAKE128ph; + /** + * @deprecated use xmss_SHAKE256ph + */ + public static final ASN1ObjectIdentifier xmss_with_SHAKE256 = xmss_SHAKE256ph; + + /** + * @deprecated use xmss_mt_SHA256ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHA256 = xmss_mt_SHA256ph; + /** + * @deprecated use xmss_mt_SHA512ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHA512 = xmss_mt_SHA512ph; + /** + * @deprecated use xmss_mt_SHAKE128ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE128 = xmss_mt_SHAKE128; + /** + * @deprecated use xmss_mt_SHAKE256ph + */ + public static final ASN1ObjectIdentifier xmss_mt_with_SHAKE256 = xmss_mt_SHAKE256; + + /** + * qTESLA + */ + public static final ASN1ObjectIdentifier qTESLA = BCObjectIdentifiers.qTESLA; + public static final ASN1ObjectIdentifier qTESLA_p_I = BCObjectIdentifiers.qTESLA_p_I; + public static final ASN1ObjectIdentifier qTESLA_p_III = BCObjectIdentifiers.qTESLA_p_III; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/ParSet.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/ParSet.java index eeed8b2d9..c761d1737 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/ParSet.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/ParSet.java @@ -2,6 +2,7 @@ package com.fr.third.org.bouncycastle.pqc.asn1; import java.math.BigInteger; +import com.fr.third.org.bouncycastle.asn1.ASN1Encodable; import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; import com.fr.third.org.bouncycastle.asn1.ASN1Object; @@ -30,14 +31,15 @@ public class ParSet private int[] w; private int[] k; - private static int checkBigIntegerInIntRangeAndPositive(BigInteger b) + private static int checkBigIntegerInIntRangeAndPositive(ASN1Encodable e) { - if ((b.compareTo(BigInteger.valueOf(Integer.MAX_VALUE)) > 0) || - (b.compareTo(ZERO) <= 0)) + ASN1Integer i = (ASN1Integer)e; + int value = i.intValueExact(); + if (value <= 0) { - throw new IllegalArgumentException("BigInteger not in Range: " + b.toString()); + throw new IllegalArgumentException("BigInteger not in Range: " + value); } - return b.intValue(); + return value; } private ParSet(ASN1Sequence seq) @@ -46,9 +48,8 @@ public class ParSet { throw new IllegalArgumentException("sie of seqOfParams = " + seq.size()); } - BigInteger asn1int = ((ASN1Integer)seq.getObjectAt(0)).getValue(); - t = checkBigIntegerInIntRangeAndPositive(asn1int); + t = checkBigIntegerInIntRangeAndPositive(seq.getObjectAt(0)); ASN1Sequence seqOfPSh = (ASN1Sequence)seq.getObjectAt(1); ASN1Sequence seqOfPSw = (ASN1Sequence)seq.getObjectAt(2); @@ -67,9 +68,9 @@ public class ParSet for (int i = 0; i < t; i++) { - h[i] = checkBigIntegerInIntRangeAndPositive((((ASN1Integer)seqOfPSh.getObjectAt(i))).getValue()); - w[i] = checkBigIntegerInIntRangeAndPositive((((ASN1Integer)seqOfPSw.getObjectAt(i))).getValue()); - k[i] = checkBigIntegerInIntRangeAndPositive((((ASN1Integer)seqOfPSK.getObjectAt(i))).getValue()); + h[i] = checkBigIntegerInIntRangeAndPositive(seqOfPSh.getObjectAt(i)); + w[i] = checkBigIntegerInIntRangeAndPositive(seqOfPSw.getObjectAt(i)); + k[i] = checkBigIntegerInIntRangeAndPositive(seqOfPSK.getObjectAt(i)); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/RainbowPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/RainbowPublicKey.java index ca07702be..937e149ac 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/RainbowPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/RainbowPublicKey.java @@ -103,7 +103,7 @@ public class RainbowPublicKey */ public int getDocLength() { - return this.docLength.getValue().intValue(); + return this.docLength.intValueExact(); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSKeyParams.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSKeyParams.java index ce7cfb0b1..9ea9e77a1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSKeyParams.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSKeyParams.java @@ -35,7 +35,7 @@ public class XMSSKeyParams private XMSSKeyParams(ASN1Sequence sequence) { this.version = ASN1Integer.getInstance(sequence.getObjectAt(0)); - this.height = ASN1Integer.getInstance(sequence.getObjectAt(1)).getValue().intValue(); + this.height = ASN1Integer.getInstance(sequence.getObjectAt(1)).intValueExact(); this.treeDigest = AlgorithmIdentifier.getInstance(sequence.getObjectAt(2)); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTKeyParams.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTKeyParams.java index 73413f066..ceb1fb3eb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTKeyParams.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTKeyParams.java @@ -38,8 +38,8 @@ public class XMSSMTKeyParams private XMSSMTKeyParams(ASN1Sequence sequence) { this.version = ASN1Integer.getInstance(sequence.getObjectAt(0)); - this.height = ASN1Integer.getInstance(sequence.getObjectAt(1)).getValue().intValue(); - this.layers = ASN1Integer.getInstance(sequence.getObjectAt(2)).getValue().intValue(); + this.height = ASN1Integer.getInstance(sequence.getObjectAt(1)).intValueExact(); + this.layers = ASN1Integer.getInstance(sequence.getObjectAt(2)).intValueExact(); this.treeDigest = AlgorithmIdentifier.getInstance(sequence.getObjectAt(3)); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTPrivateKey.java index 35afc9f89..6e1592e09 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTPrivateKey.java @@ -1,7 +1,5 @@ package com.fr.third.org.bouncycastle.pqc.asn1; -import java.math.BigInteger; - import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector; import com.fr.third.org.bouncycastle.asn1.ASN1Integer; import com.fr.third.org.bouncycastle.asn1.ASN1Object; @@ -12,18 +10,20 @@ import com.fr.third.org.bouncycastle.asn1.DEROctetString; import com.fr.third.org.bouncycastle.asn1.DERSequence; import com.fr.third.org.bouncycastle.asn1.DERTaggedObject; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * XMMSMTPrivateKey *

  *     XMMSMTPrivateKey ::= SEQUENCE {
- *         version INTEGER -- 0
+ *         version INTEGER -- 0, or 1 if maxIndex is present
  *         keyData SEQUENCE {
  *            index         INTEGER
  *            secretKeySeed OCTET STRING
  *            secretKeyPRF  OCTET STRING
  *            publicSeed    OCTET STRING
  *            root          OCTET STRING
+ *            maxIndex      [0] INTEGER OPTIONAL
  *         }
  *         bdsState CHOICE {
  *            platformSerialization [0] OCTET STRING
@@ -34,29 +34,47 @@ import com.fr.third.org.bouncycastle.util.Arrays;
 public class XMSSMTPrivateKey
     extends ASN1Object
 {
-    private final int index;
+    private final int version;
+    private final long index;
+    private final long maxIndex;
     private final byte[] secretKeySeed;
     private final byte[] secretKeyPRF;
     private final byte[] publicSeed;
     private final byte[] root;
     private final byte[] bdsState;
 
-    public XMSSMTPrivateKey(int index, byte[] secretKeySeed, byte[] secretKeyPRF, byte[] publicSeed, byte[] root, byte[] bdsState)
+    public XMSSMTPrivateKey(long index, byte[] secretKeySeed, byte[] secretKeyPRF, byte[] publicSeed, byte[] root, byte[] bdsState)
+    {
+        this.version = 0;
+        this.index = index;
+        this.secretKeySeed = Arrays.clone(secretKeySeed);
+        this.secretKeyPRF = Arrays.clone(secretKeyPRF);
+        this.publicSeed = Arrays.clone(publicSeed);
+        this.root = Arrays.clone(root);
+        this.bdsState = Arrays.clone(bdsState);
+        this.maxIndex = -1;
+    }
+
+    public XMSSMTPrivateKey(long index, byte[] secretKeySeed, byte[] secretKeyPRF, byte[] publicSeed, byte[] root, byte[] bdsState, long maxIndex)
     {
+        this.version = 1;
         this.index = index;
         this.secretKeySeed = Arrays.clone(secretKeySeed);
         this.secretKeyPRF = Arrays.clone(secretKeyPRF);
         this.publicSeed = Arrays.clone(publicSeed);
         this.root = Arrays.clone(root);
         this.bdsState = Arrays.clone(bdsState);
+        this.maxIndex = maxIndex;
     }
 
     private XMSSMTPrivateKey(ASN1Sequence seq)
     {
-        if (!ASN1Integer.getInstance(seq.getObjectAt(0)).getValue().equals(BigInteger.valueOf(0)))
+        ASN1Integer v = ASN1Integer.getInstance(seq.getObjectAt(0));
+        if (!(v.hasValue(BigIntegers.ZERO) || v.hasValue(BigIntegers.ONE)))
         {
             throw new IllegalArgumentException("unknown version of sequence");
         }
+        this.version = v.intValueExact();
 
         if (seq.size() != 2 && seq.size() != 3)
         {
@@ -65,12 +83,30 @@ public class XMSSMTPrivateKey
 
         ASN1Sequence keySeq = ASN1Sequence.getInstance(seq.getObjectAt(1));
 
-        this.index = ASN1Integer.getInstance(keySeq.getObjectAt(0)).getValue().intValue();
+        this.index = ASN1Integer.getInstance(keySeq.getObjectAt(0)).longValueExact();
         this.secretKeySeed = Arrays.clone(DEROctetString.getInstance(keySeq.getObjectAt(1)).getOctets());
         this.secretKeyPRF = Arrays.clone(DEROctetString.getInstance(keySeq.getObjectAt(2)).getOctets());
         this.publicSeed = Arrays.clone(DEROctetString.getInstance(keySeq.getObjectAt(3)).getOctets());
         this.root = Arrays.clone(DEROctetString.getInstance(keySeq.getObjectAt(4)).getOctets());
 
+        if (keySeq.size() == 6)
+        {
+            ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(keySeq.getObjectAt(5));
+            if (tagged.getTagNo() != 0)
+            {
+                throw new IllegalArgumentException("unknown tag in XMSSPrivateKey");
+            }
+            this.maxIndex = ASN1Integer.getInstance(tagged, false).longValueExact();
+        }
+        else if (keySeq.size() == 5)
+        {
+            this.maxIndex = -1;
+        }
+        else
+        {
+            throw new IllegalArgumentException("keySeq should be 5 or 6 in length");
+        }
+
         if(seq.size() == 3)
         {
             this.bdsState = Arrays.clone(DEROctetString.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(2)), true).getOctets());
@@ -95,11 +131,21 @@ public class XMSSMTPrivateKey
         return null;
     }
 
-    public int getIndex()
+    public int getVersion()
+    {
+        return version;
+    }
+
+    public long getIndex()
     {
         return index;
     }
 
+    public long getMaxIndex()
+    {
+        return maxIndex;
+    }
+
     public byte[] getSecretKeySeed()
     {
         return Arrays.clone(secretKeySeed);
@@ -129,7 +175,14 @@ public class XMSSMTPrivateKey
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
-        v.add(new ASN1Integer(0)); // version
+        if (maxIndex >= 0)
+        {
+            v.add(new ASN1Integer(1)); // version 1
+        }
+        else
+        {
+            v.add(new ASN1Integer(0)); // version 0
+        }
 
         ASN1EncodableVector vK = new ASN1EncodableVector();
 
@@ -138,6 +191,10 @@ public class XMSSMTPrivateKey
         vK.add(new DEROctetString(secretKeyPRF));
         vK.add(new DEROctetString(publicSeed));
         vK.add(new DEROctetString(root));
+        if (maxIndex >= 0)
+        {
+            vK.add(new DERTaggedObject(false, 0, new ASN1Integer(maxIndex)));
+        }
 
         v.add(new DERSequence(vK));
         v.add(new DERTaggedObject(true, 0, new DEROctetString(bdsState)));
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTPublicKey.java
index f10d51b5a..d3868a4bd 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTPublicKey.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSMTPublicKey.java
@@ -35,7 +35,7 @@ public class XMSSMTPublicKey
 
     private XMSSMTPublicKey(ASN1Sequence seq)
     {
-        if (!ASN1Integer.getInstance(seq.getObjectAt(0)).getValue().equals(BigInteger.valueOf(0)))
+        if (!ASN1Integer.getInstance(seq.getObjectAt(0)).hasValue(BigInteger.valueOf(0)))
         {
             throw new IllegalArgumentException("unknown version of sequence");
         }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSPrivateKey.java
index ee2076e9d..d4f036395 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSPrivateKey.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSPrivateKey.java
@@ -1,7 +1,5 @@
 package com.fr.third.org.bouncycastle.pqc.asn1;
 
-import java.math.BigInteger;
-
 import com.fr.third.org.bouncycastle.asn1.ASN1EncodableVector;
 import com.fr.third.org.bouncycastle.asn1.ASN1Integer;
 import com.fr.third.org.bouncycastle.asn1.ASN1Object;
@@ -12,18 +10,20 @@ import com.fr.third.org.bouncycastle.asn1.DEROctetString;
 import com.fr.third.org.bouncycastle.asn1.DERSequence;
 import com.fr.third.org.bouncycastle.asn1.DERTaggedObject;
 import com.fr.third.org.bouncycastle.util.Arrays;
+import com.fr.third.org.bouncycastle.util.BigIntegers;
 
 /**
  * XMMSPrivateKey
  * 
  *     XMMSPrivateKey ::= SEQUENCE {
- *         version INTEGER -- 0
+ *         version INTEGER -- 0, or 1 if maxIndex is present
  *         keyData SEQUENCE {
  *            index         INTEGER
  *            secretKeySeed OCTET STRING
  *            secretKeyPRF  OCTET STRING
  *            publicSeed    OCTET STRING
  *            root          OCTET STRING
+ *            maxIndex      [0] INTEGER OPTIONAL
  *         }
  *         bdsState CHOICE {
  *            platformSerialization [0] OCTET STRING
@@ -34,30 +34,48 @@ import com.fr.third.org.bouncycastle.util.Arrays;
 public class XMSSPrivateKey
     extends ASN1Object
 {
+    private final int version;
     private final int index;
     private final byte[] secretKeySeed;
     private final byte[] secretKeyPRF;
     private final byte[] publicSeed;
     private final byte[] root;
+    private final int maxIndex;
     private final byte[] bdsState;
 
     public XMSSPrivateKey(int index, byte[] secretKeySeed, byte[] secretKeyPRF, byte[] publicSeed, byte[] root, byte[] bdsState)
     {
+        this.version = 0;
         this.index = index;
         this.secretKeySeed = Arrays.clone(secretKeySeed);
         this.secretKeyPRF = Arrays.clone(secretKeyPRF);
         this.publicSeed = Arrays.clone(publicSeed);
         this.root = Arrays.clone(root);
         this.bdsState = Arrays.clone(bdsState);
+        this.maxIndex = -1;
+    }
+
+    public XMSSPrivateKey(int index, byte[] secretKeySeed, byte[] secretKeyPRF, byte[] publicSeed, byte[] root, byte[] bdsState, int maxIndex)
+    {
+        this.version = 1;
+        this.index = index;
+        this.secretKeySeed = Arrays.clone(secretKeySeed);
+        this.secretKeyPRF = Arrays.clone(secretKeyPRF);
+        this.publicSeed = Arrays.clone(publicSeed);
+        this.root = Arrays.clone(root);
+        this.bdsState = Arrays.clone(bdsState);
+        this.maxIndex = maxIndex;
     }
 
     private XMSSPrivateKey(ASN1Sequence seq)
     {
-        if (!ASN1Integer.getInstance(seq.getObjectAt(0)).getValue().equals(BigInteger.valueOf(0)))
+        ASN1Integer v = ASN1Integer.getInstance(seq.getObjectAt(0));
+        if (!(v.hasValue(BigIntegers.ZERO) || v.hasValue(BigIntegers.ONE)))
         {
             throw new IllegalArgumentException("unknown version of sequence");
         }
-
+        this.version = v.intValueExact();
+        
         if (seq.size() != 2 && seq.size() != 3)
         {
             throw new IllegalArgumentException("key sequence wrong size");
@@ -65,12 +83,30 @@ public class XMSSPrivateKey
 
         ASN1Sequence keySeq = ASN1Sequence.getInstance(seq.getObjectAt(1));
 
-        this.index = ASN1Integer.getInstance(keySeq.getObjectAt(0)).getValue().intValue();
+        this.index = ASN1Integer.getInstance(keySeq.getObjectAt(0)).intValueExact();
         this.secretKeySeed = Arrays.clone(DEROctetString.getInstance(keySeq.getObjectAt(1)).getOctets());
         this.secretKeyPRF = Arrays.clone(DEROctetString.getInstance(keySeq.getObjectAt(2)).getOctets());
         this.publicSeed = Arrays.clone(DEROctetString.getInstance(keySeq.getObjectAt(3)).getOctets());
         this.root = Arrays.clone(DEROctetString.getInstance(keySeq.getObjectAt(4)).getOctets());
 
+        if (keySeq.size() == 6)
+        {
+            ASN1TaggedObject tagged = ASN1TaggedObject.getInstance(keySeq.getObjectAt(5));
+            if (tagged.getTagNo() != 0)
+            {
+                throw new IllegalArgumentException("unknown tag in XMSSPrivateKey");
+            }
+            this.maxIndex = ASN1Integer.getInstance(tagged, false).intValueExact();
+        }
+        else if (keySeq.size() == 5)
+        {
+            this.maxIndex = -1;
+        }
+        else
+        {
+            throw new IllegalArgumentException("keySeq should be 5 or 6 in length");
+        }
+
         if (seq.size() == 3)
         {
             this.bdsState = Arrays.clone(DEROctetString.getInstance(ASN1TaggedObject.getInstance(seq.getObjectAt(2)), true).getOctets());
@@ -95,11 +131,21 @@ public class XMSSPrivateKey
         return null;
     }
 
+    public int getVersion()
+    {
+        return version;
+    }
+
     public int getIndex()
     {
         return index;
     }
 
+    public int getMaxIndex()
+    {
+        return maxIndex;
+    }
+
     public byte[] getSecretKeySeed()
     {
         return Arrays.clone(secretKeySeed);
@@ -129,7 +175,14 @@ public class XMSSPrivateKey
     {
         ASN1EncodableVector v = new ASN1EncodableVector();
 
-        v.add(new ASN1Integer(0)); // version
+        if (maxIndex >= 0)
+        {
+            v.add(new ASN1Integer(1)); // version 1
+        }
+        else
+        {
+            v.add(new ASN1Integer(0)); // version 0
+        }
 
         ASN1EncodableVector vK = new ASN1EncodableVector();
 
@@ -138,7 +191,11 @@ public class XMSSPrivateKey
         vK.add(new DEROctetString(secretKeyPRF));
         vK.add(new DEROctetString(publicSeed));
         vK.add(new DEROctetString(root));
-
+        if (maxIndex >= 0)
+        {
+            vK.add(new DERTaggedObject(false, 0, new ASN1Integer(maxIndex)));
+        }
+        
         v.add(new DERSequence(vK));
         v.add(new DERTaggedObject(true, 0, new DEROctetString(bdsState)));
 
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSPublicKey.java
index 33e80cab8..76e16479f 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSPublicKey.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/asn1/XMSSPublicKey.java
@@ -35,7 +35,7 @@ public class XMSSPublicKey
 
     private XMSSPublicKey(ASN1Sequence seq)
     {
-        if (!ASN1Integer.getInstance(seq.getObjectAt(0)).getValue().equals(BigInteger.valueOf(0)))
+        if (!ASN1Integer.getInstance(seq.getObjectAt(0)).hasValue(BigInteger.valueOf(0)))
         {
             throw new IllegalArgumentException("unknown version of sequence");
         }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSLeaf.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSLeaf.java
index eaab4f648..9d9d0f92e 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSLeaf.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSLeaf.java
@@ -112,7 +112,7 @@ public class GMSSLeaf
      * The constructor precomputes some needed variables for distributed leaf
      * calculation
      *
-     * @param digest     an array of strings, containing the digest of the used hash
+     * @param digest   an array of strings, containing the digest of the used hash
      *                 function and PRNG and the digest of the corresponding
      *                 provider
      * @param w        the winterniz parameter of that tree the leaf is computed
@@ -231,7 +231,7 @@ public class GMSSLeaf
      */
     private void updateLeafCalc()
     {
-         byte[] buf = new byte[messDigestOTS.getDigestSize()];
+        byte[] buf = new byte[messDigestOTS.getDigestSize()];
 
         // steps times do
         // TODO: this really needs to be looked at, the 10000 has been added as
@@ -273,7 +273,7 @@ public class GMSSLeaf
             }
         }
 
-       throw new IllegalStateException("unable to updateLeaf in steps: " + steps + " " + i + " " + j);
+        throw new IllegalStateException("unable to updateLeaf in steps: " + steps + " " + i + " " + j);
     }
 
     /**
@@ -292,7 +292,7 @@ public class GMSSLeaf
      *
      * @param intValue an integer
      * @return The least integer greater or equal to the logarithm to the base 2
-     *         of intValue
+     * of intValue
      */
     private int getLog(int intValue)
     {
@@ -315,10 +315,6 @@ public class GMSSLeaf
     {
 
         byte[][] statByte = new byte[4][];
-        statByte[0] = new byte[mdsize];
-        statByte[1] = new byte[mdsize];
-        statByte[2] = new byte[mdsize * keysize];
-        statByte[3] = new byte[mdsize];
         statByte[0] = privateKeyOTS;
         statByte[1] = seed;
         statByte[2] = concHashs;
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java
index 346c228f0..ad2f6bc89 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSPrivateKeyParameters.java
@@ -198,7 +198,7 @@ public class GMSSPrivateKeyParameters
         this.currentSeeds = currentSeeds;
         this.nextNextSeeds = nextNextSeeds;
 
-        this.currentAuthPaths = currentAuthPaths;
+        this.currentAuthPaths = Arrays.clone(currentAuthPaths);
         this.nextAuthPaths = nextAuthPaths;
 
         // initialize keep if null
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSRootCalc.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSRootCalc.java
index fababcf8a..e3691a8ce 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSRootCalc.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/gmss/GMSSRootCalc.java
@@ -102,80 +102,6 @@ public class GMSSRootCalc
      */
     private int heightOfNextSeed;
 
-    /**
-     * This constructor regenerates a prior treehash object
-     *
-     * @param digest     an array of strings, containing the digest of the used hash
-     *                 function and PRNG and the digest of the corresponding
-     *                 provider
-     * @param statByte status bytes
-     * @param statInt  status ints
-     */
-    public GMSSRootCalc(Digest digest, byte[][] statByte, int[] statInt,
-                        Treehash[] treeH, Vector[] ret)
-    {
-        this.messDigestTree = digestProvider.get();
-        this.digestProvider = digestProvider;
-        // decode statInt
-        this.heightOfTree = statInt[0];
-        this.mdLength = statInt[1];
-        this.K = statInt[2];
-        this.indexForNextSeed = statInt[3];
-        this.heightOfNextSeed = statInt[4];
-        if (statInt[5] == 1)
-        {
-            this.isFinished = true;
-        }
-        else
-        {
-            this.isFinished = false;
-        }
-        if (statInt[6] == 1)
-        {
-            this.isInitialized = true;
-        }
-        else
-        {
-            this.isInitialized = false;
-        }
-
-        int tailLength = statInt[7];
-
-        this.index = new int[heightOfTree];
-        for (int i = 0; i < heightOfTree; i++)
-        {
-            this.index[i] = statInt[8 + i];
-        }
-
-        this.heightOfNodes = new Vector();
-        for (int i = 0; i < tailLength; i++)
-        {
-            this.heightOfNodes.addElement(Integers.valueOf(statInt[8 + heightOfTree
-                + i]));
-        }
-
-        // decode statByte
-        this.root = statByte[0];
-
-        this.AuthPath = new byte[heightOfTree][mdLength];
-        for (int i = 0; i < heightOfTree; i++)
-        {
-            this.AuthPath[i] = statByte[1 + i];
-        }
-
-        this.tailStack = new Vector();
-        for (int i = 0; i < tailLength; i++)
-        {
-            this.tailStack.addElement(statByte[1 + heightOfTree + i]);
-        }
-
-        // decode treeH
-        this.treehash = GMSSUtils.clone(treeH);
-
-        // decode ret
-        this.retain = GMSSUtils.clone(ret);
-    }
-
     /**
      * Constructor
      *
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java
index 37c07829c..bcef87925 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/mceliece/McElieceKeyPairGenerator.java
@@ -71,7 +71,11 @@ public class McElieceKeyPairGenerator
         this.mcElieceParams = (McElieceKeyGenerationParameters)param;
 
         // set source of randomness
-        this.random = CryptoServicesRegistrar.getSecureRandom();
+        this.random = param.getRandom();
+        if (this.random == null)
+        {
+            this.random = CryptoServicesRegistrar.getSecureRandom();
+        }
 
         this.m = this.mcElieceParams.getParameters().getM();
         this.n = this.mcElieceParams.getParameters().getN();
@@ -140,7 +144,6 @@ public class McElieceKeyPairGenerator
     public void init(KeyGenerationParameters param)
     {
         this.initialize(param);
-
     }
 
     public AsymmetricCipherKeyPair generateKeyPair()
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/newhope/NHOtherInfoGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/newhope/NHOtherInfoGenerator.java
index ac3997808..605907901 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/newhope/NHOtherInfoGenerator.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/newhope/NHOtherInfoGenerator.java
@@ -20,6 +20,8 @@ public class NHOtherInfoGenerator
     protected final DEROtherInfo.Builder otherInfoBuilder;
     protected final SecureRandom random;
 
+    protected boolean used = false;
+    
     /**
      * Create a basic builder with just the compulsory fields.
      *
@@ -76,6 +78,13 @@ public class NHOtherInfoGenerator
 
         public DEROtherInfo generate(byte[] suppPrivInfoPartB)
         {
+            if (used)
+            {
+                throw new IllegalStateException("builder already used");
+            }
+
+            used = true;
+
             this.otherInfoBuilder.withSuppPrivInfo(agreement.calculateAgreement(NHOtherInfoGenerator.getPublicKey(suppPrivInfoPartB)));
 
             return otherInfoBuilder.build();
@@ -119,6 +128,13 @@ public class NHOtherInfoGenerator
 
         public DEROtherInfo generate()
         {
+            if (used)
+            {
+                throw new IllegalStateException("builder already used");
+            }
+
+            used = true;
+
             return otherInfoBuilder.build();
         }
     }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/HashUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/HashUtils.java
new file mode 100644
index 000000000..eed265ca4
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/HashUtils.java
@@ -0,0 +1,52 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qtesla;
+
+import com.fr.third.org.bouncycastle.crypto.digests.CSHAKEDigest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest;
+
+class HashUtils
+{
+
+    static final int SECURE_HASH_ALGORITHM_KECCAK_128_RATE = 168;
+    static final int SECURE_HASH_ALGORITHM_KECCAK_256_RATE = 136;
+
+    /***************************************************************************************************************************************************************
+     * Description:	The Secure-Hash-Algorithm-3 Extendable-Output Function That Generally Supports 128 Bits of Security Strength, If the Output is Sufficiently Long
+     ***************************************************************************************************************************************************************/
+    static void secureHashAlgorithmKECCAK128(byte[] output, int outputOffset, int outputLength, byte[] input, int inputOffset, int inputLength)
+    {
+        SHAKEDigest dig = new SHAKEDigest(128);
+        dig.update(input, inputOffset, inputLength);
+
+        dig.doFinal(output, outputOffset, outputLength);
+    }
+
+    /***************************************************************************************************************************************************************
+     * Description:	The Secure-Hash-Algorithm-3 Extendable-Output Function That Generally Supports 256 Bits of Security Strength, If the Output is Sufficiently Long
+     ***************************************************************************************************************************************************************/
+    static void secureHashAlgorithmKECCAK256(byte[] output, int outputOffset, int outputLength, byte[] input, int inputOffset, int inputLength)
+    {
+        SHAKEDigest dig = new SHAKEDigest(256);
+        dig.update(input, inputOffset, inputLength);
+
+        dig.doFinal(output, outputOffset, outputLength);
+    }
+
+    /* Customizable Secure Hash Algorithm KECCAK 128 / Customizable Secure Hash Algorithm KECCAK 256 */
+
+
+    static void customizableSecureHashAlgorithmKECCAK128Simple(byte[] output, int outputOffset, int outputLength, short continuousTimeStochasticModelling, byte[] input, int inputOffset, int inputLength)
+    {
+        CSHAKEDigest dig = new CSHAKEDigest(128, null, new byte[]{(byte)continuousTimeStochasticModelling, (byte)(continuousTimeStochasticModelling >> 8)});
+        dig.update(input, inputOffset, inputLength);
+
+        dig.doFinal(output, outputOffset, outputLength);
+    }
+
+    static void customizableSecureHashAlgorithmKECCAK256Simple(byte[] output, int outputOffset, int outputLength, short continuousTimeStochasticModelling, byte[] input, int inputOffset, int inputLength)
+    {
+        CSHAKEDigest dig = new CSHAKEDigest(256, null, new byte[]{(byte)continuousTimeStochasticModelling, (byte)(continuousTimeStochasticModelling >> 8)});
+        dig.update(input, inputOffset, inputLength);
+
+        dig.doFinal(output, outputOffset, outputLength);
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/IntSlicer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/IntSlicer.java
new file mode 100644
index 000000000..3ae355f25
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/IntSlicer.java
@@ -0,0 +1,52 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qtesla;
+
+/**
+ * Simulates pointer arithmetic.
+ * A utility for porting C to Java where C code makes heavy use of pointer arithmetic.
+ *
+ * @Deprecated Remove when Post-Quantum Standardization project has finished and standard is published.
+ */
+final class IntSlicer
+{
+    private final int[] values;
+    private int base;
+
+    IntSlicer(int[] values, int base)
+    {
+        this.values = values;
+        this.base = base;
+    }
+
+    final int at(int index)
+    {
+        return values[base + index];
+    }
+
+    final int at(int index, int value)
+    {
+        return values[base + index] = value;
+    }
+
+
+    final int at(int index, long value)
+    {
+        return values[base + index] = (int)value;
+    }
+
+    final IntSlicer from(int o)
+    {
+        return new IntSlicer(values, base + o);
+    }
+
+    final void incBase(int paramM)
+    {
+        base += paramM;
+
+    }
+
+    final IntSlicer copy()
+    {
+        return new IntSlicer(values, base);
+    }
+
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAKeyGenerationParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAKeyGenerationParameters.java
new file mode 100644
index 000000000..f27a0fe01
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAKeyGenerationParameters.java
@@ -0,0 +1,39 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qtesla;
+
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters;
+
+/**
+ * qTESLA key-pair generation parameters.
+ */
+public class QTESLAKeyGenerationParameters
+    extends KeyGenerationParameters
+{
+    private final int securityCategory;
+
+    /**
+     * Base constructor - provide the qTESLA security category and a source of randomness.
+     *
+     * @param securityCategory the security category to generate the parameters for.
+     * @param random           the random byte source.
+     */
+    public QTESLAKeyGenerationParameters(int securityCategory, SecureRandom random)
+    {
+        super(random, -1);
+
+        QTESLASecurityCategory.getPrivateSize(securityCategory);  // check the category is valid
+
+        this.securityCategory = securityCategory;
+    }
+
+    /**
+      * Return the security category for these parameters.
+      *
+      * @return the security category for keys generated using these parameters.
+      */
+    public int getSecurityCategory()
+    {
+        return securityCategory;
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAKeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAKeyPairGenerator.java
new file mode 100644
index 000000000..16cd8c7bb
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAKeyPairGenerator.java
@@ -0,0 +1,71 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qtesla;
+
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters;
+
+/**
+ * Key-pair generator for qTESLA keys.
+ */
+public final class QTESLAKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator
+{
+    /**
+     * qTESLA Security Category
+     */
+    private int securityCategory;
+    private SecureRandom secureRandom;
+
+    /**
+     * Initialize the generator with a security category and a source of randomness.
+     *
+     * @param param a {@link QTESLAKeyGenerationParameters} object.
+     */
+    public void init(
+        KeyGenerationParameters param)
+    {
+        QTESLAKeyGenerationParameters parameters = (QTESLAKeyGenerationParameters)param;
+
+        this.secureRandom = parameters.getRandom();
+        this.securityCategory = parameters.getSecurityCategory();
+    }
+
+    /**
+     * Generate a key-pair.
+     *
+     * @return a matching key-pair consisting of (QTESLAPublicKeyParameters, QTESLAPrivateKeyParameters).
+     */
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        byte[] privateKey = allocatePrivate(securityCategory);
+        byte[] publicKey = allocatePublic(securityCategory);
+
+        switch (securityCategory)
+        {
+        case QTESLASecurityCategory.PROVABLY_SECURE_I:
+            QTesla1p.generateKeyPair(publicKey, privateKey, secureRandom);
+            break;
+
+        case QTESLASecurityCategory.PROVABLY_SECURE_III:
+            QTesla3p.generateKeyPair(publicKey, privateKey, secureRandom);
+            break;
+
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+
+        return new AsymmetricCipherKeyPair(new QTESLAPublicKeyParameters(securityCategory, publicKey), new QTESLAPrivateKeyParameters(securityCategory, privateKey));
+    }
+
+    private byte[] allocatePrivate(int securityCategory)
+    {
+        return new byte[QTESLASecurityCategory.getPrivateSize(securityCategory)];
+    }
+
+    private byte[] allocatePublic(int securityCategory)
+    {
+        return new byte[QTESLASecurityCategory.getPublicSize(securityCategory)];
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAPrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAPrivateKeyParameters.java
new file mode 100644
index 000000000..5ce0684f7
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAPrivateKeyParameters.java
@@ -0,0 +1,60 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qtesla;
+
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.fr.third.org.bouncycastle.util.Arrays;
+
+/**
+ * qTESLA private key
+ */
+public final class QTESLAPrivateKeyParameters
+    extends AsymmetricKeyParameter
+{
+    /**
+     * qTESLA Security Category (From 4 To 8)
+     */
+    private int securityCategory;
+
+    /**
+     * Text of the qTESLA Private Key
+     */
+    private byte[] privateKey;
+
+    /**
+     * Base constructor.
+     *
+     * @param securityCategory the security category for the passed in public key data.
+     * @param privateKey the private key data.
+     */
+    public QTESLAPrivateKeyParameters(int securityCategory, byte[] privateKey)
+    {
+        super(true);
+
+        if (privateKey.length != QTESLASecurityCategory.getPrivateSize(securityCategory))
+        {
+            throw new IllegalArgumentException("invalid key size for security category");
+        }
+
+        this.securityCategory = securityCategory;
+        this.privateKey = Arrays.clone(privateKey);
+    }
+
+    /**
+     * Return the security category for this key.
+     *
+     * @return the key's security category.
+     */
+    public int getSecurityCategory()
+    {
+        return this.securityCategory;
+    }
+
+    /**
+     * Return the key's secret value.
+     *
+     * @return key private data.
+     */
+    public byte[] getSecret()
+    {
+        return Arrays.clone(privateKey);
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAPublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAPublicKeyParameters.java
new file mode 100644
index 000000000..040b8b0c3
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLAPublicKeyParameters.java
@@ -0,0 +1,61 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qtesla;
+
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.fr.third.org.bouncycastle.util.Arrays;
+
+/**
+ * qTESLA public key
+ */
+public final class QTESLAPublicKeyParameters
+    extends AsymmetricKeyParameter
+{
+    /**
+     * qTESLA Security Category
+     */
+    private int securityCategory;
+
+    /**
+     * Text of the qTESLA Public Key
+     */
+    private byte[] publicKey;
+
+    /**
+     * Base constructor.
+     *
+     * @param securityCategory the security category for the passed in public key data.
+     * @param publicKey the public key data.
+     */
+    public QTESLAPublicKeyParameters(int securityCategory, byte[] publicKey)
+    {
+        super(false);
+
+        if (publicKey.length != QTESLASecurityCategory.getPublicSize(securityCategory))
+        {
+            throw new IllegalArgumentException("invalid key size for security category");
+        }
+
+        this.securityCategory = securityCategory;
+        this.publicKey = Arrays.clone(publicKey);
+
+    }
+
+    /**
+     * Return the security category for this key.
+     *
+     * @return the key's security category.
+     */
+    public int getSecurityCategory()
+    {
+        return this.securityCategory;
+    }
+
+    /**
+     * Return the key's public value.
+     *
+     * @return key public data.
+     */
+    public byte[] getPublicData()
+    {
+        return Arrays.clone(publicKey);
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLASecurityCategory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLASecurityCategory.java
new file mode 100644
index 000000000..c36a7b249
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLASecurityCategory.java
@@ -0,0 +1,87 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qtesla;
+
+/**
+ * The qTESLA security categories.
+ */
+public class QTESLASecurityCategory
+{
+    public static final int PROVABLY_SECURE_I = 5;
+    public static final int PROVABLY_SECURE_III = 6;
+
+    private QTESLASecurityCategory()
+    {
+    }
+
+    static void validate(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+        case PROVABLY_SECURE_I:
+        case PROVABLY_SECURE_III:
+            break;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+
+    static int getPrivateSize(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+        case PROVABLY_SECURE_I:
+            return QTesla1p.CRYPTO_SECRETKEYBYTES;
+        case PROVABLY_SECURE_III:
+            return QTesla3p.CRYPTO_SECRETKEYBYTES;
+
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+
+    static int getPublicSize(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+        case PROVABLY_SECURE_I:
+            return QTesla1p.CRYPTO_PUBLICKEYBYTES;
+        case PROVABLY_SECURE_III:
+            return QTesla3p.CRYPTO_PUBLICKEYBYTES;
+
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+
+    static int getSignatureSize(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+
+        case PROVABLY_SECURE_I:
+            return QTesla1p.CRYPTO_BYTES;
+        case PROVABLY_SECURE_III:
+            return QTesla3p.CRYPTO_BYTES;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+
+    /**
+     * Return a standard name for the security category.
+     *
+     * @param securityCategory the category of interest.
+     * @return the name for the category.
+     */
+    public static String getName(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+        case PROVABLY_SECURE_I:
+            return "qTESLA-p-I";
+        case PROVABLY_SECURE_III:
+            return "qTESLA-p-III";
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLASigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLASigner.java
new file mode 100644
index 000000000..bb4b54105
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTESLASigner.java
@@ -0,0 +1,120 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qtesla;
+
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.crypto.CipherParameters;
+import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.fr.third.org.bouncycastle.pqc.crypto.MessageSigner;
+
+/**
+ * Signer for the qTESLA algorithm (https://qtesla.org/)
+ */
+public class QTESLASigner
+    implements MessageSigner
+{
+    /**
+     * The Public Key of the Identity Whose Signature Will be Generated
+     */
+    private QTESLAPublicKeyParameters publicKey;
+
+    /**
+     * The Private Key of the Identity Whose Signature Will be Generated
+     */
+    private QTESLAPrivateKeyParameters privateKey;
+
+    /**
+     * The Source of Randomness for private key operations
+     */
+    private SecureRandom secureRandom;
+
+    public QTESLASigner()
+    {
+    }
+
+    /**
+     * Initialise the signer.
+     *
+     * @param forSigning true if we are generating a signature, false
+     *                   otherwise.
+     * @param param      ParametersWithRandom containing a private key for signature generation, public key otherwise.
+     */
+    public void init(boolean forSigning, CipherParameters param)
+    {
+        if (forSigning)
+        {
+            if (param instanceof ParametersWithRandom)
+            {
+                this.secureRandom = ((ParametersWithRandom)param).getRandom();
+                privateKey = (QTESLAPrivateKeyParameters)((ParametersWithRandom)param).getParameters();
+            }
+            else
+            {
+                this.secureRandom = CryptoServicesRegistrar.getSecureRandom();
+                privateKey = (QTESLAPrivateKeyParameters)param;
+            }
+            publicKey = null;
+            QTESLASecurityCategory.validate(privateKey.getSecurityCategory());
+        }
+        else
+        {
+            privateKey = null;
+            publicKey = (QTESLAPublicKeyParameters)param;
+            QTESLASecurityCategory.validate(publicKey.getSecurityCategory());
+        }
+    }
+
+    /**
+     * Generate a signature directly for the passed in message.
+     *
+     * @param message the message to be signed.
+     * @return the signature generated.
+     */
+    public byte[] generateSignature(byte[] message)
+    {
+        byte[] sig = new byte[QTESLASecurityCategory.getSignatureSize(privateKey.getSecurityCategory())];
+
+        switch (privateKey.getSecurityCategory())
+        {
+        case QTESLASecurityCategory.PROVABLY_SECURE_I:
+            QTesla1p.generateSignature(sig, message, 0, message.length, privateKey.getSecret(), secureRandom);
+            break;
+        case QTESLASecurityCategory.PROVABLY_SECURE_III:
+            QTesla3p.generateSignature(sig, message, 0, message.length, privateKey.getSecret(), secureRandom);
+            break;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + privateKey.getSecurityCategory());
+        }
+
+        return sig;
+    }
+
+    /**
+     * Verify the signature against the passed in message.
+     *
+     * @param message   the message that was supposed to have been signed.
+     * @param signature the signature of the message
+     * @return true if the signature passes, false otherwise.
+     */
+    public boolean verifySignature(byte[] message, byte[] signature)
+    {
+        int status;
+
+        switch (publicKey.getSecurityCategory())
+        {
+
+        case QTESLASecurityCategory.PROVABLY_SECURE_I:
+            status = QTesla1p.verifying(message, signature, 0, signature.length, publicKey.getPublicData());
+            break;
+
+        case QTESLASecurityCategory.PROVABLY_SECURE_III:
+            status = QTesla3p.verifying(message, signature, 0, signature.length, publicKey.getPublicData());
+            break;
+
+        default:
+            throw new IllegalArgumentException("unknown security category: " + publicKey.getSecurityCategory());
+        }
+
+        return 0 == status;
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTesla1p.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTesla1p.java
new file mode 100644
index 000000000..9ae027529
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTesla1p.java
@@ -0,0 +1,1414 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qtesla;
+
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.util.Arrays;
+import com.fr.third.org.bouncycastle.util.Pack;
+
+class QTesla1p
+{
+    private static final int PARAM_N = 1024;
+    private static final int PARAM_N_LOG = 10;
+    private static final double PARAM_SIGMA = 8.5;
+    private static final int PARAM_Q = 343576577;
+    private static final int PARAM_Q_LOG = 29;
+    private static final long PARAM_QINV = 2205847551L;
+    private static final int PARAM_BARR_MULT = 3;
+    private static final int PARAM_BARR_DIV = 30;
+    private static final int PARAM_B = 524287;
+    private static final int PARAM_B_BITS = 19;
+    private static final int PARAM_S_BITS = 8;
+    private static final int PARAM_K = 4;
+    private static final double PARAM_SIGMA_E = PARAM_SIGMA;
+    private static final int PARAM_H = 25;
+    private static final int PARAM_D = 22;
+    private static final int PARAM_GEN_A = 108;
+    private static final int PARAM_KEYGEN_BOUND_E = 554;
+    private static final int PARAM_E = PARAM_KEYGEN_BOUND_E;
+    private static final int PARAM_KEYGEN_BOUND_S = 554;
+    private static final int PARAM_S = PARAM_KEYGEN_BOUND_S;
+    private static final int PARAM_R2_INVN = 13632409;
+    private static final int PARAM_R = 172048372;
+
+    private static final int CRYPTO_RANDOMBYTES = 32;
+    private static final int CRYPTO_SEEDBYTES = 32;
+    private static final int CRYPTO_C_BYTES = 32;
+    private static final int HM_BYTES = 64;
+
+    private static final int RADIX = 32;
+    private static final int RADIX32 = 32;
+
+
+    static final int CRYPTO_BYTES = ((PARAM_N * (PARAM_B_BITS + 1) + 7) / 8 + CRYPTO_C_BYTES);
+    // Contains polynomial s and e, and seeds seed_a and seed_y
+    static final int CRYPTO_SECRETKEYBYTES = (1 * PARAM_N + 1 * PARAM_N * PARAM_K + 2 * CRYPTO_SEEDBYTES);
+
+    // Contains seed_a and polynomials t
+    static final int CRYPTO_PUBLICKEYBYTES = ((PARAM_Q_LOG * PARAM_N * PARAM_K + 7) / 8 + CRYPTO_SEEDBYTES);
+
+
+    static int generateKeyPair(
+
+        byte[] publicKey, byte[] privateKey, SecureRandom secureRandom)
+    {
+
+        /* Initialize Domain Separator for Error Polynomial and Secret Polynomial */
+        int nonce = 0;
+
+        byte[] randomness = new byte[CRYPTO_RANDOMBYTES];
+
+        /* Extend Random Bytes to Seed Generation of Error Polynomial and Secret Polynomial */
+        byte[] randomnessExtended = new byte[(PARAM_K + 3) * CRYPTO_SEEDBYTES];
+
+        long[] secretPolynomial = new long[PARAM_N];
+        long[] errorPolynomial = new long[PARAM_N * PARAM_K];
+        long[] A = new long[PARAM_N * PARAM_K];
+        long[] T = new long[PARAM_N * PARAM_K];
+
+        long[] s_ntt = new long[PARAM_N];
+
+        /* Get randomnessExtended <- seedErrorPolynomial, seedSecretPolynomial, seedA, seedY */
+        // this.rng.randomByte (randomness, (short) 0, Polynomial.RANDOM);
+        secureRandom.nextBytes(randomness);
+
+
+        HashUtils.secureHashAlgorithmKECCAK128(randomnessExtended, 0, (PARAM_K + 3) * CRYPTO_SEEDBYTES, randomness, 0, CRYPTO_RANDOMBYTES);
+
+
+        /*
+         * Sample the Error Polynomial Fulfilling the Criteria
+         * Choose All Error Polynomial in R with Entries from D_SIGMA
+         * Repeat Step at Iteration if the h Largest Entries of Error Polynomial Summation to L_E
+         */
+
+        for (int k = 0; k < PARAM_K; k++)
+        {
+            do
+            {
+                Gaussian.sample_gauss_polly(++nonce, randomnessExtended, k * CRYPTO_SEEDBYTES, errorPolynomial, k * PARAM_N);
+            }
+            while (checkPolynomial(errorPolynomial, k * PARAM_N, PARAM_KEYGEN_BOUND_E));
+        }
+
+
+        /*
+         * Sample the Secret Polynomial Fulfilling the Criteria
+         * Choose Secret Polynomial in R with Entries from D_SIGMA
+         * Repeat Step if the h Largest Entries of Secret Polynomial Summation to L_S
+         */
+        do
+        {
+
+            Gaussian.sample_gauss_polly(++nonce, randomnessExtended, PARAM_K * CRYPTO_SEEDBYTES, secretPolynomial, 0);
+
+            //Sample.polynomialGaussSamplerI(secretPolynomial, 0, randomnessExtended, Polynomial.SEED, ++nonce);
+        }
+        while (checkPolynomial(secretPolynomial, 0, PARAM_KEYGEN_BOUND_S));
+
+
+        QTesla1PPolynomial.poly_uniform(A, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES);
+
+        QTesla1PPolynomial.poly_ntt(s_ntt, secretPolynomial);
+
+
+        for (int k = 0; k < PARAM_K; k++)
+        {
+            QTesla1PPolynomial.poly_mul(T, k * PARAM_N, A, k * PARAM_N, s_ntt);
+            QTesla1PPolynomial.poly_add_correct(T, k * PARAM_N, T, k * PARAM_N, errorPolynomial, k * PARAM_N);
+        }
+
+
+        /* Pack Public and Private Keys */
+
+        encodePublicKey(publicKey, T, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES);
+        encodePrivateKey(privateKey, secretPolynomial, errorPolynomial, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES);
+
+        return 0;
+
+    }
+
+
+    static int generateSignature(
+
+        byte[] signature,
+        final byte[] message, int messageOffset, int messageLength,
+        final byte[] privateKey, SecureRandom secureRandom
+    )
+    {
+        byte[] c = new byte[CRYPTO_C_BYTES];
+        byte[] randomness = new byte[CRYPTO_SEEDBYTES];
+        byte[] randomness_input = new byte[CRYPTO_RANDOMBYTES + CRYPTO_SEEDBYTES + HM_BYTES];
+        int[] pos_list = new int[PARAM_H];
+        short[] sign_list = new short[PARAM_H];
+        long[] y = new long[PARAM_N];
+
+        long[] y_ntt = new long[PARAM_N];
+        long[] Sc = new long[PARAM_N];
+        long[] z = new long[PARAM_N];
+
+        long[] v = new long[PARAM_N * PARAM_K];
+        long[] Ec = new long[PARAM_N * PARAM_K];
+        long[] a = new long[PARAM_N * PARAM_K];
+
+        int k;
+        int nonce = 0;  // Initialize domain separator for sampling y
+        boolean rsp = false;
+
+        //  randombytes(randomness_input + CRYPTO_RANDOMBYTES, CRYPTO_RANDOMBYTES);
+        byte[] temporaryRandomnessInput = new byte[CRYPTO_RANDOMBYTES];
+        secureRandom.nextBytes(temporaryRandomnessInput);
+        System.arraycopy(temporaryRandomnessInput, 0, randomness_input, CRYPTO_RANDOMBYTES, CRYPTO_RANDOMBYTES);
+        // --
+
+
+        //  memcpy(randomness_input, &sk[CRYPTO_SECRETKEYBYTES - CRYPTO_SEEDBYTES], CRYPTO_SEEDBYTES);
+        System.arraycopy(privateKey, CRYPTO_SECRETKEYBYTES - CRYPTO_SEEDBYTES, randomness_input, 0, CRYPTO_SEEDBYTES);
+        // --
+
+        HashUtils.secureHashAlgorithmKECCAK128(
+            randomness_input, CRYPTO_RANDOMBYTES + CRYPTO_SEEDBYTES, HM_BYTES, message, 0, messageLength);
+
+        HashUtils.secureHashAlgorithmKECCAK128(
+            randomness, 0, CRYPTO_SEEDBYTES, randomness_input, 0, CRYPTO_RANDOMBYTES + CRYPTO_SEEDBYTES + HM_BYTES);
+
+
+        QTesla1PPolynomial.poly_uniform(a, privateKey, CRYPTO_SECRETKEYBYTES - 2 * CRYPTO_SEEDBYTES);
+
+        while (true)
+        {
+            sample_y(y, randomness, 0, ++nonce);
+
+            QTesla1PPolynomial.poly_ntt(y_ntt, y);
+            for (k = 0; k < PARAM_K; k++)
+            {
+                QTesla1PPolynomial.poly_mul(v, k * PARAM_N, a, k * PARAM_N, y_ntt);
+            }
+
+            hashFunction(c, 0, v, randomness_input, CRYPTO_RANDOMBYTES + CRYPTO_SEEDBYTES);
+            encodeC(pos_list, sign_list, c, 0);
+
+            QTesla1PPolynomial.sparse_mul8(Sc, privateKey, pos_list, sign_list);
+
+            QTesla1PPolynomial.poly_add(z, y, Sc);
+
+            if (testRejection(z))
+            {
+                continue;
+            }
+
+            for (k = 0; k < PARAM_K; k++)
+            {
+                QTesla1PPolynomial.sparse_mul8(Ec, k * PARAM_N, privateKey, (PARAM_N * (k + 1)), pos_list, sign_list);
+                QTesla1PPolynomial.poly_sub(v, k * PARAM_N, v, k * PARAM_N, Ec, k * PARAM_N);
+                rsp = test_correctness(v, k * PARAM_N);
+                if (rsp)
+                {
+                    break;
+                } // TODO replace with contine outer
+            }
+            if (rsp)
+            {
+                continue;
+            }
+
+
+            encodeSignature(signature, 0, c, 0, z);
+            return 0;
+
+        }
+
+        // return 0;
+    }
+
+
+    static int verifying(
+
+        byte[] message,
+        final byte[] signature, int signatureOffset, int signatureLength,
+        final byte[] publicKey)
+    {
+
+        byte c[] = new byte[CRYPTO_C_BYTES];
+        byte c_sig[] = new byte[CRYPTO_C_BYTES];
+        byte seed[] = new byte[CRYPTO_SEEDBYTES];
+        byte hm[] = new byte[HM_BYTES];
+        int pos_list[] = new int[PARAM_H];
+        short sign_list[] = new short[PARAM_H];
+        int pk_t[] = new int[PARAM_N * PARAM_K];
+        long[] w = new long[PARAM_N * PARAM_K];
+        long[] a = new long[PARAM_N * PARAM_K];
+        long[] Tc = new long[PARAM_N * PARAM_K];
+
+        long[] z = new long[PARAM_N];
+        long[] z_ntt = new long[PARAM_N];
+
+        int k = 0;
+
+        if (signatureLength < CRYPTO_BYTES)
+        {
+            return -1;
+        }
+
+        decodeSignature(c, z, signature, signatureOffset);
+
+        if (testZ(z))
+        {
+            return -2;
+        }
+
+
+        decodePublicKey(pk_t, seed, 0, publicKey);
+        QTesla1PPolynomial.poly_uniform(a, seed, 0);
+        encodeC(pos_list, sign_list, c, 0);
+        QTesla1PPolynomial.poly_ntt(z_ntt, z);
+
+        for (k = 0; k < PARAM_K; k++)
+        {      // Compute w = az - tc
+            QTesla1PPolynomial.sparse_mul32(Tc, k * PARAM_N, pk_t, (k * PARAM_N), pos_list, sign_list);
+            QTesla1PPolynomial.poly_mul(w, k * PARAM_N, a, k * PARAM_N, z_ntt);
+            QTesla1PPolynomial.poly_sub(w, k * PARAM_N, w, k * PARAM_N, Tc, k * PARAM_N);
+        }
+
+        HashUtils.secureHashAlgorithmKECCAK128(
+            hm, 0, HM_BYTES, message, 0, message.length
+        );
+        hashFunction(c_sig, 0, w, hm, 0);
+
+        if (!memoryEqual(c, 0, c_sig, 0, CRYPTO_C_BYTES))
+        {
+            return -3;
+        }
+
+        return 0;
+    }
+
+
+    static void encodePrivateKey(byte[] privateKey, final long[] secretPolynomial, final long[] errorPolynomial, final byte[] seed, int seedOffset)
+    {
+
+        int i, k = 0;
+        int skPtr = 0;
+
+        for (i = 0; i < PARAM_N; i++)
+        {
+            privateKey[skPtr + i] = (byte)secretPolynomial[i];
+        }
+
+        skPtr += PARAM_N;
+        for (k = 0; k < PARAM_K; k++)
+        {
+            for (i = 0; i < PARAM_N; i++)
+            {
+                privateKey[skPtr + (k * PARAM_N + i)] = (byte)errorPolynomial[k * PARAM_N + i];
+                //  System.out.printf("%d,   %x\n", skPtr + (k * PARAM_N + i), privateKey[skPtr + (k * PARAM_N + i)]);
+            }
+        }
+
+        System.arraycopy(seed, seedOffset, privateKey, skPtr + (PARAM_K * PARAM_N), CRYPTO_SEEDBYTES * 2);
+
+    }
+
+
+    static void encodePublicKey(byte[] publicKey, final long[] T, final byte[] seedA, int seedAOffset)
+    {
+
+        int j = 0;
+
+
+        for (int i = 0; i < (PARAM_N * PARAM_K * PARAM_Q_LOG / 32); i += PARAM_Q_LOG)
+        {
+            at(publicKey, i, 0, (int)(T[j] | (T[j + 1] << 29)));
+            at(publicKey, i, 1, (int)((T[j + 1] >> 3) | (T[j + 2] << 26)));
+            at(publicKey, i, 2, (int)((T[j + 2] >> 6) | (T[j + 3] << 23)));
+            at(publicKey, i, 3, (int)((T[j + 3] >> 9) | (T[j + 4] << 20)));
+            at(publicKey, i, 4, (int)((T[j + 4] >> 12) | (T[j + 5] << 17)));
+            at(publicKey, i, 5, (int)((T[j + 5] >> 15) | (T[j + 6] << 14)));
+            at(publicKey, i, 6, (int)((T[j + 6] >> 18) | (T[j + 7] << 11)));
+            at(publicKey, i, 7, (int)((T[j + 7] >> 21) | (T[j + 8] << 8)));
+            at(publicKey, i, 8, (int)((T[j + 8] >> 24) | (T[j + 9] << 5)));
+            at(publicKey, i, 9, (int)((T[j + 9] >> 27) | (T[j + 10] << 2) | (T[j + 11] << 31)));
+            at(publicKey, i, 10, (int)((T[j + 11] >> 1) | (T[j + 12] << 28)));
+            at(publicKey, i, 11, (int)((T[j + 12] >> 4) | (T[j + 13] << 25)));
+            at(publicKey, i, 12, (int)((T[j + 13] >> 7) | (T[j + 14] << 22)));
+            at(publicKey, i, 13, (int)((T[j + 14] >> 10) | (T[j + 15] << 19)));
+            at(publicKey, i, 14, (int)((T[j + 15] >> 13) | (T[j + 16] << 16)));
+            at(publicKey, i, 15, (int)((T[j + 16] >> 16) | (T[j + 17] << 13)));
+            at(publicKey, i, 16, (int)((T[j + 17] >> 19) | (T[j + 18] << 10)));
+            at(publicKey, i, 17, (int)((T[j + 18] >> 22) | (T[j + 19] << 7)));
+            at(publicKey, i, 18, (int)((T[j + 19] >> 25) | (T[j + 20] << 4)));
+            at(publicKey, i, 19, (int)((T[j + 20] >> 28) | (T[j + 21] << 1) | (T[j + 22] << 30)));
+            at(publicKey, i, 20, (int)((T[j + 22] >> 2) | (T[j + 23] << 27)));
+            at(publicKey, i, 21, (int)((T[j + 23] >> 5) | (T[j + 24] << 24)));
+            at(publicKey, i, 22, (int)((T[j + 24] >> 8) | (T[j + 25] << 21)));
+            at(publicKey, i, 23, (int)((T[j + 25] >> 11) | (T[j + 26] << 18)));
+            at(publicKey, i, 24, (int)((T[j + 26] >> 14) | (T[j + 27] << 15)));
+            at(publicKey, i, 25, (int)((T[j + 27] >> 17) | (T[j + 28] << 12)));
+            at(publicKey, i, 26, (int)((T[j + 28] >> 20) | (T[j + 29] << 9)));
+            at(publicKey, i, 27, (int)((T[j + 29] >> 23) | (T[j + 30] << 6)));
+            at(publicKey, i, 28, (int)((T[j + 30] >> 26) | (T[j + 31] << 3)));
+            j += 32;
+        }
+
+        System.arraycopy(seedA, seedAOffset, publicKey, PARAM_N * PARAM_K * PARAM_Q_LOG / 8, CRYPTO_SEEDBYTES);
+
+    }
+
+
+    static void decodePublicKey(int[] publicKey, byte[] seedA, int seedAOffset, final byte[] publicKeyInput)
+    {
+
+        int j = 0;
+        byte[] pt = publicKeyInput;
+        int mask29 = (1 << PARAM_Q_LOG) - 1;
+
+
+        for (int i = 0; i < PARAM_N * PARAM_K; i += 32)
+        {
+            publicKey[i] = at(pt, j, 0) & mask29;
+            publicKey[i + 1] = ((at(pt, j, 0) >>> 29) | (at(pt, j, 1) << 3)) & mask29;
+            publicKey[i + 2] = ((at(pt, j, 1) >>> 26) | (at(pt, j, 2) << 6)) & mask29;
+            publicKey[i + 3] = ((at(pt, j, 2) >>> 23) | (at(pt, j, 3) << 9)) & mask29;
+            publicKey[i + 4] = ((at(pt, j, 3) >>> 20) | (at(pt, j, 4) << 12)) & mask29;
+            publicKey[i + 5] = ((at(pt, j, 4) >>> 17) | (at(pt, j, 5) << 15)) & mask29;
+            publicKey[i + 6] = ((at(pt, j, 5) >>> 14) | (at(pt, j, 6) << 18)) & mask29;
+            publicKey[i + 7] = ((at(pt, j, 6) >>> 11) | (at(pt, j, 7) << 21)) & mask29;
+            publicKey[i + 8] = ((at(pt, j, 7) >>> 8) | (at(pt, j, 8) << 24)) & mask29;
+            publicKey[i + 9] = ((at(pt, j, 8) >>> 5) | (at(pt, j, 9) << 27)) & mask29;
+            publicKey[i + 10] = (at(pt, j, 9) >>> 2) & mask29;
+            publicKey[i + 11] = ((at(pt, j, 9) >>> 31) | (at(pt, j, 10) << 1)) & mask29;
+            publicKey[i + 12] = ((at(pt, j, 10) >>> 28) | (at(pt, j, 11) << 4)) & mask29;
+            publicKey[i + 13] = ((at(pt, j, 11) >>> 25) | (at(pt, j, 12) << 7)) & mask29;
+            publicKey[i + 14] = ((at(pt, j, 12) >>> 22) | (at(pt, j, 13) << 10)) & mask29;
+            publicKey[i + 15] = ((at(pt, j, 13) >>> 19) | (at(pt, j, 14) << 13)) & mask29;
+            publicKey[i + 16] = ((at(pt, j, 14) >>> 16) | (at(pt, j, 15) << 16)) & mask29;
+            publicKey[i + 17] = ((at(pt, j, 15) >>> 13) | (at(pt, j, 16) << 19)) & mask29;
+            publicKey[i + 18] = ((at(pt, j, 16) >>> 10) | (at(pt, j, 17) << 22)) & mask29;
+            publicKey[i + 19] = ((at(pt, j, 17) >>> 7) | (at(pt, j, 18) << 25)) & mask29;
+            publicKey[i + 20] = ((at(pt, j, 18) >>> 4) | (at(pt, j, 19) << 28)) & mask29;
+            publicKey[i + 21] = (at(pt, j, 19) >>> 1) & mask29;
+            publicKey[i + 22] = ((at(pt, j, 19) >>> 30) | (at(pt, j, 20) << 2)) & mask29;
+            publicKey[i + 23] = ((at(pt, j, 20) >>> 27) | (at(pt, j, 21) << 5)) & mask29;
+            publicKey[i + 24] = ((at(pt, j, 21) >>> 24) | (at(pt, j, 22) << 8)) & mask29;
+            publicKey[i + 25] = ((at(pt, j, 22) >>> 21) | (at(pt, j, 23) << 11)) & mask29;
+            publicKey[i + 26] = ((at(pt, j, 23) >>> 18) | (at(pt, j, 24) << 14)) & mask29;
+            publicKey[i + 27] = ((at(pt, j, 24) >>> 15) | (at(pt, j, 25) << 17)) & mask29;
+            publicKey[i + 28] = ((at(pt, j, 25) >>> 12) | (at(pt, j, 26) << 20)) & mask29;
+            publicKey[i + 29] = ((at(pt, j, 26) >>> 9) | (at(pt, j, 27) << 23)) & mask29;
+            publicKey[i + 30] = ((at(pt, j, 27) >>> 6) | (at(pt, j, 28) << 26)) & mask29;
+            publicKey[i + 31] = at(pt, j, 28) >>> 3;
+            j += 29;
+        }
+
+
+        System.arraycopy(publicKeyInput, PARAM_N * PARAM_K * PARAM_Q_LOG / 8, seedA, seedAOffset, CRYPTO_SEEDBYTES);
+
+    }
+
+    private static boolean testZ(long[] Z)
+    {
+        // Returns false if valid, otherwise outputs 1 if invalid (rejected)
+
+        for (int i = 0; i < PARAM_N; i++)
+        {
+
+            if ((Z[i] < -(PARAM_B - PARAM_S)) || (Z[i] > PARAM_B - PARAM_S))
+            {
+
+                return true;
+
+            }
+
+        }
+
+        return false;
+
+    }
+
+
+    private static final int maskb1 = ((1 << (PARAM_B_BITS + 1)) - 1);
+
+    static void encodeSignature(byte[] signature, int signatureOffset, byte[] C, int cOffset, long[] Z)
+    {
+        int j = 0;
+
+        for (int i = 0; i < (PARAM_N * (PARAM_B_BITS + 1) / 32); i += 10)
+        {
+            at(signature, i, 0, (int)((Z[j] & ((1 << 20) - 1)) | (Z[j + 1] << 20)));
+            at(signature, i, 1, (int)(((Z[j + 1] >>> 12) & ((1 << 8) - 1)) | ((Z[j + 2] & maskb1) << 8) | (Z[j + 3] << 28)));
+            at(signature, i, 2, (int)(((Z[j + 3] >>> 4) & ((1 << 16) - 1)) | (Z[j + 4] << 16)));
+            at(signature, i, 3, (int)(((Z[j + 4] >>> 16) & ((1 << 4) - 1)) | ((Z[j + 5] & maskb1) << 4) | (Z[j + 6] << 24)));
+            at(signature, i, 4, (int)(((Z[j + 6] >>> 8) & ((1 << 12) - 1)) | (Z[j + 7] << 12)));
+            at(signature, i, 5, (int)((Z[j + 8] & ((1 << 20) - 1)) | (Z[j + 9] << 20)));
+            at(signature, i, 6, (int)(((Z[j + 9] >>> 12) & ((1 << 8) - 1)) | ((Z[j + 10] & maskb1) << 8) | (Z[j + 11] << 28)));
+            at(signature, i, 7, (int)(((Z[j + 11] >>> 4) & ((1 << 16) - 1)) | (Z[j + 12] << 16)));
+            at(signature, i, 8, (int)(((Z[j + 12] >>> 16) & ((1 << 4) - 1)) | ((Z[j + 13] & maskb1) << 4) | (Z[j + 14] << 24)));
+            at(signature, i, 9, (int)(((Z[j + 14] >>> 8) & ((1 << 12) - 1)) | (Z[j + 15] << 12)));
+            j += 16;
+        }
+
+        System.arraycopy(C, cOffset, signature, signatureOffset + PARAM_N * (PARAM_B_BITS + 1) / 8, CRYPTO_C_BYTES);
+
+    }
+
+
+    static void decodeSignature(byte[] C, long[] Z, final byte[] signature, int signatureOffset)
+    {
+
+        int j = 0;
+        for (int i = 0; i < PARAM_N; i += 16)
+        {
+            Z[i] = (at(signature, j, 0) << 12) >> 12;
+            Z[i + 1] = (at(signature, j, 0) >>> 20) | ((at(signature, j, 1) << 24) >> 12);
+            Z[i + 2] = ((at(signature, j, 1) << 4) >> 12);
+            Z[i + 3] = (at(signature, j, 1) >>> 28) | ((at(signature, j, 2) << 16) >> 12);
+            Z[i + 4] = (at(signature, j, 2) >>> 16) | ((at(signature, j, 3) << 28) >> 12);
+            Z[i + 5] = (at(signature, j, 3) << 8) >> 12;
+            Z[i + 6] = (at(signature, j, 3) >>> 24) | ((at(signature, j, 4) << 20) >> 12);
+            Z[i + 7] = at(signature, j, 4) >> 12;
+            Z[i + 8] = (at(signature, j, 5) << 12) >> 12;
+            Z[i + 9] = (at(signature, j, 5) >>> 20) | ((at(signature, j, 6) << 24) >> 12);
+            Z[i + 10] = (at(signature, j, 6) << 4) >> 12;
+            Z[i + 11] = (at(signature, j, 6) >>> 28) | ((at(signature, j, 7) << 16) >> 12);
+            Z[i + 12] = (at(signature, j, 7) >>> 16) | ((at(signature, j, 8) << 28) >> 12);
+            Z[i + 13] = (at(signature, j, 8) << 8) >> 12;
+            Z[i + 14] = (at(signature, j, 8) >>> 24) | ((at(signature, j, 9) << 20) >> 12);
+            Z[i + 15] = (at(signature, j, 9) >> 12);
+            j += 10;
+        }
+        System.arraycopy(signature, signatureOffset + PARAM_N * (PARAM_B_BITS + 1) / 8, C, 0, CRYPTO_C_BYTES);
+
+
+    }
+
+
+    static void encodeC(int[] positionList, short[] signList, byte[] output, int outputOffset)
+    {
+
+        int count = 0;
+        int position;
+        short domainSeparator = 0;
+        short[] C = new short[PARAM_N];
+        byte[] randomness = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE];
+
+        /* Use the Hash Value as Key to Generate Some Randomness */
+        HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+            randomness, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE,
+            domainSeparator++,
+            output, outputOffset, CRYPTO_RANDOMBYTES
+        );
+
+        /* Use Rejection Sampling to Determine Positions to be Set in the New Vector */
+        Arrays.fill(C, (short)0);
+
+        /* Sample A Unique Position k times.
+         * Use Two Bytes
+         */
+        for (int i = 0; i < PARAM_H; )
+        {
+
+            if (count > HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE - 3)
+            {
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                    randomness, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE,
+                    domainSeparator++,
+                    output, outputOffset, CRYPTO_RANDOMBYTES
+                );
+
+                count = 0;
+
+            }
+
+            position = (randomness[count] << 8) | (randomness[count + 1] & 0xFF);
+            position &= (PARAM_N - 1);
+
+            /* Position is between [0, n - 1] and Has not Been Set Yet
+             * Determine Signature
+             */
+            if (C[position] == 0)
+            {
+
+                if ((randomness[count + 2] & 1) == 1)
+                {
+
+                    C[position] = -1;
+
+                }
+                else
+                {
+
+                    C[position] = 1;
+
+                }
+
+                positionList[i] = position;
+                signList[i] = C[position];
+                i++;
+
+            }
+
+            count += 3;
+
+        }
+
+    }
+
+
+    private static void hashFunction(byte[] output, int outputOffset, long[] v, final byte[] message, int messageOffset) //, int n, int d, int q)
+    {
+
+        int mask;
+        int cL;
+
+        byte[] T = new byte[PARAM_K * PARAM_N + HM_BYTES];
+
+        for (int k = 0; k < PARAM_K; k++)
+        {
+            int index = k * PARAM_N;
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                int temp = (int)v[index];
+                // If v[i] > PARAM_Q/2 then v[i] -= PARAM_Q
+                mask = (PARAM_Q / 2 - temp) >> (RADIX32 - 1);
+                temp = ((temp - PARAM_Q) & mask) | (temp & ~mask);
+
+                cL = temp & ((1 << PARAM_D) - 1);
+                // If cL > 2^(d-1) then cL -= 2^d
+                mask = ((1 << (PARAM_D - 1)) - cL) >> (RADIX32 - 1);
+                cL = ((cL - (1 << PARAM_D)) & mask) | (cL & ~mask);
+                T[index++] = (byte)((temp - cL) >> PARAM_D);
+            }
+        }
+        System.arraycopy(message, messageOffset, T, PARAM_N * PARAM_K, HM_BYTES);
+        HashUtils.secureHashAlgorithmKECCAK128(output, outputOffset, CRYPTO_C_BYTES, T, 0, PARAM_K * PARAM_N + HM_BYTES);
+
+    }
+
+
+    static int lE24BitToInt(byte[] bs, int off)
+    {
+        int n = bs[off] & 0xff;
+        n |= (bs[++off] & 0xff) << 8;
+        n |= (bs[++off] & 0xff) << 16;
+        return n;
+    }
+
+
+    private static int NBLOCKS_SHAKE = HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE / (((PARAM_B_BITS + 1) + 7) / 8);
+    private static int BPLUS1BYTES = ((PARAM_B_BITS + 1) + 7) / 8;
+
+
+    static void sample_y(long[] y, byte[] seed, int seedOffset, int nonce)
+    { // Sample polynomial y, such that each coefficient is in the range [-B,B]
+        int i = 0, pos = 0, nblocks = PARAM_N;
+        byte buf[] = new byte[PARAM_N * BPLUS1BYTES+1];
+        int nbytes = BPLUS1BYTES;
+        short dmsp = (short)(nonce << 8);
+
+        HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+            buf, 0, PARAM_N * nbytes, dmsp++, seed, seedOffset, CRYPTO_RANDOMBYTES
+        );
+
+
+        while (i < PARAM_N)
+        {
+            if (pos >= nblocks * nbytes)
+            {
+                nblocks = NBLOCKS_SHAKE;
+                HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                    buf, 0, PARAM_N * nbytes, dmsp++, seed, seedOffset, CRYPTO_RANDOMBYTES
+                );
+                pos = 0;
+            }
+            y[i] = lE24BitToInt(buf, pos) & ((1 << (PARAM_B_BITS + 1)) - 1);
+            y[i] -= PARAM_B;
+            if (y[i] != (1 << PARAM_B_BITS))
+            {
+                i++;
+            }
+            pos += nbytes;
+        }
+    }
+
+
+    private static void at(byte[] bs, int base, int index, int value)
+    {
+        com.fr.third.org.bouncycastle.util.Pack.intToLittleEndian(value, bs, (base * 4) + (index * 4));
+    }
+
+    private static int at(byte[] bs, int base, int index)
+    {
+        int off = (base * 4) + (index * 4);
+
+        int n = bs[off] & 0xff;
+        n |= (bs[++off] & 0xff) << 8;
+        n |= (bs[++off] & 0xff) << 16;
+        n |= bs[++off] << 24;
+        return n;
+    }
+
+
+    static boolean test_correctness(long[] v, int vpos)
+    { // Check bounds for w = v - ec during signature verification. Returns 0 if valid, otherwise outputs 1 if invalid (rejected).
+        // This function leaks the position of the coefficient that fails the test (but this is independent of the secret data).
+        // It does not leak the sign of the coefficients.
+        int mask, left, val;
+        int t0, t1;
+
+        for (int i = 0; i < PARAM_N; i++)
+        {
+            // If v[i] > PARAM_Q/2 then v[i] -= PARAM_Q
+            mask = (int)(PARAM_Q / 2 - v[vpos + i]) >> (RADIX32 - 1);
+            val = (int)(((v[vpos + i] - PARAM_Q) & mask) | (v[vpos + i] & ~mask));
+            // If (Abs(val) < PARAM_Q/2 - PARAM_E) then t0 = 0, else t0 = 1
+            t0 = (int)(~(absolute(val) - (PARAM_Q / 2 - PARAM_E))) >>> (RADIX32 - 1);
+
+            left = val;
+            val = (val + (1 << (PARAM_D - 1)) - 1) >> PARAM_D;
+            val = left - (val << PARAM_D);
+            // If (Abs(val) < (1<<(PARAM_D-1))-PARAM_E) then t1 = 0, else t1 = 1
+            t1 = (int)(~(absolute(val) - ((1 << (PARAM_D - 1)) - PARAM_E))) >>> (RADIX32 - 1);
+
+            if ((t0 | t1) == 1)  // Returns 1 if any of the two tests failed
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    private static boolean testRejection(long[] Z) //, int n, int b, int u)
+    {
+
+        int valid = 0;
+
+        for (int i = 0; i < PARAM_N; i++)
+        {
+            valid |= (PARAM_B - PARAM_S) - absolute(Z[i]);
+
+        }
+
+        return (valid >>> 31) > 0;
+
+    }
+
+    private static int absolute(int value)
+    {
+
+        return ((value >> RADIX32 - 1) ^ value) - (value >> RADIX32 - 1);
+
+    }
+
+    private static long absolute(long value)
+    {
+
+        return ((value >> 63) ^ value) - (value >> 63);
+
+    }
+
+
+    private static boolean checkPolynomial(long[] polynomial, int polyOffset, int bound)
+    {
+
+        int i, j, sum = 0, limit = PARAM_N;
+        long temp, mask;
+        long[] list = new long[PARAM_N];
+
+        for (j = 0; j < PARAM_N; j++)
+        {
+            list[j] = absolute(polynomial[polyOffset + j]);
+        }
+
+        for (j = 0; j < PARAM_H; j++)
+        {
+            for (i = 0; i < limit - 1; i++)
+            {
+                // If list[i+1] > list[i] then exchange contents
+                mask = (list[i + 1] - list[i]) >> (RADIX32 - 1);
+                temp = (list[i + 1] & mask) | (list[i] & ~mask);
+                list[i + 1] = (list[i] & mask) | (list[i + 1] & ~mask);
+                list[i] = temp;
+            }
+            sum += list[limit - 1];
+            limit -= 1;
+        }
+
+        return (sum > bound);
+    }
+
+    static boolean memoryEqual(byte[] left, int leftOffset, byte[] right, int rightOffset, int length)
+    {
+
+        if ((leftOffset + length <= left.length) && (rightOffset + length <= right.length))
+        {
+
+            for (int i = 0; i < length; i++)
+            {
+
+                if (left[leftOffset + i] != right[rightOffset + i])
+                {
+
+                    return false;
+
+                }
+
+            }
+
+            return true;
+
+        }
+        else
+        {
+
+            return false;
+
+        }
+
+    }
+
+
+    // End of outer.
+
+    static class Gaussian
+    {
+
+        private static final int CDT_ROWS = 78;
+        private static final int CDT_COLS = 2;
+        private static final int CHUNK_SIZE = 512;
+
+        private static final long[] cdt_v = new long[]{
+            0x00000000L, 0x00000000L, // 0
+            0x0601F22AL, 0x280663D4L, // 1
+            0x11F09FFAL, 0x162FE23DL, // 2
+            0x1DA089E9L, 0x437226E8L, // 3
+            0x28EAB25DL, 0x04C51FE2L, // 4
+            0x33AC2F26L, 0x14FDBA70L, // 5
+            0x3DC767DCL, 0x4565C960L, // 6
+            0x4724FC62L, 0x3342C78AL, // 7
+            0x4FB448F4L, 0x5229D06DL, // 8
+            0x576B8599L, 0x7423407FL, // 9
+            0x5E4786DAL, 0x3210BAF7L, // 10
+            0x644B2C92L, 0x431B3947L, // 11
+            0x697E90CEL, 0x77C362C4L, // 12
+            0x6DEE0B96L, 0x2798C9CEL, // 13
+            0x71A92144L, 0x5765FCE4L, // 14
+            0x74C16FD5L, 0x1E2A0990L, // 15
+            0x7749AC92L, 0x0DF36EEBL, // 16
+            0x7954BFA4L, 0x28079289L, // 17
+            0x7AF5067AL, 0x2EDC2050L, // 18
+            0x7C3BC17CL, 0x123D5E7BL, // 19
+            0x7D38AD76L, 0x2A9381D9L, // 20
+            0x7DF9C5DFL, 0x0E868CA7L, // 21
+            0x7E8B2ABAL, 0x18E5C811L, // 22
+            0x7EF7237CL, 0x00908272L, // 23
+            0x7F4637C5L, 0x6DBA5126L, // 24
+            0x7F7F5707L, 0x4A52EDEBL, // 25
+            0x7FA808CCL, 0x23290599L, // 26
+            0x7FC4A083L, 0x69BDF2D5L, // 27
+            0x7FD870CAL, 0x42275558L, // 28
+            0x7FE5FB5DL, 0x3EF82C1BL, // 29
+            0x7FEF1BFAL, 0x6C03A362L, // 30
+            0x7FF52D4EL, 0x316C2C8CL, // 31
+            0x7FF927BAL, 0x12AE54AFL, // 32
+            0x7FFBBA43L, 0x749CC0E2L, // 33
+            0x7FFD5E3DL, 0x4524AD91L, // 34
+            0x7FFE6664L, 0x535785B5L, // 35
+            0x7FFF0A41L, 0x0B291681L, // 36
+            0x7FFF6E81L, 0x132C3D6FL, // 37
+            0x7FFFAAFEL, 0x4DBC6BEDL, // 38
+            0x7FFFCEFDL, 0x7A1E2D14L, // 39
+            0x7FFFE41EL, 0x4C6EC115L, // 40
+            0x7FFFF059L, 0x319503C8L, // 41
+            0x7FFFF754L, 0x5DDD0D40L, // 42
+            0x7FFFFB43L, 0x0B9E9823L, // 43
+            0x7FFFFD71L, 0x76B81AE1L, // 44
+            0x7FFFFEA3L, 0x7E66A1ECL, // 45
+            0x7FFFFF49L, 0x26F6E191L, // 46
+            0x7FFFFFA1L, 0x2FA31694L, // 47
+            0x7FFFFFCFL, 0x5247BEC9L, // 48
+            0x7FFFFFE7L, 0x4F4127C7L, // 49
+            0x7FFFFFF3L, 0x6FAA69FDL, // 50
+            0x7FFFFFFAL, 0x0630D073L, // 51
+            0x7FFFFFFDL, 0x0F2957BBL, // 52
+            0x7FFFFFFEL, 0x4FD29432L, // 53
+            0x7FFFFFFFL, 0x2CFAD60DL, // 54
+            0x7FFFFFFFL, 0x5967A930L, // 55
+            0x7FFFFFFFL, 0x6E4C9DFFL, // 56
+            0x7FFFFFFFL, 0x77FDCCC8L, // 57
+            0x7FFFFFFFL, 0x7C6CE89EL, // 58
+            0x7FFFFFFFL, 0x7E6D116FL, // 59
+            0x7FFFFFFFL, 0x7F50FA31L, // 60
+            0x7FFFFFFFL, 0x7FB50089L, // 61
+            0x7FFFFFFFL, 0x7FE04C2DL, // 62
+            0x7FFFFFFFL, 0x7FF2C7C1L, // 63
+            0x7FFFFFFFL, 0x7FFA8FE3L, // 64
+            0x7FFFFFFFL, 0x7FFDCB1BL, // 65
+            0x7FFFFFFFL, 0x7FFF1DE2L, // 66
+            0x7FFFFFFFL, 0x7FFFA6B7L, // 67
+            0x7FFFFFFFL, 0x7FFFDD39L, // 68
+            0x7FFFFFFFL, 0x7FFFF2A3L, // 69
+            0x7FFFFFFFL, 0x7FFFFAEFL, // 70
+            0x7FFFFFFFL, 0x7FFFFE1BL, // 71
+            0x7FFFFFFFL, 0x7FFFFF4DL, // 72
+            0x7FFFFFFFL, 0x7FFFFFBFL, // 73
+            0x7FFFFFFFL, 0x7FFFFFE9L, // 74
+            0x7FFFFFFFL, 0x7FFFFFF8L, // 75
+            0x7FFFFFFFL, 0x7FFFFFFDL, // 76
+            0x7FFFFFFFL, 0x7FFFFFFFL, // 77
+        };
+
+
+
+
+
+        static void sample_gauss_polly(int nonce, byte[] seed, int seedOffset, long[] poly, int polyOffset)
+        {
+            int dmsp = nonce << 8;
+
+            byte samp[] = new byte[CHUNK_SIZE*CDT_COLS * 4]; // This is int32_t in C, we will treat it as byte[] in java
+            int c[] = new int[CDT_COLS];
+            int borrow, sign;
+            int mask = (-1) >>> 1;
+
+            for (int chunk = 0; chunk < PARAM_N; chunk += CHUNK_SIZE)
+            {
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                    samp, 0, CHUNK_SIZE * CDT_COLS * 4, (short)dmsp++, seed, seedOffset, CRYPTO_SEEDBYTES);
+
+                for (int i = 0; i < CHUNK_SIZE; i++) {
+                    poly[ polyOffset+ chunk+i] = 0;
+                    for (int j = 1; j < CDT_ROWS; j++) {
+                        borrow = 0;
+                        for (int k = CDT_COLS-1; k >= 0; k--) {
+                            c[k] = (int)(( at(samp, 0,i*CDT_COLS+k) & mask) - (cdt_v[j*CDT_COLS+k] + borrow));
+                            borrow = c[k] >> (RADIX32-1);
+                        }
+                        poly[polyOffset+chunk+i] += ~borrow & 1;
+                    }
+                    sign =  at(samp,0,i*CDT_COLS) >> (RADIX32-1);
+                    poly[polyOffset+chunk+i] = (sign & -poly[polyOffset+chunk+i]) | (~sign & poly[polyOffset+chunk+i]);
+                }
+
+            }
+
+        }
+
+    }
+
+
+    static class QTesla1PPolynomial
+    {
+
+
+        private static final long[] zeta = new long[]{
+            184007114, 341297933, 172127038, 306069179, 260374244, 269720605, 20436325, 2157599, 36206659, 61987110, 112759694, 92762708, 278504038, 139026960, 183642748, 298230187,
+            37043356, 230730845, 107820937, 97015745, 156688276, 38891102, 170244636, 259345227, 170077366, 141586883, 100118513, 328793523, 289946488, 263574185, 132014089, 14516260,
+            87424978, 192691578, 190961717, 262687761, 333967048, 12957952, 326574509, 273585413, 151922543, 195893203, 261889302, 120488377, 169571794, 44896463, 128576039, 68257019,
+            20594664, 44164717, 36060712, 256009818, 172063915, 211967562, 135533785, 104908181, 203788155, 52968398, 123297488, 44711423, 329131026, 245797804, 220629853, 200431766,
+            92905498, 215466666, 227373088, 120513729, 274875394, 236766448, 84216704, 97363940, 224003799, 167341181, 333540791, 225846253, 290150331, 137934911, 101127339, 95054535,
+            7072757, 58600117, 264117725, 207480694, 268253444, 292044590, 166300682, 256585624, 133577520, 119707476, 58169614, 188489502, 184778640, 156039906, 286669262, 112658784,
+            89254003, 266568758, 290599527, 80715937, 180664712, 225980378, 103512701, 304604206, 327443646, 92082345, 296093912, 144843084, 309484036, 329737605, 141656867, 264967053,
+            227847682, 328674715, 208663554, 309005608, 315790590, 182996330, 333212133, 203436199, 13052895, 23858345, 173478900, 97132319, 57066271, 70747422, 202106993, 309870606,
+            56390934, 336126437, 189147643, 219236223, 293351741, 305570320, 18378834, 336914091, 59506067, 277923611, 217306643, 129369847, 308113789, 56954705, 190254906, 199465001,
+            119331054, 143640880, 17590914, 309468163, 172483421, 153376031, 58864560, 70957183, 237697179, 116097341, 62196815, 80692520, 310642530, 328595292, 12121494, 71200620,
+            200016287, 235006678, 21821056, 102505389, 183332133, 59734849, 283127491, 313646880, 30359439, 163176989, 50717815, 100183661, 322975554, 92821217, 283119421, 34453836,
+            303758926, 89460722, 147514506, 175603941, 76494101, 220775631, 304963431, 38821441, 217317485, 301302769, 328727631, 101476595, 270750726, 253708871, 176201368, 324059659,
+            114780906, 304156831, 273708648, 144095014, 263545324, 179240984, 187811389, 244886526, 202581571, 209325648, 117231636, 182195945, 217965216, 252295904, 332003328, 46153749,
+            334740528, 62618402, 301165510, 283016648, 212224416, 234984074, 107363471, 125430881, 172821269, 270409387, 156316970, 311644197, 50537885, 248376507, 154072039, 331539029,
+            48454192, 267029920, 225963915, 16753350, 76840946, 226444843, 108106635, 154887261, 326283837, 101291223, 204194230, 54014060, 104099734, 104245071, 260949411, 333985274,
+            291682234, 328313139, 29607387, 106291750, 162553334, 275058303, 64179189, 263147140, 15599810, 325103190, 137254480, 66787068, 4755224, 308520011, 181897417, 325162685,
+            221099032, 131741505, 147534370, 131533267, 144073688, 166398146, 155829711, 252509898, 251605008, 323547097, 216038649, 232629333, 95137254, 287931575, 235583527, 32386598,
+            76722491, 60825791, 138354268, 400761, 51907675, 197369064, 319840588, 98618414, 84343982, 108113946, 314679670, 134518178, 64988900, 4333172, 295712261, 200707216,
+            147647414, 318013383, 77682006, 92518996, 42154619, 87464521, 285037574, 332936592, 62635246, 5534097, 308862707, 91097989, 269726589, 273280832, 251670430, 95492698,
+            21676891, 182964692, 177187742, 294825274, 85128609, 273594538, 93115857, 116308166, 312212122, 18665807, 32192823, 313249299, 98777368, 273984239, 312125377, 205655336,
+            264861277, 178920022, 341054719, 232663249, 173564046, 176591124, 157537342, 305058098, 277279130, 170028356, 228573747, 31628995, 175280663, 37304323, 122111670, 210658936,
+            175704183, 314649282, 325535066, 266783938, 301319742, 327923297, 279787306, 304633001, 304153402, 292839078, 147442886, 94150133, 40461238, 221384781, 269671052, 265445273,
+            208370149, 160863546, 287765159, 339146643, 129600429, 96192870, 113146118, 95879915, 216708053, 285201955, 67756451, 79028039, 309141895, 138447809, 212246614, 12641916,
+            243544995, 33459809, 76979779, 71155723, 152521243, 200750888, 36425947, 339074467, 319204591, 188312744, 266105966, 280016981, 183723313, 238915015, 23277613, 160934729,
+            200611286, 163282810, 297928823, 226921588, 86839172, 145317111, 202226936, 51887320, 318474782, 282270658, 221219795, 207597867, 132089009, 334627662, 163952597, 67529059,
+            173759630, 234865017, 255217646, 277806158, 61964704, 216678166, 96126463, 39218331, 70028373, 4899005, 238135514, 242700690, 284680271, 81041980, 332906491, 463527,
+            299280916, 204600651, 149654879, 222229829, 26825157, 81825189, 127990873, 200962599, 16149163, 108812393, 217708971, 152638110, 28735779, 5272794, 19720409, 231726324,
+            49854178, 118319174, 185669526, 223407181, 243138094, 259020958, 308825615, 164156486, 341391280, 192526841, 97036052, 279986894, 20263748, 32228956, 43816679, 343421811,
+            124320208, 3484106, 31711063, 147679160, 195369505, 54243678, 279088595, 149119313, 301997352, 244557309, 19700779, 138872683, 230523717, 113507709, 135291486, 313025300,
+            254384479, 219815764, 253574481, 220646316, 124744817, 123915741, 325760383, 123516396, 138140410, 154060994, 314730104, 57286356, 222353426, 76630003, 145380041, 52039855,
+            229881219, 332902036, 152308429, 95071889, 124799350, 270141530, 47897266, 119620601, 133269057, 138561303, 341820265, 66049665, 273409631, 304306012, 212490958, 210388603,
+            277413768, 280793261, 223131872, 162407285, 44911970, 316685837, 298709373, 252812339, 230786851, 230319350, 56863422, 341141914, 177295413, 248222411, 215148650, 97970603,
+            291678055, 161911155, 339645428, 206445182, 31895080, 279676698, 78257775, 268845232, 92545841, 336725589, 47384597, 62216335, 82290365, 89893410, 266117967, 791867,
+            28042243, 110563426, 183316855, 281174508, 166338432, 86326996, 261473803, 164647535, 84749290, 157518777, 214336587, 72257047, 13358702, 229010735, 204196474, 179927635,
+            21786785, 330554989, 164559635, 144505300, 280425045, 324057501, 268227440, 323362437, 26891539, 228523003, 166709094, 61174973, 13532911, 42168701, 133044957, 158219357,
+            220115616, 15174468, 281706353, 283813987, 263212325, 289818392, 247170937, 276072317, 197581495, 33713097, 181695825, 96829354, 32991226, 228583784, 4040287, 65188717,
+            258204083, 96366799, 176298395, 341574369, 306098123, 218746932, 29191888, 311810435, 305844323, 31614267, 28130094, 72716426, 38568041, 197579396, 14876445, 228525674,
+            294569685, 2451649, 165929882, 112195415, 204786047, 138216235, 3438132, 126150615, 59754608, 158965324, 268160978, 266231264, 244422459, 306155336, 218178824, 301806695,
+            208837335, 212153467, 209725081, 269355286, 295716530, 13980580, 264284060, 301901789, 275319045, 107139083, 4006959, 143908623, 139848274, 25357089, 21607040, 340818603,
+            91260932, 198869267, 45119941, 224113252, 269556513, 42857483, 268925602, 188501450, 235382337, 324688793, 113056679, 177232352, 98280013, 117743899, 87369665, 330110286,
+            310895756, 268425063, 27568325, 266303142, 181405304, 65876631, 246283438, 127636847, 16153922, 210256884, 9257227, 147272724, 235571791, 340876897, 31558760, 224463520,
+            229909008, 40943950, 263351999, 14865952, 27279162, 51980445, 99553161, 108121152, 145230283, 217402431, 84060866, 190168688, 46894008, 205718237, 296935065, 331646198,
+            59709076, 265829428, 214503586, 310273189, 86051634, 247210969, 275872780, 55395653, 302717617, 155583500, 207999042, 293597246, 305796948, 139332832, 198434142, 104197059,
+            320317582, 101819543, 70813687, 43594385, 241913829, 210308279, 298735610, 151599086, 92093482, 24654121, 52528801, 134711941, 324580593, 293101038, 121757877, 323940193,
+            276114751, 33522997, 218880483, 46953248, 33126382, 294367143, 161595040, 208968904, 129221110, 323693686, 234366848, 50155901, 123936119, 72127416, 34243899, 171824126,
+            26019236, 93997235, 28452989, 24219933, 188331672, 181161011, 146526219, 186502916, 258266311, 207146754, 206589869, 189836867, 107762500, 129011227, 222324073, 331319091,
+            36618753, 141615400, 273319528, 246222615, 156139193, 290104141, 154851520, 310226922, 60187406, 73704819, 225899604, 87931539, 142487643, 152682959, 45891249, 212048348,
+            148547910, 207745063, 4405848, 179269204, 216233362, 230307487, 303352796, 41616117, 47140231, 13452075, 94626849, 48892822, 78453712, 214721933, 300785835, 1512599,
+            173577933, 163255132, 239883248, 205714288, 306118903, 106953300, 150085654, 77068348, 246390345, 199698311, 280165539, 256497526, 194381508, 78125966, 168327358, 180735395,
+            145983352, 243342736, 198463602, 83165996, 286431792, 22885329, 271516106, 66137359, 243561376, 324886778, 149497212, 24531379, 32857894, 62778029, 56960216, 224996784,
+            129315394, 81068505, 277744916, 215817366, 117205172, 195090165, 287841567, 57750901, 162987791, 259309908, 135370005, 194853269, 236792732, 219249166, 42349628, 27805769,
+            186263338, 310699018, 6491000, 228545163, 315890485, 22219119, 144392189, 15505150, 87848372, 155973124, 20446561, 177725890, 226669021, 205315635, 269580641, 133696452,
+            189388357, 314652032, 317225560, 304194584, 157633737, 298144493, 185785271, 337434647, 559796, 4438732, 249110619, 184824722, 221490126, 205632858, 172362641, 176702767,
+            276712118, 296075254, 111221225, 259809961, 15438443, 198021462, 134378223, 162261445, 170746654, 256890644, 125206341, 307078324, 279553989, 170124925, 296845387, 188226544,
+            295437875, 315053523, 172025817, 279046062, 189967278, 158662482, 192989875, 326540363, 135446089, 98631439, 257379933, 325004289, 26554274, 62190249, 228828648, 274361329,
+            18518762, 184854759, 210189061, 186836398, 230859454, 206912014, 201250021, 276332768, 119984643, 91358832, 325377399, 69085488, 307352479, 308876137, 208756649, 32865966,
+            152976045, 207821125, 66426662, 67585526, 118828370, 3107192, 322037257, 146029104, 106553806, 266958791, 89567376, 153815988, 90786397, 271042585, 203781777, 169087756,
+            315867500, 306916544, 7528726, 327732739, 227901532, 2263402, 14357894, 269740764, 322090105, 59838559, 298337502, 292797139, 337635349, 66476915, 75612762, 328089387,
+            155232910, 87069405, 36163560, 273715413, 321325749, 218096743, 308178877, 21861281, 180676741, 135208372, 119891712, 122406065, 267537516, 341350322, 87789083, 196340943,
+            217070591, 83564209, 159382818, 253921239, 184673854, 213569600, 194031064, 35973794, 18071215, 250854127, 115090766, 147707843, 330337973, 266187164, 27853295, 296801215,
+            254949704, 43331190, 73930201, 35703461, 119780800, 216998106, 12687572, 250863345, 243908221, 330555990, 296216993, 202100577, 111307303, 151049872, 103451600, 237710099,
+            78658022, 121490075, 134292528, 88277916, 177315676, 186629690, 77848818, 211822377, 145696683, 289190386, 274721999, 328391282, 218772820, 91324151, 321725584, 277577004,
+            65732866, 275538085, 144429136, 204062923, 177280727, 214204692, 264758257, 169151951, 335535576, 334002493, 281131703, 305997258, 310527888, 136973519, 216764406, 235954329,
+            254049694, 285174861, 264316834, 11792643, 149333889, 214699018, 261331547, 317320791, 24527858, 118790777, 264146824, 174296812, 332779737, 94199786, 288227027, 172048372,
+        };
+
+        private static final long[] zetainv = new long[]{
+            55349550, 249376791, 10796840, 169279765, 79429753, 224785800, 319048719, 26255786, 82245030, 128877559, 194242688, 331783934, 79259743, 58401716, 89526883, 107622248,
+            126812171, 206603058, 33048689, 37579319, 62444874, 9574084, 8041001, 174424626, 78818320, 129371885, 166295850, 139513654, 199147441, 68038492, 277843711, 65999573,
+            21850993, 252252426, 124803757, 15185295, 68854578, 54386191, 197879894, 131754200, 265727759, 156946887, 166260901, 255298661, 209284049, 222086502, 264918555, 105866478,
+            240124977, 192526705, 232269274, 141476000, 47359584, 13020587, 99668356, 92713232, 330889005, 126578471, 223795777, 307873116, 269646376, 300245387, 88626873, 46775362,
+            315723282, 77389413, 13238604, 195868734, 228485811, 92722450, 325505362, 307602783, 149545513, 130006977, 158902723, 89655338, 184193759, 260012368, 126505986, 147235634,
+            255787494, 2226255, 76039061, 221170512, 223684865, 208368205, 162899836, 321715296, 35397700, 125479834, 22250828, 69861164, 307413017, 256507172, 188343667, 15487190,
+            267963815, 277099662, 5941228, 50779438, 45239075, 283738018, 21486472, 73835813, 329218683, 341313175, 115675045, 15843838, 336047851, 36660033, 27709077, 174488821,
+            139794800, 72533992, 252790180, 189760589, 254009201, 76617786, 237022771, 197547473, 21539320, 340469385, 224748207, 275991051, 277149915, 135755452, 190600532, 310710611,
+            134819928, 34700440, 36224098, 274491089, 18199178, 252217745, 223591934, 67243809, 142326556, 136664563, 112717123, 156740179, 133387516, 158721818, 325057815, 69215248,
+            114747929, 281386328, 317022303, 18572288, 86196644, 244945138, 208130488, 17036214, 150586702, 184914095, 153609299, 64530515, 171550760, 28523054, 48138702, 155350033,
+            46731190, 173451652, 64022588, 36498253, 218370236, 86685933, 172829923, 181315132, 209198354, 145555115, 328138134, 83766616, 232355352, 47501323, 66864459, 166873810,
+            171213936, 137943719, 122086451, 158751855, 94465958, 339137845, 343016781, 6141930, 157791306, 45432084, 185942840, 39381993, 26351017, 28924545, 154188220, 209880125,
+            73995936, 138260942, 116907556, 165850687, 323130016, 187603453, 255728205, 328071427, 199184388, 321357458, 27686092, 115031414, 337085577, 32877559, 157313239, 315770808,
+            301226949, 124327411, 106783845, 148723308, 208206572, 84266669, 180588786, 285825676, 55735010, 148486412, 226371405, 127759211, 65831661, 262508072, 214261183, 118579793,
+            286616361, 280798548, 310718683, 319045198, 194079365, 18689799, 100015201, 277439218, 72060471, 320691248, 57144785, 260410581, 145112975, 100233841, 197593225, 162841182,
+            175249219, 265450611, 149195069, 87079051, 63411038, 143878266, 97186232, 266508229, 193490923, 236623277, 37457674, 137862289, 103693329, 180321445, 169998644, 342063978,
+            42790742, 128854644, 265122865, 294683755, 248949728, 330124502, 296436346, 301960460, 40223781, 113269090, 127343215, 164307373, 339170729, 135831514, 195028667, 131528229,
+            297685328, 190893618, 201088934, 255645038, 117676973, 269871758, 283389171, 33349655, 188725057, 53472436, 187437384, 97353962, 70257049, 201961177, 306957824, 12257486,
+            121252504, 214565350, 235814077, 153739710, 136986708, 136429823, 85310266, 157073661, 197050358, 162415566, 155244905, 319356644, 315123588, 249579342, 317557341, 171752451,
+            309332678, 271449161, 219640458, 293420676, 109209729, 19882891, 214355467, 134607673, 181981537, 49209434, 310450195, 296623329, 124696094, 310053580, 67461826, 19636384,
+            221818700, 50475539, 18995984, 208864636, 291047776, 318922456, 251483095, 191977491, 44840967, 133268298, 101662748, 299982192, 272762890, 241757034, 23258995, 239379518,
+            145142435, 204243745, 37779629, 49979331, 135577535, 187993077, 40858960, 288180924, 67703797, 96365608, 257524943, 33303388, 129072991, 77747149, 283867501, 11930379,
+            46641512, 137858340, 296682569, 153407889, 259515711, 126174146, 198346294, 235455425, 244023416, 291596132, 316297415, 328710625, 80224578, 302632627, 113667569, 119113057,
+            312017817, 2699680, 108004786, 196303853, 334319350, 133319693, 327422655, 215939730, 97293139, 277699946, 162171273, 77273435, 316008252, 75151514, 32680821, 13466291,
+            256206912, 225832678, 245296564, 166344225, 230519898, 18887784, 108194240, 155075127, 74650975, 300719094, 74020064, 119463325, 298456636, 144707310, 252315645, 2757974,
+            321969537, 318219488, 203728303, 199667954, 339569618, 236437494, 68257532, 41674788, 79292517, 329595997, 47860047, 74221291, 133851496, 131423110, 134739242, 41769882,
+            125397753, 37421241, 99154118, 77345313, 75415599, 184611253, 283821969, 217425962, 340138445, 205360342, 138790530, 231381162, 177646695, 341124928, 49006892, 115050903,
+            328700132, 145997181, 305008536, 270860151, 315446483, 311962310, 37732254, 31766142, 314384689, 124829645, 37478454, 2002208, 167278182, 247209778, 85372494, 278387860,
+            339536290, 114992793, 310585351, 246747223, 161880752, 309863480, 145995082, 67504260, 96405640, 53758185, 80364252, 59762590, 61870224, 328402109, 123460961, 185357220,
+            210531620, 301407876, 330043666, 282401604, 176867483, 115053574, 316685038, 20214140, 75349137, 19519076, 63151532, 199071277, 179016942, 13021588, 321789792, 163648942,
+            139380103, 114565842, 330217875, 271319530, 129239990, 186057800, 258827287, 178929042, 82102774, 257249581, 177238145, 62402069, 160259722, 233013151, 315534334, 342784710,
+            77458610, 253683167, 261286212, 281360242, 296191980, 6850988, 251030736, 74731345, 265318802, 63899879, 311681497, 137131395, 3931149, 181665422, 51898522, 245605974,
+            128427927, 95354166, 166281164, 2434663, 286713155, 113257227, 112789726, 90764238, 44867204, 26890740, 298664607, 181169292, 120444705, 62783316, 66162809, 133187974,
+            131085619, 39270565, 70166946, 277526912, 1756312, 205015274, 210307520, 223955976, 295679311, 73435047, 218777227, 248504688, 191268148, 10674541, 113695358, 291536722,
+            198196536, 266946574, 121223151, 286290221, 28846473, 189515583, 205436167, 220060181, 17816194, 219660836, 218831760, 122930261, 90002096, 123760813, 89192098, 30551277,
+            208285091, 230068868, 113052860, 204703894, 323875798, 99019268, 41579225, 194457264, 64487982, 289332899, 148207072, 195897417, 311865514, 340092471, 219256369, 154766,
+            299759898, 311347621, 323312829, 63589683, 246540525, 151049736, 2185297, 179420091, 34750962, 84555619, 100438483, 120169396, 157907051, 225257403, 293722399, 111850253,
+            323856168, 338303783, 314840798, 190938467, 125867606, 234764184, 327427414, 142613978, 215585704, 261751388, 316751420, 121346748, 193921698, 138975926, 44295661, 343113050,
+            10670086, 262534597, 58896306, 100875887, 105441063, 338677572, 273548204, 304358246, 247450114, 126898411, 281611873, 65770419, 88358931, 108711560, 169816947, 276047518,
+            179623980, 8948915, 211487568, 135978710, 122356782, 61305919, 25101795, 291689257, 141349641, 198259466, 256737405, 116654989, 45647754, 180293767, 142965291, 182641848,
+            320298964, 104661562, 159853264, 63559596, 77470611, 155263833, 24371986, 4502110, 307150630, 142825689, 191055334, 272420854, 266596798, 310116768, 100031582, 330934661,
+            131329963, 205128768, 34434682, 264548538, 275820126, 58374622, 126868524, 247696662, 230430459, 247383707, 213976148, 4429934, 55811418, 182713031, 135206428, 78131304,
+            73905525, 122191796, 303115339, 249426444, 196133691, 50737499, 39423175, 38943576, 63789271, 15653280, 42256835, 76792639, 18041511, 28927295, 167872394, 132917641,
+            221464907, 306272254, 168295914, 311947582, 115002830, 173548221, 66297447, 38518479, 186039235, 166985453, 170012531, 110913328, 2521858, 164656555, 78715300, 137921241,
+            31451200, 69592338, 244799209, 30327278, 311383754, 324910770, 31364455, 227268411, 250460720, 69982039, 258447968, 48751303, 166388835, 160611885, 321899686, 248083879,
+            91906147, 70295745, 73849988, 252478588, 34713870, 338042480, 280941331, 10639985, 58539003, 256112056, 301421958, 251057581, 265894571, 25563194, 195929163, 142869361,
+            47864316, 339243405, 278587677, 209058399, 28896907, 235462631, 259232595, 244958163, 23735989, 146207513, 291668902, 343175816, 205222309, 282750786, 266854086, 311189979,
+            107993050, 55645002, 248439323, 110947244, 127537928, 20029480, 91971569, 91066679, 187746866, 177178431, 199502889, 212043310, 196042207, 211835072, 122477545, 18413892,
+            161679160, 35056566, 338821353, 276789509, 206322097, 18473387, 327976767, 80429437, 279397388, 68518274, 181023243, 237284827, 313969190, 15263438, 51894343, 9591303,
+            82627166, 239331506, 239476843, 289562517, 139382347, 242285354, 17292740, 188689316, 235469942, 117131734, 266735631, 326823227, 117612662, 76546657, 295122385, 12037548,
+            189504538, 95200070, 293038692, 31932380, 187259607, 73167190, 170755308, 218145696, 236213106, 108592503, 131352161, 60559929, 42411067, 280958175, 8836049, 297422828,
+            11573249, 91280673, 125611361, 161380632, 226344941, 134250929, 140995006, 98690051, 155765188, 164335593, 80031253, 199481563, 69867929, 39419746, 228795671, 19516918,
+            167375209, 89867706, 72825851, 242099982, 14848946, 42273808, 126259092, 304755136, 38613146, 122800946, 267082476, 167972636, 196062071, 254115855, 39817651, 309122741,
+            60457156, 250755360, 20601023, 243392916, 292858762, 180399588, 313217138, 29929697, 60449086, 283841728, 160244444, 241071188, 321755521, 108569899, 143560290, 272375957,
+            331455083, 14981285, 32934047, 262884057, 281379762, 227479236, 105879398, 272619394, 284712017, 190200546, 171093156, 34108414, 325985663, 199935697, 224245523, 144111576,
+            153321671, 286621872, 35462788, 214206730, 126269934, 65652966, 284070510, 6662486, 325197743, 38006257, 50224836, 124340354, 154428934, 7450140, 287185643, 33705971,
+            141469584, 272829155, 286510306, 246444258, 170097677, 319718232, 330523682, 140140378, 10364444, 160580247, 27785987, 34570969, 134913023, 14901862, 115728895, 78609524,
+            201919710, 13838972, 34092541, 198733493, 47482665, 251494232, 16132931, 38972371, 240063876, 117596199, 162911865, 262860640, 52977050, 77007819, 254322574, 230917793,
+            56907315, 187536671, 158797937, 155087075, 285406963, 223869101, 209999057, 86990953, 177275895, 51531987, 75323133, 136095883, 79458852, 284976460, 336503820, 248522042,
+            242449238, 205641666, 53426246, 117730324, 10035786, 176235396, 119572778, 246212637, 259359873, 106810129, 68701183, 223062848, 116203489, 128109911, 250671079, 143144811,
+            122946724, 97778773, 14445551, 298865154, 220279089, 290608179, 139788422, 238668396, 208042792, 131609015, 171512662, 87566759, 307515865, 299411860, 322981913, 275319558,
+            215000538, 298680114, 174004783, 223088200, 81687275, 147683374, 191654034, 69991164, 17002068, 330618625, 9609529, 80888816, 152614860, 150884999, 256151599, 329060317,
+            211562488, 80002392, 53630089, 14783054, 243458064, 201989694, 173499211, 84231350, 173331941, 304685475, 186888301, 246560832, 235755640, 112845732, 306533221, 45346390,
+            159933829, 204549617, 65072539, 250813869, 230816883, 281589467, 307369918, 341418978, 323140252, 73855972, 83202333, 37507398, 171449539, 2278644, 159569463, 171528205,
+        };
+
+
+        static void poly_uniform(long[] a, byte[] seed, int seedOffset)
+        {
+            int pos = 0, i = 0, nbytes = (PARAM_Q_LOG + 7) / 8;
+            int nblocks = PARAM_GEN_A;
+            int val1, val2, val3, val4, mask = (1 << PARAM_Q_LOG) - 1;
+            byte[] buf = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A];
+            short dmsp = 0;
+
+
+            HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                buf, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A,
+                dmsp++,
+                seed, seedOffset, CRYPTO_RANDOMBYTES
+            );
+
+
+            while (i < PARAM_K * PARAM_N)
+            {
+                if (pos > HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * nblocks - 4 * nbytes)
+                {
+                    nblocks = 1;
+
+                    HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                        buf, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A,
+                        dmsp++,
+                        seed, seedOffset, CRYPTO_RANDOMBYTES
+                    );
+
+                    pos = 0;
+                }
+                val1 = Pack.littleEndianToInt(buf, pos) & mask;
+                pos += nbytes;
+                val2 = Pack.littleEndianToInt(buf, pos) & mask;
+                pos += nbytes;
+                val3 = Pack.littleEndianToInt(buf, pos) & mask;
+                pos += nbytes;
+                val4 = Pack.littleEndianToInt(buf, pos) & mask;
+                pos += nbytes;
+                if (val1 < PARAM_Q && i < PARAM_K * PARAM_N)
+                {
+                    a[i++] = reduce((long)val1 * PARAM_R2_INVN);
+                }
+                if (val2 < PARAM_Q && i < PARAM_K * PARAM_N)
+                {
+                    a[i++] = reduce((long)val2 * PARAM_R2_INVN);
+                }
+                if (val3 < PARAM_Q && i < PARAM_K * PARAM_N)
+                {
+                    a[i++] = reduce((long)val3 * PARAM_R2_INVN);
+                }
+                if (val4 < PARAM_Q && i < PARAM_K * PARAM_N)
+                {
+                    a[i++] = reduce((long)val4 * PARAM_R2_INVN);
+                }
+            }
+        }
+
+
+        static long reduce(long a)
+        { // Montgomery reduction
+            long u;
+
+            u = (a * (long)PARAM_QINV) & 0xFFFFFFFFL;
+            u *= PARAM_Q;
+            a += u;
+            return a >> 32;
+        }
+
+
+        static void ntt(long[] a, long[] w)
+        { // Forward NTT transform
+            int NumoProblems = PARAM_N >> 1, jTwiddle = 0;
+
+            for (; NumoProblems > 0; NumoProblems >>= 1)
+            {
+                int jFirst, j = 0;
+                for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems)
+                {
+                    long W = (int)w[jTwiddle++];
+                    for (j = jFirst; j < jFirst + NumoProblems; j++)
+                    {
+                        long temp = reduce(W * a[j + NumoProblems]);
+                        a[j + NumoProblems] = a[j] + (PARAM_Q - temp);
+                        a[j] = temp + a[j];
+                    }
+                }
+            }
+        }
+
+
+        static long barr_reduce(long a)
+        { // Barrett reduction
+            long u = (((long)a * PARAM_BARR_MULT) >> PARAM_BARR_DIV); // TODO u may need to be cast back to int.
+            return a - u * PARAM_Q;
+        }
+
+
+        static void nttinv(long[] a, long[] w)
+        { // Inverse NTT transform
+            int NumoProblems = 1, jTwiddle = 0;
+            for (NumoProblems = 1; NumoProblems < PARAM_N; NumoProblems *= 2)
+            {
+                int jFirst, j = 0;
+                for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems)
+                {
+                    int W = (int)w[jTwiddle++];
+                    for (j = jFirst; j < jFirst + NumoProblems; j++)
+                    {
+                        long temp = a[j];
+
+                        if (NumoProblems == 16)
+                        {
+                            a[j] = barr_reduce(temp + a[j + NumoProblems]);
+                        }
+                        else
+                        {
+                            a[j] = temp + a[j + NumoProblems];
+                        }
+                        a[j + NumoProblems] = reduce((long)W * (temp - a[j + NumoProblems]));
+                    }
+                }
+            }
+
+            for (int i = 0; i < PARAM_N / 2; i++)
+            {
+                a[i] = reduce((long)PARAM_R * a[i]);
+            }
+        }
+
+        static void nttinv(long[] a, int aPos, long[] w)
+        { // Inverse NTT transform
+            int NumoProblems = 1, jTwiddle = 0;
+            for (NumoProblems = 1; NumoProblems < PARAM_N; NumoProblems *= 2)
+            {
+                int jFirst, j = 0;
+                for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems)
+                {
+                    int W = (int)w[jTwiddle++];
+                    for (j = jFirst; j < jFirst + NumoProblems; j++)
+                    {
+                        long temp = a[aPos + j];
+                        a[aPos + j] = temp + a[aPos + j + NumoProblems];
+                        a[aPos + j + NumoProblems] = reduce((long)W * (temp + (2 * PARAM_Q - a[aPos + j + NumoProblems])));
+                    }
+                }
+
+
+                NumoProblems *= 2;
+                for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems)
+                {
+                    int W = (int)w[jTwiddle++];
+                    for (j = jFirst; j < jFirst + NumoProblems; j++)
+                    {
+                        long temp = a[aPos + j];
+                        a[aPos + j] = barr_reduce(temp + a[aPos + j + NumoProblems]);
+                        a[aPos + j + NumoProblems] = reduce((long)W * (temp + (2 * PARAM_Q - a[aPos + j + NumoProblems])));
+                    }
+                }
+            }
+        }
+
+
+        static void poly_ntt(long[] x_ntt, long[] x)
+        { // Call to NTT function. Avoids input destruction
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                x_ntt[i] = x[i];
+            }
+            ntt(x_ntt, zeta);
+        }
+
+
+        static void poly_pointwise(long[] result, long[] x, long[] y)
+        { // Pointwise polynomial multiplication result = x.y
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[i] = reduce((long)x[i] * y[i]);
+            }
+        }
+
+        static void poly_pointwise(long[] result, int rpos, long[] x, int xpos, long[] y)
+        { // Pointwise polynomial multiplication result = x.y
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[i + rpos] = reduce((long)x[i + xpos] * y[i]);
+            }
+        }
+
+
+        static void poly_mul(long[] result, long[] x, long[] y)
+        { // Polynomial multiplication result = x*y, with in place reduction for (X^N+1)
+            // The input x is assumed to be in NTT form
+
+            poly_pointwise(result, x, y);
+            nttinv(result, zetainv);
+        }
+
+
+        static void poly_mul(long[] result, int rpos, long[] x, int xpos, long[] y)
+        { // Polynomial multiplication result = x*y, with in place reduction for (X^N+1)
+
+            poly_pointwise(result, rpos, x, xpos, y);
+            nttinv(result, rpos, zetainv);
+        }
+
+
+        static void poly_add(long[] result, long[] x, long[] y)
+        { // Polynomial addition result = x+y
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[i] = x[i] + y[i];
+            }
+        }
+
+        static void poly_sub(long[] result, int rpos, long[] x, int xpos, long[] y, int ypos)
+        { // Polynomial subtraction result = x-y
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[rpos + i] = barr_reduce(x[xpos + i] - y[ypos + i]);
+            }
+        }
+
+
+        static void poly_add_correct(long[] result, int rpos, long[] x, int xpos, long[] y, int ypos)
+        { // Polynomial addition result = x+y with correction
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[rpos + i] = x[xpos + i] + y[ypos + i];
+                result[rpos + i] -= PARAM_Q;
+                result[rpos + i] += (result[rpos + i] >> (RADIX32 - 1)) & PARAM_Q;   // If result[i] >= q then subtract q
+            }
+        }
+
+
+        static void poly_sub_correct(int[] result, int[] x, int[] y)
+        { // Polynomial subtraction result = x-y with correction
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[i] = x[i] - y[i];
+                result[i] += (result[i] >> (RADIX32 - 1)) & PARAM_Q;    // If result[i] < 0 then add q
+            }
+        }
+
+
+        static void sparse_mul8(long[] prod, int ppos, byte[] s, int spos, int[] pos_list, short[] sign_list)
+        {
+            int i, j, pos;
+
+            for (i = 0; i < PARAM_N; i++)
+            {
+                prod[ppos + i] = 0;
+            }
+
+            for (i = 0; i < PARAM_H; i++)
+            {
+                pos = pos_list[i];
+                for (j = 0; j < pos; j++)
+                {
+                    prod[ppos + j] = prod[ppos + j] - sign_list[i] * s[spos + j + PARAM_N - pos];
+                }
+                for (j = pos; j < PARAM_N; j++)
+                {
+                    prod[ppos + j] = prod[ppos + j] + sign_list[i] * s[spos + j - pos];
+                }
+            }
+        }
+
+
+        static void sparse_mul8(long[] prod, byte[] s, int[] pos_list, short[] sign_list)
+        {
+            int i, j, pos;
+            byte t[] = s;
+
+            for (i = 0; i < PARAM_N; i++)
+            {
+                prod[i] = 0;
+            }
+
+            for (i = 0; i < PARAM_H; i++)
+            {
+                pos = pos_list[i];
+                for (j = 0; j < pos; j++)
+                {
+                    prod[j] = prod[j] - sign_list[i] * t[j + PARAM_N - pos];
+                }
+                for (j = pos; j < PARAM_N; j++)
+                {
+                    prod[j] = prod[j] + sign_list[i] * t[j - pos];
+                }
+            }
+        }
+
+
+        static void sparse_mul16(int[] prod, int s[], int pos_list[], short sign_list[])
+        {
+            int i, j, pos;
+//            short[] t = s;
+
+            for (i = 0; i < PARAM_N; i++)
+            {
+                prod[i] = 0;
+            }
+
+            for (i = 0; i < PARAM_H; i++)
+            {
+                pos = pos_list[i];
+                for (j = 0; j < pos; j++)
+                {
+                    prod[j] = prod[j] - sign_list[i] * s[j + PARAM_N - pos];
+                }
+                for (j = pos; j < PARAM_N; j++)
+                {
+                    prod[j] = prod[j] + sign_list[i] * s[j - pos];
+                }
+            }
+        }
+
+
+        static void sparse_mul32(int[] prod, int[] pk, int[] pos_list, short[] sign_list)
+        {
+            int i, j, pos;
+
+            for (i = 0; i < PARAM_N; i++)
+            {
+                prod[i] = 0;
+            }
+
+            for (i = 0; i < PARAM_H; i++)
+            {
+                pos = pos_list[i];
+                for (j = 0; j < pos; j++)
+                {
+                    prod[j] = prod[j] - sign_list[i] * pk[j + PARAM_N - pos];
+                }
+                for (j = pos; j < PARAM_N; j++)
+                {
+                    prod[j] = prod[j] + sign_list[i] * pk[j - pos];
+                }
+            }
+        }
+
+        static void sparse_mul32(long[] prod, int ppos, int[] pk, int pkPos, int[] pos_list, short[] sign_list)
+        {
+            int i, j, pos;
+
+            for (i = 0; i < PARAM_N; i++)
+            {
+                prod[ppos + i] = 0;
+            }
+
+            for (i = 0; i < PARAM_H; i++)
+            {
+                pos = pos_list[i];
+                for (j = 0; j < pos; j++)
+                {
+                    prod[ppos + j] = prod[ppos + j] - sign_list[i] * pk[pkPos + j + PARAM_N - pos];
+                }
+                for (j = pos; j < PARAM_N; j++)
+                {
+                    prod[ppos + j] = prod[ppos + j] + sign_list[i] * pk[pkPos + j - pos];
+                }
+            }
+        }
+
+
+    }
+
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTesla3p.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTesla3p.java
new file mode 100644
index 000000000..d0eb1a517
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qtesla/QTesla3p.java
@@ -0,0 +1,1530 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qtesla;
+
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.util.Arrays;
+import com.fr.third.org.bouncycastle.util.Pack;
+
+class QTesla3p
+{
+
+    private static final int PARAM_N = 2048;
+    private static final double PARAM_SIGMA = 8.5;
+    private static final int PARAM_Q = 856145921;
+    private static final int PARAM_Q_LOG = 30;
+    private static final long PARAM_QINV = 587710463;
+    private static final long PARAM_BARR_MULT = 5;
+    private static final int PARAM_BARR_DIV = 32;
+    private static final int PARAM_B = 2097151;
+    private static final int PARAM_B_BITS = 21;
+    private static final int PARAM_S_BITS = 8;
+    private static final int PARAM_K = 5;
+    private static final double PARAM_SIGMA_E = PARAM_SIGMA;
+    private static final int PARAM_H = 40;
+    private static final int PARAM_D = 24;
+    private static final int PARAM_GEN_A = 180;
+    private static final int PARAM_KEYGEN_BOUND_E = 901;
+    private static final int PARAM_E = PARAM_KEYGEN_BOUND_E;
+    private static final int PARAM_KEYGEN_BOUND_S = 901;
+    private static final int PARAM_S = PARAM_KEYGEN_BOUND_S;
+    private static final int PARAM_R2_INVN = 513161157;
+    private static final int PARAM_R = 14237691;
+
+
+    private static final int CRYPTO_RANDOMBYTES = 32;
+    private static final int CRYPTO_SEEDBYTES = 32;
+    private static final int CRYPTO_C_BYTES = 32;
+    private static final int HM_BYTES = 64;
+
+    private static final int RADIX = 32;
+    private static final int RADIX32 = 32;
+
+
+    static final int CRYPTO_BYTES = ((PARAM_N * (PARAM_B_BITS + 1) + 7) / 8 + CRYPTO_C_BYTES);
+    // Contains polynomial s and e, and seeds seed_a and seed_y
+    static final int CRYPTO_SECRETKEYBYTES = (1 * PARAM_N + 1 * PARAM_N * PARAM_K + 2 * CRYPTO_SEEDBYTES);
+
+    // Contains seed_a and polynomials t
+    static final int CRYPTO_PUBLICKEYBYTES = ((PARAM_Q_LOG * PARAM_N * PARAM_K + 7) / 8 + CRYPTO_SEEDBYTES);
+
+
+    static int generateKeyPair(
+
+        byte[] publicKey, byte[] privateKey, SecureRandom secureRandom)
+    {
+
+        /* Initialize Domain Separator for Error Polynomial and Secret Polynomial */
+        int nonce = 0;
+
+        byte[] randomness = new byte[CRYPTO_RANDOMBYTES];
+
+        /* Extend Random Bytes to Seed Generation of Error Polynomial and Secret Polynomial */
+        byte[] randomnessExtended = new byte[(PARAM_K + 3) * CRYPTO_SEEDBYTES];
+
+        long[] secretPolynomial = new long[PARAM_N];
+        long[] errorPolynomial = new long[PARAM_N * PARAM_K];
+        long[] A = new long[PARAM_N * PARAM_K];
+        long[] T = new long[PARAM_N * PARAM_K];
+
+        long[] s_ntt = new long[PARAM_N];
+
+        /* Get randomnessExtended <- seedErrorPolynomial, seedSecretPolynomial, seedA, seedY */
+        // this.rng.randomByte (randomness, (short) 0, Polynomial.RANDOM);
+        secureRandom.nextBytes(randomness);
+
+
+        HashUtils.secureHashAlgorithmKECCAK256(randomnessExtended, 0, (PARAM_K + 3) * CRYPTO_SEEDBYTES, randomness, 0, CRYPTO_RANDOMBYTES);
+
+
+
+
+
+
+        /*
+         * Sample the Error Polynomial Fulfilling the Criteria
+         * Choose All Error Polynomial in R with Entries from D_SIGMA
+         * Repeat Step at Iteration if the h Largest Entries of Error Polynomial Summation to L_E
+         */
+
+        for (int k = 0; k < PARAM_K; k++)
+        {
+            do
+            {
+                Gaussian.sample_gauss_poly(++nonce, randomnessExtended, k * CRYPTO_SEEDBYTES, errorPolynomial, k * PARAM_N);
+            }
+            while (checkPolynomial(errorPolynomial, k * PARAM_N, PARAM_KEYGEN_BOUND_E));
+        }
+
+
+        /*
+         * Sample the Secret Polynomial Fulfilling the Criteria
+         * Choose Secret Polynomial in R with Entries from D_SIGMA
+         * Repeat Step if the h Largest Entries of Secret Polynomial Summation to L_S
+         */
+        do
+        {
+
+            Gaussian.sample_gauss_poly(++nonce, randomnessExtended, PARAM_K * CRYPTO_SEEDBYTES, secretPolynomial, 0);
+
+            //Sample.polynomialGaussSamplerI(secretPolynomial, 0, randomnessExtended, Polynomial.SEED, ++nonce);
+        }
+        while (checkPolynomial(secretPolynomial, 0, PARAM_KEYGEN_BOUND_S));
+
+
+        QTesla3PPolynomial.poly_uniform(A, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES);
+        QTesla3PPolynomial.poly_ntt(s_ntt, secretPolynomial);
+
+
+        for (int k = 0; k < PARAM_K; k++)
+        {
+            QTesla3PPolynomial.poly_mul(T, k * PARAM_N, A, k * PARAM_N, s_ntt);
+            QTesla3PPolynomial.poly_add_correct(T, k * PARAM_N, T, k * PARAM_N, errorPolynomial, k * PARAM_N);
+        }
+
+
+        /* Pack Public and Private Keys */
+
+        encodePrivateKey(privateKey, secretPolynomial, errorPolynomial, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES);
+        encodePublicKey(publicKey, T, randomnessExtended, (PARAM_K + 1) * CRYPTO_SEEDBYTES);
+
+        return 0;
+
+    }
+
+
+    static int generateSignature(
+        byte[] signature,
+        final byte[] message, int messageOffset, int messageLength,
+        final byte[] privateKey, SecureRandom secureRandom)
+    {
+        byte[] c = new byte[CRYPTO_C_BYTES];
+        byte[] randomness = new byte[CRYPTO_SEEDBYTES];
+        byte[] randomness_input = new byte[CRYPTO_RANDOMBYTES + CRYPTO_SEEDBYTES + HM_BYTES];
+        int[] pos_list = new int[PARAM_H];
+        short[] sign_list = new short[PARAM_H];
+        long[] y = new long[PARAM_N];
+
+        long[] y_ntt = new long[PARAM_N];
+        long[] Sc = new long[PARAM_N];
+        long[] z = new long[PARAM_N];
+
+        long[] v = new long[PARAM_N * PARAM_K];
+        long[] Ec = new long[PARAM_N * PARAM_K];
+        long[] a = new long[PARAM_N * PARAM_K];
+
+        int k;
+        int nonce = 0;  // Initialize domain separator for sampling y
+        boolean rsp = false;
+
+        //  randombytes(randomness_input + CRYPTO_RANDOMBYTES, CRYPTO_RANDOMBYTES);
+        byte[] temporaryRandomnessInput = new byte[CRYPTO_RANDOMBYTES];
+        secureRandom.nextBytes(temporaryRandomnessInput);
+        System.arraycopy(temporaryRandomnessInput, 0, randomness_input, CRYPTO_RANDOMBYTES, CRYPTO_RANDOMBYTES);
+        // --
+
+
+        //  memcpy(randomness_input, &sk[CRYPTO_SECRETKEYBYTES - CRYPTO_SEEDBYTES], CRYPTO_SEEDBYTES);
+        System.arraycopy(privateKey, CRYPTO_SECRETKEYBYTES - CRYPTO_SEEDBYTES, randomness_input, 0, CRYPTO_SEEDBYTES);
+        // --
+
+        HashUtils.secureHashAlgorithmKECCAK256(
+            randomness_input, CRYPTO_RANDOMBYTES + CRYPTO_SEEDBYTES, HM_BYTES, message, 0, messageLength);
+
+        HashUtils.secureHashAlgorithmKECCAK256(
+            randomness, 0, CRYPTO_SEEDBYTES, randomness_input, 0, CRYPTO_RANDOMBYTES + CRYPTO_SEEDBYTES + HM_BYTES);
+
+
+        QTesla3PPolynomial.poly_uniform(a, privateKey, CRYPTO_SECRETKEYBYTES - 2 * CRYPTO_SEEDBYTES);
+
+        while (true)
+        {
+            sample_y(y, randomness, 0, ++nonce);
+
+            QTesla3PPolynomial.poly_ntt(y_ntt, y);
+            for (k = 0; k < PARAM_K; k++)
+            {
+                QTesla3PPolynomial.poly_mul(v, k * PARAM_N, a, k * PARAM_N, y_ntt);
+            }
+
+            hashFunction(c, 0, v, randomness_input, CRYPTO_RANDOMBYTES + CRYPTO_SEEDBYTES);
+            encodeC(pos_list, sign_list, c, 0);
+
+            QTesla3PPolynomial.sparse_mul8(Sc, privateKey, pos_list, sign_list);
+
+            QTesla3PPolynomial.poly_add(z, y, Sc);
+
+            if (testRejection(z))
+            {
+                continue;
+            }
+
+            for (k = 0; k < PARAM_K; k++)
+            {
+                QTesla3PPolynomial.sparse_mul8(Ec, k * PARAM_N, privateKey, (PARAM_N * (k + 1)), pos_list, sign_list);
+                QTesla3PPolynomial.poly_sub(v, k * PARAM_N, v, k * PARAM_N, Ec, k * PARAM_N);
+                rsp = test_correctness(v, k * PARAM_N);
+                if (rsp)
+                {
+                    break;
+                } // TODO replace with contine outer
+            }
+            if (rsp)
+            {
+                continue;
+            }
+
+
+            encodeSignature(signature, 0, c, 0, z);
+            return 0;
+
+        }
+
+        // return 0;
+    }
+
+
+    static int verifying(
+        byte[] message,
+        final byte[] signature, int signatureOffset, int signatureLength,
+        final byte[] publicKey)
+    {
+
+        byte c[] = new byte[CRYPTO_C_BYTES];
+        byte c_sig[] = new byte[CRYPTO_C_BYTES];
+        byte seed[] = new byte[CRYPTO_SEEDBYTES];
+        byte hm[] = new byte[HM_BYTES];
+        int pos_list[] = new int[PARAM_H];
+        short sign_list[] = new short[PARAM_H];
+        int pk_t[] = new int[PARAM_N * PARAM_K];
+        long[] w = new long[PARAM_N * PARAM_K];
+        long[] a = new long[PARAM_N * PARAM_K];
+        long[] Tc = new long[PARAM_N * PARAM_K];
+
+        long[] z = new long[PARAM_N];
+        long[] z_ntt = new long[PARAM_N];
+
+        int k = 0;
+
+        if (signatureLength < CRYPTO_BYTES)
+        {
+            return -1;
+        }
+
+        decodeSignature(c, z, signature, signatureOffset);
+
+        if (testZ(z))
+        {
+            return -2;
+        }
+
+
+        decodePublicKey(pk_t, seed, 0, publicKey);
+        QTesla3PPolynomial.poly_uniform(a, seed, 0);
+        encodeC(pos_list, sign_list, c, 0);
+        QTesla3PPolynomial.poly_ntt(z_ntt, z);
+
+        for (k = 0; k < PARAM_K; k++)
+        {      // Compute w = az - tc
+            QTesla3PPolynomial.sparse_mul32(Tc, k * PARAM_N, pk_t, (k * PARAM_N), pos_list, sign_list);
+            QTesla3PPolynomial.poly_mul(w, k * PARAM_N, a, k * PARAM_N, z_ntt);
+            QTesla3PPolynomial.poly_sub(w, k * PARAM_N, w, k * PARAM_N, Tc, k * PARAM_N);
+        }
+
+        HashUtils.secureHashAlgorithmKECCAK256(
+            hm, 0, HM_BYTES, message, 0, message.length
+        );
+        hashFunction(c_sig, 0, w, hm, 0);
+
+        if (!memoryEqual(c, 0, c_sig, 0, CRYPTO_C_BYTES))
+        {
+            return -3;
+        }
+
+        return 0;
+    }
+
+
+    static void encodePrivateKey(byte[] privateKey, final long[] secretPolynomial, final long[] errorPolynomial, final byte[] seed, int seedOffset)
+    {
+
+        int i, k = 0;
+        int skPtr = 0;
+
+        for (i = 0; i < PARAM_N; i++)
+        {
+            privateKey[skPtr + i] = (byte)secretPolynomial[i];
+        }
+
+        skPtr += PARAM_N;
+        for (k = 0; k < PARAM_K; k++)
+        {
+            for (i = 0; i < PARAM_N; i++)
+            {
+                privateKey[skPtr + (k * PARAM_N + i)] = (byte)errorPolynomial[k * PARAM_N + i];
+                //  System.out.printf("%d,   %x\n", skPtr + (k * PARAM_N + i), privateKey[skPtr + (k * PARAM_N + i)]);
+            }
+        }
+
+        System.arraycopy(seed, seedOffset, privateKey, skPtr + (PARAM_K * PARAM_N), CRYPTO_SEEDBYTES * 2);
+
+    }
+
+
+    static void encodePublicKey(byte[] publicKey, final long[] T, final byte[] seedA, int seedAOffset)
+    {
+
+        int j = 0;
+
+
+        for (int i = 0; i < (PARAM_N * PARAM_K * PARAM_Q_LOG / 32); i += 15)
+        {
+            at(publicKey, i, 0, (int)(T[j] | (T[j + 1] << 30)));
+            at(publicKey, i, 1, (int)((T[j + 1] >> 2) | (T[j + 2] << 28)));
+            at(publicKey, i, 2, (int)((T[j + 2] >> 4) | (T[j + 3] << 26)));
+            at(publicKey, i, 3, (int)((T[j + 3] >> 6) | (T[j + 4] << 24)));
+            at(publicKey, i, 4, (int)((T[j + 4] >> 8) | (T[j + 5] << 22)));
+            at(publicKey, i, 5, (int)((T[j + 5] >> 10) | (T[j + 6] << 20)));
+            at(publicKey, i, 6, (int)((T[j + 6] >> 12) | (T[j + 7] << 18)));
+            at(publicKey, i, 7, (int)((T[j + 7] >> 14) | (T[j + 8] << 16)));
+            at(publicKey, i, 8, (int)((T[j + 8] >> 16) | (T[j + 9] << 14)));
+            at(publicKey, i, 9, (int)((T[j + 9] >> 18) | (T[j + 10] << 12)));
+            at(publicKey, i, 10, (int)((T[j + 10] >> 20) | (T[j + 11] << 10)));
+            at(publicKey, i, 11, (int)((T[j + 11] >> 22) | (T[j + 12] << 8)));
+            at(publicKey, i, 12, (int)((T[j + 12] >> 24) | (T[j + 13] << 6)));
+            at(publicKey, i, 13, (int)((T[j + 13] >> 26) | (T[j + 14] << 4)));
+            at(publicKey, i, 14, (int)((T[j + 14] >> 28) | (T[j + 15] << 2)));
+            j += 16;
+        }
+
+        System.arraycopy(seedA, seedAOffset, publicKey, PARAM_N * PARAM_K * PARAM_Q_LOG / 8, CRYPTO_SEEDBYTES);
+
+    }
+
+
+    static void decodePublicKey(int[] publicKey, byte[] seedA, int seedAOffset, final byte[] publicKeyInput)
+    {
+
+        int j = 0;
+        byte[] pt = publicKeyInput;
+        int maskq = (1 << PARAM_Q_LOG) - 1;
+
+
+        for (int i = 0; i < PARAM_N * PARAM_K; i += 16)
+        {
+            publicKey[i] = at(pt, j, 0) & maskq;
+            publicKey[i + 1] = ((at(pt, j, 0) >>> 30) | (at(pt, j, 1) << 2)) & maskq;
+            publicKey[i + 2] = ((at(pt, j, 1) >>> 28) | (at(pt, j, 2) << 4)) & maskq;
+            publicKey[i + 3] = ((at(pt, j, 2) >>> 26) | (at(pt, j, 3) << 6)) & maskq;
+            publicKey[i + 4] = ((at(pt, j, 3) >>> 24) | (at(pt, j, 4) << 8)) & maskq;
+            publicKey[i + 5] = ((at(pt, j, 4) >>> 22) | (at(pt, j, 5) << 10)) & maskq;
+            publicKey[i + 6] = ((at(pt, j, 5) >>> 20) | (at(pt, j, 6) << 12)) & maskq;
+            publicKey[i + 7] = ((at(pt, j, 6) >>> 18) | (at(pt, j, 7) << 14)) & maskq;
+            publicKey[i + 8] = ((at(pt, j, 7) >>> 16) | (at(pt, j, 8) << 16)) & maskq;
+            publicKey[i + 9] = ((at(pt, j, 8) >>> 14) | (at(pt, j, 9) << 18)) & maskq;
+            publicKey[i + 10] = ((at(pt, j, 9) >>> 12) | (at(pt, j, 10) << 20)) & maskq;
+            publicKey[i + 11] = ((at(pt, j, 10) >>> 10) | (at(pt, j, 11) << 22)) & maskq;
+            publicKey[i + 12] = ((at(pt, j, 11) >>> 8) | (at(pt, j, 12) << 24)) & maskq;
+            publicKey[i + 13] = ((at(pt, j, 12) >>> 6) | (at(pt, j, 13) << 26)) & maskq;
+            publicKey[i + 14] = ((at(pt, j, 13) >>> 4) | (at(pt, j, 14) << 28)) & maskq;
+            publicKey[i + 15] = (at(pt, j, 14) >>> 2) & maskq;
+            j += 15;
+        }
+
+
+        System.arraycopy(publicKeyInput, PARAM_N * PARAM_K * PARAM_Q_LOG / 8, seedA, seedAOffset, CRYPTO_SEEDBYTES);
+
+    }
+
+    private static boolean testZ(long[] Z)
+    {
+        // Returns false if valid, otherwise outputs 1 if invalid (rejected)
+
+        for (int i = 0; i < PARAM_N; i++)
+        {
+
+            if ((Z[i] < -(PARAM_B - PARAM_S)) || (Z[i] > PARAM_B - PARAM_S))
+            {
+
+                return true;
+
+            }
+
+        }
+
+        return false;
+
+    }
+
+
+    private static final int maskb1 = ((1 << (PARAM_B_BITS + 1)) - 1);
+
+    static void encodeSignature(byte[] signature, int signatureOffset, byte[] C, int cOffset, long[] Z)
+    {
+        int j = 0;
+
+        for (int i = 0; i < (PARAM_N * (PARAM_B_BITS + 1) / 32); i += 11)
+        {
+            at(signature, i, 0, (int)((Z[j + 0] & ((1 << 22) - 1)) | (Z[j + 1] << 22)));
+            at(signature, i, 1, (int)(((Z[j + 1] >>> 10) & ((1 << 12) - 1)) | (Z[j + 2] << 12)));
+            at(signature, i, 2, (int)(((Z[j + 2] >>> 20) & ((1 << 2) - 1)) | ((Z[j + 3] & maskb1) << 2) | (Z[j + 4] << 24)));
+            at(signature, i, 3, (int)(((Z[j + 4] >>> 8) & ((1 << 14) - 1)) | (Z[j + 5] << 14)));
+            at(signature, i, 4, (int)(((Z[j + 5] >>> 18) & ((1 << 4) - 1)) | ((Z[j + 6] & maskb1) << 4) | (Z[j + 7] << 26)));
+            at(signature, i, 5, (int)(((Z[j + 7] >>> 6) & ((1 << 16) - 1)) | (Z[j + 8] << 16)));
+            at(signature, i, 6, (int)(((Z[j + 8] >>> 16) & ((1 << 6) - 1)) | ((Z[j + 9] & maskb1) << 6) | (Z[j + 10] << 28)));
+            at(signature, i, 7, (int)(((Z[j + 10] >>> 4) & ((1 << 18) - 1)) | (Z[j + 11] << 18)));
+            at(signature, i, 8, (int)(((Z[j + 11] >>> 14) & ((1 << 8) - 1)) | ((Z[j + 12] & maskb1) << 8) | (Z[j + 13] << 30)));
+            at(signature, i, 9, (int)(((Z[j + 13] >>> 2) & ((1 << 20) - 1)) | (Z[j + 14] << 20)));
+            at(signature, i, 10, (int)(((Z[j + 14] >>> 12) & ((1 << 10) - 1)) | (Z[j + 15] << 10)));
+            j += 16;
+        }
+
+        System.arraycopy(C, cOffset, signature, signatureOffset + PARAM_N * (PARAM_B_BITS + 1) / 8, CRYPTO_C_BYTES);
+
+    }
+
+
+    static void decodeSignature(byte[] C, long[] Z, final byte[] signature, int signatureOffset)
+    {
+
+        int j = 0;
+        for (int i = 0; i < PARAM_N; i += 16)
+        {
+            Z[i] = (at(signature, j, 0) << 10) >> 10;
+            Z[i + 1] = (at(signature, j, 0) >>> 22) | ((at(signature, j, 1) << 20) >> 10);
+            Z[i + 2] = (at(signature, j, 1) >>> 12) | ((at(signature, j, 2) << 30) >> 10);
+            Z[i + 3] = ((at(signature, j, 2) << 8) >> 10);
+            Z[i + 4] = (at(signature, j, 2) >>> 24) | ((at(signature, j, 3) << 18) >> 10);
+            Z[i + 5] = (at(signature, j, 3) >>> 14) | ((at(signature, j, 4) << 28) >> 10);
+            Z[i + 6] = ((at(signature, j, 4) << 6) >> 10);
+            Z[i + 7] = (at(signature, j, 4) >>> 26) | ((at(signature, j, 5) << 16) >> 10);
+            Z[i + 8] = (at(signature, j, 5) >>> 16) | ((at(signature, j, 6) << 26) >> 10);
+            Z[i + 9] = ((at(signature, j, 6) << 4) >> 10);
+            Z[i + 10] = (at(signature, j, 6) >>> 28) | ((at(signature, j, 7) << 14) >> 10);
+            Z[i + 11] = (at(signature, j, 7) >>> 18) | ((at(signature, j, 8) << 24) >> 10);
+            Z[i + 12] = ((at(signature, j, 8) << 2) >> 10);
+            Z[i + 13] = (at(signature, j, 8) >>> 30) | ((at(signature, j, 9) << 12) >> 10);
+            Z[i + 14] = (at(signature, j, 9) >>> 20) | ((at(signature, j, 10) << 22) >> 10);
+            Z[i + 15] = (at(signature, j, 10) >> 10);
+
+            j += 11;
+        }
+        System.arraycopy(signature, signatureOffset + PARAM_N * (PARAM_B_BITS + 1) / 8, C, 0, CRYPTO_C_BYTES);
+
+
+    }
+
+
+    static void encodeC(int[] positionList, short[] signList, byte[] output, int outputOffset)
+    {
+
+        int count = 0;
+        int position;
+        short domainSeparator = 0;
+        short[] C = new short[PARAM_N];
+        byte[] randomness = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE];
+
+        /* Use the Hash Value as Key to Generate Some Randomness */
+        HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+            randomness, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE,
+            domainSeparator++,
+            output, outputOffset, CRYPTO_RANDOMBYTES
+        );
+
+        /* Use Rejection Sampling to Determine Positions to be Set in the New Vector */
+        Arrays.fill(C, (short)0);
+
+        /* Sample A Unique Position k times.
+         * Use Two Bytes
+         */
+        for (int i = 0; i < PARAM_H; )
+        {
+
+            if (count > HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE - 3)
+            {
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                    randomness, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE,
+                    domainSeparator++,
+                    output, outputOffset, CRYPTO_RANDOMBYTES
+                );
+
+                count = 0;
+
+            }
+
+            position = (randomness[count] << 8) | (randomness[count + 1] & 0xFF);
+            position &= (PARAM_N - 1);
+
+            /* Position is between [0, n - 1] and Has not Been Set Yet
+             * Determine Signature
+             */
+            if (C[position] == 0)
+            {
+
+                if ((randomness[count + 2] & 1) == 1)
+                {
+
+                    C[position] = -1;
+
+                }
+                else
+                {
+
+                    C[position] = 1;
+
+                }
+
+                positionList[i] = position;
+                signList[i] = C[position];
+                i++;
+
+            }
+
+            count += 3;
+
+        }
+
+    }
+
+
+    private static void hashFunction(byte[] output, int outputOffset, long[] v, final byte[] message, int messageOffset) //, int n, int d, int q)
+    {
+
+        int mask;
+        int cL;
+
+        byte[] T = new byte[PARAM_K * PARAM_N + HM_BYTES];
+
+        for (int k = 0; k < PARAM_K; k++)
+        {
+            int index = k * PARAM_N;
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                int temp = (int)v[index];
+                // If v[i] > PARAM_Q/2 then v[i] -= PARAM_Q
+                mask = (PARAM_Q / 2 - temp) >> (RADIX32 - 1);
+                temp = ((temp - PARAM_Q) & mask) | (temp & ~mask);
+
+                cL = temp & ((1 << PARAM_D) - 1);
+                // If cL > 2^(d-1) then cL -= 2^d
+                mask = ((1 << (PARAM_D - 1)) - cL) >> (RADIX32 - 1);
+                cL = ((cL - (1 << PARAM_D)) & mask) | (cL & ~mask);
+                T[index++] = (byte)((temp - cL) >> PARAM_D);
+            }
+        }
+        System.arraycopy(message, messageOffset, T, PARAM_N * PARAM_K, HM_BYTES);
+        HashUtils.secureHashAlgorithmKECCAK256(output, outputOffset, CRYPTO_C_BYTES, T, 0, PARAM_K * PARAM_N + HM_BYTES);
+
+    }
+
+
+    static int lE24BitToInt(byte[] bs, int off)
+    {
+        int n = bs[off] & 0xff;
+        n |= (bs[++off] & 0xff) << 8;
+        n |= (bs[++off] & 0xff) << 16;
+        return n;
+    }
+
+
+    private static int NBLOCKS_SHAKE = HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE / (((PARAM_B_BITS + 1) + 7) / 8);
+    private static int BPLUS1BYTES = ((PARAM_B_BITS + 1) + 7) / 8;
+
+
+    static void sample_y(long[] y, byte[] seed, int seedOffset, int nonce)
+    { // Sample polynomial y, such that each coefficient is in the range [-B,B]
+        int i = 0, pos = 0, nblocks = PARAM_N;
+        byte buf[] = new byte[PARAM_N * BPLUS1BYTES + 1];
+        int nbytes = BPLUS1BYTES;
+        short dmsp = (short)(nonce << 8);
+
+        HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+            buf, 0, PARAM_N * nbytes, dmsp++, seed, seedOffset, CRYPTO_RANDOMBYTES
+        );
+
+
+        while (i < PARAM_N)
+        {
+            if (pos >= nblocks * nbytes)
+            {
+                nblocks = NBLOCKS_SHAKE;
+                HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+                    buf, 0, PARAM_N * nbytes, dmsp++, seed, seedOffset, CRYPTO_RANDOMBYTES
+                );
+                pos = 0;
+            }
+            y[i] = lE24BitToInt(buf, pos) & ((1 << (PARAM_B_BITS + 1)) - 1);
+            y[i] -= PARAM_B;
+            if (y[i] != (1 << PARAM_B_BITS))
+            {
+                i++;
+            }
+            pos += nbytes;
+        }
+    }
+
+
+    private static void at(byte[] bs, int base, int index, int value)
+    {
+        Pack.intToLittleEndian(value, bs, (base * 4) + (index * 4));
+    }
+
+    private static int at(byte[] bs, int base, int index)
+    {
+        int off = (base * 4) + (index * 4);
+
+        int n = bs[off] & 0xff;
+        n |= (bs[++off] & 0xff) << 8;
+        n |= (bs[++off] & 0xff) << 16;
+        n |= bs[++off] << 24;
+        return n;
+    }
+
+
+    static boolean test_correctness(long[] v, int vpos)
+    { // Check bounds for w = v - ec during signature verification. Returns 0 if valid, otherwise outputs 1 if invalid (rejected).
+        // This function leaks the position of the coefficient that fails the test (but this is independent of the secret data).
+        // It does not leak the sign of the coefficients.
+        int mask, left, val;
+        int t0, t1;
+
+        for (int i = 0; i < PARAM_N; i++)
+        {
+            // If v[i] > PARAM_Q/2 then v[i] -= PARAM_Q
+            mask = (int)(PARAM_Q / 2 - v[vpos + i]) >> (RADIX32 - 1);
+            val = (int)(((v[vpos + i] - PARAM_Q) & mask) | (v[vpos + i] & ~mask));
+            // If (Abs(val) < PARAM_Q/2 - PARAM_E) then t0 = 0, else t0 = 1
+            t0 = (int)(~(absolute(val) - (PARAM_Q / 2 - PARAM_E))) >>> (RADIX32 - 1);
+
+            left = val;
+            val = (val + (1 << (PARAM_D - 1)) - 1) >> PARAM_D;
+            val = left - (val << PARAM_D);
+            // If (Abs(val) < (1<<(PARAM_D-1))-PARAM_E) then t1 = 0, else t1 = 1
+            t1 = (int)(~(absolute(val) - ((1 << (PARAM_D - 1)) - PARAM_E))) >>> (RADIX32 - 1);
+
+            if ((t0 | t1) == 1)  // Returns 1 if any of the two tests failed
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+
+    private static boolean testRejection(long[] Z) //, int n, int b, int u)
+    {
+
+        int valid = 0;
+
+        for (int i = 0; i < PARAM_N; i++)
+        {
+            valid |= (PARAM_B - PARAM_S) - absolute(Z[i]);
+
+        }
+
+        return (valid >>> 31) > 0;
+
+    }
+
+    private static int absolute(int value)
+    {
+
+        return ((value >> 31) ^ value) - (value >> 31);
+
+    }
+
+    private static long absolute(long value)
+    {
+
+        return ((value >> 63) ^ value) - (value >> 63);
+
+    }
+
+
+    private static boolean checkPolynomial(long[] polynomial, int polyOffset, int bound)
+    {
+
+        int i, j, sum = 0, limit = PARAM_N;
+        long temp, mask;
+        long[] list = new long[PARAM_N];
+
+        for (j = 0; j < PARAM_N; j++)
+        {
+            list[j] = absolute((int)polynomial[polyOffset + j]);
+        }
+
+        for (j = 0; j < PARAM_H; j++)
+        {
+            for (i = 0; i < limit - 1; i++)
+            {
+                // If list[i+1] > list[i] then exchange contents
+                mask = (list[i + 1] - list[i]) >> (RADIX32 - 1);
+                temp = (list[i + 1] & mask) | (list[i] & ~mask);
+                list[i + 1] = (list[i] & mask) | (list[i + 1] & ~mask);
+                list[i] = temp;
+            }
+            sum += (int)list[limit - 1];
+            limit -= 1;
+        }
+
+        return (sum > bound);
+    }
+
+
+    // End of outer.
+
+    static class Gaussian
+    {
+
+        private static final int CDT_ROWS = 111;
+        private static final int CDT_COLS = 4;
+        private static final int CHUNK_SIZE = 512;
+
+        private static final long[] cdt_v = new long[]{
+            0x00000000L, 0x00000000L, 0x00000000L, 0x00000000L, // 0
+            0x0601F22AL, 0x280663D4L, 0x2E1B038CL, 0x1E75FCA7L, // 1
+            0x11F09FFAL, 0x162FE23DL, 0x403739B4L, 0x3F2AA531L, // 2
+            0x1DA089E9L, 0x437226E8L, 0x115E99C8L, 0x68C472A6L, // 3
+            0x28EAB25DL, 0x04C51FE2L, 0x13F63FD0L, 0x1E56BF40L, // 4
+            0x33AC2F26L, 0x14FDBA70L, 0x6618880FL, 0x792CE93EL, // 5
+            0x3DC767DCL, 0x4565C95FL, 0x7EAC4790L, 0x163F4D99L, // 6
+            0x4724FC62L, 0x3342C78AL, 0x390873B2L, 0x13A12ACEL, // 7
+            0x4FB448F4L, 0x5229D06DL, 0x09A6C84BL, 0x1D13CB0DL, // 8
+            0x576B8599L, 0x7423407FL, 0x1287EE2FL, 0x7B908556L, // 9
+            0x5E4786DAL, 0x3210BAF6L, 0x6881795CL, 0x13DF4F59L, // 10
+            0x644B2C92L, 0x431B3946L, 0x63F188D9L, 0x22AFB6DEL, // 11
+            0x697E90CEL, 0x77C362C3L, 0x600A627EL, 0x66AEDF96L, // 12
+            0x6DEE0B96L, 0x2798C9CEL, 0x147A98F9L, 0x27427F24L, // 13
+            0x71A92144L, 0x5765FCE4L, 0x0FF04C94L, 0x74183C18L, // 14
+            0x74C16FD5L, 0x1E2A0990L, 0x13EB545FL, 0x1CD9A2ADL, // 15
+            0x7749AC92L, 0x0DF36EEBL, 0x414629E5L, 0x66610A51L, // 16
+            0x7954BFA4L, 0x28079289L, 0x29D5B127L, 0x29B69601L, // 17
+            0x7AF5067AL, 0x2EDC2050L, 0x2B486556L, 0x43BF4664L, // 18
+            0x7C3BC17CL, 0x123D5E7AL, 0x63D4DD26L, 0x3B1E3755L, // 19
+            0x7D38AD76L, 0x2A9381D9L, 0x1D20D034L, 0x77C09C55L, // 20
+            0x7DF9C5DFL, 0x0E868CA7L, 0x23627687L, 0x78864423L, // 21
+            0x7E8B2ABAL, 0x18E5C810L, 0x7C85B42CL, 0x7AC98BCCL, // 22
+            0x7EF7237CL, 0x00908272L, 0x3D4B170EL, 0x3CD572E3L, // 23
+            0x7F4637C5L, 0x6DBA5125L, 0x5B0285ECL, 0x46661EB9L, // 24
+            0x7F7F5707L, 0x4A52EDEBL, 0x50ECECB1L, 0x7384DC42L, // 25
+            0x7FA808CCL, 0x23290598L, 0x704F7A4DL, 0x08532154L, // 26
+            0x7FC4A083L, 0x69BDF2D4L, 0x73B67B27L, 0x3AE237ADL, // 27
+            0x7FD870CAL, 0x42275557L, 0x6F2AE034L, 0x4E4B0395L, // 28
+            0x7FE5FB5DL, 0x3EF82C1BL, 0x256E2EB0L, 0x09E42B11L, // 29
+            0x7FEF1BFAL, 0x6C03A362L, 0x07334BD4L, 0x22B6B15FL, // 30
+            0x7FF52D4EL, 0x316C2C8CL, 0x1C77A4C3L, 0x1C3A974EL, // 31
+            0x7FF927BAL, 0x12AE54AEL, 0x6CC24956L, 0x3BA9A3E4L, // 32
+            0x7FFBBA43L, 0x749CC0E2L, 0x044B3068L, 0x620F14DAL, // 33
+            0x7FFD5E3DL, 0x4524AD91L, 0x31F84A1FL, 0x4D23AF51L, // 34
+            0x7FFE6664L, 0x535785B4L, 0x683C9E5EL, 0x2BD857DFL, // 35
+            0x7FFF0A41L, 0x0B291681L, 0x1CB4CE6FL, 0x32B314B9L, // 36
+            0x7FFF6E81L, 0x132C3D6FL, 0x4C8771CCL, 0x67421A75L, // 37
+            0x7FFFAAFEL, 0x4DBC6BEDL, 0x4E8644D2L, 0x5158A208L, // 38
+            0x7FFFCEFDL, 0x7A1E2D14L, 0x2CF905AAL, 0x79BFABD9L, // 39
+            0x7FFFE41EL, 0x4C6EC115L, 0x2D648F1AL, 0x4B01BA3EL, // 40
+            0x7FFFF059L, 0x319503C8L, 0x2CBEB96AL, 0x52FF656EL, // 41
+            0x7FFFF754L, 0x5DDD0D40L, 0x09D07206L, 0x6BF97EB5L, // 42
+            0x7FFFFB43L, 0x0B9E9822L, 0x5B584BE0L, 0x4974ED83L, // 43
+            0x7FFFFD71L, 0x76B81AE1L, 0x3C93755CL, 0x375F857BL, // 44
+            0x7FFFFEA3L, 0x7E66A1ECL, 0x3E342087L, 0x44ED1696L, // 45
+            0x7FFFFF49L, 0x26F6E190L, 0x7E3625F9L, 0x2F4F5849L, // 46
+            0x7FFFFFA1L, 0x2FA31694L, 0x0D53F684L, 0x59931C0DL, // 47
+            0x7FFFFFCFL, 0x5247BEC8L, 0x5CC20735L, 0x397CE966L, // 48
+            0x7FFFFFE7L, 0x4F4127C6L, 0x64926788L, 0x01CFEF66L, // 49
+            0x7FFFFFF3L, 0x6FAA69FDL, 0x26A67DC3L, 0x1FFA2528L, // 50
+            0x7FFFFFFAL, 0x0630D072L, 0x7AA0C1B7L, 0x7E90AAE6L, // 51
+            0x7FFFFFFDL, 0x0F2957BBL, 0x3ADCE1E6L, 0x5A311C28L, // 52
+            0x7FFFFFFEL, 0x4FD29431L, 0x6429F9EDL, 0x04653965L, // 53
+            0x7FFFFFFFL, 0x2CFAD60DL, 0x52ED82D1L, 0x26455881L, // 54
+            0x7FFFFFFFL, 0x5967A92FL, 0x5C85AB2DL, 0x188033BEL, // 55
+            0x7FFFFFFFL, 0x6E4C9DFEL, 0x76798EAFL, 0x0DC0BA65L, // 56
+            0x7FFFFFFFL, 0x77FDCCC8L, 0x194FF9ACL, 0x2C3FA855L, // 57
+            0x7FFFFFFFL, 0x7C6CE89EL, 0x01FA1A72L, 0x6C3DC40BL, // 58
+            0x7FFFFFFFL, 0x7E6D116EL, 0x5F82B352L, 0x57B67FCEL, // 59
+            0x7FFFFFFFL, 0x7F50FA31L, 0x31856599L, 0x579DC24BL, // 60
+            0x7FFFFFFFL, 0x7FB50089L, 0x43E64BB5L, 0x7F498E42L, // 61
+            0x7FFFFFFFL, 0x7FE04C2CL, 0x56CBFAEFL, 0x7FC9C15FL, // 62
+            0x7FFFFFFFL, 0x7FF2C7C0L, 0x5D509634L, 0x41DCA82BL, // 63
+            0x7FFFFFFFL, 0x7FFA8FE3L, 0x24F6020DL, 0x7B594401L, // 64
+            0x7FFFFFFFL, 0x7FFDCB1BL, 0x2D294BB3L, 0x1D1631BFL, // 65
+            0x7FFFFFFFL, 0x7FFF1DE1L, 0x5D75B704L, 0x323B12FEL, // 66
+            0x7FFFFFFFL, 0x7FFFA6B6L, 0x7E983E86L, 0x23392636L, // 67
+            0x7FFFFFFFL, 0x7FFFDD39L, 0x029CCA2CL, 0x035F7017L, // 68
+            0x7FFFFFFFL, 0x7FFFF2A3L, 0x205DBF7BL, 0x173D7F90L, // 69
+            0x7FFFFFFFL, 0x7FFFFAEFL, 0x3F79145BL, 0x642F005DL, // 70
+            0x7FFFFFFFL, 0x7FFFFE1BL, 0x23B2C7E4L, 0x6CA216CFL, // 71
+            0x7FFFFFFFL, 0x7FFFFF4DL, 0x1E959E3FL, 0x4A29BB03L, // 72
+            0x7FFFFFFFL, 0x7FFFFFBEL, 0x7C23D3D9L, 0x71DC92E4L, // 73
+            0x7FFFFFFFL, 0x7FFFFFE8L, 0x55110485L, 0x0E1813E2L, // 74
+            0x7FFFFFFFL, 0x7FFFFFF7L, 0x5EBC7B7BL, 0x2DFEE922L, // 75
+            0x7FFFFFFFL, 0x7FFFFFFDL, 0x0EDB0975L, 0x0C9F1639L, // 76
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x00DDA1A1L, 0x6DE86AA0L, // 77
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x54CF6D87L, 0x023F1F47L, // 78
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7186FF6AL, 0x5B71BF8CL, // 79
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7B375EBCL, 0x767A89DCL, // 80
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7E70BA89L, 0x44EBCEAAL, // 81
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7F7F98B5L, 0x44C8E44AL, // 82
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FD744C2L, 0x448EE5A4L, // 83
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FF34165L, 0x008855D0L, // 84
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFC1110L, 0x754A60B6L, // 85
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFECD77L, 0x44BE6D4AL, // 86
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFA3F4L, 0x7400A73EL, // 87
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFE4BDL, 0x1143830BL, // 88
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFF809L, 0x1A385059L, // 89
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFDB4L, 0x41CA0794L, // 90
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFF59L, 0x02FFB605L, // 91
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFD1L, 0x18360E8DL, // 92
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFF3L, 0x072A0E9AL, // 93
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFCL, 0x3C1BFEB0L, // 94
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x066EBCDDL, // 95
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x5FBE171AL, // 96
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x778EB81FL, // 97
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7DD211FEL, // 98
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7F71F071L, // 99
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FDC528FL, // 100
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FF7298CL, // 101
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFDD739L, // 102
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFF7ACAL, // 103
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFE056L, // 104
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFF893L, // 105
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFE48L, // 106
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFF9CL, // 107
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFE9L, // 108
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFBL, // 109
+            0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, 0x7FFFFFFFL, // 110
+        };
+
+
+        static void sample_gauss_poly(int nonce, byte[] seed, int seedOffset, long[] poly, int polyOffset)
+        {
+            int dmsp = nonce << 8;
+
+            byte samp[] = new byte[CHUNK_SIZE * CDT_COLS * 4]; // This is int32_t in C, we will treat it as byte[] in java
+            int c[] = new int[CDT_COLS];
+            int borrow, sign;
+            int mask = (-1) >>> 1;
+
+            for (int chunk = 0; chunk < PARAM_N; chunk += CHUNK_SIZE)
+            {
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+                    samp, 0, CHUNK_SIZE * CDT_COLS * 4, (short)dmsp++, seed, seedOffset, CRYPTO_SEEDBYTES);
+
+                for (int i = 0; i < CHUNK_SIZE; i++)
+                {
+                    poly[polyOffset + chunk + i] = 0;
+                    for (int j = 1; j < CDT_ROWS; j++)
+                    {
+                        borrow = 0;
+                        for (int k = CDT_COLS - 1; k >= 0; k--)
+                        {
+                            c[k] = (int)((at(samp, 0, i * CDT_COLS + k) & mask) - (cdt_v[j * CDT_COLS + k] + borrow));
+                            borrow = c[k] >> (RADIX32 - 1);
+                        }
+                        poly[polyOffset + chunk + i] += ~borrow & 1;
+                    }
+                    sign = at(samp, 0, i * CDT_COLS) >> (RADIX32 - 1);
+                    poly[polyOffset + chunk + i] = (sign & -poly[polyOffset + chunk + i]) | (~sign & poly[polyOffset + chunk + i]);
+                }
+
+            }
+
+        }
+    }
+
+    static boolean memoryEqual(byte[] left, int leftOffset, byte[] right, int rightOffset, int length)
+    {
+
+        if ((leftOffset + length <= left.length) && (rightOffset + length <= right.length))
+        {
+
+            for (int i = 0; i < length; i++)
+            {
+
+                if (left[leftOffset + i] != right[rightOffset + i])
+                {
+
+                    return false;
+
+                }
+
+            }
+
+            return true;
+
+        }
+        else
+        {
+
+            return false;
+
+        }
+
+    }
+
+
+    static class QTesla3PPolynomial
+    {
+
+
+        private static final long[] zeta = new long[]{
+            147314272, 762289503, 284789571, 461457674, 723990704, 123382358, 685457283, 458774590, 644795450, 723622678, 441493948, 676062368, 648739792, 214990524, 261899220, 138474554,
+            205277234, 788000393, 541334956, 769530525, 786231394, 812002793, 251385069, 152717354, 674883688, 458756880, 323745289, 823881240, 686340396, 716163820, 107735873, 144028791,
+            586327243, 71257244, 739303131, 487030542, 313626215, 396596783, 664640087, 728258996, 854656117, 567834989, 2315110, 210792230, 795895843, 433034260, 432732757, 480454055,
+            750130006, 47628047, 2271301, 98590211, 729637734, 683553815, 476917424, 121851414, 296210757, 820475433, 403416438, 605633242, 804828963, 435181077, 781182803, 276684653,
+            329135201, 697859430, 248472020, 396579594, 109340098, 97605675, 755271019, 565755143, 534799496, 378374148, 85686225, 298978496, 650100484, 712463562, 818417023, 283716467,
+            269132585, 153024538, 223768950, 331863760, 761523727, 586019306, 805044248, 810909760, 77905343, 401203343, 162625701, 616243024, 659789238, 385270982, 720521140, 545633566,
+            688663167, 740046782, 257189758, 115795491, 101106443, 409863172, 622399622, 405606434, 498832246, 730567206, 350755879, 41236295, 561547732, 525723591, 18655497, 3396399,
+            289694332, 221478904, 738940554, 769726362, 32128402, 693016435, 275431006, 65292213, 601823865, 469363520, 480544944, 607230206, 473150754, 267072604, 463615065, 412972775,
+            197544577, 770873783, 189036815, 407973558, 110878446, 442760341, 667560342, 756992079, 663708407, 585601880, 763637579, 660019224, 424935088, 249313490, 844593983, 664952705,
+            274981537, 40233161, 655530034, 742724096, 8926394, 67709207, 616610795, 539664358, 306118645, 741629065, 283521858, 621397947, 369041534, 162477412, 258256937, 269480966,
+            75469364, 815614830, 724060729, 510819743, 489239410, 265607303, 103024793, 434961090, 474838542, 234701483, 505818866, 450427360, 188113529, 650423376, 599263141, 720479782,
+            755079140, 469798456, 745591660, 432033717, 530128582, 94480771, 722477467, 169342233, 35413255, 89769525, 424389771, 240236288, 360665614, 66702784, 76128663, 565345206,
+            605031892, 393503210, 249841967, 485930917, 45880284, 746120091, 684031522, 537926896, 408749937, 608644803, 692593939, 515424474, 748771159, 155377700, 347101257, 393516280,
+            708186062, 809233270, 562547654, 768251664, 651110951, 574473323, 588028067, 352359235, 646902518, 410726541, 134129459, 460099853, 829152883, 819102028, 7270760, 562515302,
+            419641762, 347973450, 161011009, 401974733, 619807719, 559105457, 276126568, 165473862, 380215069, 356617900, 347744328, 615885981, 824819772, 811367929, 6451967, 515345658,
+            648239021, 56427040, 709160497, 71545092, 390921213, 17177139, 194174898, 825533429, 497469884, 88988508, 64227614, 641021859, 159258883, 529265733, 823190295, 567280997,
+            414094239, 238392498, 695610059, 416342151, 90807038, 206865379, 568337348, 168011486, 844375038, 777332780, 147582038, 199025846, 396231915, 151630666, 466807217, 12672521,
+            570774644, 764098787, 283719496, 779154504, 383628791, 851035387, 395488461, 291115871, 52707730, 776449280, 479801706, 73403989, 402014636, 255214342, 56904698, 446531030,
+            639487570, 848061696, 202732901, 739018922, 653983847, 453022791, 391722680, 584290855, 270911670, 390838431, 653070075, 535876472, 83207555, 131151682, 505677504, 778583044,
+            472363568, 734419459, 768500943, 321131696, 371745445, 751887879, 51797676, 157604159, 838805925, 358099697, 763440819, 776721566, 719570904, 304610785, 656838485, 239522278,
+            796234199, 659506535, 825373307, 674901303, 250484891, 54612517, 410236408, 111976920, 728940855, 720463104, 559960962, 514189554, 637176165, 436151981, 485801800, 802811374,
+            549456481, 808832355, 112672706, 199163132, 807410080, 645955491, 365378122, 222316474, 381896744, 693909930, 402130292, 199856804, 277639257, 6848838, 648262319, 601521139,
+            108516632, 392382841, 563420106, 475932203, 249861415, 99274558, 152886431, 744977783, 269184267, 562674804, 760959275, 733098096, 771348891, 674288361, 631521272, 513632066,
+            476339117, 621937967, 206834230, 507101607, 420341698, 528715580, 853092790, 580174958, 278044321, 432350205, 603769437, 144426940, 733518338, 365468467, 848983278, 385382826,
+            846062026, 593903051, 216589699, 219997638, 350708517, 733669279, 624754239, 499821820, 772548008, 199677439, 287505007, 144199205, 215073292, 825467700, 101591831, 571728784,
+            841898341, 420897808, 61323616, 823475752, 72494861, 89946011, 236594097, 379582577, 539401967, 221244669, 479250487, 100726882, 263096036, 647161225, 491060387, 419890898,
+            816149055, 546441322, 690509770, 215789647, 5870948, 821456387, 294091098, 783700004, 278643020, 520754327, 813718894, 123610053, 157045201, 265331664, 807174256, 258134244,
+            703519669, 300265991, 41892125, 662173055, 439638698, 494124024, 700655120, 535348417, 37146186, 379568907, 644973451, 554904963, 594757858, 477812802, 266085643, 46337543,
+            454847754, 496027901, 701947604, 5722633, 790588605, 233501932, 728956461, 462020148, 214013660, 155806979, 159935426, 423504958, 638889309, 602641304, 277759403, 71654804,
+            710920410, 108337831, 641924564, 252946326, 463082282, 23277660, 142056200, 263317553, 9044238, 367816044, 349695658, 291597086, 230031083, 385106216, 281069679, 644033142,
+            134221740, 212497862, 686686078, 787489098, 781698667, 748299513, 774414792, 380836293, 114027649, 766161763, 10536612, 707355910, 100516219, 637517297, 21478533, 769067854,
+            668364559, 410803198, 64949715, 643421522, 525590993, 585289785, 423839840, 554109325, 450599860, 295350132, 435789550, 306634115, 611298620, 777817576, 553655202, 804525538,
+            794474290, 138542076, 780958763, 62228371, 738032107, 684994110, 661486955, 67099069, 68865906, 32413094, 358393763, 205008770, 849715545, 289798348, 384767209, 787328590,
+            823677120, 47455925, 706001331, 612392717, 487804928, 731804935, 520572665, 442307581, 351275150, 726042356, 667657829, 254929787, 459520026, 625393223, 319307882, 77267096,
+            815224795, 335964550, 408353208, 604252110, 574953308, 563501897, 515015302, 313600371, 178773384, 417549087, 510834475, 167049599, 488791556, 664276219, 82933775, 822541833,
+            17111190, 409659978, 96304098, 500484311, 269766378, 327037310, 584926256, 538611363, 404132255, 170931824, 744460626, 154011192, 322194096, 215888234, 258344560, 702851111,
+            192046250, 738511820, 530780560, 57197515, 335425579, 410968369, 830078545, 448351649, 208921555, 356653676, 718038774, 424362596, 158929491, 420096666, 387056270, 797383293,
+            381201911, 466480709, 373815662, 84912008, 4969808, 524614597, 93448903, 559481007, 400813998, 665223025, 601707338, 466022707, 192709574, 615503265, 822863744, 639854175,
+            158713505, 12757666, 389196370, 823105438, 682974863, 468401586, 93508626, 402414043, 806357152, 180544963, 27876186, 321527031, 329857607, 669501423, 829809824, 333202822,
+            106923493, 368991112, 282317903, 790323774, 517381333, 548329656, 236147848, 700119793, 404187488, 343578810, 798813301, 497964535, 656188346, 678161787, 736817175, 518031339,
+            716647183, 674797219, 308643560, 714308544, 516103468, 605229646, 564549717, 47650358, 706404486, 494887760, 152496104, 54954356, 271435602, 76951527, 136123931, 601823638,
+            329273401, 252710411, 754980731, 351648254, 49239731, 837833233, 88830509, 598216539, 155534490, 669603727, 418388693, 79322074, 636251444, 703683994, 796989459, 126497707,
+            644863316, 730359063, 265213001, 64483814, 552208981, 8135537, 782474322, 780853310, 733976806, 395661138, 128188419, 266691358, 407092046, 447349747, 526245954, 119272088,
+            359659635, 812410956, 669835517, 565139408, 248981831, 139910745, 685462294, 406991131, 709944045, 589819925, 714299787, 72923680, 648836181, 145321778, 392775383, 243093077,
+            412955839, 174619485, 310936394, 699727061, 421087619, 745421519, 539546394, 29471558, 116471631, 852650639, 443777703, 773131303, 81618669, 756719012, 702785073, 847088653,
+            851830586, 300908692, 430974543, 463215976, 668971423, 414271988, 108350516, 345933325, 716417649, 174980945, 679092437, 384030489, 814050910, 506580116, 249434097, 178438885,
+            146797119, 10369463, 296359082, 215645133, 149545847, 483689845, 322009569, 308978588, 38531178, 328571637, 815396967, 709744233, 765487128, 645413104, 564779557, 213794315,
+            280607549, 124792697, 423470554, 631348430, 21223627, 220718413, 598791979, 47797633, 734556299, 590321944, 168292920, 484802055, 340999812, 769601438, 42675060, 116026587,
+            227462622, 543574607, 444066479, 467277895, 278798674, 597413704, 350168725, 301936652, 82885511, 656047519, 765110538, 52228202, 533005731, 621989298, 148235931, 317833915,
+            118463894, 522391939, 451332724, 548031654, 73854149, 527786213, 583308898, 840663438, 275278054, 362931963, 587861579, 830807449, 431695707, 178004048, 75513216, 60681147,
+            638603143, 470791469, 490903319, 527370962, 102981857, 224220555, 756514239, 293859807, 797926303, 620196520, 466126507, 646136763, 265504163, 213257337, 92270416, 398713724,
+            91810366, 724247342, 855386762, 631553083, 376095634, 833728623, 636218061, 510719408, 378530670, 737821436, 127781731, 3443282, 770116208, 769633348, 430675947, 40370755,
+            52361322, 844601468, 442556599, 128290354, 494328514, 405616679, 651440882, 421541290, 171560170, 386143493, 284277254, 450756213, 248305939, 526718005, 300780198, 714218239,
+            68021827, 527353904, 236472015, 309320156, 683815803, 527980097, 598849444, 779607597, 339852811, 845420163, 96001931, 326760873, 609319751, 520803868, 140143851, 766988701,
+            844896794, 532008178, 388459130, 574799295, 760406065, 773758517, 453271555, 134636434, 155747417, 105505251, 796987277, 399016325, 71156680, 709579308, 274279004, 96962867,
+            476741915, 585319990, 709143538, 721328791, 293159344, 640577897, 138404614, 572892015, 394460832, 465897068, 325895331, 413861636, 447337182, 376950267, 721061932, 181671909,
+            272138750, 247768905, 634973622, 280653872, 165108426, 134241779, 15142090, 153256717, 783424845, 773227607, 172477802, 504458250, 349868083, 461422806, 487725644, 586146740,
+            561546455, 815406759, 468110471, 126476456, 285774551, 522013234, 801943660, 79684345, 654558548, 188038414, 249923934, 551812615, 562560206, 407120348, 384535446, 176837117,
+            433155458, 82591339, 459412819, 435604627, 312211805, 98158590, 752137480, 446017293, 666480139, 60261988, 275386848, 642778031, 8582401, 677484160, 819506256, 333441964,
+            25465219, 190315429, 91529631, 754681170, 563660271, 167135649, 20270015, 115773732, 658954441, 132923202, 844102455, 453432758, 250487209, 423813160, 632223296, 537494486,
+            158265753, 327949044, 494109748, 659672289, 67984726, 422358258, 345141182, 164372996, 338500924, 41400311, 207638305, 832074651, 50853458, 228267776, 621895888, 635834787,
+            484972544, 181125024, 558134871, 282159878, 788157855, 145576343, 194837894, 501440949, 63641414, 252098681, 835930645, 662856247, 456140980, 206147937, 565198503, 449503819,
+            684013129, 494002381, 793836418, 649296754, 444313288, 136544068, 540002286, 355912945, 613175147, 134541429, 843111781, 672612536, 541098995, 734996181, 211869705, 620777828,
+            756152791, 242128346, 795442420, 73925532, 735232214, 738668090, 530800757, 266183732, 97165934, 803231879, 10057267, 175942047, 181460965, 320684297, 637472526, 213840116,
+            182671953, 152704513, 388004388, 597349323, 473851493, 445333546, 679315863, 267078568, 46538491, 530171754, 698082287, 75308587, 266467406, 96440883, 759196579, 470119952,
+            381731475, 428392158, 10628712, 173921356, 116809433, 323843928, 812172630, 403459283, 655501128, 261944441, 774418023, 790520709, 589149480, 264133112, 806274256, 752372117,
+            66236193, 713859568, 90804933, 551864345, 843839891, 600244073, 719230074, 803646506, 254956426, 138935723, 738829647, 109576220, 105819621, 249706947, 110623114, 10002331,
+            795710911, 547062229, 721440199, 820747461, 397666160, 685179945, 463869301, 470338753, 641244231, 652990696, 698429485, 41147155, 638072709, 515832968, 241130026, 314161759,
+            526815813, 529167244, 53391331, 782008115, 822962086, 337706389, 648197286, 209496506, 760818531, 781900302, 717270807, 709143641, 740503641, 734328409, 514061476, 844010670,
+            67993787, 712083588, 319801387, 338260400, 48758556, 304195768, 478833380, 841413917, 710197685, 196321647, 777595184, 775983866, 147506314, 620961439, 399972264, 398715644,
+            684489092, 659918078, 664075287, 723890579, 643103903, 508525962, 375409248, 501237729, 740609783, 639854810, 510797913, 521151016, 421045341, 193698327, 800266392, 93518128,
+            443879633, 699245445, 194001794, 123905867, 75572337, 242620749, 463111940, 755239011, 31718790, 162155292, 386689240, 381413538, 745322913, 367897558, 343088005, 31706107,
+            10842029, 404961623, 537521191, 281624684, 372852160, 55286017, 534907560, 264398082, 667644310, 486871690, 716964533, 734731419, 143593638, 293949413, 760014789, 594443755,
+            147804127, 537704286, 460110740, 596458323, 577775570, 333025386, 260094086, 711487611, 359384182, 323339045, 716675075, 248179763, 525311626, 76326208, 559009987, 548139736,
+            541721430, 31450329, 653923741, 676193285, 295171241, 558845563, 387079118, 403184480, 807941436, 501042343, 284608894, 705710380, 82388415, 763336555, 126077422, 438548854,
+            606252517, 144569238, 126964439, 809559381, 263253751, 547929033, 236704198, 377978058, 59501955, 749500335, 254242336, 605755194, 408388953, 116242711, 116340056, 691021496,
+            48100285, 371076069, 638156108, 211570763, 185945242, 653505761, 667569173, 335131755, 736662207, 572078378, 755939949, 840393623, 322934679, 520522390, 252068808, 491370519,
+            200565770, 552637112, 182345569, 394747039, 822229467, 817698102, 644484388, 156591766, 729600982, 695826242, 509682463, 785132583, 746139100, 188369785, 628995003, 406654440,
+            650660075, 676485042, 540766742, 493428142, 753346328, 82608613, 670846442, 145894970, 770907988, 621807160, 14676199, 793865193, 36579515, 619741404, 303691972, 794920577,
+            134684826, 190038753, 538889970, 836657477, 643017556, 316870164, 464572481, 305395359, 446406992, 587814221, 423552502, 122802120, 146043780, 173756097, 130720237, 445515559,
+            109884833, 133119099, 804139234, 834841519, 458514524, 74213698, 490363622, 119287122, 165016718, 351506713, 433750226, 439149867, 348281119, 319795826, 320785867, 446561207,
+            705678831, 714536161, 172299381, 552925586, 635421942, 851853231, 208071525, 142303096, 93164236, 207534795, 655906672, 558127940, 98870558, 388322132, 87475979, 835970665,
+            61996500, 298060757, 256194194, 563529863, 249184704, 451295997, 73892211, 559049908, 44006160, 832886345, 720732161, 255948582, 827295342, 629663637, 323103159, 155698755,
+            598913314, 586685341, 761273875, 135225209, 324099714, 391112815, 493469140, 796490769, 667498514, 148390126, 721802249, 781884558, 309264043, 603401759, 503111668, 563611748,
+            363342598, 383209405, 108340736, 758017880, 145907493, 312330194, 608895549, 45540348, 143092704, 772401556, 806068040, 853177536, 662120004, 463347842, 495085709, 560431884,
+            274002454, 76985308, 519320299, 253092838, 727478114, 593752634, 490277266, 206283832, 701277908, 504787112, 816832531, 730997507, 27807749, 58254704, 584933136, 515463756,
+            241104222, 251881934, 566567573, 592887586, 528932268, 88111104, 523103099, 448331392, 351083975, 157811347, 758866581, 802151021, 843579185, 481417280, 507414106, 462708367,
+            461501222, 790988186, 462220673, 727683888, 159759683, 59757110, 310746434, 326369241, 305829588, 457718309, 529317279, 503631310, 661769334, 343160359, 472216278, 740498212,
+            11312284, 760170115, 513391009, 538224236, 710934956, 491998229, 539829044, 610387964, 86624968, 72542777, 493966272, 132327984, 371526334, 182549152, 51622114, 173997077,
+            550633787, 205437301, 435219235, 406409162, 414751325, 33371226, 40899348, 77245052, 763383124, 817701136, 598256078, 357440859, 468418959, 353612800, 721601331, 262567156,
+            521577430, 232027892, 75986872, 443113391, 107360999, 482079354, 563502258, 782475535, 402866161, 515580626, 742688144, 677398836, 425899303, 42066550, 537192943, 430672016,
+            115368023, 64053241, 92008456, 74327791, 572607165, 681138002, 378104858, 695786430, 844827190, 436817825, 751393351, 142965259, 81300919, 688342617, 433082724, 221191094,
+            712003270, 301076404, 747091407, 514191589, 814985450, 260951422, 187161058, 22316970, 806106670, 759397054, 158423624, 419813636, 462241316, 438231460, 108466764, 212745115,
+            386264342, 176072326, 767127195, 399981627, 762991681, 173125691, 464627163, 770046798, 179369718, 829917528, 693004603, 178596003, 422852852, 182684967, 662425026, 713404098,
+            766206683, 130088738, 321282752, 134898541, 86701214, 120555423, 464987852, 82865891, 758340585, 138256323, 308997895, 659614345, 510091933, 822699180, 464631718, 819896232,
+            120792059, 160708255, 462868879, 72974246, 260451492, 120601343, 228097712, 369436704, 155304088, 74380537, 732305166, 203294189, 307421597, 96510570, 634243454, 486539430,
+            16204477, 241987531, 317824421, 510180366, 794475492, 262770124, 441034891, 741864347, 205569410, 684844547, 340863522, 440616421, 454438375, 26285496, 141886125, 648947081,
+            3791510, 529746935, 317826713, 411458050, 661690316, 45696331, 679684665, 184597094, 829228068, 375683582, 591739456, 855242340, 628594662, 30968619, 363932244, 103091463,
+            614269714, 465960778, 791477766, 332731888, 853151007, 266045534, 132189407, 435008168, 65667470, 669304246, 760035868, 481409581, 36650645, 523634336, 702968013, 351902214,
+            284360680, 34261165, 593134528, 337534074, 239112910, 710342799, 163287447, 20209506, 780785984, 480727309, 125776519, 691236193, 603228570, 48261672, 183120677, 73638683,
+            3430616, 568026489, 808739797, 298585898, 64471573, 724550960, 568093636, 187449517, 655699449, 672689645, 829049456, 263525899, 612969883, 621652807, 186362075, 731851539,
+            377104257, 39335761, 210768226, 253965025, 201921517, 715681274, 369453531, 18897741, 612559390, 660723864, 476963596, 585483298, 318614839, 227626072, 298891387, 110505944,
+            814885802, 177563961, 443724544, 374856237, 577963338, 617516835, 475669105, 633353115, 12579943, 796644307, 569746680, 22381253, 343603333, 724567543, 845363898, 4023795,
+            801359177, 347489967, 214644600, 78674056, 131782857, 284041623, 660502381, 161470286, 668158595, 765738294, 715872268, 678418089, 280458288, 758715787, 9311288, 490771912,
+            757112000, 253990619, 698573830, 390611635, 52593584, 421202448, 494394112, 386893540, 29349323, 533111491, 774401558, 108660117, 405990553, 143728136, 852741683, 354532633,
+            440222591, 663461253, 593338391, 298882952, 758170600, 660294062, 332348846, 541714172, 77716403, 169377728, 71932929, 110210904, 776771173, 645222398, 162195941, 792388932,
+            502165627, 146897021, 243625970, 139123400, 462352793, 409369440, 247509680, 270865496, 539140627, 16949766, 245869282, 637926655, 37386603, 383033875, 316560876, 707909555,
+            367315004, 173821041, 529529257, 227507318, 831716891, 830055847, 228911074, 205127100, 178872273, 819938491, 129875615, 764680417, 97028082, 560682982, 433649390, 727508847,
+            494848582, 81279272, 435186566, 174468080, 69172161, 241860102, 692179355, 333985572, 788895276, 469576414, 594155471, 157828532, 182105752, 310394758, 673085082, 695719789,
+            39004854, 251000641, 98748282, 744318650, 815050298, 622456803, 240419561, 403871914, 202214044, 627433637, 649505808, 668918393, 334630440, 386856024, 352649543, 135139523,
+            216499252, 736376783, 269223150, 468318208, 801808348, 180378366, 640086372, 672618369, 291378195, 732195369, 805632553, 518515631, 603280165, 629836417, 59712833, 531020081,
+            708771168, 539819295, 179149444, 552251927, 458994127, 584987693, 238644928, 640603619, 46728500, 843989005, 688747457, 236924093, 261539965, 705411056, 765907765, 38095657,
+            382461698, 146650814, 351462947, 749417520, 628887925, 800857475, 790554154, 695483946, 160495923, 40896482, 471385785, 535516195, 197056285, 622795937, 368016917, 696525353,
+            377315918, 58087122, 246518254, 431338589, 795949654, 611141265, 406307405, 365750089, 396243561, 843849531, 33802729, 573076974, 557841126, 411725124, 109489622, 370935707,
+            372610558, 769825999, 367932152, 231499145, 240819898, 22648665, 418344529, 142438794, 552806180, 669450690, 614608056, 784369586, 258710636, 474742428, 166021530, 805595815,
+            603578176, 686703780, 412868426, 26588048, 379895115, 77550061, 751188758, 294447541, 433574579, 234362222, 821492181, 23912038, 681093196, 483584545, 404339808, 396405029,
+            744756742, 702481685, 413127074, 204115019, 187381271, 633523978, 433629465, 628184183, 783160918, 268799033, 646479372, 160458176, 602612912, 644506365, 391554011, 676966578,
+            386430153, 98736426, 412745127, 296141927, 685909285, 355152260, 361415843, 127323093, 586337666, 1734791, 368678692, 155431915, 597290023, 109507713, 291804866, 135016081,
+            144077689, 35054937, 16808265, 431962815, 534195521, 629326143, 309352001, 319948849, 443083246, 336744161, 100845182, 314804947, 476736581, 468528479, 416978018, 35141019,
+            43314058, 384847955, 665126798, 295857628, 768013680, 741182796, 157855570, 695547618, 145251639, 818473396, 708640763, 87460130, 736400748, 465173936, 376720282, 437268868,
+            137236663, 693860377, 247960644, 402124416, 656418852, 231401654, 248187016, 628418583, 224261112, 120581342, 49749199, 588812480, 309599954, 111357387, 14507354, 754564049,
+            513444423, 816496110, 509193085, 361635970, 190608265, 697367838, 230953561, 140447357, 27745100, 163340427, 607823059, 325305463, 383028479, 269707244, 475022415, 708990989,
+            738971809, 797646021, 126610937, 589310701, 191123172, 819715815, 337443183, 432224976, 337343783, 257301390, 172631141, 560659319, 646332329, 55110483, 467212803, 442977895,
+            311159578, 569890333, 669396086, 536323022, 542648615, 366162176, 88951009, 408335586, 276237497, 384733042, 525960156, 74199534, 338209206, 676233089, 264342641, 241682204,
+            226505461, 165013960, 129858819, 664852498, 432090291, 165700308, 382150900, 537002255, 368893910, 61006155, 238726881, 92317627, 632392147, 404715651, 802622348, 126100061,
+            306024238, 397891265, 214661020, 211132870, 783722518, 149847645, 665379914, 624725195, 85864665, 496272723, 304811252, 29995710, 410500887, 756406394, 31206753, 647154006,
+            596539568, 783214792, 286381882, 24560691, 681500270, 774933112, 506538708, 850347997, 611696036, 512607061, 251719669, 367108021, 456442965, 636694730, 399940257, 73870039,
+            85190759, 264953709, 238854238, 395048514, 612738126, 27417876, 652695826, 188238483, 324168828, 736238139, 789061724, 529275445, 382304068, 176318391, 709989466, 14237691,
+        };
+
+        private static final long[] zetainv = new long[]{
+            146156455, 679827530, 473841853, 326870476, 67084197, 119907782, 531977093, 667907438, 203450095, 828728045, 243407795, 461097407, 617291683, 591192212, 770955162, 782275882,
+            456205664, 219451191, 399702956, 489037900, 604426252, 343538860, 244449885, 5797924, 349607213, 81212809, 174645651, 831585230, 569764039, 72931129, 259606353, 208991915,
+            824939168, 99739527, 445645034, 826150211, 551334669, 359873198, 770281256, 231420726, 190766007, 706298276, 72423403, 645013051, 641484901, 458254656, 550121683, 730045860,
+            53523573, 451430270, 223753774, 763828294, 617419040, 795139766, 487252011, 319143666, 473995021, 690445613, 424055630, 191293423, 726287102, 691131961, 629640460, 614463717,
+            591803280, 179912832, 517936715, 781946387, 330185765, 471412879, 579908424, 447810335, 767194912, 489983745, 313497306, 319822899, 186749835, 286255588, 544986343, 413168026,
+            388933118, 801035438, 209813592, 295486602, 683514780, 598844531, 518802138, 423920945, 518702738, 36430106, 665022749, 266835220, 729534984, 58499900, 117174112, 147154932,
+            381123506, 586438677, 473117442, 530840458, 248322862, 692805494, 828400821, 715698564, 625192360, 158778083, 665537656, 494509951, 346952836, 39649811, 342701498, 101581872,
+            841638567, 744788534, 546545967, 267333441, 806396722, 735564579, 631884809, 227727338, 607958905, 624744267, 199727069, 454021505, 608185277, 162285544, 718909258, 418877053,
+            479425639, 390971985, 119745173, 768685791, 147505158, 37672525, 710894282, 160598303, 698290351, 114963125, 88132241, 560288293, 191019123, 471297966, 812831863, 821004902,
+            439167903, 387617442, 379409340, 541340974, 755300739, 519401760, 413062675, 536197072, 546793920, 226819778, 321950400, 424183106, 839337656, 821090984, 712068232, 721129840,
+            564341055, 746638208, 258855898, 700714006, 487467229, 854411130, 269808255, 728822828, 494730078, 500993661, 170236636, 560003994, 443400794, 757409495, 469715768, 179179343,
+            464591910, 211639556, 253533009, 695687745, 209666549, 587346888, 72985003, 227961738, 422516456, 222621943, 668764650, 652030902, 443018847, 153664236, 111389179, 459740892,
+            451806113, 372561376, 175052725, 832233883, 34653740, 621783699, 422571342, 561698380, 104957163, 778595860, 476250806, 829557873, 443277495, 169442141, 252567745, 50550106,
+            690124391, 381403493, 597435285, 71776335, 241537865, 186695231, 303339741, 713707127, 437801392, 833497256, 615326023, 624646776, 488213769, 86319922, 483535363, 485210214,
+            746656299, 444420797, 298304795, 283068947, 822343192, 12296390, 459902360, 490395832, 449838516, 245004656, 60196267, 424807332, 609627667, 798058799, 478830003, 159620568,
+            488129004, 233349984, 659089636, 320629726, 384760136, 815249439, 695649998, 160661975, 65591767, 55288446, 227257996, 106728401, 504682974, 709495107, 473684223, 818050264,
+            90238156, 150734865, 594605956, 619221828, 167398464, 12156916, 809417421, 215542302, 617500993, 271158228, 397151794, 303893994, 676996477, 316326626, 147374753, 325125840,
+            796433088, 226309504, 252865756, 337630290, 50513368, 123950552, 564767726, 183527552, 216059549, 675767555, 54337573, 387827713, 586922771, 119769138, 639646669, 721006398,
+            503496378, 469289897, 521515481, 187227528, 206640113, 228712284, 653931877, 452274007, 615726360, 233689118, 41095623, 111827271, 757397639, 605145280, 817141067, 160426132,
+            183060839, 545751163, 674040169, 698317389, 261990450, 386569507, 67250645, 522160349, 163966566, 614285819, 786973760, 681677841, 420959355, 774866649, 361297339, 128637074,
+            422496531, 295462939, 759117839, 91465504, 726270306, 36207430, 677273648, 651018821, 627234847, 26090074, 24429030, 628638603, 326616664, 682324880, 488830917, 148236366,
+            539585045, 473112046, 818759318, 218219266, 610276639, 839196155, 317005294, 585280425, 608636241, 446776481, 393793128, 717022521, 612519951, 709248900, 353980294, 63756989,
+            693949980, 210923523, 79374748, 745935017, 784212992, 686768193, 778429518, 314431749, 523797075, 195851859, 97975321, 557262969, 262807530, 192684668, 415923330, 501613288,
+            3404238, 712417785, 450155368, 747485804, 81744363, 323034430, 826796598, 469252381, 361751809, 434943473, 803552337, 465534286, 157572091, 602155302, 99033921, 365374009,
+            846834633, 97430134, 575687633, 177727832, 140273653, 90407627, 187987326, 694675635, 195643540, 572104298, 724363064, 777471865, 641501321, 508655954, 54786744, 852122126,
+            10782023, 131578378, 512542588, 833764668, 286399241, 59501614, 843565978, 222792806, 380476816, 238629086, 278182583, 481289684, 412421377, 678581960, 41260119, 745639977,
+            557254534, 628519849, 537531082, 270662623, 379182325, 195422057, 243586531, 837248180, 486692390, 140464647, 654224404, 602180896, 645377695, 816810160, 479041664, 124294382,
+            669783846, 234493114, 243176038, 592620022, 27096465, 183456276, 200446472, 668696404, 288052285, 131594961, 791674348, 557560023, 47406124, 288119432, 852715305, 782507238,
+            673025244, 807884249, 252917351, 164909728, 730369402, 375418612, 75359937, 835936415, 692858474, 145803122, 617033011, 518611847, 263011393, 821884756, 571785241, 504243707,
+            153177908, 332511585, 819495276, 374736340, 96110053, 186841675, 790478451, 421137753, 723956514, 590100387, 2994914, 523414033, 64668155, 390185143, 241876207, 753054458,
+            492213677, 825177302, 227551259, 903581, 264406465, 480462339, 26917853, 671548827, 176461256, 810449590, 194455605, 444687871, 538319208, 326398986, 852354411, 207198840,
+            714259796, 829860425, 401707546, 415529500, 515282399, 171301374, 650576511, 114281574, 415111030, 593375797, 61670429, 345965555, 538321500, 614158390, 839941444, 369606491,
+            221902467, 759635351, 548724324, 652851732, 123840755, 781765384, 700841833, 486709217, 628048209, 735544578, 595694429, 783171675, 393277042, 695437666, 735353862, 36249689,
+            391514203, 33446741, 346053988, 196531576, 547148026, 717889598, 97805336, 773280030, 391158069, 735590498, 769444707, 721247380, 534863169, 726057183, 89939238, 142741823,
+            193720895, 673460954, 433293069, 677549918, 163141318, 26228393, 676776203, 86099123, 391518758, 683020230, 93154240, 456164294, 89018726, 680073595, 469881579, 643400806,
+            747679157, 417914461, 393904605, 436332285, 697722297, 96748867, 50039251, 833828951, 668984863, 595194499, 41160471, 341954332, 109054514, 555069517, 144142651, 634954827,
+            423063197, 167803304, 774845002, 713180662, 104752570, 419328096, 11318731, 160359491, 478041063, 175007919, 283538756, 781818130, 764137465, 792092680, 740777898, 425473905,
+            318952978, 814079371, 430246618, 178747085, 113457777, 340565295, 453279760, 73670386, 292643663, 374066567, 748784922, 413032530, 780159049, 624118029, 334568491, 593578765,
+            134544590, 502533121, 387726962, 498705062, 257889843, 38444785, 92762797, 778900869, 815246573, 822774695, 441394596, 449736759, 420926686, 650708620, 305512134, 682148844,
+            804523807, 673596769, 484619587, 723817937, 362179649, 783603144, 769520953, 245757957, 316316877, 364147692, 145210965, 317921685, 342754912, 95975806, 844833637, 115647709,
+            383929643, 512985562, 194376587, 352514611, 326828642, 398427612, 550316333, 529776680, 545399487, 796388811, 696386238, 128462033, 393925248, 65157735, 394644699, 393437554,
+            348731815, 374728641, 12566736, 53994900, 97279340, 698334574, 505061946, 407814529, 333042822, 768034817, 327213653, 263258335, 289578348, 604263987, 615041699, 340682165,
+            271212785, 797891217, 828338172, 125148414, 39313390, 351358809, 154868013, 649862089, 365868655, 262393287, 128667807, 603053083, 336825622, 779160613, 582143467, 295714037,
+            361060212, 392798079, 194025917, 2968385, 50077881, 83744365, 713053217, 810605573, 247250372, 543815727, 710238428, 98128041, 747805185, 472936516, 492803323, 292534173,
+            353034253, 252744162, 546881878, 74261363, 134343672, 707755795, 188647407, 59655152, 362676781, 465033106, 532046207, 720920712, 94872046, 269460580, 257232607, 700447166,
+            533042762, 226482284, 28850579, 600197339, 135413760, 23259576, 812139761, 297096013, 782253710, 404849924, 606961217, 292616058, 599951727, 558085164, 794149421, 20175256,
+            768669942, 467823789, 757275363, 298017981, 200239249, 648611126, 762981685, 713842825, 648074396, 4292690, 220723979, 303220335, 683846540, 141609760, 150467090, 409584714,
+            535360054, 536350095, 507864802, 416996054, 422395695, 504639208, 691129203, 736858799, 365782299, 781932223, 397631397, 21304402, 52006687, 723026822, 746261088, 410630362,
+            725425684, 682389824, 710102141, 733343801, 432593419, 268331700, 409738929, 550750562, 391573440, 539275757, 213128365, 19488444, 317255951, 666107168, 721461095, 61225344,
+            552453949, 236404517, 819566406, 62280728, 841469722, 234338761, 85237933, 710250951, 185299479, 773537308, 102799593, 362717779, 315379179, 179660879, 205485846, 449491481,
+            227150918, 667776136, 110006821, 71013338, 346463458, 160319679, 126544939, 699554155, 211661533, 38447819, 33916454, 461398882, 673800352, 303508809, 655580151, 364775402,
+            604077113, 335623531, 533211242, 15752298, 100205972, 284067543, 119483714, 521014166, 188576748, 202640160, 670200679, 644575158, 217989813, 485069852, 808045636, 165124425,
+            739805865, 739903210, 447756968, 250390727, 601903585, 106645586, 796643966, 478167863, 619441723, 308216888, 592892170, 46586540, 729181482, 711576683, 249893404, 417597067,
+            730068499, 92809366, 773757506, 150435541, 571537027, 355103578, 48204485, 452961441, 469066803, 297300358, 560974680, 179952636, 202222180, 824695592, 314424491, 308006185,
+            297135934, 779819713, 330834295, 607966158, 139470846, 532806876, 496761739, 144658310, 596051835, 523120535, 278370351, 259687598, 396035181, 318441635, 708341794, 261702166,
+            96131132, 562196508, 712552283, 121414502, 139181388, 369274231, 188501611, 591747839, 321238361, 800859904, 483293761, 574521237, 318624730, 451184298, 845303892, 824439814,
+            513057916, 488248363, 110823008, 474732383, 469456681, 693990629, 824427131, 100906910, 393033981, 613525172, 780573584, 732240054, 662144127, 156900476, 412266288, 762627793,
+            55879529, 662447594, 435100580, 334994905, 345348008, 216291111, 115536138, 354908192, 480736673, 347619959, 213042018, 132255342, 192070634, 196227843, 171656829, 457430277,
+            456173657, 235184482, 708639607, 80162055, 78550737, 659824274, 145948236, 14732004, 377312541, 551950153, 807387365, 517885521, 536344534, 144062333, 788152134, 12135251,
+            342084445, 121817512, 115642280, 147002280, 138875114, 74245619, 95327390, 646649415, 207948635, 518439532, 33183835, 74137806, 802754590, 326978677, 329330108, 541984162,
+            615015895, 340312953, 218073212, 814998766, 157716436, 203155225, 214901690, 385807168, 392276620, 170965976, 458479761, 35398460, 134705722, 309083692, 60435010, 846143590,
+            745522807, 606438974, 750326300, 746569701, 117316274, 717210198, 601189495, 52499415, 136915847, 255901848, 12306030, 304281576, 765340988, 142286353, 789909728, 103773804,
+            49871665, 592012809, 266996441, 65625212, 81727898, 594201480, 200644793, 452686638, 43973291, 532301993, 739336488, 682224565, 845517209, 427753763, 474414446, 386025969,
+            96949342, 759705038, 589678515, 780837334, 158063634, 325974167, 809607430, 589067353, 176830058, 410812375, 382294428, 258796598, 468141533, 703441408, 673473968, 642305805,
+            218673395, 535461624, 674684956, 680203874, 846088654, 52914042, 758979987, 589962189, 325345164, 117477831, 120913707, 782220389, 60703501, 614017575, 99993130, 235368093,
+            644276216, 121149740, 315046926, 183533385, 13034140, 721604492, 242970774, 500232976, 316143635, 719601853, 411832633, 206849167, 62309503, 362143540, 172132792, 406642102,
+            290947418, 649997984, 400004941, 193289674, 20215276, 604047240, 792504507, 354704972, 661308027, 710569578, 67988066, 573986043, 298011050, 675020897, 371173377, 220311134,
+            234250033, 627878145, 805292463, 24071270, 648507616, 814745610, 517644997, 691772925, 511004739, 433787663, 788161195, 196473632, 362036173, 528196877, 697880168, 318651435,
+            223922625, 432332761, 605658712, 402713163, 12043466, 723222719, 197191480, 740372189, 835875906, 689010272, 292485650, 101464751, 764616290, 665830492, 830680702, 522703957,
+            36639665, 178661761, 847563520, 213367890, 580759073, 795883933, 189665782, 410128628, 104008441, 757987331, 543934116, 420541294, 396733102, 773554582, 422990463, 679308804,
+            471610475, 449025573, 293585715, 304333306, 606221987, 668107507, 201587373, 776461576, 54202261, 334132687, 570371370, 729669465, 388035450, 40739162, 294599466, 269999181,
+            368420277, 394723115, 506277838, 351687671, 683668119, 82918314, 72721076, 702889204, 841003831, 721904142, 691037495, 575492049, 221172299, 608377016, 584007171, 674474012,
+            135083989, 479195654, 408808739, 442284285, 530250590, 390248853, 461685089, 283253906, 717741307, 215568024, 562986577, 134817130, 147002383, 270825931, 379404006, 759183054,
+            581866917, 146566613, 784989241, 457129596, 59158644, 750640670, 700398504, 721509487, 402874366, 82387404, 95739856, 281346626, 467686791, 324137743, 11249127, 89157220,
+            716002070, 335342053, 246826170, 529385048, 760143990, 10725758, 516293110, 76538324, 257296477, 328165824, 172330118, 546825765, 619673906, 328792017, 788124094, 141927682,
+            555365723, 329427916, 607839982, 405389708, 571868667, 470002428, 684585751, 434604631, 204705039, 450529242, 361817407, 727855567, 413589322, 11544453, 803784599, 815775166,
+            425469974, 86512573, 86029713, 852702639, 728364190, 118324485, 477615251, 345426513, 219927860, 22417298, 480050287, 224592838, 759159, 131898579, 764335555, 457432197,
+            763875505, 642888584, 590641758, 210009158, 390019414, 235949401, 58219618, 562286114, 99631682, 631925366, 753164064, 328774959, 365242602, 385354452, 217542778, 795464774,
+            780632705, 678141873, 424450214, 25338472, 268284342, 493213958, 580867867, 15482483, 272837023, 328359708, 782291772, 308114267, 404813197, 333753982, 737682027, 538312006,
+            707909990, 234156623, 323140190, 803917719, 91035383, 200098402, 773260410, 554209269, 505977196, 258732217, 577347247, 388868026, 412079442, 312571314, 628683299, 740119334,
+            813470861, 86544483, 515146109, 371343866, 687853001, 265823977, 121589622, 808348288, 257353942, 635427508, 834922294, 224797491, 432675367, 731353224, 575538372, 642351606,
+            291366364, 210732817, 90658793, 146401688, 40748954, 527574284, 817614743, 547167333, 534136352, 372456076, 706600074, 640500788, 559786839, 845776458, 709348802, 677707036,
+            606711824, 349565805, 42095011, 472115432, 177053484, 681164976, 139728272, 510212596, 747795405, 441873933, 187174498, 392929945, 425171378, 555237229, 4315335, 9057268,
+            153360848, 99426909, 774527252, 83014618, 412368218, 3495282, 739674290, 826674363, 316599527, 110724402, 435058302, 156418860, 545209527, 681526436, 443190082, 613052844,
+            463370538, 710824143, 207309740, 783222241, 141846134, 266325996, 146201876, 449154790, 170683627, 716235176, 607164090, 291006513, 186310404, 43734965, 496486286, 736873833,
+            329899967, 408796174, 449053875, 589454563, 727957502, 460484783, 122169115, 75292611, 73671599, 848010384, 303936940, 791662107, 590932920, 125786858, 211282605, 729648214,
+            59156462, 152461927, 219894477, 776823847, 437757228, 186542194, 700611431, 257929382, 767315412, 18312688, 806906190, 504497667, 101165190, 603435510, 526872520, 254322283,
+            720021990, 779194394, 584710319, 801191565, 703649817, 361258161, 149741435, 808495563, 291596204, 250916275, 340042453, 141837377, 547502361, 181348702, 139498738, 338114582,
+            119328746, 177984134, 199957575, 358181386, 57332620, 512567111, 451958433, 156026128, 619998073, 307816265, 338764588, 65822147, 573828018, 487154809, 749222428, 522943099,
+            26336097, 186644498, 526288314, 534618890, 828269735, 675600958, 49788769, 453731878, 762637295, 387744335, 173171058, 33040483, 466949551, 843388255, 697432416, 216291746,
+            33282177, 240642656, 663436347, 390123214, 254438583, 190922896, 455331923, 296664914, 762697018, 331531324, 851176113, 771233913, 482330259, 389665212, 474944010, 58762628,
+            469089651, 436049255, 697216430, 431783325, 138107147, 499492245, 647224366, 407794272, 26067376, 445177552, 520720342, 798948406, 325365361, 117634101, 664099671, 153294810,
+            597801361, 640257687, 533951825, 702134729, 111685295, 685214097, 452013666, 317534558, 271219665, 529108611, 586379543, 355661610, 759841823, 446485943, 839034731, 33604088,
+            773212146, 191869702, 367354365, 689096322, 345311446, 438596834, 677372537, 542545550, 341130619, 292644024, 281192613, 251893811, 447792713, 520181371, 40921126, 778878825,
+            536838039, 230752698, 396625895, 601216134, 188488092, 130103565, 504870771, 413838340, 335573256, 124340986, 368340993, 243753204, 150144590, 808689996, 32468801, 68817331,
+            471378712, 566347573, 6430376, 651137151, 497752158, 823732827, 787280015, 789046852, 194658966, 171151811, 118113814, 793917550, 75187158, 717603845, 61671631, 51620383,
+            302490719, 78328345, 244847301, 549511806, 420356371, 560795789, 405546061, 302036596, 432306081, 270856136, 330554928, 212724399, 791196206, 445342723, 187781362, 87078067,
+            834667388, 218628624, 755629702, 148790011, 845609309, 89984158, 742118272, 475309628, 81731129, 107846408, 74447254, 68656823, 169459843, 643648059, 721924181, 212112779,
+            575076242, 471039705, 626114838, 564548835, 506450263, 488329877, 847101683, 592828368, 714089721, 832868261, 393063639, 603199595, 214221357, 747808090, 145225511, 784491117,
+            578386518, 253504617, 217256612, 432640963, 696210495, 700338942, 642132261, 394125773, 127189460, 622643989, 65557316, 850423288, 154198317, 360118020, 401298167, 809808378,
+            590060278, 378333119, 261388063, 301240958, 211172470, 476577014, 818999735, 320797504, 155490801, 362021897, 416507223, 193972866, 814253796, 555879930, 152626252, 598011677,
+            48971665, 590814257, 699100720, 732535868, 42427027, 335391594, 577502901, 72445917, 562054823, 34689534, 850274973, 640356274, 165636151, 309704599, 39996866, 436255023,
+            365085534, 208984696, 593049885, 755419039, 376895434, 634901252, 316743954, 476563344, 619551824, 766199910, 783651060, 32670169, 794822305, 435248113, 14247580, 284417137,
+            754554090, 30678221, 641072629, 711946716, 568640914, 656468482, 83597913, 356324101, 231391682, 122476642, 505437404, 636148283, 639556222, 262242870, 10083895, 470763095,
+            7162643, 490677454, 122627583, 711718981, 252376484, 423795716, 578101600, 275970963, 3053131, 327430341, 435804223, 349044314, 649311691, 234207954, 379806804, 342513855,
+            224624649, 181857560, 84797030, 123047825, 95186646, 293471117, 586961654, 111168138, 703259490, 756871363, 606284506, 380213718, 292725815, 463763080, 747629289, 254624782,
+            207883602, 849297083, 578506664, 656289117, 454015629, 162235991, 474249177, 633829447, 490767799, 210190430, 48735841, 656982789, 743473215, 47313566, 306689440, 53334547,
+            370344121, 419993940, 218969756, 341956367, 296184959, 135682817, 127205066, 744169001, 445909513, 801533404, 605661030, 181244618, 30772614, 196639386, 59911722, 616623643,
+            199307436, 551535136, 136575017, 79424355, 92705102, 498046224, 17339996, 698541762, 804348245, 104258042, 484400476, 535014225, 87644978, 121726462, 383782353, 77562877,
+            350468417, 724994239, 772938366, 320269449, 203075846, 465307490, 585234251, 271855066, 464423241, 403123130, 202162074, 117126999, 653413020, 8084225, 216658351, 409614891,
+            799241223, 600931579, 454131285, 782741932, 376344215, 79696641, 803438191, 565030050, 460657460, 5110534, 472517130, 76991417, 572426425, 92047134, 285371277, 843473400,
+            389338704, 704515255, 459914006, 657120075, 708563883, 78813141, 11770883, 688134435, 287808573, 649280542, 765338883, 439803770, 160535862, 617753423, 442051682, 288864924,
+            32955626, 326880188, 696887038, 215124062, 791918307, 767157413, 358676037, 30612492, 661971023, 838968782, 465224708, 784600829, 146985424, 799718881, 207906900, 340800263,
+            849693954, 44777992, 31326149, 240259940, 508401593, 499528021, 475930852, 690672059, 580019353, 297040464, 236338202, 454171188, 695134912, 508172471, 436504159, 293630619,
+            848875161, 37043893, 26993038, 396046068, 722016462, 445419380, 209243403, 503786686, 268117854, 281672598, 205034970, 87894257, 293598267, 46912651, 147959859, 462629641,
+            509044664, 700768221, 107374762, 340721447, 163551982, 247501118, 447395984, 318219025, 172114399, 110025830, 810265637, 370215004, 606303954, 462642711, 251114029, 290800715,
+            780017258, 789443137, 495480307, 615909633, 431756150, 766376396, 820732666, 686803688, 133668454, 761665150, 326017339, 424112204, 110554261, 386347465, 101066781, 135666139,
+            256882780, 205722545, 668032392, 405718561, 350327055, 621444438, 381307379, 421184831, 753121128, 590538618, 366906511, 345326178, 132085192, 40531091, 780676557, 586664955,
+            597888984, 693668509, 487104387, 234747974, 572624063, 114516856, 550027276, 316481563, 239535126, 788436714, 847219527, 113421825, 200615887, 815912760, 581164384, 191193216,
+            11551938, 606832431, 431210833, 196126697, 92508342, 270544041, 192437514, 99153842, 188585579, 413385580, 745267475, 448172363, 667109106, 85272138, 658601344, 443173146,
+            392530856, 589073317, 382995167, 248915715, 375600977, 386782401, 254322056, 790853708, 580714915, 163129486, 824017519, 86419559, 117205367, 634667017, 566451589, 852749522,
+            837490424, 330422330, 294598189, 814909626, 505390042, 125578715, 357313675, 450539487, 233746299, 446282749, 755039478, 740350430, 598956163, 116099139, 167482754, 310512355,
+            135624781, 470874939, 196356683, 239902897, 693520220, 454942578, 778240578, 45236161, 51101673, 270126615, 94622194, 524282161, 632376971, 703121383, 587013336, 572429454,
+            37728898, 143682359, 206045437, 557167425, 770459696, 477771773, 321346425, 290390778, 100874902, 758540246, 746805823, 459566327, 607673901, 158286491, 527010720, 579461268,
+            74963118, 420964844, 51316958, 250512679, 452729483, 35670488, 559935164, 734294507, 379228497, 172592106, 126508187, 757555710, 853874620, 808517874, 106015915, 375691866,
+            423413164, 423111661, 60250078, 645353691, 853830811, 288310932, 1489804, 127886925, 191505834, 459549138, 542519706, 369115379, 116842790, 784888677, 269818678, 712117130,
+            748410048, 139982101, 169805525, 32264681, 532400632, 397389041, 181262233, 703428567, 604760852, 44143128, 69914527, 86615396, 314810965, 68145528, 650868687, 717671367,
+            594246701, 641155397, 207406129, 180083553, 414651973, 132523243, 211350471, 397371331, 170688638, 732763563, 132155217, 394688247, 571356350, 93856418, 708831649, 841908230,
+        };
+
+
+        static void poly_uniform(long[] a, byte[] seed, int seedOffset)
+        {
+            int pos = 0, i = 0, nbytes = (PARAM_Q_LOG + 7) / 8;
+            int nblocks = PARAM_GEN_A;
+            int val1, val2, val3, val4, mask = (1 << PARAM_Q_LOG) - 1;
+            byte[] buf = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A];
+            short dmsp = 0;
+
+
+            HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                buf, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A,
+                dmsp++,
+                seed, seedOffset, CRYPTO_RANDOMBYTES
+            );
+
+
+            while (i < PARAM_K * PARAM_N)
+            {
+                if (pos > HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * nblocks - 4 * nbytes)
+                {
+                    nblocks = 1;
+
+                    HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                        buf, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * PARAM_GEN_A,
+                        dmsp++,
+                        seed, seedOffset, CRYPTO_RANDOMBYTES
+                    );
+
+                    pos = 0;
+                }
+                val1 = Pack.littleEndianToInt(buf, pos) & mask;
+                pos += nbytes;
+                val2 = Pack.littleEndianToInt(buf, pos) & mask;
+                pos += nbytes;
+                val3 = Pack.littleEndianToInt(buf, pos) & mask;
+                pos += nbytes;
+                val4 = Pack.littleEndianToInt(buf, pos) & mask;
+                pos += nbytes;
+                if (val1 < PARAM_Q && i < PARAM_K * PARAM_N)
+                {
+                    a[i++] = reduce((long)val1 * PARAM_R2_INVN);
+                }
+                if (val2 < PARAM_Q && i < PARAM_K * PARAM_N)
+                {
+                    a[i++] = reduce((long)val2 * PARAM_R2_INVN);
+                }
+                if (val3 < PARAM_Q && i < PARAM_K * PARAM_N)
+                {
+                    a[i++] = reduce((long)val3 * PARAM_R2_INVN);
+                }
+                if (val4 < PARAM_Q && i < PARAM_K * PARAM_N)
+                {
+                    a[i++] = reduce((long)val4 * PARAM_R2_INVN);
+                }
+            }
+        }
+
+
+        static long reduce(long a)
+        { // Montgomery reduction
+            long u;
+
+            u = (a * (long)PARAM_QINV) & 0xFFFFFFFFL;
+            u *= PARAM_Q;
+            a += u;
+            return a >> 32;
+        }
+
+
+        static void ntt(long[] a, long[] w)
+        { // Forward NTT transform
+            int NumoProblems = PARAM_N >> 1, jTwiddle = 0;
+
+            for (; NumoProblems > 0; NumoProblems >>= 1)
+            {
+                int jFirst, j = 0;
+                for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems)
+                {
+                    int W = (int)w[jTwiddle++];
+                    for (j = jFirst; j < jFirst + NumoProblems; j++)
+                    {
+                        long temp = barr_reduce(reduce(W * a[j + NumoProblems]));
+                        a[j + NumoProblems] = barr_reduce(a[j] + (2L * PARAM_Q - temp));
+                        a[j] = barr_reduce(temp + a[j]);
+                    }
+                }
+            }
+        }
+
+
+        static long barr_reduce(long a)
+        { // Barrett reduction
+            long u = (((long)a * PARAM_BARR_MULT) >> PARAM_BARR_DIV); // TODO u may need to be cast back to int.
+            return a - u * PARAM_Q;
+        }
+
+
+        static void nttinv(long[] a, long[] w)
+        { // Inverse NTT transform
+            int NumoProblems = 1, jTwiddle = 0;
+            for (NumoProblems = 1; NumoProblems < PARAM_N; NumoProblems *= 2)
+            {
+                int jFirst, j = 0;
+                for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems)
+                {
+                    int W = (int)w[jTwiddle++];
+                    for (j = jFirst; j < jFirst + NumoProblems; j++)
+                    {
+                        long temp = a[j];
+
+                        a[j] = barr_reduce((temp + a[j + NumoProblems]));
+                        a[j + NumoProblems] = barr_reduce(reduce(W * (temp + (2L * PARAM_Q - a[j + NumoProblems]))));
+                    }
+                }
+            }
+        }
+
+        static void nttinv(long[] a, int aPos, long[] w)
+        { // Inverse NTT transform
+            int NumoProblems = 1, jTwiddle = 0;
+            for (NumoProblems = 1; NumoProblems < PARAM_N; NumoProblems *= 2)
+            {
+                int jFirst, j = 0;
+                for (jFirst = 0; jFirst < PARAM_N; jFirst = j + NumoProblems)
+                {
+                    int W = (int)w[jTwiddle++];
+                    for (j = jFirst; j < jFirst + NumoProblems; j++)
+                    {
+                        long temp = a[aPos + j];
+                        a[aPos + j] = barr_reduce((temp + a[aPos + j + NumoProblems]));
+                        a[aPos + j + NumoProblems] = barr_reduce(reduce((long)W * (temp + (2L * PARAM_Q - a[aPos + j + NumoProblems]))));
+                    }
+                }
+
+            }
+        }
+
+
+        static void poly_ntt(long[] x_ntt, long[] x)
+        { // Call to NTT function. Avoids input destruction
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                x_ntt[i] = x[i];
+            }
+            ntt(x_ntt, zeta);
+        }
+
+
+        static void poly_pointwise(long[] result, long[] x, long[] y)
+        { // Pointwise polynomial multiplication result = x.y
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[i] = reduce((long)x[i] * y[i]);
+            }
+        }
+
+        static void poly_pointwise(long[] result, int rpos, long[] x, int xpos, long[] y)
+        { // Pointwise polynomial multiplication result = x.y
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[i + rpos] = reduce((long)x[i + xpos] * y[i]);
+            }
+        }
+
+
+        static void poly_mul(long[] result, long[] x, long[] y)
+        { // Polynomial multiplication result = x*y, with in place reduction for (X^N+1)
+            // The input x is assumed to be in NTT form
+//            long[] y_ntt = new long[PARAM_N];
+//
+//            for (int i = 0; i < PARAM_N; i++)
+//            {
+//                y_ntt[i] = y[i];
+//            }
+//
+//            ntt(y_ntt, zeta);
+            poly_pointwise(result, x, y);
+            nttinv(result, zetainv);
+        }
+
+
+        static void poly_mul(long[] result, int rpos, long[] x, int xpos, long[] y)
+        { // Polynomial multiplication result = x*y, with in place reduction for (X^N+1)
+
+            poly_pointwise(result, rpos, x, xpos, y);
+            nttinv(result, rpos, zetainv);
+        }
+
+
+        static void poly_add(long[] result, long[] x, long[] y)
+        { // Polynomial addition result = x+y
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[i] = x[i] + y[i];
+            }
+        }
+
+        static void poly_sub(long[] result, int rpos, long[] x, int xpos, long[] y, int ypos)
+        { // Polynomial subtraction result = x-y
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[rpos + i] = barr_reduce(x[xpos + i] - y[ypos + i]);
+            }
+        }
+
+
+        static void poly_add_correct(long[] result, int rpos, long[] x, int xpos, long[] y, int ypos)
+        { // Polynomial addition result = x+y with correction
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[rpos + i] = x[xpos + i] + y[ypos + i];
+                result[rpos + i] -= PARAM_Q;
+                result[rpos + i] += (result[rpos + i] >> (RADIX32 - 1)) & PARAM_Q;   // If result[i] >= q then subtract q
+            }
+        }
+
+
+        static void poly_sub_correct(int[] result, int[] x, int[] y)
+        { // Polynomial subtraction result = x-y with correction
+
+            for (int i = 0; i < PARAM_N; i++)
+            {
+                result[i] = x[i] - y[i];
+                result[i] += (result[i] >> (RADIX32 - 1)) & PARAM_Q;    // If result[i] < 0 then add q
+            }
+        }
+
+
+        static void sparse_mul8(long[] prod, int ppos, byte[] s, int spos, int[] pos_list, short[] sign_list)
+        {
+            int i, j, pos;
+
+            for (i = 0; i < PARAM_N; i++)
+            {
+                prod[ppos + i] = 0;
+            }
+
+            for (i = 0; i < PARAM_H; i++)
+            {
+                pos = pos_list[i];
+                for (j = 0; j < pos; j++)
+                {
+                    prod[ppos + j] = prod[ppos + j] - sign_list[i] * s[spos + j + PARAM_N - pos];
+                }
+                for (j = pos; j < PARAM_N; j++)
+                {
+                    prod[ppos + j] = prod[ppos + j] + sign_list[i] * s[spos + j - pos];
+                }
+            }
+        }
+
+
+        static void sparse_mul8(long[] prod, byte[] s, int[] pos_list, short[] sign_list)
+        {
+            int i, j, pos;
+            byte t[] = s;
+
+            for (i = 0; i < PARAM_N; i++)
+            {
+                prod[i] = 0;
+            }
+
+            for (i = 0; i < PARAM_H; i++)
+            {
+                pos = pos_list[i];
+                for (j = 0; j < pos; j++)
+                {
+                    prod[j] = prod[j] - sign_list[i] * t[j + PARAM_N - pos];
+                }
+                for (j = pos; j < PARAM_N; j++)
+                {
+                    prod[j] = prod[j] + sign_list[i] * t[j - pos];
+                }
+            }
+        }
+
+
+        static void sparse_mul16(int[] prod, int s[], int pos_list[], short sign_list[])
+        {
+            int i, j, pos;
+//            short[] t = s;
+
+            for (i = 0; i < PARAM_N; i++)
+            {
+                prod[i] = 0;
+            }
+
+            for (i = 0; i < PARAM_H; i++)
+            {
+                pos = pos_list[i];
+                for (j = 0; j < pos; j++)
+                {
+                    prod[j] = prod[j] - sign_list[i] * s[j + PARAM_N - pos];
+                }
+                for (j = pos; j < PARAM_N; j++)
+                {
+                    prod[j] = prod[j] + sign_list[i] * s[j - pos];
+                }
+            }
+        }
+
+
+        static void sparse_mul32(int[] prod, int[] pk, int[] pos_list, short[] sign_list)
+        {
+            int i, j, pos;
+
+            for (i = 0; i < PARAM_N; i++)
+            {
+                prod[i] = 0;
+            }
+
+            for (i = 0; i < PARAM_H; i++)
+            {
+                pos = pos_list[i];
+                for (j = 0; j < pos; j++)
+                {
+                    prod[j] = prod[j] - sign_list[i] * pk[j + PARAM_N - pos];
+                }
+                for (j = pos; j < PARAM_N; j++)
+                {
+                    prod[j] = prod[j] + sign_list[i] * pk[j - pos];
+                }
+            }
+        }
+
+        static void sparse_mul32(long[] prod, int ppos, int[] pk, int pkPos, int[] pos_list, short[] sign_list)
+        {
+            int i, j, pos;
+
+            for (i = 0; i < PARAM_N; i++)
+            {
+                prod[ppos + i] = 0;
+            }
+
+            for (i = 0; i < PARAM_H; i++)
+            {
+                pos = pos_list[i];
+                for (j = 0; j < pos; j++)
+                {
+                    prod[ppos + j] = prod[ppos + j] - sign_list[i] * pk[pkPos + j + PARAM_N - pos];
+                }
+                for (j = pos; j < PARAM_N; j++)
+                {
+                    prod[ppos + j] = prod[ppos + j] + sign_list[i] * pk[pkPos + j - pos];
+                }
+            }
+        }
+
+
+    }
+
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/CommonFunction.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/CommonFunction.java
new file mode 100644
index 000000000..70bfe8ce7
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/CommonFunction.java
@@ -0,0 +1,286 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+class CommonFunction
+{
+
+    /****************************************************************************************************
+     * Description:	Checks Whether the Two Parts of Arrays are Equal to Each Other
+     *
+     * @param        left            Left Array
+     * @param        leftOffset        Starting Point of the Left Array
+     * @param        right            Right Array
+     * @param        rightOffset        Starting Point of the Right Array
+     * @param        length            Length to be Compared from the Starting Point
+     *
+     * @return true            Equal
+     *				false			Different
+     ****************************************************************************************************/
+    public static boolean memoryEqual(byte[] left, int leftOffset, byte[] right, int rightOffset, int length)
+    {
+
+        if ((leftOffset + length <= left.length) && (rightOffset + length <= right.length))
+        {
+
+            for (int i = 0; i < length; i++)
+            {
+
+                if (left[leftOffset + i] != right[rightOffset + i])
+                {
+
+                    return false;
+
+                }
+
+            }
+
+            return true;
+
+        }
+        else
+        {
+
+            return false;
+
+        }
+
+    }
+
+    /****************************************************************************
+     * Description:	Converts 2 Consecutive Bytes in "load" to A Number of "Short"
+     *				from A Known Position
+     *
+     * @param        load            Source Array
+     * @param        loadOffset        Starting Position
+     *
+     * @return A Number of "Short"
+     ****************************************************************************/
+    public static short load16(final byte[] load, int loadOffset)
+    {
+
+        short number = 0;
+
+        if (load.length - loadOffset >= Const.SHORT_SIZE / Const.BYTE_SIZE)
+        {
+
+            for (int i = 0; i < Const.SHORT_SIZE / Const.BYTE_SIZE; i++)
+            {
+
+                number ^= (short)(load[loadOffset + i] & 0xFF) << (Const.BYTE_SIZE * i);
+
+            }
+
+        }
+        else
+        {
+
+            for (int i = 0; i < load.length - loadOffset; i++)
+            {
+
+                number ^= (short)(load[loadOffset + i] & 0xFF) << (Const.BYTE_SIZE * i);
+
+            }
+
+        }
+
+        return number;
+
+    }
+
+    /******************************************************************************
+     * Description:	Converts 4 Consecutive Bytes in "load" to A Number of "Integer"
+     *				from A Known Position
+     *
+     * @param        load            Source Array
+     * @param        loadOffset        Starting Position
+     *
+     * @return A Number of "Integer"
+     ******************************************************************************/
+    public static int load32(final byte[] load, int loadOffset)
+    {
+
+        int number = 0;
+
+        if (load.length - loadOffset >= Const.INT_SIZE / Const.BYTE_SIZE)
+        {
+
+            for (int i = 0; i < Const.INT_SIZE / Const.BYTE_SIZE; i++)
+            {
+
+                number ^= (int)(load[loadOffset + i] & 0xFF) << (Const.BYTE_SIZE * i);
+
+            }
+
+        }
+        else
+        {
+
+
+            for (int i = 0; i < load.length - loadOffset; i++)
+            {
+
+                number ^= (int)(load[loadOffset + i] & 0xFF) << (Const.BYTE_SIZE * i);
+
+            }
+
+        }
+
+        return number;
+
+    }
+
+    /***************************************************************************
+     * Description:	Converts 8 Consecutive Bytes in "load" to A Number of "Long"
+     *				from A Known Position
+     *
+     * @param        load            Source Array
+     * @param        loadOffset        Starting Position
+     *
+     * @return A Number of "Long"
+     ***************************************************************************/
+    public static long load64(final byte[] load, int loadOffset)
+    {
+
+        long number = 0L;
+
+        if (load.length - loadOffset >= Const.LONG_SIZE / Const.BYTE_SIZE)
+        {
+
+            for (int i = 0; i < Const.LONG_SIZE / Const.BYTE_SIZE; i++)
+            {
+
+                number ^= (long)(load[loadOffset + i] & 0xFF) << (Const.BYTE_SIZE * i);
+
+            }
+
+        }
+        else
+        {
+
+            for (int i = 0; i < load.length - loadOffset; i++)
+            {
+
+                number ^= (long)(load[loadOffset + i] & 0xFF) << (Const.BYTE_SIZE * i);
+
+            }
+
+        }
+
+        return number;
+
+    }
+
+    /*****************************************************************************
+     * Description:	Converts A Number of "Short" to 2 Consecutive Bytes in "store"
+     *				from a known position
+     *
+     * @param        store            Destination Array
+     * @param        storeOffset        Starting position
+     * @param        number            Source Number
+     *
+     * @return none
+     *****************************************************************************/
+    public static void store16(byte[] store, int storeOffset, short number)
+    {
+
+        if (store.length - storeOffset >= Const.SHORT_SIZE / Const.BYTE_SIZE)
+        {
+
+            for (int i = 0; i < Const.SHORT_SIZE / Const.BYTE_SIZE; i++)
+            {
+
+                store[storeOffset + i] = (byte)((number >> (Const.BYTE_SIZE * i)) & 0xFF);
+
+            }
+
+        }
+        else
+        {
+
+            for (int i = 0; i < store.length - storeOffset; i++)
+            {
+
+                store[storeOffset + i] = (byte)((number >> (Const.BYTE_SIZE * i)) & 0xFF);
+
+            }
+
+        }
+
+    }
+
+    /*******************************************************************************
+     * Description:	Converts A Number of "Integer" to 4 Consecutive Bytes in "store"
+     * 				from A Known Position
+     *
+     * @param        store            Destination Array
+     * @param        storeOffset        Starting Position
+     * @param        number:			Source Number
+     *
+     * @return none
+     *******************************************************************************/
+    public static void store32(byte[] store, int storeOffset, int number)
+    {
+
+        if (store.length - storeOffset >= Const.INT_SIZE / Const.BYTE_SIZE)
+        {
+
+            for (int i = 0; i < Const.INT_SIZE / Const.BYTE_SIZE; i++)
+            {
+
+                store[storeOffset + i] = (byte)((number >> (Const.BYTE_SIZE * i)) & 0xFF);
+
+            }
+
+        }
+        else
+        {
+
+            for (int i = 0; i < store.length - storeOffset; i++)
+            {
+
+                store[storeOffset + i] = (byte)((number >> (Const.BYTE_SIZE * i)) & 0xFF);
+
+            }
+
+        }
+
+    }
+
+    /****************************************************************************
+     * Description:	Converts A Number of "Long" to 8 Consecutive Bytes in "store"
+     * 				from A Known Position
+     *
+     * @param        store            Destination Array
+     * @param        storeOffset        Starting Position
+     * @param        number            Source Number
+     *
+     * @return none
+     ****************************************************************************/
+    public static void store64(byte[] store, int storeOffset, long number)
+    {
+
+        if (store.length - storeOffset >= Const.LONG_SIZE / Const.BYTE_SIZE)
+        {
+
+            for (int i = 0; i < Const.LONG_SIZE / Const.BYTE_SIZE; i++)
+            {
+
+                store[storeOffset + i] = (byte)((number >> (Const.BYTE_SIZE * i)) & 0xFFL);
+
+            }
+
+        }
+        else
+        {
+
+            for (int i = 0; i < store.length - storeOffset; i++)
+            {
+
+                store[storeOffset + i] = (byte)((number >> (Const.BYTE_SIZE * i)) & 0xFFL);
+
+            }
+
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Const.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Const.java
new file mode 100644
index 000000000..73fe8192c
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Const.java
@@ -0,0 +1,9 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+class Const
+{
+    static final int BYTE_SIZE = 8;
+    static final int SHORT_SIZE = 16;
+    static final int INT_SIZE = 32;
+    static final int LONG_SIZE = 64;
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/HashUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/HashUtils.java
new file mode 100644
index 000000000..6388c6c73
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/HashUtils.java
@@ -0,0 +1,52 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+import com.fr.third.org.bouncycastle.crypto.digests.CSHAKEDigest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest;
+
+class HashUtils
+{
+
+    public static final int SECURE_HASH_ALGORITHM_KECCAK_128_RATE = 168;
+    public static final int SECURE_HASH_ALGORITHM_KECCAK_256_RATE = 136;
+
+    /***************************************************************************************************************************************************************
+     * Description:	The Secure-Hash-Algorithm-3 Extendable-Output Function That Generally Supports 128 Bits of Security Strength, If the Output is Sufficiently Long
+     ***************************************************************************************************************************************************************/
+    static void secureHashAlgorithmKECCAK128(byte[] output, int outputOffset, int outputLength, byte[] input, int inputOffset, int inputLength)
+    {
+        SHAKEDigest dig = new SHAKEDigest(128);
+        dig.update(input, inputOffset, inputLength);
+
+        dig.doFinal(output, outputOffset, outputLength);
+    }
+
+    /***************************************************************************************************************************************************************
+     * Description:	The Secure-Hash-Algorithm-3 Extendable-Output Function That Generally Supports 256 Bits of Security Strength, If the Output is Sufficiently Long
+     ***************************************************************************************************************************************************************/
+    static void secureHashAlgorithmKECCAK256(byte[] output, int outputOffset, int outputLength, byte[] input, int inputOffset, int inputLength)
+    {
+        SHAKEDigest dig = new SHAKEDigest(256);
+        dig.update(input, inputOffset, inputLength);
+
+        dig.doFinal(output, outputOffset, outputLength);
+    }
+
+    /* Customizable Secure Hash Algorithm KECCAK 128 / Customizable Secure Hash Algorithm KECCAK 256 */
+
+
+    static void customizableSecureHashAlgorithmKECCAK128Simple(byte[] output, int outputOffset, int outputLength, short continuousTimeStochasticModelling, byte[] input, int inputOffset, int inputLength)
+    {
+        CSHAKEDigest dig = new CSHAKEDigest(128, null, new byte[] {(byte)continuousTimeStochasticModelling, (byte)(continuousTimeStochasticModelling >> 8) });
+        dig.update(input, inputOffset, inputLength);
+
+        dig.doFinal(output, outputOffset, outputLength);
+    }
+
+    static void customizableSecureHashAlgorithmKECCAK256Simple(byte[] output, int outputOffset, int outputLength, short continuousTimeStochasticModelling, byte[] input, int inputOffset, int inputLength)
+    {
+        CSHAKEDigest dig = new CSHAKEDigest(256, null, new byte[] {(byte)continuousTimeStochasticModelling, (byte)(continuousTimeStochasticModelling >> 8) });
+        dig.update(input, inputOffset, inputLength);
+
+        dig.doFinal(output, outputOffset, outputLength);
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Pack.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Pack.java
new file mode 100644
index 000000000..fae238b14
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Pack.java
@@ -0,0 +1,1370 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+class Pack
+{
+
+    /*******************************************************************************************************************************************************
+     * Description:	Encode Private Key for Heuristic qTESLA Security Category-1
+     *
+     * @param        privateKey                Private Key
+     * @param        secretPolynomial        Coefficients of the Secret Polynomial
+     * @param        errorPolynomial            Coefficients of the Error Polynomial
+     * @param        seed                    Kappa-Bit Seed
+     * @param        seedOffset                Starting Point of the Kappa-Bit Seed
+     *
+     * @return none
+     *******************************************************************************************************************************************************/
+    public static void encodePrivateKeyI(byte[] privateKey, final int[] secretPolynomial, final int[] errorPolynomial, final byte[] seed, int seedOffset)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < Parameter.N_I; i += 4)
+        {
+
+            privateKey[j + 0] = (byte)secretPolynomial[i + 0];
+            privateKey[j + 1] = (byte)(((secretPolynomial[i + 0] >> 8) & 0x03) | (secretPolynomial[i + 1] << 2));
+            privateKey[j + 2] = (byte)(((secretPolynomial[i + 1] >> 6) & 0x0F) | (secretPolynomial[i + 2] << 4));
+            privateKey[j + 3] = (byte)(((secretPolynomial[i + 2] >> 4) & 0x3F) | (secretPolynomial[i + 3] << 6));
+            privateKey[j + 4] = (byte)(secretPolynomial[i + 3] >> 2);
+
+            j += 5;
+
+        }
+
+        for (int i = 0; i < Parameter.N_I; i += 4)
+        {
+
+            privateKey[j + 0] = (byte)errorPolynomial[i + 0];
+            privateKey[j + 1] = (byte)(((errorPolynomial[i + 0] >> 8) & 0x03) | (errorPolynomial[i + 1] << 2));
+            privateKey[j + 2] = (byte)(((errorPolynomial[i + 1] >> 6) & 0x0F) | (errorPolynomial[i + 2] << 4));
+            privateKey[j + 3] = (byte)(((errorPolynomial[i + 2] >> 4) & 0x3F) | (errorPolynomial[i + 3] << 6));
+            privateKey[j + 4] = (byte)(errorPolynomial[i + 3] >> 2);
+
+            j += 5;
+
+        }
+
+        System.arraycopy(seed, seedOffset, privateKey, Parameter.N_I * Parameter.S_BIT_I * 2 / Const.BYTE_SIZE, Polynomial.SEED * 2);
+
+    }
+
+    /*************************************************************************************************************************************************************
+     * Description:	Encode Private Key for Heuristic qTESLA Security Category-3 (Option for Size)
+     *
+     * @param        privateKey                Private Key
+     * @param        secretPolynomial        Coefficients of the Secret Polynomial
+     * @param        errorPolynomial            Coefficients of the Error Polynomial
+     * @param        seed                    Kappa-Bit Seed
+     * @param        seedOffset                Starting Point of the Kappa-Bit Seed
+     *
+     * @return none
+     *************************************************************************************************************************************************************/
+    public static void encodePrivateKeyIIISize(byte[] privateKey, final int[] secretPolynomial, final int[] errorPolynomial, final byte[] seed, int seedOffset)
+    {
+
+        for (int i = 0; i < Parameter.N_III_SIZE; i++)
+        {
+
+            privateKey[i] = (byte)secretPolynomial[i];
+
+        }
+
+        for (int i = 0; i < Parameter.N_III_SIZE; i++)
+        {
+
+            privateKey[Parameter.N_III_SIZE + i] = (byte)errorPolynomial[i];
+
+        }
+
+        System.arraycopy(seed, seedOffset, privateKey, Parameter.N_III_SIZE * Parameter.S_BIT_III_SIZE * 2 / Const.BYTE_SIZE, Polynomial.SEED * 2);
+
+    }
+
+    /***********************************************************************************************************************************************************************************
+     * Description:	Encode Private Key for Heuristic qTESLA Security Category-3 (Option for Speed)
+     *
+     * @param        privateKey                Private Key
+     * @param        secretPolynomial        Coefficients of the Secret Polynomial
+     * @param        errorPolynomial            Coefficients of the Error Polynomial
+     * @param        seed                    Kappa-Bit Seed
+     * @param        seedOffset                Starting Point of the Kappa-Bit Seed
+     *
+     * @return none
+     ***********************************************************************************************************************************************************************************/
+    public static void encodePrivateKeyIIISpeed(byte[] privateKey, final int[] secretPolynomial, final int[] errorPolynomial, final byte[] seed, int seedOffset)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < Parameter.N_III_SPEED; i += 8)
+        {
+
+            privateKey[j + 0] = (byte)secretPolynomial[i + 0];
+            privateKey[j + 1] = (byte)(((secretPolynomial[i + 0] >> 8) & 0x01) | (secretPolynomial[i + 1] << 1));
+            privateKey[j + 2] = (byte)(((secretPolynomial[i + 1] >> 7) & 0x03) | (secretPolynomial[i + 2] << 2));
+            privateKey[j + 3] = (byte)(((secretPolynomial[i + 2] >> 6) & 0x07) | (secretPolynomial[i + 3] << 3));
+            privateKey[j + 4] = (byte)(((secretPolynomial[i + 3] >> 5) & 0x0F) | (secretPolynomial[i + 4] << 4));
+            privateKey[j + 5] = (byte)(((secretPolynomial[i + 4] >> 4) & 0x1F) | (secretPolynomial[i + 5] << 5));
+            privateKey[j + 6] = (byte)(((secretPolynomial[i + 5] >> 3) & 0x3F) | (secretPolynomial[i + 6] << 6));
+            privateKey[j + 7] = (byte)(((secretPolynomial[i + 6] >> 2) & 0x7F) | (secretPolynomial[i + 7] << 7));
+            privateKey[j + 8] = (byte)(secretPolynomial[i + 7] >> 1);
+
+            j += 9;
+
+        }
+
+        for (int i = 0; i < Parameter.N_III_SPEED; i += 8)
+        {
+
+            privateKey[j + 0] = (byte)errorPolynomial[i + 0];
+            privateKey[j + 1] = (byte)(((errorPolynomial[i + 0] >> 8) & 0x01) | (errorPolynomial[i + 1] << 1));
+            privateKey[j + 2] = (byte)(((errorPolynomial[i + 1] >> 7) & 0x03) | (errorPolynomial[i + 2] << 2));
+            privateKey[j + 3] = (byte)(((errorPolynomial[i + 2] >> 6) & 0x07) | (errorPolynomial[i + 3] << 3));
+            privateKey[j + 4] = (byte)(((errorPolynomial[i + 3] >> 5) & 0x0F) | (errorPolynomial[i + 4] << 4));
+            privateKey[j + 5] = (byte)(((errorPolynomial[i + 4] >> 4) & 0x1F) | (errorPolynomial[i + 5] << 5));
+            privateKey[j + 6] = (byte)(((errorPolynomial[i + 5] >> 3) & 0x3F) | (errorPolynomial[i + 6] << 6));
+            privateKey[j + 7] = (byte)(((errorPolynomial[i + 6] >> 2) & 0x7F) | (errorPolynomial[i + 7] << 7));
+            privateKey[j + 8] = (byte)(errorPolynomial[i + 7] >> 1);
+
+            j += 9;
+
+        }
+
+        System.arraycopy(seed, seedOffset, privateKey, Parameter.N_III_SPEED * Parameter.S_BIT_III_SPEED * 2 / Const.BYTE_SIZE, Polynomial.SEED * 2);
+
+    }
+
+    /*******************************************************************************************************************************
+     * Description:	Decode Private Key for Heuristic qTESLA Security Category-1
+     *
+     * @param        seed                    Kappa-Bit Seed
+     * @param        secretPolynomial        Coefficients of the Secret Polynomial
+     * @param        errorPolynomial            Coefficients of the Error Polynomial
+     * @param        privateKey                Private Key
+     *
+     * @return none
+     *******************************************************************************************************************************/
+    public static void decodePrivateKeyI(byte[] seed, short[] secretPolynomial, short[] errorPolynomial, final byte[] privateKey)
+    {
+
+        int j = 0;
+        int temporary = 0;
+
+        for (int i = 0; i < Parameter.N_I; i += 4)
+        {
+
+            temporary = privateKey[j + 0] & 0xFF;
+            secretPolynomial[i + 0] = (short)temporary;
+            temporary = privateKey[j + 1] & 0xFF;
+            temporary = (temporary << 30) >> 22;
+            secretPolynomial[i + 0] |= (short)temporary;
+
+            temporary = privateKey[j + 1] & 0xFF;
+            temporary = temporary >> 2;
+            secretPolynomial[i + 1] = (short)temporary;
+            temporary = privateKey[j + 2] & 0xFF;
+            temporary = (temporary << 28) >> 22;
+            secretPolynomial[i + 1] |= (short)temporary;
+
+            temporary = privateKey[j + 2] & 0xFF;
+            temporary = temporary >> 4;
+            secretPolynomial[i + 2] = (short)temporary;
+            temporary = privateKey[j + 3] & 0xFF;
+            temporary = (temporary << 26) >> 22;
+            secretPolynomial[i + 2] |= (short)temporary;
+
+            temporary = privateKey[j + 3] & 0xFF;
+            temporary = temporary >> 6;
+            secretPolynomial[i + 3] = (short)temporary;
+            temporary = privateKey[j + 4];
+            temporary = (short)temporary << 2;
+            secretPolynomial[i + 3] |= (short)temporary;
+
+            j += 5;
+
+        }
+
+        for (int i = 0; i < Parameter.N_I; i += 4)
+        {
+
+            temporary = privateKey[j + 0] & 0xFF;
+            errorPolynomial[i + 0] = (short)temporary;
+            temporary = privateKey[j + 1] & 0xFF;
+            temporary = (temporary << 30) >> 22;
+            errorPolynomial[i + 0] |= (short)temporary;
+
+            temporary = privateKey[j + 1] & 0xFF;
+            temporary = temporary >> 2;
+            errorPolynomial[i + 1] = (short)temporary;
+            temporary = privateKey[j + 2] & 0xFF;
+            temporary = (temporary << 28) >> 22;
+            errorPolynomial[i + 1] |= (short)temporary;
+
+            temporary = privateKey[j + 2] & 0xFF;
+            temporary = temporary >> 4;
+            errorPolynomial[i + 2] = (short)temporary;
+            temporary = privateKey[j + 3] & 0xFF;
+            temporary = (temporary << 26) >> 22;
+            errorPolynomial[i + 2] |= (short)temporary;
+
+            temporary = privateKey[j + 3] & 0xFF;
+            temporary = temporary >> 6;
+            errorPolynomial[i + 3] = (short)temporary;
+            temporary = privateKey[j + 4];
+            temporary = (short)temporary << 2;
+            errorPolynomial[i + 3] |= (short)temporary;
+
+            j += 5;
+
+        }
+
+        System.arraycopy(privateKey, Parameter.N_I * Parameter.S_BIT_I * 2 / Const.BYTE_SIZE, seed, 0, Polynomial.SEED * 2);
+
+    }
+
+    /*************************************************************************************************************************************
+     * Description:	Decode Private Key for Heuristic qTESLA Security Category-3 (Option for Size)
+     *
+     * @param        seed                    Kappa-Bit Seed
+     * @param        secretPolynomial        Coefficients of the Secret Polynomial
+     * @param        errorPolynomial            Coefficients of the Error Polynomial
+     * @param        privateKey                Private Key
+     *
+     * @return none
+     *************************************************************************************************************************************/
+    public static void decodePrivateKeyIIISize(byte[] seed, short[] secretPolynomial, short[] errorPolynomial, final byte[] privateKey)
+    {
+
+        for (int i = 0; i < Parameter.N_III_SIZE; i++)
+        {
+
+            secretPolynomial[i] = privateKey[i];
+
+        }
+
+        for (int i = 0; i < Parameter.N_III_SIZE; i++)
+        {
+
+            errorPolynomial[i] = privateKey[Parameter.N_III_SIZE + i];
+
+        }
+
+        System.arraycopy(privateKey, Parameter.N_III_SIZE * Parameter.S_BIT_III_SIZE * 2 / Const.BYTE_SIZE, seed, 0, Polynomial.SEED * 2);
+
+    }
+
+    /**************************************************************************************************************************************
+     * Description:	Decode Private Key for Heuristic qTESLA Security Category-3 (Option for Speed)
+     *
+     * @param        seed                    Kappa-Bit Seed
+     * @param        secretPolynomial        Coefficients of the Secret Polynomial
+     * @param        errorPolynomial            Coefficients of the Error Polynomial
+     * @param        privateKey                Private Key
+     *
+     * @return none
+     **************************************************************************************************************************************/
+    public static void decodePrivateKeyIIISpeed(byte[] seed, short[] secretPolynomial, short[] errorPolynomial, final byte[] privateKey)
+    {
+
+        int j = 0;
+        int temporary = 0;
+
+        for (int i = 0; i < Parameter.N_III_SPEED; i += 8)
+        {
+
+            temporary = privateKey[j + 0] & 0xFF;
+            secretPolynomial[i + 0] = (short)temporary;
+            temporary = privateKey[j + 1] & 0xFF;
+            temporary = (temporary << 31) >> 23;
+            secretPolynomial[i + 0] |= (short)temporary;
+
+            temporary = privateKey[j + 1] & 0xFF;
+            temporary = temporary >> 1;
+            secretPolynomial[i + 1] = (short)temporary;
+            temporary = privateKey[j + 2] & 0xFF;
+            temporary = (temporary << 30) >> 23;
+            secretPolynomial[i + 1] |= (short)temporary;
+
+            temporary = privateKey[j + 2] & 0xFF;
+            temporary = temporary >> 2;
+            secretPolynomial[i + 2] = (short)temporary;
+            temporary = privateKey[j + 3] & 0xFF;
+            temporary = (temporary << 29) >> 23;
+            secretPolynomial[i + 2] |= (short)temporary;
+
+            temporary = privateKey[j + 3] & 0xFF;
+            temporary = temporary >> 3;
+            secretPolynomial[i + 3] = (short)temporary;
+            temporary = privateKey[j + 4] & 0xFF;
+            temporary = (temporary << 28) >> 23;
+            secretPolynomial[i + 3] |= (short)temporary;
+
+            temporary = privateKey[j + 4] & 0xFF;
+            temporary = temporary >> 4;
+            secretPolynomial[i + 4] = (short)temporary;
+            temporary = privateKey[j + 5] & 0xFF;
+            temporary = (temporary << 27) >> 23;
+            secretPolynomial[i + 4] |= (short)temporary;
+
+            temporary = privateKey[j + 5] & 0xFF;
+            temporary = temporary >> 5;
+            secretPolynomial[i + 5] = (short)temporary;
+            temporary = privateKey[j + 6] & 0xFF;
+            temporary = (temporary << 26) >> 23;
+            secretPolynomial[i + 5] |= (short)temporary;
+
+            temporary = privateKey[j + 6] & 0xFF;
+            temporary = temporary >> 6;
+            secretPolynomial[i + 6] = (short)temporary;
+            temporary = privateKey[j + 7] & 0xFF;
+            temporary = (temporary << 25) >> 23;
+            secretPolynomial[i + 6] |= (short)temporary;
+
+            temporary = privateKey[j + 7] & 0xFF;
+            temporary = temporary >> 7;
+            secretPolynomial[i + 7] = (short)temporary;
+            temporary = privateKey[j + 8];
+            temporary = (short)temporary << 1;
+            secretPolynomial[i + 7] |= (short)temporary;
+
+            j += 9;
+
+        }
+
+        for (int i = 0; i < Parameter.N_III_SPEED; i += 8)
+        {
+
+            temporary = privateKey[j + 0] & 0xFF;
+            errorPolynomial[i + 0] = (short)temporary;
+            temporary = privateKey[j + 1] & 0xFF;
+            temporary = (temporary << 31) >> 23;
+            errorPolynomial[i + 0] |= (short)temporary;
+
+            temporary = privateKey[j + 1] & 0xFF;
+            temporary = temporary >> 1;
+            errorPolynomial[i + 1] = (short)temporary;
+            temporary = privateKey[j + 2] & 0xFF;
+            temporary = (temporary << 30) >> 23;
+            errorPolynomial[i + 1] |= (short)temporary;
+
+            temporary = privateKey[j + 2] & 0xFF;
+            temporary = temporary >> 2;
+            errorPolynomial[i + 2] = (short)temporary;
+            temporary = privateKey[j + 3] & 0xFF;
+            temporary = (temporary << 29) >> 23;
+            errorPolynomial[i + 2] |= (short)temporary;
+
+            temporary = privateKey[j + 3] & 0xFF;
+            temporary = temporary >> 3;
+            errorPolynomial[i + 3] = (short)temporary;
+            temporary = privateKey[j + 4] & 0xFF;
+            temporary = (temporary << 28) >> 23;
+            errorPolynomial[i + 3] |= (short)temporary;
+
+            temporary = privateKey[j + 4] & 0xFF;
+            temporary = temporary >> 4;
+            errorPolynomial[i + 4] = (short)temporary;
+            temporary = privateKey[j + 5] & 0xFF;
+            temporary = (temporary << 27) >> 23;
+            errorPolynomial[i + 4] |= (short)temporary;
+
+            temporary = privateKey[j + 5] & 0xFF;
+            temporary = temporary >> 5;
+            errorPolynomial[i + 5] = (short)temporary;
+            temporary = privateKey[j + 6] & 0xFF;
+            temporary = (temporary << 26) >> 23;
+            errorPolynomial[i + 5] |= (short)temporary;
+
+            temporary = privateKey[j + 6] & 0xFF;
+            temporary = temporary >> 6;
+            errorPolynomial[i + 6] = (short)temporary;
+            temporary = privateKey[j + 7] & 0xFF;
+            temporary = (temporary << 25) >> 23;
+            errorPolynomial[i + 6] |= (short)temporary;
+
+            temporary = privateKey[j + 7] & 0xFF;
+            temporary = temporary >> 7;
+            errorPolynomial[i + 7] = (short)temporary;
+            temporary = privateKey[j + 8];
+            temporary = (short)temporary << 1;
+            errorPolynomial[i + 7] |= (short)temporary;
+
+            j += 9;
+
+        }
+
+        System.arraycopy(privateKey, Parameter.N_III_SPEED * Parameter.S_BIT_III_SPEED * 2 / Const.BYTE_SIZE, seed, 0, Polynomial.SEED * 2);
+
+    }
+
+    /********************************************************************************************************************************************************************
+     * Description:	Pack Private Key for Provably-Secure qTESLA Security Category-1 and Security Category-3
+     *
+     * @param        privateKey                Private Key
+     * @param        secretPolynomial        Coefficients of the Secret Polynomial
+     * @param        errorPolynomial            Coefficients of the Error Polynomial
+     * @param        seed                    Kappa-Bit Seed
+     * @param        seedOffset                Starting Point of the Kappa-Bit Seed
+     * @param        n                        Polynomial Degree
+     * @param        k                        Number of Ring-Learning-With-Errors Samples
+     *
+     * @return none
+     ********************************************************************************************************************************************************************/
+    public static void packPrivateKey(byte[] privateKey, final long[] secretPolynomial, final long[] errorPolynomial, final byte[] seed, int seedOffset, int n, int k)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            privateKey[i] = (byte)secretPolynomial[i];
+
+        }
+
+        for (int j = 0; j < k; j++)
+        {
+
+            for (int i = 0; i < n; i++)
+            {
+
+                privateKey[n + j * n + i] = (byte)errorPolynomial[j * n + i];
+
+            }
+
+        }
+
+        System.arraycopy(seed, seedOffset, privateKey, n + k * n, Polynomial.SEED * 2);
+
+    }
+
+    /**************************************************************************************************************************************************
+     * Description:	Encode Public Key for Heuristic qTESLA Security Category-1 and Category-3 (Option for Size)
+     *
+     * @param        publicKey            Public Key
+     * @param        T                    T_1, ..., T_k
+     * @param        seedA                Seed Used to Generate the Polynomials a_i for i = 1, ..., k
+     * @param        seedAOffset            Starting Point of the Seed A
+     * @param        n                    Polynomial Degree
+     * @param        qLogarithm            q <= 2 ^ qLogartihm
+     *
+     * @return none
+     **************************************************************************************************************************************************/
+    public static void encodePublicKey(byte[] publicKey, final int[] T, final byte[] seedA, int seedAOffset, int n, int qLogarithm)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < n * qLogarithm / Const.INT_SIZE; i += qLogarithm)
+        {
+
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 0), (int)(T[j + 0] | (T[j + 1] << 23)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 1), (int)((T[j + 1] >> 9) | (T[j + 2] << 14)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 2), (int)((T[j + 2] >> 18) | (T[j + 3] << 5) | (T[j + 4] << 28)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 3), (int)((T[j + 4] >> 4) | (T[j + 5] << 19)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 4), (int)((T[j + 5] >> 13) | (T[j + 6] << 10)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 5), (int)((T[j + 6] >> 22) | (T[j + 7] << 1) | (T[j + 8] << 24)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 6), (int)((T[j + 8] >> 8) | (T[j + 9] << 15)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 7), (int)((T[j + 9] >> 17) | (T[j + 10] << 6) | (T[j + 11] << 29)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 8), (int)((T[j + 11] >> 3) | (T[j + 12] << 20)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 9), (int)((T[j + 12] >> 12) | (T[j + 13] << 11)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 10), (int)((T[j + 13] >> 21) | (T[j + 14] << 2) | (T[j + 15] << 25)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 11), (int)((T[j + 15] >> 7) | (T[j + 16] << 16)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 12), (int)((T[j + 16] >> 16) | (T[j + 17] << 7) | (T[j + 18] << 30)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 13), (int)((T[j + 18] >> 2) | (T[j + 19] << 21)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 14), (int)((T[j + 19] >> 11) | (T[j + 20] << 12)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 15), (int)((T[j + 20] >> 20) | (T[j + 21] << 3) | (T[j + 22] << 26)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 16), (int)((T[j + 22] >> 6) | (T[j + 23] << 17)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 17), (int)((T[j + 23] >> 15) | (T[j + 24] << 8) | (T[j + 25] << 31)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 18), (int)((T[j + 25] >> 1) | (T[j + 26] << 22)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 19), (int)((T[j + 26] >> 10) | (T[j + 27] << 13)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 20), (int)((T[j + 27] >> 19) | (T[j + 28] << 4) | (T[j + 29] << 27)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 21), (int)((T[j + 29] >> 5) | (T[j + 30] << 18)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 22), (int)((T[j + 30] >> 14) | (T[j + 31] << 9)));
+
+            j += Const.INT_SIZE;
+
+        }
+
+        System.arraycopy(seedA, seedAOffset, publicKey, n * qLogarithm / Const.BYTE_SIZE, Polynomial.SEED);
+
+    }
+
+    /******************************************************************************************************************************************************
+     * Description:	Encode Public Key for Heuristic qTESLA Security Category-3 (Option for Speed)
+     *
+     * @param        publicKey            Public Key
+     * @param        T                    T_1, ..., T_k
+     * @param        seedA                Seed Used to Generate the Polynomials a_i for i = 1, ..., k
+     * @param        seedAOffset            Starting Point of the Seed A
+     *
+     * @return none
+     ******************************************************************************************************************************************************/
+    public static void encodePublicKeyIIISpeed(byte[] publicKey, final int[] T, final byte[] seedA, int seedAOffset)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < Parameter.N_III_SPEED * Parameter.Q_LOGARITHM_III_SPEED / Const.INT_SIZE; i += (Parameter.Q_LOGARITHM_III_SPEED / Const.BYTE_SIZE))
+        {
+
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 0), (int)(T[j + 0] | (T[j + 1] << 24)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 1), (int)((T[j + 1] >> 8) | (T[j + 2] << 16)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 2), (int)((T[j + 2] >> 16) | (T[j + 3] << 8)));
+
+            j += Const.INT_SIZE / Const.BYTE_SIZE;
+
+        }
+
+        System.arraycopy(seedA, seedAOffset, publicKey, Parameter.N_III_SPEED * Parameter.Q_LOGARITHM_III_SPEED / Const.BYTE_SIZE, Polynomial.SEED);
+
+    }
+
+    /*******************************************************************************************************************************************************
+     * Description:	Encode Public Key for Provably-Secure qTESLA Security Category-1
+     *
+     * @param        publicKey            Public Key
+     * @param        T                    T_1, ..., T_k
+     * @param        seedA                Seed Used to Generate the Polynomials a_i for i = 1, ..., k
+     * @param        seedAOffset            Starting Point of the Seed A
+     *
+     * @return none
+     *******************************************************************************************************************************************************/
+    public static void encodePublicKeyIP(byte[] publicKey, final long[] T, final byte[] seedA, int seedAOffset)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < Parameter.N_I_P * Parameter.K_I_P * Parameter.Q_LOGARITHM_I_P / Const.INT_SIZE; i += Parameter.Q_LOGARITHM_I_P)
+        {
+
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 0), (int)(T[j + 0] | (T[j + 1] << 29)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 1), (int)((T[j + 1] >> 3) | (T[j + 2] << 26)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 2), (int)((T[j + 2] >> 6) | (T[j + 3] << 23)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 3), (int)((T[j + 3] >> 9) | (T[j + 4] << 20)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 4), (int)((T[j + 4] >> 12) | (T[j + 5] << 17)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 5), (int)((T[j + 5] >> 15) | (T[j + 6] << 14)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 6), (int)((T[j + 6] >> 18) | (T[j + 7] << 11)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 7), (int)((T[j + 7] >> 21) | (T[j + 8] << 8)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 8), (int)((T[j + 8] >> 24) | (T[j + 9] << 5)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 9), (int)((T[j + 9] >> 27) | (T[j + 10] << 2) | (T[j + 11] << 31)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 10), (int)((T[j + 11] >> 1) | (T[j + 12] << 28)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 11), (int)((T[j + 12] >> 4) | (T[j + 13] << 25)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 12), (int)((T[j + 13] >> 7) | (T[j + 14] << 22)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 13), (int)((T[j + 14] >> 10) | (T[j + 15] << 19)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 14), (int)((T[j + 15] >> 13) | (T[j + 16] << 16)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 15), (int)((T[j + 16] >> 16) | (T[j + 17] << 13)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 16), (int)((T[j + 17] >> 19) | (T[j + 18] << 10)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 17), (int)((T[j + 18] >> 22) | (T[j + 19] << 7)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 18), (int)((T[j + 19] >> 25) | (T[j + 20] << 4)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 19), (int)((T[j + 20] >> 28) | (T[j + 21] << 1) | (T[j + 22] << 30)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 20), (int)((T[j + 22] >> 2) | (T[j + 23] << 27)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 21), (int)((T[j + 23] >> 5) | (T[j + 24] << 24)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 22), (int)((T[j + 24] >> 8) | (T[j + 25] << 21)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 23), (int)((T[j + 25] >> 11) | (T[j + 26] << 18)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 24), (int)((T[j + 26] >> 14) | (T[j + 27] << 15)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 25), (int)((T[j + 27] >> 17) | (T[j + 28] << 12)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 26), (int)((T[j + 28] >> 20) | (T[j + 29] << 9)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 27), (int)((T[j + 29] >> 23) | (T[j + 30] << 6)));
+            CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + 28), (int)((T[j + 30] >> 26) | (T[j + 31] << 3)));
+
+            j += Const.INT_SIZE;
+
+        }
+
+        System.arraycopy(seedA, seedAOffset, publicKey, Parameter.N_I_P * Parameter.K_I_P * Parameter.Q_LOGARITHM_I_P / Const.BYTE_SIZE, Polynomial.SEED);
+
+    }
+
+    /*************************************************************************************************************************************************************************************
+     * Description:	Encode Public Key for Provably-Secure qTESLA Security Category-3
+     *
+     * @param        publicKey            Public Key
+     * @param        T                    T_1, ..., T_k
+     * @param        seedA                Seed Used to Generate the Polynomials a_i for i = 1, ..., k
+     * @param        seedAOffset            Starting Point of the Seed A
+     *
+     * @return none
+     *************************************************************************************************************************************************************************************/
+    public static void encodePublicKeyIIIP(byte[] publicKey, final long[] T, final byte[] seedA, int seedAOffset)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < Parameter.N_III_P * Parameter.K_III_P * Parameter.Q_LOGARITHM_III_P / Const.INT_SIZE; i += Parameter.Q_LOGARITHM_III_P)
+        {
+
+            for (int index = 0; index < Parameter.Q_LOGARITHM_III_P; index++)
+            {
+
+                CommonFunction.store32(publicKey, Const.INT_SIZE / Const.BYTE_SIZE * (i + index), (int)((T[j + index] >> index) | (T[j + index + 1] << (Parameter.Q_LOGARITHM_III_P - index))));
+
+            }
+
+            j += Const.INT_SIZE;
+
+        }
+
+        System.arraycopy(seedA, seedAOffset, publicKey, Parameter.N_III_P * Parameter.K_III_P * Parameter.Q_LOGARITHM_III_P / Const.BYTE_SIZE, Polynomial.SEED);
+
+    }
+
+    /****************************************************************************************************************************************
+     * Description:	Decode Public Key for Heuristic qTESLA Security Category-1 and Category-3 (Option for Size)
+     *
+     * @param        publicKey            Decoded Public Key
+     * @param        seedA                Seed Used to Generate the Polynomials A_i for i = 1, ..., k
+     * @param        seedAOffset            Starting Point of the Seed A
+     * @param        publicKeyInput        Public Key to be Decoded
+     * @param        n                    Polynomial Degree
+     * @param        qLogarithm            q <= 2 ^ qLogartihm
+     *
+     * @return none
+     ****************************************************************************************************************************************/
+    public static void decodePublicKey(int[] publicKey, byte[] seedA, int seedAOffset, final byte[] publicKeyInput, int n, int qLogarithm)
+    {
+
+        int j = 0;
+
+        int mask = (1 << qLogarithm) - 1;
+
+        for (int i = 0; i < n; i += Const.INT_SIZE)
+        {
+
+            publicKey[i + 0] = CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) & mask;
+
+            publicKey[i + 1] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) >>> 23) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) << 9)) & mask;
+
+            publicKey[i + 2] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) >>> 14) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) << 18)) & mask;
+
+            publicKey[i + 3] = (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) >>> 5) & mask;
+
+            publicKey[i + 4] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) >>> 28) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) << 4)) & mask;
+
+            publicKey[i + 5] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) >>> 19) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) << 13)) & mask;
+
+            publicKey[i + 6] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) >>> 10) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) << 22)) & mask;
+
+            publicKey[i + 7] = (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) >>> 1) & mask;
+
+            publicKey[i + 8] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) >>> 24) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) << 8)) & mask;
+
+            publicKey[i + 9] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) >>> 15) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) << 17)) & mask;
+
+            publicKey[i + 10] = (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) >>> 6) & mask;
+
+            publicKey[i + 11] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) >>> 29) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) << 3)) & mask;
+
+            publicKey[i + 12] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) >>> 20) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) << 12)) & mask;
+
+            publicKey[i + 13] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) >>> 11) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) << 21)) & mask;
+
+            publicKey[i + 14] = (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) >>> 2) & mask;
+
+            publicKey[i + 15] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) >>> 25) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 11)) << 7)) & mask;
+
+            publicKey[i + 16] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 11)) >>> 16) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 12)) << 16)) & mask;
+
+            publicKey[i + 17] = (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 12)) >>> 7) & mask;
+
+            publicKey[i + 18] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 12)) >>> 30) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 13)) << 2)) & mask;
+
+            publicKey[i + 19] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 13)) >>> 21) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 14)) << 11)) & mask;
+
+            publicKey[i + 20] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 14)) >>> 12) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 15)) << 20)) & mask;
+
+            publicKey[i + 21] = (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 15)) >>> 3) & mask;
+
+            publicKey[i + 22] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 15)) >>> 26) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 16)) << 6)) & mask;
+
+            publicKey[i + 23] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 16)) >>> 17) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 17)) << 15)) & mask;
+
+            publicKey[i + 24] = (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 17)) >>> 8) & mask;
+
+            publicKey[i + 25] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 17)) >>> 31) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 18)) << 1)) & mask;
+
+            publicKey[i + 26] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 18)) >>> 22) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 19)) << 10)) & mask;
+
+            publicKey[i + 27] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 19)) >>> 13) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 20)) << 19)) & mask;
+
+            publicKey[i + 28] = (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 20)) >>> 4) & mask;
+
+            publicKey[i + 29] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 20)) >>> 27) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 21)) << 5)) & mask;
+
+            publicKey[i + 30] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 21)) >>> 18) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 22)) << 14)) & mask;
+
+            publicKey[i + 31] = CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 22)) >>> 9;
+
+            j += qLogarithm;
+
+        }
+
+        System.arraycopy(publicKeyInput, n * qLogarithm / Const.BYTE_SIZE, seedA, seedAOffset, Polynomial.SEED);
+
+    }
+
+    /*************************************************************************************************************************************************
+     * Description:	Decode Public Key for Heuristic qTESLA Security Category-3 (Option for Speed)
+     *
+     * @param        publicKey            Decoded Public Key
+     * @param        seedA                Seed Used to Generate the Polynomials A_i for i = 1, ..., k
+     * @param        seedAOffset            Starting Point of the Seed A
+     * @param        publicKeyInput        Public Key to be Decoded
+     *
+     * @return none
+     *************************************************************************************************************************************************/
+    public static void decodePublicKeyIIISpeed(int[] publicKey, byte[] seedA, int seedAOffset, final byte[] publicKeyInput)
+    {
+
+        int j = 0;
+
+        int mask = (1 << Parameter.Q_LOGARITHM_III_SPEED) - 1;
+
+        for (int i = 0; i < Parameter.N_III_SPEED; i += Const.INT_SIZE / Const.BYTE_SIZE)
+        {
+
+            publicKey[i + 0] = CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) & mask;
+
+            publicKey[i + 1] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) >>> 24) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) << 8)) & mask;
+
+            publicKey[i + 2] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) >>> 16) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) << 16)) & mask;
+
+            publicKey[i + 3] = CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) >>> 8;
+
+            j += Parameter.Q_LOGARITHM_III_SPEED / Const.BYTE_SIZE;
+
+        }
+
+        System.arraycopy(publicKeyInput, Parameter.N_III_SPEED * Parameter.Q_LOGARITHM_III_SPEED / Const.BYTE_SIZE, seedA, seedAOffset, Polynomial.SEED);
+
+    }
+
+    /************************************************************************************************************************************************************
+     * Description:	Decode Public Key for Provably-Secure qTESLA Security Category-1
+     *
+     * @param        publicKey            Decoded Public Key
+     * @param        seedA                Seed Used to Generate the Polynomials A_i for i = 1, ..., k
+     * @param        seedAOffset            Starting Point of the Seed A
+     * @param        publicKeyInput        Public Key to be Decoded
+     *
+     * @return none
+     ************************************************************************************************************************************************************/
+    public static void decodePublicKeyIP(int[] publicKey, byte[] seedA, int seedAOffset, final byte[] publicKeyInput)
+    {
+
+        int j = 0;
+
+        int mask = (1 << Parameter.Q_LOGARITHM_I_P) - 1;
+
+        for (int i = 0; i < Parameter.N_I_P * Parameter.K_I_P; i += Const.INT_SIZE)
+        {
+
+            publicKey[i + 0] = CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) & mask;
+
+            publicKey[i + 1] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) >>> 29) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) << 3)) & mask;
+
+            publicKey[i + 2] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) >>> 26) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) << 6)) & mask;
+
+            publicKey[i + 3] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) >>> 23) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) << 9)) & mask;
+
+            publicKey[i + 4] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) >>> 20) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) << 12)) & mask;
+
+            publicKey[i + 5] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) >>> 17) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) << 15)) & mask;
+
+            publicKey[i + 6] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) >>> 14) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) << 18)) & mask;
+
+            publicKey[i + 7] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) >>> 11) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) << 21)) & mask;
+
+            publicKey[i + 8] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) >>> 8) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) << 24)) & mask;
+
+            publicKey[i + 9] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) >>> 5) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) << 27)) & mask;
+
+            publicKey[i + 10] = (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) >>> 2) & mask;
+
+            publicKey[i + 11] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) >>> 31) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) << 1)) & mask;
+
+            publicKey[i + 12] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) >>> 28) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 11)) << 4)) & mask;
+
+            publicKey[i + 13] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 11)) >>> 25) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 12)) << 7)) & mask;
+
+            publicKey[i + 14] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 12)) >>> 22) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 13)) << 10)) & mask;
+
+            publicKey[i + 15] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 13)) >>> 19) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 14)) << 13)) & mask;
+
+            publicKey[i + 16] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 14)) >>> 16) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 15)) << 16)) & mask;
+
+            publicKey[i + 17] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 15)) >>> 13) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 16)) << 19)) & mask;
+
+            publicKey[i + 18] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 16)) >>> 10) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 17)) << 22)) & mask;
+
+            publicKey[i + 19] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 17)) >>> 7) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 18)) << 25)) & mask;
+
+            publicKey[i + 20] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 18)) >>> 4) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 19)) << 28)) & mask;
+
+            publicKey[i + 21] = (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 19)) >>> 1) & mask;
+
+            publicKey[i + 22] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 19)) >>> 30) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 20)) << 2)) & mask;
+
+            publicKey[i + 23] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 20)) >>> 27) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 21)) << 5)) & mask;
+
+            publicKey[i + 24] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 21)) >>> 24) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 22)) << 8)) & mask;
+
+            publicKey[i + 25] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 22)) >>> 21) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 23)) << 11)) & mask;
+
+            publicKey[i + 26] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 23)) >>> 18) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 24)) << 14)) & mask;
+
+            publicKey[i + 27] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 24)) >>> 15) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 25)) << 17)) & mask;
+
+            publicKey[i + 28] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 25)) >>> 12) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 26)) << 20)) & mask;
+
+            publicKey[i + 29] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 26)) >>> 9) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 27)) << 23)) & mask;
+
+            publicKey[i + 30] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 27)) >>> 6) |
+                (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 28)) << 26)) & mask;
+
+            publicKey[i + 31] = CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + 28)) >>> 3;
+
+            j += Parameter.Q_LOGARITHM_I_P;
+
+        }
+
+        System.arraycopy(publicKeyInput, Parameter.N_I_P * Parameter.K_I_P * Parameter.Q_LOGARITHM_I_P / Const.BYTE_SIZE, seedA, seedAOffset, Polynomial.SEED);
+
+    }
+
+    /****************************************************************************************************************************************************************
+     * Description:	Decode Public Key for Provably-Secure qTESLA Security Category-3
+     *
+     * @param        publicKey            Decoded Public Key
+     * @param        seedA                Seed Used to Generate the Polynomials A_i for i = 1, ..., k
+     * @param        seedAOffset            Starting Point of the Seed A
+     * @param        publicKeyInput        Public Key to be Decoded
+     *
+     * @return none
+     ****************************************************************************************************************************************************************/
+    public static void decodePublicKeyIIIP(int[] publicKey, byte[] seedA, int seedAOffset, final byte[] publicKeyInput)
+    {
+
+        int j = 0;
+
+        int mask = (1 << Parameter.Q_LOGARITHM_III_P) - 1;
+
+        for (int i = 0; i < Parameter.N_III_P * Parameter.K_III_P; i += Const.INT_SIZE)
+        {
+
+            publicKey[i] = CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * j) & mask;
+
+            for (int index = 1; index < Parameter.Q_LOGARITHM_III_P; index++)
+            {
+
+                publicKey[i + index] = ((CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + index - 1)) >>> (Const.INT_SIZE - index)) |
+                    (CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + index)) << index)) & mask;
+
+            }
+
+            publicKey[i + Parameter.Q_LOGARITHM_III_P] = CommonFunction.load32(publicKeyInput, Const.INT_SIZE / Const.BYTE_SIZE * (j + Parameter.Q_LOGARITHM_III_P - 1)) >>> 1;
+
+            j += Parameter.Q_LOGARITHM_III_P;
+
+        }
+
+        System.arraycopy(publicKeyInput, Parameter.N_III_P * Parameter.K_III_P * Parameter.Q_LOGARITHM_III_P / Const.BYTE_SIZE, seedA, seedAOffset, Polynomial.SEED);
+
+    }
+
+
+    /***************************************************************************************************************************************************************************************************************
+     * Description:	Encode Signature for Heuristic qTESLA Security Category-1 and Category-3 (Option for Size)
+     *
+     * @param        signature            Output Package Containing Signature
+     * @param        signatureOffset        Starting Point of the Output Package Containing Signature
+     * @param        C
+     * @param        cOffset
+     * @param        Z
+     * @param        n                    Polynomial Degree
+     * @param        d                    Number of Rounded Bits
+     *
+     * @return none
+     ***************************************************************************************************************************************************************************************************************/
+    public static void encodeSignature(byte[] signature, int signatureOffset, byte[] C, int cOffset, int[] Z, int n, int d)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < (n * d / Const.INT_SIZE); i += d)
+        {
+
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 0), (int)(((Z[j + 0] & ((1 << 21) - 1))) | (Z[j + 1] << 21)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 1), (int)(((Z[j + 1] >>> 11) & ((1 << 10) - 1)) | ((Z[j + 2] & ((1 << 21) - 1)) << 10) | (Z[j + 3] << 31)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 2), (int)((((Z[j + 3] >>> 1) & ((1 << 20) - 1))) | (Z[j + 4] << 20)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 3), (int)(((Z[j + 4] >>> 12) & ((1 << 9) - 1)) | ((Z[j + 5] & ((1 << 21) - 1)) << 9) | (Z[j + 6] << 30)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 4), (int)((((Z[j + 6] >>> 2) & ((1 << 19) - 1))) | (Z[j + 7] << 19)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 5), (int)(((Z[j + 7] >>> 13) & ((1 << 8) - 1)) | ((Z[j + 8] & ((1 << 21) - 1)) << 8) | (Z[j + 9] << 29)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 6), (int)((((Z[j + 9] >>> 3) & ((1 << 18) - 1))) | (Z[j + 10] << 18)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 7), (int)(((Z[j + 10] >>> 14) & ((1 << 7) - 1)) | ((Z[j + 11] & ((1 << 21) - 1)) << 7) | (Z[j + 12] << 28)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 8), (int)((((Z[j + 12] >>> 4) & ((1 << 17) - 1))) | (Z[j + 13] << 17)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 9), (int)(((Z[j + 13] >>> 15) & ((1 << 6) - 1)) | ((Z[j + 14] & ((1 << 21) - 1)) << 6) | (Z[j + 15] << 27)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 10), (int)((((Z[j + 15] >>> 5) & ((1 << 16) - 1))) | (Z[j + 16] << 16)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 11), (int)(((Z[j + 16] >>> 16) & ((1 << 5) - 1)) | ((Z[j + 17] & ((1 << 21) - 1)) << 5) | (Z[j + 18] << 26)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 12), (int)((((Z[j + 18] >>> 6) & ((1 << 15) - 1))) | (Z[j + 19] << 15)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 13), (int)(((Z[j + 19] >>> 17) & ((1 << 4) - 1)) | ((Z[j + 20] & ((1 << 21) - 1)) << 4) | (Z[j + 21] << 25)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 14), (int)((((Z[j + 21] >>> 7) & ((1 << 14) - 1))) | (Z[j + 22] << 14)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 15), (int)(((Z[j + 22] >>> 18) & ((1 << 3) - 1)) | ((Z[j + 23] & ((1 << 21) - 1)) << 3) | (Z[j + 24] << 24)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 16), (int)((((Z[j + 24] >>> 8) & ((1 << 13) - 1))) | (Z[j + 25] << 13)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 17), (int)(((Z[j + 25] >>> 19) & ((1 << 2) - 1)) | ((Z[j + 26] & ((1 << 21) - 1)) << 2) | (Z[j + 27] << 23)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 18), (int)((((Z[j + 27] >>> 9) & ((1 << 12) - 1))) | (Z[j + 28] << 12)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 19), (int)(((Z[j + 28] >>> 20) & ((1 << 1) - 1)) | ((Z[j + 29] & ((1 << 21) - 1)) << 1) | (Z[j + 30] << 22)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 20), (int)((((Z[j + 30] >>> 10) & ((1 << 11) - 1))) | (Z[j + 31] << 11)));
+
+            j += Const.INT_SIZE;
+
+        }
+
+        System.arraycopy(C, cOffset, signature, signatureOffset + n * d / Const.BYTE_SIZE, Polynomial.HASH);
+
+    }
+
+    /*************************************************************************************************************************************************************************************************************
+     * Description:	Encode Signature for Heuristic qTESLA Security Category-3 (Option for Speed)
+     *
+     * @param        signature            Output Package Containing Signature
+     * @param        signatureOffset        Starting Point of the Output Package Containing Signature
+     * @param        C
+     * @param        cOffset
+     * @param        Z
+     *
+     * @return none
+     *************************************************************************************************************************************************************************************************************/
+    public static void encodeSignatureIIISpeed(byte[] signature, int signatureOffset, byte[] C, int cOffset, int[] Z)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < (Parameter.N_III_SPEED * Parameter.D_III_SPEED / Const.INT_SIZE); i += Parameter.D_III_SPEED / 2)
+        {
+
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 0), (int)(((Z[j + 0] & ((1 << 22) - 1))) | (Z[j + 1] << 22)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 1), (int)((((Z[j + 1] >>> 10) & ((1 << 12) - 1))) | (Z[j + 2] << 12)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 2), (int)(((Z[j + 2] >>> 20) & ((1 << 2) - 1)) | ((Z[j + 3] & ((1 << 22) - 1)) << 2) | (Z[j + 4] << 24)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 3), (int)((((Z[j + 4] >>> 8) & ((1 << 14) - 1))) | (Z[j + 5] << 14)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 4), (int)(((Z[j + 5] >>> 18) & ((1 << 4) - 1)) | ((Z[j + 6] & ((1 << 22) - 1)) << 4) | (Z[j + 7] << 26)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 5), (int)((((Z[j + 7] >>> 6) & ((1 << 16) - 1))) | (Z[j + 8] << 16)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 6), (int)(((Z[j + 8] >>> 16) & ((1 << 6) - 1)) | ((Z[j + 9] & ((1 << 22) - 1)) << 6) | (Z[j + 10] << 28)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 7), (int)((((Z[j + 10] >>> 4) & ((1 << 18) - 1))) | (Z[j + 11] << 18)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 8), (int)(((Z[j + 11] >>> 14) & ((1 << 8) - 1)) | ((Z[j + 12] & ((1 << 22) - 1)) << 8) | (Z[j + 13] << 30)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 9), (int)((((Z[j + 13] >>> 2) & ((1 << 20) - 1))) | (Z[j + 14] << 20)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 10), (int)((((Z[j + 14] >>> 12) & ((1 << 10) - 1))) | (Z[j + 15] << 10)));
+
+            j += Const.INT_SIZE / 2;
+
+        }
+
+        System.arraycopy(C, cOffset, signature, signatureOffset + Parameter.N_III_SPEED * Parameter.D_III_SPEED / Const.BYTE_SIZE, Polynomial.HASH);
+
+    }
+
+    /*************************************************************************************************************************************************************************************************************
+     * Description:	Encode Signature for Provably-Secure qTESLA Security Category-1
+     *
+     * @param        signature            Output Package Containing Signature
+     * @param        signatureOffset        Starting Point of the Output Package Containing Signature
+     * @param        C
+     * @param        cOffset
+     * @param        Z
+     *
+     * @return none
+     *************************************************************************************************************************************************************************************************************/
+    public static void encodeSignatureIP(byte[] signature, int signatureOffset, byte[] C, int cOffset, long[] Z)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < (Parameter.N_III_SPEED * Parameter.D_III_SPEED / Const.INT_SIZE); i += Parameter.D_III_SPEED / 2)
+        {
+
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 0), (int)(((Z[j + 0] & ((1 << 22) - 1))) | (Z[j + 1] << 22)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 1), (int)((((Z[j + 1] >>> 10) & ((1 << 12) - 1))) | (Z[j + 2] << 12)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 2), (int)(((Z[j + 2] >>> 20) & ((1 << 2) - 1)) | ((Z[j + 3] & ((1 << 22) - 1)) << 2) | (Z[j + 4] << 24)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 3), (int)((((Z[j + 4] >>> 8) & ((1 << 14) - 1))) | (Z[j + 5] << 14)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 4), (int)(((Z[j + 5] >>> 18) & ((1 << 4) - 1)) | ((Z[j + 6] & ((1 << 22) - 1)) << 4) | (Z[j + 7] << 26)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 5), (int)((((Z[j + 7] >>> 6) & ((1 << 16) - 1))) | (Z[j + 8] << 16)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 6), (int)(((Z[j + 8] >>> 16) & ((1 << 6) - 1)) | ((Z[j + 9] & ((1 << 22) - 1)) << 6) | (Z[j + 10] << 28)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 7), (int)((((Z[j + 10] >>> 4) & ((1 << 18) - 1))) | (Z[j + 11] << 18)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 8), (int)(((Z[j + 11] >>> 14) & ((1 << 8) - 1)) | ((Z[j + 12] & ((1 << 22) - 1)) << 8) | (Z[j + 13] << 30)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 9), (int)((((Z[j + 13] >>> 2) & ((1 << 20) - 1))) | (Z[j + 14] << 20)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 10), (int)((((Z[j + 14] >>> 12) & ((1 << 10) - 1))) | (Z[j + 15] << 10)));
+
+            j += Const.INT_SIZE / 2;
+
+        }
+
+        System.arraycopy(C, cOffset, signature, signatureOffset + Parameter.N_III_SPEED * Parameter.D_III_SPEED / Const.BYTE_SIZE, Polynomial.HASH);
+
+    }
+
+    /***************************************************************************************************************************************************************
+     * Description:	Encode Signature for Provably-Secure qTESLA Security Category-3
+     *
+     * @param        signature            Output Package Containing Signature
+     * @param        signatureOffset        Starting Point of the Output Package Containing Signature
+     * @param        C
+     * @param        cOffset
+     * @param        Z
+     *
+     * @return none
+     ***************************************************************************************************************************************************************/
+    public static void encodeSignatureIIIP(byte[] signature, int signatureOffset, byte[] C, int cOffset, long[] Z)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < (Parameter.N_III_P * Parameter.D_III_P / Const.INT_SIZE); i += Parameter.D_III_P / Const.BYTE_SIZE)
+        {
+
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 0), (int)(((Z[j + 0] & ((1 << 24) - 1))) | (Z[j + 1] << 24)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 1), (int)((((Z[j + 1] >>> 8) & ((1 << 16) - 1))) | (Z[j + 2] << 16)));
+            CommonFunction.store32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (i + 2), (int)((((Z[j + 2] >>> 16) & ((1 << 8) - 1))) | (Z[j + 3] << 8)));
+
+            j += Const.BYTE_SIZE / 2;
+
+        }
+
+        System.arraycopy(C, cOffset, signature, signatureOffset + Parameter.N_III_P * Parameter.D_III_P / Const.BYTE_SIZE, Polynomial.HASH);
+
+    }
+
+    /******************************************************************************************************************************
+     * Description:	Decode Signature for Heuristic qTESLA Security Category-1 and Category-3 (Option for Size)
+     *
+     * @param    C
+     * @param    Z
+     * @param    signature            Output Package Containing Signature
+     * @param    signatureOffset        Starting Point of the Output Package Containing Signature
+     * @param    n                    Polynomial Degree
+     * @param    d                    Number of Rounded Bits
+     *
+     * @return none
+     ******************************************************************************************************************************/
+    public static void decodeSignature(byte[] C, int[] Z, final byte[] signature, int signatureOffset, int n, int d)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < n; i += Const.INT_SIZE)
+        {
+
+            Z[i + 0] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) << 11) >> 11;
+
+            Z[i + 1] = ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) >>> 21) |
+                (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) << 22) >> 11);
+
+            Z[i + 2] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) << 1) >> 11;
+
+            Z[i + 3] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) >>> 31) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) << 12) >> 11);
+
+            Z[i + 4] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) >>> 20) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) << 23) >> 11);
+
+            Z[i + 5] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) << 2) >> 11;
+
+            Z[i + 6] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) >>> 30) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) << 13) >> 11);
+
+            Z[i + 7] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) >>> 19) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) << 24) >> 11);
+
+            Z[i + 8] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) << 3) >> 11;
+
+            Z[i + 9] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) >>> 29) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) << 14) >> 11);
+
+            Z[i + 10] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) >>> 18) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) << 25) >> 11);
+
+            Z[i + 11] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) << 4) >> 11;
+
+            Z[i + 12] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) >>> 28) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) << 15) >> 11);
+
+            Z[i + 13] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) >>> 17) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) << 26) >> 11);
+
+            Z[i + 14] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) << 5) >> 11;
+
+            Z[i + 15] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) >>> 27) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) << 16) >> 11);
+
+            Z[i + 16] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) >>> 16) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 11)) << 27) >> 11);
+
+            Z[i + 17] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 11)) << 6) >> 11;
+
+            Z[i + 18] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 11)) >>> 26) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 12)) << 17) >> 11);
+
+            Z[i + 19] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 12)) >>> 15) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 13)) << 28) >> 11);
+
+            Z[i + 20] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 13)) << 7) >> 11;
+
+            Z[i + 21] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 13)) >>> 25) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 14)) << 18) >> 11);
+
+            Z[i + 22] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 14)) >>> 14) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 15)) << 29) >> 11);
+
+            Z[i + 23] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 15)) << 8) >> 11;
+
+            Z[i + 24] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 15)) >>> 24) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 16)) << 19) >> 11);
+
+            Z[i + 25] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 16)) >>> 13) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 17)) << 30) >> 11);
+
+            Z[i + 26] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 17)) << 9) >> 11;
+
+            Z[i + 27] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 17)) >>> 23) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 18)) << 20) >> 11);
+
+            Z[i + 28] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 18)) >>> 12) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 19)) << 31) >> 11);
+
+            Z[i + 29] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 19)) << 10) >> 11;
+
+            Z[i + 30] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 19)) >>> 22) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 20)) << 21) >> 11);
+
+            Z[i + 31] = CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 20)) >> 11;
+
+            j += d;
+
+        }
+
+        System.arraycopy(signature, signatureOffset + n * d / Const.BYTE_SIZE, C, 0, Polynomial.HASH);
+
+    }
+
+    /**************************************************************************************************************************************
+     * Description:	Decode Signature for Heuristic qTESLA Security Category-3 (Option for Speed)
+     *
+     * @param    C
+     * @param    Z
+     * @param    signature            Output Package Containing Signature
+     * @param    signatureOffset        Starting Point of the Output Package Containing Signature
+     *
+     * @return none
+     **************************************************************************************************************************************/
+    public static void decodeSignatureIIISpeed(byte[] C, int[] Z, final byte[] signature, int signatureOffset)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < Parameter.N_III_SPEED; i += Const.INT_SIZE / 2)
+        {
+
+            Z[i + 0] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) << 10) >> 10;
+
+            Z[i + 1] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) >>> 22) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) << 20) >> 10);
+
+            Z[i + 2] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) >>> 12) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) << 30) >> 10);
+
+            Z[i + 3] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) << 8) >> 10;
+
+            Z[i + 4] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) >>> 24) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) << 18) >> 10);
+
+            Z[i + 5] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) >>> 14) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) << 28) >> 10);
+
+            Z[i + 6] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) << 6) >> 10;
+
+            Z[i + 7] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) >>> 26) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) << 16) >> 10);
+
+            Z[i + 8] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) >>> 16) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) << 26) >> 10);
+
+            Z[i + 9] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) << 4) >> 10;
+
+            Z[i + 10] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) >>> 28) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) << 14) >> 10);
+
+            Z[i + 11] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) >>> 18) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) << 24) >> 10);
+
+            Z[i + 12] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) << 2) >> 10;
+
+            Z[i + 13] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) >>> 30) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) << 12) >> 10);
+
+            Z[i + 14] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) >>> 20) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) << 22) >> 10);
+
+            Z[i + 15] = CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) >> 10;
+
+            j += Parameter.D_III_SPEED / 2;
+
+        }
+
+        System.arraycopy(signature, signatureOffset + Parameter.N_III_SPEED * Parameter.D_III_SPEED / Const.BYTE_SIZE, C, 0, Polynomial.HASH);
+
+    }
+
+    /****************************************************************************************************************************
+     * Description:	Decode Signature for Provably-Secure qTESLA Security Category-1
+     *
+     * @param    C
+     * @param    Z
+     * @param    signature            Output Package Containing Signature
+     * @param    signatureOffset        Starting Point of the Output Package Containing Signature
+     *
+     * @return none
+     ****************************************************************************************************************************/
+    public static void decodeSignatureIP(byte[] C, long[] Z, final byte[] signature, int signatureOffset)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < Parameter.N_I_P; i += Const.INT_SIZE / 2)
+        {
+
+            Z[i + 0] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) << 10) >> 10;
+
+            Z[i + 1] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) >>> 22) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) << 20) >> 10);
+
+            Z[i + 2] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) >>> 12) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) << 30) >> 10);
+
+            Z[i + 3] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) << 8) >> 10;
+
+            Z[i + 4] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) >>> 24) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) << 18) >> 10);
+
+            Z[i + 5] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 3)) >>> 14) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) << 28) >> 10);
+
+            Z[i + 6] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) << 6) >> 10;
+
+            Z[i + 7] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 4)) >>> 26) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) << 16) >> 10);
+
+            Z[i + 8] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 5)) >>> 16) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) << 26) >> 10);
+
+            Z[i + 9] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) << 4) >> 10;
+
+            Z[i + 10] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 6)) >>> 28) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) << 14) >> 10);
+
+            Z[i + 11] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 7)) >>> 18) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) << 24) >> 10);
+
+            Z[i + 12] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) << 2) >> 10;
+
+            Z[i + 13] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 8)) >>> 30) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) << 12) >> 10);
+
+            Z[i + 14] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 9)) >>> 20) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) << 22) >> 10);
+
+            Z[i + 15] = CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 10)) >> 10;
+
+            j += Parameter.D_I_P / 2;
+
+        }
+
+        System.arraycopy(signature, signatureOffset + Parameter.N_I_P * Parameter.D_I_P / Const.BYTE_SIZE, C, 0, Polynomial.HASH);
+
+    }
+
+    /****************************************************************************************************************************************
+     * Description:	Decode Signature for Provably-Secure qTESLA Security Category-3
+     *
+     * @param    C
+     * @param    Z
+     * @param    signature            Output Package Containing Signature
+     * @param    signatureOffset        Starting Point of the Output Package Containing Signature
+     *
+     * @return none
+     ****************************************************************************************************************************************/
+    public static void decodeSignatureIIIP(byte[] C, long[] Z, final byte[] signature, int signatureOffset)
+    {
+
+        int j = 0;
+
+        for (int i = 0; i < Parameter.N_III_P; i += Const.BYTE_SIZE / 2)
+        {
+
+            Z[i + 0] = (CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) << 8) >> 8;
+
+            Z[i + 1] = ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 0)) >>> 24) & ((1 << 8) - 1)) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) << 16) >> 8);
+
+            Z[i + 2] = ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 1)) >>> 16) & ((1 << 16) - 1)) |
+                ((CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) << 24) >> 8);
+
+            Z[i + 3] = CommonFunction.load32(signature, signatureOffset + Const.INT_SIZE / Const.BYTE_SIZE * (j + 2)) >> 8;
+
+            j += Const.BYTE_SIZE / 2 - 1;
+
+        }
+
+        System.arraycopy(signature, signatureOffset + Parameter.N_III_P * Parameter.D_III_P / Const.BYTE_SIZE, C, 0, Polynomial.HASH);
+
+    }
+
+}
\ No newline at end of file
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Parameter.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Parameter.java
new file mode 100644
index 000000000..ad970ee22
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Parameter.java
@@ -0,0 +1,413 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+final class Parameter
+{
+
+    /**
+     * Dimension, (Dimension - 1) is the Polynomial Degree for Heuristic qTESLA Security Category-1
+     */
+    public static final int N_I = 512;
+
+    /**
+     * Dimension, (Dimension - 1) is the Polynomial Degree for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int N_I_P = 1024;
+
+    /**
+     * Dimension, (Dimension - 1) is the Polynomial Degree for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int N_III_SIZE = 1024;
+
+    /**
+     * Dimension, (Dimension - 1) is the Polynomial Degree for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int N_III_SPEED = 1024;
+
+    /**
+     * Dimension, (Dimension - 1) is the Polynomial Degree for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int N_III_P = 2048;
+
+    /**
+     * N_LOGARITHM = LOGARITHM (N) / LOGARITHM (2) for Heuristic qTESLA Security Category-1
+     */
+    public static final int N_LOGARITHM_I = 9;
+
+    /**
+     * N_LOGARITHM = LOGARITHM (N) / LOGARITHM (2) for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int N_LOGARITHM_I_P = 10;
+
+    /**
+     * N_LOGARITHM = LOGARITHM (N) / LOGARITHM (2) for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int N_LOGARITHM_III_SIZE = 10;
+
+    /**
+     * N_LOGARITHM = LOGARITHM (N) / LOGARITHM (2) for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int N_LOGARITHM_III_SPEED = 10;
+
+    /**
+     * N_LOGARITHM = LOGARITHM (N) / LOGARITHM (2) for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int N_LOGARITHM_III_P = 11;
+
+    /**
+     * Modulus for Heuristic qTESLA Security Category-1
+     */
+    public static final int Q_I = 4205569;
+
+    /**
+     * Modulus for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int Q_I_P = 485978113;
+
+    /**
+     * Modulus for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int Q_III_SIZE = 4206593;
+
+    /**
+     * Modulus for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int Q_III_SPEED = 8404993;
+
+    /**
+     * Modulus for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int Q_III_P = 1129725953;
+
+    /**
+     * Q <= 2 ^ Q_LOGARITHM for Heuristic qTESLA Security Category-1
+     */
+    public static final int Q_LOGARITHM_I = 23;
+
+    /**
+     * Q <= 2 ^ Q_LOGARITHM for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int Q_LOGARITHM_I_P = 29;
+
+    /**
+     * Q <= 2 ^ Q_LOGARITHM for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int Q_LOGARITHM_III_SIZE = 23;
+
+    /**
+     * Q <= 2 ^ Q_LOGARITHM for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int Q_LOGARITHM_III_SPEED = 24;
+
+    /**
+     * Q <= 2 ^ Q_LOGARITHM for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int Q_LOGARITHM_III_P = 31;
+
+    public static final long Q_INVERSE_I = 3098553343L;
+    public static final long Q_INVERSE_I_P = 3421990911L;
+    public static final long Q_INVERSE_III_SIZE = 4148178943L;
+    public static final long Q_INVERSE_III_SPEED = 4034936831L;
+    public static final long Q_INVERSE_III_P = 861290495L;
+
+    /**
+     * B Determines the Interval the Randomness is Chosen in During Signing for Heuristic qTESLA Security Category-1
+     */
+    public static final int B_I = 1048575;
+
+    /**
+     * B Determines the Interval the Randomness is Chosen in During Signing for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int B_I_P = 2097151;
+
+    /**
+     * B Determines the Interval the Randomness is Chosen in During Signing for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int B_III_SIZE = 1048575;
+
+    /**
+     * B Determines the Interval the Randomness is Chosen in During Signing for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int B_III_SPEED = 2097151;
+
+    /**
+     * B Determines the Interval the Randomness is Chosen in During Signing for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int B_III_P = 8388607;
+
+    /**
+     * B = 2 ^ B_BIT - 1 for Heuristic qTESLA Security Category-1
+     */
+    public static final int B_BIT_I = 20;
+
+    /**
+     * B = 2 ^ B_BIT - 1 for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int B_BIT_I_P = 21;
+
+    /**
+     * B = 2 ^ B_BIT - 1 for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int B_BIT_III_SIZE = 20;
+
+    /**
+     * B = 2 ^ B_BIT - 1 for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int B_BIT_III_SPEED = 21;
+
+    /**
+     * B = 2 ^ B_BIT - 1 for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int B_BIT_III_P = 23;
+
+    public static final int S_BIT_I = 10;
+    public static final int S_BIT_I_P = 8;
+    public static final int S_BIT_III_SIZE = 8;
+    public static final int S_BIT_III_SPEED = 9;
+    public static final int S_BIT_III_P = 8;
+
+    /**
+     * Number of Ring-Learning-With-Errors Samples for Heuristic qTESLA Security Category-1
+     */
+    public static final int K_I = 1;
+
+    /**
+     * Number of Ring-Learning-With-Errors Samples for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int K_I_P = 4;
+
+    /**
+     * Number of Ring-Learning-With-Errors Samples for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int K_III_SIZE = 1;
+
+    /**
+     * Number of Ring-Learning-With-Errors Samples for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int K_III_SPEED = 1;
+
+    /**
+     * Number of Ring-Learning-With-Errors Samples for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int K_III_P = 5;
+
+    /**
+     * Number of Non-Zero Entries of Output Elements of Encryption for Heuristic qTESLA Security Category-1
+     */
+    public static final int H_I = 30;
+
+    /**
+     * Number of Non-Zero Entries of Output Elements of Encryption for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int H_I_P = 25;
+
+    /**
+     * Number of Non-Zero Entries of Output Elements of Encryption for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int H_III_SIZE = 48;
+
+    /**
+     * Number of Non-Zero Entries of Output Elements of Encryption for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int H_III_SPEED = 48;
+
+    /**
+     * Number of Non-Zero Entries of Output Elements of Encryption for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int H_III_P = 40;
+
+    /**
+     * Number of Rounded Bits for Heuristic qTESLA Security Category-1
+     */
+    public static final int D_I = 21;
+
+    /**
+     * Number of Rounded Bits for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int D_I_P = 22;
+
+    /**
+     * Number of Rounded Bits for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int D_III_SIZE = 21;
+
+    /**
+     * Number of Rounded Bits for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int D_III_SPEED = 22;
+
+    /**
+     * Number of Rounded Bits for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int D_III_P = 24;
+
+    /**
+     * Bound in Checking Error Polynomial for Heuristic qTESLA Security Category-1
+     */
+    public static final int KEY_GENERATOR_BOUND_E_I = 1586;
+
+    /**
+     * Bound in Checking Error Polynomial for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int KEY_GENERATOR_BOUND_E_I_P = 554;
+
+    /**
+     * Bound in Checking Error Polynomial for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int KEY_GENERATOR_BOUND_E_III_SIZE = 910;
+
+    /**
+     * Bound in Checking Error Polynomial for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int KEY_GENERATOR_BOUND_E_III_SPEED = 1147;
+
+    /**
+     * Bound in Checking Error Polynomial for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int KEY_GENERATOR_BOUND_E_III_P = 901;
+
+    public static final int REJECTION_I = KEY_GENERATOR_BOUND_E_I;
+    public static final int REJECTION_I_P = KEY_GENERATOR_BOUND_E_I_P;
+    public static final int REJECTION_III_SIZE = KEY_GENERATOR_BOUND_E_III_SIZE;
+    public static final int REJECTION_III_SPEED = KEY_GENERATOR_BOUND_E_III_SPEED;
+    public static final int REJECTION_III_P = KEY_GENERATOR_BOUND_E_III_P;
+
+    /**
+     * Bound in Checking Secret Polynomial for Heuristic qTESLA Security Category-1
+     */
+    public static final int KEY_GENERATOR_BOUND_S_I = 1586;
+
+    /**
+     * Bound in Checking Secret Polynomial for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int KEY_GENERATOR_BOUND_S_I_P = 554;
+
+    /**
+     * Bound in Checking Secret Polynomial for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int KEY_GENERATOR_BOUND_S_III_SIZE = 910;
+
+    /**
+     * Bound in Checking Secret Polynomial for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int KEY_GENERATOR_BOUND_S_III_SPEED = 1233;
+
+    /**
+     * Bound in Checking Secret Polynomial for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int KEY_GENERATOR_BOUND_S_III_P = 901;
+
+    public static final int U_I = KEY_GENERATOR_BOUND_S_I;
+    public static final int U_I_P = KEY_GENERATOR_BOUND_S_I_P;
+    public static final int U_III_SIZE = KEY_GENERATOR_BOUND_S_III_SIZE;
+    public static final int U_III_SPEED = KEY_GENERATOR_BOUND_S_III_SPEED;
+    public static final int U_III_P = KEY_GENERATOR_BOUND_S_III_P;
+
+    /**
+     * Standard Deviation of Centered Discrete Gaussian Distribution for Heuristic qTESLA Security Category-1
+     */
+    public static final double SIGMA_I = 22.93;
+
+    /**
+     * Standard Deviation of Centered Discrete Gaussian Distribution for Provably-Secure qTESLA Security Category-1
+     */
+    public static final double SIGMA_I_P = 8.5;
+
+    /**
+     * Standard Deviation of Centered Discrete Gaussian Distribution for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final double SIGMA_III_SIZE = 7.64;
+
+    /**
+     * Standard Deviation of Centered Discrete Gaussian Distribution for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final double SIGMA_III_SPEED = 10.2;
+
+    /**
+     * Standard Deviation of Centered Discrete Gaussian Distribution for Provably-Secure qTESLA Security Category-3
+     */
+    public static final double SIGMA_III_P = 8.5;
+
+    public static final double SIGMA_E_I = SIGMA_I;
+    public static final double SIGMA_E_I_P = SIGMA_I_P;
+    public static final double SIGMA_E_III_SIZE = SIGMA_III_SIZE;
+    public static final double SIGMA_E_III_SPEED = SIGMA_III_SPEED;
+    public static final double SIGMA_E_III_P = SIGMA_III_P;
+
+    /**
+     * XI = SIGMA * SQUARE_ROOT (2 * LOGARITHM (2) / LOGARITHM (e)) for Heuristic qTESLA Security Category-1
+     */
+    public static final double XI_I = 27;
+
+    /**
+     * XI = SIGMA * SQUARE_ROOT (2 * LOGARITHM (2) / LOGARITHM (e)) for Provably-Secure qTESLA Security Category-1
+     */
+    public static final double XI_I_P = 10;
+
+    /**
+     * XI = SIGMA * SQUARE_ROOT (2 * LOGARITHM (2) / LOGARITHM (e)) for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final double XI_III_SIZE = 9;
+
+    /**
+     * XI = SIGMA * SQUARE_ROOT (2 * LOGARITHM (2) / LOGARITHM (e)) for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final double XI_III_SPEED = 12;
+
+    /**
+     * XI = SIGMA * SQUARE_ROOT (2 * LOGARITHM (2) / LOGARITHM (e)) for Provably-Secure qTESLA Security Category-3
+     */
+    public static final double XI_III_P = 10;
+
+    public static final int BARRETT_MULTIPLICATION_I = 1021;
+    public static final int BARRETT_MULTIPLICATION_I_P = 1;
+    public static final int BARRETT_MULTIPLICATION_III_SIZE = 1021;
+    public static final int BARRETT_MULTIPLICATION_III_SPEED = 511;
+    public static final int BARRETT_MULTIPLICATION_III_P = 15;
+
+    public static final int BARRETT_DIVISION_I = 32;
+    public static final int BARRETT_DIVISION_I_P = 29;
+    public static final int BARRETT_DIVISION_III_SIZE = 32;
+    public static final int BARRETT_DIVISION_III_SPEED = 32;
+    public static final int BARRETT_DIVISION_III_P = 34;
+
+    /**
+     * The Number of Blocks Requested in the First Extendable-Output Function Call
+     * for Heuristic qTESLA Security Category-1
+     */
+    public static final int GENERATOR_A_I = 19;
+
+    /**
+     * The Number of Blocks Requested in the First Extendable-Output Function Call
+     * for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int GENERATOR_A_I_P = 108;
+
+    /**
+     * The Number of Blocks Requested in the First Extendable-Output Function Call
+     * for Provably-Secure qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int GENERATOR_A_III_SIZE = 38;
+
+    /**
+     * The Number of Blocks Requested in the First Extendable-Output Function Call
+     * for Provably-Secure qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int GENERATOR_A_III_SPEED = 38;
+
+    /**
+     * The Number of Blocks Requested in the First Extendable-Output Function Call
+     * for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int GENERATOR_A_III_P = 180;
+
+    public static final int INVERSE_NUMBER_THEORETIC_TRANSFORM_I = 113307;
+    public static final int INVERSE_NUMBER_THEORETIC_TRANSFORM_I_P = 472064468;
+    public static final int INVERSE_NUMBER_THEORETIC_TRANSFORM_III_SIZE = 1217638;
+    public static final int INVERSE_NUMBER_THEORETIC_TRANSFORM_III_SPEED = 237839;
+    public static final int INVERSE_NUMBER_THEORETIC_TRANSFORM_III_P = 851423148;
+
+    public static final int R_I = 1081347;
+    public static final int R_III_SIZE = 35843;
+    public static final int R_III_SPEED = 15873;
+
+}
\ No newline at end of file
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Polynomial.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Polynomial.java
new file mode 100644
index 000000000..664d3b8ee
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Polynomial.java
@@ -0,0 +1,1303 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+import com.fr.third.org.bouncycastle.util.Arrays;
+
+class Polynomial
+{
+
+    /**
+     * Size of A Random Number (in Byte)
+     */
+    public static final int RANDOM = 32;
+
+    /**
+     * Size of A Seed (in Byte)
+     */
+    public static final int SEED = 32;
+
+    /**
+     * Size of Hash Value C (in Byte) in the Signature Package
+     */
+    public static final int HASH = 32;
+
+    /**
+     * Size of Hashed Message
+     */
+    public static final int MESSAGE = 64;
+
+    /**
+     * Size of the Signature Package (Z, C) (in Byte) for Heuristic qTESLA Security Category-1.
+     * Z is A Polynomial Bounded by B and C is the Output of A Hashed String
+     */
+    public static final int SIGNATURE_I = (Parameter.N_I * Parameter.D_I + 7) / 8 + HASH;
+
+    /**
+     * Size of the Signature Package (Z, C) (in Byte) for Heuristic qTESLA Security Category-3 (Option for Size).
+     * Z is A Polynomial Bounded by B and C is the Output of A Hashed String
+     */
+    public static final int SIGNATURE_III_SIZE = (Parameter.N_III_SIZE * Parameter.D_III_SIZE + 7) / 8 + HASH;
+
+    /**
+     * Size of the Signature Package (Z, C) (in Byte) for Heuristic qTESLA Security Category-3 (Option for Speed).
+     * Z is A Polynomial Bounded by B and C is the Output of A Hashed String
+     */
+    public static final int SIGNATURE_III_SPEED = (Parameter.N_III_SPEED * Parameter.D_III_SPEED + 7) / 8 + HASH;
+
+    /**
+     * Size of the Signature Package (Z, C) (in Byte) for Provably-Secure qTESLA Security Category-1.
+     * Z is A Polynomial Bounded by B and C is the Output of A Hashed String
+     */
+    public static final int SIGNATURE_I_P = (Parameter.N_I_P * Parameter.D_I_P + 7) / 8 + HASH;
+
+    /**
+     * Size of the Signature Package (Z, C) (in Byte) for Provably-Secure qTESLA Security Category-3.
+     * Z is A Polynomial Bounded by B and C is the Output of A Hashed String
+     */
+    public static final int SIGNATURE_III_P = (Parameter.N_III_P * Parameter.D_III_P + 7) / 8 + HASH;
+
+    /**
+     * Size of the Public Key (in Byte) Containing seedA and Polynomial T for Heuristic qTESLA Security Category-1
+     */
+    public static final int PUBLIC_KEY_I = (Parameter.N_I * Parameter.K_I * Parameter.Q_LOGARITHM_I + 7) / 8 + SEED;
+
+    /**
+     * Size of the Public Key (in Byte) Containing seedA and Polynomial T for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int PUBLIC_KEY_III_SIZE = (Parameter.N_III_SIZE * Parameter.K_III_SIZE * Parameter.Q_LOGARITHM_III_SIZE + 7) / 8 + SEED;
+
+    /**
+     * Size of the Public Key (in Byte) Containing seedA and Polynomial T for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int PUBLIC_KEY_III_SPEED = (Parameter.N_III_SPEED * Parameter.K_III_SPEED * Parameter.Q_LOGARITHM_III_SPEED + 7) / 8 + SEED;
+
+    /**
+     * Size of the Public Key (in Byte) Containing seedA and Polynomial T for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int PUBLIC_KEY_I_P = (Parameter.N_I_P * Parameter.K_I_P * Parameter.Q_LOGARITHM_I_P + 7) / 8 + SEED;
+
+    /**
+     * Size of the Public Key (in Byte) Containing seedA and Polynomial T for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int PUBLIC_KEY_III_P = (Parameter.N_III_P * Parameter.K_III_P * Parameter.Q_LOGARITHM_III_P + 7) / 8 + SEED;
+
+    /**
+     * Size of the Private Key (in Byte) Containing Polynomials (Secret Polynomial and Error Polynomial) and Seeds (seedA and seedY)
+     * for Heuristic qTESLA Security Category-1
+     */
+    public static final int PRIVATE_KEY_I = Parameter.N_I * Parameter.S_BIT_I / Const.BYTE_SIZE * 2 + SEED * 2;
+
+    /**
+     * Size of the Private Key (in Byte) Containing Polynomials (Secret Polynomial and Error Polynomial) and Seeds (seedA and seedY)
+     * for Heuristic qTESLA Security Category-3 (Option for Size)
+     */
+    public static final int PRIVATE_KEY_III_SIZE = Parameter.N_III_SIZE * Parameter.S_BIT_III_SIZE / Const.BYTE_SIZE * 2 + SEED * 2;
+
+    /**
+     * Size of the Private Key (in Byte) Containing Polynomials (Secret Polynomial and Error Polynomial) and Seeds (seedA and seedY)
+     * for Heuristic qTESLA Security Category-3 (Option for Speed)
+     */
+    public static final int PRIVATE_KEY_III_SPEED = Parameter.N_III_SPEED * Parameter.S_BIT_III_SPEED / Const.BYTE_SIZE * 2 + SEED * 2;
+
+    /**
+     * Size of the Private Key (in Byte) Containing Polynomials (Secret Polynomial and Error Polynomial) and Seeds (seedA and seedY)
+     * for Provably-Secure qTESLA Security Category-1
+     */
+    public static final int PRIVATE_KEY_I_P = Parameter.N_I_P + Parameter.N_I_P * Parameter.K_I_P + SEED * 2;
+
+    /**
+     * Size of the Private Key (in Byte) Containing Polynomials (Secret Polynomial and Error Polynomial) and Seeds (seedA and seedY)
+     * for Provably-Secure qTESLA Security Category-3
+     */
+    public static final int PRIVATE_KEY_III_P = Parameter.N_III_P + Parameter.N_III_P * Parameter.K_III_P + SEED * 2;
+
+    /****************************************************************************
+     * Description:	Montgomery Reduction for Heuristic qTESLA Security Category 1
+     * 				and Security Category-3 (Option for Size and Speed)
+     *
+     * @param        number        Number to be Reduced
+     * @param        q            Modulus
+     * @param        qInverse
+     *
+     * @return Reduced Number
+     ****************************************************************************/
+    private static int montgomery(long number, int q, long qInverse)
+    {
+
+        return (int)((number + ((number * qInverse) & 0xFFFFFFFFL) * q) >> 32);
+
+    }
+
+    /****************************************************************************
+     * Description:	Montgomery Reduction for Provably-Secure qTESLA
+     * 				Security Category-1 and Security Category-3
+     *
+     * @param        number        Number to be Reduced
+     * @param        q            Modulus
+     * @param        qInverse
+     *
+     * @return Reduced Number
+     ****************************************************************************/
+    private static long montgomeryP(long number, int q, long qInverse)
+    {
+
+        return (number + ((number * qInverse) & 0xFFFFFFFFL) * q) >> 32;
+
+    }
+
+    /**********************************************************************************************
+     * Description:	Barrett Reduction for Heuristic qTESLA Security Category-3
+     * 				(Option for Size or Speed)
+     *
+     * @param        number                    Number to be Reduced
+     * @param        barrettMultiplication
+     * @param        barrettDivision
+     * @param        q                        Modulus
+     *
+     * @return Reduced Number
+     **********************************************************************************************/
+    public static int barrett(int number, int q, int barrettMultiplication, int barrettDivision)
+    {
+
+        return number - (int)(((long)number * barrettMultiplication) >> barrettDivision) * q;
+
+    }
+
+    /*************************************************************************************************
+     * Description:	Barrett Reduction for Provably-Secure qTESLA Security Category-1 and
+     * 				Security Category-3
+     *
+     * @param        number                    Number to be Reduced
+     * @param        barrettMultiplication
+     * @param        barrettDivision
+     * @param        q                        Modulus
+     *
+     * @return Reduced Number
+     *************************************************************************************************/
+    public static long barrett(long number, int q, int barrettMultiplication, int barrettDivision)
+    {
+
+        return number - ((number * barrettMultiplication) >> barrettDivision) * q;
+
+    }
+
+    /************************************************************************************************************
+     * Description:	Forward Number Theoretic Transform for Heuristic qTESLA Security Category-1,
+     * 				Security Category-3 (Option for Size and Speed)
+     *
+     * @param        destination        Destination of Transformation
+     * @param        source            Source of Transformation
+     * @param        n                Polynomial Degree
+     * @param        q                Modulus
+     * @param        qInverse
+     *
+     * @return none
+     ************************************************************************************************************/
+    private static void numberTheoreticTransform(int destination[], int source[], int n, int q, long qInverse)
+    {
+
+        int jTwiddle = 0;
+        int numberOfProblem = n >> 1;
+
+        for (; numberOfProblem > 0; numberOfProblem >>= 1)
+        {
+
+            int j = 0;
+            int jFirst;
+
+            for (jFirst = 0; jFirst < n; jFirst = j + numberOfProblem)
+            {
+
+                long omega = source[jTwiddle++];
+
+                for (j = jFirst; j < jFirst + numberOfProblem; j++)
+                {
+
+                    int temporary = montgomery(omega * destination[j + numberOfProblem], q, qInverse);
+
+                    destination[j + numberOfProblem] = destination[j] - temporary;
+                    destination[j] = destination[j] + temporary;
+
+                }
+
+            }
+
+        }
+
+    }
+
+    /**************************************************************************************************************
+     * Description:	Forward Number Theoretic Transform for Provably-Secure qTESLA Security Category-1
+     *
+     * @param        destination        Destination of Transformation
+     * @param        source            Source of Transformation
+     *
+     * @return none
+     **************************************************************************************************************/
+    private static void numberTheoreticTransformIP(long destination[], long source[])
+    {
+
+        int numberOfProblem = Parameter.N_I_P >> 1;
+        int jTwiddle = 0;
+
+        for (; numberOfProblem > 0; numberOfProblem >>= 1)
+        {
+
+            int j = 0;
+            int jFirst;
+
+            for (jFirst = 0; jFirst < Parameter.N_I_P; jFirst = j + numberOfProblem)
+            {
+
+                long omega = source[jTwiddle++];
+
+                for (j = jFirst; j < jFirst + numberOfProblem; j++)
+                {
+
+                    long temporary = montgomeryP(
+                        omega * destination[j + numberOfProblem],
+                        Parameter.Q_I_P, Parameter.Q_INVERSE_I_P
+                    );
+
+                    destination[j + numberOfProblem] = destination[j] + (Parameter.Q_I_P - temporary);
+
+                    destination[j] = destination[j] + temporary;
+
+                }
+
+            }
+
+        }
+
+    }
+
+    /**************************************************************************************************************
+     * Description:	Forward Number Theoretic Transform for Provably-Secure qTESLA Security Category-3
+     *
+     * @param        destination        Destination of Transformation
+     * @param        source            Source of Transformation
+     *
+     * @return none
+     **************************************************************************************************************/
+    private static void numberTheoreticTransformIIIP(long destination[], long source[])
+    {
+
+        int jTwiddle = 0;
+        int numberOfProblem = Parameter.N_III_P >> 1;
+
+        for (; numberOfProblem > 0; numberOfProblem >>= 1)
+        {
+
+            int j = 0;
+            int jFirst;
+
+            for (jFirst = 0; jFirst < Parameter.N_III_P; jFirst = j + numberOfProblem)
+            {
+
+                int omega = (int)source[jTwiddle++];
+
+                for (j = jFirst; j < jFirst + numberOfProblem; j++)
+                {
+
+                    long temporary = barrett(
+                        montgomeryP(
+                            omega * destination[j + numberOfProblem],
+                            Parameter.Q_III_P,
+                            Parameter.Q_INVERSE_III_P
+                        ),
+                        Parameter.Q_III_P,
+                        Parameter.BARRETT_MULTIPLICATION_III_P,
+                        Parameter.BARRETT_DIVISION_III_P
+                    );
+
+                    destination[j + numberOfProblem] = barrett(
+                        destination[j] + (2L * Parameter.Q_III_P - temporary),
+                        Parameter.Q_III_P,
+                        Parameter.BARRETT_MULTIPLICATION_III_P,
+                        Parameter.BARRETT_DIVISION_III_P
+                    );
+
+                    destination[j] = barrett(
+                        destination[j] + temporary,
+                        Parameter.Q_III_P,
+                        Parameter.BARRETT_MULTIPLICATION_III_P,
+                        Parameter.BARRETT_DIVISION_III_P
+                    );
+
+                }
+
+            }
+
+        }
+
+    }
+
+    /******************************************************************************************************************
+     * Description:	Inverse Number Theoretic Transform for Heuristic qTESLA Security Category-1
+     *
+     * @param        destination            Destination of Inverse Transformation
+     * @param        source                Source of Inverse Transformation
+     *
+     * @return none
+     ******************************************************************************************************************/
+    private static void inverseNumberTheoreticTransformI(int destination[], int source[])
+    {
+
+        int jTwiddle = 0;
+
+        for (int numberOfProblem = 1; numberOfProblem < Parameter.N_I; numberOfProblem *= 2)
+        {
+
+            int j = 0;
+            int jFirst;
+
+            for (jFirst = 0; jFirst < Parameter.N_I; jFirst = j + numberOfProblem)
+            {
+
+                long omega = source[jTwiddle++];
+
+                for (j = jFirst; j < jFirst + numberOfProblem; j++)
+                {
+
+                    int temporary = destination[j];
+
+                    destination[j] = temporary + destination[j + numberOfProblem];
+
+                    destination[j + numberOfProblem] = montgomery(
+                        omega * (temporary - destination[j + numberOfProblem]),
+                        Parameter.Q_I, Parameter.Q_INVERSE_I
+                    );
+
+                }
+
+            }
+
+        }
+
+        for (int i = 0; i < Parameter.N_I / 2; i++)
+        {
+
+            destination[i] = montgomery((long)Parameter.R_I * destination[i], Parameter.Q_I, Parameter.Q_INVERSE_I);
+
+        }
+
+    }
+
+    /**************************************************************************************************************************************************************************
+     * Description:	Inverse Number Theoretic Transform for Heuristic qTESLA Security Category-3 (Option for Size and Speed)
+     *
+     * @param        destination                    Destination of Inverse Transformation
+     * @param        source                        Source of Inverse Transformation
+     * @param        n                            Polynomial Degree
+     * @param        q                            Modulus
+     * @param        qInverse
+     * @param        r
+     * @param        barrettMultiplication
+     * @param        barrettDivision
+     *
+     * @return none
+     **************************************************************************************************************************************************************************/
+    private static void inverseNumberTheoreticTransform(int destination[], int source[], int n, int q, long qInverse, int r, int barrettMultiplication, int barrettDivision)
+    {
+
+        int jTwiddle = 0;
+
+        for (int numberOfProblem = 1; numberOfProblem < n; numberOfProblem *= 2)
+        {
+
+            int j = 0;
+
+            for (int jFirst = 0; jFirst < n; jFirst = j + numberOfProblem)
+            {
+
+                long omega = source[jTwiddle++];
+
+                for (j = jFirst; j < jFirst + numberOfProblem; j++)
+                {
+
+                    int temporary = destination[j];
+
+                    if (numberOfProblem == 16)
+                    {
+
+                        destination[j] = barrett(temporary + destination[j + numberOfProblem], q, barrettMultiplication, barrettDivision);
+
+                    }
+                    else
+                    {
+
+                        destination[j] = temporary + destination[j + numberOfProblem];
+
+                    }
+
+                    destination[j + numberOfProblem] = montgomery(omega * (temporary - destination[j + numberOfProblem]), q, qInverse);
+
+                }
+
+            }
+
+        }
+
+        for (int i = 0; i < n / 2; i++)
+        {
+
+            destination[i] = montgomery((long)r * destination[i], q, qInverse);
+
+        }
+
+    }
+
+    /***********************************************************************************************************************************************************************************
+     * Description:	Inverse Number Theoretic Transform for Provably-Secure qTESLA Security Category-1
+     *
+     * @param        destination            Destination of Inverse Transformation
+     * @param        destinationOffset    Starting Point of the Destination
+     * @param        source                Source of Inverse Transformation
+     * @param        sourceOffset        Starting Point of the Source
+     *
+     * @return none
+     ***********************************************************************************************************************************************************************************/
+    private static void inverseNumberTheoreticTransformIP(long destination[], int destinationOffset, long source[], int sourceOffset)
+    {
+
+        int jTwiddle = 0;
+
+        for (int numberOfProblem = 1; numberOfProblem < Parameter.N_I_P; numberOfProblem *= 2)
+        {
+
+            int j = 0;
+            int jFirst;
+
+            for (jFirst = 0; jFirst < Parameter.N_I_P; jFirst = j + numberOfProblem)
+            {
+
+                long omega = source[sourceOffset + (jTwiddle++)];
+
+                for (j = jFirst; j < jFirst + numberOfProblem; j++)
+                {
+
+                    long temporary = destination[destinationOffset + j];
+
+                    destination[destinationOffset + j] = temporary + destination[destinationOffset + j + numberOfProblem];
+
+                    destination[destinationOffset + j + numberOfProblem] = montgomeryP(
+                        omega * (temporary + (2L * Parameter.Q_I_P - destination[destinationOffset + j + numberOfProblem])),
+                        Parameter.Q_I_P, Parameter.Q_INVERSE_I_P
+                    );
+
+                }
+
+            }
+
+            numberOfProblem *= 2;
+
+            for (jFirst = 0; jFirst < Parameter.N_I_P; jFirst = j + numberOfProblem)
+            {
+
+                long omega = source[sourceOffset + (jTwiddle++)];
+
+                for (j = jFirst; j < jFirst + numberOfProblem; j++)
+                {
+
+                    long temporary = destination[destinationOffset + j];
+
+                    destination[destinationOffset + j] = barrett(
+                        temporary + destination[destinationOffset + j + numberOfProblem],
+                        Parameter.Q_I_P, Parameter.BARRETT_MULTIPLICATION_I_P, Parameter.BARRETT_DIVISION_I_P
+                    );
+
+                    destination[destinationOffset + j + numberOfProblem] = montgomeryP(
+                        omega * (temporary + (2L * Parameter.Q_I_P - destination[destinationOffset + j + numberOfProblem])),
+                        Parameter.Q_I_P, Parameter.Q_INVERSE_I_P
+                    );
+
+                }
+
+            }
+
+        }
+
+    }
+
+    /******************************************************************************************************************************************************************************************
+     * Description:	Inverse Number Theoretic Transform for Provably-Secure qTESLA Security Category-3
+     *
+     * @param        destination            Destination of Inverse Transformation
+     * @param        destinationOffset    Starting Point of the Destination
+     * @param        source                Source of Inverse Transformation
+     * @param        sourceOffset        Starting Point of the Source
+     *
+     * @return none
+     ******************************************************************************************************************************************************************************************/
+    private static void inverseNumberTheoreticTransformIIIP(long destination[], int destinationOffset, long source[], int sourceOffset)
+    {
+
+        int jTwiddle = 0;
+
+        for (int numberOfProblem = 1; numberOfProblem < Parameter.N_III_P; numberOfProblem *= 2)
+        {
+
+            int j = 0;
+            int jFirst;
+
+            for (jFirst = 0; jFirst < Parameter.N_III_P; jFirst = j + numberOfProblem)
+            {
+
+                long omega = source[sourceOffset + (jTwiddle++)];
+
+                for (j = jFirst; j < jFirst + numberOfProblem; j++)
+                {
+
+                    long temporary = destination[destinationOffset + j];
+
+                    destination[destinationOffset + j] = barrett(
+                        temporary + destination[destinationOffset + j + numberOfProblem],
+                        Parameter.Q_III_P, Parameter.BARRETT_MULTIPLICATION_III_P, Parameter.BARRETT_DIVISION_III_P
+                    );
+
+                    destination[destinationOffset + j + numberOfProblem] = barrett(
+                        montgomeryP(
+                            omega * (temporary + (2L * Parameter.Q_III_P - destination[destinationOffset + j + numberOfProblem])),
+                            Parameter.Q_III_P, Parameter.Q_INVERSE_III_P
+                        ),
+                        Parameter.Q_III_P, Parameter.BARRETT_MULTIPLICATION_III_P, Parameter.BARRETT_DIVISION_III_P
+                    );
+
+                }
+
+            }
+
+        }
+
+    }
+
+    /****************************************************************************************************************************************************
+     * Description:	Component Wise Polynomial Multiplication for Heuristic qTESLA Security Category-1 and Security Category-3 (Option for Size and Speed)
+     *
+     * @param        product                    Product = Multiplicand (*) Multiplier
+     * @param        multiplicand            Multiplicand Array
+     * @param        multiplier                Multiplier Array
+     * @param        n                        Polynomial Degree
+     * @param        q                        Modulus
+     * @param        qInverse
+     *
+     * @return none
+     ****************************************************************************************************************************************************/
+    private static void componentWisePolynomialMultiplication(int[] product, int[] multiplicand, int[] multiplier, int n, int q, long qInverse)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            product[i] = montgomery((long)multiplicand[i] * multiplier[i], q, qInverse);
+
+        }
+
+    }
+
+    /******************************************************************************************************************************************************************************************************************
+     * Description:	Component Wise Polynomial Multiplication for Provably-Secure qTESLA Security Category-1 and Security Category-3
+     *
+     * @param        product                    Product = Multiplicand (*) Multiplier
+     * @param        productOffset            Starting Point of the Product Array
+     * @param        multiplicand            Multiplicand Array
+     * @param        multiplicandOffset        Starting Point of the Multiplicand Array
+     * @param        multiplier                Multiplier Array
+     * @param        multiplierOffset        Starting Point of the Multiplier Array
+     * @param        n                        Polynomial Degree
+     * @param        q                        Modulus
+     * @param        qInverse
+     *
+     * @return none
+     ******************************************************************************************************************************************************************************************************************/
+    private static void componentWisePolynomialMultiplication(long[] product, int productOffset, long[] multiplicand, int multiplicandOffset, long[] multiplier, int multiplierOffset, int n, int q, long qInverse)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            product[productOffset + i] = montgomeryP(multiplicand[multiplicandOffset + i] * multiplier[multiplierOffset + i], q, qInverse);
+
+        }
+
+    }
+
+    /***********************************************************************************************************************************************
+     * Description:	Polynomial Number Theoretic Transform for Provably-Secure qTESLA Security Category-1 and Category-3
+     *
+     * @param        arrayNumberTheoreticTransform        Transformed Array
+     * @param        array                                Array to be Transformed
+     * @param        n                                    Polynomial Degree
+     *
+     * @return none
+     ***********************************************************************************************************************************************/
+    public static void polynomialNumberTheoreticTransform(long[] arrayNumberTheoreticTransform, long[] array, int n)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            arrayNumberTheoreticTransform[i] = array[i];
+
+        }
+
+        if (n == Parameter.N_I_P)
+        {
+
+            numberTheoreticTransformIP(arrayNumberTheoreticTransform, PolynomialProvablySecure.ZETA_I_P);
+
+        }
+
+        if (n == Parameter.N_III_P)
+        {
+
+            numberTheoreticTransformIIIP(arrayNumberTheoreticTransform, PolynomialProvablySecure.ZETA_III_P);
+
+        }
+
+    }
+
+    /*******************************************************************************************************************************************
+     * Description:	Polynomial Multiplication for Heuristic qTESLA Security Category-1 and Category-3 (Option for Size and Speed)
+     *
+     * @param        product                    Product = Multiplicand * Multiplier
+     * @param        multiplicand            Multiplicand Array
+     * @param        multiplier                Multiplier Array
+     * @param        n                        Polynomial Degree
+     * @param        q                        Modulus
+     * @param        qInverse
+     * @param        zeta
+     *
+     * @return none
+     *******************************************************************************************************************************************/
+    public static void polynomialMultiplication(int[] product, int[] multiplicand, int[] multiplier, int n, int q, long qInverse, int[] zeta)
+    {
+
+        int[] multiplierNumberTheoreticTransform = new int[n];
+
+        for (int i = 0; i < n; i++)
+        {
+
+            multiplierNumberTheoreticTransform[i] = multiplier[i];
+
+        }
+
+        numberTheoreticTransform(multiplierNumberTheoreticTransform, zeta, n, q, qInverse);
+
+        componentWisePolynomialMultiplication(product, multiplicand, multiplierNumberTheoreticTransform, n, q, qInverse);
+
+        if (q == Parameter.Q_I)
+        {
+
+            inverseNumberTheoreticTransformI(product, PolynomialHeuristic.ZETA_INVERSE_I);
+
+        }
+
+        if (q == Parameter.Q_III_SIZE)
+        {
+
+            inverseNumberTheoreticTransform(
+
+                product, PolynomialHeuristic.ZETA_INVERSE_III_SIZE,
+                Parameter.N_III_SIZE, Parameter.Q_III_SIZE, Parameter.Q_INVERSE_III_SIZE, Parameter.R_III_SIZE,
+                Parameter.BARRETT_MULTIPLICATION_III_SIZE, Parameter.BARRETT_DIVISION_III_SIZE
+
+            );
+
+        }
+
+        if (q == Parameter.Q_III_SPEED)
+        {
+
+            inverseNumberTheoreticTransform(
+
+                product, PolynomialHeuristic.ZETA_INVERSE_III_SPEED,
+                Parameter.N_III_SPEED, Parameter.Q_III_SPEED, Parameter.Q_INVERSE_III_SPEED, Parameter.R_III_SPEED,
+                Parameter.BARRETT_MULTIPLICATION_III_SPEED, Parameter.BARRETT_DIVISION_III_SPEED
+
+            );
+
+        }
+
+    }
+
+    /***************************************************************************************************************************************************************************************************
+     * Description:	Polynomial Multiplication for Provably-Secure qTESLA Security Category-1 and Category-3
+     *
+     * @param        product                    Product = Multiplicand * Multiplier
+     * @param        productOffset            Starting Point of the Product Array
+     * @param        multiplicand            Multiplicand Array
+     * @param        multiplicandOffset        Starting Point of the Multiplicand Array
+     * @param        multiplier                Multiplier Array
+     * @param        multiplierOffset        Starting Point of the Multiplier Array
+     * @param        n                        Polynomial Degree
+     * @param        q                        Modulus
+     * @param        qInverse
+     *
+     * @return none
+     ***************************************************************************************************************************************************************************************************/
+    public static void polynomialMultiplication(long[] product, int productOffset, long[] multiplicand, int multiplicandOffset, long[] multiplier, int multiplierOffset, int n, int q, long qInverse)
+    {
+
+        componentWisePolynomialMultiplication(product, productOffset, multiplicand, multiplicandOffset, multiplier, multiplierOffset, n, q, qInverse);
+
+        if (q == Parameter.Q_I_P)
+        {
+
+            inverseNumberTheoreticTransformIP(product, productOffset, PolynomialProvablySecure.ZETA_INVERSE_I_P, 0);
+
+        }
+
+        if (q == Parameter.Q_III_P)
+        {
+
+            inverseNumberTheoreticTransformIIIP(product, productOffset, PolynomialProvablySecure.ZETA_INVERSE_III_P, 0);
+
+        }
+
+    }
+
+    /****************************************************************************************************************************************************
+     * Description:	Polynomial Addition for Heuristic qTESLA Security Category-1 and Category-3 (Option for Size or Speed)
+     * 				Q + L_E < 2 ^ (CEIL (LOGARITHM (Q, 2)))
+     * 				No Necessary Reduction for Y + SC
+     *
+     * @param        summation            Summation = Augend + Addend
+     * @param        augend                Augend Array
+     * @param        addend                Addend Array
+     * @param        n                    Polynomial Degree
+     *
+     * @return none
+     ****************************************************************************************************************************************************/
+    public static void polynomialAddition(int[] summation, int[] augend, int[] addend, int n)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            summation[i] = augend[i] + addend[i];
+
+        }
+
+    }
+
+    /********************************************************************************************************************************************************
+     * Description:	Polynomial Addition for Provably-Secure qTESLA Security Category-1 and Category-3
+     * 				Q + L_E < 2 ^ (CEIL (LOGARITHM (Q, 2)))
+     * 				No Necessary Reduction for Y + SC
+     *
+     * @param        summation            Summation = Augend + Addend
+     * @param        summationOffset        Starting Point of the Summation Array
+     * @param        augend                Augend Array
+     * @param        augendOffset        Starting Point of the Augend Array
+     * @param        addend                Addend Array
+     * @param        addendOffset        Starting Point of the Addend Array
+     * @param        n                    Polynomial Degree
+     *
+     * @return none
+     ********************************************************************************************************************************************************/
+    public static void polynomialAddition(long[] summation, int summationOffset, long[] augend, int augendOffset, long[] addend, int addendOffset, int n)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            summation[summationOffset + i] = augend[augendOffset + i] + addend[addendOffset + i];
+
+        }
+
+    }
+
+    /*************************************************************************************************************
+     * Description:	Polynomial Addition with Correction for Heuristic qTESLA Security Category-1 and Category-3
+     * 				(Option for Size or Speed)
+     * 				Q + L_E < 2 ^ (CEIL (LOGARITHM (Q, 2)))
+     * 				No Necessary Reduction for Y + SC
+     *
+     * @param        summation            Summation = Augend + Addend
+     * @param        augend                Augend Array
+     * @param        addend                Addend Array
+     * @param        n                    Polynomial Degree
+     *
+     * @return none
+     ************************************************************************************************************/
+    public static void polynomialAdditionCorrection(int[] summation, int[] augend, int[] addend, int n, int q)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            summation[i] = augend[i] + addend[i];
+            /* If summation[i] < 0 Then Add Q */
+            summation[i] += (summation[i] >> 31) & q;
+            summation[i] -= q;
+            /* If summation[i] >= Q Then Subtract Q */
+            summation[i] += (summation[i] >> 31) & q;
+
+        }
+
+    }
+
+    /**********************************************************************************************************************
+     * Description:	Polynomial Subtraction with Correction for Heuristic qTESLA Security Category-1 and Security Category-3
+     *				(Option for Size or Speed)
+     *
+     * @param        difference                    Difference = Minuend (-) Subtrahend
+     * @param        minuend                        Minuend Array
+     * @param        subtrahend                    Subtrahend Array
+     * @param        n                            Polynomial Degree
+     * @param        q                            Modulus
+     *
+     * @return none
+     ***********************************************************************************************************************/
+    public static void polynomialSubtractionCorrection(int[] difference, int[] minuend, int[] subtrahend, int n, int q)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            difference[i] = minuend[i] - subtrahend[i];
+            /* If difference[i] < 0 Then Add Q */
+            difference[i] += (difference[i] >> 31) & q;
+
+        }
+
+    }
+
+    /*******************************************************************************************************************************************
+     * Description:	Polynomial Subtraction with Montgomery Reduction for Heuristic qTESLA Security Category-1 and Security Category-3
+     *				(Option for Size or Speed)
+     *
+     * @param        difference                    Difference = Minuend (-) Subtrahend
+     * @param        minuend                        Minuend Array
+     * @param        subtrahend                    Subtrahend Array
+     * @param        n                            Polynomial Degree
+     * @param        q                            Modulus
+     * @param        qInverse
+     * @param        r
+     *
+     * @return none
+     *******************************************************************************************************************************************/
+    public static void polynomialSubtractionMontgomery(int[] difference, int[] minuend, int[] subtrahend, int n, int q, long qInverse, int r)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            difference[i] = montgomery((long)r * (minuend[i] - subtrahend[i]), q, qInverse);
+
+        }
+
+    }
+
+    /******************************************************************************************************************************************************************************************************************************
+     * Description:	Polynomial Subtraction for Provably-Secure qTESLA Security Category-1 and Security Category-3
+     *
+     * @param        difference                    Difference = Minuend (-) Subtrahend
+     * @param        differenceOffset            Starting Point of the Difference Array
+     * @param        minuend                        Minuend Array
+     * @param        minuendOffset                Starting Point of the Minuend Array
+     * @param        subtrahend                    Subtrahend Array
+     * @param        subtrahendOffset            Starting Point of the Subtrahend Array
+     * @param        n                            Polynomial Degree
+     * @param        q                            Modulus
+     * @param        barrettMultiplication
+     * @param        barrettDivision
+     *
+     * @return none
+     ******************************************************************************************************************************************************************************************************************************/
+    public static void polynomialSubtraction(long[] difference, int differenceOffset, long[] minuend, int minuendOffset, long[] subtrahend, int subtrahendOffset, int n, int q, int barrettMultiplication, int barrettDivision)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            difference[differenceOffset + i] = barrett(minuend[minuendOffset + i] - subtrahend[subtrahendOffset + i], q, barrettMultiplication, barrettDivision);
+
+        }
+
+    }
+
+    /******************************************************************************************************************************************************************************
+     * Description:	Generation of Polynomial A for Heuristic qTESLA Security Category-1 and Security Category-3 (Option for Size or Speed)
+     *
+     * @param        A                                    Polynomial to be Generated
+     * @param        seed                                Kappa-Bit Seed
+     * @param        seedOffset                            Starting Point of the Kappa-Bit Seed
+     * @param        n                                    Polynomial Degree
+     * @param        q                                    Modulus
+     * @param        qInverse
+     * @param        qLogarithm                            q <= 2 ^ qLogarithm
+     * @param        generatorA
+     * @param        inverseNumberTheoreticTransform
+     *
+     * @return none
+     ******************************************************************************************************************************************************************************/
+    public static void polynomialUniform(int[] A, byte[] seed, int seedOffset, int n, int q, long qInverse, int qLogarithm, int generatorA, int inverseNumberTheoreticTransform)
+    {
+
+        int position = 0;
+        int i = 0;
+        int numberOfByte = (qLogarithm + 7) / 8;
+        int numberOfBlock = generatorA;
+        short dualModeSampler = 0;
+        int value1;
+        int value2;
+        int value3;
+        int value4;
+        int mask = (1 << qLogarithm) - 1;
+
+        byte[] buffer = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * generatorA];
+
+        HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+            buffer, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * generatorA,
+            dualModeSampler++,
+            seed, seedOffset, RANDOM
+        );
+
+        while (i < n)
+        {
+
+            if (position > (HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * numberOfBlock - Const.INT_SIZE / Const.BYTE_SIZE * numberOfByte))
+            {
+
+                numberOfBlock = 1;
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                    buffer, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * numberOfBlock,
+                    dualModeSampler++,
+                    seed, seedOffset, RANDOM
+                );
+
+                position = 0;
+
+            }
+
+            value1 = CommonFunction.load32(buffer, position) & mask;
+            position += numberOfByte;
+
+            value2 = CommonFunction.load32(buffer, position) & mask;
+            position += numberOfByte;
+
+            value3 = CommonFunction.load32(buffer, position) & mask;
+            position += numberOfByte;
+
+            value4 = CommonFunction.load32(buffer, position) & mask;
+            position += numberOfByte;
+
+            if (value1 < q && i < n)
+            {
+
+                A[i++] = montgomery((long)value1 * inverseNumberTheoreticTransform, q, qInverse);
+
+            }
+
+            if (value2 < q && i < n)
+            {
+
+                A[i++] = montgomery((long)value2 * inverseNumberTheoreticTransform, q, qInverse);
+
+            }
+
+            if (value3 < q && i < n)
+            {
+
+                A[i++] = montgomery((long)value3 * inverseNumberTheoreticTransform, q, qInverse);
+
+            }
+
+            if (value4 < q && i < n)
+            {
+
+                A[i++] = montgomery((long)value4 * inverseNumberTheoreticTransform, q, qInverse);
+
+            }
+
+        }
+
+    }
+
+    /**************************************************************************************************************************************************************************************
+     * Description:	Generation of Polynomial A for Provably-Secure qTESLA Security Category-1 and Security Category-3
+     *
+     * @param        A                                    Polynomial to be Generated
+     * @param        seed                                Kappa-Bit Seed
+     * @param        seedOffset                            Starting Point of the Kappa-Bit Seed
+     * @param        n                                    Polynomial Degree
+     * @param        k                                    Number of Ring-Learning-With-Errors Samples
+     * @param        q                                    Modulus
+     * @param        qInverse
+     * @param        qLogarithm                            q <= 2 ^ qLogarithm
+     * @param        generatorA
+     * @param        inverseNumberTheoreticTransform
+     *
+     * @return none
+     **************************************************************************************************************************************************************************************/
+    public static void polynomialUniform(long[] A, byte[] seed, int seedOffset, int n, int k, int q, long qInverse, int qLogarithm, int generatorA, int inverseNumberTheoreticTransform)
+    {
+
+        int position = 0;
+        int i = 0;
+        int numberOfByte = (qLogarithm + 7) / 8;
+        int numberOfBlock = generatorA;
+        short dualModeSampler = 0;
+        int value1;
+        int value2;
+        int value3;
+        int value4;
+        int mask = (1 << qLogarithm) - 1;
+
+        byte[] buffer = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * numberOfBlock];
+
+        HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+            buffer, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * numberOfBlock,
+            dualModeSampler++,
+            seed, seedOffset, RANDOM
+        );
+
+        while (i < n * k)
+        {
+
+            if (position > (HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * numberOfBlock - Const.INT_SIZE / Const.BYTE_SIZE * numberOfByte))
+            {
+
+                numberOfBlock = 1;
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                    buffer, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE * numberOfBlock,
+                    dualModeSampler++,
+                    seed, seedOffset, RANDOM
+                );
+
+                position = 0;
+
+            }
+
+            value1 = CommonFunction.load32(buffer, position) & mask;
+            position += numberOfByte;
+
+            value2 = CommonFunction.load32(buffer, position) & mask;
+            position += numberOfByte;
+
+            value3 = CommonFunction.load32(buffer, position) & mask;
+            position += numberOfByte;
+
+            value4 = CommonFunction.load32(buffer, position) & mask;
+            position += numberOfByte;
+
+            if (value1 < q && i < n * k)
+            {
+
+                A[i++] = montgomeryP((long)value1 * inverseNumberTheoreticTransform, q, qInverse);
+
+            }
+
+            if (value2 < q && i < n * k)
+            {
+
+                A[i++] = montgomeryP((long)value2 * inverseNumberTheoreticTransform, q, qInverse);
+
+            }
+
+            if (value3 < q && i < n * k)
+            {
+
+                A[i++] = montgomeryP((long)value3 * inverseNumberTheoreticTransform, q, qInverse);
+
+            }
+
+            if (value4 < q && i < n * k)
+            {
+
+                A[i++] = montgomeryP((long)value4 * inverseNumberTheoreticTransform, q, qInverse);
+
+            }
+
+        }
+
+    }
+
+    /**************************************************************************************************************************************************************
+     * Description:	Performs Sparse Polynomial Multiplication for A Value Needed During Message Signification for Heuristic qTESLA Security Category-1 and
+     *				SecurityCategory-3 (Option for Size or Speed)
+     *
+     * @param        product                Product of Two Polynomials
+     * @param        privateKey            Part of the Private Key
+     * @param        positionList        List of Indices of Non-Zero Elements in C
+     * @param        signList            List of Signs of Non-Zero Elements in C
+     * @param        n                    Polynomial Degree
+     * @param        h                    Number of Non-Zero Entries of Output Elements of Encryption
+     *
+     * @return none
+     **************************************************************************************************************************************************************/
+    public static void sparsePolynomialMultiplication16(int[] product, final short[] privateKey, final int[] positionList, final short[] signList, int n, int h)
+    {
+
+        int position;
+
+        Arrays.fill(product, 0);
+
+        for (int i = 0; i < h; i++)
+        {
+
+            position = positionList[i];
+
+            for (int j = 0; j < position; j++)
+            {
+
+                product[j] -= signList[i] * privateKey[n + j - position];
+
+            }
+
+            for (int j = position; j < n; j++)
+            {
+
+                product[j] += signList[i] * privateKey[j - position];
+
+            }
+
+        }
+
+    }
+
+    /*****************************************************************************************************************************************************************************************************
+     * Description:	Performs Sparse Polynomial Multiplication for A Value Needed During Message Signification for Provably-Secure qTESLA Security Category-1 and Category-3
+     *
+     * @param        product                Product of Two Polynomials
+     * @param        productOffset        Starting Point of the Product of Two Polynomials
+     * @param        privateKey            Part of the Private Key
+     * @param        privateKeyOffset    Starting Point of the Private Key
+     * @param        positionList        List of Indices of Non-Zero Elements in C
+     * @param        signList            List of Signs of Non-Zero Elements in C
+     * @param        n                    Polynomial Degree
+     * @param        h                    Number of Non-Zero Entries of Output Elements of Encryption
+     *
+     * @return none
+     ******************************************************************************************************************************************************************************************************/
+    public static void sparsePolynomialMultiplication8(long[] product, int productOffset, final byte[] privateKey, int privateKeyOffset, final int[] positionList, final short[] signList, int n, int h)
+    {
+
+        int position;
+
+        Arrays.fill(product, 0L);
+
+        for (int i = 0; i < h; i++)
+        {
+
+            position = positionList[i];
+
+            for (int j = 0; j < position; j++)
+            {
+
+                product[productOffset + j] -= signList[i] * privateKey[privateKeyOffset + n + j - position];
+
+            }
+
+            for (int j = position; j < n; j++)
+            {
+
+                product[productOffset + j] += signList[i] * privateKey[privateKeyOffset + j - position];
+
+            }
+
+        }
+
+    }
+
+    /***********************************************************************************************************************************************************
+     * Description:	Performs Sparse Polynomial Multiplication for A Value Needed During Message Signification for Heuristic qTESLA Security Category-1 and
+     * 				Security Category-3 (Option for Size or Speed)
+     *
+     * @param        product                    Product of Two Polynomials
+     * @param        publicKey                Part of the Public Key
+     * @param        positionList            List of Indices of Non-Zero Elements in C
+     * @param        signList                List of Signs of Non-Zero Elements in C
+     * @param        n                        Polynomial Degree
+     * @param        h                        Number of Non-Zero Entries of Output Elements of Encryption
+     *
+     * @return none
+     ***********************************************************************************************************************************************************/
+    public static void sparsePolynomialMultiplication32(int[] product, final int[] publicKey, final int[] positionList, final short[] signList, int n, int h)
+    {
+
+        int position;
+
+        Arrays.fill(product, 0);
+
+        for (int i = 0; i < h; i++)
+        {
+
+            position = positionList[i];
+
+            for (int j = 0; j < position; j++)
+            {
+
+                product[j] -= signList[i] * publicKey[n + j - position];
+
+            }
+
+            for (int j = position; j < n; j++)
+            {
+
+                product[j] += signList[i] * publicKey[j - position];
+
+            }
+
+        }
+
+    }
+
+    /***********************************************************************************************************************************************************************************************************************************************************
+     * Description:	Performs Sparse Polynomial Multiplication for A Value Needed During Message Signification for Provably-Secure qTESLA Security Category-1 and Security Category-3
+     *
+     * @param        product                    Product of Two Polynomials
+     * @param        productOffset            Starting Point of the Product of Two Polynomials
+     * @param        publicKey                Part of the Public Key
+     * @param        publicKeyOffset            Starting Point of the Public Key
+     * @param        positionList            List of Indices of Non-Zero Elements in C
+     * @param        signList                List of Signs of Non-Zero Elements in C
+     * @param        n                        Polynomial Degree
+     * @param        h                        Number of Non-Zero Entries of Output Elements of Encryption
+     * @param        q                        Modulus
+     * @param        barrettMultiplication
+     * @param        barrettDivision
+     *
+     * @return none
+     ***********************************************************************************************************************************************************************************************************************************************************/
+    public static void sparsePolynomialMultiplication32(long[] product, int productOffset, final int[] publicKey, int publicKeyOffset, final int[] positionList, final short[] signList, int n, int h, int q, int barrettMultiplication, int barrettDivision)
+    {
+
+        int position;
+
+        Arrays.fill(product, 0L);
+
+        for (int i = 0; i < h; i++)
+        {
+
+            position = positionList[i];
+
+            for (int j = 0; j < position; j++)
+            {
+
+                product[productOffset + j] -= signList[i] * publicKey[publicKeyOffset + n + j - position];
+
+            }
+
+            for (int j = position; j < n; j++)
+            {
+
+                product[productOffset + j] += signList[i] * publicKey[publicKeyOffset + j - position];
+
+            }
+
+        }
+
+        for (int i = 0; i < n; i++)
+        {
+
+            product[productOffset + i] = barrett(product[productOffset + i], q, barrettMultiplication, barrettDivision);
+
+        }
+
+    }
+
+}
\ No newline at end of file
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/PolynomialHeuristic.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/PolynomialHeuristic.java
new file mode 100644
index 000000000..a1b67d443
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/PolynomialHeuristic.java
@@ -0,0 +1,682 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+final class PolynomialHeuristic
+{
+
+    /* Heuristic qTESLA Security Category-1 */
+
+    public static final int[] ZETA_I = {                    /* 512-Entry */
+
+        3359531, 2189080, 370173, 677362, 3132616, 2989204, 2362181, 1720831,
+        1203721, 3239574, 641414, 3932234, 3634017, 2251707, 355329, 4152265,
+        1356023, 4021436, 1465601, 4145892, 3348341, 675693, 1598775, 2799365,
+        3336234, 3856839, 603157, 1381183, 1069471, 2142038, 2877387, 2653969,
+        2055310, 3837123, 3141231, 1951522, 2375048, 445122, 1689285, 3664328,
+        676319, 3844199, 3669724, 1009639, 3666694, 1585701, 2102892, 966523,
+        4069555, 3246046, 846643, 2088895, 4068915, 3715722, 4119007, 230501,
+        1626667, 2119752, 1171284, 3153846, 17941, 1316589, 1814059, 3185686,
+        1183551, 2533671, 4152595, 2616162, 3015757, 194860, 1601807, 1271569,
+        139534, 2581874, 2183200, 2060697, 1036874, 646550, 2823563, 3312274,
+        391700, 99391, 638903, 2397164, 3924868, 3315551, 1170767, 422539,
+        1801679, 166402, 742283, 222557, 522210, 3415900, 177835, 3243355,
+        4196855, 1821376, 1290490, 3624896, 1546898, 1282351, 3960516, 835944,
+        2251927, 90910, 3034838, 4082965, 2311377, 3512216, 2652413, 2191140,
+        302935, 3866228, 2007511, 744185, 2801160, 3993630, 592962, 795067,
+        2822609, 3471782, 3710854, 1824985, 1495256, 3906591, 3111335, 3902620,
+        11234, 1586236, 3698245, 492808, 2729660, 3369937, 1869963, 7244,
+        1453951, 1757304, 1005437, 3668653, 1821321, 4203686, 1192473, 113408,
+        2904803, 1346735, 4161890, 711442, 4020959, 1164150, 2139014, 4134238,
+        731747, 3856202, 2351090, 3382729, 2644693, 617098, 2796766, 1911274,
+        552932, 2476095, 1801797, 1381577, 2338697, 1336590, 2798544, 459121,
+        3555631, 741068, 2302686, 1883916, 2148181, 2471691, 2174195, 1684042,
+        3266036, 227434, 4107207, 2910899, 3427718, 2011049, 2706372, 4182237,
+        1243355, 2908998, 15068, 1966206, 2157082, 4114100, 1846352, 230880,
+        1161075, 1259576, 1212857, 1697580, 39500, 3079648, 2529577, 2082167,
+        50282, 476606, 1494601, 1334236, 3349015, 1600445, 413060, 3104844,
+        139283, 1688398, 3230017, 1009712, 614253, 2973529, 2077610, 2218429,
+        4185344, 254428, 506799, 196179, 3310395, 4183346, 3897905, 2234639,
+        1859699, 3322900, 2151737, 1904476, 2457045, 383438, 2543045, 2985636,
+        731083, 1609871, 2171434, 535413, 2666041, 405934, 3303186, 802974,
+        3573046, 1760267, 2758359, 2102800, 1512274, 3981750, 1838169, 2101846,
+        1363757, 1342163, 3608830, 321523, 1072908, 855117, 1679204, 3624675,
+        3183259, 2438624, 407591, 1549799, 490068, 2769318, 3185950, 990968,
+        3700398, 2715638, 3672301, 3203080, 1775408, 2071611, 778637, 2335351,
+        3317014, 3768001, 571163, 2618746, 1028702, 3174131, 764504, 1386439,
+        4188876, 1131998, 1057083, 39651, 2588805, 2519763, 3838931, 4130059,
+        1893001, 2066802, 572208, 2529031, 220967, 3880345, 1820301, 2205978,
+        3036090, 1648541, 4012391, 1432533, 3068186, 1645476, 1397186, 2112498,
+        4168213, 1234734, 1648052, 1803157, 2011730, 1648875, 2547914, 437873,
+        2460774, 3403214, 2690605, 2567052, 739775, 1854855, 520305, 3661464,
+        1120944, 1245195, 1147367, 2571134, 696367, 3009976, 834907, 1691662,
+        1384090, 2795844, 1813845, 3425954, 4194068, 1317042, 2056507, 470026,
+        3097617, 2678203, 3077203, 2116013, 4155561, 2844478, 1467696, 4150754,
+        992951, 471101, 4062883, 1584992, 2252609, 3322854, 1597940, 3581574,
+        1115369, 4153697, 3236495, 4075586, 2066340, 1262360, 2730720, 3664692,
+        2681478, 2929295, 3831713, 3683420, 2511172, 3689552, 2645837, 2414330,
+        857564, 3703853, 468246, 1574274, 3590547, 2348366, 1565207, 1815326,
+        2508730, 1749217, 465029, 260794, 1630097, 3019607, 3872759, 1053481,
+        3958758, 3415305, 54348, 2516, 3045515, 3011542, 1951553, 1882613,
+        1729323, 801736, 3662451, 909634, 2949838, 2598628, 1652685, 1945350,
+        3221627, 2879417, 2732226, 3883548, 1891328, 3215710, 3159721, 1318941,
+        2153764, 1870381, 4039453, 3375151, 2655219, 4089723, 1388508, 3436490,
+        3956335, 2748982, 4111030, 328986, 1780674, 2570336, 2608795, 2600572,
+        2748827, 790335, 1988956, 3946950, 1789942, 710384, 3900335, 457139,
+        2550557, 3042298, 1952120, 1998308, 259999, 2361900, 119023, 3680445,
+        1893737, 4050016, 2696786, 567472, 3085466, 1580931, 1360307, 3075154,
+        904205, 1306381, 3257843, 2926984, 2065676, 3221598, 2551064, 1580354,
+        1636374, 699891, 1821560, 670885, 947258, 2908840, 3049868, 1038075,
+        1701447, 2439140, 2048478, 3183312, 2224644, 320592, 3304074, 2611056,
+        422256, 1752180, 2217951, 2900510, 1321050, 2797671, 312886, 2624042,
+        3166863, 908176, 24947, 152205, 2891981, 189908, 1959427, 1365987,
+        2071767, 1932065, 3185693, 3889374, 3644713, 79765, 969178, 11268,
+        1992233, 1579325, 1224905, 3741957, 1894871, 3060100, 1787540, 4194180,
+        1396587, 2745514, 26822, 695515, 2348201, 249698, 2988539, 1081347
+
+    };
+
+    public static final int[] ZETA_INVERSE_I = {            /* 512-Entry */
+
+        1217030, 3955871, 1857368, 3510054, 4178747, 1460055, 2808982, 11389,
+        2418029, 1145469, 2310698, 463612, 2980664, 2626244, 2213336, 4194301,
+        3236391, 4125804, 560856, 316195, 1019876, 2273504, 2133802, 2839582,
+        2246142, 4015661, 1313588, 4053364, 4180622, 3297393, 1038706, 1581527,
+        3892683, 1407898, 2884519, 1305059, 1987618, 2453389, 3783313, 1594513,
+        901495, 3884977, 1980925, 1022257, 2157091, 1766429, 2504122, 3167494,
+        1155701, 1296729, 3258311, 3534684, 2384009, 3505678, 2569195, 2625215,
+        1654505, 983971, 2139893, 1278585, 947726, 2899188, 3301364, 1130415,
+        2845262, 2624638, 1120103, 3638097, 1508783, 155553, 2311832, 525124,
+        4086546, 1843669, 3945570, 2207261, 2253449, 1163271, 1655012, 3748430,
+        305234, 3495185, 2415627, 258619, 2216613, 3415234, 1456742, 1604997,
+        1596774, 1635233, 2424895, 3876583, 94539, 1456587, 249234, 769079,
+        2817061, 115846, 1550350, 830418, 166116, 2335188, 2051805, 2886628,
+        1045848, 989859, 2314241, 322021, 1473343, 1326152, 983942, 2260219,
+        2552884, 1606941, 1255731, 3295935, 543118, 3403833, 2476246, 2322956,
+        2254016, 1194027, 1160054, 4203053, 4151221, 790264, 246811, 3152088,
+        332810, 1185962, 2575472, 3944775, 3740540, 2456352, 1696839, 2390243,
+        2640362, 1857203, 615022, 2631295, 3737323, 501716, 3348005, 1791239,
+        1559732, 516017, 1694397, 522149, 373856, 1276274, 1524091, 540877,
+        1474849, 2943209, 2139229, 129983, 969074, 51872, 3090200, 623995,
+        2607629, 882715, 1952960, 2620577, 142686, 3734468, 3212618, 54815,
+        2737873, 1361091, 50008, 2089556, 1128366, 1527366, 1107952, 3735543,
+        2149062, 2888527, 11501, 779615, 2391724, 1409725, 2821479, 2513907,
+        3370662, 1195593, 3509202, 1634435, 3058202, 2960374, 3084625, 544105,
+        3685264, 2350714, 3465794, 1638517, 1514964, 802355, 1744795, 3767696,
+        1657655, 2556694, 2193839, 2402412, 2557517, 2970835, 37356, 2093071,
+        2808383, 2560093, 1137383, 2773036, 193178, 2557028, 1169479, 1999591,
+        2385268, 325224, 3984602, 1676538, 3633361, 2138767, 2312568, 75510,
+        366638, 1685806, 1616764, 4165918, 3148486, 3073571, 16693, 2819130,
+        3441065, 1031438, 3176867, 1586823, 3634406, 437568, 888555, 1870218,
+        3426932, 2133958, 2430161, 1002489, 533268, 1489931, 505171, 3214601,
+        1019619, 1436251, 3715501, 2655770, 3797978, 1766945, 1022310, 580894,
+        2526365, 3350452, 3132661, 3884046, 596739, 2863406, 2841812, 2103723,
+        2367400, 223819, 2693295, 2102769, 1447210, 2445302, 632523, 3402595,
+        902383, 3799635, 1539528, 3670156, 2034135, 2595698, 3474486, 1219933,
+        1662524, 3822131, 1748524, 2301093, 2053832, 882669, 2345870, 1970930,
+        307664, 22223, 895174, 4009390, 3698770, 3951141, 20225, 1987140,
+        2127959, 1232040, 3591316, 3195857, 975552, 2517171, 4066286, 1100725,
+        3792509, 2605124, 856554, 2871333, 2710968, 3728963, 4155287, 2123402,
+        1675992, 1125921, 4166069, 2507989, 2992712, 2945993, 3044494, 3974689,
+        2359217, 91469, 2048487, 2239363, 4190501, 1296571, 2962214, 23332,
+        1499197, 2194520, 777851, 1294670, 98362, 3978135, 939533, 2521527,
+        2031374, 1733878, 2057388, 2321653, 1902883, 3464501, 649938, 3746448,
+        1407025, 2868979, 1866872, 2823992, 2403772, 1729474, 3652637, 2294295,
+        1408803, 3588471, 1560876, 822840, 1854479, 349367, 3473822, 71331,
+        2066555, 3041419, 184610, 3494127, 43679, 2858834, 1300766, 4092161,
+        3013096, 1883, 2384248, 536916, 3200132, 2448265, 2751618, 4198325,
+        2335606, 835632, 1475909, 3712761, 507324, 2619333, 4194335, 302949,
+        1094234, 298978, 2710313, 2380584, 494715, 733787, 1382960, 3410502,
+        3612607, 211939, 1404409, 3461384, 2198058, 339341, 3902634, 2014429,
+        1553156, 693353, 1894192, 122604, 1170731, 4114659, 1953642, 3369625,
+        245053, 2923218, 2658671, 580673, 2915079, 2384193, 8714, 962214,
+        4027734, 789669, 3683359, 3983012, 3463286, 4039167, 2403890, 3783030,
+        3034802, 890018, 280701, 1808405, 3566666, 4106178, 3813869, 893295,
+        1382006, 3559019, 3168695, 2144872, 2022369, 1623695, 4066035, 2934000,
+        2603762, 4010709, 1189812, 1589407, 52974, 1671898, 3022018, 1019883,
+        2391510, 2888980, 4187628, 1051723, 3034285, 2085817, 2578902, 3975068,
+        86562, 489847, 136654, 2116674, 3358926, 959523, 136014, 3239046,
+        2102677, 2619868, 538875, 3195930, 535845, 361370, 3529250, 541241,
+        2516284, 3760447, 1830521, 2254047, 1064338, 368446, 2150259, 1551600,
+        1328182, 2063531, 3136098, 2824386, 3602412, 348730, 869335, 1406204,
+        2606794, 3529876, 857228, 59677, 2739968, 184133, 2849546, 53304,
+        3850240, 1953862, 571552, 273335, 3564155, 965995, 3001848, 2484738,
+        1843388, 1216365, 1072953, 3528207, 3835396, 2016489, 846038, 3124222
+
+    };
+
+    /* Heuristic qTESLA Security Category-3 (Option for Size) */
+
+    public static final int[] ZETA_III_SIZE = {            /* 1024-Entry */
+
+        671800, 4181291, 975654, 970836, 1459996, 2949013, 1578790, 3375131,
+        177347, 2024971, 3299069, 2879655, 1061156, 3772041, 1726661, 2646527,
+        224962, 3106510, 1764167, 3790159, 110295, 277183, 2296602, 1995237,
+        1574725, 1473236, 1081285, 144829, 114244, 719647, 4114328, 917441,
+        4188270, 3805772, 261389, 52393, 2185303, 1021265, 2167874, 2986441,
+        3886274, 2191966, 284211, 3446813, 1389427, 2107810, 1173125, 1597161,
+        3753261, 1373052, 793684, 4091628, 1677907, 4164049, 1948749, 2758369,
+        1027640, 1118203, 891820, 1309242, 1810791, 1863364, 2587868, 1541007,
+        4104068, 675426, 1402433, 2557508, 1068970, 1940808, 3957823, 798456,
+        4092960, 3262467, 1793460, 658044, 1978921, 1367494, 3136736, 2360480,
+        941550, 37800, 1919065, 3032526, 581001, 3323192, 299785, 3114533,
+        545048, 2845265, 1891473, 102035, 2256179, 221259, 1796623, 504470,
+        377401, 3184337, 3107383, 606431, 200460, 3770995, 986925, 207500,
+        3712747, 1696453, 4158053, 3530443, 32005, 3222743, 3918763, 3574153,
+        2768592, 2608835, 1856937, 905294, 214652, 4154226, 2876170, 2651799,
+        1098009, 3905542, 3763042, 3055325, 1438567, 969841, 2397140, 3637385,
+        3779810, 644984, 1638607, 498549, 3404792, 4055115, 9472, 315805,
+        1796876, 972163, 3025826, 3334639, 2290368, 2552107, 160996, 3282568,
+        2279239, 1305163, 2304247, 603598, 3803059, 2582009, 3202587, 1094032,
+        1195417, 2879417, 1648902, 542294, 3085586, 3325229, 4177450, 150226,
+        890698, 503530, 3122945, 1929018, 3309179, 1075767, 2185016, 276011,
+        1620579, 1349757, 454010, 3835301, 3658519, 2369797, 203221, 2116132,
+        1371940, 3499700, 2991078, 3597638, 942280, 506271, 701979, 1853372,
+        2165162, 2830558, 2083508, 3582128, 4177826, 2623861, 3740436, 725559,
+        791017, 595361, 2192451, 878351, 1919935, 1730363, 165115, 3011415,
+        539166, 4049306, 2512830, 3633034, 3743092, 1721797, 356766, 3860922,
+        551806, 520752, 1492250, 3020875, 296084, 3951086, 3702654, 1541222,
+        2760082, 2967699, 1811892, 1913148, 3121111, 2583448, 37791, 2289197,
+        228811, 315449, 2711375, 2035264, 998876, 684125, 1377229, 1723513,
+        2093137, 1181754, 3978572, 1168111, 1295590, 1870157, 2992279, 1610031,
+        2052968, 3195982, 3195020, 2498826, 2430997, 1447298, 2178224, 1573739,
+        3444420, 2425537, 3066466, 1895376, 3494178, 2341084, 2603206, 2810264,
+        3665075, 4030046, 232980, 3770527, 2425457, 3193512, 1906687, 3838549,
+        1081341, 3385499, 343154, 3648238, 3066045, 3502707, 903006, 2216085,
+        2477447, 3769256, 2700907, 2899931, 3094342, 404354, 2325640, 4161594,
+        1153616, 2601633, 624385, 56418, 4122920, 303574, 3474524, 3047326,
+        3446806, 1755473, 1289687, 3030484, 745529, 2037059, 1126174, 3508536,
+        3263841, 1057863, 2424516, 3666380, 2238799, 1918076, 1096624, 666757,
+        2414037, 4105141, 86489, 236751, 2175830, 2842379, 3751432, 366978,
+        1727916, 627613, 2576775, 231383, 2352896, 1039386, 650148, 3849095,
+        2893195, 2813545, 2172937, 1389954, 1261168, 1470030, 832830, 3548304,
+        2585258, 3650945, 3733752, 797947, 4183412, 261772, 374082, 3717015,
+        1306771, 591941, 3320862, 3969254, 3730288, 4153963, 2641916, 706453,
+        3574687, 687011, 3723863, 518936, 674472, 2242626, 174183, 3560884,
+        3969544, 425417, 789235, 4183047, 4027225, 982625, 2075760, 2392513,
+        2538340, 3022462, 1997528, 356548, 3730142, 1536313, 1202696, 1344848,
+        3103217, 2383022, 1762142, 2994989, 3102783, 3072599, 1517632, 2024436,
+        2534641, 147328, 2356097, 190578, 2587663, 440306, 2374767, 3182600,
+        680532, 484370, 4131095, 3009332, 3562207, 976019, 3613316, 3033006,
+        3743622, 4136404, 1605237, 66645, 3859240, 908865, 4051121, 2726336,
+        3637443, 2340134, 813357, 3985220, 2868243, 3650243, 1684957, 3023114,
+        2402323, 1820096, 1764462, 1049670, 2260628, 4976, 3760346, 3157996,
+        3573461, 1006628, 454916, 4159906, 337885, 22277, 520578, 2607705,
+        2561874, 503606, 1415232, 3823408, 3829828, 554510, 914738, 3838536,
+        653901, 664244, 3918457, 361056, 515834, 2583400, 2666144, 1562200,
+        2635470, 3523620, 2847787, 281762, 1416774, 4047010, 2739024, 1492985,
+        2613083, 2116726, 4076288, 4141191, 3357856, 741301, 977038, 4028938,
+        1661277, 2769449, 3571042, 2601104, 57237, 3026729, 3478919, 87366,
+        3697654, 2676961, 3932341, 2883942, 3200147, 623723, 871365, 763732,
+        2354543, 661482, 1442350, 148821, 966821, 2154509, 1229800, 2252524,
+        1712762, 687319, 1231124, 225814, 127675, 2786959, 2996601, 1997279,
+        1410197, 2759369, 254896, 2633749, 743622, 2420984, 594581, 1359068,
+        3724994, 3338166, 473524, 3323698, 110693, 2630130, 3742099, 1392129,
+        1263087, 1474128, 964094, 3338617, 2682625, 2350723, 4039051, 2437147,
+        2003303, 1029372, 3710675, 1198388, 4047402, 337401, 959139, 3673320,
+        3269977, 1757086, 3846011, 3052386, 1555886, 1213798, 1730449, 574426,
+        3730903, 4058825, 3075, 3232877, 597243, 584901, 3208277, 423060,
+        3216342, 3727213, 89571, 709528, 3722455, 112585, 4199553, 578587,
+        1727014, 3010665, 1118724, 3088559, 458307, 695931, 2551953, 3462204,
+        2654347, 2908501, 3034211, 3511237, 3734268, 2443875, 270514, 776347,
+        683036, 1526569, 521044, 2352920, 557737, 4056083, 2391161, 2389563,
+        2293979, 2581739, 2738173, 2545480, 1008072, 3577574, 1673061, 4116273,
+        133058, 1222352, 1144238, 882222, 3000625, 4046931, 141504, 1904001,
+        1035854, 3807884, 2398461, 446181, 2041489, 1148183, 2291458, 3675915,
+        255124, 369448, 3016249, 2025225, 3237403, 2220199, 3134791, 2587255,
+        3220754, 3366174, 132697, 3383227, 1358468, 1158291, 2321651, 2869559,
+        1425523, 4054733, 69091, 3521561, 2453355, 2968118, 2968833, 3185424,
+        988606, 3025251, 1154802, 24092, 1305476, 3938667, 3405455, 2280837,
+        2987149, 1576181, 3812113, 481232, 1911887, 2305037, 3637072, 515558,
+        3183843, 3460525, 2134536, 3376047, 849276, 912675, 3126131, 3349335,
+        1736653, 247313, 307171, 2906949, 2483567, 3951115, 449581, 3211241,
+        119780, 3050685, 312715, 129516, 1413964, 3626707, 1834389, 739674,
+        2166987, 1898439, 3247386, 543470, 3893129, 1952324, 4010533, 2663329,
+        1611039, 4159354, 3221090, 4011118, 456104, 4128401, 3481956, 1341852,
+        1346376, 1373597, 1886912, 2289124, 2035164, 3802432, 4020200, 1440583,
+        131860, 2447356, 1147783, 3884191, 36600, 1417517, 3115113, 4106357,
+        2209232, 3913295, 2079509, 2915453, 253356, 2093028, 3105753, 420898,
+        3641863, 2237777, 589597, 3471638, 1556385, 1574364, 2961455, 2414774,
+        2532838, 3894119, 2561579, 1825751, 2610770, 4095615, 2366084, 1696032,
+        2935352, 1982899, 3940806, 962691, 2874348, 2295425, 3088987, 1724605,
+        138760, 2611152, 2321223, 3862854, 977071, 3373271, 2119442, 2444640,
+        184156, 2401204, 2250096, 3883423, 24318, 1799015, 2709027, 2477092,
+        2937887, 872546, 348220, 49520, 266109, 1166709, 1470353, 712356,
+        4162049, 2520023, 1093919, 3371334, 1529777, 3549597, 3033168, 3626405,
+        317815, 972428, 3325840, 1416192, 1615043, 3225312, 49030, 591050,
+        3470933, 533400, 905783, 2128579, 2589779, 1556207, 3295501, 3128246,
+        1323037, 2836289, 1222103, 2635029, 764092, 1785154, 1271391, 407326,
+        3293361, 697832, 1957938, 26925, 1909470, 921060, 1189793, 452905,
+        177180, 3986522, 3612073, 2634482, 3811697, 2155464, 3184049, 3773906,
+        4155559, 890604, 965647, 946702, 2980153, 2514794, 1634712, 1413135,
+        2059115, 1095948, 1094602, 3286386, 1617289, 2234906, 2942756, 2831603,
+        2790364, 4110867, 3267277, 2818115, 997189, 3975212, 1919457, 3294782,
+        42631, 3979780, 677949, 1074671, 4007873, 2013224, 4064265, 1404667,
+        1266413, 1753048, 1480954, 2251688, 3671233, 3337348, 3023835, 704482,
+        1867102, 2290506, 1202801, 3686892, 3618479, 3297031, 2477670, 3415258,
+        2889498, 2106378, 361488, 1478812, 3536666, 645275, 2793501, 2983604,
+        3150760, 1136423, 2629214, 3144871, 1095947, 2432448, 3144124, 1562104,
+        3685583, 2519659, 1745378, 275993, 1028739, 4053547, 3139341, 791685,
+        205316, 940435, 3044250, 3537550, 2347550, 2748749, 216515, 2376693,
+        3994272, 758809, 336837, 4138282, 254982, 2087732, 1443586, 2090448,
+        2407213, 2192231, 584225, 1528366, 714102, 2781015, 1061159, 144894,
+        2251444, 1706143, 3064185, 1082774, 1212561, 1964667, 1808852, 1281436,
+        380192, 1938622, 3594224, 2865093, 1814198, 3709791, 3557452, 641073,
+        3449310, 2797672, 1886229, 2374072, 1947652, 910530, 4110612, 3688785,
+        2761424, 2192378, 1210992, 432423, 3990493, 3710041, 3364266, 1402625,
+        1430941, 466915, 2307343, 3969361, 3041855, 1636011, 2336989, 4083954,
+        1752367, 1468975, 4003767, 2752277, 2639144, 2435428, 168292, 2731409,
+        2173963, 313121, 1885409, 1792411, 105750, 1595875, 3535511, 1917121,
+        3348968, 3600516, 3025874, 1234611, 387230, 254793, 2267177, 423073,
+        3643782, 2241875, 720861, 3996710, 2066073, 1031892, 2436415, 3356685,
+        3628852, 1131491, 315588, 3085726, 4060906, 3713538, 561022, 142143,
+        137017, 4091465, 525060, 523088, 2581256, 2546361, 529201, 1724592,
+        3917913, 4096490, 1689933, 575672, 2633453, 2453964, 3882580, 236313,
+        394169, 2731312, 3191196, 135139, 1208112, 2180950, 4051722, 330078,
+        4161293, 3314132, 1075088, 3797989, 958522, 1974573, 3610471, 3368492,
+        629863, 3712506, 281606, 4189621, 1437509, 2515187, 1936773, 3150875,
+        797596, 4050969, 2506561, 2023050, 3235484, 2216101, 3003527, 569898,
+        2081018, 3678953, 3392925, 857476, 1224594, 2996526, 3160227, 35843
+
+    };
+
+    public static final int[] ZETA_INVERSE_III_SIZE = {    /* 1024-Entry */
+
+        1046366, 1210067, 2981999, 3349117, 813668, 527640, 2125575, 3636695,
+        1203066, 1990492, 971109, 2183543, 1700032, 155624, 3408997, 1055718,
+        2269820, 1691406, 2769084, 16972, 3924987, 494087, 3576730, 838101,
+        596122, 2232020, 3248071, 408604, 3131505, 892461, 45300, 3876515,
+        154871, 2025643, 2998481, 4071454, 1015397, 1475281, 3812424, 3970280,
+        324013, 1752629, 1573140, 3630921, 2516660, 110103, 288680, 2482001,
+        3677392, 1660232, 1625337, 3683505, 3681533, 115128, 4069576, 4064450,
+        3645571, 493055, 145687, 1120867, 3891005, 3075102, 577741, 849908,
+        1770178, 3174701, 2140520, 209883, 3485732, 1964718, 562811, 3783520,
+        1939416, 3951800, 3819363, 2971982, 1180719, 606077, 857625, 2289472,
+        671082, 2610718, 4100843, 2414182, 2321184, 3893472, 2032630, 1475184,
+        4038301, 1771165, 1567449, 1454316, 202826, 2737618, 2454226, 122639,
+        1869604, 2570582, 1164738, 237232, 1899250, 3739678, 2775652, 2803968,
+        842327, 496552, 216100, 3774170, 2995601, 2014215, 1445169, 517808,
+        95981, 3296063, 2258941, 1832521, 2320364, 1408921, 757283, 3565520,
+        649141, 496802, 2392395, 1341500, 612369, 2267971, 3826401, 2925157,
+        2397741, 2241926, 2994032, 3123819, 1142408, 2500450, 1955149, 4061699,
+        3145434, 1425578, 3492491, 2678227, 3622368, 2014362, 1799380, 2116145,
+        2763007, 2118861, 3951611, 68311, 3869756, 3447784, 212321, 1829900,
+        3990078, 1457844, 1859043, 669043, 1162343, 3266158, 4001277, 3414908,
+        1067252, 153046, 3177854, 3930600, 2461215, 1686934, 521010, 2644489,
+        1062469, 1774145, 3110646, 1061722, 1577379, 3070170, 1055833, 1222989,
+        1413092, 3561318, 669927, 2727781, 3845105, 2100215, 1317095, 791335,
+        1728923, 909562, 588114, 519701, 3003792, 1916087, 2339491, 3502111,
+        1182758, 869245, 535360, 1954905, 2725639, 2453545, 2940180, 2801926,
+        142328, 2193369, 198720, 3131922, 3528644, 226813, 4163962, 911811,
+        2287136, 231381, 3209404, 1388478, 939316, 95726, 1416229, 1374990,
+        1263837, 1971687, 2589304, 920207, 3111991, 3110645, 2147478, 2793458,
+        2571881, 1691799, 1226440, 3259891, 3240946, 3315989, 51034, 432687,
+        1022544, 2051129, 394896, 1572111, 594520, 220071, 4029413, 3753688,
+        3016800, 3285533, 2297123, 4179668, 2248655, 3508761, 913232, 3799267,
+        2935202, 2421439, 3442501, 1571564, 2984490, 1370304, 2883556, 1078347,
+        911092, 2650386, 1616814, 2078014, 3300810, 3673193, 735660, 3615543,
+        4157563, 981281, 2591550, 2790401, 880753, 3234165, 3888778, 580188,
+        1173425, 656996, 2676816, 835259, 3112674, 1686570, 44544, 3494237,
+        2736240, 3039884, 3940484, 4157073, 3858373, 3334047, 1268706, 1729501,
+        1497566, 2407578, 4182275, 323170, 1956497, 1805389, 4022437, 1761953,
+        2087151, 833322, 3229522, 343739, 1885370, 1595441, 4067833, 2481988,
+        1117606, 1911168, 1332245, 3243902, 265787, 2223694, 1271241, 2510561,
+        1840509, 110978, 1595823, 2380842, 1645014, 312474, 1673755, 1791819,
+        1245138, 2632229, 2650208, 734955, 3616996, 1968816, 564730, 3785695,
+        1100840, 2113565, 3953237, 1291140, 2127084, 293298, 1997361, 100236,
+        1091480, 2789076, 4169993, 322402, 3058810, 1759237, 4074733, 2766010,
+        186393, 404161, 2171429, 1917469, 2319681, 2832996, 2860217, 2864741,
+        724637, 78192, 3750489, 195475, 985503, 47239, 2595554, 1543264,
+        196060, 2254269, 313464, 3663123, 959207, 2308154, 2039606, 3466919,
+        2372204, 579886, 2792629, 4077077, 3893878, 1155908, 4086813, 995352,
+        3757012, 255478, 1723026, 1299644, 3899422, 3959280, 2469940, 857258,
+        1080462, 3293918, 3357317, 830546, 2072057, 746068, 1022750, 3691035,
+        569521, 1901556, 2294706, 3725361, 394480, 2630412, 1219444, 1925756,
+        801138, 267926, 2901117, 4182501, 3051791, 1181342, 3217987, 1021169,
+        1237760, 1238475, 1753238, 685032, 4137502, 151860, 2781070, 1337034,
+        1884942, 3048302, 2848125, 823366, 4073896, 840419, 985839, 1619338,
+        1071802, 1986394, 969190, 2181368, 1190344, 3837145, 3951469, 530678,
+        1915135, 3058410, 2165104, 3760412, 1808132, 398709, 3170739, 2302592,
+        4065089, 159662, 1205968, 3324371, 3062355, 2984241, 4073535, 90320,
+        2533532, 629019, 3198521, 1661113, 1468420, 1624854, 1912614, 1817030,
+        1815432, 150510, 3648856, 1853673, 3685549, 2680024, 3523557, 3430246,
+        3936079, 1762718, 472325, 695356, 1172382, 1298092, 1552246, 744389,
+        1654640, 3510662, 3748286, 1118034, 3087869, 1195928, 2479579, 3628006,
+        7040, 4094008, 484138, 3497065, 4117022, 479380, 990251, 3783533,
+        998316, 3621692, 3609350, 973716, 4203518, 147768, 475690, 3632167,
+        2476144, 2992795, 2650707, 1154207, 360582, 2449507, 936616, 533273,
+        3247454, 3869192, 159191, 3008205, 495918, 3177221, 2203290, 1769446,
+        167542, 1855870, 1523968, 867976, 3242499, 2732465, 2943506, 2814464,
+        464494, 1576463, 4095900, 882895, 3733069, 868427, 481599, 2847525,
+        3612012, 1785609, 3462971, 1572844, 3951697, 1447224, 2796396, 2209314,
+        1209992, 1419634, 4078918, 3980779, 2975469, 3519274, 2493831, 1954069,
+        2976793, 2052084, 3239772, 4057772, 2764243, 3545111, 1852050, 3442861,
+        3335228, 3582870, 1006446, 1322651, 274252, 1529632, 508939, 4119227,
+        727674, 1179864, 4149356, 1605489, 635551, 1437144, 2545316, 177655,
+        3229555, 3465292, 848737, 65402, 130305, 2089867, 1593510, 2713608,
+        1467569, 159583, 2789819, 3924831, 1358806, 682973, 1571123, 2644393,
+        1540449, 1623193, 3690759, 3845537, 288136, 3542349, 3552692, 368057,
+        3291855, 3652083, 376765, 383185, 2791361, 3702987, 1644719, 1598888,
+        3686015, 4184316, 3868708, 46687, 3751677, 3199965, 633132, 1048597,
+        446247, 4201617, 1945965, 3156923, 2442131, 2386497, 1804270, 1183479,
+        2521636, 556350, 1338350, 221373, 3393236, 1866459, 569150, 1480257,
+        155472, 3297728, 347353, 4139948, 2601356, 70189, 462971, 1173587,
+        593277, 3230574, 644386, 1197261, 75498, 3722223, 3526061, 1023993,
+        1831826, 3766287, 1618930, 4016015, 1850496, 4059265, 1671952, 2182157,
+        2688961, 1133994, 1103810, 1211604, 2444451, 1823571, 1103376, 2861745,
+        3003897, 2670280, 476451, 3850045, 2209065, 1184131, 1668253, 1814080,
+        2130833, 3223968, 179368, 23546, 3417358, 3781176, 237049, 645709,
+        4032410, 1963967, 3532121, 3687657, 482730, 3519582, 631906, 3500140,
+        1564677, 52630, 476305, 237339, 885731, 3614652, 2899822, 489578,
+        3832511, 3944821, 23181, 3408646, 472841, 555648, 1621335, 658289,
+        3373763, 2736563, 2945425, 2816639, 2033656, 1393048, 1313398, 357498,
+        3556445, 3167207, 1853697, 3975210, 1629818, 3578980, 2478677, 3839615,
+        455161, 1364214, 2030763, 3969842, 4120104, 101452, 1792556, 3539836,
+        3109969, 2288517, 1967794, 540213, 1782077, 3148730, 942752, 698057,
+        3080419, 2169534, 3461064, 1176109, 2916906, 2451120, 759787, 1159267,
+        732069, 3903019, 83673, 4150175, 3582208, 1604960, 3052977, 44999,
+        1880953, 3802239, 1112251, 1306662, 1505686, 437337, 1729146, 1990508,
+        3303587, 703886, 1140548, 558355, 3863439, 821094, 3125252, 368044,
+        2299906, 1013081, 1781136, 436066, 3973613, 176547, 541518, 1396329,
+        1603387, 1865509, 712415, 2311217, 1140127, 1781056, 762173, 2632854,
+        2028369, 2759295, 1775596, 1707767, 1011573, 1010611, 2153625, 2596562,
+        1214314, 2336436, 2911003, 3038482, 228021, 3024839, 2113456, 2483080,
+        2829364, 3522468, 3207717, 2171329, 1495218, 3891144, 3977782, 1917396,
+        4168802, 1623145, 1085482, 2293445, 2394701, 1238894, 1446511, 2665371,
+        503939, 255507, 3910509, 1185718, 2714343, 3685841, 3654787, 345671,
+        3849827, 2484796, 463501, 573559, 1693763, 157287, 3667427, 1195178,
+        4041478, 2476230, 2286658, 3328242, 2014142, 3611232, 3415576, 3481034,
+        466157, 1582732, 28767, 624465, 2123085, 1376035, 2041431, 2353221,
+        3504614, 3700322, 3264313, 608955, 1215515, 706893, 2834653, 2090461,
+        4003372, 1836796, 548074, 371292, 3752583, 2856836, 2586014, 3930582,
+        2021577, 3130826, 897414, 2277575, 1083648, 3703063, 3315895, 4056367,
+        29143, 881364, 1121007, 3664299, 2557691, 1327176, 3011176, 3112561,
+        1004006, 1624584, 403534, 3602995, 1902346, 2901430, 1927354, 924025,
+        4045597, 1654486, 1916225, 871954, 1180767, 3234430, 2409717, 3890788,
+        4197121, 151478, 801801, 3708044, 2567986, 3561609, 426783, 569208,
+        1809453, 3236752, 2768026, 1151268, 443551, 301051, 3108584, 1554794,
+        1330423, 52367, 3991941, 3301299, 2349656, 1597758, 1438001, 632440,
+        287830, 983850, 4174588, 676150, 48540, 2510140, 493846, 3999093,
+        3219668, 435598, 4006133, 3600162, 1099210, 1022256, 3829192, 3702123,
+        2409970, 3985334, 1950414, 4104558, 2315120, 1361328, 3661545, 1092060,
+        3906808, 883401, 3625592, 1174067, 2287528, 4168793, 3265043, 1846113,
+        1069857, 2839099, 2227672, 3548549, 2413133, 944126, 113633, 3408137,
+        248770, 2265785, 3137623, 1649085, 2804160, 3531167, 102525, 2665586,
+        1618725, 2343229, 2395802, 2897351, 3314773, 3088390, 3178953, 1448224,
+        2257844, 42544, 2528686, 114965, 3412909, 2833541, 453332, 2609432,
+        3033468, 2098783, 2817166, 759780, 3922382, 2014627, 320319, 1220152,
+        2038719, 3185328, 2021290, 4154200, 3945204, 400821, 18323, 3289152,
+        92265, 3486946, 4092349, 4061764, 3125308, 2733357, 2631868, 2211356,
+        1909991, 3929410, 4096298, 416434, 2442426, 1100083, 3981631, 1560066,
+        2479932, 434552, 3145437, 1326938, 907524, 2181622, 4029246, 831462,
+        2627803, 1257580, 2746597, 3235757, 3230939, 25302, 3534793, 4170750
+
+    };
+
+    /* Heuristic qTESLA Security Category-3 (Option for Speed) */
+
+    public static final int[] ZETA_III_SPEED = {            /* 1024-Entry */
+
+        4751355, 3795849, 4203855, 2135008, 6005859, 8231721, 5028848, 2129664,
+        7697675, 4755217, 4725508, 3239612, 6448681, 1076080, 3836135, 157994,
+        5620931, 7886062, 2890907, 5218426, 5961785, 6266756, 6428554, 5190121,
+        4542230, 1731429, 2223635, 4784194, 3466184, 2050685, 6391390, 2917454,
+        2117568, 5724978, 3127077, 96284, 5251989, 3298678, 7201703, 432021,
+        540694, 6011377, 6511091, 6136825, 215125, 6152822, 4121955, 6320948,
+        4723419, 3116754, 3645529, 4643271, 3249093, 3697259, 965302, 3790255,
+        413429, 835404, 7555714, 4708344, 980578, 8245349, 3583234, 5891188,
+        510086, 5483952, 4214513, 7522675, 1382737, 8097349, 2423268, 1978286,
+        5820434, 2985005, 1002240, 3252040, 5584283, 4027445, 3761478, 571563,
+        7926529, 5265675, 4705738, 1136608, 2087977, 4856723, 7896505, 2504130,
+        4175968, 5245926, 3848909, 3723902, 2181242, 6476735, 5922041, 2555482,
+        6087709, 1106974, 975919, 978505, 666303, 510879, 5043449, 4402981,
+        4204183, 6947226, 3519239, 7237093, 2533941, 1259684, 4897608, 2422013,
+        5398162, 3551190, 6378523, 1066751, 5216741, 6557683, 7171180, 7736022,
+        7762004, 7816398, 434930, 5685531, 7776512, 2136107, 4689096, 2604202,
+        981324, 6730872, 7113462, 4313227, 5315069, 2687514, 6464663, 6622027,
+        4919554, 3137828, 6662263, 180027, 1225049, 993103, 6035200, 4768729,
+        7594608, 7982166, 1506084, 1412996, 7294988, 6493396, 3679803, 707143,
+        5016089, 5893370, 7746168, 8284307, 2196442, 4506697, 5744441, 8155374,
+        2335696, 3358969, 4559736, 8378847, 7396599, 5613912, 5146767, 5609330,
+        7478110, 7007768, 1540167, 2082109, 4395136, 2443, 1730472, 6785605,
+        3689430, 7862069, 5994777, 2079150, 1569788, 3575961, 2449565, 7637802,
+        3223577, 7636917, 7014221, 3206599, 1033702, 2788915, 2962522, 5785994,
+        2935623, 8040165, 646639, 6994735, 1576929, 4976182, 1923760, 7349612,
+        7767222, 5695773, 2143434, 1957445, 6164911, 6325092, 3612819, 5415356,
+        6956649, 426840, 6748291, 3530533, 2487417, 7851363, 3671732, 7201581,
+        4717139, 4328822, 5046010, 6056773, 997476, 3549222, 1616322, 3335537,
+        2012692, 7475529, 2140630, 167787, 3791455, 3347958, 1263751, 2818658,
+        8280316, 4667491, 7207537, 6918648, 6602507, 1441518, 5135376, 1610367,
+        1016061, 6841480, 1841539, 2809077, 5412381, 1240493, 4442913, 2092171,
+        530239, 4308557, 3094305, 18124, 7247221, 5096652, 6892131, 3384856,
+        1435046, 3360331, 4908655, 1534384, 724138, 4632705, 7021901, 776577,
+        6462800, 658408, 6767742, 6323190, 163450, 3090558, 8264681, 6113406,
+        2256514, 2002774, 4157811, 1055743, 4272701, 50782, 506820, 2425609,
+        6121916, 7048118, 7211758, 7436523, 7921267, 8219231, 2113012, 5561555,
+        5402793, 6238877, 2785469, 6601179, 5379488, 8247469, 7039082, 8122949,
+        4032315, 7719142, 6412117, 1765474, 1423373, 3702073, 6814517, 4539579,
+        3714409, 3581714, 4818181, 4950204, 6549391, 6746510, 1332314, 6200219,
+        4026957, 4085009, 6474721, 6328096, 8097370, 821395, 4479068, 6408341,
+        1730278, 3865108, 131998, 3351400, 4527559, 4193606, 1952686, 3339484,
+        549242, 3890467, 3314638, 2970830, 7867854, 235273, 4948941, 3082658,
+        6487691, 6448908, 3822702, 5156099, 3762420, 359477, 1160634, 2545064,
+        2616573, 343964, 1277910, 8113538, 5564704, 6944366, 2663139, 2516714,
+        7942808, 5983628, 6727371, 7839582, 4671024, 5279277, 2488251, 5096610,
+        7584873, 1054559, 3389302, 5410955, 2700464, 7113783, 1182446, 681631,
+        7959149, 1325409, 3882231, 4559, 7653722, 2600940, 4354328, 6155200,
+        8125241, 629708, 1056841, 5566349, 6779032, 7067599, 5284661, 693330,
+        7111640, 6054764, 513663, 3702555, 3667331, 8053262, 3156410, 3207020,
+        6096921, 3226364, 425916, 1538990, 398369, 155207, 5962206, 3895624,
+        3506460, 4470299, 8132637, 7313282, 1829556, 3023684, 7819374, 258083,
+        4547318, 6274233, 4376026, 630321, 5354666, 3252030, 3347795, 5465400,
+        424523, 5150532, 4329513, 5096843, 2541091, 4590781, 5698802, 5642789,
+        6737542, 6616826, 6654175, 1804189, 2843875, 5019191, 2161010, 1581450,
+        7289320, 4525144, 2861293, 1184843, 6181826, 3408399, 6954125, 5897789,
+        899044, 983144, 996950, 2489509, 387143, 6743865, 6535741, 5316114,
+        2464958, 6452453, 6588356, 7749117, 3100483, 5451553, 6683005, 6153131,
+        2627493, 3750459, 6016367, 1854681, 5732487, 5756336, 8222984, 6286073,
+        4805023, 4851345, 5346259, 2571898, 7886466, 915166, 750162, 7786158,
+        3314583, 3691654, 8162728, 2964553, 934173, 2078087, 5894912, 103974,
+        2087696, 8074875, 5687948, 6220280, 5741269, 3408244, 5908533, 5524440,
+        405672, 2691224, 4107404, 1478212, 5069278, 1307718, 2701016, 5020579,
+        3281802, 173449, 7661012, 6737317, 2871182, 7099172, 8035102, 4259638,
+        676548, 1986555, 2711904, 72486, 1537417, 4903843, 6366739, 2767425,
+        4405806, 3939004, 6029482, 7042007, 7145803, 4423846, 5865280, 6985580,
+        4890457, 5525519, 3020926, 5286410, 2507470, 164000, 7418741, 3860720,
+        464246, 7532333, 2980645, 2208123, 1971493, 7819798, 4391480, 3562255,
+        1579560, 3499404, 3220123, 5084410, 2287245, 6505523, 7780056, 63470,
+        7361152, 6336292, 3791465, 1891129, 6121738, 6215206, 578317, 2487175,
+        2862407, 7213504, 175006, 850302, 4374314, 3335934, 5070337, 6404001,
+        6073674, 8339498, 2024643, 590809, 3871922, 7695009, 3420134, 2417242,
+        2441851, 510359, 6415975, 5966400, 1511640, 3278055, 7552659, 7251424,
+        299565, 4631182, 923500, 4565103, 1774136, 1514014, 504288, 7611114,
+        348434, 6179273, 6103289, 5512004, 6204874, 4163633, 4030619, 5442160,
+        5517078, 4979705, 1450139, 4955279, 6892996, 1378796, 7049658, 7482552,
+        2773460, 3700106, 5637962, 1306126, 1342831, 2876039, 2004802, 7911534,
+        7811881, 7092783, 2948733, 3985770, 4334975, 2089910, 4202878, 5889243,
+        2572806, 7276150, 3116397, 4610309, 4197207, 4524762, 3158380, 712800,
+        7767402, 2288328, 3468435, 4486610, 3258256, 4642983, 4397184, 3897150,
+        3551813, 5337205, 7602723, 882125, 4202004, 8272524, 4429435, 2663261,
+        1849803, 4271342, 947283, 5290695, 2673376, 7191822, 2383684, 5913757,
+        1682056, 4777883, 695434, 2390033, 5758581, 3482483, 6148624, 4372212,
+        1400527, 3325425, 3100142, 7502466, 6912369, 6564003, 187779, 6691298,
+        1850484, 1886083, 496958, 4353128, 6385269, 7972087, 3249950, 1216051,
+        2945392, 1716654, 974864, 2073675, 4221586, 3197564, 5970107, 2900682,
+        1387771, 1054897, 5018658, 4773826, 2772495, 3056563, 3437397, 1151634,
+        3999643, 4238788, 2370183, 7770204, 2300657, 4762800, 4526771, 4778855,
+        6276244, 2113067, 4081453, 4596532, 896126, 1589159, 5012357, 1884715,
+        3849142, 1866468, 1032092, 4847686, 5661618, 424095, 6396824, 6683872,
+        1861112, 2415218, 7008299, 7999725, 61635, 7831813, 1934052, 1635771,
+        5857904, 3890446, 3661009, 4427825, 1472600, 2675631, 3142762, 2889031,
+        6246428, 3402870, 890885, 300722, 6084442, 6218398, 6764876, 198422,
+        5203148, 1220540, 3348691, 7973167, 1045857, 5930282, 7686549, 4965437,
+        2645402, 3029580, 1825802, 4844838, 5808305, 3553948, 2913430, 4640069,
+        3231039, 5061776, 3388089, 5793791, 5210767, 6179591, 3259669, 208882,
+        7981542, 8176212, 8044267, 4362411, 8164807, 3882310, 4575856, 1654989,
+        2265125, 4993003, 1845358, 876204, 4604356, 6572234, 3709582, 2495322,
+        7769694, 925160, 5211127, 3071339, 8271814, 1715113, 5979772, 8317560,
+        2452182, 4560530, 2756321, 7541123, 2085235, 2131014, 7043807, 945796,
+        1043611, 2220162, 1519639, 1881321, 4596482, 136652, 8225264, 4442429,
+        3140394, 4274467, 2235364, 3403641, 181254, 2256107, 5402447, 274444,
+        2450384, 774651, 1007857, 488393, 7305342, 8006923, 6213033, 6045031,
+        7357074, 3686418, 2069641, 4827274, 6134510, 8182850, 6622239, 4957796,
+        5001496, 2676491, 2165891, 4258696, 1805202, 5978874, 5892091, 3081817,
+        8351892, 2919790, 6813596, 1226235, 7874664, 1597662, 445691, 7699844,
+        517985, 5142533, 583275, 2942212, 2005170, 2781492, 5325095, 5840485,
+        5904531, 1652696, 462001, 488382, 1483208, 3583371, 3903552, 4338246,
+        8102054, 4607027, 3097235, 5461223, 878707, 5641705, 3004044, 6269117,
+        8310809, 1068150, 3754674, 7419023, 2389012, 2672920, 7033357, 3299934,
+        5696831, 8333890, 6870124, 4248890, 7451238, 2996873, 969409, 4748469,
+        6761147, 7334152, 4608897, 6381766, 593469, 5060352, 7663929, 3490012,
+        5639842, 804562, 3554683, 1275119, 2464713, 584123, 1282802, 869246,
+        1698712, 460380, 2270294, 1082297, 5755881, 4164200, 3083595, 7232256,
+        6669791, 5297513, 7888160, 305159, 4943995, 4839451, 4607217, 4607189,
+        4027370, 6773057, 2930951, 7228212, 4930292, 5787132, 6979166, 3679768,
+        2488882, 7434774, 6751191, 4901863, 601751, 3772392, 4470584, 3139313,
+        2581011, 5344571, 2578160, 126930, 4080823, 5594812, 3191131, 2170321,
+        4703512, 3837804, 7417071, 2996858, 6019670, 5239573, 1770901, 7113857,
+        5965467, 8008016, 192380, 7790747, 867783, 2310931, 477474, 723267,
+        2025346, 7474446, 1992778, 5665730, 5375937, 1925098, 1772156, 7957977,
+        7842750, 4780661, 1703317, 4165961, 5256458, 4850569, 4937646, 1616991,
+        8229940, 128563, 1160620, 5109082, 4794032, 4890146, 4147576, 7912097,
+        927266, 450684, 7302719, 2598976, 5529718, 1041149, 4841395, 6276135,
+        7825395, 7621671, 6329777, 1955851, 6040427, 1035300, 2855476, 3258870,
+        3396861, 5274746, 2777694, 3359337, 4493563, 561924, 7215951, 2907115,
+        4547697, 5403413, 7025806, 2453538, 4137455, 971005, 4298903, 1271923,
+        7150549, 2833306, 8021667, 7587207, 833119, 2919663, 5306176, 659188,
+        4708953, 3799478, 5584025, 7305039, 5709959, 3562365, 965949, 15873
+
+    };
+
+    public static final int[] ZETA_INVERSE_III_SPEED = {    /* 1024-Entry */
+
+        7439044, 4842628, 2695034, 1099954, 2820968, 4605515, 3696040, 7745805,
+        3098817, 5485330, 7571874, 817786, 383326, 5571687, 1254444, 7133070,
+        4106090, 7433988, 4267538, 5951455, 1379187, 3001580, 3857296, 5497878,
+        1189042, 7843069, 3911430, 5045656, 5627299, 3130247, 5008132, 5146123,
+        5549517, 7369693, 2364566, 6449142, 2075216, 783322, 579598, 2128858,
+        3563598, 7363844, 2875275, 5806017, 1102274, 7954309, 7477727, 492896,
+        4257417, 3514847, 3610961, 3295911, 7244373, 8276430, 175053, 6788002,
+        3467347, 3554424, 3148535, 4239032, 6701676, 3624332, 562243, 447016,
+        6632837, 6479895, 3029056, 2739263, 6412215, 930547, 6379647, 7681726,
+        7927519, 6094062, 7537210, 614246, 8212613, 396977, 2439526, 1291136,
+        6634092, 3165420, 2385323, 5408135, 987922, 4567189, 3701481, 6234672,
+        5213862, 2810181, 4324170, 8278063, 5826833, 3060422, 5823982, 5265680,
+        3934409, 4632601, 7803242, 3503130, 1653802, 970219, 5916111, 4725225,
+        1425827, 2617861, 3474701, 1176781, 5474042, 1631936, 4377623, 3797804,
+        3797776, 3565542, 3460998, 8099834, 516833, 3107480, 1735202, 1172737,
+        5321398, 4240793, 2649112, 7322696, 6134699, 7944613, 6706281, 7535747,
+        7122191, 7820870, 5940280, 7129874, 4850310, 7600431, 2765151, 4914981,
+        741064, 3344641, 7811524, 2023227, 3796096, 1070841, 1643846, 3656524,
+        7435584, 5408120, 953755, 4156103, 1534869, 71103, 2708162, 5105059,
+        1371636, 5732073, 6015981, 985970, 4650319, 7336843, 94184, 2135876,
+        5400949, 2763288, 7526286, 2943770, 5307758, 3797966, 302939, 4066747,
+        4501441, 4821622, 6921785, 7916611, 7942992, 6752297, 2500462, 2564508,
+        3079898, 5623501, 6399823, 5462781, 7821718, 3262460, 7887008, 705149,
+        7959302, 6807331, 530329, 7178758, 1591397, 5485203, 53101, 5323176,
+        2512902, 2426119, 6599791, 4146297, 6239102, 5728502, 3403497, 3447197,
+        1782754, 222143, 2270483, 3577719, 6335352, 4718575, 1047919, 2359962,
+        2191960, 398070, 1099651, 7916600, 7397136, 7630342, 5954609, 8130549,
+        3002546, 6148886, 8223739, 5001352, 6169629, 4130526, 5264599, 3962564,
+        179729, 8268341, 3808511, 6523672, 6885354, 6184831, 7361382, 7459197,
+        1361186, 6273979, 6319758, 863870, 5648672, 3844463, 5952811, 87433,
+        2425221, 6689880, 133179, 5333654, 3193866, 7479833, 635299, 5909671,
+        4695411, 1832759, 3800637, 7528789, 6559635, 3411990, 6139868, 6750004,
+        3829137, 4522683, 240186, 4042582, 360726, 228781, 423451, 8196111,
+        5145324, 2225402, 3194226, 2611202, 5016904, 3343217, 5173954, 3764924,
+        5491563, 4851045, 2596688, 3560155, 6579191, 5375413, 5759591, 3439556,
+        718444, 2474711, 7359136, 431826, 5056302, 7184453, 3201845, 8206571,
+        1640117, 2186595, 2320551, 8104271, 7514108, 5002123, 2158565, 5515962,
+        5262231, 5729362, 6932393, 3977168, 4743984, 4514547, 2547089, 6769222,
+        6470941, 573180, 8343358, 405268, 1396694, 5989775, 6543881, 1721121,
+        2008169, 7980898, 2743375, 3557307, 7372901, 6538525, 4555851, 6520278,
+        3392636, 6815834, 7508867, 3808461, 4323540, 6291926, 2128749, 3626138,
+        3878222, 3642193, 6104336, 634789, 6034810, 4166205, 4405350, 7253359,
+        4967596, 5348430, 5632498, 3631167, 3386335, 7350096, 7017222, 5504311,
+        2434886, 5207429, 4183407, 6331318, 7430129, 6688339, 5459601, 7188942,
+        5155043, 432906, 2019724, 4051865, 7908035, 6518910, 6554509, 1713695,
+        8217214, 1840990, 1492624, 902527, 5304851, 5079568, 7004466, 4032781,
+        2256369, 4922510, 2646412, 6014960, 7709559, 3627110, 6722937, 2491236,
+        6021309, 1213171, 5731617, 3114298, 7457710, 4133651, 6555190, 5741732,
+        3975558, 132469, 4202989, 7522868, 802270, 3067788, 4853180, 4507843,
+        4007809, 3762010, 5146737, 3918383, 4936558, 6116665, 637591, 7692193,
+        5246613, 3880231, 4207786, 3794684, 5288596, 1128843, 5832187, 2515750,
+        4202115, 6315083, 4070018, 4419223, 5456260, 1312210, 593112, 493459,
+        6400191, 5528954, 7062162, 7098867, 2767031, 4704887, 5631533, 922441,
+        1355335, 7026197, 1511997, 3449714, 6954854, 3425288, 2887915, 2962833,
+        4374374, 4241360, 2200119, 2892989, 2301704, 2225720, 8056559, 793879,
+        7900705, 6890979, 6630857, 3839890, 7481493, 3773811, 8105428, 1153569,
+        852334, 5126938, 6893353, 2438593, 1989018, 7894634, 5963142, 5987751,
+        4984859, 709984, 4533071, 7814184, 6380350, 65495, 2331319, 2000992,
+        3334656, 5069059, 4030679, 7554691, 8229987, 1191489, 5542586, 5917818,
+        7826676, 2189787, 2283255, 6513864, 4613528, 2068701, 1043841, 8341523,
+        624937, 1899470, 6117748, 3320583, 5184870, 4905589, 6825433, 4842738,
+        4013513, 585195, 6433500, 6196870, 5424348, 872660, 7940747, 4544273,
+        986252, 8240993, 5897523, 3118583, 5384067, 2879474, 3514536, 1419413,
+        2539713, 3981147, 1259190, 1362986, 2375511, 4465989, 3999187, 5637568,
+        2038254, 3501150, 6867576, 8332507, 5693089, 6418438, 7728445, 4145355,
+        369891, 1305821, 5533811, 1667676, 743981, 8231544, 5123191, 3384414,
+        5703977, 7097275, 3335715, 6926781, 4297589, 5713769, 7999321, 2880553,
+        2496460, 4996749, 2663724, 2184713, 2717045, 330118, 6317297, 8301019,
+        2510081, 6326906, 7470820, 5440440, 242265, 4713339, 5090410, 618835,
+        7654831, 7489827, 518527, 5833095, 3058734, 3553648, 3599970, 2118920,
+        182009, 2648657, 2672506, 6550312, 2388626, 4654534, 5777500, 2251862,
+        1721988, 2953440, 5304510, 655876, 1816637, 1952540, 5940035, 3088879,
+        1869252, 1661128, 8017850, 5915484, 7408043, 7421849, 7505949, 2507204,
+        1450868, 4996594, 2223167, 7220150, 5543700, 3879849, 1115673, 6823543,
+        6243983, 3385802, 5561118, 6600804, 1750818, 1788167, 1667451, 2762204,
+        2706191, 3814212, 5863902, 3308150, 4075480, 3254461, 7980470, 2939593,
+        5057198, 5152963, 3050327, 7774672, 4028967, 2130760, 3857675, 8146910,
+        585619, 5381309, 6575437, 1091711, 272356, 3934694, 4898533, 4509369,
+        2442787, 8249786, 8006624, 6866003, 7979077, 5178629, 2308072, 5197973,
+        5248583, 351731, 4737662, 4702438, 7891330, 2350229, 1293353, 7711663,
+        3120332, 1337394, 1625961, 2838644, 7348152, 7775285, 279752, 2249793,
+        4050665, 5804053, 751271, 8400434, 4522762, 7079584, 445844, 7723362,
+        7222547, 1291210, 5704529, 2994038, 5015691, 7350434, 820120, 3308383,
+        5916742, 3125716, 3733969, 565411, 1677622, 2421365, 462185, 5888279,
+        5741854, 1460627, 2840289, 291455, 7127083, 8061029, 5788420, 5859929,
+        7244359, 8045516, 4642573, 3248894, 4582291, 1956085, 1917302, 5322335,
+        3456052, 8169720, 537139, 5434163, 5090355, 4514526, 7855751, 5065509,
+        6452307, 4211387, 3877434, 5053593, 8272995, 4539885, 6674715, 1996652,
+        3925925, 7583598, 307623, 2076897, 1930272, 4319984, 4378036, 2204774,
+        7072679, 1658483, 1855602, 3454789, 3586812, 4823279, 4690584, 3865414,
+        1590476, 4702920, 6981620, 6639519, 1992876, 685851, 4372678, 282044,
+        1365911, 157524, 3025505, 1803814, 5619524, 2166116, 3002200, 2843438,
+        6291981, 185762, 483726, 968470, 1193235, 1356875, 2283077, 5979384,
+        7898173, 8354211, 4132292, 7349250, 4247182, 6402219, 6148479, 2291587,
+        140312, 5314435, 8241543, 2081803, 1637251, 7746585, 1942193, 7628416,
+        1383092, 3772288, 7680855, 6870609, 3496338, 5044662, 6969947, 5020137,
+        1512862, 3308341, 1157772, 8386869, 5310688, 4096436, 7874754, 6312822,
+        3962080, 7164500, 2992612, 5595916, 6563454, 1563513, 7388932, 6794626,
+        3269617, 6963475, 1802486, 1486345, 1197456, 3737502, 124677, 5586335,
+        7141242, 5057035, 4613538, 8237206, 6264363, 929464, 6392301, 5069456,
+        6788671, 4855771, 7407517, 2348220, 3358983, 4076171, 3687854, 1203412,
+        4733261, 553630, 5917576, 4874460, 1656702, 7978153, 1448344, 2989637,
+        4792174, 2079901, 2240082, 6447548, 6261559, 2709220, 637771, 1055381,
+        6481233, 3428811, 6828064, 1410258, 7758354, 364828, 5469370, 2618999,
+        5442471, 5616078, 7371291, 5198394, 1390772, 768076, 5181416, 767191,
+        5955428, 4829032, 6835205, 6325843, 2410216, 542924, 4715563, 1619388,
+        6674521, 8402550, 4009857, 6322884, 6864826, 1397225, 926883, 2795663,
+        3258226, 2791081, 1008394, 26146, 3845257, 5046024, 6069297, 249619,
+        2660552, 3898296, 6208551, 120686, 658825, 2511623, 3388904, 7697850,
+        4725190, 1911597, 1110005, 6991997, 6898909, 422827, 810385, 3636264,
+        2369793, 7411890, 7179944, 8224966, 1742730, 5267165, 3485439, 1782966,
+        1940330, 5717479, 3089924, 4091766, 1291531, 1674121, 7423669, 5800791,
+        3715897, 6268886, 628481, 2719462, 7970063, 588595, 642989, 668971,
+        1233813, 1847310, 3188252, 7338242, 2026470, 4853803, 3006831, 5982980,
+        3507385, 7145309, 5871052, 1167900, 4885754, 1457767, 4200810, 4002012,
+        3361544, 7894114, 7738690, 7426488, 7429074, 7298019, 2317284, 5849511,
+        2482952, 1928258, 6223751, 4681091, 4556084, 3159067, 4229025, 5900863,
+        508488, 3548270, 6317016, 7268385, 3699255, 3139318, 478464, 7833430,
+        4643515, 4377548, 2820710, 5152953, 7402753, 5419988, 2584559, 6426707,
+        5981725, 307644, 7022256, 882318, 4190480, 2921041, 7894907, 2513805,
+        4821759, 159644, 7424415, 3696649, 849279, 7569589, 7991564, 4614738,
+        7439691, 4707734, 5155900, 3761722, 4759464, 5288239, 3681574, 2084045,
+        4283038, 2252171, 8189868, 2268168, 1893902, 2393616, 7864299, 7972972,
+        1203290, 5106315, 3153004, 8308709, 5277916, 2680015, 6287425, 5487539,
+        2013603, 6354308, 4938809, 3620799, 6181358, 6673564, 3862763, 3214872,
+        1976439, 2138237, 2443208, 3186567, 5514086, 518931, 2784062, 8246999,
+        4568858, 7328913, 1956312, 5165381, 3679485, 3649776, 707318, 6275329,
+        3376145, 173272, 2399134, 6269985, 4201138, 4609144, 3653638, 8389120
+
+    };
+
+}
\ No newline at end of file
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/PolynomialProvablySecure.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/PolynomialProvablySecure.java
new file mode 100644
index 000000000..e0d8c1eef
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/PolynomialProvablySecure.java
@@ -0,0 +1,798 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+final class PolynomialProvablySecure
+{
+
+    /* Provably-Secure qTESLA Security Category-1 */
+
+    public static final long[] ZETA_I_P = {                    /* 1024-Entry */
+
+        152487987, 362708180, 151084668, 393585500, 285507339, 301982154, 215753424, 31155376,
+        233716852, 465705615, 128512487, 219324660, 50229578, 153034376, 215476824, 300536066,
+        335024578, 289187646, 164713195, 268061318, 189759369, 377168836, 116435874, 176113053,
+        431517196, 190900734, 338220498, 464878555, 173361289, 232250039, 454096337, 436656394,
+        195787662, 168565616, 114027909, 101482211, 122304260, 245339257, 270992315, 4286310,
+        284182633, 281862863, 467931137, 7603533, 87296419, 467325730, 121905925, 68965750,
+        7622021, 337743349, 393551614, 47124528, 159423746, 411556895, 272161997, 437233591,
+        145848369, 293644567, 483816172, 151632492, 404105953, 50166550, 146739314, 412145078,
+        15864543, 70750806, 129965017, 341088149, 316683907, 350635104, 130053135, 163148141,
+        121505175, 321911633, 208679484, 294431751, 453314132, 108343178, 347335911, 164705047,
+        162721550, 207020617, 292545544, 470584726, 172724538, 305647837, 149867383, 362637208,
+        452440748, 260522302, 286994319, 24740874, 202044444, 119470626, 478104674, 80911411,
+        414592412, 2221974, 246379318, 129955789, 28799678, 36003616, 152368173, 339611023,
+        223510693, 291221765, 193132933, 463217793, 331552134, 325636488, 203402489, 295759306,
+        248357734, 68229047, 81897305, 240159122, 118053748, 317468757, 422053445, 366729953,
+        437649988, 255661703, 483132783, 73941682, 473070031, 266941830, 273715645, 293305752,
+        97728261, 387416830, 466510576, 359483415, 350097663, 303812937, 61983368, 110765849,
+        174098312, 288799426, 21108638, 467492225, 174686783, 248408233, 45473451, 384747267,
+        405224388, 88952814, 320950556, 7845265, 96262921, 194785009, 345346400, 283984375,
+        141922183, 197095618, 350922677, 11272999, 89297173, 32109806, 274225692, 315879286,
+        447761615, 162801357, 472516440, 273754932, 433704551, 12277378, 129604129, 130765873,
+        341928374, 97220107, 381055612, 81197393, 281134974, 179347952, 39761035, 34072176,
+        156107747, 160521566, 445615052, 382999431, 114761104, 217307868, 361522659, 154828064,
+        108616610, 483961979, 7594235, 235284403, 243224032, 389934638, 100293270, 300649913,
+        252603238, 156952794, 476122165, 413580514, 276718826, 361292064, 361798877, 469444666,
+        478187612, 366087489, 58364362, 377641792, 464279854, 238407425, 414624898, 95101086,
+        321027398, 429694956, 464583265, 437187651, 60881585, 385486792, 312091683, 66834498,
+        233738788, 348037644, 233604363, 107253653, 131016429, 73947604, 169670982, 290195637,
+        119921194, 271135954, 190934119, 290478001, 458387655, 30555018, 243654544, 445824897,
+        428159318, 284210623, 380070942, 43667456, 346591135, 469657107, 229110312, 89859525,
+        279253247, 439931225, 229136222, 321034403, 246424219, 100693825, 214223676, 217294437,
+        256157960, 295265349, 79251464, 286824915, 454734790, 151846826, 92265815, 248302338,
+        324806913, 107169154, 198491413, 107136390, 135693521, 363861623, 129717151, 385117374,
+        341459776, 364530058, 331840615, 338653108, 179941421, 145194323, 232142444, 310117875,
+        245100240, 236651455, 321450096, 408132892, 459643284, 120999848, 331994388, 466033192,
+        444350281, 46244984, 349366459, 47312667, 210852290, 461907423, 473508756, 243941159,
+        334095768, 484392307, 87495054, 79707111, 10325325, 200821060, 83579595, 150963302,
+        117650353, 241599951, 324099496, 449053341, 36312493, 53120594, 297622605, 80558972,
+        378548649, 444726854, 381040843, 435710377, 437798831, 409728224, 337424109, 119488440,
+        361132895, 56096923, 105509808, 62508901, 220866000, 465933834, 134955292, 165152430,
+        461194453, 94958388, 126965781, 461323542, 383847206, 317476902, 163556720, 256017938,
+        72928042, 371345649, 72741296, 1132229, 282268470, 212115745, 379618538, 106905134,
+        239955357, 192105800, 279633365, 261297633, 471571564, 90968104, 459175544, 256276478,
+        349475049, 94611089, 471946846, 339973147, 179509745, 334215655, 348294589, 246487412,
+        338690430, 257410736, 386561992, 130193167, 10375815, 352823358, 66528931, 326800610,
+        5109748, 350056529, 248785466, 71808467, 91140754, 240803382, 46545554, 148468313,
+        217897756, 178220810, 477609665, 208790805, 132277867, 140742422, 254913327, 28667006,
+        128372915, 79301382, 407186666, 89552874, 246186501, 285455129, 391678316, 275180688,
+        128264018, 310322712, 204235493, 392483801, 82342680, 216812163, 464479351, 180360499,
+        444647478, 203271968, 245690827, 184373912, 109600517, 224566820, 28243984, 271488557,
+        21295878, 5023179, 37276402, 156173856, 216282463, 114627758, 400597776, 384792625,
+        105917732, 345779139, 120948814, 379908150, 352765486, 416168777, 56042296, 349589484,
+        144728793, 388255614, 261690821, 484844902, 12918385, 60552278, 302475143, 407425208,
+        184843522, 76793749, 43262192, 318572606, 192724017, 307990251, 164548393, 289980843,
+        119689917, 192248504, 86870040, 113677230, 207612114, 48663937, 453434248, 377339887,
+        132917063, 336896801, 106411814, 268777744, 109251604, 359574042, 467613823, 362251552,
+        400195434, 397227950, 447715984, 156476326, 407995653, 323955098, 143648649, 6572585,
+        61447842, 60823848, 132376333, 156552612, 447237682, 3352830, 437079412, 293474358,
+        288464703, 15328503, 138579659, 221291483, 380584037, 357161755, 205687364, 479414291,
+        173269786, 295661628, 1098184, 377981714, 433970464, 385767379, 200391723, 463310671,
+        470707303, 280545651, 289143978, 1390137, 320221838, 213802405, 52847233, 440579585,
+        361337171, 467447061, 278099177, 130391690, 112618414, 24013500, 144924227, 296806074,
+        251842387, 345992943, 284162718, 360902180, 420467337, 110656360, 350012131, 202820082,
+        130403434, 353559391, 97646151, 331494212, 207981153, 178821640, 6093504, 174655523,
+        25199097, 350851018, 171708038, 460816830, 103136904, 80524000, 275742304, 458552752,
+        472541551, 190172218, 362093141, 38733526, 9645818, 67304688, 67935446, 108377230,
+        311977539, 474309436, 444125532, 103441699, 3468252, 349723698, 97903160, 300076184,
+        267658035, 238838767, 242177661, 26606481, 135193080, 123327558, 344360834, 367595829,
+        356606282, 264791463, 257139528, 162368489, 211890949, 55564884, 438861649, 229441471,
+        237272101, 233185135, 277657399, 407149255, 91300697, 479685681, 430422637, 119519807,
+        421727840, 192635510, 93585631, 135381498, 18652441, 397908973, 188581729, 232327608,
+        69565403, 391762415, 326530182, 441347692, 230134217, 64984929, 478944650, 351581551,
+        190325639, 193670224, 149376075, 211003745, 282313407, 401282565, 142157967, 358980062,
+        420121767, 23490157, 334750456, 333888004, 267502025, 165819942, 232587558, 86202250,
+        302042598, 410443459, 257125477, 225677323, 414705770, 25685059, 301886182, 108044670,
+        22721383, 270234733, 79875762, 146613845, 419895311, 369960062, 103044731, 31676484,
+        286660070, 419993402, 364984450, 18133974, 446533052, 445715499, 406972835, 163019061,
+        450202465, 241240654, 188881609, 340298195, 253414624, 384263117, 228275432, 255596801,
+        10999354, 326104131, 470162945, 345212724, 481147036, 355238387, 445490028, 455415009,
+        260881193, 427862585, 132654052, 18007865, 59818933, 68142229, 461931681, 213097607,
+        330845761, 345671100, 445951421, 379951938, 351197187, 411141392, 7263182, 70699592,
+        365421264, 376472585, 461484665, 162243510, 31855741, 293625046, 335452299, 133496651,
+        449999480, 91675672, 274948339, 231546888, 5898807, 374453904, 415664585, 187816557,
+        366875998, 16795888, 358324214, 67223590, 208260807, 81751761, 331910299, 126163909,
+        197637544, 425142827, 380092754, 432163910, 455820426, 254980283, 256358636, 238549963,
+        394492520, 207988901, 382035000, 58514991, 406817321, 338951326, 85955701, 385883363,
+        199611595, 193846573, 242046917, 445871847, 194675932, 153430125, 126399473, 212399985,
+        131399120, 150281168, 241101682, 424624124, 463829369, 220399539, 250758923, 286498206,
+        389690457, 295269249, 379701698, 289778634, 337591505, 299401947, 408084588, 222627582,
+        436090373, 268654172, 96674628, 63939283, 63956567, 362372935, 443759942, 75655989,
+        451148002, 74813563, 245300859, 92113977, 235932323, 24871709, 445930061, 112311252,
+        382591591, 341672267, 192081751, 227249338, 104393113, 338268986, 206994950, 319724787,
+        213198392, 170478760, 37605185, 158287930, 411833228, 74675173, 290411522, 234950252,
+        147659191, 477676082, 302215477, 236037294, 396241956, 90037635, 71703941, 189694446,
+        127714437, 72581761, 388695298, 324058182, 307942478, 25250803, 430776557, 98441916,
+        244856801, 54851167, 334050668, 381066122, 91898087, 55879503, 447270860, 473167653,
+        219844498, 187193519, 266952433, 391729403, 53226126, 51780224, 371399487, 333787358,
+        56263300, 280390944, 162069765, 126088217, 254997184, 219544659, 290699753, 91930445,
+        262038894, 420981566, 460776098, 376255854, 282871085, 189434060, 447641051, 348987773,
+        393608679, 229566111, 403901447, 471446519, 411894730, 215726740, 484920069, 409829517,
+        306172231, 65880808, 272668213, 300554215, 165356547, 127919123, 432943738, 184462319,
+        474779995, 312870826, 103228518, 118983222, 470656522, 71417412, 480528917, 63072121,
+        276207594, 101611809, 92202812, 400978338, 316767039, 228776701, 96935521, 229917830,
+        205039402, 397476586, 344074695, 398615665, 107334948, 321477097, 84224896, 289704056,
+        337221600, 298175575, 221915312, 193369885, 426129039, 447853316, 54842415, 451086232,
+        182463979, 451831604, 247440983, 302608727, 173057620, 189163830, 406954853, 263838955,
+        390119120, 323062166, 209857219, 233847360, 397630721, 465926004, 10245195, 426687348,
+        106435173, 177694955, 463447907, 18002511, 30155910, 224512318, 357311179, 265219392,
+        299513685, 30291602, 60997329, 10326191, 138035293, 231111502, 414088384, 77026622,
+        174972782, 4116187, 52092276, 228872080, 15308807, 286405235, 414584533, 228392331,
+        399460999, 219125940, 337293712, 187192073, 183965759, 229399789, 51179285, 419512139,
+        28392143, 424986565, 69672656, 202415584, 216120556, 455470549, 76078626, 278191677,
+        228751917, 246802857, 389799018, 342470047, 313959017, 69383448, 340686475, 61470385,
+        26192776, 409901437, 119717553, 174793260, 123425866, 250300643, 429290586, 387248439,
+        183926914, 285901994, 391555377, 468207735, 22116415, 13034202, 399447558, 317569778,
+        269660832, 44359608, 57347786, 225367797, 253610604, 205790505, 20120029, 285335246,
+        351522795, 256987219, 358102627, 167191360, 50532216, 327731504, 369248325, 460123994,
+        266415358, 194297404, 175124754, 431803266, 172719791, 347394909, 478670700, 198769524,
+        172061925, 145181173, 153659180, 261113394, 234615141, 174150073, 188625016, 395363348,
+        356478592, 350375496, 185431871, 422914531, 144616554, 328948119, 417580486, 132620154,
+        208514724, 323125199, 169409944, 209437217, 147304756, 313577692, 467533131, 102365927,
+        353952516, 47854485, 378899191, 136952166, 46435149, 470355414, 328058320, 292689847,
+        24707084, 114822297, 272180086, 182640159, 7628028, 408073454, 377046674, 214221064,
+        472655903, 91461227, 453378209, 459785635, 126296748, 7369666, 52466342, 269961618,
+        231883972, 233439994, 228009066, 436059177, 355741338, 103186287, 391072528, 386169816,
+        317017329, 449528664, 378844336, 330396197, 137599363, 20911303, 288139426, 164788880,
+        266741184, 89618721, 54677577, 457226242, 208474107, 240521207, 158524358, 480614438,
+        226941889, 385643536, 326188597, 389903564, 264886102, 226747931, 258540220, 407142392
+
+    };
+
+    public static final long[] ZETA_INVERSE_I_P = {            /* 1024-Entry */
+
+        227437893, 259230182, 221092011, 96074549, 159789516, 100334577, 259036224, 5363675,
+        327453755, 245456906, 277504006, 28751871, 431300536, 396359392, 219236929, 321189233,
+        197838687, 465066810, 348378750, 155581916, 107133777, 36449449, 168960784, 99808297,
+        94905585, 382791826, 130236775, 49918936, 257969047, 252538119, 254094141, 216016495,
+        433511771, 478608447, 359681365, 26192478, 32599904, 394516886, 13322210, 271757049,
+        108931439, 77904659, 478350085, 303337954, 213798027, 371155816, 461271029, 193288266,
+        157919793, 15622699, 439542964, 349025947, 107078922, 438123628, 132025597, 383612186,
+        18444982, 172400421, 338673357, 276540896, 316568169, 162852914, 277463389, 353357959,
+        68397627, 157029994, 341361559, 63063582, 300546242, 135602617, 129499521, 90614765,
+        297353097, 311828040, 251362972, 224864719, 332318933, 340796940, 313916188, 287208589,
+        7307413, 138583204, 313258322, 54174847, 310853359, 291680709, 219562755, 25854119,
+        116729788, 158246609, 435445897, 318786753, 127875486, 228990894, 134455318, 200642867,
+        465858084, 280187608, 232367509, 260610316, 428630327, 441618505, 216317281, 168408335,
+        86530555, 472943911, 463861698, 17770378, 94422736, 200076119, 302051199, 98729674,
+        56687527, 235677470, 362552247, 311184853, 366260560, 76076676, 459785337, 424507728,
+        145291638, 416594665, 172019096, 143508066, 96179095, 239175256, 257226196, 207786436,
+        409899487, 30507564, 269857557, 283562529, 416305457, 60991548, 457585970, 66465974,
+        434798828, 256578324, 302012354, 298786040, 148684401, 266852173, 86517114, 257585782,
+        71393580, 199572878, 470669306, 257106033, 433885837, 481861926, 311005331, 408951491,
+        71889729, 254866611, 347942820, 475651922, 424980784, 455686511, 186464428, 220758721,
+        128666934, 261465795, 455822203, 467975602, 22530206, 308283158, 379542940, 59290765,
+        475732918, 20052109, 88347392, 252130753, 276120894, 162915947, 95858993, 222139158,
+        79023260, 296814283, 312920493, 183369386, 238537130, 34146509, 303514134, 34891881,
+        431135698, 38124797, 59849074, 292608228, 264062801, 187802538, 148756513, 196274057,
+        401753217, 164501016, 378643165, 87362448, 141903418, 88501527, 280938711, 256060283,
+        389042592, 257201412, 169211074, 84999775, 393775301, 384366304, 209770519, 422905992,
+        5449196, 414560701, 15321591, 366994891, 382749595, 173107287, 11198118, 301515794,
+        53034375, 358058990, 320621566, 185423898, 213309900, 420097305, 179805882, 76148596,
+        1058044, 270251373, 74083383, 14531594, 82076666, 256412002, 92369434, 136990340,
+        38337062, 296544053, 203107028, 109722259, 25202015, 64996547, 223939219, 394047668,
+        195278360, 266433454, 230980929, 359889896, 323908348, 205587169, 429714813, 152190755,
+        114578626, 434197889, 432751987, 94248710, 219025680, 298784594, 266133615, 12810460,
+        38707253, 430098610, 394080026, 104911991, 151927445, 431126946, 241121312, 387536197,
+        55201556, 460727310, 178035635, 161919931, 97282815, 413396352, 358263676, 296283667,
+        414274172, 395940478, 89736157, 249940819, 183762636, 8302031, 338318922, 251027861,
+        195566591, 411302940, 74144885, 327690183, 448372928, 315499353, 272779721, 166253326,
+        278983163, 147709127, 381585000, 258728775, 293896362, 144305846, 103386522, 373666861,
+        40048052, 461106404, 250045790, 393864136, 240677254, 411164550, 34830111, 410322124,
+        42218171, 123605178, 422021546, 422038830, 389303485, 217323941, 49887740, 263350531,
+        77893525, 186576166, 148386608, 196199479, 106276415, 190708864, 96287656, 199479907,
+        235219190, 265578574, 22148744, 61353989, 244876431, 335696945, 354578993, 273578128,
+        359578640, 332547988, 291302181, 40106266, 243931196, 292131540, 286366518, 100094750,
+        400022412, 147026787, 79160792, 427463122, 103943113, 277989212, 91485593, 247428150,
+        229619477, 230997830, 30157687, 53814203, 105885359, 60835286, 288340569, 359814204,
+        154067814, 404226352, 277717306, 418754523, 127653899, 469182225, 119102115, 298161556,
+        70313528, 111524209, 480079306, 254431225, 211029774, 394302441, 35978633, 352481462,
+        150525814, 192353067, 454122372, 323734603, 24493448, 109505528, 120556849, 415278521,
+        478714931, 74836721, 134780926, 106026175, 40026692, 140307013, 155132352, 272880506,
+        24046432, 417835884, 426159180, 467970248, 353324061, 58115528, 225096920, 30563104,
+        40488085, 130739726, 4831077, 140765389, 15815168, 159873982, 474978759, 230381312,
+        257702681, 101714996, 232563489, 145679918, 297096504, 244737459, 35775648, 322959052,
+        79005278, 40262614, 39445061, 467844139, 120993663, 65984711, 199318043, 454301629,
+        382933382, 116018051, 66082802, 339364268, 406102351, 215743380, 463256730, 377933443,
+        184091931, 460293054, 71272343, 260300790, 228852636, 75534654, 183935515, 399775863,
+        253390555, 320158171, 218476088, 152090109, 151227657, 462487956, 65856346, 126998051,
+        343820146, 84695548, 203664706, 274974368, 336602038, 292307889, 295652474, 134396562,
+        7033463, 420993184, 255843896, 44630421, 159447931, 94215698, 416412710, 253650505,
+        297396384, 88069140, 467325672, 350596615, 392392482, 293342603, 64250273, 366458306,
+        55555476, 6292432, 394677416, 78828858, 208320714, 252792978, 248706012, 256536642,
+        47116464, 430413229, 274087164, 323609624, 228838585, 221186650, 129371831, 118382284,
+        141617279, 362650555, 350785033, 459371632, 243800452, 247139346, 218320078, 185901929,
+        388074953, 136254415, 482509861, 382536414, 41852581, 11668677, 174000574, 377600883,
+        418042667, 418673425, 476332295, 447244587, 123884972, 295805895, 13436562, 27425361,
+        210235809, 405454113, 382841209, 25161283, 314270075, 135127095, 460779016, 311322590,
+        479884609, 307156473, 277996960, 154483901, 388331962, 132418722, 355574679, 283158031,
+        135965982, 375321753, 65510776, 125075933, 201815395, 139985170, 234135726, 189172039,
+        341053886, 461964613, 373359699, 355586423, 207878936, 18531052, 124640942, 45398528,
+        433130880, 272175708, 165756275, 484587976, 196834135, 205432462, 15270810, 22667442,
+        285586390, 100210734, 52007649, 107996399, 484879929, 190316485, 312708327, 6563822,
+        280290749, 128816358, 105394076, 264686630, 347398454, 470649610, 197513410, 192503755,
+        48898701, 482625283, 38740431, 329425501, 353601780, 425154265, 424530271, 479405528,
+        342329464, 162023015, 77982460, 329501787, 38262129, 88750163, 85782679, 123726561,
+        18364290, 126404071, 376726509, 217200369, 379566299, 149081312, 353061050, 108638226,
+        32543865, 437314176, 278365999, 372300883, 399108073, 293729609, 366288196, 195997270,
+        321429720, 177987862, 293254096, 167405507, 442715921, 409184364, 301134591, 78552905,
+        183502970, 425425835, 473059728, 1133211, 224287292, 97722499, 341249320, 136388629,
+        429935817, 69809336, 133212627, 106069963, 365029299, 140198974, 380060381, 101185488,
+        85380337, 371350355, 269695650, 329804257, 448701711, 480954934, 464682235, 214489556,
+        457734129, 261411293, 376377596, 301604201, 240287286, 282706145, 41330635, 305617614,
+        21498762, 269165950, 403635433, 93494312, 281742620, 175655401, 357714095, 210797425,
+        94299797, 200522984, 239791612, 396425239, 78791447, 406676731, 357605198, 457311107,
+        231064786, 345235691, 353700246, 277187308, 8368448, 307757303, 268080357, 337509800,
+        439432559, 245174731, 394837359, 414169646, 237192647, 135921584, 480868365, 159177503,
+        419449182, 133154755, 475602298, 355784946, 99416121, 228567377, 147287683, 239490701,
+        137683524, 151762458, 306468368, 146004966, 14031267, 391367024, 136503064, 229701635,
+        26802569, 395010009, 14406549, 224680480, 206344748, 293872313, 246022756, 379072979,
+        106359575, 273862368, 203709643, 484845884, 413236817, 114632464, 413050071, 229960175,
+        322421393, 168501211, 102130907, 24654571, 359012332, 391019725, 24783660, 320825683,
+        351022821, 20044279, 265112113, 423469212, 380468305, 429881190, 124845218, 366489673,
+        148554004, 76249889, 48179282, 50267736, 104937270, 41251259, 107429464, 405419141,
+        188355508, 432857519, 449665620, 36924772, 161878617, 244378162, 368327760, 335014811,
+        402398518, 285157053, 475652788, 406271002, 398483059, 1585806, 151882345, 242036954,
+        12469357, 24070690, 275125823, 438665446, 136611654, 439733129, 41627832, 19944921,
+        153983725, 364978265, 26334829, 77845221, 164528017, 249326658, 240877873, 175860238,
+        253835669, 340783790, 306036692, 147325005, 154137498, 121448055, 144518337, 100860739,
+        356260962, 122116490, 350284592, 378841723, 287486700, 378808959, 161171200, 237675775,
+        393712298, 334131287, 31243323, 199153198, 406726649, 190712764, 229820153, 268683676,
+        271754437, 385284288, 239553894, 164943710, 256841891, 46046888, 206724866, 396118588,
+        256867801, 16321006, 139386978, 442310657, 105907171, 201767490, 57818795, 40153216,
+        242323569, 455423095, 27590458, 195500112, 295043994, 214842159, 366056919, 195782476,
+        316307131, 412030509, 354961684, 378724460, 252373750, 137940469, 252239325, 419143615,
+        173886430, 100491321, 425096528, 48790462, 21394848, 56283157, 164950715, 390877027,
+        71353215, 247570688, 21698259, 108336321, 427613751, 119890624, 7790501, 16533447,
+        124179236, 124686049, 209259287, 72397599, 9855948, 329025319, 233374875, 185328200,
+        385684843, 96043475, 242754081, 250693710, 478383878, 2016134, 377361503, 331150049,
+        124455454, 268670245, 371217009, 102978682, 40363061, 325456547, 329870366, 451905937,
+        446217078, 306630161, 204843139, 404780720, 104922501, 388758006, 144049739, 355212240,
+        356373984, 473700735, 52273562, 212223181, 13461673, 323176756, 38216498, 170098827,
+        211752421, 453868307, 396680940, 474705114, 135055436, 288882495, 344055930, 201993738,
+        140631713, 291193104, 389715192, 478132848, 165027557, 397025299, 80753725, 101230846,
+        440504662, 237569880, 311291330, 18485888, 464869475, 197178687, 311879801, 375212264,
+        423994745, 182165176, 135880450, 126494698, 19467537, 98561283, 388249852, 192672361,
+        212262468, 219036283, 12908082, 412036431, 2845330, 230316410, 48328125, 119248160,
+        63924668, 168509356, 367924365, 245818991, 404080808, 417749066, 237620379, 190218807,
+        282575624, 160341625, 154425979, 22760320, 292845180, 194756348, 262467420, 146367090,
+        333609940, 449974497, 457178435, 356022324, 239598795, 483756139, 71385701, 405066702,
+        7873439, 366507487, 283933669, 461237239, 198983794, 225455811, 33537365, 123340905,
+        336110730, 180330276, 313253575, 15393387, 193432569, 278957496, 323256563, 321273066,
+        138642202, 377634935, 32663981, 191546362, 277298629, 164066480, 364472938, 322829972,
+        355924978, 135343009, 169294206, 144889964, 356013096, 415227307, 470113570, 73833035,
+        339238799, 435811563, 81872160, 334345621, 2161941, 192333546, 340129744, 48744522,
+        213816116, 74421218, 326554367, 438853585, 92426499, 148234764, 478356092, 417012363,
+        364072188, 18652383, 398681694, 478374580, 18046976, 204115250, 201795480, 481691803,
+        214985798, 240638856, 363673853, 384495902, 371950204, 317412497, 290190451, 49321719,
+        31881776, 253728074, 312616824, 21099558, 147757615, 295077379, 54460917, 309865060,
+        369542239, 108809277, 296218744, 217916795, 321264918, 196790467, 150953535, 185442047,
+        270501289, 332943737, 435748535, 266653453, 357465626, 20272498, 252261261, 454822737,
+        270224689, 183995959, 200470774, 92392613, 334893445, 123269933, 333490126, 78835721
+
+    };
+
+    /* Provably-Secure qTESLA Security Category-3 */
+
+    public static final long[] ZETA_III_P = {                /* 2048-Entry */
+
+        663045521, 592864312, 129934065, 177469925, 343322489, 76003277, 514174562, 190066344,
+        383213768, 787962888, 658937726, 1080673671, 1119184179, 711485619, 895353292, 741830559,
+        449748398, 882352834, 210564246, 513517678, 792274530, 1106148000, 447255681, 838374925,
+        817124617, 494866507, 801735296, 793510817, 270693858, 301435475, 260117255, 10836133,
+        1090140236, 870237322, 519619509, 74028645, 223438873, 115296996, 731671863, 711767285,
+        756344742, 432270821, 921367017, 743782190, 756600516, 403820997, 571909291, 809934428,
+        12306094, 1080752961, 1103853276, 848006190, 651623616, 1066528111, 991262313, 90376233,
+        1031639319, 16581402, 195692585, 764838834, 443651394, 397689573, 855192181, 464522040,
+        992536780, 1065244154, 280383996, 468397118, 363648899, 30284833, 136693103, 866826704,
+        684264872, 369300261, 147123393, 425272346, 947975751, 200848998, 207227922, 949139594,
+        347812886, 312530409, 270384680, 1035127685, 844540200, 354908220, 399963784, 771423554,
+        168982346, 111911899, 891254450, 606094727, 997954525, 531583148, 617069803, 183958096,
+        133356782, 708062096, 808380329, 644973028, 1122831312, 519547216, 764125907, 320659143,
+        557529771, 1016802360, 1043273438, 1045802164, 1034628659, 450715977, 741225144, 605149405,
+        1012579499, 651882116, 904529967, 300080999, 629210435, 173034527, 989077200, 1078174711,
+        110168090, 256388598, 610617659, 881033840, 608872901, 50037154, 640116890, 769511414,
+        738741272, 92678917, 442704510, 821794500, 142894162, 370261366, 899737750, 578322223,
+        983445865, 278101088, 320548969, 960437988, 847057645, 535264585, 1031091774, 384531787,
+        839679409, 791760948, 937608754, 64047905, 315242491, 690211684, 304945377, 127139900,
+        55322681, 615105519, 1057531084, 720717234, 1061452791, 1095429367, 975341664, 483335114,
+        346985754, 486624908, 954236263, 606609353, 374493515, 1026296717, 325660087, 901013385,
+        53959974, 212660347, 959289131, 1056916487, 1125908681, 840084518, 527647955, 143827226,
+        1054554933, 861883427, 114992875, 332264810, 1071780030, 502142509, 205074888, 328230624,
+        728399298, 6590787, 412294778, 821072942, 186833297, 86543585, 380686974, 684478338,
+        685483832, 170880254, 1049509911, 299404976, 355091877, 952129776, 345588044, 357652764,
+        1076734604, 924340986, 262332782, 562093746, 674846863, 869200402, 167429450, 230595565,
+        379519977, 64054402, 667864494, 252591944, 174034622, 45520823, 784274107, 752467928,
+        436711302, 1004905853, 329220738, 721523796, 169192713, 551217408, 907929323, 194805106,
+        62131815, 68055725, 545662009, 726339771, 10612113, 878659984, 675814719, 365783377,
+        951164276, 866711073, 684096262, 413270603, 702997992, 778608769, 127639044, 47216120,
+        744109445, 430463358, 1117777586, 424051168, 656374939, 1103725866, 14621181, 919164722,
+        915751418, 976196867, 260519617, 802701264, 977088018, 632721351, 20944803, 435584923,
+        672284530, 530447301, 1080372403, 969633414, 858453527, 467086140, 377506201, 201043187,
+        624606245, 356437339, 392100995, 997346375, 344147086, 1086111956, 718030456, 110621087,
+        452912731, 336746546, 621211472, 795046, 794852591, 919732385, 714562897, 692647493,
+        521856561, 892141810, 929164476, 178245765, 949027329, 511109867, 501815810, 855826969,
+        240246307, 1090455392, 871247558, 612287417, 200668298, 658636844, 62944986, 482777398,
+        714192478, 867140496, 199314763, 780516102, 571032048, 817693014, 607138429, 912533516,
+        774019587, 835671643, 168024255, 449898784, 964159534, 486792883, 1119449268, 6657041,
+        86939725, 764245347, 273343215, 777897095, 930426166, 788914763, 469974947, 178163195,
+        519599146, 886003889, 859825363, 1024222142, 888997684, 402918616, 146815556, 742952999,
+        908078470, 687435577, 647696655, 693593765, 766931890, 944985585, 394729082, 816013317,
+        392951623, 65907852, 96202750, 645391372, 795224730, 402710723, 863608137, 818970673,
+        545310222, 970699745, 913314065, 344644471, 195858177, 414360679, 357670948, 683445481,
+        833938949, 1027656845, 191164920, 78809923, 1041045426, 73270196, 101525688, 185383095,
+        583325181, 265134328, 467801210, 1096264575, 367433146, 474798672, 41386419, 8344607,
+        170218721, 635545135, 668716283, 348890991, 155290659, 123249926, 769501318, 244415064,
+        1050203259, 859568787, 237251392, 995643980, 522636185, 829867059, 324850649, 618298124,
+        650748178, 467147593, 524674833, 341426504, 402629779, 519829789, 805279247, 494226863,
+        508315225, 319600904, 48615828, 165396124, 328305874, 183239019, 878118280, 161754975,
+        715041085, 746274821, 961841131, 357826469, 97008202, 885304034, 352059292, 197879468,
+        25678065, 1028070136, 447949253, 962673193, 813464159, 17237594, 674670906, 959137288,
+        10286769, 182827874, 439769615, 875041932, 304463252, 374894049, 749497333, 38938778,
+        95615605, 323023572, 918611876, 207681758, 859164726, 97118122, 769881035, 360249017,
+        507250246, 223795463, 24153203, 927058118, 178686381, 765072252, 491103160, 30816153,
+        100214484, 554568910, 715304135, 93510037, 1021905527, 1045723816, 900771572, 1011589617,
+        558930760, 228903927, 41675196, 857737037, 1092385029, 1067405169, 526576034, 25638952,
+        1017160549, 1052660585, 364103167, 228705333, 566586884, 1126549926, 148651837, 217709216,
+        614537001, 773273483, 1097591846, 480172084, 365704498, 262321659, 937989155, 1036392392,
+        811974084, 132591218, 799370207, 255702709, 215218285, 632314426, 58376649, 483086198,
+        401012915, 839724879, 70449719, 502867571, 757507513, 1073691794, 215293647, 725537396,
+        398067214, 584143318, 392011063, 554158763, 730533625, 632408477, 259767996, 1124249847,
+        432958856, 1026767843, 237644370, 29926518, 131813155, 898001983, 581765490, 215126607,
+        937229093, 1030360940, 452462053, 645808548, 645402879, 379809569, 577012489, 1082786079,
+        572510912, 475330285, 152788398, 690858296, 876393456, 1002942486, 67723832, 132689262,
+        1030380537, 529311082, 41121650, 626066149, 866026053, 240011600, 574505003, 565608154,
+        414049009, 123706126, 80739723, 326160835, 476194893, 1126100881, 646887456, 987296393,
+        1119394953, 994979769, 133560363, 725327130, 850262599, 132796686, 1114247361, 1040894619,
+        562914322, 641645573, 817070125, 57537779, 59054681, 878878988, 307674440, 1001013577,
+        594860688, 879718195, 318482613, 698792051, 756144110, 204900318, 1031928100, 926221256,
+        695955308, 662601363, 408725276, 424272249, 110402404, 535365123, 226700293, 372920839,
+        1118626221, 1070521569, 639548808, 621533107, 260391977, 316354318, 362523650, 733090366,
+        456807669, 113808372, 399369653, 647539514, 165899708, 312376469, 213806296, 208149196,
+        937880087, 289692684, 580756218, 963782721, 1086045881, 705999228, 1115084349, 508210869,
+        893248141, 1109740411, 338975294, 752813515, 622466015, 372202503, 55041759, 338412385,
+        29530795, 689413481, 974303137, 605274799, 812143197, 121492617, 758223932, 200993249,
+        575018581, 1039577172, 1090395670, 612284976, 414561447, 886969, 685649488, 667914411,
+        183143190, 272811635, 104938162, 64626548, 404300448, 333824065, 399917080, 105374124,
+        329534966, 930231830, 187994078, 772453163, 81595362, 135380677, 536704334, 787124497,
+        554875178, 60344266, 790999625, 581578940, 72453408, 872892444, 204321645, 885844343,
+        942736233, 12824064, 23018086, 996569940, 818486394, 1484060, 349940348, 981882207,
+        855621323, 1034617940, 565456643, 745822751, 68273335, 578729865, 170455086, 173683666,
+        375983003, 128070235, 982298151, 650454518, 218561113, 1063878953, 541912322, 695738038,
+        232263685, 671557037, 584280432, 126161631, 394804150, 149748923, 670383088, 150214459,
+        409907258, 730673023, 452696559, 556617060, 271416278, 398913344, 793695740, 603610724,
+        620753264, 760650912, 867673149, 32169440, 106515963, 802984660, 859117007, 854436840,
+        736728629, 789197380, 1065424969, 689713946, 980964818, 605711034, 1105012640, 552261321,
+        980118632, 868407647, 247404352, 182421983, 1076188005, 324001412, 258504546, 973008126,
+        458306267, 216381363, 1099063604, 172774993, 897006405, 662034826, 827348922, 213283635,
+        712936407, 586286121, 133326382, 771279651, 77080161, 692598228, 272139235, 156805228,
+        184634865, 216660729, 331306952, 180435518, 1098019508, 642364354, 759605128, 444205747,
+        818119290, 697748488, 779633860, 1123069299, 628905992, 1093632915, 363341708, 896455329,
+        653929021, 348858884, 483831705, 248783457, 50018777, 527261991, 1108955766, 683741144,
+        838366046, 1040212608, 956504693, 441862460, 181267978, 415765896, 551409278, 866054366,
+        855141207, 141967451, 462022373, 903388714, 5583486, 624006881, 1027131584, 127103419,
+        227496735, 876597209, 1075725589, 13097576, 275925041, 46896293, 1047922947, 480370214,
+        979242782, 304620097, 88645237, 157252101, 1080960020, 1019514352, 910182857, 344499049,
+        841029348, 586201316, 561562804, 877577189, 774682172, 420802584, 243335866, 818233882,
+        1102088786, 910997938, 394459347, 114606856, 959148981, 304978043, 15246639, 410347623,
+        819777499, 304889937, 196333903, 294201539, 742724283, 136229739, 1095082129, 710673795,
+        303958022, 730529672, 330937766, 290549001, 975944911, 1012630530, 940739802, 428357654,
+        876150675, 270868991, 605451019, 692162505, 164423625, 414486664, 567335281, 60501334,
+        301815246, 988181982, 749960008, 971794624, 1044979874, 846257184, 944403720, 1028849636,
+        20676966, 402436874, 1038249855, 636703483, 52612884, 457266419, 404964279, 764097082,
+        73543501, 850137726, 543909567, 478253061, 341753973, 145701153, 816141937, 150699764,
+        1012159718, 996158125, 874816245, 140152812, 1046568846, 731360631, 165696325, 923351799,
+        373705673, 295885033, 571437494, 323580072, 535312031, 261690954, 128330254, 678037418,
+        730169337, 800223155, 493938662, 1035925088, 1086213401, 1029948847, 703929623, 1067237691,
+        203498545, 260171642, 489884813, 595714326, 717921496, 379455421, 739695761, 991791615,
+        1101866478, 768413486, 248059075, 641256446, 252045193, 383431807, 1098526663, 655518597,
+        868514850, 975851412, 607928997, 1015436331, 219860723, 248644475, 1100013490, 1059262194,
+        616750819, 706912112, 186194896, 371412253, 932777950, 605371544, 32806481, 41915372,
+        942949174, 657520226, 337575994, 767026353, 795340494, 602216057, 1051603235, 38167611,
+        383256063, 961974657, 643676937, 850900578, 1033468109, 791020067, 602254362, 742154500,
+        5280825, 557072845, 260014823, 274231000, 957875719, 620840911, 468091423, 844999033,
+        1097180885, 635575570, 741694428, 564249983, 1015743243, 179096376, 326642449, 737067396,
+        404230544, 164870855, 233971733, 25568965, 480191729, 304346683, 43284571, 600295394,
+        805273167, 1081440213, 132076275, 660273218, 115344223, 436181422, 581442439, 521590088,
+        278258022, 1016124223, 326820478, 833856285, 578613123, 981790341, 912622887, 677878660,
+        983305736, 582146018, 50261960, 421861087, 688852042, 1053015424, 638857404, 13988561,
+        613374169, 246804474, 354822706, 755945338, 48594230, 1112837032, 490266853, 331336539,
+        573470525, 482415512, 1066189384, 480749813, 340470541, 1087888528, 866254054, 328905420,
+        282987588, 772186429, 280721545, 827109021, 1065603359, 319039186, 632282960, 368180744,
+        103743324, 1039700039, 944775691, 35416271, 876336840, 387995308, 744351857, 1024873450,
+        846245765, 488549456, 793960147, 360822038, 1047746824, 70006457, 1081240530, 845224049,
+        158270603, 1040065115, 109153922, 842769347, 357450022, 745529551, 127101430, 1013053569,
+        653900906, 1066692138, 1026185333, 40127076, 888550251, 1074046165, 859190733, 172044729,
+        232991700, 856026028, 181368869, 11312168, 965826001, 718641942, 140897415, 300107020,
+        760832029, 454871649, 538869148, 209839945, 603404196, 1070516093, 362685617, 594598150,
+        706680144, 248566695, 624350428, 687354425, 108825926, 996763990, 768570600, 192652503,
+        1030980703, 285993613, 678456384, 666912839, 636939881, 724986064, 567331335, 1109690969,
+        786490830, 1041275289, 13569330, 310803565, 1018122073, 236560398, 625689685, 227532759,
+        773302523, 275485190, 151580837, 1097590370, 43338286, 709601963, 530263051, 696952520,
+        591327015, 779208675, 900380693, 779322099, 365008051, 816626432, 9177437, 715814813,
+        951132001, 978726879, 539618044, 330049876, 794850808, 75659606, 535871088, 1117571277,
+        1035668574, 737539534, 638053030, 1067376479, 817653745, 608323193, 952285144, 489088626,
+        643974231, 1100308604, 80188084, 1009055308, 528621558, 845717932, 574893980, 185963698,
+        304405106, 254075674, 885653667, 125272317, 310803515, 431578311, 49069840, 734649900,
+        64565269, 68004786, 877673289, 927546004, 379372125, 179774076, 313581255, 48547291,
+        669540902, 805507558, 458763285, 808407028, 467495228, 200042934, 286655832, 204624339,
+        1076184783, 580415818, 422842319, 130214533, 1019327141, 196299734, 544501682, 1039357725,
+        139924087, 1079672537, 517801387, 1103773407, 832398676, 971715180, 249998343, 17982966,
+        226812113, 1056456541, 429118671, 1115368643, 731996995, 114969826, 90081103, 503306049,
+        601600644, 221645888, 419902454, 366845662, 668188540, 595203705, 289744999, 311876332,
+        708499030, 814702169, 1038171811, 305413430, 1025269191, 401153805, 524933941, 244137773,
+        690611117, 1006016675, 368084114, 695256047, 400388115, 315582560, 240063473, 316625045,
+        193016450, 444532677, 490320790, 1007751505, 809310640, 335632874, 932973140, 879894932,
+        664689650, 582802605, 524248338, 381467584, 15568620, 102853205, 344510143, 244997234,
+        228087680, 804700227, 33671368, 202173391, 810352194, 941527027, 107007723, 250295846,
+        439491161, 385750316, 881611329, 305721499, 489662560, 253590441, 574217985, 187749275,
+        767834897, 577560416, 666585061, 536277466, 31104595, 459368906, 738728273, 395846485,
+        915511988, 152055976, 123475832, 434555954, 708682317, 873350950, 733405860, 594180445,
+        508539260, 411702537, 525230789, 245498406, 807139759, 421829267, 576175978, 671688378,
+        586113326, 717964200, 549178465, 340455344, 177498005, 185915353, 758077402, 35174925,
+        62477885, 432126554, 865525725, 94991243, 953163796, 64489669, 63466463, 1027121609,
+        603180773, 102927367, 328204523, 849484682, 1106252192, 166218129, 336284946, 115841434,
+        394987097, 1071354740, 1124188058, 756569276, 1109657140, 693362574, 582653179, 356054504,
+        10684879, 43556307, 683161419, 43248060, 311516690, 801263962, 259313122, 1076460000,
+        627348913, 723691023, 1029014449, 1100617454, 910402911, 804049172, 439314326, 277694586,
+        89508968, 45373766, 191679221, 573131182, 602365665, 620254956, 594424107, 763083130,
+        984103431, 746523686, 419387264, 1030279302, 774892955, 242854266, 102748733, 633218020,
+        205014651, 835462852, 458575555, 34062189, 765679808, 999547926, 509921953, 785947219,
+        966902522, 639941920, 244960006, 581685840, 1052422889, 674992133, 61665140, 451012255,
+        122965849, 190085617, 748838858, 349331162, 529980624, 16193587, 34516478, 42504381,
+        160246364, 173535194, 187379517, 111011381, 365394663, 102220644, 699473271, 366177836,
+        81692890, 659930501, 36322222, 896361190, 473670263, 1039987458, 412734344, 864218684,
+        138309539, 146538307, 1101721292, 898028054, 727055521, 601140835, 577133426, 451632863,
+        725601236, 388561051, 696130927, 299179408, 194132814, 104549843, 919472671, 900644523,
+        848766532, 557407329, 506005527, 529295823, 637231568, 840578154, 40752048, 1043021730,
+        940132528, 1635875, 390473136, 36409813, 938731454, 1005273567, 169556667, 456362115,
+        968015234, 385125443, 1033592386, 622268544, 824710397, 811874465, 1126356395, 1030647864,
+        1027801728, 1032615842, 990780079, 340414618, 431920306, 797512392, 36624143, 1039964580,
+        78368304, 725419125, 1031876274, 545277986, 400681087, 824700406, 916868477, 979226643,
+        327065594, 666022464, 692190875, 241031536, 486380927, 271722557, 903843361, 141586809,
+        747887461, 634534510, 613428929, 35052951, 519999706, 907994356, 122720932, 47771789,
+        111045658, 101409844, 478385667, 160271513, 709331396, 407803014, 233222181, 446853856,
+        325464420, 902760210, 272094082, 341360162, 749117421, 560701701, 963877946, 787641615,
+        205947725, 590645393, 232274153, 623635766, 912309623, 1120569701, 620395638, 104547179,
+        326785462, 462547537, 940416330, 25839620, 19867751, 37744827, 852776583, 515439522,
+        254321646, 368159144, 977334258, 457474804, 545693728, 590432747, 485742318, 929078943,
+        737942351, 275516935, 808617222, 720700675, 172457394, 549776288, 773237950, 425343903,
+        106571968, 735846275, 60428193, 122914286, 749764808, 987165321, 38777778, 78068884,
+        255797430, 533180457, 948660956, 48180746, 1126178511, 529625145, 556629751, 638195644,
+        832146389, 336969603, 525037491, 33022927, 179961503, 1111138669, 8606225, 744603862,
+        831709431, 936738778, 976276214, 628380488, 186998645, 1058798754, 681993880, 653924606,
+        946881757, 648359538, 739466740, 91286181, 294298084, 874448181, 197552840, 1095208028,
+        1044083721, 391228026, 525623627, 1098872860, 195023028, 787479821, 623295468, 953049875,
+        598245883, 53206653, 107774100, 1118437046, 444804586, 736921099, 245341091, 386750976,
+        133313309, 679691423, 1106023536, 311728621, 298633293, 401684808, 243635798, 110079800,
+        995741344, 323549381, 934619946, 561564543, 318482785, 437414717, 954436048, 120567824,
+        939556676, 96791826, 457592630, 938550164, 338458435, 235369986, 520146590, 367137669,
+        215447981, 816673608, 388257556, 367337840, 505745620, 16797457, 625598745, 670629880,
+        254936589, 910270385, 42251434, 163010455, 35446687, 313308255, 882198755, 1020005685,
+        629715947, 45305629, 160442570, 751826615, 839359276, 665790727, 1126866480, 206409968,
+        243347643, 601811321, 987009162, 748255207, 204576339, 60528047, 215906665, 956509919,
+        298034351, 23754044, 490568798, 458549410, 38365707, 66017494, 289322020, 23546127,
+        1110422453, 430589196, 451259509, 452129088, 246026906, 479959331, 657705765, 154141097,
+        545145366, 756619911, 1056054068, 305614614, 982437349, 733683110, 356219317, 138617825,
+        1077109241, 367006768, 107952142, 792745355, 1101149620, 190430549, 642564451, 1027811321,
+        529836063, 856677079, 136144741, 193585315, 759745460, 929992250, 670307004, 1127656802,
+        1006741766, 845736365, 936834519, 1017230852, 281391123, 580173947, 30327752, 1121201269,
+        1055919747, 182909919, 160816233, 602222114, 380162230, 868238592, 238843489, 626593576,
+        827265325, 474165116, 237320246, 663594943, 436318864, 1049025048, 70720879, 971089740,
+        88817691, 635640003, 121885571, 243941023, 2431313, 941718254, 799204753, 612476838,
+        941429841, 218425031, 62583588, 843195067, 826107237, 360474616, 699278259, 879607149,
+        103065937, 68048433, 88684453, 368247280, 352557675, 958077844, 188716852, 142753212,
+        187289952, 1075600752, 538047877, 79021856, 72991411, 855788038, 872392901, 230685283,
+        684292160, 1006193052, 389933214, 858196548, 879451470, 275454910, 233947442, 798039506,
+        522351014, 1028810225, 973496946, 459028464, 716757179, 299354781, 303032004, 378782749,
+        726394798, 822245773, 1112315820, 572181708, 792445736, 354854796, 391571531, 1120313604,
+        948219264, 683224878, 109721560, 210780537, 877361416, 837335205, 829228039, 710692263,
+        336548681, 1113948080, 500533488, 561629043, 1004877220, 538880595, 121199664, 933983782,
+        1012189335, 466644222, 948695748, 1030237630, 409196123, 831874921, 209931563, 472212875,
+        667493959, 374083498, 121993645, 135468879, 743372774, 445381601, 1056162737, 535313411,
+        731504361, 106330271, 449811720, 1025526021, 538706550, 384586636, 672759140, 214035474,
+        1061388936, 1083928033, 581161697, 343521559, 467089784, 918062822, 197840310, 276992034,
+        267922106, 626045501, 689381922, 1031751565, 453082931, 703374420, 543907459, 1101013667,
+        158907990, 531648771, 96624556, 1107736421, 653786417, 1020275778, 1100295652, 1080331394,
+        934499233, 1103133235, 665774139, 760309263, 583529543, 927074230, 109488746, 759686422,
+        658349346, 1121943871, 528665116, 800822916, 210288486, 526666123, 265162098, 797138998,
+        225170105, 773601444, 1074231036, 358050025, 792486275, 559918288, 931510368, 283561253,
+        929909084, 643871325, 165045098, 236482168, 27010690, 947252425, 762156229, 403915775,
+        226420583, 111771291, 457403715, 390913388, 417791477, 1051596236, 218412938, 231310973,
+        913814997, 1010678562, 1061436357, 402561769, 46161499, 194906871, 1106996555, 1044025883,
+        84769121, 958130074, 458164325, 75716319, 742943036, 662710618, 1015724782, 541305935,
+        887985887, 374173602, 667853276, 1118405527, 888897413, 806335907, 483810195, 94681964,
+        932049061, 419630532, 863884216, 258267823, 871542447, 748276380, 1089602035, 956286084,
+        452661681, 297101315, 292838603, 602202013, 59322052, 868600049, 695946675, 1119453722,
+        369279180, 571163895, 1076824823, 613633165, 1105924843, 970753160, 38059756, 230436803,
+        993075206, 825136859, 772252886, 665426090, 252341082, 81169114, 15411109, 1109435384,
+        169742336, 879343295, 637603710, 1050610062, 543393828, 360888011, 622980636, 538625088,
+        384365656, 954674344, 672395534, 822045489, 271453575, 379517678, 745140555, 64423305,
+        132805764, 730783710, 818513567, 1062263522, 633828399, 609441394, 952235218, 443525262,
+        408766329, 154648340, 321016488, 39971097, 975003097, 115001826, 929799112, 1079586908,
+        630403891, 883673758, 1017692831, 982184607, 1052333730, 732655912, 673402471, 144580658,
+        776541469, 599807837, 897876410, 750409126, 408883399, 800706291, 525848844, 1043397101,
+        546417436, 927622216, 923472422, 126273770, 976796416, 301390002, 640312848, 64953087,
+        850801014, 80099312, 344764299, 166353727, 304339056, 563820482, 620610256, 95176064,
+        436429135, 450761768, 1080607344, 554114394, 1051016002, 1094965858, 1044316801, 90082309,
+        802170370, 785939405, 96092255, 481999812, 399399466, 798786453, 1069910963, 1075397160,
+        645632403, 721614722, 81169724, 16732546, 256145620, 1032181185, 858152279, 261506136,
+        939613769, 1109259166, 1072545109, 893701664, 1076290454, 94376212, 1129486743, 496007349,
+        461211004, 215869774, 903345586, 185658758, 769007243, 973105742, 843449005, 531620573,
+        115498344, 118893063, 1080559132, 289993254, 729094212, 100228973, 970141524, 88018590,
+        401752692, 490667846, 120206196, 1053373040, 927137503, 109156130, 1099960359, 852051778,
+        542020710, 890761046, 935484975, 503476669, 247175418, 137646228, 122463313, 1098625172,
+        313612773, 1045687932, 942418016, 223296002, 613265129, 618070459, 210263615, 258537008,
+        687201993, 1069972265, 1092070505, 209044958, 705866604, 959480062, 37107231, 530334549,
+        940857114, 888162459, 550603427, 833686010, 914377969, 777858517, 823074720, 257780639,
+        682005406, 79684712, 1108405948, 546085914, 695245394, 296369184, 90008780, 876596576,
+        1060844810, 971909901, 180162302, 155422312, 913147941, 572392352, 172449506, 707256652,
+        379461286, 396142844, 341990080, 626969834, 156354367, 614031487, 682424885, 1092771510,
+        881893810, 1087158911, 85380176, 1044830162, 986021749, 619772632, 829678380, 1095084953,
+        726141659, 941134286, 949047185, 1013348374, 17076281, 979953556, 730262704, 692286875,
+        723405610, 879517616, 639675138, 319980056, 711102461, 564387868, 1089317723, 659400607,
+        372246588, 1035423048, 766956675, 186444638, 504211183, 871579167, 64189114, 905789437
+
+    };
+
+    public static final long[] ZETA_INVERSE_III_P = {        /* 2048-Entry */
+
+        1065536839, 258146786, 625514770, 943281315, 362769278, 94302905, 757479365, 470325346,
+        40408230, 565338085, 418623492, 809745897, 490050815, 250208337, 406320343, 437439078,
+        399463249, 149772397, 1112649672, 116377579, 180678768, 188591667, 403584294, 34641000,
+        300047573, 509953321, 143704204, 84895791, 1044345777, 42567042, 247832143, 36954443,
+        447301068, 515694466, 973371586, 502756119, 787735873, 733583109, 750264667, 422469301,
+        957276447, 557333601, 216578012, 974303641, 949563651, 157816052, 68881143, 253129377,
+        1039717173, 833356769, 434480559, 583640039, 21320005, 1050041241, 447720547, 871945314,
+        306651233, 351867436, 215347984, 296039943, 579122526, 241563494, 188868839, 599391404,
+        1092618722, 170245891, 423859349, 920680995, 37655448, 59753688, 442523960, 871188945,
+        919462338, 511655494, 516460824, 906429951, 187307937, 84038021, 816113180, 31100781,
+        1007262640, 992079725, 882550535, 626249284, 194240978, 238964907, 587705243, 277674175,
+        29765594, 1020569823, 202588450, 76352913, 1009519757, 639058107, 727973261, 1041707363,
+        159584429, 1029496980, 400631741, 839732699, 49166821, 1010832890, 1014227609, 598105380,
+        286276948, 156620211, 360718710, 944067195, 226380367, 913856179, 668514949, 633718604,
+        239210, 1035349741, 53435499, 236024289, 57180844, 20466787, 190112184, 868219817,
+        271573674, 97544768, 873580333, 1112993407, 1048556229, 408111231, 484093550, 54328793,
+        59814990, 330939500, 730326487, 647726141, 1033633698, 343786548, 327555583, 1039643644,
+        85409152, 34760095, 78709951, 575611559, 49118609, 678964185, 693296818, 1034549889,
+        509115697, 565905471, 825386897, 963372226, 784961654, 1049626641, 278924939, 1064772866,
+        489413105, 828335951, 152929537, 1003452183, 206253531, 202103737, 583308517, 86328852,
+        603877109, 329019662, 720842554, 379316827, 231849543, 529918116, 353184484, 985145295,
+        456323482, 397070041, 77392223, 147541346, 112033122, 246052195, 499322062, 50139045,
+        199926841, 1014724127, 154722856, 1089754856, 808709465, 975077613, 720959624, 686200691,
+        177490735, 520284559, 495897554, 67462431, 311212386, 398942243, 996920189, 1065302648,
+        384585398, 750208275, 858272378, 307680464, 457330419, 175051609, 745360297, 591100865,
+        506745317, 768837942, 586332125, 79115891, 492122243, 250382658, 959983617, 20290569,
+        1114314844, 1048556839, 877384871, 464299863, 357473067, 304589094, 136650747, 899289150,
+        1091666197, 158972793, 23801110, 516092788, 52901130, 558562058, 760446773, 10272231,
+        433779278, 261125904, 1070403901, 527523940, 836887350, 832624638, 677064272, 173439869,
+        40123918, 381449573, 258183506, 871458130, 265841737, 710095421, 197676892, 1035043989,
+        645915758, 323390046, 240828540, 11320426, 461872677, 755552351, 241740066, 588420018,
+        114001171, 467015335, 386782917, 1054009634, 671561628, 171595879, 1044956832, 85700070,
+        22729398, 934819082, 1083564454, 727164184, 68289596, 119047391, 215910956, 898414980,
+        911313015, 78129717, 711934476, 738812565, 672322238, 1017954662, 903305370, 725810178,
+        367569724, 182473528, 1102715263, 893243785, 964680855, 485854628, 199816869, 846164700,
+        198215585, 569807665, 337239678, 771675928, 55494917, 356124509, 904555848, 332586955,
+        864563855, 603059830, 919437467, 328903037, 601060837, 7782082, 471376607, 370039531,
+        1020237207, 202651723, 546196410, 369416690, 463951814, 26592718, 195226720, 49394559,
+        29430301, 109450175, 475939536, 21989532, 1033101397, 598077182, 970817963, 28712286,
+        585818494, 426351533, 676643022, 97974388, 440344031, 503680452, 861803847, 852733919,
+        931885643, 211663131, 662636169, 786204394, 548564256, 45797920, 68337017, 915690479,
+        456966813, 745139317, 591019403, 104199932, 679914233, 1023395682, 398221592, 594412542,
+        73563216, 684344352, 386353179, 994257074, 1007732308, 755642455, 462231994, 657513078,
+        919794390, 297851032, 720529830, 99488323, 181030205, 663081731, 117536618, 195742171,
+        1008526289, 590845358, 124848733, 568096910, 629192465, 15777873, 793177272, 419033690,
+        300497914, 292390748, 252364537, 918945416, 1020004393, 446501075, 181506689, 9412349,
+        738154422, 774871157, 337280217, 557544245, 17410133, 307480180, 403331155, 750943204,
+        826693949, 830371172, 412968774, 670697489, 156229007, 100915728, 607374939, 331686447,
+        895778511, 854271043, 250274483, 271529405, 739792739, 123532901, 445433793, 899040670,
+        257333052, 273937915, 1056734542, 1050704097, 591678076, 54125201, 942436001, 986972741,
+        941009101, 171648109, 777168278, 761478673, 1041041500, 1061677520, 1026660016, 250118804,
+        430447694, 769251337, 303618716, 286530886, 1067142365, 911300922, 188296112, 517249115,
+        330521200, 188007699, 1127294640, 885784930, 1007840382, 494085950, 1040908262, 158636213,
+        1059005074, 80700905, 693407089, 466131010, 892405707, 655560837, 302460628, 503132377,
+        890882464, 261487361, 749563723, 527503839, 968909720, 946816034, 73806206, 8524684,
+        1099398201, 549552006, 848334830, 112495101, 192891434, 283989588, 122984187, 2069151,
+        459418949, 199733703, 369980493, 936140638, 993581212, 273048874, 599889890, 101914632,
+        487161502, 939295404, 28576333, 336980598, 1021773811, 762719185, 52616712, 991108128,
+        773506636, 396042843, 147288604, 824111339, 73671885, 373106042, 584580587, 975584856,
+        472020188, 649766622, 883699047, 677596865, 678466444, 699136757, 19303500, 1106179826,
+        840403933, 1063708459, 1091360246, 671176543, 639157155, 1105971909, 831691602, 173216034,
+        913819288, 1069197906, 925149614, 381470746, 142716791, 527914632, 886378310, 923315985,
+        2859473, 463935226, 290366677, 377899338, 969283383, 1084420324, 500010006, 109720268,
+        247527198, 816417698, 1094279266, 966715498, 1087474519, 219455568, 874789364, 459096073,
+        504127208, 1112928496, 623980333, 762388113, 741468397, 313052345, 914277972, 762588284,
+        609579363, 894355967, 791267518, 191175789, 672133323, 1032934127, 190169277, 1009158129,
+        175289905, 692311236, 811243168, 568161410, 195106007, 806176572, 133984609, 1019646153,
+        886090155, 728041145, 831092660, 817997332, 23702417, 450034530, 996412644, 742974977,
+        884384862, 392804854, 684921367, 11288907, 1021951853, 1076519300, 531480070, 176676078,
+        506430485, 342246132, 934702925, 30853093, 604102326, 738497927, 85642232, 34517925,
+        932173113, 255277772, 835427869, 1038439772, 390259213, 481366415, 182844196, 475801347,
+        447732073, 70927199, 942727308, 501345465, 153449739, 192987175, 298016522, 385122091,
+        1121119728, 18587284, 949764450, 1096703026, 604688462, 792756350, 297579564, 491530309,
+        573096202, 600100808, 3547442, 1081545207, 181064997, 596545496, 873928523, 1051657069,
+        1090948175, 142560632, 379961145, 1006811667, 1069297760, 393879678, 1023153985, 704382050,
+        356488003, 579949665, 957268559, 409025278, 321108731, 854209018, 391783602, 200647010,
+        643983635, 539293206, 584032225, 672251149, 152391695, 761566809, 875404307, 614286431,
+        276949370, 1091981126, 1109858202, 1103886333, 189309623, 667178416, 802940491, 1025178774,
+        509330315, 9156252, 217416330, 506090187, 897451800, 539080560, 923778228, 342084338,
+        165848007, 569024252, 380608532, 788365791, 857631871, 226965743, 804261533, 682872097,
+        896503772, 721922939, 420394557, 969454440, 651340286, 1028316109, 1018680295, 1081954164,
+        1007005021, 221731597, 609726247, 1094673002, 516297024, 495191443, 381838492, 988139144,
+        225882592, 858003396, 643345026, 888694417, 437535078, 463703489, 802660359, 150499310,
+        212857476, 305025547, 729044866, 584447967, 97849679, 404306828, 1051357649, 89761373,
+        1093101810, 332213561, 697805647, 789311335, 138945874, 97110111, 101924225, 99078089,
+        3369558, 317851488, 305015556, 507457409, 96133567, 744600510, 161710719, 673363838,
+        960169286, 124452386, 190994499, 1093316140, 739252817, 1128090078, 189593425, 86704223,
+        1088973905, 289147799, 492494385, 600430130, 623720426, 572318624, 280959421, 229081430,
+        210253282, 1025176110, 935593139, 830546545, 433595026, 741164902, 404124717, 678093090,
+        552592527, 528585118, 402670432, 231697899, 28004661, 983187646, 991416414, 265507269,
+        716991609, 89738495, 656055690, 233364763, 1093403731, 469795452, 1048033063, 763548117,
+        430252682, 1027505309, 764331290, 1018714572, 942346436, 956190759, 969479589, 1087221572,
+        1095209475, 1113532366, 599745329, 780394791, 380887095, 939640336, 1006760104, 678713698,
+        1068060813, 454733820, 77303064, 548040113, 884765947, 489784033, 162823431, 343778734,
+        619804000, 130178027, 364046145, 1095663764, 671150398, 294263101, 924711302, 496507933,
+        1026977220, 886871687, 354832998, 99446651, 710338689, 383202267, 145622522, 366642823,
+        535301846, 509470997, 527360288, 556594771, 938046732, 1084352187, 1040216985, 852031367,
+        690411627, 325676781, 219323042, 29108499, 100711504, 406034930, 502377040, 53265953,
+        870412831, 328461991, 818209263, 1086477893, 446564534, 1086169646, 1119041074, 773671449,
+        547072774, 436363379, 20068813, 373156677, 5537895, 58371213, 734738856, 1013884519,
+        793441007, 963507824, 23473761, 280241271, 801521430, 1026798586, 526545180, 102604344,
+        1066259490, 1065236284, 176562157, 1034734710, 264200228, 697599399, 1067248068, 1094551028,
+        371648551, 943810600, 952227948, 789270609, 580547488, 411761753, 543612627, 458037575,
+        553549975, 707896686, 322586194, 884227547, 604495164, 718023416, 621186693, 535545508,
+        396320093, 256375003, 421043636, 695169999, 1006250121, 977669977, 214213965, 733879468,
+        390997680, 670357047, 1098621358, 593448487, 463140892, 552165537, 361891056, 941976678,
+        555507968, 876135512, 640063393, 824004454, 248114624, 743975637, 690234792, 879430107,
+        1022718230, 188198926, 319373759, 927552562, 1096054585, 325025726, 901638273, 884728719,
+        785215810, 1026872748, 1114157333, 748258369, 605477615, 546923348, 465036303, 249831021,
+        196752813, 794093079, 320415313, 121974448, 639405163, 685193276, 936709503, 813100908,
+        889662480, 814143393, 729337838, 434469906, 761641839, 123709278, 439114836, 885588180,
+        604792012, 728572148, 104456762, 824312523, 91554142, 315023784, 421226923, 817849621,
+        839980954, 534522248, 461537413, 762880291, 709823499, 908080065, 528125309, 626419904,
+        1039644850, 1014756127, 397728958, 14357310, 700607282, 73269412, 902913840, 1111742987,
+        879727610, 158010773, 297327277, 25952546, 611924566, 50053416, 989801866, 90368228,
+        585224271, 933426219, 110398812, 999511420, 706883634, 549310135, 53541170, 925101614,
+        843070121, 929683019, 662230725, 321318925, 670962668, 324218395, 460185051, 1081178662,
+        816144698, 949951877, 750353828, 202179949, 252052664, 1061721167, 1065160684, 395076053,
+        1080656113, 698147642, 818922438, 1004453636, 244072286, 875650279, 825320847, 943762255,
+        554831973, 284008021, 601104395, 120670645, 1049537869, 29417349, 485751722, 640637327,
+        177440809, 521402760, 312072208, 62349474, 491672923, 392186419, 94057379, 12154676,
+        593854865, 1054066347, 334875145, 799676077, 590107909, 150999074, 178593952, 413911140,
+        1120548516, 313099521, 764717902, 350403854, 229345260, 350517278, 538398938, 432773433,
+        599462902, 420123990, 1086387667, 32135583, 978145116, 854240763, 356423430, 902193194,
+        504036268, 893165555, 111603880, 818922388, 1116156623, 88450664, 343235123, 20034984,
+        562394618, 404739889, 492786072, 462813114, 451269569, 843732340, 98745250, 937073450,
+        361155353, 132961963, 1020900027, 442371528, 505375525, 881159258, 423045809, 535127803,
+        767040336, 59209860, 526321757, 919886008, 590856805, 674854304, 368893924, 829618933,
+        988828538, 411084011, 163899952, 1118413785, 948357084, 273699925, 896734253, 957681224,
+        270535220, 55679788, 241175702, 1089598877, 103540620, 63033815, 475825047, 116672384,
+        1002624523, 384196402, 772275931, 286956606, 1020572031, 89660838, 971455350, 284501904,
+        48485423, 1059719496, 81979129, 768903915, 335765806, 641176497, 283480188, 104852503,
+        385374096, 741730645, 253389113, 1094309682, 184950262, 90025914, 1025982629, 761545209,
+        497442993, 810686767, 64122594, 302616932, 849004408, 357539524, 846738365, 800820533,
+        263471899, 41837425, 789255412, 648976140, 63536569, 647310441, 556255428, 798389414,
+        639459100, 16888921, 1081131723, 373780615, 774903247, 882921479, 516351784, 1115737392,
+        490868549, 76710529, 440873911, 707864866, 1079463993, 547579935, 146420217, 451847293,
+        217103066, 147935612, 551112830, 295869668, 802905475, 113601730, 851467931, 608135865,
+        548283514, 693544531, 1014381730, 469452735, 997649678, 48285740, 324452786, 529430559,
+        1086441382, 825379270, 649534224, 1104156988, 895754220, 964855098, 725495409, 392658557,
+        803083504, 950629577, 113982710, 565475970, 388031525, 494150383, 32545068, 284726920,
+        661634530, 508885042, 171850234, 855494953, 869711130, 572653108, 1124445128, 387571453,
+        527471591, 338705886, 96257844, 278825375, 486049016, 167751296, 746469890, 1091558342,
+        78122718, 527509896, 334385459, 362699600, 792149959, 472205727, 186776779, 1087810581,
+        1096919472, 524354409, 196948003, 758313700, 943531057, 422813841, 512975134, 70463759,
+        29712463, 881081478, 909865230, 114289622, 521796956, 153874541, 261211103, 474207356,
+        31199290, 746294146, 877680760, 488469507, 881666878, 361312467, 27859475, 137934338,
+        390030192, 750270532, 411804457, 534011627, 639841140, 869554311, 926227408, 62488262,
+        425796330, 99777106, 43512552, 93800865, 635787291, 329502798, 399556616, 451688535,
+        1001395699, 868034999, 594413922, 806145881, 558288459, 833840920, 756020280, 206374154,
+        964029628, 398365322, 83157107, 989573141, 254909708, 133567828, 117566235, 979026189,
+        313584016, 984024800, 787971980, 651472892, 585816386, 279588227, 1056182452, 365628871,
+        724761674, 672459534, 1077113069, 493022470, 91476098, 727289079, 1109048987, 100876317,
+        185322233, 283468769, 84746079, 157931329, 379765945, 141543971, 827910707, 1069224619,
+        562390672, 715239289, 965302328, 437563448, 524274934, 858856962, 253575278, 701368299,
+        188986151, 117095423, 153781042, 839176952, 798788187, 399196281, 825767931, 419052158,
+        34643824, 993496214, 387001670, 835524414, 933392050, 824836016, 309948454, 719378330,
+        1114479314, 824747910, 170576972, 1015119097, 735266606, 218728015, 27637167, 311492071,
+        886390087, 708923369, 355043781, 252148764, 568163149, 543524637, 288696605, 785226904,
+        219543096, 110211601, 48765933, 972473852, 1041080716, 825105856, 150483171, 649355739,
+        81803006, 1082829660, 853800912, 1116628377, 54000364, 253128744, 902229218, 1002622534,
+        102594369, 505719072, 1124142467, 226337239, 667703580, 987758502, 274584746, 263671587,
+        578316675, 713960057, 948457975, 687863493, 173221260, 89513345, 291359907, 445984809,
+        20770187, 602463962, 1079707176, 880942496, 645894248, 780867069, 475796932, 233270624,
+        766384245, 36093038, 500819961, 6656654, 350092093, 431977465, 311606663, 685520206,
+        370120825, 487361599, 31706445, 949290435, 798419001, 913065224, 945091088, 972920725,
+        857586718, 437127725, 1052645792, 358446302, 996399571, 543439832, 416789546, 916442318,
+        302377031, 467691127, 232719548, 956950960, 30662349, 913344590, 671419686, 156717827,
+        871221407, 805724541, 53537948, 947303970, 882321601, 261318306, 149607321, 577464632,
+        24713313, 524014919, 148761135, 440012007, 64300984, 340528573, 392997324, 275289113,
+        270608946, 326741293, 1023209990, 1097556513, 262052804, 369075041, 508972689, 526115229,
+        336030213, 730812609, 858309675, 573108893, 677029394, 399052930, 719818695, 979511494,
+        459342865, 979977030, 734921803, 1003564322, 545445521, 458168916, 897462268, 433987915,
+        587813631, 65847000, 911164840, 479271435, 147427802, 1001655718, 753742950, 956042287,
+        959270867, 550996088, 1061452618, 383903202, 564269310, 95108013, 274104630, 147843746,
+        779785605, 1128241893, 311239559, 133156013, 1106707867, 1116901889, 186989720, 243881610,
+        925404308, 256833509, 1057272545, 548147013, 338726328, 1069381687, 574850775, 342601456,
+        593021619, 994345276, 1048130591, 357272790, 941731875, 199494123, 800190987, 1024351829,
+        729808873, 795901888, 725425505, 1065099405, 1024787791, 856914318, 946582763, 461811542,
+        444076465, 1128838984, 715164506, 517440977, 39330283, 90148781, 554707372, 928732704,
+        371502021, 1008233336, 317582756, 524451154, 155422816, 440312472, 1100195158, 791313568,
+        1074684194, 757523450, 507259938, 376912438, 790750659, 19985542, 236477812, 621515084,
+        14641604, 423726725, 43680072, 165943232, 548969735, 840033269, 191845866, 921576757,
+        915919657, 817349484, 963826245, 482186439, 730356300, 1015917581, 672918284, 396635587,
+        767202303, 813371635, 869333976, 508192846, 490177145, 59204384, 11099732, 756805114,
+        903025660, 594360830, 1019323549, 705453704, 721000677, 467124590, 433770645, 203504697,
+        97797853, 924825635, 373581843, 430933902, 811243340, 250007758, 534865265, 128712376,
+        822051513, 250846965, 1070671272, 1072188174, 312655828, 488080380, 566811631, 88831334,
+        15478592, 996929267, 279463354, 404398823, 996165590, 134746184, 10331000, 142429560,
+        482838497, 3625072, 653531060, 803565118, 1048986230, 1006019827, 715676944, 564117799,
+        555220950, 889714353, 263699900, 503659804, 1088604303, 600414871, 99345416, 997036691,
+        1062002121, 126783467, 253332497, 438867657, 976937555, 654395668, 557215041, 46939874,
+        552713464, 749916384, 484323074, 483917405, 677263900, 99365013, 192496860, 914599346,
+        547960463, 231723970, 997912798, 1099799435, 892081583, 102958110, 696767097, 5476106,
+        869957957, 497317476, 399192328, 575567190, 737714890, 545582635, 731658739, 404188557,
+        914432306, 56034159, 372218440, 626858382, 1059276234, 290001074, 728713038, 646639755,
+        1071349304, 497411527, 914507668, 874023244, 330355746, 997134735, 317751869, 93333561,
+        191736798, 867404294, 764021455, 649553869, 32134107, 356452470, 515188952, 912016737,
+        981074116, 3176027, 563139069, 901020620, 765622786, 77065368, 112565404, 1104087001,
+        603149919, 62320784, 37340924, 271988916, 1088050757, 900822026, 570795193, 118136336,
+        228954381, 84002137, 107820426, 1036215916, 414421818, 575157043, 1029511469, 1098909800,
+        638622793, 364653701, 951039572, 202667835, 1105572750, 905930490, 622475707, 769476936,
+        359844918, 1032607831, 270561227, 922044195, 211114077, 806702381, 1034110348, 1090787175,
+        380228620, 754831904, 825262701, 254684021, 689956338, 946898079, 1119439184, 170588665,
+        455055047, 1112488359, 316261794, 167052760, 681776700, 101655817, 1104047888, 931846485,
+        777666661, 244421919, 1032717751, 771899484, 167884822, 383451132, 414684868, 967970978,
+        251607673, 946486934, 801420079, 964329829, 1081110125, 810125049, 621410728, 635499090,
+        324446706, 609896164, 727096174, 788299449, 605051120, 662578360, 478977775, 511427829,
+        804875304, 299858894, 607089768, 134081973, 892474561, 270157166, 79522694, 885310889,
+        360224635, 1006476027, 974435294, 780834962, 461009670, 494180818, 959507232, 1121381346,
+        1088339534, 654927281, 762292807, 33461378, 661924743, 864591625, 546400772, 944342858,
+        1028200265, 1056455757, 88680527, 1050916030, 938561033, 102069108, 295787004, 446280472,
+        772055005, 715365274, 933867776, 785081482, 216411888, 159026208, 584415731, 310755280,
+        266117816, 727015230, 334501223, 484334581, 1033523203, 1063818101, 736774330, 313712636,
+        734996871, 184740368, 362794063, 436132188, 482029298, 442290376, 221647483, 386772954,
+        982910397, 726807337, 240728269, 105503811, 269900590, 243722064, 610126807, 951562758,
+        659751006, 340811190, 199299787, 351828858, 856382738, 365480606, 1042786228, 1123068912,
+        10276685, 642933070, 165566419, 679827169, 961701698, 294054310, 355706366, 217192437,
+        522587524, 312032939, 558693905, 349209851, 930411190, 262585457, 415533475, 646948555,
+        1066780967, 471089109, 929057655, 517438536, 258478395, 39270561, 889479646, 273898984,
+        627910143, 618616086, 180698624, 951480188, 200561477, 237584143, 607869392, 437078460,
+        415163056, 209993568, 334873362, 1128930907, 508514481, 792979407, 676813222, 1019104866,
+        411695497, 43613997, 785578867, 132379578, 737624958, 773288614, 505119708, 928682766,
+        752219752, 662639813, 271272426, 160092539, 49353550, 599278652, 457441423, 694141030,
+        1108781150, 497004602, 152637935, 327024689, 869206336, 153529086, 213974535, 210561231,
+        1115104772, 26000087, 473351014, 705674785, 11948367, 699262595, 385616508, 1082509833,
+        1002086909, 351117184, 426727961, 716455350, 445629691, 263014880, 178561677, 763942576,
+        453911234, 251065969, 1119113840, 403386182, 584063944, 1061670228, 1067594138, 934920847,
+        221796630, 578508545, 960533240, 408202157, 800505215, 124820100, 693014651, 377258025,
+        345451846, 1084205130, 955691331, 877134009, 461861459, 1065671551, 750205976, 899130388,
+        962296503, 260525551, 454879090, 567632207, 867393171, 205384967, 52991349, 772073189,
+        784137909, 177596177, 774634076, 830320977, 80216042, 958845699, 444242121, 445247615,
+        749038979, 1043182368, 942892656, 308653011, 717431175, 1123135166, 401326655, 801495329,
+        924651065, 627583444, 57945923, 797461143, 1014733078, 267842526, 75171020, 985898727,
+        602077998, 289641435, 3817272, 72809466, 170436822, 917065606, 1075765979, 228712568,
+        804065866, 103429236, 755232438, 523116600, 175489690, 643101045, 782740199, 646390839,
+        154384289, 34296586, 68273162, 409008719, 72194869, 514620434, 1074403272, 1002586053,
+        824780576, 439514269, 814483462, 1065678048, 192117199, 337965005, 290046544, 745194166,
+        98634179, 594461368, 282668308, 169287965, 809176984, 851624865, 146280088, 551403730,
+        229988203, 759464587, 986831791, 307931453, 687021443, 1037047036, 390984681, 360214539,
+        489609063, 1079688799, 520853052, 248692113, 519108294, 873337355, 1019557863, 51551242,
+        140648753, 956691426, 500515518, 829644954, 225195986, 477843837, 117146454, 524576548,
+        388500809, 679009976, 95097294, 83923789, 86452515, 112923593, 572196182, 809066810,
+        365600046, 610178737, 6894641, 484752925, 321345624, 421663857, 996369171, 945767857,
+        512656150, 598142805, 131771428, 523631226, 238471503, 1017814054, 960743607, 358302399,
+        729762169, 774817733, 285185753, 94598268, 859341273, 817195544, 781913067, 180586359,
+        922498031, 928876955, 181750202, 704453607, 982602560, 760425692, 445461081, 262899249,
+        993032850, 1099441120, 766077054, 661328835, 849341957, 64481799, 137189173, 665203913,
+        274533772, 732036380, 686074559, 364887119, 934033368, 1113144551, 98086634, 1039349720,
+        138463640, 63197842, 478102337, 281719763, 25872677, 48972992, 1117419859, 319791525,
+        557816662, 725904956, 373125437, 385943763, 208358936, 697455132, 373381211, 417958668,
+        398054090, 1014428957, 906287080, 1055697308, 610106444, 259488631, 39585717, 1118889820,
+        869608698, 828290478, 859032095, 336215136, 327990657, 634859446, 312601336, 291351028,
+        682470272, 23577953, 337451423, 616208275, 919161707, 247373119, 679977555, 387895394,
+        234372661, 418240334, 10541774, 49052282, 470788227, 341763065, 746512185, 939659609,
+        615551391, 1053722676, 786403464, 952256028, 999791888, 536861641, 466680432, 223936516
+
+    };
+
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLA.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLA.java
new file mode 100644
index 000000000..f56a2c96f
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLA.java
@@ -0,0 +1,1948 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+import java.security.SecureRandom;
+
+public class QTESLA
+{
+
+    /******************************************************************************************************************************************
+     * Description:	Hash Function to Generate C' for Heuristic qTESLA Security Category-1 and Category-3 (Option for Size or Speed)
+     ******************************************************************************************************************************************/
+    private static void hashFunction(byte[] output, int outputOffset, int[] V, final byte[] message, int messageOffset, int n, int d, int q)
+    {
+
+        int mask;
+        int cL;
+
+        byte[] T = new byte[n + Polynomial.MESSAGE];
+
+        for (int i = 0; i < n; i++)
+        {
+            /* If V[i] > Q / 2 Then V[i] = V[i] - Q */
+            mask = (q / 2 - V[i]) >> 31;
+            V[i] = ((V[i] - q) & mask) | (V[i] & (~mask));
+            cL = V[i] & ((1 << d) - 1);
+            /* If cL > 2 ^ (d - 1) Then cL = cL - 2 ^ d */
+            mask = ((1 << (d - 1)) - cL) >> 31;
+            cL = ((cL - (1 << d)) & mask) | (cL & (~mask));
+            T[i] = (byte)((V[i] - cL) >> d);
+
+        }
+
+        System.arraycopy(message, messageOffset, T, n, Polynomial.MESSAGE);
+
+        if (q == Parameter.Q_I)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK128(output, outputOffset, Polynomial.HASH, T, 0, n + Polynomial.MESSAGE);
+
+        }
+
+        if (q == Parameter.Q_III_SIZE || q == Parameter.Q_III_SPEED)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK256(output, outputOffset, Polynomial.HASH, T, 0, n + Polynomial.MESSAGE);
+
+        }
+
+    }
+
+    /**************************************************************************************************************************************************
+     * Description:	Hash Function to Generate C' for Provably-Secure qTESLA Security Category-1 and Security Category-3
+     **************************************************************************************************************************************************/
+    private static void hashFunction(byte[] output, int outputOffset, long[] V, final byte[] message, int messageOffset, int n, int k, int d, int q)
+    {
+
+        int index;
+        long mask;
+        long cL;
+        long temporary;
+
+        byte[] T = new byte[n * k + Polynomial.MESSAGE];
+
+        for (int j = 0; j < k; j++)
+        {
+
+            index = n * j;
+
+            for (int i = 0; i < n; i++)
+            {
+
+                temporary = V[index];
+                /* If V[i] > Q / 2 Then V[i] = V[i] - Q */
+                mask = (q / 2 - temporary) >> 63;
+                temporary = ((temporary - q) & mask) | (temporary & (~mask));
+                cL = temporary & ((1 << d) - 1);
+                /* If cL > 2 ^ (d - 1) Then cL = cL - 2 ^ d */
+                mask = ((1 << (d - 1)) - cL) >> 63;
+                cL = ((cL - (1 << d)) & mask) | (cL & (~mask));
+                T[index++] = (byte)((temporary - cL) >> d);
+
+            }
+
+        }
+
+        System.arraycopy(message, messageOffset, T, n * k, Polynomial.MESSAGE);
+
+        if (q == Parameter.Q_I_P)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK128(output, outputOffset, Polynomial.HASH, T, 0, n * k + Polynomial.MESSAGE);
+
+        }
+
+        if (q == Parameter.Q_III_P)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK256(output, outputOffset, Polynomial.HASH, T, 0, n * k + Polynomial.MESSAGE);
+
+        }
+
+    }
+
+    /**************************************************************************************************************************************
+     * Description:	Computes Absolute Value for for Heuristic qTESLA Security Category-1 and Security Category-3 (Option for Size or Speed)
+     **************************************************************************************************************************************/
+    private static int absolute(int value)
+    {
+
+        return ((value >> 31) ^ value) - (value >> 31);
+
+    }
+
+    /*****************************************************************************************************************
+     * Description:	Computes Absolute Value for for Provably-Secure qTESLA Security Category-1 and Security Category-3
+     *****************************************************************************************************************/
+    private static long absolute(long value)
+    {
+
+        return ((value >> 63) ^ value) - (value >> 63);
+
+    }
+
+    /*********************************************************************************
+     * Description:	Checks Bounds for Signature Vector Z During Signification.
+     * 				Leaks the Position of the Coefficient that Fails the Test.
+     * 				The Position of the Coefficient is Independent of the Secret Data.
+     * 				Does not Leak the Signature of the Coefficients.
+     * 				For Heuristic qTESLA Security Category-1 and Security Category-3
+     * 				(Option for Size or Speed)
+     *
+     * @param        Z        Signature Vector
+     * @param        n        Polynomial Degree
+     * @param        b        Interval the Randomness is Chosen in During Signification
+     * @param        u        Bound in Checking Secret Polynomial
+     *
+     * @return false    Valid / Accepted
+     * 				true	Invalid / Rejected
+     ********************************************************************************/
+    private static boolean testRejection(int[] Z, int n, int b, int u)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            if (absolute(Z[i]) > (b - u))
+            {
+
+                return true;
+
+            }
+
+        }
+
+        return false;
+
+    }
+
+    /*************************************************************************************
+     * Description:	Checks Bounds for Signature Vector Z During Signification.
+     * 				Leaks the Position of the Coefficient that Fails the Test.
+     * 				The Position of the Coefficient is Independent of the Secret Data.
+     * 				Does not Leak the Signature of the Coefficients.
+     * 				For Provably-Secure qTESLA Security Category-1 and Security Category-3
+     *
+     * @param        Z        Signature Vector
+     * @param        n        Polynomial Degree
+     * @param        b        Interval the Randomness is Chosen in During Signification
+     * @param        u        Bound in Checking Secret Polynomial
+     *
+     * @return false    Valid / Accepted
+     * 				true	Invalid / Rejected
+     *************************************************************************************/
+    private static boolean testRejection(long[] Z, int n, int b, int u)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            if (absolute(Z[i]) > (b - u))
+            {
+
+                return true;
+
+            }
+
+        }
+
+        return false;
+
+    }
+
+    /**********************************************************************************
+     * Description:	Checks Bounds for Signature Vector Z During Signature Verification
+     * 				for Heuristic qTESLA Security Category-1 and Security Category-3
+     * 				(Option of Size of Speed)
+     *
+     * @param        Z        Signature Vector
+     * @param        n        Polynomial Degree
+     * @param        b        Interval the Randomness is Chosen in During Signification
+     * @param        u        Bound in Checking Secret Polynomial
+     *
+     * @return false    Valid / Accepted
+     * 				true	Invalid / Rejected
+     *********************************************************************************/
+    private static boolean testZ(int[] Z, int n, int b, int u)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            if ((Z[i] < -(b - u)) || (Z[i] > b - u))
+            {
+
+                return true;
+
+            }
+
+        }
+
+        return false;
+
+    }
+
+    /*************************************************************************************
+     * Description:	Checks Bounds for Signature Vector Z During Signature Verification
+     * 				for Provably-Secure qTESLA Security Category-1 and Security Category-3
+     *
+     * @param        Z        Signature Vector
+     * @param        n        Polynomial Degree
+     * @param        b        Interval the Randomness is Chosen in During Signification
+     * @param        u        Bound in Checking Secret Polynomial
+     *
+     * @return false    Valid / Accepted
+     * 				true	Invalid / Rejected
+     *************************************************************************************/
+    private static boolean testZ(long[] Z, int n, int b, int u)
+    {
+
+        for (int i = 0; i < n; i++)
+        {
+
+            if ((Z[i] < -(b - u)) || (Z[i] > b - u))
+            {
+
+                return true;
+
+            }
+
+        }
+
+        return false;
+
+    }
+
+    /*********************************************************************************
+     * Description:	Checks Bounds for W = V - EC During Signature Verification.
+     * 				Leaks the Position of the Coefficient that Fails the Test.
+     * 				The Position of the Coefficient is Independent of the Secret Data.
+     * 				Does not Leak the Signature of the Coefficients.
+     * 				For Heuristic qTESLA Security Category-1 and Security Category-3
+     * 				(Option for Size or Speed)
+     *
+     * @param        V            Parameter to be Checked
+     * @param        n            Polynomial Degree
+     * @param        d            Number of Rounded Bits
+     * @param        q            Modulus
+     * @param        rejection    Bound in Checking Error Polynomial
+     *
+     * @return false        Valid / Accepted
+     * 				true		Invalid / Rejected
+     *********************************************************************************/
+    private static boolean testV(int[] V, int n, int d, int q, int rejection)
+    {
+
+        int mask;
+        int left;
+        int right;
+        int test1;
+        int test2;
+
+        for (int i = 0; i < n; i++)
+        {
+
+            mask = (q / 2 - V[i]) >> 31;
+            right = ((V[i] - q) & mask) | (V[i] & (~mask));
+            test1 = (~(absolute(right) - (q / 2 - rejection))) >>> 31;
+            left = right;
+            right = (right + (1 << (d - 1)) - 1) >> d;
+            right = left - (right << d);
+            test2 = (~(absolute(right) - ((1 << (d - 1)) - rejection))) >>> 31;
+
+            /* Two Tests Fail */
+            if ((test1 | test2) == 1)
+            {
+
+                return true;
+
+            }
+
+        }
+
+        return false;
+
+    }
+
+    /****************************************************************************************
+     * Description:	Checks Bounds for W = V - EC During Signature Verification.
+     * 				Leaks the Position of the Coefficient that Fails the Test.
+     * 				The Position of the Coefficient is Independent of the Secret Data.
+     * 				Does not Leak the Signature of the Coefficients.
+     * 				For Provably-Secure qTESLA Security Category-1 and Security Category-3
+     *
+     * @param        V            Parameter to be Checked
+     * @param        vOffset        Starting Point of V
+     * @param        n            Polynomial Degree
+     * @param        d            Number of Rounded Bits
+     * @param        q            Modulus
+     * @param        rejection    Bound in Checking Error Polynomial
+     *
+     * @return false        Valid / Accepted
+     * 				true		Invalid / Rejected
+     ****************************************************************************************/
+    private static boolean testV(long[] V, int vOffset, int n, int d, int q, int rejection)
+    {
+
+        long mask;
+        long left;
+        long right;
+        long test1;
+        long test2;
+
+        for (int i = 0; i < n; i++)
+        {
+
+            mask = (q / 2 - V[vOffset + i]) >> 63;
+            right = ((V[vOffset + i] - q) & mask) | (V[vOffset + i] & (~mask));
+            test1 = (~(absolute(right) - (q / 2 - rejection))) >>> 63;
+
+            left = right;
+            right = (int)((right + (1 << (d - 1)) - 1) >> d);
+            right = left - (right << d);
+            test2 = (~(absolute(right) - ((1 << (d - 1)) - rejection))) >>> 63;
+
+            /* Two Tests Fail */
+            if ((test1 | test2) == 1L)
+            {
+
+                return true;
+
+            }
+
+        }
+
+        return false;
+
+    }
+
+    /**********************************************************************************************************
+     * Description:	Checks Whether the Generated Error Polynomial or the Generated Secret Polynomial
+     *				Fulfills Certain Properties Needed in Key Generation Algorithm
+     *				For Heuristic qTESLA Security Category-1 and Security Category-3 (Option for Size or Speed)
+     *
+     * @param        polynomial        Parameter to be Checked
+     * @param        bound            Threshold of Summation
+     * @param        n                Polynomial Degree
+     * @param        h                Number of Non-Zero Entries of Output Elements of Encryption
+     *
+     * @return false            Fulfillment
+     * 				true			No Fulfillment
+     **********************************************************************************************************/
+    private static boolean checkPolynomial(int[] polynomial, int bound, int n, int h)
+    {
+
+        int summation = 0;
+        int limit = n;
+        int temporary;
+        int mask;
+        int[] list = new int[n];
+
+        for (int i = 0; i < n; i++)
+        {
+
+            list[i] = absolute(polynomial[i]);
+
+        }
+
+        for (int i = 0; i < h; i++)
+        {
+
+            for (int j = 0; j < limit - 1; j++)
+            {
+                /* If list[j + 1] > list[j] Then Exchanges Contents */
+                mask = (list[j + 1] - list[j]) >> 31;
+                temporary = (list[j + 1] & mask) | (list[j] & (~mask));
+                list[j + 1] = (list[j] & mask) | (list[j + 1] & (~mask));
+                list[j] = temporary;
+
+            }
+
+            summation += list[limit - 1];
+            limit--;
+
+        }
+
+        if (summation > bound)
+        {
+
+            return true;
+
+        }
+
+        return false;
+
+    }
+
+    /**********************************************************************************************************
+     * Description:	Checks Whether the Generated Error Polynomial or the Generated Secret Polynomial
+     *				Fulfills Certain Properties Needed in Key Generation Algorithm
+     *				For Provably-Secure qTESLA Security Category-1 and Security Category-3
+     *
+     * @param        polynomial        Parameter to be Checked
+     * @param        offset            Starting Point of the Polynomial to be Checked
+     * @param        bound            Threshold of Summation
+     * @param        n                Polynomial Degree
+     * @param        h                Number of Non-Zero Entries of Output Elements of Encryption
+     *
+     * @return false            Fulfillment
+     * 				true			No Fulfillment
+     **********************************************************************************************************/
+    private static boolean checkPolynomial(long[] polynomial, int offset, int bound, int n, int h)
+    {
+
+        int summation = 0;
+        int limit = n;
+        short temporary;
+        short mask;
+        short[] list = new short[n];
+
+        for (int i = 0; i < n; i++)
+        {
+
+            list[i] = (short)(absolute(polynomial[offset + i]));
+
+        }
+
+        for (int i = 0; i < h; i++)
+        {
+
+            for (int j = 0; j < limit - 1; j++)
+            {
+                /* If list[j + 1] > list[j] Then Exchanges Contents */
+                mask = (short)((list[j + 1] - list[j]) >> 15);
+                temporary = (short)((list[j + 1] & mask) | (list[j] & (~mask)));
+                list[j + 1] = (short)((list[j] & mask) | (list[j + 1] & (~mask)));
+                list[j] = temporary;
+
+            }
+
+            summation += (int)list[limit - 1];
+            limit--;
+
+        }
+
+        if (summation > bound)
+        {
+
+            return true;
+
+        }
+
+        return false;
+
+    }
+
+    /************************************************************************************************************************************************************
+     * Description:	Generates A Pair of Public Key and Private Key for qTESLA Signature Scheme for Heuristic qTESLA Security Category-1 and Security Category-3
+     *				(Option for Size or Speed)
+     *
+     * @param        publicKey                            Contains Public Key
+     * @param        privateKey                            Contains Private Key
+     * @param        secureRandom                        Source of Randomness
+     * @param        n                                    Polynomial Degree
+     * @param        h                                    Number of Non-Zero Entries of Output Elements of Encryption
+     * @param        q                                    Modulus
+     * @param        qInverse
+     * @param        qLogarithm                            q <= 2 ^ qLogarithm
+     * @param        generatorA
+     * @param        inverseNumberTheoreticTransform
+     * @param        xi
+     * @param        zeta
+     * @param        errorBound                            Bound in Checking Error Polynomial
+     * @param        secretBound                            Bound in Checking Secret Polynomial
+     *
+     * @return 0                                    Successful Execution
+     ************************************************************************************************************************************************************/
+    private static int generateKeyPair(
+
+        byte[] publicKey, byte[] privateKey, SecureRandom secureRandom,
+        int n, int h, int q, long qInverse, int qLogarithm, int generatorA, int inverseNumberTheoreticTransform, double xi,
+        int[] zeta,
+        int errorBound, int secretBound)
+    {
+
+        /* Initialize Domain Separator for Error Polynomial and Secret Polynomial */
+        int nonce = 0;
+
+        byte[] randomness = new byte[Polynomial.RANDOM];
+
+        /* Extend Random Bytes to Seed Generation of Error Polynomial and Secret Polynomial */
+        byte[] randomnessExtended = new byte[Polynomial.SEED * 4];
+
+        int[] secretPolynomial = new int[n];
+        int[] errorPolynomial = new int[n];
+        int[] A = new int[n];
+        int[] T = new int[n];
+
+        /* Get randomnessExtended <- seedErrorPolynomial, seedSecretPolynomial, seedA, seedY */
+        // this.rng.randomByte (randomness, (short) 0, Polynomial.RANDOM);
+        secureRandom.nextBytes(randomness);
+
+        if (q == Parameter.Q_I)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK128(randomnessExtended, 0, Polynomial.SEED * 4, randomness, 0, Polynomial.RANDOM);
+
+        }
+
+        if (q == Parameter.Q_III_SIZE || q == Parameter.Q_III_SPEED)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK256(randomnessExtended, 0, Polynomial.SEED * 4, randomness, 0, Polynomial.RANDOM);
+
+        }
+
+        /*
+         * Sample the Error Polynomial Fulfilling the Criteria
+         * Choose All Error Polynomial in R with Entries from D_SIGMA
+         * Repeat Step at Iteration if the h Largest Entries of Error Polynomial Summation to L_E
+         */
+        do
+        {
+
+            if (q == Parameter.Q_I)
+            {
+
+                Sample.polynomialGaussSamplerI(errorPolynomial, 0, randomnessExtended, 0, ++nonce);
+
+            }
+
+            if (q == Parameter.Q_III_SIZE)
+            {
+
+                Sample.polynomialGaussSamplerIII(errorPolynomial, 0, randomnessExtended, 0, ++nonce, n, xi, Sample.EXPONENTIAL_DISTRIBUTION_III_SIZE);
+
+            }
+
+            if (q == Parameter.Q_III_SPEED)
+            {
+
+                Sample.polynomialGaussSamplerIII(errorPolynomial, 0, randomnessExtended, 0, ++nonce, n, xi, Sample.EXPONENTIAL_DISTRIBUTION_III_SPEED);
+
+            }
+
+        }
+        while (checkPolynomial(errorPolynomial, errorBound, n, h) == true);
+
+        /*
+         * Sample the Secret Polynomial Fulfilling the Criteria
+         * Choose Secret Polynomial in R with Entries from D_SIGMA
+         * Repeat Step if the h Largest Entries of Secret Polynomial Summation to L_S
+         */
+        do
+        {
+
+            if (q == Parameter.Q_I)
+            {
+
+                Sample.polynomialGaussSamplerI(secretPolynomial, 0, randomnessExtended, Polynomial.SEED, ++nonce);
+
+            }
+
+            if (q == Parameter.Q_III_SIZE)
+            {
+
+                Sample.polynomialGaussSamplerIII(secretPolynomial, 0, randomnessExtended, Polynomial.SEED, ++nonce, n, xi, Sample.EXPONENTIAL_DISTRIBUTION_III_SIZE);
+
+            }
+
+            if (q == Parameter.Q_III_SPEED)
+            {
+
+                Sample.polynomialGaussSamplerIII(secretPolynomial, 0, randomnessExtended, Polynomial.SEED, ++nonce, n, xi, Sample.EXPONENTIAL_DISTRIBUTION_III_SPEED);
+
+            }
+
+        }
+        while (checkPolynomial(secretPolynomial, secretBound, n, h) == true);
+
+        /* Generate Uniform Polynomial A */
+        Polynomial.polynomialUniform(A, randomnessExtended, Polynomial.SEED * 2, n, q, qInverse, qLogarithm, generatorA, inverseNumberTheoreticTransform);
+
+        /* Compute the Public Key T = A * secretPolynomial + errorPolynomial */
+        Polynomial.polynomialMultiplication(T, A, secretPolynomial, n, q, qInverse, zeta);
+        Polynomial.polynomialAdditionCorrection(T, T, errorPolynomial, n, q);
+
+        /* Pack Public and Private Keys */
+        if (q == Parameter.Q_I)
+        {
+
+            Pack.encodePrivateKeyI(privateKey, secretPolynomial, errorPolynomial, randomnessExtended, Polynomial.SEED * 2);
+            Pack.encodePublicKey(publicKey, T, randomnessExtended, Polynomial.SEED * 2, Parameter.N_I, Parameter.Q_LOGARITHM_I);
+
+        }
+
+        if (q == Parameter.Q_III_SIZE)
+        {
+
+            Pack.encodePrivateKeyIIISize(privateKey, secretPolynomial, errorPolynomial, randomnessExtended, Polynomial.SEED * 2);
+            Pack.encodePublicKey(publicKey, T, randomnessExtended, Polynomial.SEED * 2, Parameter.N_III_SIZE, Parameter.Q_LOGARITHM_III_SIZE);
+
+        }
+
+        if (q == Parameter.Q_III_SPEED)
+        {
+
+            Pack.encodePrivateKeyIIISpeed(privateKey, secretPolynomial, errorPolynomial, randomnessExtended, Polynomial.SEED * 2);
+            Pack.encodePublicKeyIIISpeed(publicKey, T, randomnessExtended, Polynomial.SEED * 2);
+
+        }
+
+        return 0;
+
+    }
+
+    /****************************************************************************************************************************************************************
+     * Description:	Generates A Pair of Public Key and Private Key for qTESLA Signature Scheme for
+     * 				Heuristic qTESLA Security Category-1
+     *
+     * @param        publicKey                            Contains Public Key
+     * @param        privateKey                            Contains Private Key
+     * @param        secureRandom                        Source of Randomness
+     *
+     * @return 0                                    Successful Execution
+     *
+     ****************************************************************************************************************************************************************/
+    public static int generateKeyPairI(byte[] publicKey, byte[] privateKey, SecureRandom secureRandom)
+    {
+
+        return generateKeyPair(
+
+            publicKey, privateKey, secureRandom,
+            Parameter.N_I, Parameter.H_I, Parameter.Q_I, Parameter.Q_INVERSE_I, Parameter.Q_LOGARITHM_I,
+            Parameter.GENERATOR_A_I, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_I,
+            Parameter.XI_I,
+            PolynomialHeuristic.ZETA_I,
+            Parameter.KEY_GENERATOR_BOUND_E_I, Parameter.KEY_GENERATOR_BOUND_S_I
+
+        );
+
+    }
+
+    /****************************************************************************************************************************************************************
+     * Description:	Generates A Pair of Public Key and Private Key for qTESLA Signature Scheme for Heuristic qTESLA Security Category-3 (Option for Size)
+     *
+     * @param        publicKey                            Contains Public Key
+     * @param        privateKey                            Contains Private Key
+     * @param        secureRandom                        Source of Randomness
+     *
+     * @return 0                                    Successful Execution
+     ****************************************************************************************************************************************************************/
+    public static int generateKeyPairIIISize(byte[] publicKey, byte[] privateKey, SecureRandom secureRandom)
+    {
+
+        return generateKeyPair(
+
+            publicKey, privateKey, secureRandom,
+            Parameter.N_III_SIZE, Parameter.H_III_SIZE, Parameter.Q_III_SIZE, Parameter.Q_INVERSE_III_SIZE, Parameter.Q_LOGARITHM_III_SIZE,
+            Parameter.GENERATOR_A_III_SIZE, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_III_SIZE,
+            Parameter.XI_III_SIZE,
+            PolynomialHeuristic.ZETA_III_SIZE,
+            Parameter.KEY_GENERATOR_BOUND_E_III_SIZE, Parameter.KEY_GENERATOR_BOUND_S_III_SIZE
+
+        );
+
+    }
+
+    /****************************************************************************************************************************************************************
+     * Description:	Generates A Pair of Public Key and Private Key for qTESLA Signature Scheme for Heuristic qTESLA Security Category-3
+     * 				(Option for Speed)
+     *
+     * @param        publicKey                            Contains Public Key
+     * @param        privateKey                            Contains Private Key
+     * @param        secureRandom                        Source of Randomness
+     *
+     * @return 0                                    Successful Execution
+     *
+     ****************************************************************************************************************************************************************/
+    public static int generateKeyPairIIISpeed(byte[] publicKey, byte[] privateKey, SecureRandom secureRandom)
+    {
+
+        return generateKeyPair(
+
+            publicKey, privateKey, secureRandom,
+            Parameter.N_III_SPEED, Parameter.H_III_SPEED, Parameter.Q_III_SPEED, Parameter.Q_INVERSE_III_SPEED, Parameter.Q_LOGARITHM_III_SPEED,
+            Parameter.GENERATOR_A_III_SPEED, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_III_SPEED,
+            Parameter.XI_III_SPEED,
+            PolynomialHeuristic.ZETA_III_SPEED,
+            Parameter.KEY_GENERATOR_BOUND_E_III_SPEED, Parameter.KEY_GENERATOR_BOUND_S_III_SPEED
+
+        );
+
+    }
+
+    /*******************************************************************************************************************************************************
+     * Description:	Generates A Pair of Public Key and Private Key for qTESLA Signature Scheme for Provably-Secure qTESLA Security Category-1
+     * 				and Category-3
+     *
+     * @param        publicKey                            Contains Public Key
+     * @param        privateKey                            Contains Private Key
+     * @param        secureRandom                        Source of Randomness
+     * @param        n                                    Polynomial Degree
+     * @param        k                                    Number of Ring-Learning-With-Errors Samples
+     * @param        h                                    Number of Non-Zero Entries of Output Elements of Encryption
+     * @param        q                                    Modulus
+     * @param        qInverse
+     * @param        qLogarithm                            q <= 2 ^ qLogarithm
+     * @param        generatorA
+     * @param        inverseNumberTheoreticTransform
+     * @param        xi
+     * @param        zeta
+     * @param        errorBound                            Bound in Checking Error Polynomial
+     * @param        secretBound                            Bound in Checking Secret Polynomial
+     *
+     * @return 0                                    Successful Execution
+     *******************************************************************************************************************************************************/
+    private static int generateKeyPair(
+
+        byte[] publicKey, byte[] privateKey, SecureRandom secureRandom,
+        int n, int k, int h, int q, long qInverse, int qLogarithm, int generatorA, int inverseNumberTheoreticTransform, double xi,
+        long[] zeta,
+        int errorBound, int secretBound
+
+    )
+    {
+
+        /* Initialize Domain Separator for Error Polynomial and Secret Polynomial */
+        int nonce = 0;
+
+        long mask;
+
+        byte[] randomness = new byte[Polynomial.RANDOM];
+
+        /* Extend Random Bytes to Seed Generation of Error Polynomial and Secret Polynomial */
+        byte[] randomnessExtended = new byte[Polynomial.SEED * (k + 3)];
+
+        long[] secretPolynomial = new long[n];
+        long[] secretPolynomialNumberTheoreticTransform = new long[n];
+        long[] errorPolynomial = new long[n * k];
+        long[] A = new long[n * k];
+        long[] T = new long[n * k];
+
+        /* Get randomnessExtended <- seedErrorPolynomial, seedSecretPolynomial, seedA, seedY */
+//        rng.randomByte(randomness, 0, Polynomial.RANDOM);
+        secureRandom.nextBytes (randomness);
+
+        if (q == Parameter.Q_I_P)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK128(
+                randomnessExtended, 0, Polynomial.SEED * (k + 3), randomness, 0, Polynomial.RANDOM
+            );
+
+        }
+
+        if (q == Parameter.Q_III_P)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK256(
+                randomnessExtended, 0, Polynomial.SEED * (k + 3), randomness, 0, Polynomial.RANDOM
+            );
+
+        }
+
+        /*
+         * Sample the Error Polynomial Fulfilling the Criteria
+         * Choose All Error Polynomial_i in R with Entries from D_SIGMA
+         * Repeat Step at Iteration if the h Largest Entries of Error Polynomial_k Summation to L_E
+         */
+        for (int i = 0; i < k; i++)
+        {
+
+            do
+            {
+
+                if (q == Parameter.Q_I_P)
+                {
+
+                    Sample.polynomialGaussSamplerIP(errorPolynomial, n * i, randomnessExtended, Polynomial.SEED * i, ++nonce);
+
+                }
+
+                if (q == Parameter.Q_III_P)
+                {
+
+                    Sample.polynomialGaussSamplerIIIP(errorPolynomial, n * i, randomnessExtended, Polynomial.SEED * i, ++nonce);
+
+                }
+
+            }
+            while (checkPolynomial(errorPolynomial, n * i, errorBound, n, h) == true);
+
+        }
+
+        /*
+         * Sample the Secret Polynomial Fulfilling the Criteria
+         * Choose Secret Polynomial in R with Entries from D_SIGMA
+         * Repeat Step if the h Largest Entries of Secret Polynomial Summation to L_S
+         */
+        do
+        {
+
+            if (q == Parameter.Q_I_P)
+            {
+
+                Sample.polynomialGaussSamplerIP(secretPolynomial, 0, randomnessExtended, Polynomial.SEED * k, ++nonce);
+
+            }
+
+            if (q == Parameter.Q_III_P)
+            {
+
+                Sample.polynomialGaussSamplerIIIP(secretPolynomial, 0, randomnessExtended, Polynomial.SEED * k, ++nonce);
+
+            }
+
+        }
+        while (checkPolynomial(secretPolynomial, 0, secretBound, n, h) == true);
+
+        /* Generate Uniform Polynomial A */
+        Polynomial.polynomialUniform(
+            A, randomnessExtended, Polynomial.SEED * (k + 1), n, k, q, qInverse, qLogarithm, generatorA, inverseNumberTheoreticTransform
+        );
+
+        Polynomial.polynomialNumberTheoreticTransform(secretPolynomialNumberTheoreticTransform, secretPolynomial, n);
+
+        /* Compute the Public Key T = A * secretPolynomial + errorPolynomial */
+        for (int i = 0; i < k; i++)
+        {
+
+            Polynomial.polynomialMultiplication(T, n * i, A, n * i, secretPolynomialNumberTheoreticTransform, 0, n, q, qInverse);
+            Polynomial.polynomialAddition(T, n * i, T, n * i, errorPolynomial, n * i, n);
+
+            for (int j = 0; j < n; j++)
+            {
+
+                mask = (q - T[n * i + j]) >> 63;
+                T[n * i + j] -= (q & mask);
+
+            }
+
+        }
+
+        /* Pack Public and Private Keys */
+        Pack.packPrivateKey(privateKey, secretPolynomial, errorPolynomial, randomnessExtended, Polynomial.SEED * (k + 1), n, k);
+
+        if (q == Parameter.Q_I_P)
+        {
+
+            Pack.encodePublicKeyIP(publicKey, T, randomnessExtended, Polynomial.SEED * (k + 1));
+
+        }
+
+        if (q == Parameter.Q_III_P)
+        {
+
+            Pack.encodePublicKeyIIIP(publicKey, T, randomnessExtended, Polynomial.SEED * (k + 1));
+
+        }
+
+        return 0;
+
+    }
+
+    /****************************************************************************************************************************************************************
+     * Description:	Generates A Pair of Public Key and Private Key for qTESLA Signature Scheme for Provably-Secure qTESLA Security Category-1
+     *
+     * @param        publicKey                            Contains Public Key
+     * @param        privateKey                            Contains Private Key
+     * @param        secureRandom                        Source of Randomness
+     *
+     * @return 0                                    Successful Execution
+     ****************************************************************************************************************************************************************/
+    public static int generateKeyPairIP(byte[] publicKey, byte[] privateKey, SecureRandom secureRandom)
+    {
+
+        return generateKeyPair(
+
+            publicKey, privateKey, secureRandom,
+            Parameter.N_I_P, Parameter.K_I_P, Parameter.H_I_P, Parameter.Q_I_P, Parameter.Q_INVERSE_I_P, Parameter.Q_LOGARITHM_I_P,
+            Parameter.GENERATOR_A_I_P, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_I_P,
+            Parameter.XI_I_P,
+            PolynomialProvablySecure.ZETA_I_P,
+            Parameter.KEY_GENERATOR_BOUND_E_I_P, Parameter.KEY_GENERATOR_BOUND_S_I_P
+
+        );
+
+    }
+
+    /****************************************************************************************************************************************************************
+     * Description:	Generates A Pair of Public Key and Private Key for qTESLA Signature Scheme for Provably-Secure qTESLA Security Category-3
+     *
+     * @param        publicKey                            Contains Public Key
+     * @param        privateKey                            Contains Private Key
+     * @param        secureRandom                        Source of Randomness
+     *
+     * @return 0                                    Successful Execution
+     ****************************************************************************************************************************************************************/
+    public static int generateKeyPairIIIP(byte[] publicKey, byte[] privateKey, SecureRandom secureRandom)
+    {
+
+        return generateKeyPair(
+
+            publicKey, privateKey, secureRandom,
+            Parameter.N_III_P, Parameter.K_III_P, Parameter.H_III_P, Parameter.Q_III_P, Parameter.Q_INVERSE_III_P, Parameter.Q_LOGARITHM_III_P,
+            Parameter.GENERATOR_A_III_P, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_III_P,
+            Parameter.XI_III_P,
+            PolynomialProvablySecure.ZETA_III_P,
+            Parameter.KEY_GENERATOR_BOUND_E_III_P, Parameter.KEY_GENERATOR_BOUND_S_III_P
+
+        );
+
+    }
+
+    /******************************************************************************************************************************************************
+     * Description:	Generates A Signature for A Given Message According to the Ring-TESLA Signature Scheme for Heuristic qTESLA Security Category-1 and
+     * 				Security Category-3 (Option for Size or Speed)
+     *
+     * @param        message                                Message to be Signed
+     * @param        messageOffset                        Starting Point of the Message to be Signed
+     * @param        messageLength                        Length of the Message to be Signed
+     * @param        signature                            Output Package Containing Signature
+     * @param        privateKey                            Private Key
+     * @param        secureRandom                        Source of Randomness
+     * @param        n                                    Polynomial Degree
+     * @param        h                                    Number of Non-Zero Entries of Output Elements of Encryption
+     * @param        q                                    Modulus
+     * @param        qInverse
+     * @param        qLogarithm                            q <= 2 ^ qLogarithm
+     * @param        b                                    Determines the Interval the Randomness is Chosen in During Signing
+     * @param        bBit                                b = (2 ^ bBit) - 1
+     * @param        d                                    Number of Rounded Bits
+     * @param        u                                    Bound in Checking Secret Polynomial
+     * @param        rejection                            Bound in Checking Error Polynomial
+     * @param        generatorA
+     * @param        inverseNumberTheoreticTransform
+     * @param        barrettMultiplication
+     * @param        barrettDivision
+     * @param        zeta
+     *
+     * @return 0                                    Successful Execution
+     ******************************************************************************************************************************************************/
+    private static int signing(
+
+        byte[] signature,
+        final byte[] message, int messageOffset, int messageLength,
+        final byte[] privateKey, SecureRandom secureRandom,
+        int n, int h, int q, long qInverse, int qLogarithm, int b, int bBit, int d, int u, int rejection,
+        int generatorA, int inverseNumberTheoreticTransform,
+        int barrettMultiplication, int barrettDivision,
+        int[] zeta
+
+    )
+    {
+
+        byte[] C = new byte[Polynomial.HASH];
+        byte[] randomness = new byte[Polynomial.SEED];
+        byte[] randomnessInput = new byte[Polynomial.RANDOM + Polynomial.SEED + Polynomial.MESSAGE];
+        byte[] seed = new byte[Polynomial.SEED * 2];
+        byte[] temporaryRandomnessInput	= new byte[Polynomial.RANDOM];
+        int[] positionList = new int[h];
+        short[] signList = new short[h];
+        short[] secretPolynomial = new short[n];
+        short[] errorPolynomial = new short[n];
+
+        int[] A = new int[n];
+        int[] V = new int[n];
+        int[] Y = new int[n];
+        int[] Z = new int[n];
+        int[] SC = new int[n];
+        int[] EC = new int[n];
+
+        /* Domain Separator for Sampling Y */
+        int nonce = 0;
+
+        if (q == Parameter.Q_I)
+        {
+
+            Pack.decodePrivateKeyI(seed, secretPolynomial, errorPolynomial, privateKey);
+
+        }
+
+        if (q == Parameter.Q_III_SIZE)
+        {
+
+            Pack.decodePrivateKeyIIISize(seed, secretPolynomial, errorPolynomial, privateKey);
+
+        }
+
+        if (q == Parameter.Q_III_SPEED)
+        {
+
+            Pack.decodePrivateKeyIIISpeed(seed, secretPolynomial, errorPolynomial, privateKey);
+
+        }
+
+//        rng.randomByte(randomnessInput, Polynomial.RANDOM, Polynomial.RANDOM);
+         secureRandom.nextBytes (temporaryRandomnessInput);
+         System.arraycopy (temporaryRandomnessInput, 0, randomnessInput, Polynomial.RANDOM, Polynomial.RANDOM);
+
+        System.arraycopy(seed, Polynomial.SEED, randomnessInput, 0, Polynomial.SEED);
+
+        if (q == Parameter.Q_I)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK128(
+                randomnessInput, Polynomial.RANDOM + Polynomial.SEED, Polynomial.MESSAGE, message, 0, messageLength
+            );
+
+            HashUtils.secureHashAlgorithmKECCAK128(
+                randomness, 0, Polynomial.SEED, randomnessInput, 0, Polynomial.RANDOM + Polynomial.SEED + Polynomial.MESSAGE
+            );
+
+        }
+
+        if (q == Parameter.Q_III_SIZE || q == Parameter.Q_III_SPEED)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK256(
+                randomnessInput, Polynomial.RANDOM + Polynomial.SEED, Polynomial.MESSAGE, message, 0, messageLength
+            );
+
+            HashUtils.secureHashAlgorithmKECCAK256(
+                randomness, 0, Polynomial.SEED, randomnessInput, 0, Polynomial.RANDOM + Polynomial.SEED + Polynomial.MESSAGE
+            );
+
+        }
+
+        Polynomial.polynomialUniform(A, seed, 0, n, q, qInverse, qLogarithm, generatorA, inverseNumberTheoreticTransform);
+
+        /* Loop Due to Possible Rejection */
+        while (true)
+        {
+
+            /* Sample Y Uniformly Random from -B to B */
+            Sample.sampleY(Y, randomness, 0, ++nonce, n, q, b, bBit);
+
+            /* V = A * Y Modulo Q */
+            Polynomial.polynomialMultiplication(V, A, Y, n, q, qInverse, zeta);
+
+            hashFunction(C, 0, V, randomnessInput, Polynomial.RANDOM + Polynomial.SEED, n, d, q);
+
+            /* Generate C = EncodeC (C') Where C' is the Hashing of V Together with Message */
+            Sample.encodeC(positionList, signList, C, 0, n, h);
+
+            Polynomial.sparsePolynomialMultiplication16(SC, secretPolynomial, positionList, signList, n, h);
+
+            /* Z = Y + EC Modulo Q */
+            Polynomial.polynomialAddition(Z, Y, SC, n);
+
+            /* Rejection Sampling */
+            if (testRejection(Z, n, b, u) == true)
+            {
+
+                continue;
+
+            }
+
+            Polynomial.sparsePolynomialMultiplication16(EC, errorPolynomial, positionList, signList, n, h);
+
+            /* V = V - EC modulo Q */
+            Polynomial.polynomialSubtractionCorrection(V, V, EC, n, q);
+
+            if (testV(V, n, d, q, rejection) == true)
+            {
+                continue;
+            }
+
+            if (q == Parameter.Q_I)
+            {
+                /* Pack Signature */
+                Pack.encodeSignature(signature, 0, C, 0, Z, n, d);
+            }
+
+            if (q == Parameter.Q_III_SIZE)
+            {
+                /* Pack Signature */
+                Pack.encodeSignature(signature, 0, C, 0, Z, n, d);
+            }
+
+            if (q == Parameter.Q_III_SPEED)
+            {
+                /* Pack Signature */
+                Pack.encodeSignatureIIISpeed(signature, 0, C, 0, Z);
+            }
+
+            return 0;
+
+        }
+
+    }
+
+    /*****************************************************************************************************************************************************
+     * Description:	Generates A Signature for A Given Message According to the Ring-TESLA Signature Scheme for Heuristic qTESLA Security Category-1
+     *
+     * @param        message                                Message to be Signed
+     * @param        messageOffset                        Starting Point of the Message to be Signed
+     * @param        messageLength                        Length of the Message to be Signed
+     * @param        signature                            Output Package Containing Signature
+     * @param        privateKey                            Private Key
+     * @param        secureRandom                        Source of Randomness
+     *
+     * @return 0                                    Successful Execution
+     *****************************************************************************************************************************************************/
+    static int signingI(
+
+        byte[] signature,
+        final byte[] message, int messageOffset, int messageLength,
+        final byte[] privateKey, SecureRandom secureRandom
+
+    )
+    {
+
+        return signing(
+
+            signature,
+            message, messageOffset, messageLength,
+            privateKey, secureRandom,
+            Parameter.N_I, Parameter.H_I, Parameter.Q_I, Parameter.Q_INVERSE_I, Parameter.Q_LOGARITHM_I,
+            Parameter.B_I, Parameter.B_BIT_I, Parameter.D_I, Parameter.U_I, Parameter.REJECTION_I,
+            Parameter.GENERATOR_A_I, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_I,
+            Parameter.BARRETT_MULTIPLICATION_I, Parameter.BARRETT_DIVISION_I,
+            PolynomialHeuristic.ZETA_I
+
+        );
+
+    }
+
+    /*****************************************************************************************************************************************************
+     * Description:	Generates A Signature for A Given Message According to the Ring-TESLA Signature Scheme for Heuristic qTESLA Security Category-3
+     * 				(Option for Size)
+     *
+     * @param        message                                Message to be Signed
+     * @param        messageOffset                        Starting Point of the Message to be Signed
+     * @param        messageLength                        Length of the Message to be Signed
+     * @param        signature                            Output Package Containing Signature
+     * @param        privateKey                            Private Key
+     * @param        secureRandom                        Source of Randomness
+     *
+     * @return 0                                    Successful Execution
+     *****************************************************************************************************************************************************/
+    static int signingIIISize(
+
+        byte[] signature,
+        final byte[] message, int messageOffset, int messageLength,
+        final byte[] privateKey, SecureRandom secureRandom
+
+    )
+    {
+
+        return signing(
+
+            signature,
+            message, messageOffset, messageLength,
+            privateKey, secureRandom,
+            Parameter.N_III_SIZE, Parameter.H_III_SIZE, Parameter.Q_III_SIZE, Parameter.Q_INVERSE_III_SIZE, Parameter.Q_LOGARITHM_III_SIZE,
+            Parameter.B_III_SIZE, Parameter.B_BIT_III_SIZE, Parameter.D_III_SIZE, Parameter.U_III_SIZE, Parameter.REJECTION_III_SIZE,
+            Parameter.GENERATOR_A_III_SIZE, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_III_SIZE,
+            Parameter.BARRETT_MULTIPLICATION_III_SIZE, Parameter.BARRETT_DIVISION_III_SIZE,
+            PolynomialHeuristic.ZETA_III_SIZE
+
+        );
+
+    }
+
+    /****************************************************************************************************************************************************
+     * Description:	Generates A Signature for A Given Message According to the Ring-TESLA Signature Scheme for Heuristic qTESLA Security Category-3
+     *				(Option for Speed)
+     *
+     * @param        message                                Message to be Signed
+     * @param        messageOffset                        Starting Point of the Message to be Signed
+     * @param        messageLength                        Length of the Message to be Signed
+     * @param        signature                            Output Package Containing Signature
+     * @param        privateKey                            Private Key
+     * @param        secureRandom                        Source of Randomness
+     *
+     * @return 0                                    Successful Execution
+     ****************************************************************************************************************************************************/
+    static int signingIIISpeed(
+
+        byte[] signature,
+        final byte[] message, int messageOffset, int messageLength,
+        final byte[] privateKey, SecureRandom secureRandom
+
+    )
+    {
+
+        return signing(
+
+            signature,
+            message, messageOffset, messageLength,
+            privateKey, secureRandom,
+            Parameter.N_III_SPEED, Parameter.H_III_SPEED, Parameter.Q_III_SPEED, Parameter.Q_INVERSE_III_SPEED, Parameter.Q_LOGARITHM_III_SPEED,
+            Parameter.B_III_SPEED, Parameter.B_BIT_III_SPEED, Parameter.D_III_SPEED, Parameter.U_III_SPEED, Parameter.REJECTION_III_SPEED,
+            Parameter.GENERATOR_A_III_SPEED, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_III_SPEED,
+            Parameter.BARRETT_MULTIPLICATION_III_SPEED, Parameter.BARRETT_DIVISION_III_SPEED,
+            PolynomialHeuristic.ZETA_III_SPEED
+
+        );
+
+    }
+
+    /*****************************************************************************************************************************************************
+     * Description:	Generates A Signature for A Given Message According to the Ring-TESLA Signature Scheme for Provably-Secure qTESLA Security Category-1
+     *				and Category-3
+     *
+     * @param        message                                Message to be Signed
+     * @param        messageOffset                        Starting Point of the Message to be Signed
+     * @param        messageLength                        Length of the Message to be Signed
+     * @param        signature                            Output Package Containing Signature
+     * @param        privateKey                            Private Key
+     * @param        secureRandom                        Source of Randomness
+     * @param        n                                    Polynomial Degree
+     * @param        k                                    Number of Ring-Learning-With-Errors Samples
+     * @param        h                                    Number of Non-Zero Entries of Output Elements of Encryption
+     * @param        q                                    Modulus
+     * @param        qInverse
+     * @param        qLogarithm                            q <= 2 ^ qLogarithm
+     * @param        b                                    Determines the Interval the Randomness is Chosen in During Signing
+     * @param        bBit                                b = (2 ^ bBit) - 1
+     * @param        d                                    Number of Rounded Bits
+     * @param        u                                    Bound in Checking Secret Polynomial
+     * @param        rejection                            Bound in Checking Error Polynomial
+     * @param        generatorA
+     * @param        inverseNumberTheoreticTransform
+     * @param        privateKeySize                        Size of the Private Key
+     * @param        barrettMultiplication
+     * @param        barrettDivision
+     *
+     * @return 0                                    Successful Execution
+     *****************************************************************************************************************************************************/
+    private static int signing(
+
+        byte[] signature,
+        final byte[] message, int messageOffset, int messageLength,
+        final byte[] privateKey, SecureRandom secureRandom,
+        int n, int k, int h, int q, long qInverse, int qLogarithm, int b, int bBit, int d, int u, int rejection,
+        int generatorA, int inverseNumberTheoreticTransform, int privateKeySize,
+        int barrettMultiplication, int barrettDivision
+
+    )
+    {
+
+        byte[] C = new byte[Polynomial.HASH];
+        byte[] randomness = new byte[Polynomial.SEED];
+        byte[] randomnessInput = new byte[Polynomial.RANDOM + Polynomial.SEED + Polynomial.MESSAGE];
+        byte[] temporaryRandomnessInput	= new byte[Polynomial.RANDOM];
+        int[] positionList = new int[h];
+        short[] signList = new short[h];
+
+        long[] A = new long[n * k];
+        long[] V = new long[n * k];
+        long[] Y = new long[n];
+        long[] numberTheoreticTransformY = new long[n];
+        long[] Z = new long[n];
+        long[] SC = new long[n];
+        long[] EC = new long[n * k];
+
+        boolean response = false;
+
+        /* Domain Separator for Sampling Y */
+        int nonce = 0;
+
+//        rng.randomByte(randomnessInput, Polynomial.RANDOM, Polynomial.RANDOM);
+        secureRandom.nextBytes (temporaryRandomnessInput);
+        System.arraycopy (temporaryRandomnessInput, 0, randomnessInput, Polynomial.RANDOM, Polynomial.RANDOM);
+        System.arraycopy(privateKey, privateKeySize - Polynomial.SEED, randomnessInput, 0, Polynomial.SEED);
+
+        if (q == Parameter.Q_I_P)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK128(
+                randomnessInput, Polynomial.RANDOM + Polynomial.SEED, Polynomial.MESSAGE, message, 0, messageLength
+            );
+
+
+            HashUtils.secureHashAlgorithmKECCAK128(
+                randomness, 0, Polynomial.SEED, randomnessInput, 0, Polynomial.RANDOM + Polynomial.SEED + Polynomial.MESSAGE
+            );
+
+        }
+
+        if (q == Parameter.Q_III_P)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK256(
+                randomnessInput, Polynomial.RANDOM + Polynomial.SEED, Polynomial.MESSAGE, message, 0, messageLength
+            );
+
+
+            HashUtils.secureHashAlgorithmKECCAK256(
+                randomness, 0, Polynomial.SEED, randomnessInput, 0, Polynomial.RANDOM + Polynomial.SEED + Polynomial.MESSAGE
+            );
+
+        }
+
+        Polynomial.polynomialUniform(
+            A, privateKey, privateKeySize - 2 * Polynomial.SEED, n, k, q, qInverse, qLogarithm, generatorA, inverseNumberTheoreticTransform
+        );
+
+        /* Loop Due to Possible Rejection */
+        while (true)
+        {
+
+            /* Sample Y Uniformly Random from -B to B */
+            Sample.sampleY(Y, randomness, 0, ++nonce, n, q, b, bBit);
+
+            Polynomial.polynomialNumberTheoreticTransform(numberTheoreticTransformY, Y, n);
+
+            /* V_i = A_i * Y Modulo Q for All i */
+            for (int i = 0; i < k; i++)
+            {
+
+                Polynomial.polynomialMultiplication(V, n * i, A, n * i, numberTheoreticTransformY, 0, n, q, qInverse);
+
+            }
+
+            hashFunction(C, 0, V, randomnessInput, Polynomial.RANDOM + Polynomial.SEED, n, k, d, q);
+
+            /* Generate C = EncodeC (C') Where C' is the Hashing of V Together with Message */
+            Sample.encodeC(positionList, signList, C, 0, n, h);
+
+            Polynomial.sparsePolynomialMultiplication8(SC, 0, privateKey, 0, positionList, signList, n, h);
+
+            /* Z = Y + EC modulo Q */
+            Polynomial.polynomialAddition(Z, 0, Y, 0, SC, 0, n);
+
+            /* Rejection Sampling */
+            if (testRejection(Z, n, b, u) == true)
+            {
+
+                continue;
+
+            }
+
+            for (int i = 0; i < k; i++)
+            {
+
+                Polynomial.sparsePolynomialMultiplication8(EC, n * i, privateKey, n * (i + 1), positionList, signList, n, h);
+
+                /* V_i = V_i - EC_i Modulo Q for All k */
+                Polynomial.polynomialSubtraction(V, n * i, V, n * i, EC, n * i, n, q, barrettMultiplication, barrettDivision);
+
+                response = testV(V, n * i, n, d, q, rejection);
+
+                if (response == true)
+                {
+
+                    break;
+
+                }
+
+            }
+
+            if (response == true)
+            {
+
+                continue;
+
+            }
+
+            if (q == Parameter.Q_I_P)
+            {
+                /* Pack Signature */
+                Pack.encodeSignatureIP(signature, 0, C, 0, Z);
+
+            }
+
+            if (q == Parameter.Q_III_P)
+            {
+                /* Pack Signature */
+                Pack.encodeSignatureIIIP(signature, 0, C, 0, Z);
+            }
+
+            return 0;
+
+        }
+
+    }
+
+    /*****************************************************************************************************************************************************
+     * Description:	Generates A Signature for A Given Message According to the Ring-TESLA Signature Scheme for Provably-Secure qTESLA Security Category-1
+     *
+     * @param        message                                Message to be Signed
+     * @param        messageOffset                        Starting Point of the Message to be Signed
+     * @param        messageLength                        Length of the Message to be Signed
+     * @param        signature                            Output Package Containing Signature
+     * @param        privateKey                            Private Key
+     * @param        secureRandom                        Source of Randomness
+     *
+     * @return 0                                    Successful Execution
+     *****************************************************************************************************************************************************/
+    public static int signingIP(
+
+        byte[] signature,
+        final byte[] message, int messageOffset, int messageLength,
+        final byte[] privateKey, SecureRandom secureRandom
+
+    )
+    {
+
+        return signing(
+
+            signature,
+            message, messageOffset, messageLength,
+            privateKey, secureRandom,
+            Parameter.N_I_P, Parameter.K_I_P, Parameter.H_I_P, Parameter.Q_I_P, Parameter.Q_INVERSE_I_P, Parameter.Q_LOGARITHM_I_P,
+            Parameter.B_I_P, Parameter.B_BIT_I_P, Parameter.D_I_P, Parameter.U_I_P, Parameter.REJECTION_I_P,
+            Parameter.GENERATOR_A_I_P, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_I_P, Polynomial.PRIVATE_KEY_I_P,
+            Parameter.BARRETT_MULTIPLICATION_I_P, Parameter.BARRETT_DIVISION_I_P
+
+        );
+
+    }
+
+    /**********************************************************************************************************************************************
+     * Description:	Generates A Signature for A Given Message According to the Ring-TESLA Signature Scheme for Provably-Secure
+     * 				qTESLA Security Category-3
+     *
+     * @param        message                                Message to be Signed
+     * @param        messageOffset                        Starting Point of the Message to be Signed
+     * @param        messageLength                        Length of the Message to be Signed
+     * @param        signature                            Output Package Containing Signature
+     * @param        privateKey                            Private Key
+     * @param        secureRandom                        Source of Randomness
+     *
+     * @return 0                                    Successful Execution
+     **********************************************************************************************************************************************/
+    public static int signingIIIP(
+
+        byte[] signature,
+        final byte[] message, int messageOffset, int messageLength,
+        final byte[] privateKey, SecureRandom secureRandom
+
+    )
+    {
+
+        return signing(
+
+            signature,
+            message, messageOffset, messageLength,
+            privateKey, secureRandom,
+            Parameter.N_III_P, Parameter.K_III_P, Parameter.H_III_P, Parameter.Q_III_P, Parameter.Q_INVERSE_III_P, Parameter.Q_LOGARITHM_III_P,
+            Parameter.B_III_P, Parameter.B_BIT_III_P, Parameter.D_III_P, Parameter.U_III_P, Parameter.REJECTION_III_P,
+            Parameter.GENERATOR_A_III_P, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_III_P, Polynomial.PRIVATE_KEY_III_P,
+            Parameter.BARRETT_MULTIPLICATION_III_P, Parameter.BARRETT_DIVISION_III_P
+
+        );
+
+    }
+
+    /*********************************************************************************************************************************
+     * Description:	Extracts the Original Message and Checks Whether the Generated Signature is Valid for A Given Signature Package
+     * 				for Heuristic qTESLA Security Category-1 and Security Category-3 (Option for Size of Speed)
+     *
+     * @param        signature                            Given Signature Package
+     * @param        signatureOffset                        Starting Point of the Given Signature Package
+     * @param        signatureLength                        Length of the Given Signature Package
+     * @param        message                                Original (Signed) Message
+     * @param        publicKey                            Public Key
+     * @param        n                                    Polynomial Degree
+     * @param        h                                    Number of Non-Zero Entries of Output Elements of Encryption
+     * @param        q                                    Modulus
+     * @param        qInverse
+     * @param        qLogarithm                            q <= 2 ^ qLogarithm
+     * @param        b                                    Determines the Interval the Randomness is Chosen in During Signing
+     * @param        d                                    Number of Rounded Bits
+     * @param        u                                    Bound in Checking Secret Polynomial
+     * @param        r
+     * @param        signatureSize                        Size of the Given Signature Package
+     * @param        generatorA
+     * @param        inverseNumberTheoreticTransform
+     * @param        barrettMultiplication
+     * @param        barrettDivision
+     * @param        zeta
+     *
+     * @return 0                                    Valid Signature
+     * 				< 0									Invalid Signature
+     *********************************************************************************************************************************/
+    private static int verifying(
+
+        byte[] message,
+        final byte[] signature, int signatureOffset, int signatureLength,
+        final byte[] publicKey,
+        int n, int h, int q, long qInverse, int qLogarithm, int b, int d, int u, int r, int signatureSize,
+        int generatorA, int inverseNumberTheoreticTransform,
+        int barrettMultiplication, int barrettDivision,
+        int[] zeta
+
+    )
+    {
+
+        byte[] C = new byte[Polynomial.HASH];
+        byte[] cSignature = new byte[Polynomial.HASH];
+        byte[] seed = new byte[Polynomial.SEED];
+        byte[] hashMessage = new byte[Polynomial.MESSAGE];
+        int[] newPublicKey = new int[n];
+
+        int[] positionList = new int[h];
+        short[] signList = new short[h];
+
+        int[] W = new int[n];
+        int[] Z = new int[n];
+        int[] TC = new int[n];
+        int[] A = new int[n];
+
+        if (signatureLength < signatureSize)
+        {
+
+            return -1;
+
+        }
+
+        if (q == Parameter.Q_I || q == Parameter.Q_III_SIZE)
+        {
+
+            Pack.decodeSignature(C, Z, signature, signatureOffset, n, d);
+
+        }
+
+        if (q == Parameter.Q_III_SPEED)
+        {
+
+            Pack.decodeSignatureIIISpeed(C, Z, signature, signatureOffset);
+
+        }
+
+        /* Check Norm of Z */
+        if (testZ(Z, n, b, u) == true)
+        {
+
+            return -2;
+
+        }
+
+        if (q == Parameter.Q_I || q == Parameter.Q_III_SIZE)
+        {
+
+            Pack.decodePublicKey(newPublicKey, seed, 0, publicKey, n, qLogarithm);
+
+        }
+
+        if (q == Parameter.Q_III_SPEED)
+        {
+
+            Pack.decodePublicKeyIIISpeed(newPublicKey, seed, 0, publicKey);
+
+        }
+
+        /* Generate A Polynomial */
+        Polynomial.polynomialUniform(A, seed, 0, n, q, qInverse, qLogarithm, generatorA, inverseNumberTheoreticTransform);
+
+        Sample.encodeC(positionList, signList, C, 0, n, h);
+
+        /* W = A * Z - TC */
+        Polynomial.sparsePolynomialMultiplication32(TC, newPublicKey, positionList, signList, n, h);
+
+        Polynomial.polynomialMultiplication(W, A, Z, n, q, qInverse, zeta);
+
+        Polynomial.polynomialSubtractionMontgomery(W, W, TC, n, q, qInverse, r);
+
+        if (q == Parameter.Q_I)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK128(
+                hashMessage, 0, Polynomial.MESSAGE, message, 0, message.length
+            );
+
+        }
+
+        if (q == Parameter.Q_III_SIZE || q == Parameter.Q_III_SPEED)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK256(
+                hashMessage, 0, Polynomial.MESSAGE, message, 0, message.length
+            );
+
+        }
+
+        /* Obtain the Hash Symbol */
+        hashFunction(cSignature, 0, W, hashMessage, 0, n, d, q);
+
+        /* Check if Same With One from Signature */
+        if (CommonFunction.memoryEqual(C, 0, cSignature, 0, Polynomial.HASH) == false)
+        {
+            return -3;
+        }
+
+        return 0;
+
+    }
+
+    /*******************************************************************************************************
+     * Description:	Extracts the Original Message and Checks Whether the Generated Signature is Valid for
+     * 				A Given Signature Package for Heuristic qTESLA Security Category-1
+     *
+     * @param        signature                            Given Signature Package
+     * @param        signatureOffset                        Starting Point of the Given Signature Package
+     * @param        signatureLength                        Length of the Given Signature Package
+     * @param        message                                Original (Signed) Message
+     * @param        publicKey                            Public Key
+     *
+     * @return 0                                    Valid Signature
+     * 				< 0									Invalid Signature
+     *******************************************************************************************************/
+    static int verifyingI(
+
+        byte[] message,
+        final byte[] signature, int signatureOffset, int signatureLength,
+        final byte[] publicKey
+
+    )
+    {
+
+        return verifying(
+
+            message,
+            signature, signatureOffset, signatureLength,
+            publicKey,
+            Parameter.N_I, Parameter.H_I, Parameter.Q_I, Parameter.Q_INVERSE_I, Parameter.Q_LOGARITHM_I,
+            Parameter.B_I, Parameter.D_I, Parameter.U_I, Parameter.R_I,
+            Polynomial.SIGNATURE_I,
+            Parameter.GENERATOR_A_I, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_I,
+            Parameter.BARRETT_MULTIPLICATION_I, Parameter.BARRETT_DIVISION_I,
+            PolynomialHeuristic.ZETA_I
+
+        );
+
+    }
+
+    /******************************************************************************************************
+     * Description:	Extracts the Original Message and Checks Whether the Generated Signature is Valid for
+     *				A Given Signature Package for Heuristic qTESLA Security Category-3 (Option for Size)
+     *
+     * @param        signature                            Given Signature Package
+     * @param        signatureOffset                        Starting Point of the Given Signature Package
+     * @param        signatureLength                        Length of the Given Signature Package
+     * @param        message                                Original (Signed) Message
+     * @param        publicKey                            Public Key
+     *
+     * @return 0                                    Valid Signature
+     * 				< 0									Invalid Signature
+     ******************************************************************************************************/
+    static int verifyingIIISize(
+
+        byte[] message,
+        final byte[] signature, int signatureOffset, int signatureLength,
+        final byte[] publicKey
+
+    )
+    {
+
+        return verifying(
+
+            message,
+            signature, signatureOffset, signatureLength,
+            publicKey,
+            Parameter.N_III_SIZE, Parameter.H_III_SIZE,
+            Parameter.Q_III_SIZE, Parameter.Q_INVERSE_III_SIZE, Parameter.Q_LOGARITHM_III_SIZE,
+            Parameter.B_III_SIZE, Parameter.D_III_SIZE, Parameter.U_III_SIZE, Parameter.R_III_SIZE,
+            Polynomial.SIGNATURE_III_SIZE,
+            Parameter.GENERATOR_A_III_SIZE, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_III_SIZE,
+            Parameter.BARRETT_MULTIPLICATION_III_SIZE, Parameter.BARRETT_DIVISION_III_SIZE,
+            PolynomialHeuristic.ZETA_III_SIZE
+
+        );
+
+    }
+
+    /**********************************************************************************************************
+     * Description:	Extracts the Original Message and Checks Whether the Generated Signature is Valid for
+     * 				A Given Signature Package for Heuristic qTESLA Security Category-3 (Option for Speed)
+     *
+     * @param        signature                            Given Signature Package
+     * @param        signatureOffset                        Starting Point of the Given Signature Package
+     * @param        signatureLength                        Length of the Given Signature Package
+     * @param        message                                Original (Signed) Message
+     * @param        publicKey                            Public Key
+     *
+     * @return 0                                    Valid Signature
+     * 				< 0									Invalid Signature
+     **********************************************************************************************************/
+    static int verifyingIIISpeed(
+
+        byte[] message,
+        final byte[] signature, int signatureOffset, int signatureLength,
+        final byte[] publicKey
+
+    )
+    {
+
+        return verifying(
+
+            message,
+            signature, signatureOffset, signatureLength,
+            publicKey,
+            Parameter.N_III_SPEED, Parameter.H_III_SPEED,
+            Parameter.Q_III_SPEED, Parameter.Q_INVERSE_III_SPEED, Parameter.Q_LOGARITHM_III_SPEED,
+            Parameter.B_III_SPEED, Parameter.D_III_SPEED, Parameter.U_III_SPEED, Parameter.R_III_SPEED,
+            Polynomial.SIGNATURE_III_SPEED,
+            Parameter.GENERATOR_A_III_SPEED, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_III_SPEED,
+            Parameter.BARRETT_MULTIPLICATION_III_SPEED, Parameter.BARRETT_DIVISION_III_SPEED,
+            PolynomialHeuristic.ZETA_III_SPEED
+
+        );
+
+    }
+
+    /**************************************************************************************************************************
+     * Description:	Extracts the Original Message and Checks Whether the Generated Signature is Valid for A Given Signature
+     * 				Package for Provably-Secure qTESLA Security Category-1 and Category-3
+     *
+     * @param        signature                            Given Signature Package
+     * @param        signatureOffset                        Starting Point of the Given Signature Package
+     * @param        signatureLength                        Length of the Given Signature Package
+     * @param        message                                Original (Signed) Message
+     * @param        publicKey                            Public Key
+     * @param        n                                    Polynomial Degree
+     * @param        k                                    Number of Ring-Learning-With-Errors Samples
+     * @param        h                                    Number of Non-Zero Entries of Output Elements of Encryption
+     * @param        q                                    Modulus
+     * @param        qInverse
+     * @param        qLogarithm                            q <= 2 ^ qLogarithm
+     * @param        b                                    Determines the Interval the Randomness is Chosen in During Signing
+     * @param        d                                    Number of Rounded Bits
+     * @param        u                                    Bound in Checking Secret Polynomial
+     * @param        generatorA
+     * @param        inverseNumberTheoreticTransform
+     * @param        barrettMultiplication
+     * @param        barrettDivision
+     * @param        zeta
+     *
+     * @return 0                                    Valid Signature
+     * 				< 0									Invalid Signature
+     *************************************************************************************************************************/
+    private static int verifying(
+
+        byte[] message,
+        final byte[] signature, int signatureOffset, int signatureLength,
+        final byte[] publicKey,
+        int n, int k, int h, int q, long qInverse, int qLogarithm, int b, int d, int u, int signatureSize,
+        int generatorA, int inverseNumberTheoreticTransform,
+        int barrettMultiplication, int barrettDivision,
+        long[] zeta
+
+    )
+    {
+
+        byte[] C = new byte[Polynomial.HASH];
+        byte[] cSignature = new byte[Polynomial.HASH];
+        byte[] seed = new byte[Polynomial.SEED];
+        byte[] hashMessage = new byte[Polynomial.MESSAGE];
+        int[] newPublicKey = new int[n * k];
+
+        int[] positionList = new int[h];
+        short[] signList = new short[h];
+
+        long[] W = new long[n * k];
+        long[] Z = new long[n];
+        long[] numberTheoreticTransformZ = new long[n];
+        long[] TC = new long[n * k];
+        long[] A = new long[n * k];
+
+        if (signatureLength < signatureSize)
+        {
+
+            return -1;
+
+        }
+
+        if (q == Parameter.Q_I_P)
+        {
+
+            Pack.decodeSignatureIP(C, Z, signature, signatureOffset);
+
+        }
+
+        if (q == Parameter.Q_III_P)
+        {
+
+            Pack.decodeSignatureIIIP(C, Z, signature, signatureOffset);
+
+        }
+
+        /* Check Norm of Z */
+        if (testZ(Z, n, b, u) == true)
+        {
+
+            return -2;
+
+        }
+
+        if (q == Parameter.Q_I_P)
+        {
+
+            Pack.decodePublicKeyIP(newPublicKey, seed, 0, publicKey);
+
+        }
+
+        if (q == Parameter.Q_III_P)
+        {
+
+            Pack.decodePublicKeyIIIP(newPublicKey, seed, 0, publicKey);
+
+        }
+
+        /* Generate A Polynomial */
+        Polynomial.polynomialUniform(A, seed, 0, n, k, q, qInverse, qLogarithm, generatorA, inverseNumberTheoreticTransform);
+
+        Sample.encodeC(positionList, signList, C, 0, n, h);
+
+        Polynomial.polynomialNumberTheoreticTransform(numberTheoreticTransformZ, Z, n);
+
+        /* W_i = A_i * Z_i - TC_i for All i */
+        for (int i = 0; i < k; i++)
+        {
+
+            Polynomial.polynomialMultiplication(W, n * i, A, n * i, numberTheoreticTransformZ, 0, n, q, qInverse);
+
+            Polynomial.sparsePolynomialMultiplication32(
+                TC, n * i, newPublicKey, n * i, positionList, signList, n, h, q, barrettMultiplication, barrettDivision
+            );
+
+            Polynomial.polynomialSubtraction(W, n * i, W, n * i, TC, n * i, n, q, barrettMultiplication, barrettDivision);
+
+        }
+
+        if (q == Parameter.Q_I_P)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK128(
+                hashMessage, 0, Polynomial.MESSAGE, message, 0, message.length
+            );
+
+        }
+
+        if (q == Parameter.Q_III_P)
+        {
+
+            HashUtils.secureHashAlgorithmKECCAK256(
+                hashMessage, 0, Polynomial.MESSAGE, message, 0, message.length
+            );
+
+        }
+
+        /* Obtain the Hash Symbol */
+        hashFunction(cSignature, 0, W, hashMessage, 0, n, k, d, q);
+
+        /* Check if Same with One from Signature */
+        if (CommonFunction.memoryEqual(C, 0, cSignature, 0, Polynomial.HASH) == false)
+        {
+            return -3;
+        }
+
+        return 0;
+
+    }
+
+    /*****************************************************************************************************
+     * Description:	Extracts the Original Message and Checks Whether the Generated Signature is Valid for
+     * 				A Given Signature Package for Provably-Secure qTESLA Security Category-1
+     *
+     * @param        signature                            Given Signature Package
+     * @param        signatureOffset                        Starting Point of the Given Signature Package
+     * @param        signatureLength                        Length of the Given Signature Package
+     * @param        message                                Original (Signed) Message
+     * @param        publicKey                            Public Key
+     *
+     * @return 0                                    Valid Signature
+     * 				< 0									Invalid Signature
+     *****************************************************************************************************/
+    static int verifyingPI(
+        byte[] message,
+        final byte[] signature, int signatureOffset, int signatureLength,
+        final byte[] publicKey
+    )
+    {
+
+        return verifying(
+
+            message,
+            signature, signatureOffset, signatureLength,
+            publicKey,
+            Parameter.N_I_P, Parameter.K_I_P, Parameter.H_I_P,
+            Parameter.Q_I_P, Parameter.Q_INVERSE_I_P, Parameter.Q_LOGARITHM_I_P,
+            Parameter.B_I_P, Parameter.D_I_P, Parameter.U_I_P, Polynomial.SIGNATURE_I_P,
+            Parameter.GENERATOR_A_I_P, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_I_P,
+            Parameter.BARRETT_MULTIPLICATION_I_P, Parameter.BARRETT_DIVISION_I_P,
+            PolynomialProvablySecure.ZETA_I_P
+
+        );
+
+    }
+
+    /*****************************************************************************************************
+     * Description:	Extracts the Original Message and Checks Whether the Generated Signature is Valid for
+     * 				A Given Signature Package for Provably-Secure qTESLA Security Category-3
+     *
+     * @param        signature                            Given Signature Package
+     * @param        signatureOffset                        Starting Point of the Given Signature Package
+     * @param        signatureLength                        Length of the Given Signature Package
+     * @param        message                                Original (Signed) Message
+     * @param        publicKey                            Public Key
+     *
+     * @return 0                                    Valid Signature
+     * 				< 0									Invalid Signature
+     *****************************************************************************************************/
+    static int verifyingPIII(
+
+        byte[] message,
+        final byte[] signature, int signatureOffset, int signatureLength,
+        final byte[] publicKey
+
+    )
+    {
+        return verifying(
+            message,
+            signature, signatureOffset, signatureLength,
+            publicKey,
+            Parameter.N_III_P, Parameter.K_III_P, Parameter.H_III_P,
+            Parameter.Q_III_P, Parameter.Q_INVERSE_III_P, Parameter.Q_LOGARITHM_III_P,
+            Parameter.B_III_P, Parameter.D_III_P, Parameter.U_III_P, Polynomial.SIGNATURE_III_P,
+            Parameter.GENERATOR_A_III_P, Parameter.INVERSE_NUMBER_THEORETIC_TRANSFORM_III_P,
+            Parameter.BARRETT_MULTIPLICATION_III_P, Parameter.BARRETT_DIVISION_III_P,
+            PolynomialProvablySecure.ZETA_III_P
+        );
+    }
+
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAKeyGenerationParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAKeyGenerationParameters.java
new file mode 100644
index 000000000..d63d8ce22
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAKeyGenerationParameters.java
@@ -0,0 +1,39 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters;
+
+/**
+ * qTESLA key-pair generation parameters.
+ */
+public class QTESLAKeyGenerationParameters
+    extends KeyGenerationParameters
+{
+    private final int securityCategory;
+
+    /**
+     * Base constructor - provide the qTESLA security category and a source of randomness.
+     *
+     * @param securityCategory the security category to generate the parameters for.
+     * @param random           the random byte source.
+     */
+    public QTESLAKeyGenerationParameters(int securityCategory, SecureRandom random)
+    {
+        super(random, -1);
+
+        QTESLASecurityCategory.getPrivateSize(securityCategory);  // check the category is valid
+
+        this.securityCategory = securityCategory;
+    }
+
+    /**
+      * Return the security category for these parameters.
+      *
+      * @return the security category for keys generated using these parameters.
+      */
+    public int getSecurityCategory()
+    {
+        return securityCategory;
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAKeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAKeyPairGenerator.java
new file mode 100644
index 000000000..36ab2777d
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAKeyPairGenerator.java
@@ -0,0 +1,78 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPairGenerator;
+import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters;
+
+/**
+ * Key-pair generator for qTESLA keys.
+ */
+public final class QTESLAKeyPairGenerator
+    implements AsymmetricCipherKeyPairGenerator
+{
+    /**
+     * qTESLA Security Category
+     */
+    private int securityCategory;
+    private SecureRandom secureRandom;
+
+    /**
+     * Initialize the generator with a security category and a source of randomness.
+     *
+     * @param param a {@link QTESLAKeyGenerationParameters} object.
+     */
+    public void init(
+        KeyGenerationParameters param)
+    {
+        QTESLAKeyGenerationParameters parameters = (QTESLAKeyGenerationParameters)param;
+
+        this.secureRandom = parameters.getRandom();
+        this.securityCategory = parameters.getSecurityCategory();
+    }
+
+    /**
+     * Generate a key-pair.
+     *
+     * @return a matching key-pair consisting of (QTESLAPublicKeyParameters, QTESLAPrivateKeyParameters).
+     */
+    public AsymmetricCipherKeyPair generateKeyPair()
+    {
+        byte[] privateKey = allocatePrivate(securityCategory);
+        byte[] publicKey = allocatePublic(securityCategory);
+
+        switch (securityCategory)
+        {
+        case QTESLASecurityCategory.HEURISTIC_I:
+            QTESLA.generateKeyPairI(publicKey, privateKey, secureRandom);
+            break;
+        case QTESLASecurityCategory.HEURISTIC_III_SIZE:
+            QTESLA.generateKeyPairIIISize(publicKey, privateKey, secureRandom);
+            break;
+        case QTESLASecurityCategory.HEURISTIC_III_SPEED:
+            QTESLA.generateKeyPairIIISpeed(publicKey, privateKey, secureRandom);
+            break;
+        case QTESLASecurityCategory.PROVABLY_SECURE_I:
+            QTESLA.generateKeyPairIP(publicKey, privateKey, secureRandom);
+            break;
+        case QTESLASecurityCategory.PROVABLY_SECURE_III:
+            QTESLA.generateKeyPairIIIP(publicKey, privateKey, secureRandom);
+            break;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+
+        return new AsymmetricCipherKeyPair(new QTESLAPublicKeyParameters(securityCategory, publicKey), new QTESLAPrivateKeyParameters(securityCategory, privateKey));
+    }
+
+    private byte[] allocatePrivate(int securityCategory)
+    {
+        return new byte[QTESLASecurityCategory.getPrivateSize(securityCategory)];
+    }
+
+    private byte[] allocatePublic(int securityCategory)
+    {
+        return new byte[QTESLASecurityCategory.getPublicSize(securityCategory)];
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAPrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAPrivateKeyParameters.java
new file mode 100644
index 000000000..5ec37c4a9
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAPrivateKeyParameters.java
@@ -0,0 +1,60 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.fr.third.org.bouncycastle.util.Arrays;
+
+/**
+ * qTESLA private key
+ */
+public final class QTESLAPrivateKeyParameters
+    extends AsymmetricKeyParameter
+{
+    /**
+     * qTESLA Security Category (From 4 To 8)
+     */
+    private int securityCategory;
+
+    /**
+     * Text of the qTESLA Private Key
+     */
+    private byte[] privateKey;
+
+    /**
+     * Base constructor.
+     *
+     * @param securityCategory the security category for the passed in public key data.
+     * @param privateKey the private key data.
+     */
+    public QTESLAPrivateKeyParameters(int securityCategory, byte[] privateKey)
+    {
+        super(true);
+
+        if (privateKey.length != QTESLASecurityCategory.getPrivateSize(securityCategory))
+        {
+            throw new IllegalArgumentException("invalid key size for security category");
+        }
+
+        this.securityCategory = securityCategory;
+        this.privateKey = Arrays.clone(privateKey);
+    }
+
+    /**
+     * Return the security category for this key.
+     *
+     * @return the key's security category.
+     */
+    public int getSecurityCategory()
+    {
+        return this.securityCategory;
+    }
+
+    /**
+     * Return the key's secret value.
+     *
+     * @return key private data.
+     */
+    public byte[] getSecret()
+    {
+        return Arrays.clone(privateKey);
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAPublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAPublicKeyParameters.java
new file mode 100644
index 000000000..71425561a
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLAPublicKeyParameters.java
@@ -0,0 +1,61 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.fr.third.org.bouncycastle.util.Arrays;
+
+/**
+ * qTESLA public key
+ */
+public final class QTESLAPublicKeyParameters
+    extends AsymmetricKeyParameter
+{
+    /**
+     * qTESLA Security Category
+     */
+    private int securityCategory;
+
+    /**
+     * Text of the qTESLA Public Key
+     */
+    private byte[] publicKey;
+
+    /**
+     * Base constructor.
+     *
+     * @param securityCategory the security category for the passed in public key data.
+     * @param publicKey the public key data.
+     */
+    public QTESLAPublicKeyParameters(int securityCategory, byte[] publicKey)
+    {
+        super(false);
+
+        if (publicKey.length != QTESLASecurityCategory.getPublicSize(securityCategory))
+        {
+            throw new IllegalArgumentException("invalid key size for security category");
+        }
+
+        this.securityCategory = securityCategory;
+        this.publicKey = Arrays.clone(publicKey);
+
+    }
+
+    /**
+     * Return the security category for this key.
+     *
+     * @return the key's security category.
+     */
+    public int getSecurityCategory()
+    {
+        return this.securityCategory;
+    }
+
+    /**
+     * Return the key's public value.
+     *
+     * @return key public data.
+     */
+    public byte[] getPublicData()
+    {
+        return Arrays.clone(publicKey);
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLASecurityCategory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLASecurityCategory.java
new file mode 100644
index 000000000..4973d4776
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLASecurityCategory.java
@@ -0,0 +1,114 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+/**
+ * The qTESLA security categories.
+ */
+public class QTESLASecurityCategory
+{
+    public static final int HEURISTIC_I = 0;
+    public static final int HEURISTIC_III_SIZE = 1;
+    public static final int HEURISTIC_III_SPEED = 2;
+    public static final int PROVABLY_SECURE_I = 3;
+    public static final int PROVABLY_SECURE_III = 4;
+
+    private QTESLASecurityCategory()
+    {
+    }
+
+    static void validate(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+        case HEURISTIC_I:
+        case HEURISTIC_III_SIZE:
+        case HEURISTIC_III_SPEED:
+        case PROVABLY_SECURE_I:
+        case PROVABLY_SECURE_III:
+            break;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+
+    static int getPrivateSize(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+        case HEURISTIC_I:
+            return Polynomial.PRIVATE_KEY_I;
+        case HEURISTIC_III_SIZE:
+            return Polynomial.PRIVATE_KEY_III_SIZE;
+        case HEURISTIC_III_SPEED:
+            return Polynomial.PRIVATE_KEY_III_SPEED;
+        case PROVABLY_SECURE_I:
+            return Polynomial.PRIVATE_KEY_I_P;
+        case PROVABLY_SECURE_III:
+            return Polynomial.PRIVATE_KEY_III_P;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+
+    static int getPublicSize(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+        case HEURISTIC_I:
+            return Polynomial.PUBLIC_KEY_I;
+        case HEURISTIC_III_SIZE:
+            return Polynomial.PUBLIC_KEY_III_SIZE;
+        case HEURISTIC_III_SPEED:
+            return Polynomial.PUBLIC_KEY_III_SPEED;
+        case PROVABLY_SECURE_I:
+            return Polynomial.PUBLIC_KEY_I_P;
+        case PROVABLY_SECURE_III:
+            return Polynomial.PUBLIC_KEY_III_P;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+
+    static int getSignatureSize(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+        case HEURISTIC_I:
+            return Polynomial.SIGNATURE_I;
+        case HEURISTIC_III_SIZE:
+            return Polynomial.SIGNATURE_III_SIZE;
+        case HEURISTIC_III_SPEED:
+            return Polynomial.SIGNATURE_III_SPEED;
+        case PROVABLY_SECURE_I:
+            return Polynomial.SIGNATURE_I_P;
+        case PROVABLY_SECURE_III:
+            return Polynomial.SIGNATURE_III_P;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+
+    /**
+     * Return a standard name for the security category.
+     *
+     * @param securityCategory the category of interest.
+     * @return the name for the category.
+     */
+    public static String getName(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+        case HEURISTIC_I:
+            return "qTESLA-I";
+        case HEURISTIC_III_SIZE:
+            return "qTESLA-III-size";
+        case HEURISTIC_III_SPEED:
+            return "qTESLA-III-speed";
+        case PROVABLY_SECURE_I:
+            return "qTESLA-p-I";
+        case PROVABLY_SECURE_III:
+            return "qTESLA-p-III";
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLASigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLASigner.java
new file mode 100644
index 000000000..54a61c6da
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/QTESLASigner.java
@@ -0,0 +1,135 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.crypto.CipherParameters;
+import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.fr.third.org.bouncycastle.pqc.crypto.MessageSigner;
+
+/**
+ * Signer for the qTESLA algorithm (https://qtesla.org/)
+ */
+public class QTESLASigner
+    implements MessageSigner
+{
+    /**
+     * The Public Key of the Identity Whose Signature Will be Generated
+     */
+    private QTESLAPublicKeyParameters publicKey;
+
+    /**
+     * The Private Key of the Identity Whose Signature Will be Generated
+     */
+    private QTESLAPrivateKeyParameters privateKey;
+
+    /**
+     * The Source of Randomness for private key operations
+     */
+    private SecureRandom secureRandom;
+
+    public QTESLASigner()
+    {
+    }
+
+    /**
+     * Initialise the signer.
+     *
+     * @param forSigning true if we are generating a signature, false
+     *                   otherwise.
+     * @param param      ParametersWithRandom containing a private key for signature generation, public key otherwise.
+     */
+    public void init(boolean forSigning, CipherParameters param)
+    {
+         if (forSigning)
+         {
+             if (param instanceof ParametersWithRandom)
+             {
+                 this.secureRandom = ((ParametersWithRandom)param).getRandom();
+                 privateKey = (QTESLAPrivateKeyParameters)((ParametersWithRandom)param).getParameters();
+             }
+             else
+             {
+                 this.secureRandom = CryptoServicesRegistrar.getSecureRandom();
+                 privateKey = (QTESLAPrivateKeyParameters)param;
+             }
+             publicKey = null;
+             QTESLASecurityCategory.validate(privateKey.getSecurityCategory());
+         }
+         else
+         {
+             privateKey = null;
+             publicKey = (QTESLAPublicKeyParameters)param;
+             QTESLASecurityCategory.validate(publicKey.getSecurityCategory());
+         }
+    }
+
+    /**
+     * Generate a signature directly for the passed in message.
+     *
+     * @param message the message to be signed.
+     * @return the signature generated.
+     */
+    public byte[] generateSignature(byte[] message)
+    {
+        byte[] sig = new byte[QTESLASecurityCategory.getSignatureSize(privateKey.getSecurityCategory())];
+
+        switch (privateKey.getSecurityCategory())
+        {
+        case QTESLASecurityCategory.HEURISTIC_I:
+            QTESLA.signingI(sig, message, 0, message.length, privateKey.getSecret(), secureRandom);
+            break;
+        case QTESLASecurityCategory.HEURISTIC_III_SIZE:
+            QTESLA.signingIIISize(sig, message, 0, message.length, privateKey.getSecret(), secureRandom);
+            break;
+        case QTESLASecurityCategory.HEURISTIC_III_SPEED:
+            QTESLA.signingIIISpeed(sig, message, 0, message.length, privateKey.getSecret(), secureRandom);
+            break;
+        case QTESLASecurityCategory.PROVABLY_SECURE_I:
+            QTESLA.signingIP(sig, message, 0, message.length, privateKey.getSecret(), secureRandom);
+            break;
+        case QTESLASecurityCategory.PROVABLY_SECURE_III:
+            QTESLA.signingIIIP(sig, message, 0, message.length, privateKey.getSecret(), secureRandom);
+            break;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + privateKey.getSecurityCategory());
+        }
+
+        return sig;
+    }
+
+    /**
+     * Verify the signature against the passed in message.
+     *
+     * @param message the message that was supposed to have been signed.
+     * @param signature the signature of the message
+     * @return true if the signature passes, false otherwise.
+     */
+    public boolean verifySignature(byte[] message, byte[] signature)
+    {
+        int status;
+
+        switch (publicKey.getSecurityCategory())
+        {
+        case QTESLASecurityCategory.HEURISTIC_I:
+            status = QTESLA.verifyingI(message, signature, 0, signature.length, publicKey.getPublicData());
+            break;
+        case QTESLASecurityCategory.HEURISTIC_III_SIZE:
+            status = QTESLA.verifyingIIISize(message, signature, 0, signature.length, publicKey.getPublicData());
+            break;
+        case QTESLASecurityCategory.HEURISTIC_III_SPEED:
+            status = QTESLA.verifyingIIISpeed(message, signature, 0, signature.length, publicKey.getPublicData());
+            break;
+        case QTESLASecurityCategory.PROVABLY_SECURE_I:
+            status = QTESLA.verifyingPI(message, signature, 0, signature.length, publicKey.getPublicData());
+            break;
+        case QTESLASecurityCategory.PROVABLY_SECURE_III:
+            status = QTESLA.verifyingPIII(message, signature, 0, signature.length, publicKey.getPublicData());
+            break;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + publicKey.getSecurityCategory());
+        }
+
+        return 0 == status;
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Sample.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Sample.java
new file mode 100644
index 000000000..9eaac8799
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/qteslarnd1/Sample.java
@@ -0,0 +1,1373 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.qteslarnd1;
+
+import com.fr.third.org.bouncycastle.util.Arrays;
+
+class Sample
+{
+
+    static final double[][] EXPONENTIAL_DISTRIBUTION_I = {
+        /* [3][32] */
+        {
+            1.0000000000000000000000000000000000000000, 0.9990496327075997720621566739241504871513,
+            0.9981001686131900082646604498429491608001, 0.9971516068584008799087793737854343387385,
+            0.9962039465856783249057599531380206128030, 0.9952571869382832724989228009014122394200,
+            0.9943113270602908687225570427678069689363, 0.9933663660965897025969132575731249565771,
+            0.9924223031928810330585953871541593536283, 0.9914791374956780166256527164832613053574,
+            0.9905368681523049357966736891640434381216, 0.9895954943108964281831839869512129866330,
+            0.9886550151203967163746519649066284074237, 0.9877154297305588385354051961226109899227,
+            0.9867767372919438797327625416330343864518, 0.9858389369559202039956868221933583419625,
+            0.9849020278746626871032638290431658501235, 0.9839660092011519501023140705695025630520,
+            0.9830308800891735935534443109670000387768, 0.9820966396933174325048466155419862577528,
+            0.9811632871689767321931532752331431453491, 0.9802308216723474444706566402213564033800,
+            0.9792992423604274449582035491768120172661, 0.9783685483910157709230746967427200384407,
+            0.9774387389227118598811599372828827520575, 0.9765098131149147889227411777252636721429,
+            0.9755817701278225147611951665163479411869, 0.9746546091224311145039291392620050672727,
+            0.9737283292605340271448629345703623656609, 0.9728029297047212957777718459314622781631,
+            0.9718784096183788105298051271677986565965, 0.9709547681656875522144957200697952895280
+        },
+
+        {
+            1.0000000000000000000000000000000000000000, 0.9700320045116228367035774232914930379400,
+            0.9409620897768370674212298508058219852849, 0.9127633421156708668942503744059309052528,
+            0.8854096543971923811501043960464255901147, 0.8588757018688517364879932717859212289637,
+            0.8331369187101692180902460141030849026557, 0.8081694752890624155161689578277768341910,
+            0.7839502560997556536888618983783791053116, 0.7604568383618460545183896873859249753543,
+            0.7376674712607126902372883387750345338472, 0.7155610558100490615694685434237323547987,
+            0.6941171253178751117406951384261687867164, 0.6733158264379437043232142381368341940533,
+            0.6531379007889984662634253213819854052726, 0.6335646671248656289427239706049936967143,
+            0.6145780040388724765036124496076447154217, 0.5961603331865797040852326968966728810261,
+            0.5782946030112948570545930362131434268247, 0.5609642729572995100665682618108293115511,
+            0.5441532981561743827978648643747061873131, 0.5278461145720445955231454653404664082188,
+            0.5120276245919921478529972155927751107378, 0.4966831830482948512984566287866591847562,
+            0.4817985836595507424420546966358580262381, 0.4673600458781348185224193866260805625424,
+            0.4533542021318111302275642196084653301628, 0.4397680854476881857303133336231578259611,
+            0.4265891174470596033395475021945475958821, 0.4138050967000153253100465421861800587782,
+            0.4014041874290417902572763743098032661210, 0.3893749085511525646401543103372782315254
+        },
+
+        {
+            1.0000000000000000000000000000000000000000000, 0.3777061230484043540417651455683576466650000,
+            0.1426619153882563708052119679085105421822000, 0.0538842789679578114076165050703859298545800,
+            0.0203524221022460198907862721163275696205800, 0.0076872344468839996101743286763347159496400,
+            0.0029035155198967005412614828182250511400990, 0.0010966755902310549151227158892825815595730,
+            0.0004142210854279922997296008273437255752956, 0.0001564538402619088712753422615493598849163,
+            5.909357344135995142394679824207999201121E-5, 2.232000452161222135025591154935960584027E-5,
+            8.430402374281007236700902260035220289887E-6, 3.184214596527742337148476455363347356131E-6,
+            1.202697350208632670782595114365065060885E-6, 4.542661533478916755570208360842380811059E-7,
+            1.715791076131440947144583312662638239090E-7, 6.480647953266561572601959656715022445021E-8,
+            2.447780413269889735078224512008720987199E-8, 9.245416499699910342143072277116651273927E-9,
+            3.492050422069402212293514861017928736701E-9, 1.318968826409377991494549187659977485249E-9,
+            4.981826018447900060525041555590742055479E-10, 1.881666191129624879723808164319051826703E-10,
+            7.107168419228284402686789774896404982106E-11, 2.684421029478771850078976357840397379201E-11,
+            1.013922259674033292202917547107956246173E-11, 3.829646457739566105989785588606755995719E-12,
+            1.446480916198866420590826731657500079699E-12, 5.463446989209777070985952848270039796153E-13,
+            2.063577380774902353530525926195322827410E-13, 7.794258121028692337871970872695782456164E-14
+        }
+
+    };
+
+    static final double[][] EXPONENTIAL_DISTRIBUTION_III_SIZE = {
+        /* [3][32] */
+        {
+            1.0000000000000000000000000000000000000000, 0.9914791374956780166256527164832613053571,
+            0.9830308800891735935534443109670000387763, 0.9746546091224311145039291392620050672719,
+            0.9663497112088951922951613058690022829314, 0.9581155781885929401990530331782558043141,
+            0.9499516070835989810875119461809064028436, 0.9418572000538799331122753584612083652659,
+            0.9338317643535151384510743106138183393464, 0.9258747122872904292046909607697858626681,
+            0.9179854611676617518466375609653990674902, 0.9101634332720854987115840832838713554612,
+            0.9024080558007124218622779514513692802555, 0.8947187608344420312994997523024746481561,
+            0.8870949852933344058775329566907233056474, 0.8795361708953763714606266672461444022383,
+            0.8720417641155990268059148554652540437481, 0.8646112161455436233871237462566364157436,
+            0.8572439828530728308830350554160731167048, 0.8499395247425244453469447315612369857573,
+            0.8426973069152046221501168284377584096225, 0.8355167990302177406553164840946716839800,
+            0.8283974752656300322277354108287439566785, 0.8213388142799641276318029906853001579399,
+            0.8143402991740217040952958306017837324709, 0.8074014174530314363485930132316684297705,
+            0.8005216609891194797686327175999898485396, 0.7937005259840997373758528196362056425534,
+            0.7869375129325811858498730937766509221324, 0.7802321265853895589476145632070372895529,
+            0.7735838759133007097276526159890746982448, 0.7669922740710829958085504579386416555178
+        },
+
+        {
+            1.0000000000000000000000000000000000000000000, 0.7604568383618460545183896873859249753475000,
+            0.5782946030112948570545930362131434268144000, 0.4397680854476881857303133336231578259493000,
+            0.3344246478719911187527828322027724928608000, 0.2543155103910080342970055083858543302085000,
+            0.1933959689783251774319131539973439846964000, 0.1470692871211828233002294902623869285186000,
+            0.1118398451043052539124374690378746581867000, 0.0850493750108985602659800234578596968909400,
+            0.0646763788254389154655681775607238774758000, 0.0491835945582863241156170683610789877042500,
+            0.0374020008170653143735533498156831735514100, 0.0284426072897526718347370026026486693779300,
+            0.0216293752143329118535087528015400204365400, 0.0164482062912336825104561988130156459132400,
+            0.0125081509529549918713848862125144537439400, 0.0095119089274368649464762531606995319241100,
+            0.0072333961897444564781616481310238106761860, 0.0055006855970716932734388078251246759697760,
+            0.0041830339779716833064716700383503988117580, 0.0031810167936485222816222493382931725715270,
+            0.0024190259736738921137934575940109408536480, 0.0018395648438552342443599128094977711325760,
+            0.0013989096651197544439950127319659303796870, 0.0010638104210907972987681203969116907947710,
+            0.0008089819094390918283473978621390203944673, 0.0006151958251439810374839895543363501050953,
+            0.0004678298721623988965815688638575721914033, 0.0003557644254758444808169155363704398225966,
+            0.0002705434901989792929582192527080744710506, 0.0002057366471960948784546183663182928059645
+        },
+
+        {
+            1.000000000000000000000000000000000000000, 0.0001564538402619088712753422615493598848717,
+            2.447780413269889735078224512008720985804E-8, 3.829646457739566105989785588606755992447E-12,
+            5.991628951587712183461314435723455239107E-16, 9.374133589003324437283071562544462897124E-20,
+            1.466619199127720628458909574032394007656E-23, 2.294582059053771218038974267927533833163E-27,
+            3.589961749350406706790987553377863179812E-31, 5.616633020792314645332222710264644857908E-35,
+            8.787438054448034835939954112296077697602E-39, 1.374828429682032112779050229478845154715E-42,
+            2.150971875250036652628677686695580621313E-46, 3.365278101782278104362461212648493483965E-50,
+            5.265106825731444425408506379787751403098E-54, 8.237461822748734749731771711361450782154E-58,
+            1.288782536179903234906819256928735424052E-61, 2.016349770478283712998453222332343703812E-65,
+            3.154656649025460159903286438614052035760E-69, 4.935581474477980619913950088312373997931E-73,
+            7.721906756076146364991353446502442654680E-77, 1.208121966132492313782281967679468463452E-80,
+            1.890153211061962317744312705074835436919E-84, 2.957217285540223765931001823632869648146E-88,
+            4.626680008116659240109379372702265238809E-92, 7.238618549328510447646200176448777448608E-96,
+            1.132509670233533294861752560334068442100E-99, 1.771854870417843101882482426208692422294E-103,
+            2.772134988636384669818807165401424398102E-107, 4.337111646965654912069237407317707678694E-111,
+            6.785577728124290751600099215097500773985E-115, 1.061629693960724289088455922591023103484E-118
+        }
+
+    };
+
+    static final double[][] EXPONENTIAL_DISTRIBUTION_III_SPEED = {
+        /* [3][32] */
+        {
+            1.0000000000000000000000000000000000000000, 0.9951980443443537316500388424172839303752,
+            0.9904191474668262564830185894967173613892, 0.9856631986401875746675941557587114196642,
+            0.9809300876689149347041557365309129923940, 0.9762197048866395987965541168345276706016,
+            0.9715319411536058687432894158212596709598, 0.9668666878541423134736924881553750396380,
+            0.9622238368941451396373408016639000521875, 0.9576032806985736469363056351479270970296,
+            0.9530049122089577101698314104664824876542, 0.9484286248809172302397073765744987564880,
+            0.9438743126816934966419131566675496907225, 0.9393418700876924042461092785035073150884,
+            0.9348311920820394674392081270253399758265, 0.9303421741521465749826061515830447550861,
+            0.9258747122872904292046909607697858626672, 0.9214287029762026134209634491584644007645,
+            0.9170040432046712317435415947941667461407, 0.9126006304531540657099452867877830194818,
+            0.9082183626944031924279067014123113094560, 0.9038571383911010091985145255388756529519,
+            0.8995168564935076098442888811876009946339, 0.8951974164371194582318032579854959087286,
+            0.8908987181403393047402262055905414183192, 0.8866206620021572916876550405654798379036,
+            0.8823631488998431939863624175501337704454, 0.8781260801866497415560803096876886684788,
+            0.8739093576895269702812107160640808580937, 0.8697128837068475485533842136704059167642,
+            0.8655365610061430266950922187780245940470, 0.8613802928218509568132024098758678171240
+        },
+
+        {
+            1.000000000000000000000000000000000000000000, 0.857243982853072830883035055416073116703300,
+            0.734867246137799425692104349091725698937400, 0.629960524947436582383605303639195946052600,
+            0.540029869446153084936465415644391919699900, 0.462937356143645214602345480384983067321600,
+            0.396850262992049868687926409818180089809000, 0.340197500043594241063920093831306311583500,
+            0.291632259894029145223423158665267961335500, 0.250000000000000000000000000000097352251700,
+            0.214310995713268207720758763854101733807800, 0.183716811534449856423026087273002965715400,
+            0.157490131236859145595901325909860314588700, 0.135007467361538271234116353911150553048700,
+            0.115734339035911303650586370096290834824400, 0.099212565748012467171981602454583656718920,
+            0.085049375010898560265980023457859696888520, 0.072908064973507286305855789666345381391030,
+            0.062500000000000000000000000000048676125830, 0.053577748928317051930189690963546297109930,
+            0.045929202883612464105756521818268626674130, 0.039372532809214786398975331477480410666060,
+            0.033751866840384567808529088477800781543110, 0.028933584758977825912646592524083975704600,
+            0.024803141437003116792995400613655572746400, 0.021262343752724640066495005864473203970290,
+            0.018227016243376821576463947416593443112050, 0.015625000000000000000000000000018253547190,
+            0.013394437232079262982547422740891790191980, 0.011482300720903116026439130454571627979850,
+            0.009843133202303696599743832869373935671238, 0.008437966710096141952132272119453481206014
+        },
+
+        {
+            1.000000000000000000000000000000000000000, 0.007233396189744456478161648131023810675775,
+            5.232202043780962102557587008169005410143E-5, 3.784659032745836912993682954976324658164E-7,
+            2.737593822694567686662466634421542264066E-9, 1.980210072614684707158711353745069372717E-11,
+            1.432364399414465384287735340977513952565E-13, 1.036085918905020069841154248521752033776E-15,
+            7.494419938055456100418425186702743722723E-18, 5.421010862427522170037264004417260251684E-20,
+            3.921231931684654880817938739668273317360E-22, 2.836382411375207747860568187463889509638E-24,
+            2.051667772709962123314993704273413823620E-26, 1.484052584974173558955043468582713624191E-28,
+            1.073474031353259824558654154333806911547E-30, 7.764862968180290824468612020607860317513E-33,
+            5.616633020792314645332222710264644852793E-35, 4.062733189179202535382045195211707654781E-37,
+            2.938735877055718769921841343128853888538E-39, 2.125704089576016965228859756656407540404E-41,
+            1.537605986206336992222535387300608525931E-43, 1.112211328195318530448364746285024038827E-45,
+            8.045065183558638234146057828832053516826E-48, 5.819314384499884015403474144560288801662E-50,
+            4.209340649576656799996170991423257963815E-52, 3.044782861598424467581974062513986546956E-54,
+            2.202412074968526631812431321732133496007E-56, 1.593091911132452277028880397827266782094E-58,
+            1.152346495989819456843455045622426762614E-60, 8.335378753358135655955994470664225877261E-63,
+            6.029309691461763611680553229574282672923E-65, 4.361238574900884540660050746922306538111E-67,
+        }
+
+    };
+
+    static final double[][] EXPONENTIAL_DISTRIBUTION_P = {
+        /* [3][32] */
+        {
+            1.0000000000000000000000000000000000000000, 0.9930924954370359015332102168880765048173,
+            0.9862327044933591729073804985266878802443, 0.9794202975869268710835182321094224250961,
+            0.9726549474122855185227020947295413763023, 0.9659363289248455510651443129204733029988,
+            0.9592641193252643901322834293949397264660, 0.9526379980439373889289005948680289570903,
+            0.9460576467255959075051119972754354254470, 0.9395227492140117766851490088262829075331,
+            0.9330329915368074159813432661499603336007, 0.9265880618903708756879317851202732375877,
+            0.9201876506248750783904312382017973974891, 0.9138314502294005401326428921359892449876,
+            0.9075191553171608564550809482180658363403, 0.9012504626108302434560060155923701020040,
+            0.8950250709279724289295293992056807493013, 0.8888426811665701935046683790031660959701,
+            0.8827029962906548665450116490541232503509, 0.8766057213160350863710299119436526437378,
+            0.8705505632961241391362700174797799990040, 0.8645372313078651954249311342751209858410,
+            0.8585654364377537683418658040230197384022, 0.8526348917679567215371033354114150564474,
+            0.8467453123625271602457822707284519309456, 0.8408964152537145430311254762332558266219,
+            0.8350879194283693564930171007187976000468, 0.8293195458144416997480650199452263126561,
+            0.8235910172675731299989737240342361894393, 0.8179020585577811249918276889374069238047,
+            0.8122523963562355226097093827753290960475, 0.8066417592221263022701629871861700330324
+        },
+
+        {
+            1.000000000000000000000000000000000000000000, 0.801069877589622077182576980035615205902700,
+            0.641712948781452099037917089781420222618900, 0.514056913328033254673172479396413573907600,
+            0.411795508633786564999486862017198273163900, 0.329876977693223564843500492807512798916800,
+            0.264254510140345093624873553521627364440900, 0.211686328090631790061445567682195415303500,
+            0.169575540930958985396762834141244920349500, 0.135841857815757262606900740466230788178000,
+            0.108818820412015517392033752185036062422000, 0.087171479146900338767218235365499637556050,
+            0.069830446129513747913186914700207350540810, 0.055939066932998276808095587450398613186620,
+            0.044811101500494605684562734558780780465070, 0.035896823593657343962457092086843785683310,
+            0.028755864082027346199700976193834163154190, 0.023035456520173456442055699495851578765410,
+            0.018453010334836412492976026695119689178670, 0.014782150730087436054767374957445947431420,
+            0.011841535675862485018337967197721359270050, 0.009485897534336303604787967133085469399049,
+            0.007598866776658480613458610115084898737984, 0.006087223278597655149117219956228990612855,
+            0.004876291206646921576592633968279399063782, 0.003906250000000000000000000000006084516053,
+            0.003129179209334461238994441328268996020587, 0.002506691206177547261866863631962577257343,
+            0.002008034817687629901067079997645368310618, 0.001608576205600728769529245554757186330929,
+            0.001288581944114154550169923800031354012535, 0.001032244180235723021972162318445464753156
+        },
+
+        {
+            1.000000000000000000000000000000000000000, 0.0008268997191040304299275217487598638498908,
+            6.837631454543244275598561791827450446268E-7, 5.654035529098691704742888887601969318770E-10,
+            4.675320390815916240837145591289455678271E-13, 3.866021117887026910581260785663924052584E-16,
+            3.196811776431032265107748321378670183434E-19, 2.643442759959277106397015416454182808165E-22,
+            2.185862075677909177530183421677021601630E-25, 1.807488736378216004902267757945329990433E-28,
+            1.494611928394845722509566662381681852231E-31, 1.235894183759231170477230799378805483584E-34,
+            1.021960553392813221805059629881904702629E-37, 8.450588945359167454685108853553438401193E-41,
+            6.987789625181120323479538530531788834637E-44, 5.778201278220326478541087516212630539830E-47,
+            4.777993013886937548374901071454718579294E-50, 3.950921081064128423947108109095179681258E-53,
+            3.267015532134120033414586853048549151733E-56, 2.701494225830208356330596231491229575841E-59,
+            2.233864816500159437321055999997722887780E-62, 1.847182189280358319436455385107649366142E-65,
+            1.527434433449896263866613728025637317872E-68, 1.263035103969543081968346060350962609985E-71,
+            1.044403372690945043917523022329044283453E-74, 8.636168555094444625386351863230863826745E-78,
+            7.141245352342656606906053992842560076147E-81, 5.905093775905105564186232605424573035226E-84,
+            4.882920384578890205960673105845289217904E-87, 4.037685494415628551550334502904113261957E-90,
+            3.338761001162701476381524668052565130775E-93, 2.760820534016929266476966660680800456743E-96
+        }
+
+    };
+
+    static final long[][] CUMULATIVE_DISTRIBUTION_TABLE_I = {
+        /* [12][2] */
+        {0x0200000000000000L, 0x0000000000000000L}, {0x0300000000000000L, 0x0000000000000000L},
+        {0x0320000000000000L, 0x0000000000000000L}, {0x0321000000000000L, 0x0000000000000000L},
+        {0x0321020000000000L, 0x0000000000000000L}, {0x0321020100000000L, 0x0000000000000000L},
+        {0x0321020100200000L, 0x0000000000000000L}, {0x0321020100200100L, 0x0000000000000000L},
+        {0x0321020100200100L, 0x0200000000000000L}, {0x0321020100200100L, 0x0200010000000000L},
+        {0x0321020100200100L, 0x0200010000200000L}, {0x0321020100200100L, 0x0200010000200001L},
+
+    };
+
+    static final long[][] CUMULATIVE_DISTRIBUTION_TABLE_III = {
+        /* [14][3] */
+        {0x0000020000000000L, 0x0000000000000000L, 0x0000000000000000L},
+        {0x0000030000000000L, 0x0000000000000000L, 0x0000000000000000L},
+        {0x0000032000000000L, 0x0000000000000000L, 0x0000000000000000L},
+        {0x0000032100000000L, 0x0000000000000000L, 0x0000000000000000L},
+        {0x0000032102000000L, 0x0000000000000000L, 0x0000000000000000L},
+        {0x0000032102010000L, 0x0000000000000000L, 0x0000000000000000L},
+        {0x0000032102010020L, 0x0000000000000000L, 0x0000000000000000L},
+        {0x0000032102010020L, 0x0100000000000000L, 0x0000000000000000L},
+        {0x0000032102010020L, 0x0100020000000000L, 0x0000000000000000L},
+        {0x0000032102010020L, 0x0100020001000000L, 0x0000000000000000L},
+        {0x0000032102010020L, 0x0100020001000020L, 0x0000000000000000L},
+        {0x0000032102010020L, 0x0100020001000020L, 0x0001000000000000L},
+        {0x0000032102010020L, 0x0100020001000020L, 0x0001000002000000L},
+        {0x0000032102010020L, 0x0100020001000020L, 0x0001000002000001L}
+
+    };
+
+    private static long modulus7(long number)
+    {
+
+        long temporary = number;
+
+        for (int i = 0; i < 2; i++)
+        {
+
+            temporary = (temporary & 7) + (temporary >> 3);
+
+        }
+
+        return ((temporary - 7) >> 3) & temporary;
+
+    }
+
+    /******************************************************************************************************************
+     * Description:	Samples Polynomial Y, Such That Each Coefficient is in the Range [-B, B], for Heuristic qTESLA
+     * 				Security Category-1 and Security Category-3 (Option for Size or Speed)
+     *
+     * @param        Y                Polynomial Y
+     * @param        seed            Kappa-Bit Seed
+     * @param        seedOffset        Starting Point of the Kappa-Bit Seed
+     * @param        nonce            Domain Separator for Error Polynomial and Secret Polynomial
+     * @param        n                Polynomial Degree
+     * @param        q                Modulus
+     * @param        b                Determines the Interval the Randomness is Chosen in During Signing
+     * @param        bBit            b = 2 ^ bBit - 1
+     *
+     * @return none
+     ******************************************************************************************************************/
+    public static void sampleY(int[] Y, final byte[] seed, int seedOffset, int nonce, int n, int q, int b, int bBit)
+    {
+
+        int i = 0;
+        int position = 0;
+        int numberOfByte = (bBit + 1 + 7) / 8;
+        int numberOfBlock = n;
+        byte[] buffer = new byte[n * numberOfByte];
+        int[] y = new int[4];
+
+        short dualModeSampler = (short)(nonce << 8);
+
+        if (q == Parameter.Q_I)
+        {
+
+            HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                buffer, 0, n * numberOfByte, dualModeSampler++, seed, seedOffset, Polynomial.RANDOM
+            );
+
+        }
+
+        if (q == Parameter.Q_III_SIZE || q == Parameter.Q_III_SPEED)
+        {
+
+            HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+                buffer, 0, n * numberOfByte, dualModeSampler++, seed, seedOffset, Polynomial.RANDOM
+            );
+
+        }
+
+        while (i < n)
+        {
+
+            if (position > numberOfBlock * numberOfByte * 4)
+            {
+
+                if (q == Parameter.Q_I)
+                {
+
+                    numberOfBlock =
+                        HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE /
+                            ((bBit + 1 + 7) / 8);
+
+                    HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                        buffer, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE,
+                        dualModeSampler++,
+                        seed, seedOffset, Polynomial.RANDOM
+                    );
+
+                }
+
+                if (q == Parameter.Q_III_SIZE || q == Parameter.Q_III_SPEED)
+                {
+
+                    numberOfBlock =
+                        HashUtils.SECURE_HASH_ALGORITHM_KECCAK_256_RATE /
+                            ((bBit + 1 + 7) / 8);
+
+                    HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+                        buffer, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_256_RATE,
+                        dualModeSampler++,
+                        seed, seedOffset, Polynomial.RANDOM
+                    );
+
+                }
+
+                position = 0;
+
+            }
+
+            y[0] = (CommonFunction.load32(buffer, position) & ((1 << (bBit + 1)) - 1)) - b;
+            y[1] = (CommonFunction.load32(buffer, position + numberOfByte) & ((1 << (bBit + 1)) - 1)) - b;
+            y[2] = (CommonFunction.load32(buffer, position + numberOfByte * 2) & ((1 << (bBit + 1)) - 1)) - b;
+            y[3] = (CommonFunction.load32(buffer, position + numberOfByte * 3) & ((1 << (bBit + 1)) - 1)) - b;
+
+            if (i < n && y[0] != (1 << bBit))
+            {
+
+                Y[i++] = y[0];
+
+            }
+
+            if (i < n && y[1] != (1 << bBit))
+            {
+
+                Y[i++] = y[1];
+
+            }
+
+            if (i < n && y[2] != (1 << bBit))
+            {
+
+                Y[i++] = y[2];
+
+            }
+
+            if (i < n && y[3] != (1 << bBit))
+            {
+
+                Y[i++] = y[3];
+
+            }
+
+            position += numberOfByte * 4;
+
+        }
+
+    }
+
+    /*******************************************************************************************************************
+     * Description:	Samples Polynomial Y, Such That Each Coefficient is in the Range [-B, B], for Provably-Secure qTESLA
+     *				Security Category-1 and Security Category-3
+     *
+     * @param        Y                Polynomial Y
+     * @param        seed            Kappa-Bit Seed
+     * @param        seedOffset        Starting Point of the Kappa-Bit Seed
+     * @param        nonce            Domain Separator for Error Polynomial and Secret Polynomial
+     * @param        n                Polynomial Degree
+     * @param        q                Modulus
+     * @param        b                Determines the Interval the Randomness is Chosen in During Signing
+     * @param        bBit            b = 2 ^ bBit - 1
+     *
+     * @return none
+     *******************************************************************************************************************/
+    public static void sampleY(long[] Y, final byte[] seed, int seedOffset, int nonce, int n, int q, int b, int bBit)
+    {
+
+        int i = 0;
+        int position = 0;
+        int numberOfByte = (bBit + 1 + 7) / 8;
+        int numberOfBlock = n;
+        byte[] buffer = new byte[n * numberOfByte];
+
+        short dualModeSampler = (short)(nonce << 8);
+
+        if (q == Parameter.Q_I_P)
+        {
+
+            HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                buffer, 0, n * numberOfByte, dualModeSampler++, seed, seedOffset, Polynomial.RANDOM
+            );
+
+        }
+
+        if (q == Parameter.Q_III_P)
+        {
+
+            HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+                buffer, 0, n * numberOfByte, dualModeSampler++, seed, seedOffset, Polynomial.RANDOM
+            );
+
+        }
+
+        while (i < n)
+        {
+
+            if (position > numberOfBlock * numberOfByte)
+            {
+
+                if (q == Parameter.Q_I_P)
+                {
+
+                    numberOfBlock =
+                        HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE /
+                            ((bBit + 1 + 7) / 8);
+
+                    HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                        buffer, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE,
+                        dualModeSampler++,
+                        seed, seedOffset, Polynomial.RANDOM
+                    );
+
+                }
+
+                if (q == Parameter.Q_III_P)
+                {
+
+                    numberOfBlock =
+                        HashUtils.SECURE_HASH_ALGORITHM_KECCAK_256_RATE /
+                            ((bBit + 1 + 7) / 8);
+
+                    HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+                        buffer, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_256_RATE,
+                        dualModeSampler++,
+                        seed, seedOffset, Polynomial.RANDOM
+                    );
+
+                }
+
+                position = 0;
+
+            }
+
+            Y[i] = (CommonFunction.load32(buffer, position) & ((1 << (bBit + 1)) - 1)) - b;
+
+            if (Y[i] != (1 << bBit))
+            {
+
+                i++;
+
+            }
+
+            position += numberOfByte;
+
+        }
+
+    }
+
+    /*****************************************************************************************************************
+     * Description:	Samples A Bit from Bernoulli with Restriction of 20-Bit Exponent
+     *****************************************************************************************************************/
+    private static int bernoulli(long result, long fractionOfExponent, double[][] exponentialDistribution)
+    {
+
+        /* *
+         * Computes the Actual Bernoulli Parameter = exp (-t / f)
+         * Yields A Fraction of 2^62, to Keep Only 62 Bits of Precision in This Implementation
+         * */
+        double bernoulliParameter = 4611686018427387904.0;
+
+        for (long i = 0, j = fractionOfExponent; i < 3; i++, j >>= 5)
+        {
+
+            bernoulliParameter *= exponentialDistribution[(int)i][(int)(j & 31)];
+
+        }
+
+        /* Sample from Bernoulli of bernoulliParameter */
+        return (int)(((result & 0x3FFFFFFFFFFFFFFFL) - round(bernoulliParameter)) >>> 63);
+
+    }
+
+    /**********************************************************************************************************************
+     * Description:	Gaussian Sampler for Heuristic qTESLA Security Category-1
+     *
+     * @param        data                        Data to be Sampled
+     * @param        dataOffset                    Starting Point of the Data to be Sampled
+     * @param        seed                        Kappa-Bit Seed
+     * @param        seedOffset                    Starting Point of the Kappa-Bit Seed
+     * @param        nonce                        Domain Separator for Error Polynomial and Secret Polynomial
+     *
+     * @return none
+     **********************************************************************************************************************/
+    public static void polynomialGaussSamplerI(int[] data, int dataOffset, final byte[] seed, int seedOffset, int nonce)
+    {
+
+        byte[] seedExpander = new byte[Parameter.N_I * Const.LONG_SIZE / Const.INT_SIZE];
+        short domainSeparator = (short)(nonce << 8);
+        int index;
+        int j = 0;
+        long k;
+        long sign;
+        long r;
+        long s;
+        long randomBit;
+        long bitRemained;
+        long y;
+        long z;
+        long buffer;
+
+        HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+            seedExpander, 0, Parameter.N_I * Const.LONG_SIZE / Const.INT_SIZE, domainSeparator++, seed, seedOffset, Polynomial.RANDOM
+        );
+
+        for (index = 0; index < Parameter.N_I; index++)
+        {
+
+            if (j + 46 > Parameter.N_I)
+            {
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                    seedExpander, 0, Parameter.N_I * Const.LONG_SIZE / Const.INT_SIZE, domainSeparator++, seed, seedOffset, Polynomial.RANDOM
+                );
+
+                j = 0;
+
+            }
+
+            do
+            {
+
+                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                bitRemained = 64;
+
+                do
+                {
+
+                    /* Sample x from D^+_{\SIGMA_2} and y from U ({0, ..., k - 1}) */
+                    do
+                    {
+
+                        r = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                        s = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+
+                        if (bitRemained <= 64 - 6)
+                        {
+
+                            randomBit = (randomBit << 6) ^ ((r >>> 58) & 63L);
+                            bitRemained += 6;
+
+                        }
+
+                        r &= 0x03FFFFFFFFFFFFFFL;
+
+                        /*
+                         * Checks If r Exceeds A Maximum Value
+                         * Variation is Random ad Does not Depend on Private Data
+                         */
+                    }
+                    while (r > 0x0321020100200100L);
+
+                    y = 0;
+
+                    for (int i = 0; i < 12; i++)
+                    {
+
+                        long c = s - CUMULATIVE_DISTRIBUTION_TABLE_I[i][1];
+
+                        long b = (((c & CUMULATIVE_DISTRIBUTION_TABLE_I[i][1]) & 1) + (CUMULATIVE_DISTRIBUTION_TABLE_I[i][1] >> 1) + (c >>> 1)) >>> 63;
+
+                        c = r - (CUMULATIVE_DISTRIBUTION_TABLE_I[i][0] + b);
+
+                        y += ~(c >>> 63) & 1L;
+
+                    }
+
+                    /* The Next Sampler Works Exclusively for xi <= 28 */
+                    do
+                    {
+
+                        do
+                        {
+
+                            if (bitRemained < 6)
+                            {
+
+                                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                                bitRemained = 64;
+
+                            }
+
+                            z = randomBit & 63L;
+                            randomBit >>= 6;
+                            bitRemained -= 6;
+
+                        }
+                        while (z == 63);
+
+                        if (bitRemained < 2)
+                        {
+
+                            randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                            bitRemained = 64;
+
+                        }
+
+                        z = (modulus7(z) << 2) + (randomBit & 3L);
+                        randomBit >>= 2;
+                        bitRemained -= 2;
+
+                        /*
+                         * Making Sure Random z Does not Exceed A Certain Limit
+                         * No Private Data is Leaked
+                         * It Varies Uniformly
+                         */
+                    }
+                    while (z >= Parameter.XI_I);
+
+                    /* Sample A Bit from Bernoulli_{exp (- y * (y + 2 * k * x) / (2 * k^2 * SIGMA_2^2))} */
+                    k = (long)(Parameter.XI_I * y + z);
+
+                    buffer = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+
+                }
+                while (bernoulli(buffer, z * ((k << 1) - z), EXPONENTIAL_DISTRIBUTION_I) == 0);
+
+                /* Put Last Random Bits into Sign Bit */
+                randomBit <<= (int)(64 - bitRemained);
+
+                if (bitRemained == 0)
+                {
+
+                    randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                    bitRemained = 64;
+
+                }
+
+                sign = randomBit >> 63;
+                randomBit <<= 1;
+                bitRemained--;
+
+            }
+            while ((k | (sign & 1L)) == 0);
+
+            if (bitRemained == 0)
+            {
+
+                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                bitRemained = 64;
+
+            }
+
+            sign = randomBit >> 63;
+            randomBit <<= 1;
+            bitRemained--;
+            k = ((k << 1) & sign) - k;
+            data[dataOffset + index] = (int)((k << 48) >> 48);
+
+        }
+
+    }
+
+    /**********************************************************************************************************************
+     * Description:	Gaussian Sampler for Provably-Secure qTESLA Security Category-1
+     *
+     * @param        data                        Data to be Sampled
+     * @param        dataOffset                    Starting Point of the Data to be Sampled
+     * @param        seed                        Kappa-Bit Seed
+     * @param        seedOffset                    Starting Point of the Kappa-Bit Seed
+     * @param        nonce                        Domain Separator for Error Polynomial and Secret Polynomial
+     *
+     * @return none
+     **********************************************************************************************************************/
+    public static void polynomialGaussSamplerIP(long[] data, int dataOffset, final byte[] seed, int seedOffset, int nonce)
+    {
+
+        byte[] seedExpander = new byte[Parameter.N_I_P * Const.LONG_SIZE / Const.INT_SIZE];
+        short domainSeparator = (short)(nonce << 8);
+        int index;
+        int j = 0;
+        long k;
+        long sign;
+        long r;
+        long s;
+        long randomBit;
+        long bitRemained;
+        long y;
+        long z;
+        long buffer;
+
+        HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+            seedExpander, 0, Parameter.N_I_P * Const.LONG_SIZE / Const.INT_SIZE, domainSeparator++, seed, seedOffset, Polynomial.RANDOM
+        );
+
+        for (index = 0; index < Parameter.N_I_P; index++)
+        {
+
+            if (j + 46 > Parameter.N_I_P)
+            {
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                    seedExpander, 0, Parameter.N_I_P * Const.LONG_SIZE / Const.INT_SIZE, domainSeparator++, seed, seedOffset, Polynomial.RANDOM
+                );
+
+                j = 0;
+
+            }
+
+            do
+            {
+
+                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                bitRemained = 64;
+
+                do
+                {
+
+                    /* Sample x from D^+_{\SIGMA_2} and y from U ({0, ..., k - 1}) */
+                    do
+                    {
+
+                        r = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                        s = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+
+                        if (bitRemained <= 64 - 6)
+                        {
+
+                            randomBit = (randomBit << 6) ^ ((r >>> 58) & 63L);
+                            bitRemained += 6;
+
+                        }
+
+                        r &= 0x03FFFFFFFFFFFFFFL;
+
+                        /*
+                         * Checks If r Exceeds A Maximum Value
+                         * Variation is Random ad Does not Depend on Private Data
+                         */
+                    }
+                    while (r > 0x0321020100200100L);
+
+                    y = 0;
+
+                    for (int i = 0; i < 12; i++)
+                    {
+
+                        long c = s - CUMULATIVE_DISTRIBUTION_TABLE_I[i][1];
+
+                        long b = (((c & CUMULATIVE_DISTRIBUTION_TABLE_I[i][1]) & 1) + (CUMULATIVE_DISTRIBUTION_TABLE_I[i][1] >> 1) + (c >>> 1)) >>> 63;
+
+                        c = r - (CUMULATIVE_DISTRIBUTION_TABLE_I[i][0] + b);
+
+                        y += ~(c >>> 63) & 1L;
+
+                    }
+
+                    /* The Next Sampler Works Exclusively for xi <= 28 */
+                    do
+                    {
+
+                        do
+                        {
+
+                            if (bitRemained < 6)
+                            {
+
+                                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                                bitRemained = 64;
+
+                            }
+
+                            z = randomBit & 63L;
+                            randomBit >>= 6;
+                            bitRemained -= 6;
+
+                        }
+                        while (z == 63);
+
+                        if (bitRemained < 2)
+                        {
+
+                            randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                            bitRemained = 64;
+
+                        }
+
+                        z = (modulus7(z) << 2) + (randomBit & 3L);
+                        randomBit >>= 2;
+                        bitRemained -= 2;
+
+                        /*
+                         * Making Sure Random z Does not Exceed A Certain Limit
+                         * No Private Data is Leaked
+                         * It Varies Uniformly
+                         */
+                    }
+                    while (z >= Parameter.XI_I_P);
+
+                    /* Sample A Bit from Bernoulli_{exp (- y * (y + 2 * k * x) / (2 * k^2 * SIGMA_2^2))} */
+                    k = (long)(Parameter.XI_I_P * y + z);
+
+                    buffer = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+
+                }
+                while (bernoulli(buffer, z * ((k << 1) - z), EXPONENTIAL_DISTRIBUTION_P) == 0);
+
+                /* Put Last Random Bits into Sign Bit */
+                randomBit <<= (int)(64 - bitRemained);
+
+                if (bitRemained == 0)
+                {
+
+                    randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                    bitRemained = 64;
+
+                }
+
+                sign = randomBit >> 63;
+                randomBit <<= 1;
+                bitRemained--;
+
+            }
+            while ((k | (sign & 1L)) == 0);
+
+            if (bitRemained == 0)
+            {
+
+                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                bitRemained = 64;
+
+            }
+
+            sign = randomBit >> 63;
+            randomBit <<= 1;
+            bitRemained--;
+            k = ((k << 1) & sign) - k;
+            data[dataOffset + index] = (k << 48) >> 48;
+
+        }
+
+    }
+
+    /*******************************************************************************************************************************************************************************
+     * Description:	Gaussian Sampler for Heuristic qTESLA Security Category-3 (Option for Size or Speed)
+     *
+     * @param        data                        Data to be Sampled
+     * @param        dataOffset                    Starting Point of the Data to be Sampled
+     * @param        seed                        Kappa-Bit Seed
+     * @param        seedOffset                    Starting Point of the Kappa-Bit Seed
+     * @param        nonce                        Domain Separator for Error Polynomial and Secret Polynomial
+     * @param        n                            Polynomial Degree
+     * @param        xi
+     * @param        exponentialDistribution        Exponential Distribution Table
+     *
+     * @return none
+     *******************************************************************************************************************************************************************************/
+    public static void polynomialGaussSamplerIII(int[] data, int dataOffset, final byte[] seed, int seedOffset, int nonce, int n, double xi, double[][] exponentialDistribution)
+    {
+
+        byte[] seedExpander = new byte[n * Const.LONG_SIZE / Const.INT_SIZE];
+        short domainSeparator = (short)(nonce << 8);
+        int index;
+        int j = 0;
+        long k;
+        long sign;
+        long r;
+        long s;
+        long t;
+        long randomBit;
+        long bitRemained;
+        long y;
+        long z;
+
+        HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+            seedExpander, 0, n * Const.LONG_SIZE / Const.INT_SIZE, domainSeparator++, seed, seedOffset, Polynomial.RANDOM
+        );
+
+        for (index = 0; index < n; index++)
+        {
+
+            if (j + 46 > n)
+            {
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+                    seedExpander, 0, n * Const.LONG_SIZE / Const.INT_SIZE, domainSeparator++, seed, seedOffset, Polynomial.RANDOM
+                );
+
+                j = 0;
+
+            }
+
+            do
+            {
+
+                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                bitRemained = 64;
+
+                do
+                {
+
+                    /* Sample x from D^+_{\SIGMA_2} and y from U ({0, ..., k - 1}) */
+                    do
+                    {
+
+                        r = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                        s = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                        t = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+
+                        if (bitRemained <= 64 - 6)
+                        {
+
+                            randomBit = (randomBit << 6) ^ ((r >>> 58) & 63L);
+                            bitRemained += 6;
+
+                        }
+
+                        r &= 0x000003FFFFFFFFFFL;
+
+                        /*
+                         * Checks If r Exceeds A Maximum Value
+                         * Variation is Random ad Does not Depend on Private Data
+                         */
+                    }
+                    while (r > 0x0000032102010020L);
+
+                    y = 0;
+
+                    for (int i = 0; i < 14; i++)
+                    {
+
+                        long c = t - CUMULATIVE_DISTRIBUTION_TABLE_III[i][2];
+
+                        long b = ((c & CUMULATIVE_DISTRIBUTION_TABLE_III[i][2] & 1L) + (CUMULATIVE_DISTRIBUTION_TABLE_III[i][2] >> 1) + (c >>> 1)) >> 63;
+
+                        /* Least significant Bits of All CUMULATIVE_DISTRIBUTION_TABLE[i][1] are Zero: Overflow Cannot Occur at This Point */
+                        c = s - (CUMULATIVE_DISTRIBUTION_TABLE_III[i][1] + b);
+
+                        b = (((c & b) & 1L) + (CUMULATIVE_DISTRIBUTION_TABLE_III[i][1] >> 1) + (c >>> 1)) >> 63;
+
+                        /* Least significant Bits of All CUMULATIVE_DISTRIBUTION_TABLE[i][0] are Zero: Overflow Cannot Occur at This Point */
+                        c = r - (CUMULATIVE_DISTRIBUTION_TABLE_III[i][0] + b);
+
+                        y += ~(c >>> 63) & 1L;
+
+                    }
+
+                    /* The Next Sampler Works Exclusively for xi <= 28 */
+                    do
+                    {
+
+                        do
+                        {
+
+                            if (bitRemained < 6)
+                            {
+
+                                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                                bitRemained = 64;
+
+                            }
+
+                            z = randomBit & 63L;
+                            randomBit >>= 6;
+                            bitRemained -= 6;
+
+                        }
+                        while (z == 63L);
+
+                        if (bitRemained < 2)
+                        {
+
+                            randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                            bitRemained = 64;
+
+                        }
+
+                        z = (modulus7(z) << 2) + (randomBit & 3L);
+                        randomBit >>= 2;
+                        bitRemained -= 2;
+
+                        /*
+                         * Making Sure Random z Does not Exceed A Certain Limit
+                         * No Private Data is Leaked
+                         * It Varies Uniformly
+                         */
+                    }
+                    while (z >= xi);
+
+                    /* Sample A Bit from Bernoulli_{exp (- y * (y + 2 * k * x) / (2 * k^2 * SIGMA_2^2))} */
+                    k = (long)(xi * y + z);
+
+                }
+                while (bernoulli(CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE), z * ((k << 1) - z), exponentialDistribution) == 0);
+
+                /* Put Last Random Bits into Sign Bit */
+                randomBit <<= (int)(64 - bitRemained);
+
+                if (bitRemained == 0L)
+                {
+
+                    randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                    bitRemained = 64;
+
+                }
+
+                sign = randomBit >> 63;
+                randomBit <<= 1;
+                bitRemained--;
+
+            }
+            while ((k | (sign & 1L)) == 0);
+
+            if (bitRemained == 0)
+            {
+
+                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                bitRemained = 64;
+
+            }
+
+            sign = randomBit >> 63;
+            randomBit <<= 1;
+            bitRemained--;
+            k = ((k << 1) & sign) - k;
+            data[dataOffset + index] = (int)((k << 48) >> 48);
+
+        }
+
+    }
+
+    /**************************************************************************************************************************
+     * Description:	Gaussian Sampler for Provably-Secure qTESLA Security Category-3
+     *
+     * @param        data                        Data to be Sampled
+     * @param        dataOffset                    Starting Point of the Data to be Sampled
+     * @param        seed                        Kappa-Bit Seed
+     * @param        seedOffset                    Starting Point of the Kappa-Bit Seed
+     * @param        nonce                        Domain Separator for Error Polynomial and Secret Polynomial
+     *
+     * @return none
+     **************************************************************************************************************************/
+    public static void polynomialGaussSamplerIIIP(long[] data, int dataOffset, final byte[] seed, int seedOffset, int nonce)
+    {
+
+        byte[] seedExpander = new byte[Parameter.N_III_P * Const.LONG_SIZE / Const.INT_SIZE];
+        short domainSeparator = (short)(nonce << 8);
+        int index;
+        int j = 0;
+        long k;
+        long sign;
+        long r;
+        long s;
+        long t;
+        long randomBit;
+        long bitRemained;
+        long y;
+        long z;
+
+        HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+            seedExpander, 0, Parameter.N_III_P * Const.LONG_SIZE / Const.INT_SIZE, domainSeparator++, seed, seedOffset, Polynomial.RANDOM
+        );
+
+        for (index = 0; index < Parameter.N_III_P; index++)
+        {
+
+            if (j + 46 > Parameter.N_III_P)
+            {
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK256Simple(
+                    seedExpander, 0, Parameter.N_III_P * Const.LONG_SIZE / Const.INT_SIZE, domainSeparator++, seed, seedOffset, Polynomial.RANDOM
+                );
+
+                j = 0;
+
+            }
+
+            do
+            {
+
+                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                bitRemained = 64;
+
+                do
+                {
+
+                    /* Sample x from D^+_{\SIGMA_2} and y from U ({0, ..., k - 1}) */
+                    do
+                    {
+
+                        r = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                        s = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                        t = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+
+                        if (bitRemained <= 64 - 6)
+                        {
+
+                            randomBit = (randomBit << 6) ^ ((r >>> 58) & 63L);
+                            bitRemained += 6;
+
+                        }
+
+                        r &= 0x000003FFFFFFFFFFL;
+
+                        /*
+                         * Checks If r Exceeds A Maximum Value
+                         * Variation is Random ad Does not Depend on Private Data
+                         */
+                    }
+                    while (r > 0x0000032102010020L);
+
+                    y = 0;
+
+                    for (int i = 0; i < 14; i++)
+                    {
+
+                        long c = t - CUMULATIVE_DISTRIBUTION_TABLE_III[i][2];
+
+                        long b = ((c & CUMULATIVE_DISTRIBUTION_TABLE_III[i][2] & 1L) + (CUMULATIVE_DISTRIBUTION_TABLE_III[i][2] >> 1) + (c >>> 1)) >> 63;
+
+                        /* Least significant Bits of All CUMULATIVE_DISTRIBUTION_TABLE[i][1] are Zero: Overflow Cannot Occur at This Point */
+                        c = s - (CUMULATIVE_DISTRIBUTION_TABLE_III[i][1] + b);
+
+                        b = (((c & b) & 1L) + (CUMULATIVE_DISTRIBUTION_TABLE_III[i][1] >> 1) + (c >>> 1)) >> 63;
+
+                        /* Least significant Bits of All CUMULATIVE_DISTRIBUTION_TABLE[i][0] are Zero: Overflow Cannot Occur at This Point */
+                        c = r - (CUMULATIVE_DISTRIBUTION_TABLE_III[i][0] + b);
+
+                        y += ~(c >>> 63) & 1L;
+
+                    }
+
+                    /* The Next Sampler Works Exclusively for xi <= 28 */
+                    do
+                    {
+
+                        do
+                        {
+
+                            if (bitRemained < 6)
+                            {
+
+                                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                                bitRemained = 64;
+
+                            }
+
+                            z = randomBit & 63L;
+                            randomBit >>= 6;
+                            bitRemained -= 6;
+
+                        }
+                        while (z == 63L);
+
+                        if (bitRemained < 2)
+                        {
+
+                            randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                            bitRemained = 64;
+
+                        }
+
+                        z = (modulus7(z) << 2) + (randomBit & 3L);
+                        randomBit >>= 2;
+                        bitRemained -= 2;
+
+                        /*
+                         * Making Sure Random z Does not Exceed A Certain Limit
+                         * No Private Data is Leaked
+                         * It Varies Uniformly
+                         */
+                    }
+                    while (z >= Parameter.XI_III_P);
+
+                    /* Sample A Bit from Bernoulli_{exp (- y * (y + 2 * k * x) / (2 * k^2 * SIGMA_2^2))} */
+                    k = (long)(Parameter.XI_III_P * y + z);
+
+                }
+                while (bernoulli(CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE), z * ((k << 1) - z), EXPONENTIAL_DISTRIBUTION_P) == 0);
+
+                /* Put Last Random Bits into Sign Bit */
+                randomBit <<= (int)(64 - bitRemained);
+
+                if (bitRemained == 0L)
+                {
+
+                    randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                    bitRemained = 64;
+
+                }
+
+                sign = randomBit >> 63;
+                randomBit <<= 1;
+                bitRemained--;
+
+            }
+            while ((k | (sign & 1L)) == 0);
+
+            if (bitRemained == 0)
+            {
+
+                randomBit = CommonFunction.load64(seedExpander, (j++) * Const.LONG_SIZE / Const.INT_SIZE);
+                bitRemained = 64;
+
+            }
+
+            sign = randomBit >> 63;
+            randomBit <<= 1;
+            bitRemained--;
+            k = ((k << 1) & sign) - k;
+            data[dataOffset + index] = (k << 48) >> 48;
+
+        }
+
+    }
+
+    /*************************************************************************************************************************
+     * Description:	Encoding of C' by Mapping the Output of the Hash Function H to An N-Element Vector with Entries {-1, 0, 1}
+     *
+     * @param        positionList            {0, ..., n - 1} ^ h
+     * @param        signList            {-1, +1} ^ h
+     * @param        output                Result of the Hash Function H
+     * @param        outputOffset        Starting Point of the Result of the Hash Function H
+     * @param        n                    Polynomial Degree
+     * @param        h                    Number of Non-Zero Entries of Output Elements of Encryption
+     *
+     * @return none
+     *************************************************************************************************************************/
+    public static void encodeC(int[] positionList, short[] signList, byte[] output, int outputOffset, int n, int h)
+    {
+
+        int count = 0;
+        int position;
+        short domainSeparator = 0;
+        short[] C = new short[n];
+        byte[] randomness = new byte[HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE];
+
+        /* Use the Hash Value as Key to Generate Some Randomness */
+        HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+            randomness, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE,
+            domainSeparator++,
+            output, outputOffset, Polynomial.RANDOM
+        );
+
+        /* Use Rejection Sampling to Determine Positions to be Set in the New Vector */
+        Arrays.fill(C, (short)0);
+
+        /* Sample A Unique Position k times.
+         * Use Two Bytes
+         */
+        for (int i = 0; i < h; )
+        {
+
+            if (count > HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE - 3)
+            {
+
+                HashUtils.customizableSecureHashAlgorithmKECCAK128Simple(
+                    randomness, 0, HashUtils.SECURE_HASH_ALGORITHM_KECCAK_128_RATE,
+                    domainSeparator++,
+                    output, outputOffset, Polynomial.RANDOM
+                );
+
+                count = 0;
+
+            }
+
+            position = (randomness[count] << 8) | (randomness[count + 1] & 0xFF);
+            position &= (n - 1);
+
+            /* Position is between [0, n - 1] and Has not Been Set Yet
+             * Determine Signature
+             */
+            if (C[position] == 0)
+            {
+
+                if ((randomness[count + 2] & 1) == 1)
+                {
+
+                    C[position] = -1;
+
+                }
+                else
+                {
+
+                    C[position] = 1;
+
+                }
+
+                positionList[i] = position;
+                signList[i] = C[position];
+                i++;
+
+            }
+
+            count += 3;
+
+        }
+
+    }
+
+    private static long round(double v)
+    {
+        if (v < 0)
+        {
+            return (long)(v - 0.5);
+        }
+        else
+        {
+            return (long)(v + 0.5);
+        }
+    }
+}
\ No newline at end of file
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyPairGenerator.java
index 03a9f20aa..314bbb679 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyPairGenerator.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256KeyPairGenerator.java
@@ -42,6 +42,7 @@ public class SPHINCS256KeyPairGenerator
         // Construct top subtree
         Tree.treehash(hs, pk, (Horst.N_MASKS * SPHINCS256Config.HASH_BYTES), SPHINCS256Config.SUBTREE_HEIGHT, sk, a, pk, 0);
 
-        return new AsymmetricCipherKeyPair(new SPHINCSPublicKeyParameters(pk), new SPHINCSPrivateKeyParameters(sk));
+        return new AsymmetricCipherKeyPair(new SPHINCSPublicKeyParameters(pk, treeDigest.getAlgorithmName()),
+                            new SPHINCSPrivateKeyParameters(sk, treeDigest.getAlgorithmName()));
     }
 }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Signer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Signer.java
index 2d190894b..314e9a08a 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Signer.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCS256Signer.java
@@ -2,6 +2,7 @@ package com.fr.third.org.bouncycastle.pqc.crypto.sphincs;
 
 import com.fr.third.org.bouncycastle.crypto.CipherParameters;
 import com.fr.third.org.bouncycastle.crypto.Digest;
+import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom;
 import com.fr.third.org.bouncycastle.pqc.crypto.MessageSigner;
 import com.fr.third.org.bouncycastle.util.Pack;
 
@@ -48,7 +49,12 @@ public class SPHINCS256Signer
     {
          if (forSigning)
          {
-             keyData = ((SPHINCSPrivateKeyParameters)param).getKeyData();
+             if (param instanceof ParametersWithRandom) {
+                 // SPHINCS-256 signatures are deterministic, RNG is not required.
+                 keyData = ((SPHINCSPrivateKeyParameters)((ParametersWithRandom) param).getParameters()).getKeyData();
+             } else {
+                 keyData = ((SPHINCSPrivateKeyParameters) param).getKeyData();
+             }
          }
          else
          {
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSKeyParameters.java
new file mode 100644
index 000000000..b1633f6eb
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSKeyParameters.java
@@ -0,0 +1,30 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.sphincs;
+
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+
+public class SPHINCSKeyParameters
+    extends AsymmetricKeyParameter
+{
+    /**
+     * Use SHA512-256 for the tree generation function.
+     */
+    public static final String SHA512_256 = "SHA-512/256";
+
+    /**
+     * Use SHA3-256 for the tree generation function.
+     */
+    public static final String SHA3_256 = "SHA3-256";
+
+    private final String treeDigest;
+
+    protected SPHINCSKeyParameters(boolean isPrivateKey, String treeDigest)
+    {
+        super(isPrivateKey);
+        this.treeDigest = treeDigest;
+    }
+
+    public String getTreeDigest()
+    {
+        return treeDigest;
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPrivateKeyParameters.java
index 21580fe05..29cec8550 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPrivateKeyParameters.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPrivateKeyParameters.java
@@ -1,16 +1,21 @@
 package com.fr.third.org.bouncycastle.pqc.crypto.sphincs;
 
-import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
 import com.fr.third.org.bouncycastle.util.Arrays;
 
 public class SPHINCSPrivateKeyParameters
-    extends AsymmetricKeyParameter
+    extends SPHINCSKeyParameters
 {
     private final byte[] keyData;
 
     public SPHINCSPrivateKeyParameters(byte[] keyData)
     {
-        super(true);
+        super(true, null);
+        this.keyData = Arrays.clone(keyData);
+    }
+
+    public SPHINCSPrivateKeyParameters(byte[] keyData, String treeDigest)
+    {
+        super(true, treeDigest);
         this.keyData = Arrays.clone(keyData);
     }
 
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPublicKeyParameters.java
index d03b7661e..4db8914f3 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPublicKeyParameters.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/sphincs/SPHINCSPublicKeyParameters.java
@@ -1,16 +1,22 @@
 package com.fr.third.org.bouncycastle.pqc.crypto.sphincs;
 
-import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
 import com.fr.third.org.bouncycastle.util.Arrays;
 
 public class SPHINCSPublicKeyParameters
-    extends AsymmetricKeyParameter
+    extends SPHINCSKeyParameters
 {
     private final byte[] keyData;
 
     public SPHINCSPublicKeyParameters(byte[] keyData)
     {
-        super(false);
+        super(false, null);
+        this.keyData = Arrays.clone(keyData);
+    }
+
+    public SPHINCSPublicKeyParameters(byte[] keyData, String treeDigest)
+    {
+
+        super(false, treeDigest);
         this.keyData = Arrays.clone(keyData);
     }
 
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java
new file mode 100644
index 000000000..039cfc1a9
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/GMSSSignerTest.java
@@ -0,0 +1,140 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar;
+import com.fr.third.org.bouncycastle.crypto.Digest;
+import com.fr.third.org.bouncycastle.crypto.Signer;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA224Digest;
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.fr.third.org.bouncycastle.pqc.crypto.DigestingMessageSigner;
+import com.fr.third.org.bouncycastle.pqc.crypto.DigestingStateAwareMessageSigner;
+import com.fr.third.org.bouncycastle.pqc.crypto.gmss.GMSSDigestProvider;
+import com.fr.third.org.bouncycastle.pqc.crypto.gmss.GMSSKeyGenerationParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.gmss.GMSSKeyPairGenerator;
+import com.fr.third.org.bouncycastle.pqc.crypto.gmss.GMSSParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.gmss.GMSSPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.gmss.GMSSSigner;
+import com.fr.third.org.bouncycastle.pqc.crypto.gmss.GMSSStateAwareSigner;
+import com.fr.third.org.bouncycastle.util.BigIntegers;
+import com.fr.third.org.bouncycastle.util.Strings;
+import com.fr.third.org.bouncycastle.util.encoders.Hex;
+import com.fr.third.org.bouncycastle.util.test.FixedSecureRandom;
+import com.fr.third.org.bouncycastle.util.test.SimpleTest;
+
+
+public class GMSSSignerTest
+    extends SimpleTest
+{
+    byte[] keyData = Hex.decode("b5014e4b60ef2ba8b6211b4062ba3224e0427dd3");
+
+    SecureRandom keyRandom = new FixedSecureRandom(
+        new FixedSecureRandom.Source[]{new FixedSecureRandom.Data(keyData), new FixedSecureRandom.Data(keyData)});
+
+    public String getName()
+    {
+        return "GMSS";
+    }
+
+    public void performTest()
+        throws Exception
+    {
+
+        GMSSParameters params = new GMSSParameters(3,
+            new int[]{15, 15, 10}, new int[]{5, 5, 4}, new int[]{3, 3, 2});
+
+        GMSSDigestProvider digProvider = new GMSSDigestProvider()
+        {
+            public Digest get()
+            {
+                return new SHA224Digest();
+            }
+        };
+
+        GMSSKeyPairGenerator gmssKeyGen = new GMSSKeyPairGenerator(digProvider);
+
+        GMSSKeyGenerationParameters genParam = new GMSSKeyGenerationParameters(keyRandom, params);
+
+        gmssKeyGen.init(genParam);
+
+        AsymmetricCipherKeyPair pair = gmssKeyGen.generateKeyPair();
+
+        GMSSPrivateKeyParameters privKey = (GMSSPrivateKeyParameters)pair.getPrivate();
+
+        ParametersWithRandom param = new ParametersWithRandom(privKey, keyRandom);
+
+        // TODO
+        Signer gmssSigner = new DigestingMessageSigner(new GMSSSigner(digProvider), new SHA224Digest());
+        gmssSigner.init(true, param);
+
+        byte[] message = BigIntegers.asUnsignedByteArray(new BigInteger("968236873715988614170569073515315707566766479517"));
+        gmssSigner.update(message, 0, message.length);
+        byte[] sig = gmssSigner.generateSignature();
+
+
+        gmssSigner.init(false, pair.getPublic());
+        gmssSigner.update(message, 0, message.length);
+        if (!gmssSigner.verifySignature(sig))
+        {
+            fail("verification fails");
+        }
+
+        if (!((GMSSPrivateKeyParameters)pair.getPrivate()).isUsed())
+        {
+            fail("private key not marked as used");
+        }
+
+        stateAwareTest(privKey.nextKey(), pair.getPublic());
+    }
+
+    private void stateAwareTest(GMSSPrivateKeyParameters privKey, AsymmetricKeyParameter pub)
+    {
+        DigestingStateAwareMessageSigner statefulSigner = new DigestingStateAwareMessageSigner(new GMSSStateAwareSigner(new SHA224Digest()), new SHA224Digest());
+        statefulSigner.init(true, new ParametersWithRandom(privKey, CryptoServicesRegistrar.getSecureRandom()));
+
+        byte[] mes1 = Strings.toByteArray("Message One");
+        statefulSigner.update(mes1, 0, mes1.length);
+        byte[] sig1 = statefulSigner.generateSignature();
+
+        isTrue(privKey.isUsed());
+
+        byte[] mes2 = Strings.toByteArray("Message Two");
+        statefulSigner.update(mes2, 0, mes2.length);
+        byte[] sig2 = statefulSigner.generateSignature();
+
+        GMSSPrivateKeyParameters recoveredKey = (GMSSPrivateKeyParameters)statefulSigner.getUpdatedPrivateKey();
+
+        isTrue(recoveredKey.isUsed() == false);
+
+        try
+        {
+            statefulSigner.generateSignature();
+        }
+        catch (IllegalStateException e)
+        {
+            isEquals("signing key no longer usable", e.getMessage());
+        }
+
+        statefulSigner.init(false, pub);
+        statefulSigner.update(mes2, 0, mes2.length);
+        if (!statefulSigner.verifySignature(sig2))
+        {
+            fail("verification two fails");
+        }
+
+        statefulSigner.update(mes1, 0, mes1.length);
+        if (!statefulSigner.verifySignature(sig1))
+        {
+            fail("verification one fails");
+        }
+    }
+
+    public static void main(
+        String[] args)
+    {
+        runTest(new GMSSSignerTest());
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McElieceCipherTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McElieceCipherTest.java
new file mode 100644
index 000000000..94975d397
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McElieceCipherTest.java
@@ -0,0 +1,102 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.fr.third.org.bouncycastle.crypto.Digest;
+import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest;
+import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceCipher;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceKeyGenerationParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceParameters;
+import com.fr.third.org.bouncycastle.util.test.SimpleTest;
+
+public class McElieceCipherTest
+    extends SimpleTest
+{
+
+    SecureRandom keyRandom = new SecureRandom();
+
+    public String getName()
+    {
+        return "McEliecePKCS";
+
+    }
+
+
+    public void performTest()
+        throws InvalidCipherTextException
+    {
+        int numPassesKPG = 1;
+        int numPassesEncDec = 10;
+        Random rand = new Random();
+        byte[] mBytes;
+        for (int j = 0; j < numPassesKPG; j++)
+        {
+
+            McElieceParameters params = new McElieceParameters();
+            McElieceKeyPairGenerator mcElieceKeyGen = new McElieceKeyPairGenerator();
+            McElieceKeyGenerationParameters genParam = new McElieceKeyGenerationParameters(keyRandom, params);
+
+            mcElieceKeyGen.init(genParam);
+            AsymmetricCipherKeyPair pair = mcElieceKeyGen.generateKeyPair();
+
+            ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom);
+            Digest msgDigest = new SHA256Digest();
+            McElieceCipher mcEliecePKCSDigestCipher = new McElieceCipher();
+
+
+            for (int k = 1; k <= numPassesEncDec; k++)
+            {
+                System.out.println("############### test: " + k);
+                // initialize for encryption
+                mcEliecePKCSDigestCipher.init(true, param);
+
+                // generate random message
+                int mLength = (rand.nextInt() & 0x1f) + 1;
+                mBytes = new byte[mLength];
+                rand.nextBytes(mBytes);
+
+                // encrypt
+                msgDigest.update(mBytes, 0, mBytes.length);
+                byte[] hash = new byte[msgDigest.getDigestSize()];
+
+                msgDigest.doFinal(hash, 0);
+
+                byte[] enc = mcEliecePKCSDigestCipher.messageEncrypt(hash);
+
+                // initialize for decryption
+                mcEliecePKCSDigestCipher.init(false, pair.getPrivate());
+                byte[] constructedmessage = mcEliecePKCSDigestCipher.messageDecrypt(enc);
+
+                boolean verified = true;
+                for (int i = 0; i < hash.length; i++)
+                {
+                    verified = verified && hash[i] == constructedmessage[i];
+                }
+
+                if (!verified)
+                {
+                    fail("en/decryption fails");
+                }
+                else
+                {
+                    System.out.println("test okay");
+                    System.out.println();
+                }
+
+            }
+        }
+
+    }
+
+    public static void main(
+        String[] args)
+    {
+        runTest(new McElieceCipherTest());
+    }
+
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McElieceFujisakiCipherTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McElieceFujisakiCipherTest.java
new file mode 100644
index 000000000..44ab6fd08
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McElieceFujisakiCipherTest.java
@@ -0,0 +1,103 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.fr.third.org.bouncycastle.crypto.Digest;
+import com.fr.third.org.bouncycastle.crypto.InvalidCipherTextException;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest;
+import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceFujisakiCipher;
+import com.fr.third.org.bouncycastle.util.test.SimpleTest;
+
+public class McElieceFujisakiCipherTest
+    extends SimpleTest
+{
+
+    SecureRandom keyRandom = new SecureRandom();
+
+    public String getName()
+    {
+        return "McElieceFujisaki";
+
+    }
+
+
+    public void performTest()
+        throws InvalidCipherTextException
+    {
+        int numPassesKPG = 1;
+        int numPassesEncDec = 10;
+        Random rand = new Random();
+        byte[] mBytes;
+        for (int j = 0; j < numPassesKPG; j++)
+        {
+            McElieceCCA2Parameters params = new McElieceCCA2Parameters();
+            McElieceCCA2KeyPairGenerator mcElieceCCA2KeyGen = new McElieceCCA2KeyPairGenerator();
+            McElieceCCA2KeyGenerationParameters genParam = new McElieceCCA2KeyGenerationParameters(keyRandom, params);
+
+            mcElieceCCA2KeyGen.init(genParam);
+            AsymmetricCipherKeyPair pair = mcElieceCCA2KeyGen.generateKeyPair();
+
+            ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom);
+            Digest msgDigest = new SHA256Digest();
+            McElieceFujisakiCipher mcElieceFujisakiDigestCipher = new McElieceFujisakiCipher();
+
+
+            for (int k = 1; k <= numPassesEncDec; k++)
+            {
+                System.out.println("############### test: " + k);
+                // initialize for encryption
+                mcElieceFujisakiDigestCipher.init(true, param);
+
+                // generate random message
+                int mLength = (rand.nextInt() & 0x1f) + 1;;
+                mBytes = new byte[mLength];
+                rand.nextBytes(mBytes);
+
+                msgDigest.update(mBytes, 0, mBytes.length);
+                byte[] hash = new byte[msgDigest.getDigestSize()];
+                msgDigest.doFinal(hash, 0);
+
+                // encrypt
+                byte[] enc = mcElieceFujisakiDigestCipher.messageEncrypt(hash);
+
+                // initialize for decryption
+                mcElieceFujisakiDigestCipher.init(false, pair.getPrivate());
+                byte[] constructedmessage = mcElieceFujisakiDigestCipher.messageDecrypt(enc);
+
+                // XXX write in McElieceFujisakiDigestCipher?
+
+
+                boolean verified = true;
+                for (int i = 0; i < hash.length; i++)
+                {
+                    verified = verified && hash[i] == constructedmessage[i];
+                }
+
+                if (!verified)
+                {
+                    fail("en/decryption fails");
+                }
+                else
+                {
+                    System.out.println("test okay");
+                    System.out.println();
+                }
+
+            }
+        }
+
+    }
+
+    public static void main(
+        String[] args)
+    {
+        runTest(new McElieceFujisakiCipherTest());
+    }
+
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McElieceKobaraImaiCipherTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McElieceKobaraImaiCipherTest.java
new file mode 100644
index 000000000..9679d8de2
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McElieceKobaraImaiCipherTest.java
@@ -0,0 +1,102 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.fr.third.org.bouncycastle.crypto.Digest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest;
+import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceKobaraImaiCipher;
+import com.fr.third.org.bouncycastle.util.test.SimpleTest;
+
+public class McElieceKobaraImaiCipherTest
+    extends SimpleTest
+{
+
+    SecureRandom keyRandom = new SecureRandom();
+
+    public String getName()
+    {
+        return "McElieceKobaraImai";
+
+    }
+
+
+    public void performTest()
+        throws Exception
+    {
+        int numPassesKPG = 0;   // TODO: this algorithm is broken
+        int numPassesEncDec = 10;
+        Random rand = new Random();
+        byte[] mBytes;
+        for (int j = 0; j < numPassesKPG; j++)
+        {
+
+            McElieceCCA2Parameters params = new McElieceCCA2Parameters("SHA-256");
+            McElieceCCA2KeyPairGenerator mcElieceCCA2KeyGen = new McElieceCCA2KeyPairGenerator();
+            McElieceCCA2KeyGenerationParameters genParam = new McElieceCCA2KeyGenerationParameters(keyRandom, params);
+
+            mcElieceCCA2KeyGen.init(genParam);
+            AsymmetricCipherKeyPair pair = mcElieceCCA2KeyGen.generateKeyPair();
+
+            ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom);
+            Digest msgDigest = new SHA256Digest();
+            McElieceKobaraImaiCipher mcElieceKobaraImaiDigestCipher = new McElieceKobaraImaiCipher();
+
+
+            for (int k = 1; k <= numPassesEncDec; k++)
+            {
+                System.out.println("############### test: " + k);
+                // initialize for encryption
+                mcElieceKobaraImaiDigestCipher.init(true, param);
+
+                // generate random message
+                int mLength = (rand.nextInt() & 0x1f) + 1;
+                mBytes = new byte[mLength];
+                rand.nextBytes(mBytes);
+
+                msgDigest.update(mBytes, 0, mBytes.length);
+                byte[] hash = new byte[msgDigest.getDigestSize()];
+                msgDigest.doFinal(hash, 0);
+
+                // encrypt
+                byte[] enc = mcElieceKobaraImaiDigestCipher.messageEncrypt(hash);
+
+                // initialize for decryption
+                mcElieceKobaraImaiDigestCipher.init(false, pair.getPrivate());
+                byte[] constructedmessage = mcElieceKobaraImaiDigestCipher.messageDecrypt(enc);
+
+                // XXX write in McElieceFujisakiDigestCipher?
+
+                boolean verified = true;
+                for (int i = 0; i < hash.length; i++)
+                {
+                    verified = verified && hash[i] == constructedmessage[i];
+                }
+
+                if (!verified)
+                {
+                    fail("en/decryption fails");
+                }
+                else
+                {
+                    System.out.println("test okay");
+                    System.out.println();
+                }
+
+            }
+        }
+
+    }
+
+    public static void main(
+        String[] args)
+    {
+        runTest(new McElieceKobaraImaiCipherTest());
+    }
+
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McEliecePointchevalCipherTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McEliecePointchevalCipherTest.java
new file mode 100644
index 000000000..b4284f946
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/McEliecePointchevalCipherTest.java
@@ -0,0 +1,102 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+import java.security.SecureRandom;
+import java.util.Random;
+
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.fr.third.org.bouncycastle.crypto.Digest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest;
+import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyGenerationParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2KeyPairGenerator;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceCCA2Parameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McEliecePointchevalCipher;
+import com.fr.third.org.bouncycastle.util.test.SimpleTest;
+
+public class McEliecePointchevalCipherTest
+    extends SimpleTest
+{
+
+    SecureRandom keyRandom = new SecureRandom();
+
+    public String getName()
+    {
+        return "McElieceFujisaki";
+
+    }
+
+
+    public void performTest()
+        throws Exception
+    {
+        int numPassesKPG = 1;
+        int numPassesEncDec = 10;
+        Random rand = new Random();
+        byte[] mBytes;
+        for (int j = 0; j < numPassesKPG; j++)
+        {
+
+            McElieceCCA2Parameters params = new McElieceCCA2Parameters("SHA-256");
+            McElieceCCA2KeyPairGenerator mcElieceCCA2KeyGen = new McElieceCCA2KeyPairGenerator();
+            McElieceCCA2KeyGenerationParameters genParam = new McElieceCCA2KeyGenerationParameters(keyRandom, params);
+
+            mcElieceCCA2KeyGen.init(genParam);
+            AsymmetricCipherKeyPair pair = mcElieceCCA2KeyGen.generateKeyPair();
+
+            ParametersWithRandom param = new ParametersWithRandom(pair.getPublic(), keyRandom);
+            Digest msgDigest = new SHA256Digest();
+            McEliecePointchevalCipher mcEliecePointchevalDigestCipher = new McEliecePointchevalCipher();
+
+
+            for (int k = 1; k <= numPassesEncDec; k++)
+            {
+                System.out.println("############### test: " + k);
+                // initialize for encryption
+                mcEliecePointchevalDigestCipher.init(true, param);
+
+                // generate random message
+                int mLength = (rand.nextInt() & 0x1f) + 1;
+                mBytes = new byte[mLength];
+                rand.nextBytes(mBytes);
+
+                msgDigest.update(mBytes, 0, mBytes.length);
+                byte[] hash = new byte[msgDigest.getDigestSize()];
+                msgDigest.doFinal(hash, 0);
+
+                // encrypt
+                byte[] enc = mcEliecePointchevalDigestCipher.messageEncrypt(hash);
+
+                // initialize for decryption
+                mcEliecePointchevalDigestCipher.init(false, pair.getPrivate());
+                byte[] constructedmessage = mcEliecePointchevalDigestCipher.messageDecrypt(enc);
+
+                // XXX write in McElieceFujisakiDigestCipher?
+
+                boolean verified = true;
+                for (int i = 0; i < hash.length; i++)
+                {
+                    verified = verified && hash[i] == constructedmessage[i];
+                }
+
+                if (!verified)
+                {
+                    fail("en/decryption fails");
+                }
+                else
+                {
+                    System.out.println("test okay");
+                    System.out.println();
+                }
+
+            }
+        }
+
+    }
+
+    public static void main(
+        String[] args)
+    {
+        runTest(new McEliecePointchevalCipherTest());
+    }
+
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/NewHopeTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/NewHopeTest.java
new file mode 100644
index 000000000..d9b8dcbe1
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/NewHopeTest.java
@@ -0,0 +1,227 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+import java.io.IOException;
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.asn1.oiw.OIWObjectIdentifiers;
+import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.fr.third.org.bouncycastle.crypto.KeyGenerationParameters;
+import com.fr.third.org.bouncycastle.crypto.util.DEROtherInfo;
+import com.fr.third.org.bouncycastle.pqc.crypto.ExchangePair;
+import com.fr.third.org.bouncycastle.pqc.crypto.newhope.NHAgreement;
+import com.fr.third.org.bouncycastle.pqc.crypto.newhope.NHExchangePairGenerator;
+import com.fr.third.org.bouncycastle.pqc.crypto.newhope.NHKeyPairGenerator;
+import com.fr.third.org.bouncycastle.pqc.crypto.newhope.NHOtherInfoGenerator;
+import com.fr.third.org.bouncycastle.util.Arrays;
+import com.fr.third.org.bouncycastle.util.encoders.Hex;
+import com.fr.third.org.bouncycastle.util.test.SimpleTest;
+
+public class NewHopeTest
+    extends SimpleTest
+{
+//    private static final byte[] SECRETA = Hex.decode(
+//        "0823190c27cf2066195d13721d702f1e2248309e124927d5182f175e348a1e800791357825800808223e236e22c41d4e081a2499139e238814590f3d296e34d7"
+//            + "1eaa25fb37aa2dac36fa0bba1b0b113616df29a620150bdb12071636186c27ae1546264f33182e4e11330d8e3024138d2dff18de0f411d930f2f11840a6d1e3c"
+//            + "0b0b18a81a8014eb364514f00c3a1ab41295314233e2167b049c3481103f243910ac1eaf16da23322b83227738f02b4d26782f8d0e542e04087319981c760ba8"
+//            + "329c303f1b0223b429050ef8121220772cc91355309a36051da5282318fe34c60e7034872b10188e2bc1338e0e890a6a13e508cb12dc261d34bb15950fe82f32"
+//            + "1cc8090413ec2c1127b1369b28cd0ada154d307a0e582b85240e24e525af20371d6d0c7e0dcb08b60cc023f10afe166323230f3a0a87279f0cd70e8d29b22c95"
+//            + "160d13be312131b032103349346e324f1ff812001770269e31c0251a0ab4221a1cdd2d93215b226d19a12cb407cc287c11d821a00a8022182d1725cb13a50d79"
+//            + "303d1d680d111367188932891d771f552fb014d62d0214d534b023a70da30c753212167608ae1ac72e4d26c917491bb1204f23b734eb20171a1e26ae22ae2715"
+//            + "116933b60cce1d3717701d051d980b9512ca0eb1189e188f0e2c2cd30c800c6024b310d732d6124723c207b5184818e4308f1c1e22921dee32a91f4a0b8b2e28"
+//            + "2c290685063f192628701d701d68196f284a2664234d1aa42af7120d1b2532b3168930aa26a51acf2a8214a50c6b330e059315e205c6297f2fc10d420f8d0680"
+//            + "28652c0b1119307f09a30b881d5709d52b6e2a2e1eeb19260f521c77066c18ce27262f0b048428ab1eb20ee71e9c066408b909a5275a09da2ebe254b176518ba"
+//            + "12e723df13ef152d1d112d700e1622681fa1310a2000138b09f8315622612e492df60d222a430bac2abd06e125a91e1907c92c3a19f829312a6f2dad0aca1772"
+//            + "03f1142b0b2f0bfd17a009c60eb913fe32c908590e8f300521dd31880f2b12a8215f1dfa1d8f168228730fc11ae80ca015da0bd412271c8827512325311b1b83"
+//            + "1ef2227723b605af2d7015bd14bf17b712aa304c30821a181bff1f7b22d6323b067a232526720fd91ed8054730e714ad163220a11986213a1c2d1af22958207c"
+//            + "2d3428922d710d33207a23831f430a792658042719762dd50b811f412cb20486315219ed084c1b221570327226b60e1907b224b215911ab3266128cf21c623f4"
+//            + "08930e9230331dba23790b5c0fdb26530d97323712cd279612d40c7a14341fc323a32893131c2cf520412ca60c28059a09c8181b2303275e2c13119c22772d28"
+//            + "1f5304941900134f07d2085b1dd9107b03ab0ce118d206be2eb32d3c0d981bcb0b1920f80b6c0e7b311118cc16542bb61f1005dc0fa9319b25d1165f234d0fdc"
+//            + "08e41cc4035605ad04990a0a14142e81172228b31963098a20ac27b723e9161922432b4330ef102d1067316f239e107f071d11e4053b182817f715b72c3a1ab4"
+//            + "1b0213a419c618060d9e0ba01be010820ed41e8e28580cd12bd81f7a1f4505be21862ac1262601b814ad10241476048d211c2d541834319909dd0ed11c4c29b8"
+//            + "1ba22af20689271821210b22049c0e391f6e0a6406ae1a2d06f322f80db72973127719e70fbb17070f460f732999089523ae28dd1347263431831a932264294a"
+//            + "0dc005b6211116c42daf232623ef12fa08040bc8183e1bec1d0510bd2c5f11aa20d60e5405672d46244b2b5b2c5e18740e37304c13b311ac2fb5266129600af1"
+//            + "0edc0ccb1b5030bc1abf0c1913b425c0144711a922040f352d5a2c3610390db626142ea614430503062a252f030a20a22ec4308d14fd17be19b12bac06752f86"
+//            + "237330d7132006e5229106e52a3b1d64081503c40fd230cd19ae0be3243b2c0b02601e0809421bff0ed72ede16b5201a0a9f27871c4832e023d82a40056f0584"
+//            + "136204270dbf1b0103a627c00e9315ce02b004ac1e0e06e025b526cd0e60252231d706c01d5c32fb26fc31452d3a282b20a02c042eb721d10c1126d105702c27"
+//            + "21ed246f18482f0e1cf802632ec20da91a501217277516850e0321ab0a3f06d80bb3241d0fee170b247d1be804700cdb28831720108f2e9924312f9a232f197f"
+//            + "2aad15b91534092413621c6630f623280b36208014c92fe41d9306982d0d19141b0e053e09f915001fce27b90b521bf00502151114641c50066508f12a290bb4"
+//            + "2cb908c22ef225262ddc121a0b3c2a9829f40b8719e616520b1b1c250a94160b19690a552bc22e452086266b315e14bc1240038c31f0098005d22e4e073711ef"
+//            + "040d2df103f42555198d30d80eed31c71852035817a80788070c201f286017bc0f082a8b23412f9328f1166f147529e62c2f210e16be1ade0e821346103322f6"
+//            + "222d1178119d299a1fd6272415b80d390fd4131a0e6712dd197305a40fd43157302725b315961b952b0513ff0278266c3015077120542d991b7808882b750f3a"
+//            + "093906f61288181d269f10aa22782eb5280410d82dc132170e8d1ef71cb5068219491c7514db31420f7e2df627372e5713a8073d2817025d2b862b3004ac2f8f"
+//            + "22e11c8f03cc259520d427fb100218a522121be202a22e0f29080f1b23e524941efa21a80d350f76317811d01c7d101b24e10c9e0bed1bbc21e821e31eb7044e"
+//            + "2c80287609b123071daa0b93051b2dd205b515a325d92643087814fe1978286a02c03110301b31d121b6261002e91ecb275f090a2afb230612302fbf12f21d2a"
+//            + "23771846087324ed14930694317703ac278a249e19af11350e3f05882a5d2b3f26d229f628da06cf06732f7317cc230c2bda037609f5186e2a2e29882b3d1757");
+//
+//    private static final byte[] SENDB = Hex.decode(
+//        "8c06d4972b4521374d5ce3404823db20bd5b6288795faa324216a54e8cdcd20676ba83609f5db66a1967a6079f9126e512061cf9d58dea45e7814e22c9bc2ff3"
+//            + "661546a65985f70da5fb10d675352211e847387c1b5dc0badd34284a552d7904680528d0dbb74e69ab90d844b149d81613a09c46fa6690b845707a6970953755"
+//            + "10b2abfc4675a85e3b48908011e4b53bdce691ae64c7c48f35b8c7e02cd68a0eb745139ee560984d015d4d94252408a715f0e58306ad84532794a57a75859499"
+//            + "14c4ad68b74189f0ac4d7c8947299a12d981cc2ff3581636b1515cd7b73d103def24321a05a489b8849bb3fa64b5ab690e2a57d4359621d56be79c1f396ed3e2"
+//            + "63068c138e64a26be6851dd971a69fe07adea867f1323655ed934ce6ae103464cc2ba96ff038996b0bc9321e1fec6a9844c5389eb6897aa98755aebacbbf9379"
+//            + "258b8311a4c44e7287edc6bd8765840eccc7c8b322e57131908ab33985b79b9c1c91077c8d41dedcbad2505459293dba42d0bf56d8f298ad216f7ad26fa817f6"
+//            + "4f2e525604d4092f36014e0698660c804b28e1e03e98d391636516e11b7d8d4eb82b60bec3a3bbd4944068574159517028a5d06e721a187e0a9f294569964e96"
+//            + "9a56cd371ea8556ea76151a75a4bce622d885f9892c92537ab63c17d43a79704988443980c2cd35ac69c916457e3b230087bcc92c34c607b7a633ae32c39bbbd"
+//            + "ad4bf0f98a957e854078061991256da5cbc0d07d0a8a610b1be0063cc8271716866174c28810ad4d40d7d916bafb7a1c8253826569dd2e16d4c5f48baea82fd5"
+//            + "d3412f9c680eaf0de8001c8c8766eb87fb81a771c67a269b155ee6a2e158719d205b0a8b7b89480e5c8ef7da18b8437f618c402ef11c5e8a6d59110962c94a4b"
+//            + "83a4587b58152ba895deab6c52beb9572474de1cbda147b189cbd4f1c400f985505dcf8497f65408ade1677ab434ecdc19aad3ba558e83aa5200b5555e812d2b"
+//            + "3320812b9e4fb47b20948c40269a115118b941be5926ad77c09b89a72f56be50c716e4016d384dda5fd0ab014847dccdd3044a94a8537e2b8e20043cc19be364"
+//            + "128632016321456ab2f390e29a43e42155656d5b5fb96a9812f71323b88899279f9b4da45fc26a6c91f7dd868e4aa12abef11b21e59e6758fd9c8118fb4aaeed"
+//            + "6700a8bcdad2228f9dd15593a3b1207d24f2a0d40034de9265f609acaa17e93cca96899f67811ffa9265786217d340f42a09316766d3fc8829a71d8ce7213433"
+//            + "c6c515fbd8b9626bc1b67a0f6946de4b886792aa2f77030d08532eadfea21e80d902b9d24472e363a26a6dd8cee685b88517438949373e4a11a18002240e0341"
+//            + "2c6057a230b7b51354891a86407ec612f8fdf538d08fd925812815c2d4a78ab2268e0f283e76dced3a410f396501643dbc494c55c9fd5c5ed08e28472100df58"
+//            + "2da681fc71fa200e83d3a860d556c456614c93f5c69e013d6c53ee6fe9423b9d277d4da32b6681af7d9e890b8fb01700d679881e017edd142d32f3e5bee54050"
+//            + "3372519abcc796b2d830042b0f7b97e639188b21c7231552053ed508b5ed851c0681d850230879a7c46f185a5a54b7dc1933c782434158fc43480d80d65714ab"
+//            + "54452d5544987187c655a2a3f41bbe187988c1a0702ad03a8c530262141c75830a6e962bda4f208f7a7a6f4ead5995b985bd3c5a5029aa92f6f56405c2d08155"
+//            + "6d860441e077e0053ae74061f9351e7927871b75625d0cb2433e205bb97030c5ccc9fffe9cedc62a683db90e396f2eb485305d62a76c782cbe66508bf5b130b2"
+//            + "8c8da2c993865d667e22e789301a1a94506d995d6a11581f4f314e7cbfcc4c65e7d76e48062ecff6fa32af5ac58b00b738421b211ad9ad060a3b2b67903ad28e"
+//            + "4b2214c3a14429a0d68369f856132b24e183c48991c28c35e6be2e83c1ccf078199189f55d835798008270cdbe409a5c9954c63e400e6d91694850e2352e8559"
+//            + "c34f19f7fd4c429bcb0bba944d8c0c41706361b967c96ba1eaa266cea84cd37f0c6a40caafaae8d40a89d0ca06967ca910d6a20a29685dfc2be692b0f9b0ec96"
+//            + "9723bc5996926bb2d806d86369a04dd7c272752467922128b2966b868b4559fe936baaf5c8b6892c916dab935381387da2e0f71cb26abf089913820a33b564a5"
+//            + "2b625d810c570cd147d212e649f994a1a2a7ac2e30e310f1be5359cb892016123cd27dd4efd64227eb83a90e99a79fcbc9176be25c838eb6eabbee8bbb455259"
+//            + "269197ac4c66ea383e5e265aeb1bf64c34ffd4779a6800ac4e12b1277a8c59b89f4c728cc93e71ec93c7bfd09a8e9cbf19bde439aa95a2a35c31ab4b4314d252"
+//            + "b5702f1ed69573fe12315f3561efc22ddb4b98a747922b4944c79457e430e9adbe98dcc0231bdc88a58bf67c034da18584dc7c49c776892236b67c1762f3eb1d"
+//            + "7f2323aebbf211b2b8074d29273847e50f8d43bcae33db20678a3ed61f7ac49ea6a3f0361cd0c1752c7a0a78ad52d8c9ae755b575dd28bf05b7b0ef438b85d89"
+//            + "f9edd1f598c8e972211d971df25d64d9a29fecb4de3c828219434ade29509f6170142ac0756b7176658fa4f3f7e00f2cac901db5e0bc6c3d5c0028572ff0de3a"
+//            + "f09cf1935e7c3231ad025570a895e9edbbe8d509df51a7297e729cf24e83c1e5237536417c96bc265addcf7b9f6e4dccfe45a4219b533d5db3c596cc2eed06ae"
+//            + "de6f4a9d6935367e204127eeb4547c38d830e7e9e99cac5effef27b8f57dd07c2e60e4d79ab22e250829d347c5a80730ed957a83334b1a1470d08db01b9552dc"
+//            + "092b1d3597c97f34332d4e1e503a3b755ade39b68a5ef9b9c13efd7cc4f47484dab6000750222510cfee516c5f23efdf70fd196fcf136a0bdb23745707a95a4a");
+//
+//    private static final byte[] KEYB = Hex.decode("5946400eed4b18ce8d7fb1f744e46e5689009aa4672526c0c59a0adb3dd3ca37");
+
+    private static final int ROUNDS = 1000;
+
+    private void testKeyExchange() throws Exception
+    {
+        SecureRandom aliceRand = new SecureRandom();
+        SecureRandom bobRand = new SecureRandom();
+
+        for (int i = 0; i < ROUNDS; ++i)
+        {
+            NHKeyPairGenerator kpGen = new NHKeyPairGenerator();
+
+            kpGen.init(new KeyGenerationParameters(aliceRand, 2048));
+
+            AsymmetricCipherKeyPair aliceKp = kpGen.generateKeyPair();
+
+            NHExchangePairGenerator exchGen = new NHExchangePairGenerator(bobRand);
+
+            ExchangePair bobExchPair = exchGen.generateExchange(aliceKp.getPublic());
+
+            NHAgreement agreement = new NHAgreement();
+
+            agreement.init(aliceKp.getPrivate());
+
+            byte[] aliceSharedKey = agreement.calculateAgreement(bobExchPair.getPublicKey());
+
+            isTrue("value mismatch", Arrays.areEqual(aliceSharedKey, bobExchPair.getSharedValue()));
+        }
+    }
+
+    private void testPrivInfoGeneration()
+        throws IOException
+    {
+        SecureRandom random = new SecureRandom();
+        NHOtherInfoGenerator.PartyU partyU = new NHOtherInfoGenerator.PartyU(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), Hex.decode("beef"), Hex.decode("cafe"), random);
+
+        byte[] partA = partyU.getSuppPrivInfoPartA();
+
+        NHOtherInfoGenerator.PartyV partyV = new NHOtherInfoGenerator.PartyV(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), Hex.decode("beef"), Hex.decode("cafe"), random);
+
+        byte[] partB = partyV.getSuppPrivInfoPartB(partA);
+
+        DEROtherInfo otherInfoU = partyU.generate(partB);
+
+        DEROtherInfo otherInfoV = partyV.generate();
+
+        areEqual(otherInfoU.getEncoded(), otherInfoV.getEncoded());
+    }
+
+    private void testReuse()
+        throws IOException
+    {
+        SecureRandom random = new SecureRandom();
+        NHOtherInfoGenerator.PartyU partyU = new NHOtherInfoGenerator.PartyU(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), Hex.decode("beef"), Hex.decode("cafe"), random);
+
+        byte[] partA = partyU.getSuppPrivInfoPartA();
+
+        NHOtherInfoGenerator.PartyV partyV = new NHOtherInfoGenerator.PartyV(new AlgorithmIdentifier(OIWObjectIdentifiers.idSHA1), Hex.decode("beef"), Hex.decode("cafe"), random);
+
+        byte[] partB = partyV.getSuppPrivInfoPartB(partA);
+
+        DEROtherInfo otherInfoU = partyU.generate(partB);
+
+        DEROtherInfo otherInfoV = partyV.generate();
+
+        areEqual(otherInfoU.getEncoded(), otherInfoV.getEncoded());
+
+        try
+        {
+            partyV.generate();
+            fail("no exception");
+        }
+        catch (IllegalStateException e)
+        {
+            isEquals("builder already used", e.getMessage());
+        }
+
+        try
+        {
+            partyU.generate(partB);
+            fail("no exception");
+        }
+        catch (IllegalStateException e)
+        {
+            isEquals("builder already used", e.getMessage());
+        }
+    }
+
+    private void testInterop()
+    {
+        /*
+         * Test interoperability with the C reference implementation as of:
+         *
+         *     https://github.com/tpoeppelmann/newhope/commit/bc06c1ac04101449797ae8d1029e73cdcd82f79f
+         *
+         * (version corresponding to the newhope-20160328.pdf paper).
+         * 
+         * Note that 'SENDB' and 'KEYB' were both generated by the C implementation upon receipt of a
+         * 'SENDA' (not kept) generated together with 'SECRETA'.
+         */
+
+        // NOTE: This passes as of writing, but requires public access to NewHope (currently package scope)
+        /*
+        short[] secretA = new short[SECRETA.length / 2];
+        for (int i = 0; i < secretA.length; ++i)
+        {
+            secretA[i] = Pack.bigEndianToShort(SECRETA, 2 * i);
+        }
+
+        byte[] keyA = new byte[NewHope.AGREEMENT_SIZE];
+        NewHope.sharedA(keyA, secretA, SENDB);
+
+        isTrue("value mismatch", Arrays.areEqual(keyA, KEYB));
+        */
+    }
+
+    public String getName()
+    {
+        return "NewHope";
+    }
+
+    public void performTest()
+        throws Exception
+    {
+        testKeyExchange();
+        testInterop();
+        testPrivInfoGeneration();
+        testReuse();
+    }
+
+    public static void main(
+            String[]    args)
+    {
+        runTest(new NewHopeTest());
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/NullPRNG.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/NullPRNG.java
new file mode 100644
index 000000000..b81d36c36
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/NullPRNG.java
@@ -0,0 +1,27 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+import java.security.SecureRandom;
+
+/**
+ * Implementation of null PRNG returning zeroes only. For testing purposes
+ * only(!).
+ */
+public final class NullPRNG
+    extends SecureRandom
+{
+
+    private static final long serialVersionUID = 1L;
+
+    public NullPRNG()
+    {
+        super();
+    }
+    
+    public void nextBytes(byte[] bytes)
+    {
+        for (int i = 0; i < bytes.length; i++)
+        {
+            bytes[i] = 0x00;
+        }
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/QTESLASecureRandomFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/QTESLASecureRandomFactory.java
new file mode 100644
index 000000000..abcaa7e08
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/QTESLASecureRandomFactory.java
@@ -0,0 +1,190 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+
+import com.fr.third.org.bouncycastle.util.test.FixedSecureRandom;
+
+/**
+ * Factory for producing FixedSecureRandom objects for use with testsing
+ */
+class QTESLASecureRandomFactory
+{
+    private byte[] seed;
+    private byte[] personalization;
+    private byte[] key;
+    private byte[] v;
+    int reseed_counuter = 1;
+
+
+    /**
+     * Return a seeded FixedSecureRandom representing the result of processing a
+     * qTESLA test seed with the qTESLA RandomNumberGenerator.
+     *
+     * @param seed original qTESLA seed
+     * @param strength bit-strength of the RNG required.
+     * @return a FixedSecureRandom containing the correct amount of seed material for use with Java.
+     */
+    public static FixedSecureRandom getFixed(byte[] seed, int strength)
+    {
+        return getFixed(seed,null, strength, strength / 8, strength / 8);
+    }
+
+    public static FixedSecureRandom getFixed(byte[] seed, byte[] personalization, int strength, int discard, int size)
+    {
+        QTESLASecureRandomFactory teslaRNG = new QTESLASecureRandomFactory(seed, personalization);
+        teslaRNG.init(strength);
+        byte[] burn = new byte[discard];
+        teslaRNG.nextBytes(burn);
+        if (discard != size)
+        {
+            burn = new byte[size];
+        }
+        teslaRNG.nextBytes(burn);
+        return new FixedSecureRandom(burn);
+    }
+
+
+    public static FixedSecureRandom getFixedNoDiscard(byte[] seed, int strength)
+    {
+        QTESLASecureRandomFactory teslaRNG = new QTESLASecureRandomFactory(seed, null);
+        teslaRNG.init(strength);
+        byte[] burn = new byte[strength / 8];
+        teslaRNG.nextBytes(burn);
+        return new FixedSecureRandom(burn);
+    }
+
+    private QTESLASecureRandomFactory(byte[] seed, byte[] personalization)
+    {
+        this.seed = seed;
+        this.personalization = personalization;
+    }
+
+
+    private void init(int strength)
+    {
+        randombytes_init(seed, personalization, strength);
+        reseed_counuter = 1;
+    }
+
+    private void nextBytes(byte[] x)
+    {
+        byte[] block = new byte[16];
+        int i = 0;
+
+        int xlen = x.length;
+
+        while (xlen > 0)
+        {
+            for (int j = 15; j >= 0; j--)
+            {
+                if ((v[j] & 0xFF) == 0xff)
+                {
+                    v[j] = 0x00;
+                }
+                else
+                {
+                    v[j]++;
+                    break;
+                }
+            }
+
+            AES256_ECB(key, v, block, 0);
+
+            if (xlen > 15)
+            {
+                System.arraycopy(block, 0, x, i, block.length);
+                i += 16;
+                xlen -= 16;
+            }
+            else
+            {
+                System.arraycopy(block, 0, x, i, xlen);
+                xlen = 0;
+            }
+        }
+
+        AES256_CTR_DRBG_Update(null, key, v);
+        reseed_counuter++;
+    }
+
+
+    private void AES256_ECB(byte[] key, byte[] ctr, byte[] buffer, int startPosition)
+    {
+        try
+        {
+            Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
+
+            cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES"));
+
+            cipher.doFinal(ctr, 0, ctr.length, buffer, startPosition);
+        }
+        catch (Throwable ex)
+        {
+            ex.printStackTrace();
+        }
+    }
+
+
+    private void AES256_CTR_DRBG_Update(byte[] entropy_input, byte[] key, byte[] v)
+    {
+
+        byte[] tmp = new byte[48];
+
+        for (int i = 0; i < 3; i++)
+        {
+            //increment V
+            for (int j = 15; j >= 0; j--)
+            {
+                if ((v[j] & 0xFF) == 0xff)
+                {
+                    v[j] = 0x00;
+                }
+                else
+                {
+                    v[j]++;
+                    break;
+                }
+            }
+
+            AES256_ECB(key, v, tmp, 16 * i);
+        }
+
+        if (entropy_input != null)
+        {
+            for (int i = 0; i < 48; i++)
+            {
+                tmp[i] ^= entropy_input[i];
+            }
+        }
+
+        System.arraycopy(tmp, 0, key, 0, key.length);
+        System.arraycopy(tmp, 32, v, 0, v.length);
+
+
+    }
+
+
+    private void randombytes_init(byte[] entropyInput, byte[] personalization, int strength)
+    {
+        byte[] seedMaterial = new byte[48];
+
+        System.arraycopy(entropyInput, 0, seedMaterial, 0, seedMaterial.length);
+        if (personalization != null)
+        {
+            for (int i = 0; i < 48; i++)
+            {
+                seedMaterial[i] ^= personalization[i];
+            }
+        }
+
+        key = new byte[32];
+        v = new byte[16];
+
+
+        AES256_CTR_DRBG_Update(seedMaterial, key, v);
+
+        reseed_counuter = 1;
+
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java
new file mode 100644
index 000000000..132ee69d5
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/RainbowSignerTest.java
@@ -0,0 +1,62 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+
+import java.math.BigInteger;
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA224Digest;
+import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom;
+import com.fr.third.org.bouncycastle.pqc.crypto.DigestingMessageSigner;
+import com.fr.third.org.bouncycastle.pqc.crypto.rainbow.RainbowKeyGenerationParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.rainbow.RainbowKeyPairGenerator;
+import com.fr.third.org.bouncycastle.pqc.crypto.rainbow.RainbowParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.rainbow.RainbowSigner;
+import com.fr.third.org.bouncycastle.util.BigIntegers;
+import com.fr.third.org.bouncycastle.util.test.SimpleTest;
+
+
+public class RainbowSignerTest
+extends SimpleTest
+{
+    public String getName()
+    {
+        return "Rainbow";
+    }
+
+    public void performTest()
+    {
+        RainbowParameters params = new RainbowParameters();
+
+        RainbowKeyPairGenerator rainbowKeyGen = new RainbowKeyPairGenerator();
+        RainbowKeyGenerationParameters genParam = new RainbowKeyGenerationParameters(new SecureRandom(), params);
+
+        rainbowKeyGen.init(genParam);
+
+        AsymmetricCipherKeyPair pair = rainbowKeyGen.generateKeyPair();
+
+        ParametersWithRandom param = new ParametersWithRandom(pair.getPrivate(), new SecureRandom());
+
+        DigestingMessageSigner rainbowSigner = new DigestingMessageSigner(new RainbowSigner() , new SHA224Digest());
+
+        rainbowSigner.init(true, param);
+
+        byte[] message = BigIntegers.asUnsignedByteArray(new BigInteger("968236873715988614170569073515315707566766479517"));
+        rainbowSigner.update(message, 0, message.length);
+        byte[] sig = rainbowSigner.generateSignature();
+
+        rainbowSigner.init(false, pair.getPublic());
+        rainbowSigner.update(message, 0, message.length);
+
+        if (!rainbowSigner.verifySignature(sig))
+        {
+            fail("verification fails");
+        }
+    }
+
+    public static void main(
+            String[]    args)
+    {
+        runTest(new RainbowSignerTest());
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/RegressionTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/RegressionTest.java
new file mode 100644
index 000000000..0bfe31d17
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/RegressionTest.java
@@ -0,0 +1,23 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+import com.fr.third.org.bouncycastle.util.test.SimpleTest;
+import com.fr.third.org.bouncycastle.util.test.Test;
+
+public class RegressionTest
+{
+    public static Test[]    tests = {
+        new GMSSSignerTest(),
+        new McElieceFujisakiCipherTest(),
+        new McElieceKobaraImaiCipherTest(),
+        new McElieceCipherTest(),
+        new McEliecePointchevalCipherTest(),
+        new RainbowSignerTest() ,
+        new Sphincs256Test(),
+        new NewHopeTest()
+    };
+
+    public static void main(String[] args)
+    {
+        SimpleTest.runTests(tests);
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/Sphincs256Test.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/Sphincs256Test.java
new file mode 100644
index 000000000..4227a65be
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/test/Sphincs256Test.java
@@ -0,0 +1,1679 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.test;
+
+import java.security.SecureRandom;
+
+import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA3Digest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA512tDigest;
+import com.fr.third.org.bouncycastle.pqc.crypto.MessageSigner;
+import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCS256KeyGenerationParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCS256KeyPairGenerator;
+import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCS256Signer;
+import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters;
+import com.fr.third.org.bouncycastle.util.Strings;
+import com.fr.third.org.bouncycastle.util.encoders.Base64;
+import com.fr.third.org.bouncycastle.util.test.SimpleTest;
+
+
+public class Sphincs256Test
+    extends SimpleTest
+{
+    // test vector courtesy the "Yawning Angel" GO implementation and the SUPERCOP reference implementation.
+    byte[] msg = Strings.toByteArray("Cthulhu Fthagn --What a wonderful phrase!Cthulhu Fthagn --Say it and you're crazed!");
+
+    byte[] expBlakePub = Base64.decode(
+        "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktM"
+            + "TU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5"
+            + "ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWm"
+            + "p6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT"
+            + "1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8A"
+            + "AQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywt"
+            + "Li8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFla"
+            + "W1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH"
+            + "iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0"
+            + "tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh"
+            + "4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0O"
+            + "DxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7"
+            + "PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdo"
+            + "aWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SV"
+            + "lpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHC"
+            + "w8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v"
+            + "8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhsc"
+            + "HR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJ"
+            + "SktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2"
+            + "d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKj"
+            + "pKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q"
+            + "0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9"
+            + "/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHweosZZTNIli4FJn"
+            + "DJwDmiT955i6r8DOENuXZL6Be24i");
+
+    byte[] expBlakePriv = Base64.decode(
+        "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKiss"
+            + "LS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ"
+            + "WltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWG"
+            + "h4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz"
+            + "tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g"
+            + "4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwN"
+            + "Dg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6"
+            + "Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn"
+            + "aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOU"
+            + "lZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DB"
+            + "wsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u"
+            + "7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob"
+            + "HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdI"
+            + "SUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1"
+            + "dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGi"
+            + "o6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P"
+            + "0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8"
+            + "/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygp"
+            + "KissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVW"
+            + "V1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKD"
+            + "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+w"
+            + "sbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd"
+            + "3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkK"
+            + "CwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3"
+            + "ODk6Ozw9Pj8=");
+
+    byte[] expBlakeSig = Base64.decode(
+        "rflldCn6HfDvP3o+MjcBEmveu8ICu9KFow7QygXKQMcZcaylqTeDDGFt+wq7xhGHNVtkVxj9iUf6HbjVWgvgaESIjnFyf+O7ChIJkI9QVwvAOaEnnkOV7lWj"
+            + "S0Je3PwHHV+E3brp8XNBGQOyh044YkwZXQordFyKHSYWUJIT0XcB8Vd02FnDri/97ZsYMTzLVB4tsoVORjBnNf4jQrO5LtqQ3v5djROiJhVxSfhvKUd1hGHJ"
+            + "ut/QvxtfEPwPnZ5oPq4T/qYQUIOo1QnxQBVNTCeZRpluzwG0nM6bqncPYTZulxmLtslmQO8+AvDG+tob18h3FEgles+PaJXVrHbsAeesCV/urvMndsalVrKc"
+            + "wUPMvEDG1GlzGXu1w5TdBj4iaUU3wcwNdLuLee6mjcyH/NdfvjDm8xA0qQMW/104whUUyvQwQ5tMetIcncXCQ4HcYM1KEgkLo7ySLpnCrBcYEUCmnlgjyr7y"
+            + "3gEJZICsiL8FYGjsxddccCqvtwlTeZVdQMnevquzt+nKo8eDM1N8JKHLq6WMwP03XUD0CEYmj9J/d1DVO9BOqpAURNTo8dKWgL70D139Kn5KeiuscYFppbnX"
+            + "mDhZ8pcfjv2tCFGCG4Rf1pDDkYWl6hVg/QCDMS7ZStFJ2nhyILdsRf7sYVVDEKdsELV3azQU37yOITWncvX8YO0yMOZ2fvKYI9BziiIck0u0PAjPYva6WfFx"
+            + "irMElAs0Ro+Hrzcvi4d9UwQvuY7HNKcJJfwoaAVbet3sn1T2WPk2ZgkSguo4CYKsWgxp+/PL3FxTnBpG5HNmUEJe8Yvcw9fdwhhhPRxaYggpDdOH2OKSYgPw"
+            + "1De7QKqsOI/mqHAge8nO4cRCLEI/AmKyjKxKYaOW6nARLGOBjYnCj/81oHrTclKDXmO4DfCcQWzn1HOc11RMHZN5ERRnGIzMcXU1RVIMC0T7HCGGquaCPnvQ"
+            + "6pjAzyXkMWFpihqevKGe6sn/NmgF+MZxboy2+cz5yysESiqnmMvsfdLl+rOb7+fwbYsYeeEVtaM7bZIGZZ4z9Hn7yfkxwGmzgfFqNglrrINMOHo8YVKMny3d"
+            + "Wkm/2CyOvMSQE5nPQYzlqPodrBoR88XjAN54zOjknT2lmBy3RzdnINtFZczcvYmADUop40Vfz0pNtI68aJJDCeGJpAd2iYkWRugsXYkAODTk5LBrjZ0dI+mU"
+            + "yRLn7FCpgLnSXu6JppuNMnTTUMrWLGXtywznMFRDZ7fbIXHvT+Ezs7y6GbOZaSGON6RhAyKRpwGQdjBJeK0bCjPmcoLPaJEjo2rcvdAsxdSrExrREc+oeKtV"
+            + "B0mIaJRyrF91R9uXWu1ltm7zqeoIDv/jfV+Mi1lTllbiO5FIcAfmAoQU9nU4/GLCD4VGnEJCzxtwOsuNUD/mIREGAdmM3TOjXZZw5rceoAQy43lncTUon7GI"
+            + "TiZxlANu/pZTOHVdYcQclywv0RvofIB901C+PqWEhXWXbxjP38mWpz4tOI3GGR9G051HlWk+udIdwxWyaCt/n21DPhS7btIcr4lPTDu6A+C9jin+yIoafixj"
+            + "+hHIJmx5OWfCgxjkRyRZhtgCeXAn47AWCEShnlcvzTzJ9Fma/nOotiIJV89unuxtSnuT3fel0UgiAMgrsj4BW4arpx7s1dp4ve2PI9eaGUoybK2/nC/xuQez"
+            + "I5yDHbTHDamBtlIU8of0ubgiTLKn/sSeR5N3D9Fm7adanJXuF4pRQXl5zLLEySHWKYo72BksgPkKrTvhJGltjmKd1Fgcp1o+7Z8khcMKlegkP1uQzNpkaUll"
+            + "4O+r/jj511iG3ynNN7nHd7dZkjlsWh6XECHQ9VqM+gwDMR6YzfRaVEpg0amVQDUzi7JBo453xV8HtZRzxZrybzku4c+3sc6B4V9NNtPWIDQvYlo5fizBacBr"
+            + "GQLoMD+Y/2pMbeccwN1uRcHm3IcFlRLOCUP28cTn6x7PZBY9KLENeu94AhM8ExJG1hoZXCo9BnfHpcJi2z+kqv2wXR6tgALk5BZ/OAO0CIDR/vAeh7u4q44p"
+            + "op4EI2KZxFQzE+EI/fBf461ILn3pjPUOKNaMNfcSVfnL1Zi+O3Qbm8n84lIfO12WxuYJososbJfa9fhscmVqqqAV+Qc1l5LGFDzqX3afwbmaNK3u+fVf5Myb"
+            + "6ldMWE5Ft02QBcQfQkalu7Bnwwrj+i0VxwelssR/SDspYl5tHgUoar5p6wXDmHRStwq/xVybCnAXk0LcOmNZAmIrwOfkIy0nKwTrkJjChE4BiUzqtsytLSO1"
+            + "t45FmEi4KSJnBUxE++uU1aLoyCaBxjr61Z7R8KXIaF5F6xPdOh233/hZGdc6mBktMUm4nmliD6V33BAZcgqidH0VI/LfOR+uSBtEF/dvm1rxa1DfviYqTAuW"
+            + "V8G6WzVLn75E9BWuEOX6Ba9Hj2DjZ4xu5NrHJ2ycQoiUrHYKlB1nLZboJqW7qXmhm1Y/SR/BYuPc5Jl7ftTCdbUj0xRvl3hnRZk/WHZweaPguqAp/rewjmGn"
+            + "ua3GQ13FUnQnKb3iQDfKT2UCxC0jnqLGwNj4RS7fuzaIAvH8QcvTmM/gTMs2Mq71T5xVS0kYRcIpmyupdMY3tXiWOhLhyBef0Wh0XcddR7rJ5dyNeCmBul4q"
+            + "tAZ/3f4vECDVe9VL+oqhT/WRCbDymqIov4ZvOpyxirbOeXI/hkiweHsWN9YWmJazMSB+1vt96SmF0ZVP/AvCenK2G1qNlgcBkb7jDdBgziAHL3+Joq2hInOg"
+            + "Ikb8HIVWQOAmR9GCFQFOFWxCO0iuAQ1S4g9muDrq2vP/hWKdqGwQMeVaC4GVVdf9rhSQQrHjp/SX8RfmP+hLmW53u0cY9Q1FyY9JCzRaEtf8vX2fMaRm3yLc"
+            + "w1/ASpB2sdoSpEGS8AYwqXS/iNJ9X7CC3GMTZBgWGSKXmmGpbMcplVfJysHg2q46ZqL3ls5lqdOG1R9Qpmlovzj4HomszOfk3yApOA6rYiPbx9MI9ovwg6MM"
+            + "vfaqLzBNgOjYGVtOhQjK87+v/5SleKesAzvh45aRaDaIqqZu9ZzxTrjTxavsdOC9kuoeUapG9LCktZSgC6L8CtHwoyHuwJ/sqhVMLYnP+78vmJdXXmvHLKXw"
+            + "Rvj6Ea/VEiq1+eYzuLNYrawAG++tg2SkiUPlmUctf0gkzokSj8VjiFv/b8eB9kXmyLhp4KJiMVyAfzjy/5XL5VanWcZ9JvCp38T33GaAeXOnjdsCiSHZ59C8"
+            + "+rw9SZP96tMU5xiw5Nd1fwQcAR7EDzWqakSgu9IUhd8v/giceqk7ZI8USJNCgqAON50FGh+qgIFObRNbnVqBOa8vv040t+4J6Kcgl/9G3FunPnZ3J3wpr4Hm"
+            + "jzMTB9cGuBxZxz8d4iyw1UcRAwJe3pjxs3f743MqEechy2WHiJdaXqhd3cZrIRr+SWHMCDDdEtUvCvFWt9B6tOeTGqxnm6r/Q0KaB/kwNb1rDZI0ohRkFXys"
+            + "Pwxyo4WPUEpAJCqN3qNANJq52IvL9U+KCX0AjfAYQEXhshmqDhk9VpRtajABKRRIK5qUDWJPQcyTKXIIR7pop6GdTYSq5OMfLm8ApWI98lefaP/aBf5VLAiw"
+            + "cVUQzCvuu4YfKCG53qx4dEmL7+h/xs0mnSM8ZK5Mz4kTrsE2pShZg6Mp6B7nppibBrmSIFoNMptEwI/PPJ8YiAIGgcSkKNUgGkjG+lbTgqvucZk9LqqoLq6p"
+            + "+JqNFhvyJ0aWhuT2KY02pKr0WyqCsj/A3l+yoUogjqva6eSxqpDaERNjfY7JZRnOyH3kLOQkPkG/pdMNMWpoMpTKF88BA3XeJXvNX/2ogbmsa8EtGeXzsz8O"
+            + "feZIIwvQnHbVulGdY79tFtmLgyZgIuQXLcR3g2rI5e20Asa2JUwJQtBTmg0j0vsH7hVvYwgc8+2yB1Yzw0O9LhJfXOJxCB+75DM9IlAr0zR34/UHCxriS7x3"
+            + "eADRrE0WnYumxfLTHxTSV16C/qsdR7bSHokHn4XGPL4lwKbcF7TWjo2JUHCv6rjUonyrFjN0XxUctY49VFAWbDObK8V8IaNbydJsh/tQfffG0Jp1l0+XVNml"
+            + "j8QN1YyQqvXU4u6yrDQZ/8EudBgAMpfYDBYYqXJx/iG6eGQ17CQ9rS12SKT4rSbwGdPRm4bkLR1tiJYCyLV3AByKH0XtzmSl5UYZeT0iJC0QPysjhq42DfoX"
+            + "IBnoGRSoQ/6D4f/qiQB+l/4VBsME0y7zXK0YflcvSemKCc60fE0oKQQDNpux5qp7hvelZt0YpgIDHCpnV0X5HqnE4cEsOM008RI9xeBQhn8AnZTUsPmWK6zc"
+            + "iAXGc031p/Ocs1lG/KAi4ba+nWCc/3O/6DjAI3x91Ga+sl5hrI7IwNbWCXUMz4jY5YDbtC5g7MmvN/78Av4hyZL1Ll0Yl5s0FMeMAMq89ZY4LAxUH+uOfnDi"
+            + "EZ0W4cl/j9YKJpv23h7Wjhj2bzTAHB2J7mklEX3/N/sVaroJTuPy+4fP6sZfB+zAHHlHdjj+Avn9KJzvbWLcMijIU0YEzeWXW8VagYv+dB+ns/gmqY3Lcv/K"
+            + "4erV4u89Huv3qiISoIch1AFH/pFZDuloCsTNKOFH54t/2D1xI616RTR1iX4EVN3rQ+080BF7Upo4PrISD+igX3eNYJC6wRSol0gvLPGGBTBe4Pcj3yQk8Cbq"
+            + "/iVP4mQM8scPXxOfiuLbYQz0nQQLJEGsVto5IreUCMApKn2BHkyxOV3k0jDQ8MBIp3SEkEjANWGV+t22aaZauyn2PJnN0le8oVqb2jiM57s6MMrPT3KPJbQp"
+            + "2AzNJLy3378FjNZW2T/ft8wS9oLAS2Vz+4ke2SquI/YRVgK7Cvq0Dnb+CXkp8qibiqmISSc26BQKe6AYjqskVoGf915sqweSkdduX1Q6tdQNUtVB/6QneF8d"
+            + "vFHAzpqAvQ5cxzGh5+aRfwtADWRKWRmR/+JfhNvWaFRp0hhGtGR/uCyudOnVzBITuoPtL8pLnaHn4aFvsimi/FlMwMZdDhHo+ZWH3we4B7e9T3bRuNi02bUT"
+            + "ewV3jWw1btK6ZEef2Vv9TrAn26D3ZF2Vp556YCovd9JXx45IkhsqBS66yoiB7z7weob9EXqbGm/R03yaCjuwDXiar9v5EaEorbpmT4Ot8zXtOFUEdNcoGqps"
+            + "1zP/WDHsX79+bSgrvGjkzix0YL9poPf7JjZVbHNp9usn1tJeiSPA/10TEsGdA08y/iiiH8IAjnkANZEOjfwSqTqfT/sTONsum6UoAmWLLwCHHM1tF/5s9gJJ"
+            + "mEY+TavKHVNiUvljldo2lOQwS9RjUerbEx/b4wGVUbVped9zC5qNFBbNChE77PHoTRxEsKSbVLkbiVHQbt17yIC4XfKEOcWEkjy+n7X2K5YCOmaUBnStCAo4"
+            + "q1xuGH6y6ckEchi23nH6bJqD6mHGIvqSLf/jTKQvztVHwZv+djR623UDyn9f+uoNORO0T9tRsY/Cn7ouklO/nBCYWtWkqXC2U8sA+1Bim+EUd2woHQrcoLBS"
+            + "dhYivg2p7jZliIWrzT8oLeqR3ZoIp+NqfsBvaADPD2FIYrfE2VoinPv6qOr7wd2kTuCzlE1G0X25XQHgp1GokLCyIMVkfpjrQ82vTq7fVAPMdfoTwfnqsRCY"
+            + "VlD6MV1RGA+vAaazwi5OHtHh9pyudLht3FLdTP0jJfEDAL5zLP45CsmuF+mUdwczXWCeQ7EgQGk1DWw3h67inzhiT6KEBz01SZnFgXgTusuKCBPfEKWSaICZ"
+            + "6USZkHyCPIdtF43H8gqRTMXBaYvk+0JamuOnjJ1H3p80X2G8HhWZZLW/HTuqTOzxVUXU/6ZLqlXK0EmxSzRUX7Gt6nidxZH9sUaFqIhsa6qvsGQ3cyJJnlHe"
+            + "CD7irUAXewoxJPzIU2z/jyPp0WYwLvj2ufm8LomzYFDPXJYNDi5avhOCD41LI/l2dDzKW9yI1pGQu5HJTEadPnJGWhS2Da5q7Q09Uvp3RNI28/nMeAQ482az"
+            + "XoVQybYk/NK2K0eExVEBNHxzn/dY648FNE6owq5f9k7lZSJA0kW0/I65Lt5KlyeiAcWbw11Dt3h8NlMJnh94tBSOJkTK0o7ApeuPa7moUR373+Ka0XzXkgkd"
+            + "nPIc7up6RBYDBeeZ032EJ+7D5GI17m+5a3YI73EOj172DEyPqjAbPWgQChZJRg6BUiWTpOu0guQZa2+ZdC7Df+onc2PRICMyFCAzC5s2NDvzElIfANfm3+sj"
+            + "gCV0ZaWw9NSOC3I+nuziLQ4YMf4RDwdkSB3zpGu9DcbOzNrGvEjlDfARLIRtzqFcS5EpraDCFASnAeIhvh3i6ulHXfVyhsNltxDs8Uqa0igd+zh7AgJU10Wx"
+            + "T4/jmwvvsJMPB0tXNZs1hr1rrpVdy5TVIqKh+plW5rV0w+N8rVSzkOV9V7UQlerIjhlmi7zLrCp64g5guJ1h0/gRtqXoz+AOGvAsPL2xJ+nMnIcDNHMxwtJv"
+            + "SB7l2WhXHYjcT7mBAM8PYUhit8TZWiKc+/qo6vvB3aRO4LOUTUbRfbldAeD/lR5qjQfcRLf6yXO3SeJMuk5mWzT+Ly8kuIOhnImfaU6HV58c8Cucqce9lDK2"
+            + "0Mv6YzU8fgeTdJ1D1VOXE+aYgTaCn0skY0AQbWikNGWDo+Ks9RcC+0oroxW58Prh5rukfIXy6OqQFJDprlNti6aqqydUpH4hfrT/GOELpDzfnTcIpav9leD2"
+            + "+sobxlL3euP0I/zhWEiZpdncy4BVxYVjtx7JnLJ+BT/oykyhGyIcVs4AMry7lf4PXLv5jD2lh1CqcZpHx65kr5a4cXZyjx8hvuEzM0kL0iUoAA1eySnzMpCN"
+            + "EhqQTa88/h8ZxLRP/sUQe86s9OIN01ZcsdhW7JFaEQkckeHN2KGsrVSI/ghSY/glUjfUFIFAdGTEFMzwADALXt0lWGvwV9SXsZ2RnG7gp5tNZO0GfRM93bGY"
+            + "YZZ/A2IggOYRtsO5gsK+1VSsDhlcpt1pbBMY9eqzqCDQKcfBuFcbuU/EJr+lsmRLZVQ8wMuvcMAfEanv64iDG+8tFs0sUZ9OK/GyYuym6D+IxEOM56GfxyLO"
+            + "pKJVTVQUrw24e0VlEuGTBVymUPw+t9V+ycEMc2nUOAGiSQrYLHT8obokmJ7d6GjNEDwhxoxTXoqPWgH+QL0Iw1jxRRuDKsYYTa93coWLRoYw5usQJltlk2O2"
+            + "YEJm3WO1eJ6wHk0ObmYdwIptPOmfZr17CXJJdLdJbmcTIas3xuXT9mDYFJYo4RGW7kBIkIRZbMr4TROy51XwAbjHn2oMDG8Yjtr3DllojJRIA0Gy/igTeG4S"
+            + "Ow2F1g5eqPBhIguyXBZanDNet6awabQmGMtu1keuBdf/U82Gw1AeV59pg1wuKdqhaGGKMmLvMcQvaL++MkoMnjZRBgow3DWbC5QcloJLK+1aZtHKeAg7x0ri"
+            + "Lk4+RECV5PHrZxM9nZW2yZ/k+MHzKzFUhzygeDiUX/jz6/UxmiyK9zvjNMSFEa+wgg6unCLW+NUNbWyHd8kGRD85GKyxPW1EwEykIrZ17wZciyDd6kpVFP2G"
+            + "gV1eUM9heamcgxqwf+aJh80y9joGEuu0ST2gVCEXqzpjfJnnjJzL1rtlVrS4LzVpumyZjwQ0l0BfXetJ+163dstwVYb5rfxj5mTDbPAjBKLmwJRJNYPmqgIU"
+            + "JVTqV5IDLhMGm+vy1qvfaSRLUf6SVuxQrE2jsa9EHrGskFe4ziRjNTiKbQfnfSMSGjIFVHuFRxKkZ4hBjcg5mXmCk2uGPkfGncusatuikzLRGJvgRnKjQ9Bp"
+            + "N6RyA7/WqGeMImx9St86IYuC5JHiQjy/aU2oVI7p7zf13Z6hwk0Y0iY6zwgq4i6y7NwoLabnNu89OfQAgnG0nRr1Xdt8XCQm0sGItDizH25CTW9Ozz8PUf92"
+            + "9oN9sBypZuT8kdeDIXeWaDjpDjn9T9d5dnNS+KKt1wTQUtVcYX62lFiGBDAvMCT9IlUD1sVuf1QE6bG0PJo+jo+oz5D0tqEWxGNZPun1KGEK9fJ3NHtf6HM1"
+            + "aBZBf8ECR7lMDe9MZwljeB4oRwqj0nZuvCy0VEBzEnOpp4nyCpR15ZIar586Zp5kWbXwWxU/9BYjiH+uPRPY1rGdYLtoNOfcESHJSQBSG+41dV2MGAdgcGL7"
+            + "/4Pk2oI1VFMN0wIB0Q5vxXTcq7QIjxFCxkEJxdpSbqR39NvD1MQm7StuXKXPGb7Uq83lB8IMAf8FIas7XlGQEeNvX6Tfn0F/4WYipYjdq7ZGTSLCbQ+zHMri"
+            + "G64Y2a4t2uxs9IILzlnRkIjdw/FR5AEXNh1DkUvP3nlRfJnsb1ANnx6VAGV04EzJ40TKTmwx0kGtzoWt8X+CzTuy4R0CmSfxWu+Qz+m8pipX/jRY229n9/b1"
+            + "kX/8wU9kV46X+OSsknRz5zjPQqM2i8VKamZvX7mHYBaQSr16mPl6oJDwMibJ4TwKH6tVUFuwrXTXNc5U2dbrd9O925DILxqp7ahOIH3qXoUBBgGmFjeJc3sZ"
+            + "sgOL0O5EHr4iS+GI61B0S0FDlSePcuvocIjfZVf1BuUhB7IKotnJEhGpkpHkogXM3VR8SXRX/ZnB9cVf47MwWvM4ch1tmyh9wkHom5ySuHBRiRek5/Y6/5i0"
+            + "9A8WFUcwiA52kY62DZel2Bh7JSdJsdRYOn+w1lpUpnJc2xachzIc0DpWtK573/h+uf9DOX1jEuq4FxYaqJNxdT9xu27w39oGlBkIx0NjKruO3MDd4J8QiTJf"
+            + "vdG/s+4mcltuRtzMVuIJGfsSnXMbex+yT61dMWeKE9GdgEh0suELbD8TCxxRJZ34hwQHB63Wls5fbEVx2dwIr/evhH5Ny7QuRdNDqzn67i+958Wvoce5Rg8k"
+            + "4oAOcbj23yaubnqruyvbt/T/j+eQ6u1HUqBB2WExN6B15gNoRCDjermQ4uK8afY/3Yr6JqR0lFj59OKoN6xoDoUxN0Uz+4JRkMOxOvETns2RdqOji9B0vbfv"
+            + "ET/fwmJ0qCPot43iZ9VL39KrJp8Bu1Hwf9TjZacBk25K+fYwX79gzGJGAehfp5pO4pOH8owiDP5zmKYlol793/6/DkMnpdaZE1ditXe1aDR8O5i8yJW1n1RU"
+            + "VmvkyOBiEadK7/i3oHTusd3MrYIE3YaxcbOOnTRHMuaqgWxiyVKkv4D+979QQp5lhW4e7DsRQdaoeOWHMPu8D4lUPBmNkZrvUAIKjabb88vdtpMOEImCa5KR"
+            + "Z018FfkrecysQ3bKUavhG8Rc6sKHjY0LDfTtXtAZyHGK/YxsEDlZ8L8j6UfjSK7ZgcYTWILP7ZQmSHQrucMbohYvErQVlGAG67ZWcsHVS4iXyDDc6svexxEy"
+            + "e7F3GDBoZOHQYgWdeaD4Zta9Ccc4Qr5rx/Hxa8ipTTMqo9elNUvwOIlfrAb07dudjG80JaUhG+3qsj9lGd0N7fU0T2Li5N41FrIVcE88I0mVducgYUs+oD9C"
+            + "478x0xyqaKTgOp4uFxAhjgxdwA6bIg9MRafk8bNNgMA7jG6lra6U3+nNw558R76nPz1ZCP5HlxfonSkm/SibArF933WClVN6fCD/fRX5C5HFhMRc+uliH21A"
+            + "SzAAOokA0Mi3D4mAZXXLM6ci5YeVmO6N2SLKsoDeMUsEfXzeBq55lBMLyxMiSXQC7dyfpUCKlLbpMj73UR7G0mswMf8STgBECPgB/6jH0P9Yw+CL5E+xFVhy"
+            + "FxVZMLSDmrj6YzIqQULT8rPSwwM+8lvhnt7LdGLSIp628rqB/J90b1LOCG7SmBoLgZjO4EfkZQw04oGo0qUT4MqCM2OPBFwn8cI0gRP59olvbsEH5ul63aLg"
+            + "MtWmQZ/TKWI3Ld7ps4jQD5ofCCKjl2UrPW51guNU2cMDbCLK7O/BeALlhdfkgplWj2v9vzCx6oZXuunb8qfWOtvn9vWV9gHxZyd7ZqqA4CR4VLxSnLt9+csW"
+            + "t6tneWl1TBI4djbWYuGjuNLau/uGn7M4eThTokgspYaquqCupUw5zPL1MbWFo8gEYgTy7xiGlKxDOYCjoVbvdkCdBljh+Ggu80KZXEXy1mcOOD2OEON8ixMm"
+            + "+WxMHnaGzuhsX7A6N1AYJQw894nW4Gm5rbuHulTvRWO2CFZDLvHANLdUU8VCD6pXZkSMqEzvY/LOSpJdh1NbEuuFIRJCL7cx8dJf6/OmypUvLq1zs86qzOYK"
+            + "zDwpItDkZxDU76yQVYAmglZzKkdhTUkGDi4o7JuhX4wTCPnizYZVOOk+wEoXHRVfi/C1LXwbHfitQTqy8umneMJNqsLdBWyArNDA74MKw4nC1G8WjoqPIG3+"
+            + "fESTgqGylxKH/7DCRWT247+R3Vh+4i4QfqWMOKbR/qIE6xikL0Q41HAcOek9aKzQg6pE3GFNyMGnKP4aPPyIKB0YZv8IDJtEPzBBZWjqNUHmy8C/FpjmtUwk"
+            + "En7wjV4aaEvdAZJRIHV3gH3IXzyZubqBqzsgOMXryEaexD2V9pypZW0nWYyNTHL4OrmWMzFSnOtepiwzGBqpeQZFbpNHmA6G/iy5GcO1JpckgqY2+oP6AKDn"
+            + "GIv1Y7mLvR7CzcWeOWnozatDEYMzRtG7orbFHMDQvExJiHw6q/AztocPIUfFB73Cmf84WSaX2Cn7CgQ3gGXngtznEbMM5eB7JBh83m+4agB9adB6nzP7eX/6"
+            + "/lIGapu3//PzaBcp4ppJgRzgpBgbenAsmtGUoSDtVTjpPsBKFx0VX4vwtS18Gx34rUE6svLpp3jCTarC3QWkCoCO0lo+7WFJ4wZQxImFdYvcDZ2xCiuNHTE3"
+            + "2oo4GgoKC32/eIndO3aTBV2VxaF6hDhN0gGOxyD7tym69y/QcNqFfF6jJ3mVDvh3GskwZ4KisVK206E0NYneJbCXld/CUEb3nSXog3QJwnHifWrcjA1mvRNw"
+            + "DIPtZSSMD3ecS4CsYGBQsJw9FbrmlzVK+/4hEUoOVRorLtt+gt7WfpblHSbhyJQ4WGrWcCGRF0PoAPjmVprBOpMHPEE2x2hERqXserCQC/WtFNmrsBbU1a4s"
+            + "0LvT/CRjUZdLBtHAyJOkEKzyQLrl/cppns7k7NGQkzNXMSSemDnVaG0SWt14s8+YaHsFL/Lj1DcSJ8l25VpkNMNRdlnSHkT9yC7e5TYncS0MX10QNV2fFeYF"
+            + "1Tmk97dDmZrAloZQjS2VUxdKzTisTRpIggb1qtGL1nbbiXWrrxXle6Ftb15ffQJfjjbL96AO0KKi0Yq9gy2dAXueXr8r2FNEVJm9EuWPavqcwJF6VMCpkGOq"
+            + "hvfuiFHQRW9q3QWEZYGOwxQCXNTbMe6SGXhYCBsCP158eXWDkRAGwgL7efYLun+aWoO3Q+OkOYspJAHo7RgY5dfOPeuBQNUESHXo5cUsZko5onUzcNjaHza/"
+            + "9B9eRhcsfpKuCLA8SOjqlsy1Uh87RXd2O7KvAI5O5VJQ5qiX9vabL8yzbKczE9N70gv5hahM7rHXC1hFJYGzCzvk69WASFJsq3lvtOCDk5zaUHIBZdvton1b"
+            + "DkQi+xWORkcKu9HTrQ8uyEkhqoTX79DUhEx0xFqREFL6QBwCwWZTucZ/j+QqshQPmM4IzOFwlShWAJ17QBQgT8d0NbRDLJDtEEw8B8uzlduPVBzeSbxBKNcK"
+            + "2bWb5XU4Ibxhi3uHWzMwhAHTXYcYn8nQhSdMupBq0I1E75VG2VG8aJTlqL9Sny+c3KeGeiOqBVrX/7yt7l4z5zX7uDWBx/Wh+hkMELXBY/hAxG/tKhMKDPCM"
+            + "FA4ZfBP69KGW/5vxCHEbpprcyzPla2y+/+E2rxQsElQDuSwLYCJlRwlCOOCIJKkulKNDsjaiJBuFUMtqjNTKPktPNyRFbKhXMDXKt7CZ/gs8I21Fz3CfzWrb"
+            + "1T+V9AmeEkFrQKNm3seUmaVh/o/+JTf69qw5B3rzaO0IcoiAUoRdPqSCqJ4fZMgDBNsCwfHlSBodMQrKPp5abnVakv47LPtEy/qFRuTjkApxS/76rWOclMUr"
+            + "pcPrLRkccA6C8DFnio8ovl61sRjhKDcvbpLlu2D0PyoM/VQFo1eRMM42meKaMVQNe0t2U2Nd/YnAzE3H0SjCRo/erxqUMEv0bm9a3p+Q4Bf205IuwZLt4rsU"
+            + "5T+P3bJdkrqE1SIaq47WKbx9+R4Xjktg7oqhc7bv5/BEdiWtixHYtC3v4O8KH0W+DAj/53Ch/qnxiz2iEp2jlG9lhYTvV+Asq/4p4Bucdl6Hk9IRva8MNfBe"
+            + "BoS4e3/x/JMbSs6fNtB2UqrRgm3vDUD+pD/Ge247rEAAOclNM4pT55nWvyltT1/NsfrJo410KLN8aL5kQekcJB+sjlHVQe0p+YqbyoBWhqE7SJY4F65rneg7"
+            + "2VK/jHxMf7sIiS5af49rUwRd99N1d8YRmOjp8gfonylatMCKvs+hIT0EZvYFEF72JvNSNUcM4vpRr8Aebutr4MumnAL5SPmPdyccDFdwhKqVUiqYGVEOh/nv"
+            + "wQ03rm+LvWGgfqXQBA+T88c7Q0EXRtRwlC1gduwco8pH0QgSIU/NcdTYTjt3ouxpcn0wUq2QMN7HsH8En3O60hUuM5qSXnKRaQhVwi5fCc5EkQLqphsHW5X5"
+            + "wUNqE/AAcgZvhmOdLcA+IXx3KLaYfsu00SQqQFV6/2/YZgr1byG1X6G2YyUKy/CFWKMKb2cCEjxn0cz12G/XqxD6yRdu27putzl8gl/JMeDp3jI9cBz5H9RF"
+            + "WlAT6bHSGorJv0YIhcbrd1K+2yFG0uaECKRfvYAKwZpqoPZX4kyntlFcba0n3jHfXnTizU+hbhJXHQ2vyB+nLIRddOaFqKLcsq0D2kLTu+8R+mzDRblwP2yV"
+            + "CRjIPK10QrTOZjVo5CDxJTJp5UFegB1z6WkbdSeTsP6eCL6jsT7Jc+vBqL+cQvM0C189044JX4RK1w9VqpSGlrWrAkp93MY5AzQ3n8v1+VveQfrqidp9inh2"
+            + "yboZ9zOhshBKpPbb9t+ZtPuzV7a73nd3bGcdIff4KNppogWJi+xLYi9vs0cxjCpAugBFr26yb07i3F/AAmsjYwpHWwa5vSyPLGrpixCbkd7hs6Y2pCeT6DbH"
+            + "ecv9FbUFqWOD6jWHFAtCfn38k0qO0IBpD1muxVmdFDfhfNv7IfScOukWiwDry8YKo1s8ROzv0pYMdb2Fa+rX4eHEw36oFgjsWP7dt0yWvkDrQv1duaw10L0N"
+            + "1aRLz0da1Zp+0lVJmNIAWb9BWdgriJ3VaTArL63ynq8Oxq8rLNZp3z/J68ei+6fV6bl7BOyQ4ulSjztJNIMCmf82ndiaLs0aUOFeuXqjncEn8e1Hz/A9JvHq"
+            + "kQm66eN16kp/uDCh3gSzanbphjchLwDQQm/FdntU1YG8M9/stnxE85dxMOo6IjbcG+srZHuRY22ZH1CbwDRLtf2sff9xVfA+QSea65i0T+WhhVkPN1awIVCa"
+            + "wsmCDBxguQZNStylwegsDH80jLeQtZ2PR4Xvs8kNVM3oF0jvJ6NwY4O+Q1UOVXeSLDdKymmW269W2xmzNu/fPWGa7w2//719jvB5luHTfqju5DmPjJJEhJEI"
+            + "N3I357uBwZdpbzrj6hUxDQO6CKS8j9sLI5otwtJBC6jQ1O4i6H/XHUj9t36aDVE9AaKYdm/3mlCC5dzbc0REyxOsPeiz+06flKTx+bWLEOSqLvxXe7aGgDmI"
+            + "nR4JFuE53bdqm98t09h/KX6QLPnsxcTts7+XjG4fWoOhrpo9eyIm8VzYRzfPAmQZKzXOB4D49+pZtYF6oFRsNU420q8qZDrrMztUjoCNFSVUE9gAfl0lwUI+"
+            + "jUDXIQYNo1HzC6sK5wsc6yS8DBZVtccMYtlY8a3apLs65Y9HMZhtQpgM2q+QCK+8mStJL1jTJd18IQYDdpPrnR8wZ2R3ez52fT/C/iOAmRsSKP2MPPHh9Ee9"
+            + "y4oKNy9+zBBsXSyU/8P6WC17Vsjd+9wgaryp5I926niSwwIpsAJ5REMMQ+65vKjs+QayloMkfzprLdhEij4YY90RhSj8WjNBwCax/h4Y8Ry7eysHu67gLN25"
+            + "6660NnusUUN+isEH4ZnFwnc6HvHZNEmSH+LsLhefG9SdS4k68gh7smr9MiAC00HBvZVTQgxL5tXo59uBMMiouoeDlV+HsbKDplwNL5vP5AV72ZqI7UAG0QSq"
+            + "iofvZu9t9vTzToJHGwlx12Pd2EIMM/kPZzsbYc2PWbdjfkfbyNUtkQKSSB5BG5qrQTsoC6YEIQRVqcflJQHQEFVxwrdnwJEDyZKyiu+RASAbmwpkmGsCb9F2"
+            + "x1VowYoo58CR8LmY7ntqvVlASsaIiUfuceKp4WaEHA8nQYzKgOVeynoi1nKwPQbx+hF4fo+VMTG51wHZFkVF+m9cYZBN7XKQe3243v49UoUjucRCzzBATcws"
+            + "ILXbzopuInnHOjicNcrvUR2H6QEEyFwD0gqlkcqf7K6MdhXe1pdaGSE8Wil2PBvc+ZNcanAX5zuh/SewpYIgAm0leiTIh4GfX498SYKCSfjc5ErBvgOGKWy5"
+            + "rCefedVpRplpc2gVBnZ69AB538XCmQesCkUEBBKHB1yVXxl40119jKxj7EHtjs1tleVEMI/X7lT9LLWRa5eaZfb8BdjLKhggwMW3reAzQmLxBRJRYeQMDrpU"
+            + "HQD5acCsnda8W444lfP1mKYgTUEQbwm7FIKlfOZWUeh+6S+bJHHdJJA2EeSJvsSzAit6it0VVMmkgdB8LVZ2NytlJaEGG8YfnQTLHS76VxikvM2GwqMhKm5K"
+            + "uuxUVCU6csMgJPnxbqsAHIuUlXnBa5oqqOGV7GQg7MisCyqi4VQYPtP3KJHmJMDSfDtNrP7zS9GZ6yD6VoyWUaSI3ypYKS1ImYLhEsKKKdzkcGnq4LeTmHZU"
+            + "2vXrnZCcrgYEokeWbK3dYbHqexNwyO4BghvBO4mAWEs5xM1r/UVyyy4st6bp4fhmc7w3wD8CAn+/CB7DQdwMfgnzmzjJdCoZPjFnOqep74+fp0Dmgr1hikhd"
+            + "tIIa3oQKW60Da+gBLa033/L0KA0Nvu6eyR+uSa3SdDIWKmjX3Xp5MsQdfnyBnf7dLn4oGglarjf8ByqTgIrXVrjwhFp33poNcMFcgBj8Mn8F2nnTAVwwgz/v"
+            + "SY9Y5HyS8TWf7mvNE/rXoQH3qeHsuB2gE5o3c98F9fIbbE/aoJX4lCHhaJABTGnsBGnux64PpvvkQZaKrrYWpRPAZa8avYI7CUdd0NJw/OCNNbfUTBlxTvMY"
+            + "kbSmgAfVUFIvea43sygFtqhgBSDj0RTdEUWcPe5ExmtVAOTRgpzdUlbfvvRXwLZk92dsBOJoozoWPLElDT2cNV7Tq4YKwGdhDGWuTSaJCvQUuALwvfyBkfhf"
+            + "1jxnhoA526S+ns1qHxaJFfGaF+kCRaLl4jm3YKbXNcpNtLHg4A9s0PBXQXIJNObS75Df4QFN9FAcClSBDiCGi/3UtFLXbD5UuYacjzWym1xk71201zGJDmkG"
+            + "xMvKubqg6ZxBHp1aMgshDku0sZN3sxyLGg4m+k6ZlvpyM4myIwpSxOJC87TOWjMqem2UJgSDpxqANgVPE+IorHZQ57EJQ1JI1wqILdkJFEEDlb3xfnIZm5Yy"
+            + "OcLTGp4vsk0kSj7TEMYqrFpL5yG5r5r+CDoxIVaedyId/oKIwMygPJy/EaxX+TQ7qQa/FJt5PNeDOSzP+YTpDTs3v4aJiAJwebkmYZ9sA4sJAHSaJHsRmcha"
+            + "z2S3IwZktXFUWg3NSsASZlJ9IkdCCEy2QJIegQHbwGeIJFp9YLkxO+fcAip7hr25xEGtg192moRSymgkBQxViOC5urN2XLeOZoDwlre5p65tmtX8iTld3IBR"
+            + "PtZLacvehPMY6w0Q/gcIHhRxkXEUS1Q9zD4pwdSHK4mvEa3fIwWZKfv7eGpnHYiw6cmbiK5RmUFFwN7FqyO+ogAMu9WeNjs3SWfD2dIM5nnYKZq+bwXKMvaV"
+            + "BThVJvEHcMjL5acFh2HpCLfCq91bFPVnNMc1zUVyQY7bHkaB68eGTpWutgefp5uG457f+6tiDNt1AbFdgR/32Sapw4wiE89qNncpZjq07enBIl9kBpBDWdyA"
+            + "aE/LSXiItY1PFEf1Ad1B1iwwcjmWyZNSbI6rSjZFW6LOK1RZ5yiR1q3HopEfIT4K0mMxoI9PW5FHvVnb6AUP5b7o4/kuqh+xmllAFwqgjO/NfXIh0svQvPPf"
+            + "Igl9yLXhBZjJVxJMi4aWWKzvSqSueCQHEw3VUJP5WpTBWjTWGPZxb4xGW3X35PIyaYBlgUUtVTN55JxUC+yxjM/RvEU2JjRror97sxvXH1Bk/VoifTB/M0KR"
+            + "qSgqU7/DFS7SqsTZThUIj8Skaf2AOhvZOWqlMecyoQgJiCnK5Y7Q86MPWktPz35vprMZS3QH4lcy4fnbfj0KOSb+5yq4mVnv+ymH+r1SBKh+8EGepQL7W8aH"
+            + "PC1kzu0c/nYPSKNdk5Qr3wlEN7zNQ9gFCGYnFjtAHuBB3zTxtKgTLuleqNaWyEc5XIw2NkZfa9cVPDwMDSEkCzq0xyqJVEXnKcvhxIR0nx/eP+8rK8WnpKJm"
+            + "kXXQEIhAfzovw4Dp+lMyk2sm+KqdIec5sG2xY9feg5wg9vb7QQJ5nvewYiIvASeVZhckXGu2VLflZUDDFKyySUlsnxQz+eu/DMIURh3QnmbylXezl6JXFRRr"
+            + "k7AHjjoUXnu7Mw9mqUNesa2OpU9Mib5zmJIkWEj6TMEWGKPPHXhgDbmbs2YWxJpwOsewVrlX+Y0WmtaDmhpwTzyQHqS8rZlmefUtnH2ItH655R6vBaAdDC7V"
+            + "VpUENgOTYjyZIX9XG7D3Ac8Pqs9QSMKauUaSBFR1Y5RV3qL8T+0RwIh3vhmwdlxap/Ro8kkMH0QIFOTVCMENajIEaUsEDRgLqK40DK13Z/NcrvDxXXflZzLG"
+            + "Q9wsuzHnqYHm7ZUkZSX68WHMt36zISJeRnxNreowN6Eu5MkliiE5cS1EyMiUZjYjL+B77zk4K1n1qQR9MdweATk2Qdmx84kerG53VnwHbD/w5B9FPS/ivRM4"
+            + "vih9Y5/GA926ltZPPuX3bWKY26l4KL+XpXFg++RyMr5vITdxTsk/P1ftUm5JrnIARPxXOpV6ZxVmCqvjyPrhfFaWSS7UUTbjDrQIk+EplUzoUCahZU9XQ1C0"
+            + "5VzA6PbzzwFZce9LHxT/CxS3HchbgdkT3MMDXh+aV+H7dJtR//QmEemOCy5gqdgo5iZNDQ6c4XGCY1ASALtfQ3K9tojwugC7X8PtS7YC9gp6tG0JUzpQBDMn"
+            + "cbdaqUAO6XY6sF7iHe/aijJdhSy6RLxq7lsxR20qcH4J1L4/67h25h9ciAHymhMKN+6XVibQfyZ14nXhFxgOjLQtGGxNhvqQZc6klIUJJSLM/FaYKOAl7A5U"
+            + "Y2+7nFpPJyPPWdEqYarpSNWkw5wKydRvcWlAml0Rdn7aZG4pIGXaMv7gDJJcQFZXo5IMrD+UofPGWHBKzmhEDXIUDrP9xy/60v0qsjjve2pq4swkR8HJ4uXj"
+            + "QEbkME3FiXF+g4M87QL48ISa/v+C3N9aJUcbc2mHAMqS5PfAkbBG6K5wZ5YNPMxj/XachD3xsAVfad03gEX2/y5zRoBxp64qSL0W8jVD9Z2ahofv/+DjhkEj"
+            + "TVUHoF5N8v1PHYVBBTPMP3bS74Iuw7emP6MFNL64H3yxhNugevEipDLa4+spcD1HpJRPNfW54adVGMtmhZyU08hIbJrYz06xHLBsOlA/o6sFQ2JCIH+vAedN"
+            + "FqwReRKAuC9ERLse4W+GJZdIiyz5SKUYIJYCevxVkD8p9N95UdA+s3Vhy01cCz5Llzyz/jehiRwRPWA1KN1U6OZPmd87nZGzSPlZAmsSjronuqT4/EC7pxPD"
+            + "zAn2qlSvSHMPqCLW8X1IzQW1zK+WqBoIfd9K4U73OPiVSkZpkbMddmuStKEVByxa2SrAbUqKuzmIjDtloVRsDY/y7HMl6o5NaNq2tefeeo8GOThiXJtHP7Dm"
+            + "ab6/0KKnmEIh51dtZrbsRBS4SVD64XsgABTQRxqAJsFne0u20gwmO3CIUAGqjHMFC/xL9V70Bylg6EsXDM8CRs2mQfC11vh+KvtUH7XLPmizJ1IRXRSgQ6e7"
+            + "WEqIp5QOqRTBSuvw8/57ZGssi6SSvuTBCd98ukvv9MmpoNRMQNk5qQtXh36vjRQm+9oFTjNbu72g4l1WVXhW0IsI1XAXlMFuW7lzxv+HNBVbdLsOF2LPOrB4"
+            + "sEaIosCN3CYg+LavTCJHWqfAt/BawuR97wqPDjg2ldJU2ASTTHND6SuDX8fOO6/NL+1z7X7TVD6/MqJv9ZhAbxyjKWyL8z6SvD+EOy+TN+38vmI4UXMGrigA"
+            + "ZYAWwecax8GwBmESTc2zewVrLxm/umUc5BcbDNozwfYwV/1ouJXP3eYiWzLK6Suuy90nNmkSwPzX8dsIHL9WqLRrjDq0+U8IFFl9GGe2BnivfnUMpICfliAG"
+            + "JyIqYZ5TNF7A3Dpqjvxbz30ifdKszzj0VRYzwhlSV1XQseqxKD0Iw695AKTM7AuWuZ1YGIla3MSIc4RWmUDqJFfnLTac5+yQ/LsSDUf47OMfN5XxPSlVj4M2"
+            + "hQio4aIaiiX2N3C9ZKF5N2TtGkl9UVhcyWEEPLCbvfEtK0BNyVYn5ijjpathskcKAAYvNeU5/7PKi2rwE63Twd6Ygu+1wChWPa9UKqZpaLzRIQ+zwPRoBmax"
+            + "joytMKq+LpXwvh9ydRQ3bYUL7DHNinUH411oq2q+GMTamCEN83+JN3MQcWiPEVePZ+vUuYpJA79m89zYBetAnI0PT1pWYsrQrfGJ81RIbXz44SDbVIf/rrtr"
+            + "rgZc6pUGfNjyjy38dhSwE4UJX0ryTStu0gA7Gad1XiqIuSX9hDyEV1uS6IU68Qyf/mbgx92bMC6OMEIrYvIfzdjnbb1a46JcUyqTaRPIk14icX5B/W+5ETpy"
+            + "eeVeawdnLV6fn4R0BcUH1lhpqfkwBRO0DisSs49XizmlFRe2VUOXf60DQ1zkddwezqqblFHfjbb2ByWcQsgMPenQTmuAh6O3uz3cwao2SqzlzGpT4rF3JkHD"
+            + "m1AFUmVD6FsaDU+fXG9k4W26zF1XRThE71REYmQqiuIqOdrc7RLSpmLCoAgJLWsbv8UpjNCrOPVQLSfKeoCm7qpNjrwvCXEGC5DmSujGxWnRH9bolcpOClPx"
+            + "/UW17YrgdLVdFBZ49ICvFwzc61EpMPNcZ0iSrFRACRMPQNrnOIuwR5Pc4p6hc1nbTsDuQ0mknZN3lJQELPk4bPKPtWh/5E2hepAiHE+sZyMPvMHPjCv9LdQu"
+            + "mU5FGYLAfg5LYfk5FnNnYE/0MI7p+YSr77Knw9ykrLS1x0yqOiLJUIeceULR6SymNxv7tpF+XHNJLEUh66PdXmfXefdxBZsjL1laKpAmR2k241Fu2p25w4M1"
+            + "2qBHAhoxKp8MnKfXzB8rfa9U4G51sIol2dgDaY4OnlGOGBTLh1ASqQnsvaAxK2EMmJLsk3wQ3F+mLsW7EpvwfG654K0ykmwdn6yiW+3UrJaQlTTIZoHdDRFz"
+            + "elS9nFjo/cn85yIox7f7RPVBMyGHtO+w2BJg3amIfSD561iWaI+omjkO/PfM0nTUFE7LasPOY8+mKpHHLb9CyV7wrrBHO9m57Iug1HtizC5rs4puo0zYs1+E"
+            + "sm+PVy3u6yNoGJ9UruQmdlDKwm4WTTIQa9dILSjCJCmYxy59JE1GNjwuIq/5UepdL2qtMlVQRXkWmAyFQf3POblVsi1MTtAMeObq5XkWv3FbhHx01cnqU9nu"
+            + "PnPn0qeSYdug1ULz4ba01uiIDwECwgm4XSQvbpuz6t6utNHCPPo4jBxVKzC+tOJTV5+2MtWbkvh8tjtqRuDtlxm3/OZuV2GafrHoUV476EsDNCHe9+8Vtbo8"
+            + "HYZ1ILN4I15xGNTnuMgv9VISQXP0zjH6JMvle5qlNul0+lU9lmg5uObF9MmeDC+XB1FydRA+ZwTYVm4n1S/Vbn4xQjtqH5SaTsaU1N6Zx7f2m4k1iO/h6hyS"
+            + "sxZHFVfCV8hENWNGgOaibgR9zvKxnJNmomL0fHaQH3qJEswrVCyy86iVpEm+bt1tQsGoYfLy8+cfdgT2LgSxNecw5qWWiA7VvUIpGHHZIE/0cJQt0f5Z44Er"
+            + "mH78NsYIZggdYDqLpgnAmfJd6Wrpz5XpbqwVvjQcsGCgWbobMXy5LR4sGw07eoMY3eKJYkuXNAlf/Ar3n4gxvmGZCxHMZikmmZgxGXeKo852A8UFniWl1sa/"
+            + "ctU/F+8mlL+J1UJLDoIHtIR9w14vOMggljYGFxmutEmUSyzk3NQg0qQtYOjhxvSd7U6b5QdIots7s+qXitpafkAwCe6scvl3E+phKngUkXPrRHBkHLioPru7"
+            + "6foYBlLL7icUVuw5W5aqzyUytYG9Reko4/n1BME8jlGqCJgh9FBvs19MdDeOFRAyu8ZFKdM69LO2OTcMnDoLUHiKm6kET6G9fJ+ua9x0xlRdczMPI9h3m00B"
+            + "PktOJu7JYFlwIbvZa90UKmWcbunY65DaGVYF1GQqK37zlE2XKm47cuRUrtILukSCQw4CUyeankU2waaLlVKsKyo95G9h9Z3hv3v1Ji3brqWixsMwVO2qyP6K"
+            + "jzSKdTtjyskVAh8TYhlg0YTM39xVmp/y79/OAqo19/oGp90SmqwccEn5mow2ZwlrQR+ea0fela7cHM9+NNfl9Qdr2Kbv18hi75bgVx4ib5yJ1Tn/pM94BEr7"
+            + "6KAMlMRlCOirCbWadq+utaVDy+VSsD8NOQanJyicrjRO2exssEZK4A/Nuo9ngzHJN7fPpBf+XhEKqw0ztSG18ZKv+LgGjtujpQNGIDF1UGFftuKJ8bC3uIcS"
+            + "oR7hj8fLvTQpBYOram4Sldyjpt6jqlA/UQQ2UScyfk7XfnCsJyi4cBpd0xpuXkIxul7mnoshH6KoVYgyQtynzSjcHTbHtrHBiu3iDbCEfwqZ1KwibpRbhweT"
+            + "hr85Qk0QMBjI1ggObD4g9ly6BhTHdZy1DC+lmYZe190j7T9zFLItG9UkBK8UzP0Uc11HiK4yaZP3q2nHXl/QOalnQAaqWBO8MUtTa8OR/FbRc/a+SmNI8KsC"
+            + "TFTnaf4XAgSxCzdikLBZTzhbTgrMG7dYGdiNHsvtQkyevE6ehcXz2jwbGbnxCG3X8g33pHEbumJoTg2FGCTS5assFEC5XMWPl68HXfZn5cNUlXFk7NWRUqFJ"
+            + "FZSM4DBOq33cPei72NvwCt+hElepKeWah09YnlcHRhVHsFZPNV157wBNjMwXMfteTdfy0T1Vg/FzW6VFDpDtf5+oOEPPXGwG6koadMmRNQKTUVHpp30GYC8Y"
+            + "7G7lC+anPK0I6XHsHNFm7LWc6c4GyhdI3/ghAowZlAdZUzlLt2xGz8e+gjejnpMaiqZT0Jme+ny4LZGjjIkGm97nHMTOxxmjnFmSuuwJXhW2Bstag0TGv3vN"
+            + "WjqrqEArnOuVUkDokZLRQhdustLWhYH9uiLQFPCoHMyvpC1VN1QeIACUWYHBq4lTAHs28wIwe6s2tt8PcfHAlsqUbPI/1YciLY3Gsc2B6k2EGBJ61VxBOi/P"
+            + "rANLb56J7vxmVvmeQcCuRKlTSZM2LQQiQZOAVQFm1EOFlFS/BmAZNWMb3ze7/WLo9n9YcJyuLH+7eicFZszq8uhVUFsA0EeTWfuc5MHdP7wWljcgVLxb0SYX"
+            + "VrYo0hILX63Xh6uw0YtbdJ88U9rt4yObLCcFJ0qAfK6k/I0pXkIOz9zH9cnTMzRUs8oQDFUWSORYRYb4GL6Va5hwIsKQAU5fblducUDzFt7F/Pb0k/OFk/jh"
+            + "a/wdR0uLZvb1aTmBznolYGDcISkX/vd2p/hIMp3kXk3xdlrtKQ11l0j+T1xQGh+uy2X9USB92GXcLZujSpIDNgoOcPKJ7G6x+E21NqDF4uvCMe2yt3lr9cu9"
+            + "urDWw0/m2L4tetCxbBaxjduwWU7ydtw3972vjjNVvb/tt9+i0yrCRD/ddJ+bOfjc70O0Gic6fPfCgqYtkrTbmwovMZl5xSDoNekxunZQRGHUJ2tSIdRhfGzG"
+            + "BjjqHH/e1kA0x8DeVCNlriRhcfML2BVNHvIMPP73fA33ldvrJQhzm/r0kh9uu+iVFPJrQMB9ssVtYlOewhjNW7Bdi6QlgqKkvU1Lw6Mh7tbcqkR/GBPM54nP"
+            + "b28j2F0N9Jh6ik661CdBEx0a5CHM2MyID1yCA+/mBBhReHX+cdTWlh3GZijIJdqZRyLGe74JIcTTB0mgHgmD28bGR8CaHM2Wa7CSbfdmCqdPtteV6CaDOuV6"
+            + "nqtwf4RQenJaZdCqpMiXOdXkBIt8g63eB1CBtgCdEG10ls+TS3esFy2w7wdpfpMyTWlfqZ77Tv0GCoJUHWOAfn2cFfwMKPQFa/Bm1dUU3J8iUCdb+fPiHOl7"
+            + "AzPwNceJTFH09N7nToyVCtSfXKbhAaadHc4iSuXPBK+0QF9xPNzyGPWYtAFTLQ+uE7a2IOib1lAsH/Z+ADyJkg0m+eqXAvTSrMzDzqabQ6+b6bsif5TnUUly"
+            + "EywtQgoBW2F0lEZcu8TP6f/RacpN5hcYzM/zq3IiVXSU10LzA7ncI2h2LJMDJvIh/AT3P27gAkd7KljHJxr7da9BxsqutKGGYQWAbv4R+8OzTE7ykycwXHQ6"
+            + "sIV2M4JfV3kETvQqoMnHbUwPGKxS+OD9nBH/oygWAOCZbqYPGgODTuDgIX+yHk9TSyXDzeAdtvEjc5Gkndu54V7NnsJKwlEXeR2IkmQoMpioGGzGvngL7+5M"
+            + "aMdGexMCKPchN3eJ03Cr0VN6UiQDiTXo/nS81HadiQep/bXHE+3oiuoYZhm0U6Cibg+jc+fjH9doMsrrCHRzHj/kRLyns7tC7U91fPeXrXcjfBWHqLvkVbKB"
+            + "ZWWCDcWraQZFH9dazdDQLiEobqP6clYsV5e21hlFPmNwDXhqZ3UQ/nJlYhQamJZ7RTm9QeUQsTS4Y/NsbzJgZiaOWIdGNOvrSwtnID+1THCimgeuUjiGkxSu"
+            + "RLl5/5cItBwJKbDE0av/0EkxunbARiIVIScLIjWNA0PZX79KnME8nvXHgGK+NY6auc9BR8dR1RWAkig3eD25/SYmJep+0URJRaVWPb/HXBw9nVxI4nX+a24y"
+            + "nJh/rWTiZsuEIENmGF7TDS76YK90WFNKB/xiuPf8ttNsWmqPg0iC3qTM+Bmculfb5bCNHsOsn1ioNl5tk7ObcJ7ngcounp9YnAyxO+gxav3hkOUhsY2nenrn"
+            + "vuxsDh8yYgAecbXWY/jN0/uL7HobncpBltXTMT7FMEjdqYlF5EpGnumG5+CQFKPAzPtmLn5SlqgpM7FfBFdyzW7yE7pKmm8EMK03wq0j0kWQrVdWcmCa6yWk"
+            + "ZT2kLzHAzV+/jIGVOcwVXTOd/bQYIXc5/ZT8Va0vrQM0RR3BA1Cc4KIK4eYPtD6ZHdPsVy8gXDfKYkAKxc5I4DahGVbNQ4Y1rxRDzRnAYHJEGUJaK/CD7LuT"
+            + "dSsmnh6Y3GEaQ7CKeRLV6YRHintsEIcpVwsS5IW/rVbxFfw+0ZcSXcoBNDBvqowzI02/Ttadn+Y8za7eITbKOx9i39solNWouznXjL2nZlobyA+z/hckWLaP"
+            + "uFILRL6oZfftRmaRCTI2aEwOZMeu7YnL4nHPVNT3KFwf5gQo27M2Yebp6qx7krdbmiP/gc6UGqGB+B94se5ydlydui6xK2xY6Vr9Dl4z39cHNRWm5kJgrq5y"
+            + "xAu1JmoGbmFXTLCRDo+8B3saSftXDj39+1rc3488IrTS0bCubnvutUmLpZeP/M5Vcj0Npkexp4IdeuhtOzKydbZSfw1Fr7ttqG+4PdP33Vf+mYOu/AqJ9rLs"
+            + "nuBuqpdgduHfrIKHG6XOFQY8/LjkM8XGw8xKz+a2/Do0oJAtomJiRWjEsDPhpe1gWHlU59AF6fDrQHLsromP/T5XA2KTK23ChEMKnTryD5evhH4FC4KUOVh6"
+            + "PjBJtAHpjTzHGY5/MQ0+hqDXVksabkEPaVFaCwSsK+XYJaY7fXY6FGHYN14ssUdCkSOKfsMSB9eLBOSjWStCyoSHxZ8Ys6dfe5VCvFmQTHvMh9HBIpp3kcDZ"
+            + "tFn6FVvLgEo+IEptYp6RHweD9tvJeRIRLXU2eJgkw3gNMPzpnUZHZRQU2GfVssmmvyAQ0XXK36LZW9lVPqAAkjvx/Hm4RxTKg5ejGSNvNGsYM0VhwSsdAip8"
+            + "E2EHv9cCl0f480t0JsBBU+Dh3puc6nIuIdsPxnUEFOE/T5vnxcRU4Qpvb+wtax7Hb6S4luTSdAmnPGQXCSZSfca44WI59FxOi/Glf1KkR82i/HExwWmPkHKs"
+            + "15+2YsdtLkZFbLYm2fNgzzi43od0DrAbKYhn/GZgaY85kHNHt5n67cnVMlomzIKZgNUR1GKYOeFdn2Y2i7j/zxNLmrD1juemSh2e9w0L8/JRIzhSsI6ke2XE"
+            + "C5tUd9SS+WYBZ0wigh8WQ/8B8y6yuwDGqW3xmzyhnGKfhbmcLvJEAK4DEg8XxVkuqe7qTcEXgG9PqqwgZx9xmK5U2tIwifFA1gQGfP1PkkTrhK3UuJjYs7WV"
+            + "ienomP1PIS0S5d1c3oHkGC2MtNb//KYXHmObIpuRrGn4U2CcR/fYS1Mm+rnVRn/D7nYLTPWxn9k3iY+Lu4Kuh7EcHlrVWkFTDaLK7L1pvbttT9hHd5mSL+st"
+            + "bJ+NPROhRK5ajC46/iCV+wl9IaJK0gXxKKIha8ReRcCr9cXZ7Cyfe/3YxPukzViVSRkXHdrdQzbIz6Q/QAsk9+L3U8xoQgtVzKUSvkDuwc7xP0WkW25nyUO8"
+            + "oHCUEB1E1hs+GlTLGPlB9szoDpuhSQ/sJanzpMYYKP4jG1iq3VCYpdshrnufwWj+d57fKnoyuuVP9Ncr1Ima+BBmBqngp8ycDHLSmJ4W6OwwxVXPbXzP4Vlx"
+            + "JF1rsj6+a8tobGOJ4Ra+gqxQF8cYROoma9runVTixfGr6BjhvhAlrxV5y6o29uwILLHOaqgKYr/X+/2WXitPuOan0BOKGhqINjOCCfIDFsT5tX3Zox7B0ppO"
+            + "Uuymho0I2USb4e4FTgQ7O/m70DCaajDvmHXxvZtzvAhOaRY5LS5gdvhKZT4SaocMVl7X1jrEQKMQY22AKAWbBf44UO9eyDkhizPFaZk4QdC92rA7bsCy1BJ2"
+            + "aFC0YaKRfk/IcvepW7tYF6Y/Vk96vwEFNVXUF7YjNUFzT4UsLWwLqF/rlY+g26QvKaAwPilu/PUORlNQgPV4XMMBa+M0ZOGRdt88rW4uIwNDvRZoUMLfbfQ2"
+            + "lqawtkuv0EEBz5byCAvM9F7b0r7kZ36ODFDEC5CNpw3iVkAsCnjChWpSZ5DKIPu4MyAf60iFTnb38hqyscjqrKcNqJY/W75sxdrsk20alM60sAJgSxNBsCeP"
+            + "/mXO3uVR/xVrdWjdw6SrIBKNypMCv7QfhJughq1jbAT13ee9FRNk2guMxXwNpNnSMgJM/i11T1y4vPufOsp1rGJbZ1eAXguo0ZrLnuLGgL11h7cwhhAo+KwC"
+            + "/s6pSAOPHZdBHjxMRwgENPHzAMEmiBxBIPbClrC9PvHpkEHPLS4Fofs53JfYubfLgiOZuzeQxC95bbbWir/EibZyyHCSI6FTMTKJpJfwwlPkLgq1H5umu9LP"
+            + "lxdaD/y803UtXXsETiM9ccKye3zHqgaSYdIvwoJQ2DZDh2JxQWkj8lhA5ieUmtKV91VG1lUP+BvZQejh2Bk6njsDHnepbc3wQgUtEkVQdT7hjXTeyHJcznX0"
+            + "XgErqDlBK685FcK/yJRnZQ9COiPWABn2YygGwT+1Ascxys7RMxAQq3Dt2MnbChU0YxmzNQjVtc5v1w0/9bY+toVe4jk5QrTdZJFfNVjK/hMnuuA9VOTeyJ1h"
+            + "2pZ0TkjgwpegcI+a/EqdhpICbZuAHTOE3qXf2hAr794RCCG3/3OQdtPWFFNB53F5w6RLxIv6QLm4fby4jMQ1SAxlZXCfkywUv86eQqqM0bVcF/+hBvadTAZ3"
+            + "t0GLeSBO0XrC7WwyE/m3hFtG+NfIw1GQI8A1XkASFC2TGwVwqR8I8jbebepJJZYI9ps1dtN1GkiI0x9FaPlHGx0mdimbmePqkroQIsBgtm2CwIs+haAWLW8j"
+            + "k9qkDd8lrUOtoxJiJd6cQVKNJ9epAuoeatzKn+yvFz9S87PM0liWzlNWIAbZpWUlWnX7jCPHAknRgKWZcuDwPGbQBMXkIEEBVtNT54t+JdCr729usCI0xVw4"
+            + "kidZksb/blZOt2i/RqBbAHdDkJesTbDqdwoTe1D/V+hSOmpbz1YuUMPe7rHHX1jTfBHNqMHV4GxFblwpEiyCUbJxurDBT/50T7WDPR8QY4q9lV8LvkYiMgxi"
+            + "8LIM1duuVVe0/T5C/IHQPZeMabrEZ/wbC6IWXGk6OLxSdSKO9xJvRPehhsqoYpKTcBeoxzYtlDDDHw5lWxQ6bHXfz4Cv0faHxnQYdRhO3sEkq9fk1tZAJob7"
+            + "ehqUfV3ieBJu1eCJcbfyknxdh0QIiOMPbbELKz3GINWvwjcabJlVEsXl6oh7EDpaqTiGsLfSxpMHxPmjy/7fjXKbKS1Agm7+g/PLzOWGC47YkJmo8gWRoaJw"
+            + "cy7I60np4afyoEKbMw16nBPDbiHBIBkL4DgaENvSkokaUlG1g+a2DDVVkSVSucvTVbtUT8lG0KMo2u++iWfhV1md0JilzWMPmNH0O+50x+B5q6jmduAO1Jzk"
+            + "4PgJYf2CJvq9EB1F9WgIC9TQIsso0K7vuvU46kr+7HEnQLROMQ0EN9BOUItvmJios0/i9L03SY+uReLBgNzVs9cBBHFENiguXC2YbWgSnDjUcvAO7txXCRzJ"
+            + "woCKwOP2KPalbQwfv+KNJO9Gl8zh26af6A5tSIysMdadHSaspRLgEg9nVZpehHq8gJd8Ih3Yiup/yrWFrStgq6hjcaGDkeoqcPh+BOzxYBX+oL1576XCtwsk"
+            + "42cfQvDye0HbsGCSmsE9EEidkmEKiTxVdT4Hop3zzPNCpJdAHFavF9/xvOhhqqRQ77i/oiOceiFRz69gO2W0D1ZIhG+O1eLMxEsO3+bVLPaQIbb1EeeAbyay"
+            + "jZ8t5h5rOqT/OcnIu/5Qebn6/cXRIpwsMeMOo5z1M64LfipD8O5WSs8vZmQlycJeycyYxh2Tf2iV6tjHEzNCCdz3puFc3Q/qCwDegruiAlfGxSAjv5oqilll"
+            + "UZCcI2Ve2B8k9kc6uqixjjce6MDZ4T3mnG7SAJpZYTQk2Q4cHQo0kyCqDYpJHjxg/ubo1x7UyZxSSvnoRkk2dte1xJZx9yqNohW7ruYL0GKXHu8OGka18jkI"
+            + "w00kBAkmx5chIHSD5u/GfLSnD/obiiWN1m+grE1arSk9JmKasSNwVG1nfKzmD8aZRqVYlnrdoPQ9yswklCcvOAfO4eEY3fnmlOpsU6FhTd/YBTRUX4q7sEso"
+            + "TiKjfWVUl3Q9Ds6eYcTJHMfJNnpwhjHFfIHBvn6M5tURC34u5Iq2buSManDCaIbSUCxbeqeSIhwb85mAYVBFFRvimkvoFTu6fmueswJwsHnlqYZi30MIlfiI"
+            + "ejUfHbD3ScQaLJayECdiTg5kmX7hbLT9240AVQHT/sf5lwsMfTIrRr/LOfb067iS6TGeE8vdcpK00JaB+8qUgsob7BJmqtjI2kvfwxcSkHpBjy8svL8mB+Fy"
+            + "j7EtFYBpFCiHMJa0IUMW5C8xa4x1NErPUpY/NgjhA+EK9dRCVWo4TYfuONnT35KtdM6pzgupuTr9dSdOFcP6fwYziust69OG6VhGOHhimdGztYz9de4FqxnP"
+            + "OEvczRQlNZQbP4UJw7olFGfD4pddDxbt8yYxjpe1n4v3Uypc2sf2xhE9MGdGHr4rtHu5ko1UgMj5eGuNO2gJNh7bloJpZNj7SGJ2C7OCiW/cusQYRCOuAF0z"
+            + "QJAWtPCO+NIpvSzAdX20TKpAAHlJEFIw1u6SwolnQcFEV4uDHUscYW7Y/VVibCJVZyE3WDDuPehEvh/nYt3kpMexyXvebPap+vt9sk78KLmwWF/wtyYkQ8lI"
+            + "dIfdbP05U34GUwApQ/G5XtoJlY76MCv5YXlsbp5GaK+sVERFrr4PUtEZqJ4v7KlwJN17ldBm1xJC+hIED2erAHeLuZMqGEIA6kTxjcKjDZdRaFF+c4Jzanss"
+            + "nf39Y23Ib0WyJe+slW5q0uS06knbsZz8IPWZaB8GPEg0o2zKNhLAyVsSkJ3gq/YiqptdR1eoJnLgR3q5iq4zG+R5P7n8htdh5wNtOFujWOV4TRNBHRsP2IgB"
+            + "Pg2sjnvnaykjBQlveBXrT4u09NW/fKsEmCsi9rCde9cun4PJtxvtz0BZW9x0mli18D9LTXbEP4l4NZBh1jdgLcYcxBJkogsqaftfzN+0UnUG4mNDisW2OaMn"
+            + "u03HUQUtGqIUHX9ITpCjz4QYpSZ3l4VjMiybkhkwtNaMbHzCgbW30124Fm9ZVt2cHjDeoQJ0tNoOzeiwzrY6+nuhzYOe6MWQTVZcUPgu3eXpVgVhOHhT5FyZ"
+            + "x+pnDnc4TS1IolSEJXJJy/ZBMG5njcov5M/Vkd0TPBgV6UwPHVmbH0MjxoLsdQnrMk+M7M2AxGPns284BCCE1Ti9kFlVjKJfOndvPpNzKGDOkvSQ23Zcczm3"
+            + "6F6jsndIBLESLe7vO0cxgp7ziXbexB7o+OEurnirJDa4Btg+sdVADivyyniQEDT0N9zcGDL9RBn31mQwvFa+GKw61MCn+sS0khwKx8Lh6fFl7Ru6YD/H8d5p"
+            + "nR2Id38jtcnGfS6Jf6Fcveq9fh5zkmaSPAfhd02m0QpMXxwwjD564Pswb0A1GkQSzm/anfw4CipPzx13rk1kooLoFeDFSn/VF8MnFBlkhye0befTlukKXMBE"
+            + "3TRnQuL7KEW7loKmwXJM9i8Cg2a4hiUeGGQc/aAVNa94BI1sh4hut0fPWAn32iZjkrz7OnCOMH/VtrUPHboTF9KMBFgtw6Xk2qjijzCJhLMYs4p3ovA8eP0Y"
+            + "m8agoKaEg+76EsyAhVt735Poq1C+DZoLz3F7G16ujOEwGAiKVT5zcwLQhTGRo2ypU5vK0Aad/18at4jnRcmHLL/WY2SgGiUnPel8Wf2y2UPceGmLg78gUKPg"
+            + "IheWH/Cnn5TXtPh3vGZD5oAG736pUEKbldMGKQ3zSMt8anW6i6OfSL/YkJAPOEgJukBMjPq5vQdksoa7NVEwnFUQKJm1V/Vu+chqzMJ4gjL5Li7W8i1xzz6A"
+            + "+hvLAiW0SJHxp4CZSsIw7jQEeEtPTLLlpdKomfG9lWjzLiIAOv3zcy5LVA/LWT9y2gtyr8gsudEt8rAXnSCU87on8TkTMglmPc2T+OVGxBHaKTbFGZO3erPP"
+            + "z97FxPIYXjOYPZTduHT/Cv94/81RTwQLG1EFIdIZyojG9MsHeVtMhjcDpbKvde2/SwxfA4CIFmznRKjoWdl6iP9fwyltiJZ/1sFMdYMBtHe0dCioTe02KtWx"
+            + "N13Bp7+LU07VyUErjJrKB9rvSVUK0iBvYABIujml7K3ldKYLk6XQ5ePejslccodDqE6lHTWmCee5MEII+3WgxTQUeIjoWXHG424/8h5HSUR/slbLp3793fRg"
+            + "bWcLVZ+JDayPldxxvTtwp7aCifrCSh+6laE4THkHW5rmWAn9Q1hfA3lKjhboRprTcuNVa64DPNz6hWepQmfOTweiTOHKbRLsWLeD/4xQMVwHlk41c49qKhqb"
+            + "Gobs2Td9tKCQGNghvseirjOPb9UOhIQwyjRaHL5smAAIW4ILqFfnsj3QRQnC7owXxAOyy8TfEs/korw5Yk/589d4lVEZD5vzG++P+GrABb7SYnMFkSHegKew"
+            + "Ezr1icTroawUqVp3VyMyu7HT9+C6DvEbVCE4GzgC5SmlDJtowUhKIyWkPiYkbK87O5GTHOXgoxQDCZklfhPj0UQ91hk3hsUvS7twMTsuDQxdyKxR/9wGVxVe"
+            + "JL6hqz9lemREXwFQ3Y36AMXcfchxONtCoddpBSO0ExhkUu31TwlgSfugtyBlJQEwam9Ga0Mn06cTpEpgumn5fIzTiEo9jhuUa4bWG5MGXLJY3wVxg/dTPCFL"
+            + "EBtgCu6SZyykpdyo4qD9+ld7r8NROsmSNG/ys3sWTwxWjMq31m2tYiDpYdSzxUrHrNaS04qODHadA/gGwPmKCiXRBOWE4GD11keyuwoWex9tzinWtLjUOYcJ"
+            + "gy0yk0J7J1Zotjc3JS+dE7X4qw10KjJKIWPjYMUTex8vX+0CNP1IOhBiudoqZc0Idf22+kRrar9d582W4S5ZTrVcWzOhASccuPIxgg687Ds6Xx5KZRBuOpMn"
+            + "xifSSfqRGnthagFqonQNzsIdxfemlIcMtxL5DAyvp4UPIvrBkGnLVQhFOXNsqvO8uXJOitJcpxHOGeVOWEG2XmKW8Ww7zhXpsOXlbnpeNLYuaadhU8t4lm5U"
+            + "12GDbqEFjSoSwmPwiomGUObpALP53cMJ1/JxJ0SbncFZf05p5AcU3O7900+c1eS8DyTscsWWL57NeeVlMQII9ONt6desU6z8XQtV8MDv+dL1sEzkFJ7+zz1y"
+            + "/Mp+7PxGaB8eCWtMMemNdT4K5NjRp2139k6Ah9rLwTjDORutIt7RaO7URvnWnZmwEmHpamkgIe+jNJPjBevQGZPX2iVVng4nbYFMlZTi1gdNOP8605Ms248N"
+            + "xV7gF+tJY5hUq2aN2wDGChqt5pzKA5SSaEdJD+GiorC8GEzS9jGnTf8ZoAejo7hW2/sF0uyaLmi+X43orz5bzlH0Y2yl7sCHeooRwqaLeolJ0YsaSlu38Not"
+            + "ioEFj5RAqsXImzznSO23gknYVzVPQJgFkDqU6orrMpSvvZFNNTpAC8L09ZKn4kvhcCidTShjAgLtBhJe15L/OEVYrRs8KKPbXSf+q0A/lGBskIkyWVbpRkmC"
+            + "jCZCxWKqjm80nEkrMr5Cd/awLAIK0LeL9nAJ4SsVX08J+sEnQNKS/r72jRGVyiqSZUAseUM0lKrwYDT3ZHPwlNFC7ZZSOlUnYaQc6oUznprt2UcrwEFRl3h/"
+            + "HvxFSg+/trFD8gPdVIy+Wh537SlCzYFNNPgBHbSOHo3GnaOiDXSeB7Xtk8heg5Jr3F68GcJ2r2Xo5nTTCpz0ouBGmJgkNgK8QKVF+x4vKhJeB4M1w9vlTLik"
+            + "X1dlp6wY6wbFFFdb40Ni6cQB9fdSmPFFeqq3M3JzkhiWDuN3JcVub7QKjMMkVpeINPK+BnOFetjpCBeyohzOygl5FdYFddsUib1lCdKchZvM8BQrqkEKS9ts"
+            + "FOmKXeln1en2GwmpFJK+dX1MWchNvAUDr66YOBxbgh9rizFgdIag227dWcT9+q1WmyyhwkeB6+64NuI4tH+Y8At21CUjvIOF1/C/FzzHdZ5loOoNOpYtYfI4"
+            + "yu5YGEV+lt2DOEcNJtaGh3RfLcaswMIcdDTc2nak9znT4Py7enHiQ1LE9nW4VP9ZiTPM0aRgmF7rO5E/AIUobpJGbApLeGxzdUQK83Lxsb3EJMu0ov9OMZCS"
+            + "FaJzOO41J8GVusxVIWC/7z6iOCr/x8fVmIQjkZNxD/vIE+24+bmftqVUJkU5zPvK8SR+ek4rO7YDEuMIE1ewI06ave0mIv5Pvi5rywQba5zDe/AdNBgX4D+W"
+            + "6QGqJpnhfSsk3dCSvb/dtZUwqPajmppBRZJH/tvKjFMV3/EBoTWVebgoT7mbXGoJLWJu5SJ0TGTI8GOAWUx6gipNjZVLDrN8Nvx36PX887Ea1aU5mQ9/623n"
+            + "IH/JZJ2sDOsaYFoMXgTjeKyDFe3dwyCo1gf5rIG0x05ulVkjtrHHYOOTKQJlnypxj0F7VwyNO49P004qqg/Z7y4ZDaLfR88YelTppLzd6DDj5QQSsIuU0Gnl"
+            + "AHX2h5wERyecqOU2OYFzp5YaQXud2boHr1TIdXCskF2wv76k67nqGQ2m4gPwC6NMJp/+lPh/ZTDJOTXxd4Jfle3t6oWGtPMPmnsaMarZ9vTDlO92/dwUONRc"
+            + "kE271RfxK2gsg29RBAjID18aYpOXcHsWGb2f16dmgnN+NNroWKD4tCZFABsVfSEafZ0s3YWNxQI3ROpcnPSdwYinM7xEOZeWN7jVkIe4Zb2DndmNdf9GfnIn"
+            + "2ZL1cPvuvRiXG9LxR1L///tXsAfxvduKSMBlkD7T4kqmtjCmrxboZp2OdKDg7fTRFT6B2BBw9UDi8KZamBWIfq+XSggCIrre1FUvI3+0VPqqQv20NrZrAroU"
+            + "ShKwrl3Z+/kodr6FPlh296AxG4A6IohNQH8Bf/rBvv1kZMEyMTdlZYo1JKuYVueeePappxdIUAQkks34erxzEVt1N84At2vYQY9nQzoEQFnbUiGC7W8nbEb3"
+            + "x7rfbYXQDAnrJ73kF/5+141RliWrkbIwYkKdGldKkO/0+RRdF1csfVpCaHjyYp49vxhvqtylcf+Y/843sWIa6DW4jl7hi1JeV3x/1HM1SC5XK6JCy2OQ6qXj"
+            + "M7GxRQNgYQzhnkzCzv0R8E3xxxX4bLRpvQfXu1O6l1bFiN81I9mE2h+pPJGpPfrFvRObgmNA/QUjJqddbNFMLkCuLxFW+FVPs2zyWOq0Zkyei2Sx6FNimUU+"
+            + "nxBYYy+GMPQUcwIp4fBiScahqliEoMnEhXNye2xm9WNkA1GNHjb0db+HdEjtlkxHi4W2Zo0lwgZ+9jyZgHMV/wgtxu+lMTWrW92sY7/d0AvKZ7sJCsWZn832"
+            + "1QYp/Zn0mo7ZGcNN/Uy4PZS5rPotUqI85CPzm2laIZP/MqK3vj0nhsbE0EwX4Ob6PQGi7ZOs8JPer8dlxBP/NRMDBKmzgoki0jagle+jHDnrCq+yQVImzR+Q"
+            + "nt/WXC/5w4y4Rx2k2l8Un1hGidYS6cJrT6Lymb5xzLTgQJ1uFV06haNGd+4H4ZOlbJj45386c0QEXmW39R20AB0/rgBKL/pcy9AS3pSQRaRKfLxOiRYFPXX0"
+            + "+mI4guLwDptoOORmjeHa7H3JUfhLBTJMmXb1Aa8OMaq1mElAaQO2dzS9UUvQaJ9a+NR/PW5QegjpfVtzkkvjYuVjqH0ovLBqVfxgCLmB2/TNDuKBmil20bsP"
+            + "29fQfO/cIK5+VT4eG+3FjlEiZhckHb/EYj+UUnk3trLQibawn1KLcqRJAUi42fnzIjH0vVpuPm0k9uLj3z/dC1ShkGchyD/VdGLB58BZq0LO6JsnglcNHR8h"
+            + "ZH463sNWjvaN8oDsIHNTy6vYmqRfBIzHPFOwuNtpKQw2uTIAbwSOeSGSw3na/UpziqCGuIMqnCvmuD9tz3V1DDkxykVsFGLYMcCjJbDA9o8YeA4wzysJLcMu"
+            + "SOSkMbUGvMEzijATSfoHZ9kQdBE96PAhMn1Ck/Xb4ek/iyRAhpF6y8/j/VX+IIUZ0VI7HVG+Q5uQpQMTmaUY5kFnLlz/M6pBGITPi4P43UGAyvZcdo1cpEpm"
+            + "3ChyZq53tBajHVLOMBgJpXZBsvmT96vA6UxmUdDELQs8K/cupLkIFwxvxDBHgmGHhXrUSEtjR3xPyx1drLsvIX1T1ZBZKZGsEMBFIioCeKbh7C6V4lTNznnu"
+            + "79OXmpYHwYB6Yg4WSdD+gkMHa8qoVXIueL1IGzq8oPh/gKBhXaz7qKegNAlamSCIMrT77vy3qHmSDE8uhjmm7lpds1UkyFZOT3qy4zVTTiuIVrtnL6GKFF3e"
+            + "9Vw1PEz3Zko6D1a024AipOTf3wafiq8PXinSy24MX18iBNgolKMoAjYxKqU+ValBc2R9Epy2H0TwdYmvNR1ASxq8qO/DeoEbEPN2tlicv9HTkrqpVhSvDjuq"
+            + "3Ck8Yo8falySr+RSD55jSmEhM8xW8pPi3aLCLbQF7SQXq208eGJdytwFp2NxOiOz1zReIQXL0Q/be/SDod/hI/LIu92Fsc0xtcSB6iaSC5m4d0TdBb21tvns"
+            + "xms0tnDUPO6HiZt9iCFYyIAFnHsHJH7EWw7rrZUCMsobQBmwTLcqrfVv0PaxES3JkGbAY6y8CGbSuwgEYh8DnAL1G5pGuSpN8gbdowFwpAridHNHXmF+8cWl"
+            + "jNyjPDNHXeTLPPP8b2+LsRkmVKTpF2mxMsosU+SdnxVEVGlq3h5AN/e/SJUSpZjp+/7gsYGAlPErew7vyrVuhAlY4whvqAXMc0XVldFhYESGzbZuhdMNWgyp"
+            + "Oclj8BhPxiVv1ZcK7OKR0AIYbFwtvaNUl5o7Pcs4mdVLdJvV7gzcW7DLbEVN6XD7P8g0TIR2xXvsUh4PPLGIQWYNg/PyiiY8LCirXbKA2hD8aPHimFMupbdp"
+            + "4lXrwP1pMT+kcNi+DmJaztOp/mll+WeTh4dpxs7vskT9Z2zPwHkjGoJa3YgiWkDinSq+CvMTkCRmBw7kil8v2ZlCs07W6KtpB1JJ4Vi4MRgNpxTGWJ71ozUb"
+            + "DEap8/OWlzZHaJ3uzZX+KgyYVJCp7BTEvnUJfF/QUrenrA/PdHa40h1NYXvyAXUzKNUMJKd5becWBuw0u/QVZHButZkS4eISxNOZC6KZA7kFC+UVc1KN/RCC"
+            + "kDE5SHgWkUeILPi3irSfLI8viXMlss56vSwJFEp8b+yc+yas/w/Jwbus12eFIpXITHPFNOYZHHzhof75A5fW3TNJjFw0JyWlQ34a00oRGFLixbv8b3LKJbYK"
+            + "RItlM02jbOaVl8m+jQovobQaacVwHI3XW3Ab1EqMbeXrn85HfvsM1OY7PCSxhWqXK+SzDKanNgLPhdZMKvhUTI5ycy3GF1mFLNhBO3rGiLAgY/DDo382jGb1"
+            + "VHvhlJnIt3T0LsgF1tr0yUxfqBYxGd9AANlRuDAU46CGp6ey4yEj47s2AyrTSnQyoM3c/+D7eDhbl3quMTQuX/QRWhTM/tfJbtks+XTv6TRJqIiyEDly7Q7Y"
+            + "wo2CgK6Wi7K7oaqVFymcpU0PukYuto/+7XdNh6UjVETiaApa2yK1FaOdtIQ7Hak1VitnCKq7WOrAmkiM0QrprsVaqLDv+A8L6truMKmfwGFcz9nrI+eJMtMB"
+            + "cf9HnxN7J1g2g9J5DqL8pbYpFRGqsQ+ynOxnEYL3Xw4/Qcc8R7HrmU3uv/HwY6g67zDWflX+0Y6txzaeIy+fdkI7yeoXJkmAdQ0U6tmFf2tDFR5zpW/wALY+"
+            + "K8ffLCE6DPhgKrFQJihlS2YXjWH6N9opNmkRpxuPXzxbudWr73M8/nosW9QDKvSlnmpKt114QBL/0QUUqeGAYy5nrWMcQlXn5XA8RhhQfmMGkD5Egw7781Hz"
+            + "LnmX5dIhp45hb1s5an/kVLN1WLTM7Fcw1dSgG9tNJ2R/4UxWL6l0XVTrxZE2AYKjgfjY6p7MUPA+tA4iGXJdiIUQx6gW/zCr9eEGeFyQK1NT76dYCWmM9Gnw"
+            + "7wUyYIFIv7hIg6zcUzzHmmOxVUNBQENiRnRk4lVvz0akYHKxU2gWnms2fC8lSGXfm5yU7CcluJTEzCDqsScUUsAz+6frpviBiapUjaXQvEcxT7nWKWf8JzwE"
+            + "DSPDzdgVL0iG5rbdRZdzVfCvKVtewurTlag3O10Rm3QXhnGJPY6qp4GGHkAil6uhBIuSSc87UfhG1sLLuTpH3OuHNRjSrD1eSxCmzALl0L+LgUPWJiE5obt3"
+            + "njagM0FA+tmxlUOYr5mA0CfHJQ9U4YJBQGfSUlPf7QyFEhioGZe5VSJkEIBOkdd30wPJEuqqI2KHRnovg7q2+ex65S8vPACRo7xXreRcwBVssR6sA0wKnH24"
+            + "TUNC4heWAzWzi679zYAEgb9uY445Tp/HKaRz4e7OyUsDABDXnNS96GmwZtSZfU6QbfyLQkFl806CgntVyigrVuetKTharFa8/gD29IMYih/go3Kbcl8U7wlk"
+            + "T0oLagPSCLE8hj0iXGDp5NngJhLQH30CNcNyG9yc2o0cJGIfawJU0IoxNR2T4MOJYwRzYdNWEKe9lUck3DE0h5aKHdauMCIgwjsPY7BV1pzqFTyOLIMREHhc"
+            + "b6GXrDverTKplN0VRAGDOkom1mJv7OyZacWluD1nNEvRGCm+V6ZkhW6zGxEhb/lmH+0F4Zg89rudE6DAJFxFPdZLwgpqBJ4JKoc3n856U+dxYa1DDZxEepnv"
+            + "6nygeqlmL11IZ4PipT/G1PAvNynZKDuEVR8uRI9k2zXVr53C90YXsDklB1j8sVUq5noOZe0NF2Z79CGk2YzmW9Qv5li6Aw+V91VwhbL2+CRS58K6UMV/ZW3s"
+            + "89stpo/xuPO5RN2dK3xAsX1Tv/Hf7Tp9J96rGg1tsP39Zu79xlF/+TpkIqL1tx8+x9Ef1QinZvrIrx6pNMJXqUGBKzZjBss8v9BHX4O6ljBm/q3C/Y6DuB7i"
+            + "yzwSmx6ES8VpoQ6xe6nyGkn+AF3/NYKWLkU9yeNcJ/cCTpxVL/SvP0ug0krVhQpXvJtry5iS8oULwFQOKxid7BdGxX3+YLcRhZwnJRAR1idyPkaxFoi1aea6"
+            + "aeMg5kMmXfV9emUHg0Ny7+S5Q/Oa9EKXv72XcqBSVySUo2S4lXM1XWvghh6z/TaZ8d4CrBsNN1G8iUQLgvoizfHeRvUQnv7jIUOfsN5iIsPcYDQWnjT501g7"
+            + "tNdhTsO8MItBE1lmCIESV26ApZzUbSXWwT9C0d9RGHWslQHwIu7ypM9B/Xm4rEfhIC9u0/6CH+jiz2iTOrrpoCbaPFdeDgiy7NomMPFnA/pIAR9pXRySTWpU"
+            + "tr5jJt6ejhZqWTIMjJweHkTykb63aqjgBJxg4JLmZeBrnQQI7RfyifYr/87FPO7oPX+LUiahg93F5DKjTDQkuvFgvPcVnKL2HrfQ0mFneuLOim5KH36e5gXh"
+            + "aevY6mkPPYza5AiLR1vCR6mbh8rgJCoDlbkh2u62iI2JZrXvF8KjPgXX/Lo+uhtUF+1NYNTqYjvx8p7tSAjFRGm++W8YDFAaE3atLSDoBfx9Uugd7tFl7tPV"
+            + "Vzl3poQPWbBl/r81teKIl/xboSlyOGBzWCyvndqkJoIFzK6ZKwiMMxlz0Lnj2uUPWtP1MRQCbBPi3qRA43q6w+J52FB95B9o4LaS3jjBf90tkgyuBpFzP6wS"
+            + "uk/9Mqqx5C99lfaJJPPeny9MPlghoxfQCJtA6gVUr45JVkdugVNLiOWQFmf+JTIEPGExDS64pg5EABu4YmGvp3JJx+0F1tUuvspN6/J2cGw9QR1TBJQ/L3W+"
+            + "J8WmQ3eUKd2MVwTe8G3Kd74lSGFgmKi4r+smz1U+nlSwsnBFWKl1kNhEyfxNTVW2EXAyBNiXvRcx0VWPJv+CPidIqw2qhxYMj35AlYf3ksRVi1yTWWBrjn5a"
+            + "SR3Iet+oh8ABreyZ6VC+odepeD0IfTm0vCJxoPNnaSMdUWlZM5UG7fglGH9c3NEAU/QMpxLbII0k+CjCFL1j7RDpZcrg69BDBV1lhXb01pqZqCjacjei/aBt"
+            + "UqJGcQOGJ1K1WOuvhVob1H9oO49cB9Qn9kvezK4RGXr9y2qlySy/brwlf60velBLm6NhooBLJe4rlZauLnnLt36lxyP/5y2Ndmi2QVRKh+/5H+wWBEeZ2m4K"
+            + "Jf5v1rZCwTMT/gNW5ry0CVky8z3mJWLCIPf7mF5UtafAHUN3j/TB5p/yw5Fcx4ioZVv5xRt7L+M7RPnzi93NhAtsJD31XpPgY9vW8gXUwHX0o7LAiWtE1kUN"
+            + "HV5FFHZW5Jq+dakTJiqr7jVwSeP9R9xpXW5MmWlfHIo3p4JLF1uVD9lFCBGMcPTnDrL5iYoxHtBFywiOCua8QGnZoZnrUXElThbTm8yiu6ThtXAiFpQsjgYs"
+            + "6izEkB+RQ6cuTyqEF9+amBee4tVqAavS93vwHlaCLrZZTvgjBbgoFl/LCo4wGo0v9HwAOBvxGIItSmOhhpIrZ9kOqcKvu9NEa1tU8mn5H+gwQUbOCXa358Mx"
+            + "maMuhnCBXcAbetRcTa6E5yT6J4jetPQjgIXjOTh33ceuT/xWRsrZCKXbb48Ld/6C0MQArLRLXlybLd5zult2aiqfkpOA6bQ+xuZc+Fe7emFGGZGoJVlTZcGE"
+            + "ltoGOniQ8n7FhmdFHfe5hV+8M9U53a1nduHbaUjdFP2PsH+GnHoDQWQan+9VbYptUBNLi4mLBBi8A/1BiNWZ6FtQpa8jWFo5wWQTbhGwz2VZH6YQZtrigNA4"
+            + "XE039APhmYEDjLp6UsYadf+xCgk10hETlngNd/iW2j/Qb5xQcCyDHozMomlhdIdhtwkGH7h7bZJdW6LlSO+2XeyijYBCtBs9jVTNisausGIseqzFVO54QK4h"
+            + "IHpslPOq21D6RnHBjhQ+GusmeHrOu7WYpfJvOwex2z0wbAQIn63moxbb36Gvi5fwi9HN+sTwBuqBmfMB4IW/klTRXi1oSM8zJms8E1k2Bm7ePTQlpeyUQTwW"
+            + "3I1xUfIpxJecNAMpvwhhww2aMEFsN1616zS74Qhrp6JGCvEVUaW/txE2StwP1YLQdknPjB8IkIvH2bUomcFj2wpb+uMRmuPrCimDvrP/GoUyrMd1BsP5gc1d"
+            + "j3F484ivqwSxMAsauf1Q8qAQTmH4WlcKZHL3jpf0rG1IFf5e8hLvBLudJp7lOtjvEZX2+Iy1QU9zFt4GGhNIVInYb3d24Gxyg2uAUzW/Rk9Gs4lsbJbYRiS8"
+            + "bkWa3O75a0QC7X4TKZR+yYXX3aIpeu+S1foyh9bhgo1uEg2dxQTq/evc0clZdbd5WU1CFDOxYLEM/Kql34DQfdckYFcl7MDFySvMF9fFtDvIlwAXw0XjPEX3"
+            + "pFJjhIoOhS+7c5yjQ/Vo/P41lTHcGPesHhGXqnlPVwEhNtwAtQ+REe6gbrMC/5smlnA2LKf1voOvCHXVT1J5bzCq8uE8duu8ilmvTJOFkLWzOIHVsEOgeYob"
+            + "pFILKoJF1nZCTUkVXfOPm0/GaihOzFUyMpKHkot6TJeWXGTvz8+qVPS9k5Ui+9G65ZWPXYTTdG6rE6Y4Z7duKBqQ30zYg6x55LWpuTKRqO5kRnzQecWFnyU4"
+            + "H/5KT5Ke5tZAyotNtAKlxWqEjjrKbrZCMkQl0etL3/A0l1IrQpXMF7ggCAQAFEeDAESJJZTs8Pxd1zHwiO2/pimAIlBy+NXR+QkKoVcSZ0qpX0Xf/QOiLEiT"
+            + "gvEHNqmaUa583aGcybZYRL7wjdVpGzCeBmXEsPkxuZehvVpYc5Ld/A7ABRViDxhQWMjy6EiGiZl+O4D0kKQaUBZSRDuLNvPXtXVRZMMzLbc0XDfTEIyj4g93"
+            + "w6+dkUr4ju9EcdO+XxDdeVo7WI1D8hupDDQl4uXo4OpV6zAOqU0j2HkZDUBClqJ/6IT4V9aKYzZutfhbiewPojpPwucFgOQ2fh7MiwC0U0u8T+fz+sEDInF7"
+            + "a/2lrUgqKYhTZhr1OIMlffpxR0lDWgWw5NkmNU/hNA/a10fej+YRji6BPwXjImX5mUWqFDErd+fxOlt32vZ0dqJUE9KEk3a5jdW3Jo8B4V1T9wNbYjiddhk1"
+            + "Vc3+wK/a6YrIbPGzyGa4pcFIUiwZORl6Ui8Dt4K69yo4h66zS9fX48X0RDA2K5R8OJmqivh5+OLScCwnCDuUXRFFdQ5wOw3wNvpfXaNd0JHttF46966H7iGF"
+            + "IR1IweInA1mM1R8TAS/XW/NFc4RA9fqGRMT5FnGQ1E9YRVXcr9mf4W+zciLl8Wn1o4cO533NoKjTmA7V1FdsU3zKa0bXb6zTVUmjE082JHzBcqlgM5LAPbcR"
+            + "Aunx7N3GEuu2FjyWkpoyhtSNd0Dq8ypTOEgpyKDlSqVlQyCf+Sci1yjf8OrnH8nZyGvSVN4sRyauFeRkRz7Yeb0j02g0oiuKmA9VXhR9zR9ryOPGiZGM8br9"
+            + "uZ+BB3pEK5R/2HGR1Jr1WxOsERQ5OBwUTQmqjPSulYP1Il6q6zOzcxRMkjjVLB/FA83cDBUNopSHfuuODOeHCE7a/+LeKAwUeCbr0JRcbv6tsg/727UJs3+Y"
+            + "WUn4CXkREWOQ2WrU/LI/L7Ke3JGDQQsWT9SipgY+ZOV7b9FjSlBg3Zk7ynIO046bTFYtQaXoGVx7MZWKIYoFtcbFnOLEm0+5Cq42vCx8FoSov5wF4DwhJwDt"
+            + "X2nM9iFsTLkd0GA/tEoHX+yzYkHS6kaaMB98R2G/E9evoa2HQW6508KYNdGT7TZ41L2t3wGqfqU5Ihp1IQa1DtBC0p0WWIJzhGfWmagKgmPYpzfRo76KiTcu"
+            + "0s5fO7xdnplfAn3ZO+hKGC/CSs8zp0ShaqPxk2YkHYBj/sVGRYtCTIwyGTi82MjKAz1/5gpZqSDIaHUkX92DCuLuOqzhuwd2rgfhYRWFjiR1byhhJbSMEQ6z"
+            + "6syQC4W55VbyBZZnDMQ6e+/iVYyu1hQLVeFJem6vm0SY6EpWa8UYjsVzZiwbUwAR5A1DXounsmcg7dNtOy8Sgg56B212643zNazTmM8Vvu2i8GgcgpOpT5Ll"
+            + "FUKI+pYOmpX8VH+b0Qx4DYA+OqV6tEmqPlxEQj2AcAyIQvw5d5AL+v0GZGuZSs6efbL2uKawJJ7HAu41/8OnyHQw4cMDYzXN5tCaC/4PRrWrBqTPL9DS3gdk"
+            + "bH5AT/mDW+wL1kRvFun773F9UwhF86LaN/c6KNwBpww4oiZFCe+lnogeTVXwmFYug5TKY5mMFr4Wg3SbjLuAIqy6IwawZNUe/4QIYAvWycawQ7IkWsZEB599"
+            + "qWhAMBv3xh7qgngvchymD2Rg4eXOmtCYJmi051FLq5EGsgnINWKBG2N30LLbW3RAeepVr/TJF82OKVoqS/Wc9QFKKMS9AblpHGwmUadtttPb4lS9njHjhnXN"
+            + "n3lWJ3FndIqA6u9SqUXiQDAabaQVzP+JE2Vj2YlUvLI1eal16CRkYLZqgYDZlTkFgwS6sQ50Pd8TzLVZVcvTpEJ2VmuBD9i8xBA70QQg4/Yh1cGZq3HBx5BF"
+            + "n46l3ZkR6bUNgag3Yf8vHeettal1ZnMv9Djp9/t0H46HArZMbTXib9mVQhs32MfOiNIMWORb26t2YsdCEbFgxTeoRswFUnGslnnXdbWXuS5t67WVq7p+oBhN"
+            + "aiiOqaCvao4JNwYYit4FtW4mE93kAs1OcEqNpEdaBb9Li5OCulDe7trYWCPXsWXwI2QX+fUdB14cnl+ojwEZC1PPA0aipSGZ0cufkD9S5uVfj7JHf2bzOM1+"
+            + "wTZVcOWFGxgV2q/44HYrlEuyYtWAcfKFy/28EIWce1gYa6XjiX6GZmTHSIkUWe+/+mEbypohD1A2Uu86HDyAI/TfqloHS0QQVBgjnHF9of0eOjCvAWf+/M3Q"
+            + "GP/k6x0FqiTuhDBOp4tXDKeU/BgAPIdiL5E8TQzoP9QFAmtmIeBpNhFr8qWF21Ee2pACch0GzOAnPfnagWhlbf+28nkdwVuzoNdO+zaXEpQHpvsr0iKhZDQv"
+            + "2gru5Y4OklHLctHHHP0q71B7k+9d7Fw76HVaheLEuGVaMRmw6eEy6IA8TH5DUQc83BS7W/nYVlOlFh5ucDfxBH6gtN1ut0LX+lItw6ZxphCO6AMuVMrdebJS"
+            + "H2kGTwtBQkFbLsXzkGeQvvTnalYzBikRMWTJ1BzBZC26Mzw2vwxUD14fwgtFyY/9lTR9qBrELy1tLOjcDgipH3C6vjKugB/FZPnEg/WqZjDt7Oba1aLub+1N"
+            + "xHHkDThPrdgt1gjPhK6HGo568mGy65s29IAwOfSIXAOBOc/uD5BsQ3wN0DTQY4chM4yyV/suoUvISIKgT6JqU4bx87bf0YxOWJAkAo6u5J8sWw4F8JNGhx88"
+            + "7G2YcZdiP/h6ht8fnk2Uvk9TPfSPnthpWccrdDSIMFzZoRRokMiCxGMC3mvMquZgJjHwgzjmjOyE0C3ipN0dZYi+SkyODvE7d1/uBbzJ1mxUKzMoEnOYGj3y"
+            + "o5XUvedQ8SlGWhX0LeNtR1yL0HMfkQxr9w/Xmj7dYs0mj+O7OD89gDt/6UmcPhKYIzWButxCPZE97oydVtWys9kPHJ8idCjRZ4BaZmXFhRbA6h73ZDXevZ8c"
+            + "qi/skLF3cCalF/t1SIhCslxCqlGFdrFDawLKx+Jaq9OqplWgO6LvnPAzYKh/ZOqTMLkW00K5iq6aSF2F4BXWxxSq4MwmXMz5HSejg7k3PhPzwmqgBXXbY6Yt"
+            + "+nZS2CYiQDhWQPIFodrBCHmlHxrzI7P95Rz4xeF5e+OtVzA2Z5lEKWgvXfkn4OdNJGM7jS1mn6/NPQ9mLoKu8cGXqPF4P8CvkaGL0jKbXdJyMjY/v2teR5AT"
+            + "2wNFhAs/AAisk8qa9za06d6GOgaj+EEAK7cDpsIBrKJ2Xf8+xPGUaq+ApQ5UiMVCYdLdjH1gu7aLUAO4dccvcb43G7+ec12lfZRYC6NZe9LHEYKvq6XOXnC/"
+            + "HUsJ6u+jQpQb6WbMJ/gn2E4J7GgE8cV2e1zs8dKxCC0xwSc8ZatSCWxUxBAz6HCjDbqxvQxFPPwYy7BEIRAKV3Cdofu4CwYMvBCy64M/WKvFaRtCOkNS3gIE"
+            + "qgNWa3yEH3K9xW4gwyKwnIkl811YzFBKzcZil5G+gLP4i8AUbS4W3PLlM44dokkQqInoLntFMY/YyqM9NvOxlhhr9UX4rOakoB9oUn2c8ib/1pyF8ATqg06Z"
+            + "/CArVzmYsaGjkO1X6tifZyZbz6qqR1HlN99cCglMmEads+omv7zQ+r8lWRI5Mh0fb1kxzAia/xKRPbjzj2DbSfrt+LtcHmULbQyZa6zcchme9CvuwTIpK8LY"
+            + "e+/xByDMUJgrcg0jcnblRHwXoYrNMOufW/y8QUdJA3MqlVI1zQ4Hmwp6fo5cyQsxgp/eCl2p49fghYGPtU4tCKKKe2tDzp4CjVW52oUyGpSnAqHwopzEeu70"
+            + "qJKnvHs2fdKEmG6ZfoNidIkc4HlA5EZlCyTcdtS3ga1K3w0qecUO/hGdd103zMYgLsYWhOmOn/btPTgXCrU/UXyFdjJNFHkHxoebOr5bEtDBBC7EBxeenoTk"
+            + "wOoHoBY7AKucMVj/59dbeqaolBTx7FY7BjPzwmwEeN76xz5bm/HaGuU9+M+qlzNmkAZy7XeQUz8OTOIqp5yoeQpAM1rVNEhGOyp6XKQLkA9sDY09ptNKnTPg"
+            + "RUfm3hLzgkJ84nsbgZFnCvghywoGytRFJ8ob5r96ReOsznSimLBAmvHh1nUdeeqmeivl9toyUa0dykzBdWxOpy7IdwBe1KtfB2KsIAc+7uQhqPiqdycznMny"
+            + "2+vjV3DiJVpPD0WRqfdWsCfb0QTcFEvaTfP9kl2X857ZxqCPCBKNE+mGszrsmDxAJ8bPBrIF6cCtY4KNw52nr6DgdfwmDZObf5znC0yxUT3C/k9280e58ncl"
+            + "W1YZ4wYt+aoXrg8PjziJ9PE0R5zQKuXmY5XOqnw/fA9tV4fCMgBudQd1UFaEKgie+K55weQJR3GfWPlbPxsRWyx5fFV+5BQBtcvGY8QgH44Uzbjr5S+JR7kx"
+            + "YaLUDiSlAKpG6LbhS2lchFXdhG8lHoz4XnxqvFyvaxuStBx1j0zH11JqFZX31Me+iBQBXi1tkNR8jFgdQbiTkxUY/I1QU6eQyb1Qg6HkJpLXY3Oa9xlREwMd"
+            + "TFSHnIo2HUCC2AZlW7+7I965vTDjrH5bi8DzKdqUc5KFuzx0IlYvOM1vwauww13gEV9nfymdP2985wvSMPiJ0lGzZAxsjK2wYA5PflH3xL/rnIFexciDOgCt"
+            + "lCBHWe3unckZTv59BbC63CekHG733dCs1KSdY3IjuB+lGm8035sQBZJdL+4bbAvAejdwHET+s6GIy3n1Ucm9vbRqJ4lKtIYZA7xSQpvdNVTknI7XcK9Bz4L/"
+            + "noP3Ga3PG5naCkcddgR2qyYw17FZnE7ZFj2vXnNTk4CB/AyOwyaJzjjERDygfR6UDbCk5RF5PLFhnLyvBFH6eBY+dYuG/uryUJpnfVslZDT8yPa/qSr7x+1b"
+            + "xXdv34+CHw3saYlOvEJABPuwBFYyBgeYZ9yvHAfJGCj1SbLympYs1QDwbzvXtxz+goZ7YvN80Yybqx7GRpKKYf81e8cr2ZIJs7d1LaXopB7ZcyCB9zpLevF6"
+            + "8Z2NqwMcuhN0CmsRK+kQvhnCaZ+uzK1seW8KsUx6Yp3Gu2QEPKk7fQZGjST8e/PhQkWovbbEirZjvbXjeHHYhqB6ObFwH+PXsao3C26ITr+q08S2L8Cc6bwk"
+            + "cTOHnKnONxLT7pxxVSmbR/uk+c5pWGqR00grhzeYQMJdR6d442OCQUQNhpuujx7p3SFe13jgrrf+9h2m+doF7RYWqZNhoEaZYqtxzYw7URA+4os3q1Pm2q/O"
+            + "9MumHknrhVZ4rdaAjXtzURR4L0Gq8ZpbR6S0PBHukNDACK0FfGgtY0HLVscMZutEBKFere1JSQPsSsffCPaY6pcrwt2YMUPXyfI83gr9EpJHlHWct+3FdSwI"
+            + "PxXBuIAXJRPCnnJ+O9Ssvq8oLQdhc9y6KLBwzN9OJQ5xuTFQvfWr5xbNNyQbwqy5xM66V+qIPhuMuxAHTC2gf9hJxBE9LtZY4+O2U25hUNavBNXLtA4gkYPS"
+            + "xJNx1ICcOSMCjkCe9tIvexNWNUWWT/hnVsIF3o0HeBHQ9ryeWyi0jrOSohKN8IDzO6H3IlJ9UDSKHOb66dIgNbEM8iY0smzUudf2kuozOjOssVh8CEO/C+Cd"
+            + "S+YqL3hOph87jUQcyiGY+sJp7ZHtvWIX4BqwiQTJUO3wFQ3cCuvKpVgOBanRjNi/rd3C4yEV6vIF1RjVj2PD+Lmb76GCNBpohNmbo0EXw0pkUoTLRSq68sLi"
+            + "9PZx7FVjrxHk6ZdoBA3jvvypHo/rahFyRHxg8d5YewSZl7VOgKimlcDpO43GnVNg5wnRk47PdNWRik/E+ZHbg4lniJ/wnJNadHbKlF8LweKq3gFt91FR0qhI"
+            + "63jpMPlyYYrRVgCiEULt7QDnoO7btFb2uPFjNtjhDwTh1zTNJp6GpIBjfsKhYEBu7KafcAD4exJOWtVYGMnykpsCx56FFhEnDh/bFDLPE0q//SlYZnRngsix"
+            + "xpmT4w2m1rfJUj/146+UKObtM9w2tFHhPjOoVyUCOUNA5DP5gUthRUkYPI1s1qikXQ7/T7M8AmDdnGIQm0aA+e6oj+gdEjg6456HRkn+O/Q2PgVH/r2I6KL/"
+            + "VAYLDKnu3iVHk8UQRiIphuUmKhxZJ75Vxv6hvfFoAysK9U/VbHTK04tUxLJlbkdb9zcn50jqrSuwipOmqzRnJOUk66jgN2eNm/bIP49GEL+VQqE3CneR7Raz"
+            + "e1cbtP3ZMIaBJ0PcuNcSjIgP44jhSgXvxf7JMT0voj+EqVGX4vax59i+kQnqOPV0D2czHoL4JD9UBayEh4kCVOCSfLkswRg7sSU13qRdEmudnXMXRw0h52Fb"
+            + "2GbR614flGFWj/DVbh9d8kSCABTas3yTRYFSt8k87ZtORBEbGSbgJ0pXaniOU1bdhYxzJpYydDS0zZwytJ0OyRcDfx2/TGYvxJH1N7rRyuMxT6iUL6FaN9qy"
+            + "we9JSoPHgk9tkNRYLUqJhdflduI7V+ULjW8HlUn0Jan/90CU0zYFhyRHT6DTp3qMMhB7crpk8TLWtZgdhy56dcUBEDY7f1bVWEXzl6X4fOOhlelGhLYacEbm"
+            + "l5JRdVXUCPpS83o5MIx0aMoNdyycS6rLMeQioIEM8mkHIHQAOu5b2ac3mdNyfiPHmaam2W7KLN3ehHLmtZhDaflfbCYSVjBKCiZK2WjMHVngW4moQUQkwvZv"
+            + "GapSNh63Vim+Oxyow5X4BCr44ES3eYxpVxViKNzt0RdWgZBZhJHqzoYXqsEPn/pC+bOP2rpAqO37/+zgR0L59h6fTPQYPqHxQJhD6MdAlfocMHbv0uEwZ8CD"
+            + "MkPTp1C49ioJowF/y6KMlTSdJrKhUKjPHfCcPbOgWEUJRdYm4OSBjajeexCNwkFURg4j7aG91qvZhey4LA0WUgrnrxqrwA+O3UghXpnBDUQNPvLyr99593Tk"
+            + "7FccWO9r/I3l5S2mCNkr/0dBUKuKNQYeGQKvXTOfwy4EyDyS1BRC6ezkh8XphcNmOzRDcwMVgxFiEUNOqksuxgiyMEH4JgG7d/aW8KL3nd+DLpbS1yO8F2pR"
+            + "TYunvxjFj8be2gjFc5cclMSKIMg7UyKRUaLeOACAFMNy/UCBbicBwTa9xZ2ZX2vgGp5VIqzsxc2029xMXMj4G9uXpxo2UddeiQHUvRvRuRaw2vfufQWKHPVe"
+            + "yTl5htnH11rFiAh6q/ElPZE6/rvudh+LQ/cReUB2W+/PH12rycrKfG9uc6mBUGnZsK2bInqe0w5PDCPkjm7Q+He7v192UGUWqXCnFhyZa+R+sjCT4rzY6mPL"
+            + "u359rb05T7jwq/BsLeeu0IYgvMxmuWpM0VBIJ+gp738F7sSyuNAm5wHb8sLbrfMXJMoMN6X4ELhyoDSi1PHGCMS5GegH+47YzQaxTWswtyhlftuR96bOFJ7c"
+            + "tMeJdHHfr33lUsEHAsAgn3fVT6Rg4xvEEHLARsbMGbE3fwDGWqF+bKc42IL2Ha1AVihO/XAQkipAlkDPHxTxBej4ymspObGfvSG/6P3CVC23THW+OAUQL9Rd"
+            + "f+vgPH7Xzxw3UkH2fkIa5n5Sa3OB8XthVe/vUBnDzzat38PEr/uao3R4lmWqsbHwiMqMH2dvq9/dKSswnPja4aHZTrk9/sIWgLf5CMS4Wk3swl7w42DBJ76t"
+            + "Jax29tn+k5MtBfBUlmhwXcMahhnNMM3VhFYnjR17yB4cJZW9okQeXrnrcwOpc8v93BRl9I7Jh2EyiuAQe6CiJAfdyWdYQweW8U/QKeHIvB8OGheK0hy6ud6p"
+            + "v/zDkgz1wsgxaGhPfbsNOZ9CvVejT+cmsOR1oB33RcRO4W8s3xhCxbyX2HO88tb5D3gK/Ll+klOkPFdV/rC1Ag2qIpVuH/UP7HcsN49/3n928FKBqjdv7YtB"
+            + "7yUMWHNpRMJRjqDcokggPRP0ol5cRaR9Yz9tXdZ/lBrORP7ITGy0s52LUlHebaO2U7XPi4eWCz7YxgRF6PNsIHd5jtHjLodd0HaymqXW/ttBgky9sB4niPVS"
+            + "4ZsjSV2zbmmx1MWzrZz2bitFTQ9H1DDWoqft9bju4VlTHFFT+AdwzDchw09YbypRD8d23G224wsKUtFQ7z21aW0EVISn224kwbGKm7G6F5FGA09cldWwfT1C"
+            + "8YDPY8ETMyvo9IDj0UNeccf7eF6rZ4K24dVx1EioRhsMOD/yigFB6yRsl6riLuLFF4g4CfucPo+6pkPHuGrbyqwXlAHCGAfRq0VXVeez5UmNYu90NRXcV9HT"
+            + "rOvTLxyTC3N3NOYT/VUxLiNHOKIiB4XEV+eN07TBbmqWPv7KayNcntexJirpNW7vys4h32CpAFmHEXzPeq6IriQARLLy0K8TeD654kG4uTxn2aEoV3boAPMs"
+            + "EbLWVqafRlciCWUOI+QWEujNQeZLu/vL6Lip3Y2wFfV0T0m4c6WPC3vCMkOQCo2StwHimY3X9fYAWyMgLqoAhXTloQ2Atyfc99AUb1mI5qD/BmERnze5QcmO"
+            + "TAOWs34xemwTRR3U8UbpU1y5S4iW9h5dMzghbLE3h8gwZATIRUUVpJe2l7HD1IPZjtq7J5f8WIp+50wpTzlevjUDqCvrg3ljDTIDToolZh1NAAQQjVyS0nGT"
+            + "dtB3OVN02yBgIJeRn9d4Ey+xMkROsijYmMi0QZcj/DR39GbgobOYRWEVj70KF2IiOdEJt122yLnAEXqF59NO3X6H3is+/DAQw2eIv1/HOI8VW0kP8SxTiI32"
+            + "JsaNmxvHcsk5PX76iorBWwDkA3PcW4nJ0ZwTsZca11YawQR1TlZBF25J+CTPgn2Hs8RMxlGjymYgZY1NuccZw6aCerhtdF1yoloiMmzB8g/cYKHjQqDpGj5k"
+            + "g86MXYNU8Skt2igEZaeEk0tGg5KUJ13fYqb2YHixuJf9HGOfkQ1Q6i28ue8scDRYzD/Jz0HiGJW3FwQDt3dBnDsbNq4PHKGWYwVtS6D1Qr2BAitFGv8OxFpM"
+            + "j4U624aLxZhC11uJEcdZmeJ2QgG1K20qLHsfUYwClUSmyVEh0ayUq86HnboYBaloS7wHTJVRdfM2XJzYwPB9Xu2B64+4r3WvmfFkTn4mKMakgJ3tCOjjVK0l"
+            + "1J9WxGx2LntOvKKDtLCFt30yitc1RZ9qiUm/H/4tr/qRJ8JjXfV/qf72+C0sRJsoF5jyo4wI0EMbf83bKwWyAytxkD+rpySteiOm0EKJwIPJVo8UHnh/q6jt"
+            + "kFSCyvFICHrCDgxjanrJ3nS53dYrI8zBerJwEi4+KenWMCpRElnIo+ddmYie6HF8vQqsng78nOQI629hu9+xC0Xr7rBTbHW1poGi+Gbo2m9epWZaQJRCkP3P"
+            + "9+bC8k7f07DmwQVuH+Exzv1J4LwudmsNSu1pbOB61gu4BGeqfYFNnxa46tJVtwL2nB0Rfb6cyZ11tyw1CjH5o5yu8ss/fRKdiVYnpflxDV1PEpznk2EOeLJ5"
+            + "ywpWDo724uzjeAfwMBF9eIKdDqMFDajByCYhDr2bob8Cc8s0zRhI9VkxIo7kfWfKoFUieWDCteVMuyoMkQ922hrc1ljTnLIU75wtDB2LqY9smwpCRHXtLb/P"
+            + "84MZY8WVIRA/7SXEvjdyOuCzckKesROVZ2JROk4TWXWeo/PvyeIouWKD59KDz+PHRaW6GABn4gvmrEathxsSLxwtKj0TDaIhAqsI9nic8oyjGnJaVLqTI4fu"
+            + "SzkHvjMvFAyUy+Y9Vw65jWzmqTiFgWZTCpFnw8qaDF/KiJETYpjVJlNLfegYgKa/sFkpwGM4kYep91B7uL5S1G0aovY2dg83CGuiUcVgSgl/Zgu/yi7eeltX"
+            + "Okf6t09zdhVY9O+cZcLVrrXqSnBrQ24l12P2DAlOB4kkQHyYFOmzQRG7A3PC1cPZCbqkpGSqVT0Fn4CIwx/NKl0/Q71loKONKSSksfDAEP4FUcgfFMHvFfjD"
+            + "T39mK5RsH+J4v9HtlhZQ/LHNsWJvvfMuo6jH3Y4eUffrjG3QlPS9soCcEPNse+pC9MXxTnRzTuRZAQfwVrAS7OcyfIFEV0BGDd6zVOpDclAj6R4CBvtVQ8pm"
+            + "26v2hrMfR3dkp17RXvyuKZJ4aPyQ211pQi83sNM+AYXBE572PAOzSPolbujRcNtRXm0s5OypQA2ZVCM+8A1+qrlRr6lOPvClFdiJOjPRc8utCC52FTbqh9mA"
+            + "i70SbSkN3SrGFYr5iauOyFpXp7UB8D2snPBWCS2rB/yFDOy0h0p7+VLui5btyhf9EF0vrSzDW1EUtXXQf3UDRdUL9vETia7Jtr/gFztrI34i1FWVIgRVBYBr"
+            + "rdNJww53iXqk/VbDHg5a/3S51gWA9FHC/0xVQO+jWN2TqXAGutXIdp8xGopgrwR34IK8iCGhWM7enrpSuB0jxNfe5EbJkpTArsNZUx0yXsOXhCmvr52mP8Un"
+            + "tERBrYI+EnGMcJYoAW6K1O3ONv65j8Bx4f8gVjtAlKx7+PUZJkle//n4i/M9vMUui5327SsiYWLqsPEdykjn95nZRU77hkJPazv9ovS5KOK7H28b81PZBwEu"
+            + "HrkyDUtJybMe+CzCV51fOHdhMkQf2ETbSi5Dd0fR3y3GAheaZBYh4wnIlpCowUGJ6biWTTaNn6l8pKE/iS7HkY2dEzln3lBIAM2H4SR2dXYrF+/RSQaUaJUm"
+            + "F1FtDWBG3n6YFMDpP+1168/1h48IfZlWc/Ojqn0Lfb+wjz+Nuno9pK3J6ClW8hxYbWA6dvXDn03C6P3ntSsauLl9Sy4Iv+jTBeWVR/9WsgWCwhhGR+FQAS2U"
+            + "6D+CcG1Vns5ul9+3xWLggZaaLui/rsD/4p371s/1Pj2X+VC3uvETC5H1Kf6LjrR+FtkRKDU5T/HzbydZvpd6cvS3WL+ZPPov7V35bDlR6a+ro6MojCx3Q/op"
+            + "lanACsA+w+oUZgMVRwhfcxCQxdGCDg+eHZp/LF5U8Ys/HE3xt9ht3trA13nTjSw1ahPNUx7Ni8BUNIF5wkyAC179AmntlQBY9ixkNKtQykaDT72zbtWskCNl"
+            + "phzGL6bOk8Nxy+H888WBnC2VKDQAm0ABzBHq3H6iR9xzbBr5NMEdBASFfFHtmPgN9GyW3rbrbZuWpiSO8vtaVVGrv6AgV2PY/2WgWWvlrtBABhwQvtYD8wIV"
+            + "/9MGWCoW2qRoJyeNZMmJ14LhPauArhdzUcBVrbGqJbIUs9uxVVeIQHThtG7ms2vZkeufuQEWcClc1rfIdyb/Cazalclvd/RXYgQj81O9iFHKLwOZDoTYX6X7"
+            + "D1UFoMHVypOEvk/+W/UJBJBSk7I+1OzVsNUyLCcBfBIaBMUP5uIf4DxHWFM1+XYFCnp9BykmgVrPIuAKH9OWu31K3E4ZrY2tWk975whAXiTcTjeZWZyAHXOq"
+            + "kQprr7VO6QYB5OvGrsE939LwA/nE4bFEqJMCntvSEMkaT556lvMOXZDj+WjxbJqfnbbm3ZcKOGa09AnlHwf/tV91LNzvA6PTG+saUE1jPyfn6Aj36y33JyFs"
+            + "L25QfylFe1L+uuxi1JyLze/NrmyOfz3aTSP2Hvsjy+5TwtZVr3TUGgvZCzKg8NFx5yqpTWUuX4/tNzUgF560yLwn4BigUG73C99x1wSySfbo1nMXLQmyYWjo"
+            + "NX/t6lnjHdxLCmAtwrjXdYmlzyAxPNns/eDtN5x5scVRUSj/TwkLX+8rIlmJLdYTPWoHbUBhc8WM/Who6SlWDjiXCIa5bZiH1B7B9qy0vpHr/EqOLkYI1vbG"
+            + "45mTMb5+RyLt+nuq9p5xfRmZploXyXVGhbInUYFBpd2Fu7F7ba9K6dn4nJx36wx5nMiX+kcsPpHUmSujzpMOe+roYeFxQXnwUcRBjixB8+O/P/dkkzUN82Ke"
+            + "kfX+rhkPTvYsJ8NfXqOT62LUbhD3s/du7T6vxgGY9VQ57kG/wK3m1+CFoc0ddgvhMwJEZpyv40qz5+74WIlPvwMCJdquRWpcHuU4LiwaGerOk9czYk0uqXY+"
+            + "XEW+3wGpWoiSxOrNsPEXSB6ygf4j48x7Iy/05F1SNt3JU4258eUtbX3YoKe/uFoOepEZN2PfeH8w4lIXm7jLXA9hifIYrsipYf5KTK9CDkcoMxLEInYfcojf"
+            + "ocnQFe4G874P653rfplFr6EXl246Zs8OgFR5WhGWBn0HoXr/G876x13ikqq69t36+egZHtbNHurHmR4Dc8ifXpw7frH4SE1bARkMyzmlxTAKktCAlwp2pNCe"
+            + "eUER0yI+RbklRDf+jsVHoLFG5E/uNF0o5DEjV+h5R19Elvs9cG9iZjvDlVZCMxJdaqH0RN0fJs2pHqi0jQrWhoDQQSf+JVAPFbiyhulOYxx2EN1JbndBkBTq"
+            + "9lFx5DF89qFCI3qMZDbZ52vFd2Nt3csYha24V4wEXJyEQtBzzSiduynbtn9D8ydmQTCSEHbwH2jQhWOuoSwA3kBXW+v/aGMOT1QvLlNSNvRSgLUyrO3dZvWv"
+            + "6xVT5xUgEg8CuLSHZB/rNyadpkNpL8aNKz9J6A6hCdt+lW7gnOZPX/WYNakeZUJ8LS9hKxDzlloyTiTZLDePkrWg4kIK2pGdOahsN5AyAiSkYBF31pntjvJn"
+            + "n2/bDFebePlLQi+P8+mwHJ+95GrXgWIB1k42bj4ot4fB9sMql1Ae9g0xA7u31430kUOUQFkM7fNOg2zMHXh3Iu0qd50hfTDZyZuB+Up7fizlNpx9ghwPUyam"
+            + "tLtWVN1nLedYOc8iMnoNCS+/UN19fMxd6n0+5Qh16sXr+vssNRzoAQpk5/s9X+Y8bjPL7h13xiv7MTbPgi4OFR+3wqNM98rrtSGN+dhbg6FX54XdwvdZiouF"
+            + "4Vc8NGdIyBqSQ69qNnneTYKJYGrAjNUorAmNBxKj/5dQHUnLKBCiSikLskQ8xHerun7mDlJRAYRjwAUIWZHHHYg6JNsE/FjLkxTWsmCkBr47FwhiYpPCs5YZ"
+            + "betlNxm8TsGly1Na+f0QoUgqWJa43g0nkxfSQDWLUSY8shWBKtzDCS/XyHEY3jq8bFQmtHMi7PKHwM1Mgd6C9RYR12tCSJL9CUkVIeJWFfgImJpC+tKQBL//"
+            + "cK41ZpxdLlAjoZXxj9Ky79h6utEHc6/1jv8uBKibrBJmcHNGGro+3IBWGoSyMXRnwbKfTzuafXJ3BvHJQkN/lEoG6wsvUQ+4vjo/pplswd8vJTKERG1nuB+h"
+            + "m9CEvkXyJ8LIUZmDgKq+x/cg/FjB7M6CnNie9x47aIYrvsj8fsEANOo3ma3Ew87dlY6nkv0F+BZec1th3s9kH48PPyU6BpAH/xJSkmt6FQKc67CHfaadrPY4"
+            + "wdU0NHqXxyGBeUyxj6ulcnjQJFQh5E37CcZkr6rww4E2Ha+L+UKF+k9+AbpDBm142hy4Tet533ryZIfmNyxWTdxMWwE8cmLZ2mO2Pk6mpMJOAyMyw/vuTlx1"
+            + "oYrzuGG9ANx6Da84k+A7wVso3PrkF4e4xNor+CRAVKZBFByCHh8q5lwIYEWal1Ix+rpJJaFt2dL9vRbrtKvZM6EjvGejOlSYDft7/KTJjAYHjrQVYCNZDJ7U"
+            + "Xd0wz2PMEwpgTQ649GFe6vJnacbwbRF9NCJ3sljseLef4dqdtO65dc+1wcqCFaX1khlqvIWdZGgS1mRyWOsy+BgvjJbTSRVGO9BEUId9pRIKMsJSJLQHt8EV"
+            + "VTcI7QbFRvq88tkXH4h+NasHyFtG+E6AqFu1A9cEat5qyhrIQY6kOnlGPQBIq4i6rkvGQL62EyBZiyfaOVoKlIw58CpErpH5KQEfbfArgWrifUZoCIzFlQnv"
+            + "1Ifjk7ak0W3K4y+ATdqxekbr3nnthW7sk6ZD8lHIO89ksAJD7aBdVHlrGloff7IrgnpfXSMuvb1YXohbkAsOmWdVH1JMi+9TYiAUZdKr3GETKfOActXtLcF9"
+            + "go1R9WRKVXHBiBQeU+h34Y7oJCH6MLweMcxdT8RrfjMSyLtVy+z/bJWhfTQMijoqUUItckhJmAiNIrLcFjIRTC7GkQ108rpbpurm4BLaXvk2dTm6hdPc19Nm"
+            + "Y1nZ/1zPdhxICK8SRWTpzivCa/l2a5iNdMUvkjBzcri2+UlwmvTooK7hVoLAoQHsBcoXlVhurVVjbFBmAzHfH4MulE3Npr1vsqoNErCCnIUtMphWgyPGr8Dx"
+            + "jP3HBFU5KeD1epOaTxqLtbF2d/qN0cf6+ttPzJ8dyC+6tpWQse6kThQcQHW7UwJJIYo2alsIAOOyCb+fRj2IqiZCzG9ccJppjVVQnYg+/ghRgsXqBAz5RDYO"
+            + "yMzfSDeXb+sIUqMbrSjvaR9JU5dArTYqGuHnPjlRmjzf82P35BB/BWCzWbxz5IcuMRHoVwMitnmBJMBbOFse+Zgik7UsrPMoijIKq8FO+qJMjXjIYIQ+xyhO"
+            + "TvofB0yIwjbJgp6dedx6S3gjiaSmem2H7/6rYHSqaN16Wk9tF+YhB9Yb+2myAFY4Bv2zyNZ4M4mj0hcTh/lusNROYEhghbjcw3cEzq/4Ghotdi9Z7mGzmI5Y"
+            + "nCVT1cctbhL1D0xazd0cZI3PprjdiNFrCERi1n4zUXkQFI9fgHjQkWrK74jFD/7ahPi9E8H7YoLyX97XErLok1xMz0XU4ieSetD9Cy/m1Th5AogxfCjNBWQT"
+            + "iJASs+lNZ0KIIo6+7JeQxeif+PNRtpaODFAZgwbHtFsC6WJPAfZJE7KvoiH95xrv6GeuvNqVNOm9ElQ8lBmMzLZfqSa2WvLPvYRNqazHxTHG2Re8dO26eENS"
+            + "FAE3aTjMWcDf0/v9vWexyAfYqmorTEZDK/kQHvfvD4/9SkYuLip7O21+10sUnvBLsEQ7s4F/CqKnFM7LJb+PMS/g21MylF3O+BDuyP3CqtKVnt1mIAJ+/mSd"
+            + "dmNodBo1W/6R9T9sdVHXltAvuJ8ZbRz6zqtmXyNjep34mvMLG8QO0PvM3BsDFifdB/QaCYnwcHLXWFU0+fL6M50l4uhTs+6Yip89YP0rTYjbT55mV0fDaNgO"
+            + "heTErtEi8Xj8ZKGaFE27N6DSwn2PPNJ8XXbZfm83hx9OHlYe4WGPRHbvYq8KEQvMVvfY5+2Hwll/SSwhFRpykZW8ggJsQFiddKyfprsRf2DKXEWWEM9wJ/PC"
+            + "zc3+6RGwZ8X80vJJaRHVWAEBMIcqVRwoL0ld3koCDxBbVTKOWI2HOWK2vFyHib1V/F212wjIq7wNz1dPB/xyVpc5knURug2eaQ10GcUKK+LcuwPcKum4AB5n"
+            + "QnFhBdWxch/bFSoD8UPk2HcHm8kRjWxzuvu8mGNYLQD6V5r4J7pRdii8ha4r6ftHK05N0/8CP8yigtR3fL84CDeX6geLHNWNMDG+UYYWgsv90CyPWUOE/mwh"
+            + "sla/ME8B98LJLKykN+KJbeTQMu9vJ0PBlW3+xxOopWstnSsH8ypskHTLmT1MsbwlJQ/89XSsBxUaC8SSIOGZ6+CQ0elsjmvBeV7u4UMdIQp8AEv8JKxGwbM8"
+            + "WMJOIzuP6ZVucHRpTf3SwPJ5pQC/MaXeLJbyeQ1DX22Q/+P80M5XcLC7RQ9EHcBxN6ks8icXUVdIkaS5/wbuy/ap+WcwzC9SZufpHqxdVccnAmEswUHKUmyO"
+            + "tS1tAdG6rNNUc4N9P3IWcpcF72nkdgMASITQS2c9uTAf5kWFNSNwQ93x+eRM+RICcOM=");
+
+    byte[] expSha2Pub = Base64.decode(
+        "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5"
+         + "ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT"
+         + "1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywt"
+         + "Li8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH"
+         + "iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh"
+         + "4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7"
+         + "PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SV"
+         + "lpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v"
+         + "8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJ"
+         + "SktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKj"
+         + "pKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9"
+         + "/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eH6oCyxVnw+pTAdU/b4PWLQU4M29Fe8TFHP+s9whN/N+Y");
+
+    byte[] expSha2Priv = Base64.decode(
+        "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ"
+         + "WltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz"
+         + "tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwN"
+         + "Dg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn"
+         + "aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DB"
+         + "wsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob"
+         + "HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1"
+         + "dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P"
+         + "0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygp"
+         + "KissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKD"
+         + "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd"
+         + "3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3"
+         + "ODk6Ozw9Pj8=");
+
+    byte[] expSha2Sig = Base64.decode(
+           "A+k8LRbu5H1MAwuOS48aX/kVbxXUmiVyuUYC4M5gbWfn+kuBYmUDALVXLdJn5IQipi+Ff0DtaSA41Efyo6ODWdwxAHCic7Fb8uRBq0+5wySank8ZtAwYWLqz"
+         + "TbJxqYzqdb7W3lxiSwhNsw8B66LqDDtSM0jHp3fXPF0oTc3Wb6BF4q9j/gD2LAk/jq+UTiRzn5ZMfDQ+IgFO34r5jGEVL+nITT+5g5Ig3E1D3ky2uK2pqV0I"
+         + "RYDRrEPXkgS9mrlimWFFtQplgvnPQmEUkjhpL843Qn4ccQUz7jie6TQaoTrOU/Mxp0bnXlquIuHHTSmwBC2luYtZ6aC2YxKELMVfkyIRI2TNho18LXpwwnv0"
+         + "Wnfolxg1FPxHHG+jSJlpoPTZJ3OyoyuoDk7WwSVOt80yag187Yn6bnkBiRY/qIxfArcZiUMKu+bl2bj7rmK/XZrDlcu2gRGMN0XvuYqnBRMb8/ruCQ7b0n3h"
+         + "69hEFZNJpADusCZQwiGJLGQgXxFi+hT1nanmLeGuzr9jFbyBZPLUL2J9asgBk5ejodVSEYwzk038RqZ4sSxDyZSUUkajJ8yeBbqqehXemu4G90KSssxlT4AT"
+         + "9XUAKqpnqpWynASfE1UDR75FSoyFqCAE8T6fdyjBY4IxDSdNvzuX0I0366C35b163Em1MQDUMY4ZHpJ7GhnOfkGT+vFCNQDAnLTQDbiIDRvivLzJ7Oe84VNZ"
+         + "izvZKgDWFK96pWIWTRjZ+oy3TUIF7cv/nBPxEorgv5CDQFb83hi5bMSnOCf2y8+7sKIbkzQJuQdleJu9nA39Um6t2KMR0dyg1sMuSV7CIk6y0JLucqtiijx6"
+         + "aQE4BeKyE42MlZB9yRohbollp1ZOVYy4056+e8tBwUCoCJBPBVY0t/AvOpOsn5Hud8qCmN5d/IWtY9ymKazXUbyawwDXCb12xmb9Pz0tFRItFKgkd7g5JQAw"
+         + "NKhBVLo+JOWG0SQSTKUE5mQW0vBeh0AZBEagBgg+00YNN3OpxIy7Jmj8/1XxrLrWOvCuk8RKrbtG43jXyza5sNiSuytFpEs4EoLiC0IzgC4McfNF6Vo7fuQo"
+         + "XbT7SjZ4NfMS74VagqmR301yezJmQqcwKH7CK6HL6e7ARr8x63L8lYYKiYMnn6ZzIab3FMnAxSsrxd3cJaWYOJGe976pGUTG72MC0/iIuMi9LMGr95OiltzD"
+         + "E9/R5QMplSgfpTnqbbczB5OXGXBIJi1a6kGuWTXEZxtHsBB97AjfCl5MFd+n+MLwjH15Id9h2VAnVRvA3eHHEY5iAhwBCzSuljOVupB+0yOXYMVBytNCdYJm"
+         + "vhW0bgmV3LYsgvSqz+MVHLxfoF5zpE/CnWvw/sF1MT3TJDVpHQn4xNCllje0Nn2F1W35ZI7TZ45JPyJapohGLbkBymuLJrySwbX5G2dBAHWJ6QoEYA+Ec91y"
+         + "dWC3nrac+s/zDMQAvJuHs+WClVYboPQ12p9N9+yn0MNVZKVO0HEivH/rISq7RIZRqyjbvS5fW44fwBIyM81wXR7IZJdPOme25DvMphlpJobsmwTmt8DeenwH"
+         + "D7B5TevxMraJdURTqNRA15EuTd4foKxJDaYUvgQW728nuIuXtxteaevKkWKA07ga6YBPix+GHKOGFNLJaM+gfBTx8ZD66iLTVJrt1ZqrqmrUpVV64JTn27Ls"
+         + "Kml8vWPYdrSoq8krxQbs3bsSw4RCx2k3i4NgjWJ8dYV+4sjdsCxgBB71FZatbcaB+juvYlPSF67bTCa6zoU/nswYT3j530bp5Oi6b4078lL74Nctbk/QgggH"
+         + "yhcgbWiQNS0+Cy24b5+leuM9y00nz3hJ/s1IMb5k7BTL59Pw2Rwk+716dAc6E6M3W0kaYRs04GYBXyzdoi7a2Z5SRhGITnkFLmYWNudVHnMWQx0mmPq95a71"
+         + "NcordtSmTNWHWEMaTZCRWYczIAlzuZ6c2I8Gqhfq6QzcofWvvcNc54ng6WSibpr2Rq7p+o47yGaaW4JgJtolSTSdgEzeIPuZaVY/lJIgW5olDGdBUET3Fgk7"
+         + "0zX7jaNowBw31Ys77TY8V5VexfUGTsQ83dV1LUA7MRqFpcnQ4u6FC3tI3WiPB4828RPshNncqbvIACFXdmFk5nZyfWnuVlgWahfDvtVWzithkBcHtEmH444p"
+         + "L8O8ysKVgTWyV41/4VM2g5Oamd/oWG8uSqdX+5E8BOKGB1adY3Sz+bWViEtPjlxuC9ZPezvxYtEOkSRaXnMnvaSYr3ydubqyVYnGi7jVQoQcPQ7SgWXI6w6L"
+         + "rZdftZeusbUfplVZBu66xwnHchJs7auiBfVLEVzIIhj1CPBBZwoHDIxGlBgFBh1Ofc6jo6YEChuZ2CiQaCC7ETGJsTfbBPPrg43CPR0Hd+oGCd5OIAc75wmG"
+         + "mBf1N47eRFd0B2fLNUsHuRJQmclV7NPUilYJnIPS2IUdfYCkkCapGeeN+Dqgn6FS0VRGf9KVqAH7w2/tvl5SjtIvEej8po2FdrZviB2u4yw/0Uh9bbF4nxVO"
+         + "mVH0sODFmHgDEJk9RY/rmdm6rplLuOPWb68lay/4IgO5uV3LO4VRbVcGQDgn9OeGRsbJbOTkmyR6Fj58CFzS4Yfyzi+DJnmQH/mrGjZwycUn7wuVRPsZwzBP"
+         + "dKVELVM89nsZcqv2k79eHYQjMsoN6/pegOui35kSBDDEZla86Z1wlmQf1qE3yEzD2tePmGqwEBeeoqoG3xuqkPOuAidxsHWwcR54d5fV43pTQ5P7bjF0ILgY"
+         + "WHAycgHE9RziGyzNaE0o5iXcC3vCqp9SyhAycbIDuJsS4v8FfXevYF7XAt3/H+xFPGDBAstnHBZKXW4P5nhmUpafII57yRNONZtYAu1inVHlv72eb574XOVD"
+         + "cGjcECUz99GjD5Bx+3YskmixZ3uh1/MaNyjqLjplJZMIzcTKfnfYBjAMvgvkDLPr/yl0UE5rMaW/SwcLKfmpIfs1eOz1C+g60GZAIzFFDogTycJayUBeSgi9"
+         + "mgKa17quSGqKiNcYNe15sMdho2GDp0PVLg4RF4xwQo54AuryiTu++I+YArZxQGvPzwDdu42eqj3OaitQ8ZltmVTxzKA8exfqc++aNUMsucXvZxk2q+9907C5"
+         + "1B0W0643KFLUUiQ2A/SyG4okJbaLZ7aqcmPYRHVO+N6Rkza+hIUMV7+WiQnQwJFKWgyb4nqhimivX3U80HBZvJ5H8xKtzzoE4zV80lAbPFvORxT9HGwzyaSv"
+         + "N0sFpK7cLinVAPVVaJe5WA/jgwNUQ1cAr7s7si76/4MrjHU+boqaEWcGVwfaN19JbabhGd0mw7iuvWYlf2Y2Tv6lj/5CAt/0fCnyW7zndePt+BetdzdPJ2AP"
+         + "MKvK7EgHcUAe1C9GjIHeeBnrsxAY6+HnEmPmBw4fZ1eVQpfSHV5tUzTVLy6QfU/IlnnWQfLtkk3szIbBSFUI0Uy5YOYb5llMoPXKD9aOpXMDn4T7NuiomJZe"
+         + "RdBp9ujdn9GSv4e2I5jhxPTzN89ANVgFxpmQKAqjaLEMVNTOQ8uKNn3MMQ/bzxHOHonyg3lEtDbYkLcJD0p+Lkr6gUT52rC7FEphngHUTAFBiVar5E3eW5BF"
+         + "61wLIMvdbZRiumB11Z+aHLuLZTDN28zSLyVuRLLR8j3cXi4oWSVdVgdkDiQsRpZwtT3//uPlkotoZEYSUKlY45Sqao5MMU+z9XW5hZW4ovF5hrRsi/8V077U"
+         + "9nnQzks2oegxwj+FMHyywzrd6QwgwFef/WDiz4McqerY+U2Ve1LaIsvmoJQ9MjuXHoq4213axWmkz7dIznb99psO3zmKnW8U3WMI/huBi9lOVETTD+0kue2z"
+         + "vDQ6z/2vRQdIcpk87dbQ0J8DuZelxQAh+Ogk59wM7X2kvd0LwseWz6RPh8CxDmTWfRykkz4UrCe16fn3QSamvN9b7ZpnNlJG8voCUqHWu9LCDPLe9JLWXKLw"
+         + "Z0vnIrFALTmzP8cRiSGg4bz+9doOUd/AZ54bvUntA4yf6QsUtPI3ffcDM1UBazhINpPcgYWDJ6/jwww40ymQ4SzyjVu2DE7o6DgrNg6mmj+Fan1tUf5gqYVA"
+         + "gCLsvodVVtX7wCG2n6c4NFWPsjorkOGAmfY648yr5u1zOI+dCosMgcnWdQFWePdRMJRLjgCvjnWTMfK08My7OuugV5P0yOlzFHf7xKUOv3c+KCE2XxL9ytSQ"
+         + "nKV2EqifHnWkd/sYezBMJYWoee8c/xZcfuS/qdbdbot2rIVXK3rq0+JNLexugOsei3h8PZkqtgOlOb2hTAQ62s7IM8W2WvZcb3wAVubzv1dEOQg43IJBsXhG"
+         + "o0kRbgM4zYkvBwCFEBXMsPYvczpYrV+DyM9oolEH2dk8NbK0Je2FP1fgqBq7pCKJ7/cmfr3iHWBUgWq0k4x30GkXBxQe4cenBqebVBnPFFWP26v3u2K8w5TR"
+         + "dFFIAFYC2V9I5rqVdn3ZJtMWV178yddKNKZP+URA6jbB0/GMkc5+IIVtm6IQRPMT4hF3GQWBqpjvUyExzaLjNdcIYGpbtEPJhpRqu7pC8IvWF9pDUb4bGozy"
+         + "bbfdpQtOIfpCAaCVa5+IA7hZiud4LEJyLFde+82ILqBXk/bGaBbbBZIAHT3adoTQGnqHB5rYQdkvuzfyjoA9ul+j281rrGB4UH5Wjte4njZDaEFBOI6sqLZJ"
+         + "uhBNP6JA9O3EiUzXRNYjmIY6ESE/MkCWFuonwhIZPjNL49IhHBbPAs7O94LSnIAr+zDxMpEOVIy+a5QKHQNoeGruAlXlfCMtm4PIDwUvMMxS+E6taYrnzhp6"
+         + "UTUAVLxwhg623vtW6M4JINF/ij5wIQhqkJTSsPKR5C6SS9tEFnHy7ozHtjGHCCkvvwbU9/Jhbj+CKFXENmKUo5LtqTSIrjcg6EQ6d+7UCxE9byikBurNsN29"
+         + "rBW+d/LCKvIrXTFXwz+XmKiMfw5iLosV2Dq/CdzHALzcPL4gqNShTfg8eWKfiY107/1u0qXIM8LkmiqdW/G+bpxVqzkaNcC80G3f+zKVQmuz2+mE+yUOeOOH"
+         + "5bHYUnqiyAvl1SAkawh/QFV6QMT/kq8BAXp0rfcv46i/rXDmk7EtU0OzUmNfJMTpelF4KO613+1FTdwYu2HejlVdS3DlG/mSCrAyaTtkZDToF+g4M8oHnqPA"
+         + "9UjzsY3DCiJAxyY8usOIUdCgyXY4YaNFhQt9XSCwWw3VaMfnBZqdiLL+uVWp+S0c44G0nm00itRaCrL0rK0on31RxkwE9r1GX6luALYpQ5GSaSiafiyIb8a/"
+         + "5DXBWXEnfzY/fcNN7T4gmysPFW9Xz8s/t3LqTY4AqXL7B1xn8Y169TjFFMJAv50ZYicje/n/a/tGI058J+pRrvsZZU4QG9qvOmLSbo0J7Lemh07WGKO8PdMC"
+         + "vgLdnMGV7EnBTtMYHoSjLK6N2Ms/8k/Ka24xcWSuW2YYODvtoQonM0YHsJFjrz67fY/h271GXbGQIYAmJsDI0mDJQj1I823jMgb+XM/ckokHJ6qUeyIOwjuW"
+         + "5YHg0FvbuXKLvAz97k5pWJXsalfQ4XbdVbbOKw/oVkAfSovrgxeE6kJ8EwSwr+TuicmBodUjw29n7qp0ZgbjZw50B997WcHTPRIsACmIjFTMDz5W4HQjwDIg"
+         + "Rl28sR89iBEZ5hWT0+hSMb72tnEy+QO6CH1i4EFlUNFZYsZYO/gX4d7ly4vMiX8fN9sqHAGaoR00nKrwbclcqtrMU4t5JOPpw/nBf83Aj87zPzJD+arO6mV8"
+         + "k3AExon0sxsMQrDgz6jNlQq7Ja9neJ37jvThF4pPdrugSFQdLXOwKAPH1BDnOJdKbQxi39E7uyauOocR4WjbooO/S9oZ+adLnStGkDN6dXzvCJqTH5L7msxj"
+         + "BTSKSKzvfmtO/SkyFjG+JyI7lELrw8ZHFGrCVDTnmB9ciiBmDy2XsOkYcrbYCxF3cLbb+UbryYXN0ECg9Z9h2OGfBKgo+MtGS9wR4vRguVikiLtTxEGgLFrw"
+         + "l6fmhDEhLwfuwf3HWf1En+0afHfT8ue7nBfaGfZ4f9f1t0ps0q3KnYoiSD69lNk6fTkMn3OXOpjlDwQciYUV+CXZTg1kRyo53JKnA+mdWO3K7G0Tp9Yw6OZI"
+         + "ASbh/xGCI0JKEIIVXvhCRqUqH1MP7iR2hyX6BTK9/WLt0p+mKmKldSHPciGGzIX/GEsh142HdiNDwbaryaDCtiQDRjzs7sv90JlC2lfAn3Lr4m8YBX2JKwl+"
+         + "jh7C8xjaJbAjKeGBLco3ulY0tPsLl/DsFQTOZi4d9Ssk9hNgAvc8P8VdUSd+4xPc7nPlW0UiWYqW7m6zw2kFOgpq6W6o2eOkBtcmtfMPSgGir85DkDJs1crt"
+         + "BEWRRHY1JXVsRf9Dbtf665oY2mGQdHyF4BT5B0LbUBb0cab+mr8FKYwPyES/ICH5EGANtlYKQQMIaGqaxODsfHHVRukFpoPhTUuASqCiAgfQiZIdv6Z2CPZb"
+         + "1JaOhK5dWcH20+tGPbxk4yfycVhCnTIUSaMFfEojFZfgXqgGNrUm+ecmCnW2xhYyzmgOsJUQC51uzSHbd0u+4pRXEvIZCHXq1Sa+6b/fkviXCBX9+pZKFLhf"
+         + "0Xw2Xss9CiAP9+PK71H0Cnhk658zUsIQ1y/+JVwSZrzMMPUxCtrVIwexufh3H9w4mTjGDbGgNPBqIxxgm6JJxAKZtNnQ0PioxAL+/ejSB8GffYp+h+ufvuAC"
+         + "WDIK7FAMFEOIF1fTpaOzEq+TnCRXYVEZJ+pn2cohAUtj/12e4C/5qguGZkXL2IDpL3Wj4HpOEKLHVPpOzw3lDmQFOGt1dCT0/aeM+z5Fu/yhUyt8b847LtSP"
+         + "cgtb78jqbjnlDguaArd+XXTjeUp95ccZGDlZb0zVeDSl0feHedPbEqRkzkQiFgG0bD4FsVGm9EMQ8s632rzlgh52JhP7915la9Rs/gQ5P5PFJpY/G+MdLq4w"
+         + "7gY+b5jQKQpDQgr2XViewy9cIeDBRplgkil/mzpjbZ7noEnTSjBRANfmcUiwHNfl8+SJMxg2EZ7HZg4d7NFOUzQEUKphPerwVm3OdXysxQwxOPRKO6AvuAox"
+         + "07gt4fqBuTe6R/DU7D3XiUTUNbC0l3GeBy/LhG5WklQTNcd7pbVc0y8ZSaaH+jqt5m5OBI6I39wMTYL2vRDF3/Z+B19SmC36j5lKQ9Ft57pw//VRjzWotJ0a"
+         + "yNfyEzo9a5GUOs9Y/NBgmxF1fu9jMGxuw42wbnJyAeMiP5cJNV1M0OK19rTx7FNKn4+65gsK6ys7e4bwfuTflH0bYGv2yxRP8usMsxZQoacKkj3mi/4quKZ/"
+         + "6GHy9mtRMWSeYivillW2ohP2JwpmO77VDoM9wc4w7mloUHndCfyrNtcARAmuNJz+mQSuM0h81VYqpKqDaOvTukULyYOiwOx7BIQ1b35i1kuhDlDfLOvW/f/L"
+         + "5xwkvsGQf31+MZtJl68X86ikrlRM6JdxuNPb2EbawKjO09O7WFRMmx5DkOlOmu0PGj8MdQNa8NJD0pZd9eHi/xxfunYqldYTXUvjcVZdGmlphkmSBKNeQ2iJ"
+         + "kv8edraBcXDdCvnmqC4BoxEOFqLlsEWc3ot5dnZV0fkVDmUeGGq7iVsJDW2239WFIWbWd0cqe+fIEcyGztAe6ZzbosIZZ1YyCrrJ08cpI66dOiDN0lpIRi0R"
+         + "LCUT8t49lIE2vn5UJKL5tmkbP1oKATVR6AKYhbAE4BJ9Mg8WPqu7ON0TnrRM62GsO8npOzHmA8dphgnVq9V3UMEFcUbQbJ7G+2lEb1acnOu+7kxf33LbfNQC"
+         + "u37ZdOEEoiLJ9u+SaglThhR2KMOChSDUscbxGanlJ5l6aMWPGlqHVkHAhhT6hAH8osaoXaDMqeBHWhHzNHKGDTk9iUA5B4DKSzsi0+OyBv7bKjzBNzHoFYfp"
+         + "rbuUXScuUid2dKJncaCuNMLKA/OYUTmtwHRqPbI3XAirOOhm1+VWtlm8D1ppxSNFdsdFKT3gO8kcu3UOiglpk3/6AwMi68qDD8+2ZqTxY/DsIvC92jHo+r1B"
+         + "R/6gNU0zywmoYa2yroyI6bvo1BFSiKPQDMQVAZNKtupEhKwL5bswmV8+B0cEFlSe7+8uunBu7VYoWVineBaanD0P72FW1QVChc2iwsH5Pm1VtNM8aYTtqJ/3"
+         + "gctBH0AAKE87IbImQ8XreMuUuWzO5nHpp3UTynJL55x6aeHf/NO5j47Q5JvnoFdx8uVOTYNbvWEBQ2Do33o6B9kcH+Z59Kfg33J1KA/uSHkwQMDiCCAqVgqk"
+         + "q9oO4wy0QXmI10HfNW6VKECobJ187MNxmUjG2irOwhOmZZvSbGyOCFGaYUbP+FRjzZkmuLdMkoV6IKy7Hv9WroOxhXJaOSu24F9+js7pMXr+xcN1pSAfALAn"
+         + "0Y6qC1NqANnRw+b14L3fWy15gaQSGI1Q71GZzw2GndM3/jfq0W26AQLpFj3KpwbkdcO5q9dKn34TWnJA6kwWJT0AlT9IV63Cnci//uKuMel0TecQohZgqWow"
+         + "PT2ur9UP50fgxRiv9/UsHzVUvNyjNuqF9lSbXxcemFyXgoGu77Zgp1WOc+m9MTsGH7+qp5eva/KbwpxkWmOoRUi3jyvowN3UWLvRkpj7tE/39tmoZhvT7mm7"
+         + "f8jO8S6VWZ954+1q639Q4GMNDYr1KRT4qFqYqSegu69D9zXFNKBqnDEIU7894RVMLD465wSKKx/LgTdbtgafNWfT2alAgKDiFnSUqahdqdJQ+X+0YzOo+F43"
+         + "PkyKt/5OFrjLegPGSOj7QDm23JoZ/1468PyTdfR5TjT772YBKK/ZcgI7Za5/EBEnGXYhjEGKSvl05R1vEzCt/2+X/g5ff0csFOUQWg9xrofMr+GsvXpNt1Fi"
+         + "7fpc1/5NYEoNLogpc5dmTGjRjWca3M2Ec9tE87S24i4Z+AVZ38oijx1Sfl4Fec9gmhhf9zSWQxr7uJ4r2lFf/c56fuEiGV2iJgebO1wl/MC/oSP9ezlHfp6L"
+         + "/zQRxBKzJRHEr+vQXBVpjKpVXb56m2CdF1DPDvsYADWUWMTkwWirCNkRUdYqoGjtGQrG8kv9r93/Pp3aJqqpeZoKv9MuOrdgCHkp9kfqjkkrGUgyPCVu0k2C"
+         + "zzC1eHDj6AxIQqhMNyn8IoxadTwQsneXTbx2CP7FBX9ELAt0IKHX4w5sXg1xtJqOlsP8/tgn8RQvh2DUKezVg9SEELgUR9EoCXCBjTdkqyvncbpluJJO2HjK"
+         + "v0zfMgbDlJHNi25YwnBh0DuevutcIIsdRaixvzcVHm5YDhrswrqd6/T8VaTS/02lW5V8PtjwXZErcKMwnmLQIDCL3MNHBeDnwYeRzgNKeoAhEmP6VTL/cWIJ"
+         + "hsUUDcCKvUwS52WrNMJFuSprh8Sys3TvQ14hIoYkm6etPIVVrc0nQzvqmLFMmYsN5ZLgFYP7O+Qjy6W8XEM8jDns+Sgl15r5izIG/OWfmdV2ozOMi/qoK32d"
+         + "gZOHBHLWItkQXVAyN2/3Cqd9OoafmMMIkAihSwInLzBDoDsfil0zoNBMs7cFkV3dmNz2qAusFFCSmBZhl+e9/oTf9I7mukhEkkJReDX3Xt9EADUnLxueVtuP"
+         + "i4c6XCEfevuOpluxpTS432EGFP32cPMYTr8LuSfelKlNlZYgqNnOGDd757aRCmoSLM5qTHZaGn4OJIHOYir/ELjOSzA15rOShF/C/TP7EVr5ZrFM8xi0nuxl"
+         + "2/l8jFT/jAI//tja4/vrsQzPYeEUUbW0LLbliHM8Du9+xgwpASN2jnp7WFEQJUzhuzhe1GfOtspA+OeMvWyDIwU6uJcCV4OFPRbMsl3WGKynAQ4ciRWl5VUI"
+         + "RDPnidHNPR/Z7gsLbLtjqZYsQaN4bv8ryoZIPwYD7guoBmuhu3x5Kmyasny1bPTR7YCVraTN5GDwPowtl1nfxoVzg+J57DmvMopzM6OqIBqWuP2hYRS/0mfP"
+         + "8FyEUCSrgKw9ggyqLoITb5PkvJu0BZ/U4+zW/4Hte05tS4K4I2j/lNuFbOJ6ODcrQKwzVz13qhIBSkVdg7pmT59B6gUOUHLX68g1VsjPfry3x+etCo6MmE5l"
+         + "LJg6AzNnTAjxRnAuOlHk0GSAKTGrfLkK7QqmOzAtCpqhyYt+XI2PEMjzNKVUf7yLGvRVFzHoItkBk5rZ4sNIvsR88epKF+KLYeyLB8Rhov4J7Cl5bEkr1H8+"
+         + "HGreZQioRj0LbP9PA3DSoOb02zXMjS8Zd5ReM8qQcnpkbl0O/2WfSR1Xwm7J3WEBlf+ihphZ88yRCKEumgiOHgBi2ikBhiVLw4rETcgIghwQySmLgtP9pJmB"
+         + "NBoxJXuZ5wy6hJjs9u53qRg7KahGXayI6c5RuqeQOnOwUNToKnHg1LYD+yqhUDEoafJ0R4g86tSGgs7RKQ6/hwINwa5SHu8Q9HyKKdss5EBzy+v3Ban7xXpC"
+         + "GENGdWUQ5hVKIhp+oo05x/XK4mdMWsZHPXHsChOFwsFGR2QpQ/i45ZGxBNfGtR/cBMIiqQJygcqy3HqSNk5Scc5PyrMAjRTM4Ety7gk0LjpuhzkDbjbv7vZd"
+         + "y+kkFjGENku4uG2vlIPV0ZEQMlqrit935kG7unyqpBkhaXhXOowf76kerxU29ovbWgwqTZay+uZjVaT75syhLpfBEpRfoa8nfT0V5nL0os9rSP7XjoNkZVKQ"
+         + "wMaE2wnrMo3n85IafCf0MWVxSiD0bcnrKfEeyNKy1AGULA36yknCFXqypUk+YBWNvpR+/3kUrC3AxHSo0E3QAJA6Qk8q/+/h6neROYS2zzrraYiTidBlykuh"
+         + "+/E8URW6o1UszKAZIPkXWQa/kwZaa4+HjZNtguyJBOZGqp5s7i0n6APaHsSi7eihUOiJO2bNJskhstwfCrCxhPqLe00z5hUP1PvZzDPBneK8w+WxYZt7rIG/"
+         + "NibV5KMT4fZLEWBYCi64l70e7uWQgMCrrHhrcig/sBnQ5E63G5vr21jP/X5KfuvcSuwQR50u91ulsrZdhJsFbeM0zU154jZ2GBRp5DPkqTsDJq1VCxiFhJfB"
+         + "DJZkjLV/e0YLORG66Z6/O95M3FZFdj3yZR7uuE2A9BwSkgufMLrKtcl9qt1t0j47pg19yTMK1m2YQqxrN5MyZfufZdUjd40SVp2Jk88NrB9B3WAW3MnqPrG/"
+         + "T6Aw1iRda95zjRLMjYHj9N+qtmjeaqN3+qjwxDHHMb05WN0ZPdiBtS12HpLRbR4bQT2/knfgWUw8kt7kJvTjKIDgmtfsgvwrm+Q7L8WjNsBvMrkzFyUTJ4QM"
+         + "mZ5bhK6btZ1POM6a13vjMn2AX8hxi/Fq0WGQN3MJZ7eXAJkBxdyujgAM1j9C2ImCL3WhVg+T06lBQLlMqfEAnyCYUJ036yLb8EYTAzX++ie+aauhJj7zvauG"
+         + "KT4DN4L7SNqPxJ2pYEDEtSUmT1Qu8JDcxvdyJf9hI/D23fc1/ozPSnvXf14bGCbkcth8iFtCSddOJPDTURK7Nj9GRRuCfvLCSEwzWEFb3rrBYlCp8g/Z7mGm"
+         + "2KsCpVUl6U4+8ctTVytJpLBNpkMh4At31tIEMMmvPnrNWvzsm3dtJ5JeQfqOrncOWx1yYC5hCTwTayJurFRJ9LXMvz00+IXMo+3xq5CCFrjArIwhg5EKXl2F"
+         + "HeQesLS3+HDNU7ot5zbyeTbTTWEKw0qLAH3539fcjOVLnnStRURbS26okfmomuErx2HyOEoLL8rQAYXF2O9ESwMaPoafaV0ihDuyu1LNF2AYwvunxhrHjnW2"
+         + "SxIl2H4lUBo4wq4yudQf94Py/bORpmxsb6csh2rdc3SWciWd4ufIFv4geyO1pL1B81suV39ys2l/opUXvdINOTjUuXhqDlSBEQOUXEGjA7oj0ejmXjI3Hcxz"
+         + "epP0MBSheZxzfJF8y4GhSSZZ8HHg8V8AlyR1GfQ+ZRwbSXnVO0oUNkXcsZtPJHKt4+/6Tkfg2cDeKt0ygBbTLOolG0hM9SXIwjNqevc5XJBkENSZGETHuW5C"
+         + "fF89E+R4SAQCi10Xl/BEp3HB/aJTzHZ4jJ6jy1kym1JQDsPYQY0pJfFyot9Az6J3CzZ7O0LQaw3zY3k9QJNzHT+gKXCt8kNge+iXkq0bb2BnIVj3T4bkOrIE"
+         + "RTb9kwZ8Pbxk4yfycVhCnTIUSaMFfEojFZfgXqgGNrUm+ecmCnWlQ0Ugk6pe+QbC9xQAeLYkDf5bc7O4k10fYO01BBtssI5uoXDCpQ+A1SbQKrNJvz+NBwGQ"
+         + "Nwr2EHL8P2rYeg+gUM+WJDBYhZR2TYj474eBgX3skGE1p0fOJsIyuN+OoLkQ0HSkThkIkYqxyH+sNUwIKyp605QN7DjQ7oNnuhcbbmtIO47FqfeBiyi6e2EE"
+         + "eGxPOxGsze+DvdimX4WHobVRa90KHcdcBVthhB3BMi6gmeXX1y2/F8I3HDAJqFhIJkmGzHcephUUeKTFfFKJXtv14QQfUXnUxmsDln1PEsBGXJn1zLtUYF5L"
+         + "QfIQm82qpcOZqOQAUYApw7Gtpe/s1rZpDHUxYeHU4zeps8gqnPvRwbSovJ8dulnhDrduvZ5NBHu9sFD8UW7Lc2A6+nU3GA5Z1/r7k2DGXXl20v7R2iPJxdhT"
+         + "feXKEom85RY7L1LNgOkJ/v6gWcQYh/7NYfP8P1ixWBeyyEQmRi3n2GhteVTRD3T6bsBjtE2kgjsLDFVZrxlfndk6V0oi/gD+CeRNxvFnyx5q0qKo47uHct/d"
+         + "reahGhqWcrg8b3YvaTEmk672YvLQu8Uo0DARNTNxmgVYU/LNuER+HR8ImZVFuCiY39eyWeD+qDzmViMlYnYnSiW+GI0l3HtlNyUXA3Cni8/W5P6jMb6jBTWn"
+         + "Uk9DhswD0bXm/tJgZAQE3ZcAMQAPadvji0x0BqdzOMygDKI6pvRvt03Lx4nI93zPh1WVv+uRE7LnYm1vPVdZ4wHv6qk0s6KaaIFXPqTkF/xnmWgQUjGTUEbN"
+         + "benXnSkiJ+uARI1fq/cyPMHwBX2jKdIAwbUYp6BCUDxIEfEA/+Jo2U469Z2F7YOd9MzVey3TZ8JBYGXLVGfofjDZIk/XuQrcinoK/CSUuOw+sgB0RerENwPT"
+         + "5Dy9zQS+gf+T6UI/zsBYpRyqYdOBvJ3U8xPov3Xhef/kcf0aFQqrHMPuLHBWRR0Hd6iCbdPhXOM96E3jsl9Yq4SsAXR3duvF9n/86TW66M7fQOkd3rrY+Bzr"
+         + "vELMwkouZApLD8mg0Osudg9SnKYUOwPHOuRt+jdVI8f6B/eZfJY/RCLGJLl8Zoz/XYEm393rKxlYOWw0sEWmiUDkNJM3ZGhARGr0Af+/3mzfdStZiLBWeUuw"
+         + "AFI35Towa+rG/aWnchw8WXzePTZMcPgMJ0qQpMZwbCUh2ffCLhDf3wNApZ2ixAfSYYl7H4fAj7cDbkhj6B0SseLiLCEuKdJRYNb41UqkCC9gRLK31yvF9ldL"
+         + "sKtMlC+PYBaQB+7GiZ6IpOrYRX9QB76kE2asuftQE1X2HJcKXpL2xPmN/MAnJMQSQWuRe/IousaL9aX4J1mA7TJhzHFLgi0p5dwoxj61YEEMsatliFTalcdg"
+         + "WVFkvseN2LBtHwtAEy9rQJA77m+KrpUoWYE8BV6gl61HanXSG+z0uCQCrXD0iwawtpqiWHgCn8C77Pe/ZbzTdten5kd/QsfFOvaDzUajLc0zwc2pfhBLQYUK"
+         + "EtmCmuK7ta0uuBUvuMiIXXIr22uAtTNY6n3iIgPhp9J3gs5RKUQmPU6aYFPJeHOx22Al7gAK7dn1b3/CeNUJXH3hjMqDjNh7V4DOKqlVN3/6gcJmXRnJSuj+"
+         + "9aCgTYQLpucPZBLC/sUvNZ4Qq7VIYfkxOOjUpNWd47KDM52LwkLItHx58KXBXfwVEt2lzKPTc37cr/g/KGdoI0F73eFndEp9poDVPZNs0JOhvU4rQRlWnDpK"
+         + "P4dnubra9CZlrT8MssJs2hsPQW4LpQSRQhG19ITXUYniLfB8lKaUlAVx89AIByrlTzAWpKs5ZL5yjgU4RmYwaUijzzUvKB4t7Anx5Vt/qhSB4fK7jizB7h7D"
+         + "/RHhSUE4qpn8x/Jbpn+VKEsBCBzLm2MuzCuusUKM13vfPa9B9EyEeh8v4JEZCaCzWXNzGA35bKk9PWdR7E+JN/3iE6iHAydAPFLO+45zcHo9hHCjKPpgJLSL"
+         + "wwfyTaAVPQv+T3XkiQfE+3WXM63QM1bkeCX47hSwF/ET4vHeLWljCmI3Y6JZm4mT6Kyj3SYk1N0Rud4L2zhiY4GXctuSD238Pnzrm+H1iHi5pM9InO3jXXk9"
+         + "mXy815Igk8Vd7bJzsuVoWKglTR7eHJ2qvjgmurqXJTWkDHCC3gMW51pL+PyNqsLpFLFgHqMVv2l2ICEwSzPCG2yuwBSgEbOoVt7KysyVnFrwsrhtCsDdOoQw"
+         + "bmgh4n7rJxbF/OYjf802N8b/vBhdc+tUhOK6PBucH3R5QKvaXxuVK462VizwIrbSHoqq4bPQqmP9GyoHTVzVn5d/jO3s5IsMHn3UyaDO6mLQwN7OsLJco8g7"
+         + "oqYZQokPsu9v2mHOsJSXOQsrC7Z8BXk0ckP/Lnf7rMoGBFafKmfLNTq+kEDNGobpy5AZyWDRuXfXNr1DvLnLS8ri9+eR0QONSne8Cgdn0z9Bda5LHrZ5exKe"
+         + "imBF6AC6v+6rC0BKg6vq1eOK6EX+hHKaACtKSVYttIAfaepCIIhZpnyG/4dyNc7sRm9dx5jc68/nM3imghpW/WgMols0h9dI76eKis9NdGDqIXM1qS/XKwyl"
+         + "UDEyR8iRgtGwNPJjXmHnmiaPxcxonXV5xLwBgIGPngion7B507dt0/w4e4XKRCQScPYnDUYjU456pdfEqsQHPuHstBjKBpcCp3jfDHcG2Ol8tuqidMIJ5ARv"
+         + "2jBj7D3XYGEDYEz+Uf/l6HVgpvbFCxuY6GysWStEbxTV7ExpGqKrON38JYcpgrIwcOf+kGcTSFDhjUWEngByiJhUJ82xu01YtKzLXRgqswXFQVRKg+n/YMaM"
+         + "ywMkdksXn+7XRF4ieQ4YWXz75QV07aYbhEEJ3bvfHomJRPsCZP3t1OManjQj+SDhWO05TvglUNed2ft9DK+WYDoiRw+PFz0JIQxMwNTXTBjumhEI62fINuDY"
+         + "c1wrj/cP7GVmZJjGUEREN+MijVkOFh2yaCSge2oTyNBNa00etlEdKpXpwMP9NiUFoRknrHEY3qgbl8Ugcr3GsrBlVQUw/2bLCyLoVf9Ay65EUDpBh7l06grl"
+         + "kWhzY4OXQmwdki4oOP64R6VUCR4POyH8jy8y1jTwPDo8yThdZBwgS+jKD0dbmgZi2TATim8QXdLf2EuVfIKDOsYpusFtK09TszkXGRQr0Qcih0FlOZfotLJR"
+         + "fZM0Yi3Llw0Nxqjmd43O1fDRSbOKuYKRWtKdbHEPaxjrjUQOhh4ocv0bKgdNXNWfl3+M7ezkiwwefdTJoM7qYtDA3s6wslyjGh95gLTEF4QO/EDJO4A7QGiJ"
+         + "qXEfYj4cO73boBdqnbfmmVTNxVIl6MNHAs+ylGBxpPSQg8kVzGpWbgdZRZo+d5ebmtnzZYB53yeq1cQH3jIu05E447IQsDc2UPEnX/7G4uHLnJSJFq1Ys4BW"
+         + "AVcTcsB60hrcVj0wtmy/CRyDA2f35RypsJa14KUOFVmEMhJJGK5VGBa8fpYMWR1W2JBZEdPW7dnRLa0a5rxd1XWT+ryrFrhMtM/6wjoAm3SlNE4Z/iXVcWj9"
+         + "DwngIljt7ZOtpEx6WyAddNMAu/h4S6+k1vatQ8Xj39qcZUIgQV6HW2cy8jzfi81CTKxm9Ew3qVrv9XVUVAFzXNvvjJsJ6rG1AyTh0nSGtQgNvGBEemAdrHqf"
+         + "5XpWsUpdjG3xJS6PwZikESkufSkw5SMKMxUsUAZxmqFkvxZRRI2FSz5B0AjPHeHX9iEzl6x2x0/NCYL2eFEQsPDgJx07940lBx7ureFHYyacxG02YhWiOBIY"
+         + "plqlUtu6i1WqMV7sAf09r1O2RtdQ4rBpAqrLQnHjN3DTU2h8evOEM4ijTNzOyopg5yP+O/lgb7iklGuuGJihOVPhlS72grIiSQYT08DvoNQ/YhjzjBXc/xqP"
+         + "nHPBb+M8Lb/fJnjXhi9Be/1uXaiQxeV84VVmDQa68ppdnFV+x8K9OrGdtsr2AFMlen1miMU/nNRMKgUJk0lmJPawCDeky0IN2YHNy7ns3Mson46OQ50oDv6M"
+         + "JBbe7a4r5JubC+EZ/hzXiHUuZkInSXZD9roE8U7WYSnT8FPt5TbV4RWdiKghbPEQseI/r9xnXe+usqt9l/tc5xH8SJ6vEOK5kzVk6ZJYpw6WxsTYjfvOyjnd"
+         + "d3I/4aYXLbSTmXa7UmZlrqv69it0vHfuf82ORyM26JDq5rDho83oSu5ud3L7iFG6zIpAe9ITvfNknRr0X0obo1oq4gdrlFwn+MnM/UTBCTQsxV7zasO7mhmU"
+         + "QcWcmA99/UUfyoRFigNkOBfCa1EQupAeYw28J5NCXONR+Lue7ZDt899OgYxNK3HCUW2F/p4wYw/fCoXKPgmRd/tmLPgl6nmDdhlSwiuK/+a4zQJTWL++EHno"
+         + "vmTZc81f7a5qtazZPLKKJuH5fzz7hl7yX2n3SvKXyzhIPnKC2OTJ1RIdR89VMGuPUHxj34/4DeDxyy1aVVHfpZ7uO7RmU/Q8NPaVrU9NtS3aH70YT5aiMZP7"
+         + "OT8rTBjolVtmLWTrXZT0p70GGCSagMuVbwhuBaPS3dASbP+wMnomX5DtX6PVmnYCV1qlkI0ImY0VZeVOC86rYzEvWkgwXlLK4YImaKt/dVERy2mbJqK7IAq3"
+         + "9FKQSQe+7w/f0CKYwa1JaADzW+/N0Dx5iMJ69P3vGAW2Ea/bBKj5mDWc6XtAqgtzAhSLtwRsWkdB7pZq2US3odeQtxvYbZ31UMe4nDeb5a6xD4KRj0Z1isO5"
+         + "sSdRHqdB2QxC2UVansn8wm9j7IIfFy4XLwmgnglQHTij5sstJzzW73Fj9bXb8kw98Em364+YfAJugvBDolhgCbTKYJKHlIM6qj4rC0ILZ9ObQFMZB2EJ6QCg"
+         + "sUPyVX0FGWCASC7z+sacXJRN0VbQlIwNCxXOkVBXy84/OkckL/IA2PgOEaBaftnOq0gbJCrOI3U8D5jZoNnm13050zYByo78Mg+pniY8rk9ft8Ctb8yT3lEB"
+         + "Azm6vYj4+/N42exTIu+ZbLEyZhTxjlBiXmu4ZNm6phJW/LNaDeeP0Fr9/dw6D2iZaOwup+6Xh8JnZwkc0F5gT303Qd1gFtzJ6j6xv0+gMNYkXWvec40SzI2B"
+         + "4/TfqrZo3mqjd/qo8MQxxzG9OVjdGT3YgbUtdh6S0W0eG0E9v5J34NntB3e9erjvdxrEnftgPmdYOYHGLwXvrV7gu6Im42kBLh7M6y3ibqHEGZWrNJi2fEDM"
+         + "KPDGLFHDn4GKDNLkwJaVlDH90DPQAA0vNiu+VaFkjEU3+U1DoSOSayhGaXPVOaKJJqw0QTEpNA6OH7CgYGfDTHAXXPpEMlD795iXdNTGESo7/xxd1ktsSqee"
+         + "Lj36QHOjcR1ylh48t43vbdgNmf4Q7e8kR3/p88RkXDeppPbHcgMzS6ds2vhy7HmUOSBHpKzXpxfzZbCs/OWX3sND3PmBX2Cv2uYSOrmLlVnyjbXI4A0WiFPg"
+         + "WiasYyfIkfs74My72OdoP0hz+qmvVIxaMZymDX3JMwrWbZhCrGs3kzJl+59l1SN3jRJWnYmTzw2sH0HdYBbcyeo+sb9PoDDWJF1r3nONEsyNgeP036q2aN5q"
+         + "o3f6qPDEMccxvTlY3Rk92IG1LXYektFtHhtBPb+Sd+A+f2wn6mRZ2OBZKr/zu7QDRTuZ981fF13p8s8PQGQ/dXTk3bdyx7eWp78xSsiqNQ5Zr7UgZ3fmdhUL"
+         + "W2hQnpCapJjsCTK5YnVKrUNYZ+GMbFrnmcXemlEx7bSiGCnLvE5sOf3FFC9687Sk3Vgqd41Il3hKjUAwWbHdy5zflzqc5BaVa4d3jQsekf4aa0vVJodZhDGL"
+         + "UP58TpCuwMG4fz1MF375qQqVE8rfKyE62qOwHPEg0rTtJtHY7xEeiDuNh6KvjriCUyvXhWaC21oKx2jHEttZ95uhYOt5zyVv809a2c7gbuWXwqgPDC8bwH58"
+         + "xDIKmPpm/ut+m0Rko8bpIsS3Qczo3I7s6NnEbBPLbSHNZrzJ92tfuzGetVYH+J1euDMnLUW2LOlLA9+6CkFL/eiZR4Dm0eiOwsr0lmKjEcbV6po7ZNmXvoa4"
+         + "JrS+S2mUxMCc4bFVbZSwFE4X3ThH2XKDUIOMoK+TaW1TZLuZ9W1H3G5mycdpuH4qf9+VoZ8q26rhLvvt2DJvc4ZMZlPO5oqncWzLMHuRmA0kH63KgtYNhpUN"
+         + "be1ie1KjpFnp6n5/b5PUss4r26qSJVp/TiEZKGgI6/Xfz5NqBhKroBp6iOu2R3iide7FKT+cA89Yd3LebNBRdzyGu4R5LS5ivvLX3Zyrn52kaTk3uuFdsEvr"
+         + "4CoB7aU8nxnOgaXEc8jJbYlr4PDrMTQP2gpaWDkdI/FiN8x5KghjxX/hdWIh9XloDY0H8ovx3LlYD2Krk5dFNLqwRh5RbHJ4goWzOCqn4Kba/K6PqH986cs4"
+         + "mHak18ErpRdHnnUeqijRC/bfg7H1ZFGJROxpi7aHFee48VdFTWAmu96M/i/s9d+QWnm5mBbjnkyLvP+ed3mBJxOQXSEIwn0YaapUk5GF0RX+eYgMEynWHa4L"
+         + "S+e+cNX2d/f7nhP+FVTm68xnJcumYqB6Yzz24qCdUDA1xOznfHKzIILv6uGDTzJeCUyNGchQ3wRxgLYoa/nLDGkUGjWCkv0SlD86HAUkGh292/gy7u48D/7h"
+         + "NP/HEFP0OmtapDO8b2TrRRSvCE7ujTCOOZUuLJ/Z6SCFVauRHe63km2OYHat7u17UzAP6Q+IJCIaTpPXVVjCSJ/Nqs4bbQjasY9d5Mxhl69iVIU4KutD039m"
+         + "MKkxwV4J7+FEjyv+xv3TiE+mPoBeYQLFh1n4xOOjlMmicFueh+odZ4IQPd4BlJsZ75NnF+pYwwDiKSPek3w3eCMLibRI2fQsgRwPgjqkVKAMcoz40W18b2Sh"
+         + "STeM9/QNu+Yf7/xhrh25fnd/0qumiORS4bU+BpCUvmy63xzLBfm72vNygWqdw05QN8Bx3MW6HU13yXxi+iwpLvXo1Egghm3o0S2eYaHUzfXPvbcv+56uQ1Fg"
+         + "33+kcjpXdkF0a5LdF9kzeAmc0U9hPIaMV9CtHHfLPhrbr8NaeoOsiotwZba8jBBku4Bdn4ocU7uJyten9X1iriNYMTsCXRx7zqv0rXH52As2jGC/ATIYBx+S"
+         + "KDH5btC75LHZKs+7dtL2lJoZVpZDB4SPnr3SXndIVd5vEvxiwphISxeRjcFPTRYfpPlm0eTntm1TO9Q+KI59FIpSD3VE2so5VuYLS20V1Y4nHTlmQd5Fph0E"
+         + "vXakzYWhGity+eYrhlQz7woSWdXaa15SX0gUxgFiIu6veajEb45+u0h0M6aY/+13M/s+dhpSXUixW8WB5AGlVJJEJUVRyRynJsmUpjVNvY6y+YjxXXJVHKBb"
+         + "wY4fMvBewyd3wbr4B6TAk8VUMSVXkUGc0mUkk+SI6turrlTI/snoW6e+wK607v0jmqSCM5WzrvVDx+yKf9U26vikncL5oHOLYwdI2RpWnsqgrdStmkQw5AgW"
+         + "8vxnRGjoPVayvnH+oY7MfXMH+Tfyt8TFkXj0wWU2ewXjtJVRdF9YvKK/fGj1gEU8oJUck6SbP2W49NAtzxxWgSyLj0kGKRt51aqvwasZpbZ1G4nqZnZIioNp"
+         + "w6vMfBbPyxgfhfOoswwfWmFWmRgu+IlcGwdBvGqNN4dhoLEApARkP/aR4kBWmZc0Umv23lXDxcyWpIGSeTsCH0OnRqCQj9lh4foWu0zrzm5eD/EqvOqwvISX"
+         + "+jh6CP9v6tyG7h1177s0ixE5rP1ujGzEugsO/Ged2IXP7oEUItSvtidCydvADXuUbcRd1E+nXP5AnrQUO/lURNsSIjocevm7uXTal8tT2Axj065JSZLPbC6d"
+         + "JmFgDll/ipdvEkp/ei9Vf5Mbozo/OwydYYAO+dBdsrnY5O+pgwT71RY6/lRcF/LUjQ+f7VHF9ZvYNHW5v+/JVFRG3Bb+PTOmqATaQ927303QIXvU9g6cHUHY"
+         + "rTy4Jyouzm+eV4iU/mZOkiEKowf6DN6cJWcSgV2wP3sXcF++pNtdDhNo+NockV9zX4JjRpROPA8usj5qbu69RWs2KMdHX+1E9zQiaO25PK6D1G1rNSKhoGSS"
+         + "k1FHPppNMd27XIm2Q07NryTkuCQrAgZ7Q5WjmoxoovbeUED+VEs1fMN/IySXkzQgyXQaWVXUnKZ96ROCzgRKegtT/xlciqFeOHayzkwaWXscstC5JxwZsTT8"
+         + "O8fJLUjh+wWWnI2cmL3ZYnzsQ0dS3kMCm6jk4tVbvo4YrhCOnvnk37C4JLEeWuTvdYyCN/5rmGDJNOb9jPJdzmgMS6aKrmFQ6SsAhjNlewntGWjR57XwGxTS"
+         + "8b1PbYITu3+Ox4lz0IBx7kpDwxrMHRyXMxLKUkgjK9rtyNYvzqqpeaepBwVHbSk3bjXHVTdEabFRQ+zQtrEuKh/7k8Mc0Lh+Oi3YLa/ulSUJWZ0OmewgQDnf"
+         + "GpGuFwr5LCf3t7g1ZF6LtXG+PjC0pa7r6SyuXJey97vedxnnZQlb0htSbHcUYmN4lJoeN/T2ltgxu2sx8iwTHePrDy3mS4RWVQ3pAIaHN0OBGchRvpmME6XO"
+         + "66SgXKJxqXXOZzwTPcu3RDKOfFoJQuNzSwFeRXQuprfRmQA1gejmhkDkZ9htpWEAUP1nUAg7GenygNSScpmXNRkOBQS2V/SLXQLuyug1DlhLDxK1K6DrTQfq"
+         + "tWFj97taNx+AyFdMkFg2BAMz25TDeckiRqrPfZoJZqE0oF2EeyYPvyxuIsIq4c0H+JbHbEYKeOGouBqfSGjliBAZ5xD73PQ1W4qBKKWq3x2gQ9P02o2Tt7M6"
+         + "M9hhjxV38QrCeZN8WjvuyV1L0Lg0DrXOWRtFRjaGgzo77AyxhXasj03KwJvlfg5SgTJiNbicn3zS4ZvHl+ZFmByFWZfXkQ/wZSFR0ScyQnB4twjURraywbha"
+         + "4rF5u/1QVh6E6BRvbzkcgLXdBfKXaUZCq5jnLcwFy58N8Sd97x6CzDW++2k2jxWavksKtay1jGbduc0XEMdAls3HbFcB+gqlWkm45Y3j1y7KI6jAVJRjL0m/"
+         + "jiqJ0p1Y406MAcrj5RCKo0BtZjPTfX15ac2iORF5QeP2C990/WsfPUqmLnpj4p7znE2ZNGb23rURln13nmyowwGIZNJ3TZkMI/bVTYNLN7sSTBDhM98xVk6r"
+         + "+E4jzdlWb+MsUSAmMi054o/Ei4EfTe+MYtBhakBGu2A0orYBKDMaGMC/td3qCWzJD+xFJM+WKGBZQbpXCfcYnQEsNDHWsoRywrBe3p8BeDWHvLWc05Ey0ml0"
+         + "sTHGutJ9LmT8SfzJzQJKWtCax4al9K8wGabm4WeYSfcznLV6UsAngs65R3GNIRtgob2I3lYWb/3IUjFz1qR9hwdA4ft28n1fVzYcdLWSMrOBE1uJ/ZJ1tBmp"
+         + "lDV0m77kAEY1J6xy6QYGcHMaXoG4C4cuFvtfuepqzhmcCF7B7ah0TQFwsRYYowCinmb8Cb+/uxg5+lql9772WLm+0ucPTPDTcMWBrNxfUvupJQarW8V5hGu1"
+         + "WUpU3c5GhUaGzXYhvUJblBDElC4EEWFfLSypWOzN+GCUay84zCZ+S396JXwdtx2LrMAg9QiTSIagNOGKYPuXO2ksQmh88TXvD9Y3Pv8P+FfHjPyj/we4hGxs"
+         + "uk7BL50cPOnt+ZC0qQOAd26YJqO9TJjgTorhRuE5XG0eadAGslz8n8XuwJn0z5YcYq4riBe5+totw8fVLMMsl3lGuk5SpaykEqO3UkeSwBxQs3BPkCPYXp8R"
+         + "QZdCyLMoFfNuAM66lhRvEKu0QldNkb57r3iDQojTp6FxzvJXWRKIrCFujTwESltiMxBiPgBQy7JywF68TfwlVF7lZ2rCBqKpMo3gZmudsJvP82JxSfAdmSD+"
+         + "OIhayNPD9XHe+AuJUFNv7Pq+1DaQ+k19dIlymSuepX4s1+0NR2QNVqQJH3B7BBrzeM1E4MEZJ02S4hdDyKHVRUi1ByzYc5eXTi31BAf8rdF9iOrEW3JbQ2w+"
+         + "Rzvkl/99ZmTqU4ECPzjEyCcwTZ2dfqj9IheT5hoLkH3GenFbWLpgKoeVZbcf6bMWWebSxB8HXd+UGON0q0Ium69TWyo3AVBGMk5lWzGAo7FwDW9UY7krzqXt"
+         + "JPZdfAzs7vAb0MTNxjEJWVcaDkJsPbjUC7tEUFG3iO9FvF193JbQZ5kLKMXFkUWZIc/JsZVU255nWG+yIUI/eH42+iv2+OJ17EKQ19oyVfccmcee/FBoREr2"
+         + "Pz5j1zIaVr0cxuB+xxqXLI1K/MTQl/2s15oNw9TO8OP3q0qyH0s3/K5qsnN4avz48BxOjT/xpUbLSUlq5s75K+oDF4IyBt4z457Op6/MblEB6wAVEyTTyfx6"
+         + "zOgTasmr/Gzm0LWiDxisA7wv+e6NBonkE2Qzvh/XXclCwXRDbqhvk2X3x28UZL2hFdRNLWnoQX14LunwyMbFvUXlngqnoRsTpMz5/JyCSMSzj5E7RCN173np"
+         + "yMrhI0KO5yB3Or3OxSQayRAMCJ6Ll/ntChWX3JxGL7YTYyCpluNEycnpS61Uup7cLb/VIsCF3unMF2UTk9RJoowmYzSQyg0BrHhmYv/CEKTzaKC4oKV+Uao6"
+         + "uWOxDr7rpx6DLlX4kYQ4BoaLH0UmZ2OurszRTqfSKE9XdpN8FO4WEA7vLojlqOfxQhiajfd6SAi4j0Rh7pgRhXrRuJjZQJqvDEGW+C5LKSXeI5kftAE9/RpV"
+         + "Vyggggz8hUe6igRwHGNdY8SXQSi8XgtE+saKcLXISXfy3snl2HIk+3V+ZReyVJxR3hD+LOYsQ8cfzVk9Cov8yrDSg0QxmGjsPBFCvdDioFrwU7Tdz/TS5CJK"
+         + "2TqiLcSjFQuT50VcY+vTaiQa++ayrwuFX+T0rTJaa0q8142mImUQhdYdE9XWo38cQSVSLsz4PvPvRtKBupdNrWX/Y/QsMf0y+aqzL2M6xHG/Wsz3M1ksjvB4"
+         + "DT5+gwBIwKMM4zUKTGFWEUJRxr3Vl10Sz2OTNVqH8aw+luBi4RZHshwns8Kmxwuo5vsAd8p0PFDHeIsdwMJ27mLvVPFbSqoZhbYaX36G0bZPtwKHhdtIxR0G"
+         + "ShkK+auMNOAsG32W80nP6RdSghhACW/JkXjEty4WRtVynk1VrXdQ09eDBZShhtE1r0KI9N7noimo00spquAzwmaCbDT9aSalagDQbxWLwNZZaI9NWpMTzqz2"
+         + "jSiURSW6TnJgyklEhGQclL/K8SHuuAWWQAC0A00DBjEL5AHRqavXSE0AXtQZaGvs9CQke3WElc4SjWjXLzie+VqUc5LAtWvepL8kKUmS77um126RB/d7UMrR"
+         + "OhvG2DYwxtjU5nV4v7lP/6irSZArwkVh4rsxWsOuf3yYi0hfmasaWLBZdsYTM6/UeO7Hcq4xdDnN1FgLt7owD+AtTIdNoD3SgR4CGU/yDIlwb9LQg/drgXZX"
+         + "7eGu4MrR/sf1A89CTJSCS/TxOk4Y/8Vw4qgdWELbXGiXRgpl4w9WPMXgdwBIkEtrKE0Miun7qWjhPLdO1DGY0JMYQtqIOr/lCVUVVWOos+WchfsDtOsxDBdJ"
+         + "DviUW864LUb+f04l8B5iGM0okOJosJWaqpVVWRcRaUEAqFyGiJGOxWodd2aXM3ys+Wwc9y9zhmAVVVYt8TlKJbSX+YQnymLXCrFZox8b6ihfXTNZPssPHGfo"
+         + "BpZpQFfR0yO0s0rjZ+Ed+JLZm+n9yuYgzMeBL0ECXj0BVkSjqVZDYimDuukPK1kGkA6ucgJGKSMbUBWHpQNO3I/cKjJ3sOApQj6J9H0FGn0tcnIMkJEFlXAf"
+         + "/Te5yc829FxlG+rqXMf0cSHcVRjOB/w/1nzj13cv5r+XA3HeQdkOZTGEoLb5iMBV6CGIswMiID7GpYbBM+0KnK37kFBl2zWOl17ZpDa1v4Oozwnf8XinAOCx"
+         + "p23yRRQwh9iBubkPqVXTMj1ApcqAYRCB4qn18Q/j6EEZrxxck0WV4v3v4RHseWpp/TOPyEYfd/ZB4DLA8Xu1kYvV7QQ/NA/z8SnPEkJT95HxMfTOB1G9HojB"
+         + "C1zZ8WkNCL4kUk2oKJxD+BktMSTM2xXuGz2xSJjOIUHhhWWK5DnJ+DkKVi6fBhhDrhvXEj+pv0wPKD+iOAAOESaOE4oO9xvSWT1NoPRfIwz0F/lpPmgKGRQ+"
+         + "N6d5Q+CorrUFjH8cQ0vdPkzSUvfBALTpLLTazZEtbJuVaoKHfHBjqHwDwDU3+xUXj2Q0FX5viijwWWCOY8va/lC3QOZF6RDw3l8/KacFLjTzeJq2itRI5n97"
+         + "nviI6eZGbqTSw/U23D11zhT36VHT9kKCFvY0RAyuZFKGN+xczXsYA4S7oCzs2TilXvS2Dz4qpkpx0nPSBBuFhaQnRu9ELCPK1om1RT1NVQDT9OajstDroY/1"
+         + "DiqxwxkT5EWFOj9RZWqHD+kdyDXfstMyF+O47JPYqb5U0AKQGDvUdxSDB6UO39PkrjeP4ngKtLl3Fmmm7D17sgeiH+N390zyxQML6XJTXzz9enH/KdfqylWm"
+         + "wya2AdhGYx4xJrSPNll1O3bQ7JxF9CMqggpKDHrxY6TqVltTt5hKp2GhmNyWJakib11SFOWh8sYEq2Eu/l2EgI5fCmv4mGBRLAE1LzTFUsETS3v6ovKLI3DY"
+         + "mPrXdAq7JVa0ub2lDBkLqy3pCCJ2LsT54rc0CW6FdPaviZeFSom2IRXk6q0J7vb5dHh7LBNx5vBtcvcxbtM14a7qMyiruJSA4POYDRGyOkLuIxVorgwAmwAJ"
+         + "8+pOmHMwCL/+bVGcx4CwfgCfUXrLU1JObCs28fFnH0iUH7uzzb9uVpVaTYJYCb8BJ+fuNpU+wyigMrlWfB5cKIkisRXf7v+clQKX0q4ufcj77N39yO4VthaW"
+         + "ILYJK8DDXLv2DLNUO/64kosJiLXBGsCgr4FTvHP0XUiPw7j42SbPofUVkyK4QjASNSJLdYDDIL7wsbmWF65Wug/eQJN4lHtPNMpGyfXheMt2cDdBosCoxwxf"
+         + "8OD5KsFpJRpZp3MCQ+2FXSExaxOiZYTflsDP40B+IDAUa+kCmT7qcK8ARZL3ldfy3LcbjFEdzPnKJoSSyyaXr0dm5xWGsCfNfbCkz6PXYRJB+X1DVbGg88RP"
+         + "fZ7SfdqW9kIyzI8ALkes5t/qAejwCrimBrI9kTV3z5eL1WPouvL0Mh56NYhcWIOZceZr+VlSkAliV0ZrXGVVBtCeStvxTIEE/wGJ7YumS61gDnAX0FFOislA"
+         + "zZwnV8qfChyVqc8t2fXfAIeRQBDY2Rnu+/q/xxF5YdbyRjg/4c86esIQ0wQ0YRMjC+PNOfDW8jVtEYkdvK1GLQ5oqFccN2rFi73mD0AYHazSVSyYjHE/PnHP"
+         + "D5KSBP1FZXlHc4K0DiXeb4OdUU+s4ffnQMK9DT92o1HTB77NgTs/U/nq/LaOx9PKWaDPZwoyCpDM9psGrfw3JrZ5N+us6Dsc60TzqmWx+Y7KVF+d4fbFaDz0"
+         + "QUuL1AWV5LgubKkskTBDZ2PbZfw9EKTezl4nHNZ0t0IgyvDsY6WkP03O2N1oUxgbRqkUe4EGD6I9THycVwjZ0uIngdeLmxHIC63GyRnyDPTKMwks/DWqNCdV"
+         + "qt5vb+QExD0bAT533Rq1WqUqARu6TdrKyCN/RqgwEHws0Rgw/yLltJMq8Oe/wo4S4d8SeZjy5HpJRZhVSYJ14povNNOJj3kHz+EQcqvU33hBQzh3Uwdt9Mz0"
+         + "tCWzePOtzKjKV47uFYebyQQKIBbKQusox+QOy5ylcqaKm27W9WYRjkXmabvpR5OPELOICdh6xZvaO1esrHtUY8JJx1I7RuYE4gp7/B3tqaqabF25VIwKqVoT"
+         + "8wfEZU5K5RIGksOzgjzf7RazSXmY/PePo5RiLYxHtc+zP+8u5pD8Rd2YM8UAqnDqXJtUC1kboeLrlpcWrl1zN071WL8dlQpBsDf+haGnFIeliOh3UMtXRE7i"
+         + "QAOGVr+T6jbyjKVHCbIocJeGtkRkxkElhfBGxXWgNpC/0C+G7l1Hl/Kr/ilMXB26xg9hzECwGKyeV3nqGaMmUnBHVpZaasAaZpGn2n5MBcXcWjI7dMpnYp1u"
+         + "on/rNYQpci1xwW7X4QEHoSLijFRt/sDIDCeOd6luoW75qQwqBlQCT1JhVd9ZYneNo/KlzpCpHjDg3Bi1pTlqeoX4qlgO0lJm0NdXD9FCMFMI2m+hDnYoPOwg"
+         + "5mvH+y+8bZ7wpWTd+3CSeKRnNiCb4sNaOgkW1yoCxETpl73RrMztEhx/X3AT5Xs8N6SnXKsYRQiqtRyEqknEjBwGdeONiP27jlplOZhk4+pZwT+Hb2FTh0lV"
+         + "SmGVZ6zRudUffYS/ouHsn5e6X7+FBcwEvc8F76DrjyzjPyCHrw9MSVi5XhIWdsrwj5sKe07o41umXF37izeTExQBkPWG6xSptVOtHFEAuIIXFa6LJHrr3sqw"
+         + "lFUObDakwwbMiW2jAr/Id3juviMiTnqum35UQvbskaJK5NLeE0qCys9vZgoxPP7QG5eCZE5bLtVADeVE+f9TAhmUIJYbQmT/ZD66LCGBYmbicWRjm4lPz9Aq"
+         + "OX3DO8BDzqcD29rVdwtzf/ZpHkSuH8X0OE36y4KT9eyiQJ81v3AabkBrU4W3ogC29MLlHogi5cJgZcw/C25sEruYe4osaVqpPgTkE3Okg44HgszKHqujmGLj"
+         + "BQHr/bBjBUjVA6ggsg5cmr1EAPHeeYbE6qeIe+f2UD1+qUNrwQ9DCRBlg/z8cPG44QnlmIgL93mpoiOlIrph8DW2VP6dhalv/HVEBV+AJnYcj5Q3WOe6nO9z"
+         + "m/qJEJPWyjEA38O1MYcbD0CX4xBOfecTfZjiq5sNh0Oq2QC2W7cWaI7agqHtg3+P5na+zDEG3C24GZvffYRdBZSrNIOpQpG7YPS3mJK6RPZt2pLuKFUKbV8V"
+         + "/GEdRO1NOkH3YO2wEUkBiXFhtZZnjMUwD7vbeIkIM6OPa7+/Zvc9Rha7kGygne0G4HEdiBo8Tn0QQ0k2RfhltMefIyxVx4MBEFp6zOFddZMeHKkdxZc9PPnq"
+         + "hie2HsMxNbcCzD3YpGo8p5rqTKg+h47416NGsHw1ARTPewwFR9AWGfNjjf+rNyh6pLhNjPl2nEax/hOBmkHBKnPFJwKjxUKK/KF90EvvTsIcx8U2gTKYct9r"
+         + "id4lYhxq9jMfSsj3imJPoOtHkScnTGJ0La17FSG1MqQ3FHnE9Jgi0bHljabWzQddJLqKyDZiuJ6Mxy6DO5QuxZKJLMb7UPAzNvTLasZZ/KazQp5WcBjLjgEI"
+         + "e/driqRQJNVe4ouIXkFYgDcSGfnQrct0h6Y70vBcL3ciMMxSot7fef3f9ljHyxyOJ2hNmIhghTPABEJ/h8bfqPf3ne1G3cLIxmlm2v+Mjy1dNbC4JzFlIySO"
+         + "FLXmL+l6TPVDAooXJ/ZPYecqFQcQApphcmmX2pngliynX6IJtpcTypDb3UM+M2EZ8CAZFQAyZD686bov7CboDqAE/jMc8S/zQa3oqzG1gC6bwR3ilFu/OY+E"
+         + "pjuimVFrNYxpMpULA4VaEJ3xAzdqcQ8OUvHdizLWCC16gTfbJ4+d6hyMhT1bRw3gNcI1mq3aCOcg8K2jozv/gbt8I6TOmknSTHePJLMFFC2AHGqePqLFOC1i"
+         + "xzWSDgXQydMEdyebsI9iBmn86qDje6znHkbz+7XrU2UrrBzGFlHzW+eX2xhNl5lGGKMFQjfB1CehlNLnGYjVQlJAbSZCNA8wABJM+IaNMD4bJF5o+nPvjmoG"
+         + "N4mM5NkUN8tqeR31clLx6JasuYyNo6H0/ND3424dmCihrxwhyUsaM/rxgX/k8/yl9vnvvCzJkPrB4TjGzOzx6M1FvoLUB52J4GAuyC16bloYD0fzm4naIiz8"
+         + "8ROzFsitOcs/T+wY76s9PW/lcqaTV9hREDgCAwrpGHCBaGFXZMV0797EGG9eResFt4UhJrGy3YBMgLGURMALeRh3jBc8my0zvcu1WxKPNR+vPDjql9GghIwX"
+         + "zB9RamhlYHq36nH4IwqnviVEcWJoAakfYnOR90YG+xKwSMiDU+bi52MYSFyr+vcFWJYFlFixazOarNVxyvo7+cpSOtEfBgA15BYP9QrmBdkOpDirIgSfkAmk"
+         + "7I7G/6lGpMLL6Xdzjhq/CavM/xRDW7FCLj8JzgNL6bEACOrVuSfxcBI3XzAf6foo/YSZUQjABKy1zDpW28Rn0hSq9ta7Rh/9a0e7EaclfSlxJp8/bXkTRvDI"
+         + "c7b3sqqPkFEVVNradxLf9jWDvtopwCFPt/s/tsNJfxUBO8fWsgn5BKZjHz+JbFHoBOrJvoYQGhFD6ecvqpPJQs04sGqTzQ3BsywIzlDq2OOTL42KvQk1MgdB"
+         + "cq3pmi6ceXCWoysnU0XYCKLFFFvsgaheenTCiAH2nOXKw5ATyJ1W0+t3jcM7V0yZChGhmk3BU9m3v92u+N9SxzaDB/BaI86iKgCTzISL5SV/20oLz3oLlu/N"
+         + "WQr3ns7VBjGdXrRbnRWduYNYRnAd+HglKmdU9CmWPjxKKHer+8K5dn1KJyWSPzcoRyidgz8oXxThMbx24ZTy0uJrICpRA7WDYXvPDwH3t4/ClbJmhJ/Pdknb"
+         + "A/kfaBGUVMB4OrCwcDTtuFmvm1q7rNr+qbdwUKleheHuW+jOLLgsceBTeHtBpIxp0Ql3wiaaqvsx7qRSlL/dj72LMOmB3q9zAFKq7jqcokYE0a2+zq7hSTV7"
+         + "vF1j0aW9mMsZAqBNCQPiD84DGbVtQ6RfGFC2tDfaAjhFafC8ioOH0Eb1c5+FLA7GyeRrxm2yYjeQsBM6GgLDSNu82dGtZmC0fn40fbRGUlMhBcrVGo9x95gE"
+         + "nIVwkQ9ucj0R/wLIU7dJ5LPfULM4pD++zJtmaLbNatGXgtDsALX2OVFeqOtXEZhsk8ZXkUjYxMjqpM+3JPhHgYPxpp43qnJqTmwde32by8wAiKTgFpPRO0o3"
+         + "WYMhaKA1AGngv3c2P6DERTbSsdnufNYg2lk3++rJ7NCzFjsGPK5eIrjeZEyr10feuMymlQvij/54UFaeeasiFueNOBusnLxukOmZ2yM163nk1OJt3IXphFdW"
+         + "7MwPyI98tja9WXg2d3HfIfaF80jMVs5FMgfSB7l9rxaA4oOUHUqYoC8csmitg8AgLhGlzbor7+Q44e6u8rUAyy+WcE9TlNSr1x/kDUHU9q/MKa9HBeSlOUvT"
+         + "j8gRetlVXfDZf9PU0oY6BKrkwJ03kXRMYRpJMI2InuBh08eg5eWJVC/sUi5IeZUhjVHvZ7GpjU8B+sfCDUKie97dv/DxlYg454wrObV7SKZG40YLJaRKVmAO"
+         + "zuCoyWUervx97yyzAcurBC+nGVLGBnBF+C28c81ytsltuuU0YeAI37HsJXBrz4rruxJ4iSG1laXafgCVYUoJaE00l84N6wjQEgf7f6VRdeza/H+l8D2x2jJN"
+         + "cw2Br+Hj4XI2nbzv/HpqoNZZzHh1taTnXHQeFuOyLj+zFEBc+7BQxrKvGY4CeVuktlAtvUcjQ3wwhCu0Cmf2W1poM9LtzrOzle3VipbyBIkyg3e6Xg2fJm8Q"
+         + "Wvi5m8YilM4q5YrpNBuoeSYF1tlKXzdRlSjlWI1AONDhIb17xhnoWV2pso2Flc0XmiM+37wiL+GuW1bLMDwJx9YztBZpAUmlXfvBr+MgzXo4veheBu6W00ZL"
+         + "j+FNMomWQCecsDHZWcUVoRAnL4zVT4n7hym+mRDeLAzkLU8YGtKWA7MwjtXWqakjn0+iuOuLwa/4c/bCyZzvAFoPZb+wm9+7OSUGjcRQuR1FM50G5l/j6dfa"
+         + "mflw1uF2Ruln6uq0oS9PFQHoK+iYwHYHE75mku/7/F3AqRy38j7mtg2mIM6urxX3h7Q256oZhpe+Mx7gCNLyjfnEWjrmxv/zPpEWhTiCILP0BMLpFJy427/A"
+         + "s27wM8JOsxIZEV+6Gho0Yt8weny/lVtLEw+JF92Ns6VAd8hI+wb+NM/sy8Uzlhak6OuL3vFbwY2oA8MlRwLo/YiKNYfkvTYV0HjXCPgOnjGyRBPJ64CR8iH8"
+         + "SWkea7w1koEAE9lXpApdhZGZw7qkKJ3J/nahCCHDuRLzvmahYRcpp67M7pHbLP0JSGKI/vPV0+uUCxLzTkOoEialG5dIHMtDrFmRRKw5CaZuPuwniGh//VXw"
+         + "4eDbaGUMxUhKvo7lh2RzfEMQl+2gyGMr2ptlpwbQGrMUTVekXMKfwo5bep+GQ0HXS2dVJ0HifejGTpxyizXgk4DW2v4moR/E+qEwY+0kvbiXvBgxqnJDc5V6"
+         + "RwnDRGpoCF1M252YUOoCtUnLjhnI7mIKOm8XWonwD9KJkdDhX71Xm06pIze4LqIz+jRrOQ/tSQ3Q4/fi/QGrNeQV7EbYCb9euClfs4kfqWsLfzZuj72+0TSZ"
+         + "sqQymhsmiLNfBhTzY2a0hj6SxQ9imPypaevI1MYAweRY+fIq44NNTlQ+iicDKUVAP6Vs8dC7cmrjY2jLhsBmydGVeKRw1+RTXqvj1189zgycgMzfZeMOpW9X"
+         + "jpGgjrIPheht1LrWoVUDQejV681Ecrw4k844zR9YpWkyu7/iO0FfucNUZGFY7lVML+/sVIPM5M5kPBzTUv0cgT/EiVsnmyYPXUJl88WPInOFKlerxRJ7itEU"
+         + "WxqHbvN+8IX91RMYlyo2c9z/LygzMg4ncZ8lI6/n/+acM8mrdrkkExPuHsVsChYeMEqKDoCxCYdpYOcxBomzjCWjFOcq77SCAwZO00OoIybvFlpbTpYZXanP"
+         + "WUZMeLz0/KYQkS76S3bAWeQl0u0ph0F4Q1J24TW2ZG6+IWaHi4+PWSNOjcs36329Z2Pm8CxQ3TV4Qf1BlOpgXSwBPQYckKjKVFJC52zrvKuUZUNznTdwOj0l"
+         + "rD/vV//y8wUh0jI6XEJxF8dNaMsQ+SBlsNyJTABOzhBy6n6R6ZUGxy92hzzLj12FKcFrUwurYJWM+MaTBldWlsddxKv+uwlwEkE0iZLNTRrVXRQlZ9Pp0EWj"
+         + "wpAZoh4pZ5Ok2K2DRtbFnPrJFd7J8wCsvT3WUt43arkFFR5KK0yXk7ZjRmzMKXI6TnLVcLrU0MZXtyWcygkidV3X9LE6DyFB3iNvemR1id8qlFUEInBpkfa2"
+         + "efbmvK8NVWzrgE4D9zWm4vNt8BCWIqWv6wubv/Fe+pU524pVuaVqtVg+HY9zzBK1u4CysIiDzkYxZ5+RDTG7c16fyKvdHjLCjflYHlO9MFNontc2q3XEKjtR"
+         + "5DwChT5pC1NfD9cu1x4wOGR+sPcaJGK1vhAva+1ThonsU80tjp4I9sUdMgEc2qjyKXBjlg8zo/Hvj8FuyOc/rS99VBcvVu944qNek+t56T5BlHn1v/0VZQCk"
+         + "/q/FId9iVYO7Hvt0hZRFZ1GJYCt2/SGuOqoSOa1BRcF+FKa26AFSeQbsvhnVAh3LxzoInCDMOx9A7qoJTr/XcDWkRbbYsLsx0OpWbQYyeGrUf5CanHjoaN/l"
+         + "D0qeYyxyIknfNBri/rCAVZcJJKv9bb2EZ2LlnjqFOHzphluf/983r9uC/zpIktM/2ye/bKQKqMdHzP6CctvlVtE1IC1W0+tezCw/NJoZbAlFtTx4YILcG88Y"
+         + "S4Gb0HAK0lRwyTHPlhApoX3vD0u6fTb77W/ofkpA5MQzfYIWwj6q17LlJZ/FQ/Xmc7FUZerDRYSqQAq2a/XWD8suSmEk6dKShblklD3d99n8QRyLQhPlzS9h"
+         + "l/3wi4yJDJ6TZBesfUtSpCETHG6bioagSMuykefR5CdpRzX9SoiNYJmdlQAFqxZlBysOLmMTrOxQOHkJ5qGXgwrDjxTc09plvDe4cfU+w4IlaClgWOti6TXe"
+         + "bJaLd1ENwTvaK5WPHjdvsMcqaVpDM2HmA74AKPkNy57UfGYMnuzG9cr3nGGBbaivqPnvg1xsA2cD3pwsnqWFxqsTlVyxjymbpogKILvh8Qa0mFHx8e+HdYGN"
+         + "c82xe9AymVt0KqWnaN8SDjfM9D3ikb2VjpAi7iRo8f2yZuIuna8awM2Gh4BrkQzudUh08MEMqS/yua0vFBad36vax0YfhKHC0qI9zraluYeYrMsWerEclhqh"
+         + "gIoYHhKi/y37rBOs6zUDEYBlxw8sSbgWDUXK5WZoE55uQz9peyk/fwwOaM0kqL/4Tmq8HzFi+OmNbms4/Nml1kHCdxePbWA9OlRp/GaL1l5PIWdUYXzG02k3"
+         + "TNKNCFfeVrMOYmRe5Btli4him07IezZrGSsl1uO8ge69X0/0Idfli827CUQDmn2MNwPmGrExrymFjjuh8BHc3rcvfiFIxXE5HcyKbn/nHEvpOJ/ZR9kZoR6H"
+         + "5CcwlsyrwP/U4MbaXAF/FN2cVvtx6xhKhNP4NsP0Ff1JrXz7EKHIwSwbRAQGRovZe61PQ4qT18pE0J8RxBVrW+h04T/hhkzwilzPhkh7nNp832/bn/wsj4gn"
+         + "Ij18q88rCSxskrA0b7QaLSI+DYdOsg6Kpi0tjAcPGeWK55U1bTWIZwgzmq2C+5bpn4KdERcb0HbI97w4GIN4SB1SaCEK8RWLdjxzhzJMIwKJ5wM9HhNT5n5H"
+         + "VLln5nWkds5OBFZ4KM9xkX28fKgFssj9pgvuBf3v6yqOvY1dMBtfz05/k8QP4v9nnI4ZPV4WxeoOsQ9YCQNq6hHrxpdYfQ5VzEVrnoiVTKZpuDHLfVxjblwO"
+         + "iQ3TLEyV4WsbJd7M/Z9ANeWZTVlkUc0aWG5a4M6ZJHDCPMuQQshelV27ZJYYVJ7GkvfkHwADm5V0WTRSDMDH428pZKyCZtkoZ9J+TA4sWzhyezJlvj7GxT3X"
+         + "Wcjc6g9JCCviMYeccOmkrWEHf8opARG63rOpKehNMIh6byANFhwNLhEmlJpv7e2pxoJFvs5w0WcVQRnWJVkpLmPZJ8YV3sPpATVXSnm2/G6j+fBVXCaprjEV"
+         + "sZSoeQnXQ6443FAJew3ANhEp9O/PeDPObz1zQ2Nqsrueq8OxZbKZ/OLbp2zPbQRWqIMAAH4drv9NIg8SblJ5PjFROlZvGbYs7v9Ifin5uHy/3jyw2KAk3I4b"
+         + "iI+GZyzSkHpiuS9JLWN30peSsRpIecov4110MNTk6YiUEmRhg4rMKoHcXTXo9r1pIXxFSZiiezTG1hh/NY76REmLw7I3RBzIHRveDxF3Dya5aWUJlb8s5IjV"
+         + "rQblJa/lRTM5eme5i3dYY6Eu5GH8seWVhsh0WGPyAnm8erwTr2NeG8JaxGytmmWThoAULjZuyAfj4FLegbzqH2+xZRvQqXnSNCaRsKkdIZ0xvqhtOsvh5M6B"
+         + "UHj0+SG+3YwlzGzBRRcs7nAEKglsrKpddNBvJ6CmsZw7IyuejO2Sd61EZo6kogIz1jO/GlKvIxMm8SxngtnNXK7eSrlx48HZVNFml1dBduZ0AnUKpDKvo902"
+         + "agO2hCwZg2AntC0U25jz2dS7ladf8xyF/Ft6+YuhNKEJPBZbgAJWa1wKO+iTMIHfp7QZ6KJ7Ynzvy8O/1kigl+MPrdA/OH+ZpMsbbMnsxQuu1zku8eFdUsaN"
+         + "wVB6Dv58l8aO7roSM/Om9CjUJ9q4oaOiFVPf6Kk6s2lwu/H6RN4cNH6RFlpA3cb7rrLUCZXry5stm7h5xOlzCbyO4NgUsCecUBlgk8iJs3Kxjn2wKno5YYvn"
+         + "D7jCy5eCLHxZzqY7Y3yfW4XznQ/9DYcsWfx1GphqZetSrNW/2VI0hhOyNgKQSwPautq5XU02glYccg0W+4C+4mnTRd3HllJJAPzO2ZvA+JU6WsYD8Yz5WrFz"
+         + "zDaKl0u6ULio6LHpwSlx1rHWuemSK0fxUWuCegq+vOUBPAdeDX1+qMWhzD++NPz6EnUQ1xSiPHQ+1M1B0O2dp2BR4B5WTv4uAK6f6v0xL7zWKC6bYtNGwsyO"
+         + "rFq2OvmJ2suOBAh3RUaZUUfytx7xRoUOWRlCfZWqnOT1xYKyJ3UDKPYigF0IBXkvmmCGYoNyQmQQjxdbhe8lmziNueIkIsQ/ToMKXZcvxPEdN5h7pafLp42Q"
+         + "daWntLbZ1We/+DgyY4UfHrTBUnR1BSbdkgc84Lu3TGioEd75vVSnzZtUyU52UBc2rlfwlY3Wkpfa50UFPbHV6dBp3asahe84y+14GeR1LlGuKAoCqDnfL7MH"
+         + "yxkDA/JcGHjyRj5gqT1p77KI9lu8JbnWphYXMe6vHN8I3cg1msuXM+eI9crrv1FHe33j9aLEMkkGLoSMOtMVwPyB60g7OWlcPrFfhv2ZVs5pmLO7kVcOdCtq"
+         + "T9UY1SO17M4BEaT+ji4WwuLVWbSUKDnVEyG5RjHYcSZtMsVKWm3fqWpHv5KrLLUr+fapqr6cucLhBogKEOu2Pa+gmIN8OHIBwWlJELlLx3M9GqradoCzvaNz"
+         + "oABGYTGsJ2ios1j8u6WfuUSGNYV/CTZ4ZWF5vJtPF4oaeaLeSUa2kaHF4HuFf9c4qhjzHi5geg507fOSEy+oOqmQ2aH2YBZk1iYvBEOTSOQGBvNrkVlW2T3q"
+         + "+cfoosiChzbLL5psTouuQCJE9oV5hYPN80yyWuxakNZI+A2U+IM9TPG/nzfsuuyErKvzNGvgFOWIlPmzsE+AF36gzuiU9dUYvZzpr7LvdAcnRuTwydf4i0ZW"
+         + "Bfc6afb5V9WoFYd4mcRSC3cBgUIumIxblMzGwptgZgOuHTBXPxVVXRijfc8sGC7/Pi6DUaiUvzOkcnrBoe+niV92j4DEVXCb+3T4mbnkHRsUcpdOVRCSMRZt"
+         + "/KOJFqZxm3pqz2mLBH+VastpHlu3DiIhD/XYB2T29pa/m7K+Vefv8PCO9uLOanfciwFXMTafrLyL6FJX8fpVcMOOGAHsystjbpbDiOF1w2zh7W8Bfzw5joAQ"
+         + "eVkzZmE3DtGROAzJpAtTYfx1mTF+08n/pg9fvt8g2WvUeWtrI1gj86IwGcMuaKhL2d/QW5wNrniPteasmY1YCn1srPasxnqmvCucf0b3Pxv9SHUS7l4jIhhs"
+         + "W/4/9OPQ8YRJCTJ/uGnMGstEfC1TLW6//Wktx+012x7ycGyxL56sUBMcjgKS9pz3bY/2TAxFGjfyhUu2f0VneHpm1BKPEj1w2J9Suo5UHLwquHWEiy60DLeV"
+         + "2DyaVqtmjH/5ftx7h8Odo85DKYEOqVcLhFhxUTtAEEXu7lxFEgTgipZWyYKzESww2VYZykyEGyvQAirhJ7SM39U0t+BxtCeLPr6bsriEe60omEzfI0Hlqxjc"
+         + "rHCmMLnYcdkfz3eIFdw70DrDqAQWQgx+Ll29SOdj2jBWcAuBYygmHLbn3yYFYMJA5GNgNFqQRUXVahaADQBckMSqK1KmAh+KSsJKjyEQY+zgyrZewVEBmVgb"
+         + "bPdVRQLj+nABdba9bLCwZvEWwf8DDLq87JC21VNy6YRke6rt16hSEIXqDdBUsQQETD9ycC3Jfql3Xd+D4GH6T7JR9ZTgSq4sqO8PaZ4hl0W2cXSmAnqqzYbi"
+         + "UIAx0iAfxcPPCxD+v9Qc60LdSOxzxTbIxIwKM8uqRklkrrEHk1nCe4APcojcGTBj0ZE2jZKmoJRfPOuhjS/14I9iKn83DYlikS6uI4PVLa6b0NjMBYFE+zxs"
+         + "AJS4XC0SWPXXq6lLqOwwhVVZeBT+0hiGZDGDZaGn9/RNiqjcv5ukI05VIqebIAjQvnMV2IS9pg0PW5IlbWb3es99V0UgPFL6Z1+NvLVN045v40LhTG0YP+/P"
+         + "3TnJCtFNpYfVO5GxzcoMrwzHLbPLC+o/TcUxwm9UTU4xD1cCkjssrLmWJlAJmShji1sQ4cb0QsF+DTvy9JJ7cLG5waQmBYEvWblpaSYmO9ykRfEkhbgociG/"
+         + "GRlbVABPFl+wp77CV6SfqVsSILO6CNySld1q+MBZHG304gVupSqz2tfciTEVM6VB1WaLA0XuCDMBL1lG9A8IIg1bClQJi9YZlry8nSDBM/lhPxBI2jXppqYV"
+         + "+qvbuUGbOhdo5gaMPZm9my2XYiqrRRnNV2NSJPflTenNFR6MsMca0OYhKxzt+WgbZ50CiPyeS2nQRfZ0vFN1soZkKiatpJctAiyC0KtNZn6/n+pcjUAKCDDX"
+         + "2c9JNGMNRMK7AudNA0yPmjr4UDGcZ6w6+vsAO/65FBD+hCKE0WqtWdlVH+Nlb35B4O/WWffPXpLIr5WEk4UAIB+yyLXSyPobwT1PxvyTjRlT3oROU64F9rV/"
+         + "DdxtVZ7YxS30kp3afRxg9UD0FmfL+5tpQholttKafsAGCrXzaSLwJy1/KIkapG5qX7o2s3KJooouUhp2ExrgVr3xnhnriz8a3YkvkpkHlfhWNu2TUSgvrbiw"
+         + "lbD4QraYp46vvoQIRcWRbB1KSd6UwwzYi1mOVBC191NZlzPML9/m7HeuqbXiIxeqBDxHz3NKdPW4Ko5VPa87OmH8GcVTMmq2elzz8UP5yH3NxYhBL1RnfrRi"
+         + "i1okrz8JR6SZrsPfPvhJBVrM41kOFl2D1685lXFai4I6KvaLHclcNFHbZOj+yS2uURCYDiDZFIV+Iz1PRHqgiuh5M48hogk+4tWkL9wHQaP7EB6cSkPo19Ef"
+         + "DIFAdscRvxoOkKvbogSnUCnK1rhvZcYtK2U4z9+0S/FJqnEmCIJVcksG67/6Vd44h84PsOVnOUAI3px6nkcLodUSGy54ZjA+KRX3QJM2zl+NmVmMTdUF0kuI"
+         + "dCQvebG4dkkg+I8SNvEU2RC6u3W4AOvzSPs/U0sPuxwe5b1UtLApfCaoFlIF+VMTIkj41Eld03Yjek/Kvo1Wkugc1Lq709s2P7qg5k0OcXkj3UYv8xe2LnpP"
+         + "5otUrryrpQcR4W8ZZ9bBiKPg71/KKUknA0K5Fgl8h50rhvrYrfgg4lcWj2vNGYj9CmlO21xFMLpurcZ/qqgVFcAJWCRVf591XuNlK7+o1tyI+D/Yrx+Lf5QX"
+         + "wwxIpH/v2ArUH7MNQmeFPArJiAqxw56GlJdTHc2ZQi+o6yf0mLCGu1qG+04X0fq0XJCTmHAGv9J+FbtbulNHObQXF714Jufm2OwN7k5+7iuv1LbM3FVyyE7F"
+         + "ZGiumw9jlf+K6pVHu/nAcuTCAP/K5NFrPArlGzVR74Hd3FhbvCxA4g1HjLdpls4qzSDcKPltscpttl94s54oF/k5Ei6PyikrmugM0mKwAm2cOQORcTX5PzVd"
+         + "ZFZKrDdXr5W00m03NfZ5ksOJjcYhnwuuKjko3ntBSBkpypIkZWw1NI+ASHQVi44nX2b967IYbX0D91/EPHq6kfOSTxBZKJb2XclczpjgdlbkrKXyAIIu34xF"
+         + "szUQ0CABBYLsWALkuAj77cZ9soyukcuF329eFnT+axn+jazYFg8vsw+BPcgH8JdW5kVazcyG+/kgTXA+ioWsmdpPGRvv4MzjtfxnIxSdXvVDlEDVMt0xuFlA"
+         + "oayUyyYkl7TH9yK/BeScj71WLQaPWLp0RI1YXVeuxHcecbXD59IdPou1dCCQFRuS2wJe9AdsywVPUba7eKeE9sK2cNs4e6CHS95aQf5F8Kt01xbClQpZoYlR"
+         + "OeTZLwfd8u214Vq7OIfdv5+/XnkXnO6XFOa7xMCMklKYEw+BybvD57MHj4QAqw6OMVeqRelPbuSgs8r1rQdqa2BbbOEqdtnvruh5N1VazZX4xwEt33Q55wa3"
+         + "R2Clfl34cWmiRHV8qqLdhmkMmTRRywGBy1GNSYIYFoVRohGjQXtKLe+EfVLcEn8V1rLTijcxaDccsjjLDpvOHxgkWdPZlweSU29P/F9zUVzVOb7vTfq6OMB2"
+         + "iveWiwhSq+/7Py6FTpchM+S6Sl5af2f1loNYzRr8O0CC+Cvi2fC5oUiNq3caGNdUt4fGiuAuQNbdV+65EfdYIldzCNIwaH4Ii+ooljsWhEFvPLT1Zex964J4"
+         + "/Bf5FAm3bYoSj/43WtmIipmExcPOA1Ql/PBWRyglXJ7eHIgO0MwVg4oGU8DEsk2NxCL3iW0meXXbs+8xqRyIkO9HawLUpbINJm45f2DRfDk7iuVMtQUv+aby"
+         + "KZQm/oxsu1xYdbxkPrQ0QMxVcRQ1nFd+rXuCZvTlHhwEEtgvL02By6oDp21zyEc7w5veDNHK8YHt5Vn7hKG2dwU6ytZ9ZgExAFKBGcP8x8bXiR5/oimq+7xt"
+         + "meq1HCinngHc7ZeiCmVHURIDHr0cwrSfkhQRGuOtFw9pFkSgd4UyyaShSqN81ZSLKx3UJZpXPAseaWMlcJa3x0A/QJzMZPGM0B38s35fLvW/aB1fUmKLsmIk"
+         + "91cX3Z5sp96LzGOwbwIBzCHNhgukmyvoql8Dn9BIGTjlxICmFaOL8EoahhceJMAENauO7spT7Qx5gGZgzRQZKvdzAPq+dqhngL8ZEwWJPo8/MYqBvM39zHpb"
+         + "SLuN29+VBLNARNM4md9J9JQkPGQYy3OO9X7DrUhgIRHwEuqTM8SunsHMAiOji75L99btSteHHY+J/Xoi5PZ1MhNvgxCzaoU+cY04TQHhyYBjZl5sihNJaMQN"
+         + "7eIZ4dXEQ+P710KOyVOw0k3simOF7e5ivA7p/3MeYt9eyewkdfNZh7d3ypyhcWTBTaxkh+g0EboEEF+lbp/kyGg5qapvXu1MDPC4JEhgpiU+02AD55yVAVtd"
+         + "c4k7D8jgBmEdYAZMVKI3XJ69LuM1IXE6OwuEkiOiN8d6GQ8UuElpK1tblB2pvIZh7fhKgh44L+7FySPzRD56SmbmKLU6DN/dAS2mFwbdOqmAnzOPi8+tzYq8"
+         + "w2kzpuOHiJwSW0madQDsf5V0FyEwCd0yxdrN+rxuJcij/dCOsHaluuq6KP1I+uf7F247X5FN+l1Lw+PPzfuWtgcaaRbmxxHAeYbWIfbEe5UHhLnQspe8J3HE"
+         + "CKe8Khc+Q2CnRRUF1+MkMvt/moWj5hwyx31TSR0lQCTbRpI1/5IVtSrqWaFny5xqX5YWNZcMfQll7pRmqJhjJ3N2kTs5LlpOkXjN/GsFtlWDB4OTmRr8+PqA"
+         + "cRonw5FaxaUo7fL534wyVlZ7axdn0arejYk3M6n2qGZOR20IQ+6S7DR4saAtv2auEjDBaUrjJqiBv9ZeWbmL8PlDTN8IMI+hkXLCYzs7v2smfFzGR+97JocT"
+         + "rRQ1BCgy4vZYZ/AIwPcbkATmcuFKIEREK+L2Wfm5Sr6hBQtzDnd9Cgo/sl9Y7mOPeRakwmiiv+WsCZKNMbj3MWuaQDLQ1CVlCsIFo6tV3oG1c+icPBz9+Xb3"
+         + "m98BOROatLWLKuFcNdVD2+XGy3n2BBF7HaKMZjqGYS+vt2EXxL75LIbEvMhFtaILgXGeXuYPhxMKLemWM9hUvCLjGSopb/RAYBcv8f3A/YCjIJIRYXzdUZs6"
+         + "waPjT666Mlmjsj/fZkH019qaLEUV/bXkHpGjppknjx+yJDN5AknVe2CJ7ZI3nD8iSgmrug2TsKKqYJCmVGaeB5g2abDCOi4Unlz4p3pm6y+O5rcIMgIZmDwF"
+         + "uQexqQy2Ub4GrxjUcn7G52EjOTsAgYtu7jxQARVcUrB1pnORiOonaEsYzoz5D1hZv/E6LQlsGSod92/mz0fLnwJ5YiLjEbrHJ381sc8U2XJgeDS1o7svXN6N"
+         + "lJ1FQ8hNdL4kn0ULL/dxkeo9704W7dCDVW7/asvQF5DVmrwaaHiwfzY6TQSZtPw4Q9/qPb/a+cvzxcfR/Yf1I9M42F3frPr5VTpcA6hYNyMTnpok4sISm4ed"
+         + "D9xBtX6oX7z8tryg9UmF76CanSmi1Z8SWTTOKIRmgpa2vFc+L8y3JW+z51/3oDQ90C3ZRfxS+ttaZZ73qPFx2OK85JVhyiWDy7QFjlyzqyH8W4EHDJvjNHEX"
+         + "bgT/qUxYgIgPWOgbTXT3+KNZJvfuZjQBMh3kymJUy8DWb3VOWkYXinxqWV/0LsokXWcgiz4NiQomK8gKeGoXHtbeUI1KJu3anPaYf/THYmd7jwu0UTTI/34p"
+         + "JbQZ1/Xg+l9Ah475YJU5/8voaUki3kTCRvUI1ZwFE7Ao5ov8BVEnVWJq+f9zoLYxjS7cifOfEg498acs7Ll9htb8PCfF/Y9lQodAxeImUdSeuom6pYORie6m"
+         + "/qVFDMhq5vGgGXfeUsRun4htJwUteFgHe0YF7mpQrRoQXjGIadG0NXl1cJJv9hthBcFmY1KcPNdgQXCt13z5vCkj+kXa3+Ta9nL0VjBpa3ysuh3c9T0apdOx"
+         + "1AQ8dQ5gSgDy+9l8hyZGVdWCEJ6L6bRwsw7YMS+ChvhXjp9sE4lSg7BhRtRvW1kPFRJDFwDJiXYgqTPKqGELFSwEfO6+e/K23iH27KBZtoidKsdlTTJcrNsf"
+         + "So/dsYr1zaepVkXsYb/VnL81VMefPQKyW9nz41lNN4/M7GK9zAumwN934An4jQDe90mBuwPaXjmaYofPJCG0SkXw6zlKQqinH97dGWrTnr2fbVKOmE8HRUU2"
+         + "pybHXVPy2NcEi35YiLE9KVQZkz56+m5jgD8BAa+jvD+g1TG74HepoRDBlQh1PzM2K8BMxziSGDNfRIVxSlOkWLeK9UhNYR3+x61JjGqaRqmeF9lKZPAbHAIK"
+         + "ZLQKUvyQvKhTxBcVobKbI4wHfickIZc1VcF4bYx5hvjTxe1SSpsS2CCnQs81RjeV/NAnDJpBOjV9PSLiqtJU845wqi79yMEAI+7iiOgCyBZcz9kOHpwRSGoZ"
+         + "NhzuyQN1C/h5P/Sbu7MieS/0/RkZDfXFb6+5rE/nOG40D6ePqQqSWbrcmRgnziNW51NIWgvJJRGuI6dBdo/tMnZZzvZ5NOEfFRVJ3fnpDGAVpXPOZImDRfvM"
+         + "Ow+hpZfRXqTEmjp3OD/K5qJTubygvUbYlH3gLVwe5X7S6QQBdBM2smcLTDgzbitsPu+bXbZnJPL0BEcmQCAda3+aOOPVJ/9Y+C4b4ZR6HqKGbj5oEhiK7h9S"
+         + "1QXmouL1jwue+yCp9HWhs5Onwlch3hPZ11gUXoquIjQiIKDQBidrDelimXmWm+YB34Xf1yDMKrQW5omwLAh6gq72is5ZP+q9O3ST9PE/dzlltRoasioycA6D"
+         + "Ro6ZrTKUadVPIiZOj8ID0FrgBQ6KJnbSNYl65TYA7DYubudYwPB2J7uuNASqJChdc/cDOzvXdJQGmKuUdbk04OMBiXnqUTYgDR0eYu4ZW6GTG6YCApi9Obtd"
+         + "63igSoEYENMZzStiYX50E0sgRFJJvLqJryfEoYqfaXXH3OFr0/EFiBi4BO3hghTWGQ3tsih0msz9Uy+bGkoKp86BP2zKJeneZt98E+1Pps7jzy9M/Xz5A1xz"
+         + "3BXsiDHutOycRKojsOGVQ2C8JjJzn+yrxkLIZqufsVA7gW33vmvThNiBswKrhvCPk5G6B5azicgTkia5Gz8yftbYRwjxao/dvF0q058SXS4UVUmnWREKcxN9"
+         + "vMIu9IgKk7Bnlt3lUByzVgR7gmQhjH3KPr87jsGFXAsmE3xLU9D5hRl98fKvdMOYJStE/LZZwSvyg86qeo6YU0vBALObG0Jsuhx1NFfAS1peM92/OzOwnoZ0"
+         + "Bzy1+Tms+s61+drHDwCiQG7S6KxatGfkJVgDZzv77HB0pZMxXkJHfXngE5Dl8jdBJEVDKCpb8usyLJ+G3bnKfzNkw5eR/vVUnts/tCwo7SP4qlx0rYe/A9Ch"
+         + "MLP6TZphmz5pzfaMDwiiQM+5kAxh6QEMIlOAe+2FTPvo9ki9UrsTcYDl715ty1XNOnYlNbFhTbtWmj6rRGEl/HeAguoo4zAUrk6A6+4+9LpS8QgON14tP12C"
+         + "AB1hXtJOACy/DLsk68eM0RmufI3cB/S0tP2Fl+PO72bqzYO3e+gx4uwO18L5RpgAJ2NJhowoqxBoYQgCnZhpdDaTDWLHavP8mewLpK+EiPv6GjWBzkIa6Q+e"
+         + "6w9hKLDI5B2Uo3nVaAPf51NXlqiLlsogoUNu+p2Cq9y4p1kppub+Md3yr10G7+OirkB1a3prAenZu5/Ege7dump4U9EO47RvwOVbeMwb8eXgKMsUb0fzyY17"
+         + "9PbT/SNwF0HhI2lJfzjkMd9j7naqRdYv56FfhxtXuQrVFbBm1/9IIYzHljKdAQ2ZjcBVBmYCIUCa9pwnlvXkig2t+SmWThIek4P1IJHhVSESUlJAdbG19GlA"
+         + "lv5LY5pq6Yb3gjrhi/CYa5d6cxX3XfFZY5HPKZ+2g8VOYjpe3K8JsmZZ0RmqWALHI9JwFJuFZV05sdviIFvfVrS/cqRihpZMVoIWXjuUXAm/wlN/mGb+8pc4"
+         + "VLGaOpnM8VjoFeAPaLnySLEMvrBdpzv1j4gYbnGm7TDtnguWHu/RtWIrOWsg/eeyVzyxqeVWRZRxDK7l7Fnv1kRlVZ+AgebzOKEWRfJ934OnGCA9TqI/jgG4"
+         + "02T9l0yfFaSozyASHRW7ZOyYpe6eXp+egopl/bTGR+Ipcnsjt+6f2MBXTNo/yUczHLZB+Jsa9/lSjpcOq4/293xqe1wnC0Qqa6Blar2BoRhHvynUEDLskVku"
+         + "UfVfvckIG0qzoFeA/wAplBxMNQUFGHy55N2puMRPj2u1IXZMkUElkL4M5yqhs+TJVpGN9/LuIxzsGo1Kw8rCUYDJtPudRKaBLYj33XIXaMBrhpQuEU8GKy3c"
+         + "0DMdXsQCZwaZP0BnDYySKemHnE0S6rul4b8dZQqI0A2yecIZ9ojz6coSFFIhsZFJPCQFENWIR7fCWTgazlgoNuAK2R/hyDj2Ias/YEK/B7TMs+8ZpqcfBuxp"
+         + "vyCqyqXrc2HgxMPX6ZjZ2rL9Ayg3I9DFmE2LZrkbwHx2/LOQBadHI6FTnUVytontFVzpMknOkrhZBZpy4ZB9ReMLkKnpv+Y8+bXf+0gInuhYFWNhEF987n07"
+         + "PgE0gEAwaDPoIAeravJXNOza+p99syqtduzVCqPpaT8ZY+WP223ulxoUm+7vI4db7bxUS5XUXbfYSHrBMPwo36CKnqQ10BMqCLGc4EmUvFWXM+WqtqDUAzJo"
+         + "exRSlRmihNJo9mJUo6Azqc8Zw2Jc7Hxt3McW8nFa3HK5WyY4zJ+jBDg2ybmSBQfYEyedT7laHQCpVIhXS8ecQqHparSCf1uuJGH6SBh1ZFTtW2v1sYlOcE6A"
+         + "+JgkJUw+LXShtCXkn07Gp+pZEy1UyWwkg80jIVk+Jw51X6Ft9e7qyjQYE5PqlXOmiG0az24E31EEx2ZUTXo4NGiZAoS+yuKxNpL1KaQokdfdh9NU+/UWA+N6"
+         + "QfUzRALTn/vinCv9S5kI4l2IwUE9SluRXUQ91/59FyYiom7zxoG7+uGfYVyoJJhohWPCxNpoP+qtIBti3NJj9cnnXg0wrkm/+70zxOqnjI7fBova6D1suJwZ"
+         + "6PFfhd83LGNKrh7A53+sIhZ+Y6oSsq1b+q1Mm1SUHFNm6oxcjA/om66vEGcq/ybtUze3P90hkn18HKY47lwPDsqvjEXV/7hEoDkEKxaWsJ/JuRgQPi4q2Y/R"
+         + "7ecjdiLSI5i3qSv3KFlKAGRirNbI95ZghB5RGVWT3/ip6blyeMbTsoXVhgCwl6ekXA5Su39SVk+QwwcL7IyP+zakgSumZn2VOsHQp/MZJVLbvmPqirO/au3e"
+         + "x0zb/Z0lcNp48reTnSI9C6p/7JlFclrOYffMspdI3zTlleT9zdNxPQCamL2i2+69j/A6v6VxseKBffN9etzOmUhcaSiv5/ozmOsAgRkHRr3fyAmLplVWdzzE"
+         + "KCbhwq8TNcqBwkyDuNBakERhKzCVctgG5E9s7mx1Rbl1oFOyinQtYvCpV1imWyQ9k/JleAGgtyWszTiWFR3fBt3swNv4eIGV7YvZs9/VCcpMYeLsQoAeFc81"
+         + "eEjAsr12kbqmG8HiOi0kWDlXb2LATsqFrpbbGI9I3b9xA//OC4QW6tYs2BGAiylLSifKeml0vtTtqF9c+iLT6SqzNIJtKBoFR/6f3g3W0h7YJ24P0Ufm9ppu"
+         + "sXbZER2EuPmqrb3CRKKpS50e5Abf7DIu/jFxv36/luQjo1jYxoDcaFbNlASERJ8ZTKk2n3NqetJ+Apii7gQpqiieDsHIZaOilNBvt0rxZuA52jnjzvLd8fsl"
+         + "SyTEBi8Crl9cOyyf6F8jZfxtKiAV3H8bZr+smAUSLwjlaJ1Pan1hpUPWrT0V+tMQlWMFhhRAeavDIjuXLNseLsbVA3VhpqzpiuPP+F43fYF2vWslC7TsTmko"
+         + "vrKnTQ0yZZqQHjXR+/o9Pxp3B0QGSGcvlXYj47vDnodCbzpgevOE3OD3AZF2pg0ZXfXPKVAI/GrG/0r96YkyPBPJi9e1/eG81EFb5eHIqwVPhTrNSflsqV4x"
+         + "Q+9PfA5hCxtN6vqsIbEosB5lBtjj9R7N8jRmj7f6KZRd4rC//E+/9GSS4wTHHfCG5uEpss+iFHI8++MS7Me0iFkgTtRfXktITgYyUUMt+UfGAthgVNpj9aWB"
+         + "1WvHHM1meFYNDaIFRnWaGY1XuQ7fVCTesOjALnnQkRvZMWiH3mRtqUlLCN8jEunQfwW9ZqWAtQVDEWqgxOo4mnf/kS1eRVshPu2gRl+OYO8Wtf87eC2wEgz0"
+         + "SgA6oz9/8OWsAhzKnz4E3xoTQETR47nqLPqnvyX1dfvdlOg6XK3pmSPNtaWqWYcKHrt0J/WtKgGJQirimoTizeAUCO99ZA0dcUF+pdU9u1U+BKcdCSaPcJdX"
+         + "qH/fummZoHY0rwx9HrEXtNjD+RvQ6uX3qsrEr6LVOlofi2DAE6vtINsyBMSsM0rqyZtYfo4iWIJ5jrwV9F/kFcCwKi2mb3YwLp70Q1XkwqwEB4wo2ecX8sAS"
+         + "FjlD1mTCSdi5aTnBu+dNll7/HwlCPCi+MzrYF15eAXabaQcBJ4RIfRoEAMmJBOu2GTl38U0SIe/PXMJcCmKOvxN0NrG72ERGqcSGD1x65kgC5z8obURh9Ahu"
+         + "lWzbiQqIp839RlXGHHGu+1hVCrUfLYLyvJ9uhJq2CyYHa3eZxWzDm15aPA1/uk2ig3GlZ92zNY32e0ILdy4bZcqoaL6qLzqSRzTA/nhH5EpWchBJrVX4+KjR"
+         + "Nkx4IfhB0PZv67lFwIysYoOAdf7wGIjlNyiQoIdBhecLsYxfin0MNgrjP3fy7ity7CvOKxwl5uZkM1TZEBG7uzfMdJj8iEBeRpXtTaNR6tSjzJLO3O6naDTF"
+         + "EnClof255Lb8nMF2rdqQ2obxb1iAjNkUBenDmYe6+lFmNoFbY4p3okyWSCgeJIGGB7cYwyoZtXcFOxL/dDeHcvDODDhdt5vmjRzhQLJ4DCSbi7l830gPr7rt"
+         + "vPiSeeu160MAc4hGdsWI9mtYTi8P7hAI1a5JftKID3laW+knEcgDKoCzHEe1geTvJ5inHGsovd9+keFkc52cFqObwk8UOSmDVHjccqy4iBUBAm35ldnMn7zI"
+         + "nhFxKAwBwTBaVtJaTshIxb6UOXCIsSOLDzyGOJLroiwYCU60obWUxfnfwfATI86MvZYHv7cJPOmq1t88gGpck/2AtBTBVf7YIiHWcx4BMMn21HkjyzwBKTmb"
+         + "3nOLYEnfUYq/kneu4di3A4QEzMQ4kBdzSSMHLxYo2u01ffljOtS851wLhxbiqB2Th06iHRcCr2ZH++JyEkvoCM6YZ/vhZStysKnRtZDIOutUa+CS2Zpl+2gk"
+         + "Ie5vuBXbDsN07lAnAf56Bm+KFWlkmqHAaz7wwkhEhNmTNkC1VceinbOVWT5rwonhL0a9ywoH+Ci2jfkr41UOPNdr/stitW7XFXIzzouBCuhHeysNVTQw8iVP"
+         + "vfOG0qpEHtumIRJQpw9v+XwCnH6KijmSkqkWj3xzcQKphPb8/wSnlrOPHBs5RzzegghOC8treWkzWg7uKjapf+hDx1y+SrUE3t7SiRw2DDnIdBJgkrc05c/N"
+         + "HeHFC7ysai9gcu6yGJz27B0FKoBLRFQqFRTVnFWzd3U7V8Mx712CBZQ6iWCo9CKuHm2WzW8wKHQgBhxU5ghXkS+d5KcJl3ORAs9EBKzZvgfm4YcFFAT9rDKa"
+         + "TbkIGL5d+oOd94YYMs1vDk0LGj5GzHGjsvR8gYbX/V1AHKKs0UChsGr98xkpmmgoP1y/xK0NykBvFCXmbHw1H4yCXCSyhzAxmwETl15zH4M3U5wb5b4I7WrQ"
+         + "ehXg3haWU4yHTvMPh4LmlVWT4t5JkE1kAX5bEfmeOovIhiH6ONvF//oNH2vP1700vWTycmkRUJoF8B+UW3rksnDVsC5Sj9De9SKt1gAvHm2qAoIpYgfRA4T9"
+         + "2EBCtq8RDQOe4/KeGOzxcI/FSCRnK1YoOHSC5FW4x3L3lIRoCDYrr1IF9eCyI2qz7UPW7L3FRcbu0TH/dfJHnUEpcFUaVNSQRu8ULbpzvvrWyuekA/GnIn1T"
+         + "RG7PkUK2kQzYgfAAykkbOPN1v4yUuvIfPlWrWBYjXs76UQF9LI1ttH3WqAqlu7qtLfmkLw/3uO9mCtcIwqPAY4HORKHtYdClBHEMSzdvwv4KycURoWwcie22"
+         + "dlcdrb/YpU7QL2ntgLzUrl2PUo8m6uak2LgXdkrLL1AOMNigiQ8i39KKLdQ/ZYvcbnuaowGX/iyYy4wlWLRgRVUkN9S0abzoRvcT7qkrJ0kGyIgUXsOa27gf"
+         + "+H+Htw6tSOFeL5oEkLU3l2zO/VJVUmkWAxDJWw9PDrjFd5eTmKqyC/mCG4XXZW+h84tFLIpUvwV1jBDE7FB+Rc2w6O/acnYmBtnGSq1XxyHcw+H+CWMlcHg0"
+         + "Un1TjWqF0lEeReWQllkxMxR1o+TIhNrFiTq2pmpoFUiYgMejkRtPaFdeSL9l0HeZpeEz8DOL/rVu8hqeSYRDq73NGhY8GqKRn5GEIQCZs3CeNfKEbr7rkn6v"
+         + "+SF63RE91zN2ZHhY0xPGoz5K8NDCz0lMcgxU/fsGxSmvvX0hnJD4bqQN9osq8rGL7aOuc/cpzDPZX1DkBtn0mK7/txAYAryCJcLU0BmfJxJSH0sPi6tVXOjC"
+         + "yFGRCnsjUKzNNssxzWplYVPhmc6KpGM3Xh8Mo+Ke8MgtUOGO2WjWcSlXXAraQHNYtjIbk2zbpBZVrCzhyPiyRdR40p1u+RK8ty9Ymu/IX7hxkOyoy+zY18WR"
+         + "wMW0j1NS3wSL/ox1ss9LGCsue0Vmo7K2S+ubo79Fe8b7tJUdmU+FFLrmkGfwPz1ROrgyVjp3lC7OxNqe2yVZDD5KOUb4T4TMVV016Ky6ssDLWXZc4VIAPwP2"
+         + "VLqskCy5wKQyJHqN6UDIMlCcqK/i4nM++6lZaC/CDnWmW/djwN14bmwoiyyl8neLeySwbVFJ6CaLvPgxygNDeL/Jr2jjZQfWgyo2rs4tX8Ia7vq4pBCtnkDs"
+         + "mvOgCGHPb6Bs+uWRdubfKVZfQl2uuYk5c41bwe1iYazlAd+mPIXbsja95ltLFO0MHivOTlppdf9Hw+UoWyrsgKxsIPNkCtvyexcl6lT49U8QHl0mN8C6J3Gj"
+         + "Hc8d1JC7olxbvromovJPf4dlCVRCaOIT7bqJnQjnbPyxBB4rO3dAiZLNQ1mhSthWfXIkDafthFuL+okceTxTxhyIgTAUQuTCHQHY5Kkdz1UiImmujNZJTqYS"
+         + "bw7756ZJ8bhfL2OrVumWqBKWeCa2D8EvYUFqfImxZSxpCpgG3E11tt3sKQ4ILWDS7iWLE37ckhfDjUvb0ZcMQcYXF0BCQz/IWTy9wtMXuHHTbsWAfwElgGAw"
+         + "UCqCMYNBY0XjncSwT6b+YE7BVRFVRrchLHOcLJdcV7B3nV5dg0Ah8BiL6fPwWVlvYePjdbaP+JIwmIh1HL1DszZylVZpQl9GI+3yWpsA0dLdoqHmhD01Lzmy"
+         + "b588XYUTPDFSV8BfVG7/hqdUIV8H58EcciTqjXReGSS/lFX4H+xBgNQH2yxU1uuoO5Lds4cHBp/QGCUDEa3Df/YilqSahxMpph8xA848avpfuj4lXeaAd9h+"
+         + "o/46be7/7sEuI8Su6P2N/hzLFTWuM39KFw0fe/pjqxfNoHbK4X7cdp8xz18rASCcNMyNwTnqnRiiiUbAoQWsN7DHBRMhma9pB/EH0KeddRZI8abrqjyh2nDa"
+         + "4C2MPUgCR7fH2Np1lLoYKsh2AV9tN73jncluBqlIbEjqctW0jaLogNykV7ZzaAw8e30zTmzAMgSPwbY40fklsWnyZRmA3J6KANz5EaPVi2RxYYZfv4t+pikX"
+         + "uyHWOUlqNp6EBRDLi9K4VC0r0WWM2v7HIGRZhu0UIsAymZQSS4f3ivpPYETFiBvrQEqu5YNtVrRaj4ZmMyLVsMjmG0vkCIJ/oiwPwRQjinElGhTEM5WoB0kl"
+         + "eb1+4mhzZ5333PNJshT9paEikmMH1PRe8LLBY091T4B+BcUxgM4m1rexM15jMX42moHq2SdR/pj90plObwAzk6VLGEs7Ojpe5wta9nWDP60rftDg9hfm+GKt"
+         + "xLRvXIYnN0HhyihK2lMa5JtnBR0QKPApI6ksM/+53/qvLlgO8Vsea4IsElFozgqcRrlMlRk+/Q5G+2YxpmQ2HSiuUCswxVxdeoQqkRmh8Mp1noElsGbIiwwc"
+         + "8ial/Z7zFDmQSAkZ/iR4rDo7/pu2a3k+MOM2vcSjpCmkLtwmeRTRqd6YbZXLOKrdAzzcGc+65xcsyjmrUOQ0wCyjy0A3zc4oNtxStMhZvA2oqSiBT+8fGWwj"
+         + "rCWzshaI6NWSnQpzCjYt6SbDw+kliD6Vx2F8JHHmQwPpenYNvkNmUAQWLsbhsbI9U3a4nF/rlZvUQ1qZx7J9cPKB62B2DVK0RpbpFyxFzdbLTjS3espK53go"
+         + "OChQJZxyL3U1zsdMPz3LLKHGc8tgVJKUM0/ZPyNvLMbVauGFDhG53U62/uXprI/7mYO2AIPLRjXd8RLqG891tGvmoHkDMDcAyixPO/n1Zt+e4iB9huO/tR5p"
+         + "wIgCgymEU0HLH6uJtpJYfUX+Kr5WQ9AhdPio21wPWHyNA3rcK5j11v+06pxd/+lLysuqLIljbAqiYBxIzxD5yrbHZz5K9NvxtcCKFJFJWnL7Zu2wcV/XcJUo"
+         + "46X5fT7cbEg0Uye10A6q1aFvn/4V488oPfzLp8244EY5/CBNxeGW0t9hEk3I8vfUbKTisRs4C3lnknmhZaQ/mPgqtRLcaKqgAKnbaED7oaJEhSyq/R9SH72u"
+         + "D3YTzmChCawj8wpNc+AHNai5qWdSEc0LR6Oi3DGH9OHBGSe4/aHle+l0RwwvyF+cEqQpnTJPoV+W5/poQxP0jtm1NQi3zc20w/Q8UYbjNEhNUZy3YKkQfxbg"
+         + "EVXcQ2r5ZGrFaJfHybaaEyPh0CYCB5MO638Q1kVKMjouWyP+jWLooZUjsiN6Wh/kRsAChmLmHPQng5bsxgUk1ar4nISpOgyI92gikjqE6Q4wlwF6FBjoUUOr"
+         + "K/+2GICj6bDfYjXelwdDSCvuVlDL9b29RiXN0FivvACDLxzCcVQ0HgQh5zjwtV2oRiiJz0Gdhkh+MbTWEIE4tcXmYwX42TDsVQfe4Ms4gRBCjFL2syq6zKwf"
+         + "UgdrALc2eVEd3ui6W9s/Ji4uKFvxMDq4YTajuXrrtGXIU9HPrUwb3GpS+tIZ0qmHdMbbeI/XDkqAjGn0HmiEWu3hT9fT35tEHqt0gugb9PhCdrF1ldi66Ixd"
+         + "ubPu1122XAB+u7rruHk4b5t1bOOmdJM7PEwKo+K3sFYAUD6hcgCIWqSDNU+SZaeXEAZ69ZPMLSCKHvipseqqqsTAqG7BbAViDZ6k83oyDAhuuCjTWo3erkDm"
+         + "GFrWmB816aKjTutzeLN6s4A7fwQLblhK0LpCSrrVBBIg9L31M1N2zNQnOKRkORkMwlLtpCYE0ZMgwScuvjUe38KA2pqE7I57wTHsVGHkGuWmkb6mfrxo88HA"
+         + "wlPXMW9CDyOa+C7r69oEIAnL5euoLCunTI0V4s1e9pz2Xi+VdLZc5ZJuTf1reX56Jhzg0Kwl8nvs0vlV9SEL9Tyuopy0ATj4C2OuQUKHJQGe84wDAV6dx4ho"
+         + "XEr9I/10ZdK+AQFqu+luqESNGCKkMislJiAKG+EsHsJ+vqagP5pLOnm4NK+NpJszVYL/fijREcMXOgd9EAJ6HrKtf/C/Vx3GUP95jxXVB3Wi9BJIOe56cU+F"
+         + "JtVVQ6R9w1kD/2vah6qHDdCl3kd2wHaFJ34PUBy21kJeU1k7R3O9j3BG09u53/Kx60WE3amH2SeJmUyYunBmvzVQTducnO2IST7IV/ArmTvgMFlIJPfgR+mo"
+         + "+jsuLpLOW6GcLYZQS+a6UktbkBdyeFSRCGq6qF3faxWsulI57+H7/RKsrQ4OP5rxRbMo+nCuaPMWXEHeS3/q8Njz9/Sud7iDeZ60Ks9tfVrs0Mym/AIYjKcS"
+         + "ZEl89A8Lf802AZ7j6Op18lS5OEP3BKEGleTIuJXOlnoNeQMD3F1j8YVFyH0R7vqATaE0mu5/V0WV9zQSFrm2CoxBFpGRcuGKb+OpAuWHXjSfHc5FFLzxrkUC"
+         + "KIiG4jSR2ErIdt4ft4TPkRfofjQA5WHvq+Z0qY/vcnH4FzALPlITkbdHGfShuMZhNSTuzwfP1GAgmXsFNpbJiGPNrrvPTJbm3AVLXxLLSHTjQu9cM7cLZ0zq"
+         + "SSUxpI3nMuzyeETh+i16q2iIcdHrL3wcfRUp+MrxcgjQsyxIfregiLsqnR/vTrlYUOQJQ23hO50QeqKSVCFTkWF0SPrIJoHA5vzeMo8fZaH2FOTJ0w7HqWAh"
+         + "+dXFVAktXrKaDt1cvbvnnaclEb7xqFy/JNa7eDVnGu8lhhp2vsz20TmH8l3kVq/t9RGbAiN+RwUESNUcOBSo8GpfBOddmj2AF4XVALB9sY+2u0p68ABJQPw2"
+         + "fEVfvbpJTzu/oj9QwAgWhMearjsFcCKoClxLe42SUIHFGZznkBfQ2yZ9qBxh9POvaR+0Vt7cUaVY1qsVv67mE6tApP4cxpAxFqBhCmalVQMuUPYw8HPXaL6R"
+         + "fNF6d4WGxGTPj519yeFAnTC8XqNW+4r7jzNZQi6FWhpxHCsHl9AwX/hvyb4pNB0l+AI5BbJjmwrNetVjhOAVp/ofB8URV/xcT7jwaRxm57/lFjfhnGJWfIh0"
+         + "AG/qaf29Hwgviq+CeSwCFwImVu04yoxXhhOtdhIaNPkJDH2r+/yv8TVwSFZqKpWsZXnNX6sSBYknZbCCsvZVwGkaqlJf160bDTVtINW6on8sXOaURIgLzfee"
+         + "4gZRnvru6F59Cm4l6SlsoXdpOo1f1hwfZSZlweKo5m2b8pyzhq6UVtGJSMIFpfonqxWjXCcoCIoT03ADSVSO+CVI7EOd5OKrcZRaI35J1VJ9em3XTzWeVGsa"
+         + "hEOhVjHLmxs+Ywx5lGkffXmV/pXF6jkE8IHGZiPewJp1wFaYcIY/9Il5detJ3S6wKI2JFwsnQ3WN5mXd2ArOmTw9gaK+8G/rcRtzQoGq/qoVkF3UzrqaPBUm"
+         + "h+IA/xMp5bc8QJQpsEsYBzS65ILFyH9vHME9x6vJMa5AnKVYtV81H2vdxFJYtzBUu8ytQ0NTwhDbvrjgoG0agbR+kv2oN8lOowgvPyuQGuxu5cZYJzKiEkmj"
+         + "7yWieJ3AaztPYVnQtPLyXXRn5XwF54sgAMjhih50Fh9Z3nVWi/JcdrFt1amgLuYR3wSRwJN3L5TK3cSSF/8sSVpgc1s8iZ0gcn51a+Yy6KYxUIL6uSMNoY4C"
+         + "Wo8vcNLZpJQ0iI2PqFwIHxTJN/dneaP2PC/M8SsOKZ/lKsHGvNh6Y9bYZm6bo6JjnHm7gHMaldelcRc/DoFbsyhtI1uXunxttxOR8F3UsANRoOvhkQW2hwWp"
+         + "JFb3PMJGIyAsPSm48aaHqsFpGIn8E/myaNYCQcp/zrbAWJNaEldf3MOB+d2rEgvgHJcyX2PAH7XaZEWnGreZaI6iOF5ARzRWdakt+uThPpls8jOfQEHQlPiY"
+         + "w6N6ZKmmlKQVbZwMo0TZcGbXWgy6jp4C5rQ/Eq1t1XwMrVCqfl57Sl31cP/mTFv9dMwUeZyHzcfCxOU44oo1JMhAT1MWC5Hj0xJs9I6smEihiamf5dcZsmNQ"
+         + "xKpIux6Jewov+BXCQf6kCFuqdMeh7JWBo6u1nNKSBnYhjMsTfu3dDvLtdPuO4/mf07srOZ4hL8HNhamE/pdlRM/+dQ13fbZYFTtddsDEmzJfnh9FFsHp1gXZ"
+         + "AlesUR4VJVAqqyBsWhUSPKa/y8T7N9a2uFATPwVuy4SL5rbWYKnZeaLb2WHRq24s3GIWYZaUfUrwoMEC+eFzmw2QytZOvN6xnDTSHcIx7AXP+31pOCzobZ9c"
+         + "bUkl7YXieH2az5/uUW3uqv9KE1B/b9XXlzKZxlvWaZFD6J5aPPAtAHHL2RbULAfpOEEhwDQpxmCXXANMJq8XT6bXEIMOtIehIjEu8RBGP1Pqn9nvaReNuTJk"
+         + "9drF/tExr1uJUDQcI5mmDf0ZQQOtHSKxrDDE/vtaGuvImVEo2F5fOsN1ejGQHBsDrawICCq7pZ2ToB+c2jL1F/ek0abQ5CYk0zF6Q/kw2SEPVTrKYV2JTaaA"
+         + "2Nx38opz+GaDh/azM5TZI7FMySSiyxw0POVPZcGaptupmT2FkD39c7ZDAxLwsLBoS1XbJuNXNVQ90cJEzTpydOl188TeYpj2E1uvmfARPDV6XMCFAxRGmqkg"
+         + "wy3HWhjbeIYuHCulwHRjI/vL35JhBAQgHXw5FaD+p4JlZW4HQvwhH1zSIaInY78ypuIcqa0iEVfP9Soh8LKq81mGf8uWgXx5rtwfTi2seGrIWyTVDNjyi5k3"
+         + "+iA0mlzla6Yi1BlEpdk++NmGHF4JcR9ZdZ+8GGqivdvo5sW+3zJTJ0q4fFxADacsrORrZvJRkz60xOwnlwWdu+ybQkPCrVBjB9IdVbfhoWYhvde4A5+pL/Il"
+         + "X9AqfF2tHL0polTbpio8guVMarC1Y4un290wL23z2eSg24U+vGu5RWBUuCbdG9o/Ti04fIuYM4JRANwAB+lV8IyDsuj6bYRWvt/oxWhjuAOYQWEC7PxBAb0L"
+         + "Y5Ze27VqeQwDcjh4ZHvIkTnhl8YZ9j0/UuTyNQxTavvJuRPnNogaxCSL92gEF9bexZ+bJMa3sFzw61rMJBz4jQyX9bJiJpXu+dAL82HOvFN9tqmSLjhoAPgw"
+         + "lTc5D8XpiDC053tRSVYDqLgaIsUgPm5POWf4nhbkGIRU2YV1J8wzQEjvbt7MkpcVuX6R8Ww/4gPK6bDBeuuvC14tbmauyJsmyyfjGd/mIF2Jwy5QUTdQc9DI"
+         + "1LvfaK5lbUxUa1rjMa8QrsYAkifHdTJgPW88yMmCMkPRReB2UycUkDQ8TdVoevzJ0wB6qYIGJbR00S5nYm5DJmtBdxSGtDBnn6oLfFISMjaxViBK746TnD0c"
+         + "2hyzoCU9Up4Pg9eV2VZE+wGka0uDdBv6p2m3DpDv9i9WX1OM46THRs43vMFjC0DXB8X2r7TQh/2OYBXCviR7D7+UsoFKmIEOp3Oq2hKr4HMhG6GVuNbqPbQu"
+         + "GRJ/DPQJRwtZ310KH24u8euIKBUEVa4ljOBzL+oTSH2Ip7h50ZodxJcDiE2adD2v8vzJTXMMw+eyStur4d1D4RJo3irWE91/jt259iBpaoKbDUB1ESu2aKnu"
+         + "nqV1GSYJXtFo0h7L4rRk6zSDJnV5fYjuHWaBVGJqRIbJT4xPo/6IoKZ19PmkPWgBCcSxAIhtMHYbEcLbVKlSHMLQFKAJKaCssiIM3aOZ0tSZov2f7jSroH1I"
+         + "EYhZfWuK9MMcyPs6xsq6+18254UiBsldPdA1gguG9tieW4c8zbDj6D1PS4xp3ZUGjXYENyUzB1Cu+vgZ0/H+KJIfhSa07Qhpii69XaeHCEIjfnj9iXlnH6cc"
+         + "5hPJX8w75edF9yJ7CBlGv4wSyDOUtkoeTZH1codczlgWYV3djcZRYEtnUq5/sC9jdYoNDJv0996YTfdmZDQ5TAvG8JqhxColGEBySbHgpkR0TTfR3BnqRE9T"
+         + "st7n6lFHu34U/wefjyvpD4f6nmYUL6CBIsMokPGG2YyucWEJB8wxkEXK1YNTSqWnhgevP9+ql29i0nmxl00ANa1axuRXYCotiMT8Cl+lAxtHD3NYmm3g8xfL"
+         + "5mld3dyPs4LQ3OTrxAmF5vYzuJUclJLZAZZWJwh/OVuDDaZmFRD+vrcTVOF7cB5jZpGOgbFD1pvpqEuuZzapG8Zs2SQ3O9A169epysSxKoKoxCCP8tUEkBuq"
+         + "ZaT9fWpVvUr921s/Y/oCQ3PwZm4nfq3pthZZSNx2S3RlaMa0ok5Oyn9xCsmlY+eXql/4T8t0QUQscLaDnBA2s8llUkh4tW/cfXUWw0V+GUk3N1eqN+VxAuT7"
+         + "iaL02ptHKSInalPm3KoQ1DPCcO7IqiupH0zTjjgIsDJ+iL6nW5smt3qXwKP8/DfgCF5hCduvGCxIN27aD4t6kXap/ETIsCJuEpjnGDF1E/ZYFO/iEUaKskkV"
+         + "/EDWUTBCz2JtHP5wloaKYCzjEmVGJvb1gXXo5mlfsopbhMKXU/tmcjyUOZugapNtMCpnnTaFzIf0b0hPKPiEraybjg9f+uQx+5lv6XmB/CkNOj2lkRi9rHe4"
+         + "1qJfHeaf0gsWcsCByhy6mJNyp45Aqwh1DGIEqoWfEmM/wOBCAiG7T4sAQDzbxZV6+hg=");
+
+    byte[] expSha3Pub = Base64.decode(
+        "ICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5"
+      + "ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT"
+      + "1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAhIiMkJSYnKCkqKywt"
+      + "Li8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXp7fH1+f4CBgoOEhYaH"
+      + "iImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P0NHS09TV1tfY2drb3N3e3+Dh"
+      + "4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7"
+      + "PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SV"
+      + "lpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v"
+      + "8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJ"
+      + "SktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKj"
+      + "pKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DBwsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9"
+      + "/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHzzFqLKvvsdZOxldDTvCy40RGXZFsOAMP1jw0XlUMqq9");
+
+    byte[] expSha3Priv = Base64.decode(
+         "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZ"
+          + "WltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKz"
+          + "tLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwN"
+          + "Dg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3ODk6Ozw9Pj9AQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVpbXF1eX2BhYmNkZWZn"
+          + "aGlqa2xtbm9wcXJzdHV2d3h5ent8fX5/gIGCg4SFhoeIiYqLjI2Oj5CRkpOUlZaXmJmam5ydnp+goaKjpKWmp6ipqqusra6vsLGys7S1tre4ubq7vL2+v8DB"
+          + "wsPExcbHyMnKy8zNzs/Q0dLT1NXW19jZ2tvc3d7f4OHi4+Tl5ufo6err7O3u7/Dx8vP09fb3+Pn6+/z9/v8AAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRob"
+          + "HB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2Nzg5Ojs8PT4/QEFCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaW1xdXl9gYWJjZGVmZ2hpamtsbW5vcHFyc3R1"
+          + "dnd4eXp7fH1+f4CBgoOEhYaHiImKi4yNjo+QkZKTlJWWl5iZmpucnZ6foKGio6SlpqeoqaqrrK2ur7CxsrO0tba3uLm6u7y9vr/AwcLDxMXGx8jJysvMzc7P"
+          + "0NHS09TV1tfY2drb3N3e3+Dh4uPk5ebn6Onq6+zt7u/w8fLz9PX29/j5+vv8/f7/AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygp"
+          + "KissLS4vMDEyMzQ1Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWprbG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKD"
+          + "hIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6ChoqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX2Nna29zd"
+          + "3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/wABAgMEBQYHCAkKCwwNDg8QERITFBUWFxgZGhscHR4fICEiIyQlJicoKSorLC0uLzAxMjM0NTY3"
+          + "ODk6Ozw9Pj8=");
+
+    byte[] expSha3Sig = Base64.decode(
+        "NnelQqrAxoXAVDwNqlUnwcj8Gx9VKMlKJ3z9ipYLWo1L3vBDIB+ACK7/1Nzeqpu/Pi6AQOM290kG7n+aIuV1gJI9w1iqUqxfm64OOlUqGk6XcfGNJDYHQLCM"
+      + "2Miq6KLmLb1tC1W+oIaMb7WGNnlHpy8kLh3J1QIf3mXp0hqvPEFp098vr3zGgoZexexgyRJ1p8KKuKBt951fWaBXr04n1QwBclt1tQGlJpMmxa/ttRuEFYLn"
+      + "t4yj8Iuuo67C2o0jeOo/L0JYMqQPa7AoBdtn+ODdkQNJB8ss+DRt1cRAWxZRus50lJ5daICBCuvemS8+P0v2IsvUNFs4T5qT3fwP0NPdH36iqYTytzYEFW71"
+      + "PyZ1RBaL858TTrjEbhFbRj4VpTdbe/HV/YKWsiDdLsRouKImDCON4krFgn860Nm5A5YQ1uLFIAEycS+Y+7t2HaPVehoJ9sz3tkK++ucJN8mVzl9GJAtnKKtS"
+      + "j+SoNlS8Ov4jq3UWZf4eIxDCY4uFXI2rSpMX8E2ZJV7JqbCK5InDH2mWkKcVMpIuXavTBloMNQKMMyoBchsZc5ZXVSj9olGqkYY4cEKpMwEUf3sGx4HuKeUR"
+      + "z9RW+4+0RFOUMXu7udlFcXaPpsaS10/u9CBezY4+UQgXPSxwwI31mxKMWqduyZPzQZeQcg8EIyU7usJrhsBoiGp05Aj8+Fxk719JUu4+ftatCV6F6z8KL2r1"
+      + "w2w7uQwLeIjtpLdAxHVABG3crVuEnJay+KKZm61DZjL9av+l8uDq4nso7OojpKipvDlxvsbSArT9iEZpBaUCXz3bjF0p6u8lEcdPVI3lGjmslikW//j0rpQd"
+      + "QzW8ORkM0ysFz5BN8gzmfxiwWmBH377u4Jgm+szzr0kNvjb7mWGbn5DvOxzOmArUst4OPWX7orcGCs/XKQtg9KW3FAm8sxXRvjIQLggvYINcZm8mzqVruEIf"
+      + "vAXDw8Abl4tBhM/fxltsJPqlByLtdihWVNOL4agOWfToq7+A/MSueX38wZDuJxEKVxekCTYFIqIKRSEz7Rhww5MfxCob6q+Lblv9N2OKQhxu9t8Q+hUFY6md"
+      + "6eBH08/0eP0Yt6r/3mtczejG0F+vNYa4z8fbj2pPrisv3LtlB137ULltq10ahFHyyEt3M8PFYhfIwR/6e6RNttqJ3XWGCCTo4fmbLxi5BqTbn27TkywcA2AU"
+      + "9lZZthFod50946zjxWYpaRLlsSPjElld4BTf0fVUtnagPMip3g/yIS27Q570E6vD+43s0B1vTYmTwVWQ71DRatjv3CoKi6uhiJesVrY6JC2smFIt8CxmbAYb"
+      + "mRPM0akR1sYZQC6Af6MQ9wMSEH79MkWlWz0oIfK4VBtE2HzlR2LWxyg5u9uTBZiORKuNZOlg90cWloV94IV/HypiqEQ1k2Y3Wa2n/pIiNNUQe6PdNXmZunnc"
+      + "y1f79sBfjP6J4l45OrUtUIYj9lu9ChcT1OXWiVeJE8dnDaGvqMa0thB0DiKn0wxTL1j0QjZe5P9diQHAkBECRb7HBxJ6z4Qeielj5aiWAy2E83+ND4D0x8ru"
+      + "Vi/uf+gCpJ98O3iE1hGvFoJs1CgBX0e7IjlJDnpsUHikw4D0KYciH3+a77AqdaLTrkMLPds/Z50Q6sBt6ts5v9Ns7k/oZU7uUIln8RNzfKzBzW0skVqmmfNU"
+      + "LD5frojNcc3dMepPjfwNjVf3cS6XToR/A5DEOYUldeumvKvF3eJ0O/zLqo4+YtoQh1OPFPOfbZF9wY1Lndb4Lq6zv1AUftwjjKmbt+FdLpnU1KQq1d++PF9/"
+      + "N+v9Zs5GHDyAYqbYwtFlPUCBIABQn/zoE6CAQ5D8WtpSGb5IWm3qgTMnoSEU4kwTvlx+Y14WMxPENHIXitDwJbjkMOx90OQpXjIMYpIaPdle6M5vGnZ0gKG5"
+      + "HsyfKKogjJK/K9fQXqFiPgL+guMSyz7HuZFRQPknbfSQg6dYrY/MICNbw+vZUnn5svdwv6mkloLOYK2tzYOcJa288lGGZGfRXI6WavHaBa0z1tTSvpHxix24"
+      + "nfk7HVOtGIihJWly+pc27LvlyNVBtWdO0SBGcwsGCeRz8VT8X0QlxsmcofjNfmg+jcxKrsiT6uB9AxN1WckXboHhtudFQGy0cUEFjiOEIhYjEvZ6wLDYD+Z7"
+      + "nQRbAXH72TSv0hxVIkuVQxTyJqtIUQ98qsOjP/3kSd9gTJNf55aZ0nDWQ94WDmIdkGhVrWTxM+Fx/XR0A+zEFIjbC/BWvtGM1ulrCokmgTSCduDzJcNr0dRI"
+      + "1RlakJDWmtntt55KtgOoHuR+rXTBvlWWmYLkS/vH1qiEdi127zbTPyFh1s4LNtChj9UgiHU1xjyLo2aw5I7sQOToEi1K/zagLasjj+zwqdjCrmtA27d3Cazz"
+      + "Vh83luRLXIgxsoLaL42YjUuLeRS2EaFEFYslgUwlU4fGwH/pkEoq9FinOyf2ySCCNRoXIwh1YaFDsm3Zj4Njm2ipLWVLQKCvSJrE/ESyHt6cDJVgRw0HitLH"
+      + "3xXoXF68EzuYLTEvEyeC2NXyerfwOdaZUoWAFm/iZKNjrdk7r7Zrz0lwjqOuMNuhDdoGSRwbKzedfwyCMw0l5PNcI35ehnsA5mJBmtN4957NXBMW8u2a5wH2"
+      + "KOIx7O2rm6apqeRInyJAC7ELAouJPrCkhvaprqK1duADscMYzQXK937fRVctrfJWWlLW418qIVJn57pPJ3W0lXfCHVLRP+KJvWDpe/abEvYmawMh+I2BnF/3"
+      + "CBBsZElo8p54BfeeX3rlxxuw4+j6yKder83CfVTi6+DpJygAVWYCeI3qskMGXlDVaTcrton6P/u60sFMYv62LlJu3ZkxBjXEKAX5omGvpYIohKVE50m9DD9+"
+      + "7PIpziuQ8pykHVf1QAdwadj3REDFATuOdFINCD11yDyupL1uNWhswMCPlF2dT2N7Hix3gfEnY8yMk68PBbSn4C020ql2ErntrMxYwxhIIkz0TD2iNpabHev+"
+      + "8zO8UoGXElCIzASaJjKtWJegTnqQCKXBEO0DnlqbfVeZs/r8KGo82MNe+/x4LSod4lC205PxruDga3riiRMrO7KDo1HwiDJ0q1hDWXUmfCfXNQipvLiAs6Wf"
+      + "YhWHb+EZ1ihP6g+dbmKV/LdSCakbTsUKjaoSpfso4MIdun3YLcj+3WhpnDxRUgcHocpJ6/7NvUNyJzzfz+wZu7joN1XVjkSDt/TBwOwfzwYIMgrE/qg+Srfi"
+      + "38cN2wSW+hxsfzehrn/17zv/pOASF+2+K+bguMYSGtighVkZbVJeMZae3CUoPAOx8OzhB7dPB2qzsZxpRlV9m+naQpf1Rxa2YaW0Xm4G1s3XAg8oGc8mCjKr"
+      + "J89tpsJFa2a+3HcN+6SwNyCPlqWmJzaUqXcaXOjbh2rfqLsVotZ9/8AX+hKI7+amOP+xe2eQaIN7/1ejVzKunBiUEk8P8JsJ2yZbuj3x11zevVzDZEx2p1pq"
+      + "nHtbwjGjUk2KzLLkv4XDuZrguTXIQ44pHam3CjOr3+27cU+O6q7O5JfcZlUulrASgc/i72DsTlqAwL8MeTaLyeVWAYm4iiPbLrDYQyLPlcPw14XmP7Qv1AmV"
+      + "Om7sl1xKcdJuYFeUkw9p17spGvjRF4frPwTGzxG5MAcFxLi8hXUQNfnGLZoz8wSn48/yUveucvctMa5xp3eaNn8ZUIuKsgNkLRctv2UW3xVYZzAs/CEyryp4"
+      + "BZcGagO53lTmJukbKU6Dl5KAHrTlGBMtBHh8XQe1Vbn612VRJbuRcCc/aQr1FlQgYVqGqr4B+h0A45fO3n8szmPstG93KF+Z53oosWohLaWzViLgJIuDYNSN"
+      + "EjoflP+5JAL0ate/7B8zpe9WSfkx3NoRCqLS6G695i3tVwKcO5aQac7V7CRmBSmxO8MYQt90f4YCKoDaFdYq7sX7jhlPNjrwcq2hOESrc1SqW0q5JX2Bvhp5"
+      + "fR4+4nveKpYeOEkUvc6Z0bdN8E1Ln9+XUa+0Eez2go4AGjokz46RuUc7pWqoMN6LbFk+UFDhoJOJkKCtPhxFU9RGrtODcOqB7c/+ZKiisOb4Lg9Pd9obpMYN"
+      + "HQnwtxJkhrRhs8FdP3bJnHvPZDto9OyeHKzaw+sDqty09q0NVTp+cnnsE7hjI+bv6HUxwpK4PcfdDIiimvn+CseKLpI4icw/jJ5lrMqjc4te2J4sTK3l4vr/"
+      + "uvH5ubOMwukBmAK1IS0/5eMdTWrfGHgPwUvp4Zql6k/Qwm4f42qjqi+/h8gXqMy0/ZQ1Sv0eRJ1flGLL+NKhTPHVbEIgotCrafSJbTrNpOJc1jrJcDfeaNJ4"
+      + "ou8J2xsyrTGTHcuaV63vJkSYVOF7jAZ2TDYk68DCFaQdoKUSZYf0AkAJMAFZwB9Mr7gidsgLlUskvuNTUnVQPr5oqR5J38fKHpDADhnPEY8BAdHvvUcDHvP8"
+      + "X3tijM8e/0Wz+a479lzdtisQJ2oSgguQl/NISR+apddPekSUaiHyg63HNR75GVcN6zPl/ua99k0Fdd6LOFMvi1MR70MrOge2aM/t8K415t8beJnbUsIeWRkc"
+      + "yZ8sVErSf2tb6671ho6dxNn0Wvf/EE3bVuN0ocmbYwvClwCKsR1yyCFM4pjedKCTW/N0a+60ITjSi6EdBL2N0KA34tsGtpI1p9xNJ38S96Onzuh8+xUAxn9z"
+      + "SI5Z4tqkU9EDhORelEOTzsUWo0AiNJIoCZSOJvdOkqp31vxMZAbO6QWwGkMjrUgIaIshsyZ3WQam/g9PMuWb8/l3ZzdOUYY8h0oNj15wy3pUzpQNZHIU7MZL"
+      + "p1qeFO65FURqFgrDn38k7dR8jOsw3LqKNcJNxFMxfzDiKx4LPQ3i396adCCpSoLJKUxLea3XmZVkdz2fSg6ISaxOej/TG2cGO+HPC2ESd5D1FMDsqx16SU2D"
+      + "MrSrGSv8P4p+acKUY9w9w8ccdm8cxsfWiI6BF9e0oTNl6E7wNNUbBNdzmLmfgBYiG+7182tI3S4m9YsJN4JNIhmVLuLSZZMlyekoHQOCmPaz/KLOsyEPB21M"
+      + "V63NcBUZrPnCraWUcQxeFcGIWu7N/EW3g7kBcfiuE4Ylnt+Xn0EU9f/0YJbx+hlqmKJOfNXn/MoNI6TjlJa04GhjMxo4O41N8fh8lDkOYbCwtXeTen5FJ4JK"
+      + "1sPSIWHktGb5mXqFIKWFOl+KNb/Koz0O0UJU9RJkaWmyoBk/B0trzwKE0venydKFdN6a53hQrYpvmm1AaiV8XOMc/f4k6/ooDg5HGJRYmlLIK3Fm+J4/N55F"
+      + "roR3VqL2w2r25qCp5ySXR2d3+eLWgjvglMoGk33jlLzASrGMtyh/z/WczAZi2htvIsV9VV8/LiKbwSFhHY3PNftK9INgiC9nbvUuGmN9mCsbJutHJPE2Zg7S"
+      + "V2j0XbqO/T5P8THisfBcSBWxzxcqh4ta3y+GrYP6lj/eAcoz6+c3JkUcdC6+v7GPa6jLBkgMU9isyWq9IfXNIVY+8rknm3ejOH/DE/HA91D3cML+uuE+rqhf"
+      + "Hlkp6bs3twAf6cEw1XSB2Y2d9XgUVNHsRVFPXOVkIR1c3brqjkDyL7QhJ133YDOlbn9q59S9KUF4yaB7LKMsYVcUf/zn/kphj1WvQ+8mpqRh1gLrShTngDYI"
+      + "v4m+EstiDwOYzwz9t4mPHBPlDBVkzmX6cMWGX4jwORwdiqLB7zC7p/kkBhbxD7lZrEGF81a3REdyCR2s7qyoidY49vphGU9P12ENW1oNzkGqtDr+zbIDhoEG"
+      + "7rPIYr+JnG3WJ4QGQfgsfF5c/+9g/DdKBg5SJ88F3DDL6tfmsbFYaUnDb8DwFwEL1q4i9yHG6XJvPO6Z4pLl+4r7v1HnP3djj3KVFg+oP8oLim6Mwqkquzf5"
+      + "Rs3ww9kTYO/+Wb9IHjZX2C7VkCki3J2tIoF3rbOZDDglsWomQNC/vc4w6Z/1/6PGac2EYvPuaVk9JmP1DjteX1dK+Lvll+SwMBqkmuzYZc+hOdBnolIjcxMN"
+      + "QCOvTGYNrkRYDMt3G0t+yb9htocHIfe5h8Gv1i3bYuWo+6b5venIQlVCBmKdJM/+4IwOJ2BVINheuhk/v4jAV4mAvq8gN6ZDH5km/bhvGQuIZSb0iMCPLe3G"
+      + "MRM1cbiXAWzVnThTBvFQH56MH+6z2/o85xySuagDua3l4B5B7mmDRoggrqVtwylPMm9IJ8LO7YV9b5uuBGlM7YDXzc5xuyVYCHR5MbPA62RT793RV7v6jmVc"
+      + "VTA2QNuhe+C4cuMM/ph922etbHlQSEv4pByRYO0TkcxCeKFqqUS5niQ68XUNgurzEljf0y5L0/wemG/GedA9TU6R+wxO3RIK7GRevbB51r23IHcMwdiVZ5nT"
+      + "Vj5ue3iGLDQxddGQzHK2UuOg8JRhYp4cv5V5xFOp7x9vMXAamcyOPtzYzCoB9NFZXN9rCcPrm4ki+7iiLnkQ4779SRsF4iopDGtqAfdV9xaHvsdT/Gljpab4"
+      + "lU6uGsTo79nfCLVhgtPx+JUcTjYjtM8DksHaGJAK5mOcRcvBJT28O0kKN4V5On9pxst++VUqitJykPNOy+MCHdvM73xGfKzxh0qfwZ2HN76H+51nOe+ek0in"
+      + "DaFvghbd5ZQdKJo7xuptj9IlV2XblBdqYbxH7cKL70sybhuRUUfYuRrlIwo0YbcfAotEdymOalDn7uifqsixeX+hESMBPL+kMbnjn/3n8IRjgNYjIKeGtA2d"
+      + "MsuGAsgzqFbLcJInkCGgg2aIvl4o9L+ufarsBjtKcV+lXgXzD3lohYUZni8hWRY/m93drS08F1p7wibBEq07VaAfzlC89Rq/aMLn8ZYIVcqD3P2XuNNAYDfz"
+      + "W45PLVMtZBHWSCMy3JYXIHxSVQG7KwAYmVxaId3+Lxu8p0cIik5TFSJj3yJZYdd7gQgtvr4uUoGOPDP3CxOQvftnMNTcTSptNn+xWSF2cTTJwFctrqaSvC9k"
+      + "fxdVMGWwPbg73esbEagrEPXLPU4lq8xEGhb8QZ46OfUUoIcJfYAJFgx/SEPjIm+4zxOTZ09t487frZNv3tch7xR6M1MTeEcXvJQZZw4w7pS4IF3b89M3bP5Q"
+      + "quzMpHSO/oJRk+fcdNWYdOUB3bbjfv7AIrzBGIZRXMBvFMn9Lubz/kaDI1C7L9IC8vzipgbEQkCfGLr3d/zwIDQ++CF8OfyCYmVMMV5HnXm8FFTw/Nk48xm8"
+      + "Coc1LySNZEC0sbRExyFalgEQxWjmxHVJdp/ZvzStXSfi9D/EhI6lxhzxec+TVKMYbYXq3tuT9W+3749WMbUYEw6rQ/Q53WJWyXmXrsExFbdnmrfJowDlJNep"
+      + "TvertILNAWpx6GbeF3j7rdBTdX+kVVaOgbonShIgrE+mrcvK6dVr6tH+ctAqY4yGnXPnwXscSLyMxujPNg6c09gMa0TOSH2jDdXG1XT0E2UzYD8rK42E15Lr"
+      + "i9EB6t8fA5T6KhajOFXb0eDKq/wcd6OdY18sF2MSm7RCL0ewhW1xLYch1srni+zANdUExuXKoN/50Q9t4tFDK4IQJmdb6yRD70EIz/ocVUnhuEgEYSMBsqP5"
+      + "ZLy9s3MsbaqNaKakHgUHoh3dsjONGrOzxaMQ+bjwQbhyhOFJmpW+KD3jvHGj6jJFWQrm2Oy1AtLvz7e8ThOPQ/VX76FNLRV9jS2mNV19KFKMP0vFCv1TRd02"
+      + "h4fnDZyMZIV+pYCJwiwvZBQMS18VYTK/OWeVHbMFJyo7E/AeD3DvR40Q9JZ5Ww6N+9UX2GW3Tv4+MbYMwrVkQZ2N17o5aNTTgbT7coP8UdCfXeeTUBpL2v8D"
+      + "F24njR6hfi00IIPDzRNcFdajNMGhsClhl3ZCnNEO6SuQJOXtyqScPxjc7H2Pm/vTgQSal3K48zD/YJzCsU0w9/Cw/jjJvLyoVsBUkJFaSZzBHWlMW1OTlC0k"
+      + "ARikibd9sUk17V0Z1zxxuykY4rXDEAIF3Hf+xLcv6tyBCDrPOPhy6nRUjiZ1YzYdQ5Xywo+fqqnJs7PIncPdXEuXQYsNkUcp+sHKlD6/4SJ9vTv5p5VblcOz"
+      + "bSibHw4eUQFSaiAYPId+MDgUXaqMBaYC/SB175EdCUeJk1O4fgb4v1SM4BOVYCpEQSKt5rUROTp3U+lhP+ZiZz9/wfy+6ykBG6n0jkzYkrB5odxCTRg2ze3b"
+      + "7juGxI2x5S/5qJX+k/Kjj2fX3I+FwpOIxkLmrAIBsDjhOMMAuu8NSGINUJ0c6DtKJa+Gg5uSYuc+uBregPfmJ9YFUrOUdkukGqCel/1rXt2GXO3vH42Hb1Hm"
+      + "M6eSv+tGm1zZ41xB8dfxtR3kzBjtjn6y06JYsVTkOCgBe0q7/8xuPowZPz657OvrmDwlb30jH6GvXXxbCi+x//PUyCS/7GkE779SsRa0tx5icV6fKvDFqoSI"
+      + "40kAyCGemxm27gDU+XGhn4V08HXVsFSHP8yIKibvBLmGh6BpcBHeQgRa8ZAXhtuqeULU7T4YHSR982cMKqvA1qgvNNXtsHIPJHDr66nigNbmrVlVnqaVkZ3x"
+      + "JV8Fta4Rsow57YhPlCEKNbzfMKCRsFqNqRODs9meid6odKrtiSp6sNu6WmLmOBa1JkmTjAj0h8KZGFgUfhEVKiVweygdjnMzBKBZYOO4gTiuZKx4pOChLM6W"
+      + "bxcvHH9krhjo8tg4qYGYo7jVomR70ELSSlPjvFdxMrxFk4xbvet6ARPw73h53qGCHUlzw7m2jgN4E24zGwtgVB7t/7WiNTQFv2JMzLyABGJUE/gjrM+ASDtO"
+      + "jiccU0mpZwD+nQJIGkG/oJWy0NcQ/95W79b2RYCQD05CTcmh25IIJVhwuXZe3q4ZJRIayGNeWKwvVp95j5ksxe2B7IO1k2IAUuSA2olTNvBjK9+WwXMvE79/"
+      + "wC67YlPtEK9cjiUSmQL55UVXmJrRUufjhtg3copQduFdv3mNirEX5m9cL2DPm03ts+CNo41VMJmIuiCzeg/E80p0V8LoNH6WZKSMtqeCgwwXSc57xOt5XDl2"
+      + "ZBo/y/M1F4+lYg+zJF30oVG35ZWIwkL4BdWU8LkGX3zIkjAuKLDL8RwaiKgDeqFHSkaCqo1sdkTJ31U3bA47E50gpARs//kmsTA85HxdlZXvBw/Wda3lHTYi"
+      + "zqsJzf+5h47RR/8Ia7t/yBtjM6E4d62t8a/KaCQ+2RP5NGuxnvDjGSMjMOQrjq+pCcVUFL9ApGWErZB3zOpPWwUpYspmPhXmDaO3sx1m8LdZNZClFLCn9pta"
+      + "n+i2TDXHWOuP1RQfWwFk8zpR3IQ4sHYjpkJJRWHmeDW9XVaxGYUo44UbKkTT32iBXqgNBilQFIEXR5JZHZOyN5+/wkZ+tDAIzdi7yKLqBjliKfPOClYWQ16I"
+      + "yBjSIvqZp80yuARVUCG/Wfw9LouYTqDs87tUQvhDBAgrsgw8xnlJAjDAHDn2YaLp+57gkXYedtaffYqKKdD2rCH9Fceg2KWIxe6MKjtz/Hf+60RO3Qe/UeM8"
+      + "xDLHzSZFE9qEVTr9uJTOI6SFL1005VUEcIl5+cnAPv43Bg3OHmphsrXfqMAlBnUBAu0lr8kF0lhKE9p2aVBY1eK9aU7lhf4/d/YIq1n+FzgN6WTbs+lqzuEP"
+      + "HMR1fA973xZ0vSfb+ZifM/zySjgSvSUr53YKmRZop9hI/8lPX1QaHDXRVn4fVZdv3xZLysU2qO4b8RYcD0NBIOEqomqKLtq9YEBAwPEd+MN7K8sk7RbkWdgO"
+      + "tj9qj/8tqbzh7RzQrWn2NEaOXMPyTu3UvH8hTbNGfhLUBG+BGG5Tf5jABTtT/ugs3kkG1qhx49PHVUOO4R4jqQJ4gmYA4T7ToodcuOcI7vKQ1pKwYuEyDNsD"
+      + "CXVnq7zf+nGkuSbCDP1GG4lAQy77DjZrQOXK+4VRaWfnubJ7Z5jgPfafBIxSaK8ca8nvc625vzHA1K1BBJWW+iqRs7ZTMG5Mk9g9XHP1e3GI7an/G2iXl9EA"
+      + "NLWMB6UbsoJVG6/9lS8ZzR8qyk3ecNysZqOgB2A0eqwWEizPok/sGdC6YrP+I3J5zYQWMz+OCp3PQyoCyLf3u8FQrMkyhcPBPBxpXuC/i4CaVjhy5NYS+X/Y"
+      + "5tL59Tpp0ikFM2+LHSCOgLEYd4zMbrzlmYUldvuZoYpaB6TTWAV1vyteToQNdF+E/Ojppuf7fzRE/rjfra0safMRV6SnG/TGUppFuZTr89cFbHmWZZ7UB6ba"
+      + "9nFvWwMxC4v4bHBl4GHmbs07EYdT2v5KBdPQGpK85jKR4Wuy9SoFVLTzQQaukzdfJp1EvaoRt7PmCac6+ymQlCpZQPItfVXcQrO4NNeBccQYPjVcPj3jixm0"
+      + "NBRE6sMsijvoe8/AZjZQjWFNNjRTqxO48V0TGN0U7EoeNlmbhI9K+TpctX5GaR2kxQLG/z+9kYGNDfCSlVhKLN/NlecOpri5v2jPnQl7yVJcMVDKryGtPDr5"
+      + "YKA6HO5jEKS9CQWf8fhQdzF1/S53JHrekXk+oSUfTIUq2jLq1So5aFjQVrBYNIrW7vn95Wx99nCY3BX+gy92fJsLUq2ENMUmm2yHLCEmpPSN+c9C4R+wdMX4"
+      + "VbW7UtrWsXxB5eDy9l2j+3/18XFVGfZmgPl6AnX4fsNobOFzekr2mdZlzPkXtxN835puV4FgrP6yA9ah0Hppa3XnQhuJ3LJ7VmUR9CIcNVPwZIQa1VK39Nts"
+      + "jxYmDIcFSa5DuqKAc1KQhrurNrLN9fUKTGP2n7EvPsDy0ZJZwEoLujbBzADFhMA9JOfKnqPJcRRnhtIC7F15/Z78++o+YpH+S9NAvS+6tPtTH4cwekY9MImf"
+      + "WstOEk0/3TVnnRHHO9Pafsy1myRA1XIyPkJchIw/WU5uMHCX6KnPKnLBWNMay81HRCAMmC4BA9+sNbIPK88ujgfL5HE73aAg4I6H/9XIkd3V8RsPl+7/032B"
+      + "ri7IJwSXxsLk8yGnSmL7YPI9NGp+wFU99aIRlJLffHTmPIQexv0y1Nf8kfvWY/urdexRQ9l2s74ylX8+sT1fhUsNh0hdeEHkpcOyG40qkzzhVVPeZp1UW6vG"
+      + "Ln14zAbRwD2xeDIZPtX+1ANrAUUbNMv2X3LFhjlARulWirJJT2M/qfcoDwOg12NITRLsbMlOzg4gTbzX9sPFr7lMUA3W1No6oHpBvHjrACDrb0Yns85fYoAU"
+      + "OhbRdSID8cLd2IrcphJ7QW9T59t4YCddYPf0Mcj5O8wJkIEvMNz7HdkEnZpD0zssrSWYX3gEq2a0RBDG4lR4WDQ6WBCC9+tj4aFWlGm2OdS52Vr7VrOcFoa1"
+      + "aYJdg09/1T9mUu44KUhA+CoNZu5l9MeaMtp6Z3Bs2M53EmWt+vQwdBQOExbEi0QFHCFI6qqYy8mnJO5LuDcnN/n9GQytaYnHH1zth6FfEGkSGFuxKBCEij69"
+      + "6KyD7TgZ9P4G9PGFcT5ZYVwC2k3Ld3Jl/Yf6/RBXP0WYiu9foAMWpzXIzBJecHnFq6XNC6MRpKrqj9kLBwf+x+Xs6UDM2m8KU666/WrFRFOYgOBvt2zyPmlr"
+      + "fkZmQIlgWyAzQTnRopTlJuxa5S4ZYKXq8LFHLDTYgJTiVCvcue31WcfmJ9EJ8R9Pr09lRpk7asUab2s0TnkjBXnhnT0FOetOqoEyLiZfr1I+xaZ7nJMalz1W"
+      + "aDpA1B5+H5evYQ0/MVSD+w1AW6rm7NmINXH142O9ws9zAmF9XawRr9z4f9t10YjB97F7TaZL1U/yBFEbOJvxIH3q8dOAgihOu8TUPXs33WQltjNLvnY52VAs"
+      + "bSIK4moyHh+zSbvHFiW4MofPnkzK27blxNU5e1hy7mhOoKnsd8N2KJ62N0/OBfBBOkeqkXKf3ArFqNEfJ1myiuyAASgSg1I9TQVpF+Pp8SFfNvYZDOUEsChU"
+      + "UCf8q2vpjhWUK/1TU0XVZVzguesu0U2+kVrQObtA8KzbPIJ1aao/Snm/rbDX0o2lwnDwmLmJ8rVp5I9ylRYPqD/KC4pujMKpKrs3+UbN8MPZE2Dv/lm/SB42"
+      + "V9gu1ZApItydrSKBd62zmQw4JbFqJkDQv73OMOmf9f+jxmnNhGLz7mlZPSZj9Q47Xl9XSvi75ZfksDAapJrs2GXPoTnQZ6JSI3MTDUAjr0xmDa5EWAzLdxtL"
+      + "fsm/YbaHByH3uYfBr9Yt22LlqPum+b3pyEJVQgZinSTP/uCMDicxK+V0BqvTTClsV+kLU2PysyxbwQqIxB8n07Z89KxIrBxHogYnRFtTiHY4E96synSYdIgI"
+      + "mA/te99fFzNkLOHI/kdbTUuElgVfcpCQXiXFNB3WRu/p3RKRExpEpSES/GDKldICNqoICfUImZJhz5Z2ADwQ+dQofWqRHdTU4l1w18tXrIEbAdeTVqTRwFFm"
+      + "V83uHTbR0DmMPhIuLah9C8CWxMxkC+lS90cVXiVPfjvd6f6LWnaI/3iS2RTYZPFNVQBHG3lhMh4ZY3bTzUROsyEFzuWY7MJqJ+a/ce0B/UDBS743UtpuNzWt"
+      + "ByBItW0ZGWgGYIlosHBLF8yzB5JdA3DPfFSHmxl14Gp+ZmqIjn/Kd6qWeSViKC/wTPJUyxyQby0Sdlbt5+TEi9KM8KKFF3uH75lLzrk4y6+fzMV3e9y6V4wO"
+      + "joMP1tgsW7ybWrRAo3ui3zSxb9sc5WxRIoo6qQQf/i52dCKSaokwmZQvR2F9XrZ7ZMRda7m9gbPTYcNAVjl9D8E+vLhey4gbwGFh2Ve0HueDNcNWP+droI9V"
+      + "/amI/3xp6+a32Kw2ClcoMzmz1Wy4Wm9ZVmeTOUXfmTkpr2KruN8M8Cf+z2RL0cUp0184k+uyxTVsRfMfmId5Oz5nK0osR7iwVgV2U4YxuAlyLG4w1tW0KDOP"
+      + "3lsqUFUHCB3inev7Ul2jE0PIwrpi6FYT7Rci+xhm9mAwvRGPALWJHJAVj2dy+2Co4GBR4tbYkg3VrMNQeIOchVNlDasPvwNlVWhm6XJ9kS8tfAXui9aTiEym"
+      + "P0DwAfAZBOwD9CRKT2V8+1pINfBpmhFd6rCumoXkyYX9GBJWEt07iR9KpmxIDPv9mwgd5sYQXBy2Nf+dAoJhWm8mMR2fCDKG+l6LzmgMybhcauE8bKHGQMY5"
+      + "lLvMiyAUUdMLAzvVv39LDE2JpcdgWjHJNXy46Dl6AMwDAuEin77gv0NdGWKSWGYsuik0fkLBMqs+0i0If+S0ph7uUKlqXPart9qHuwIBDsOnG1alb1XIE05i"
+      + "QxApFuSc0J+auiQRlBEYsTfM8oUSRfM1DG6Wh6ZovkkZZGiyrhPk4Ta6xYmsM0c3b0bu3kKSD0+j31WWtqurjYvFQCTp1i88Ik0zDBwGTM0IR5VoiLQ2LsiC"
+      + "xqJNmQ75AFbgU1vZKA3mKDQ5nmVbjTdqfaFSdokzQZkR8r+/uJsFuGIGwybZfAFq4e8a3Mry9eXv5ylDGa2uv5byw4MIVWcCxMj65XonxWLZmzxPNK9hsICY"
+      + "HTJBTvV8MKxFYQRA47zD14oWUEsfQEl1RqgpiLq/FgB0dAeHovYU3LQ6Mwd0AwaIiu/vWaZPRvLseA7S0bhhXL17sGiN6jvFgY73CodJ05IKMlDto7B4l4UB"
+      + "9kq9RQhm4rlOEAMXu0gUZhUlradfD3N8Fr6/lneubfKyrTW2H80fvgmCVNsWBvsJvA4Xf0Fx51FAxnFhOeXc4dJHEdPIFo4RqSWZUAix3e1OyQwoYZU42SOy"
+      + "Aa3RElAQ1oxR+XqBaMkf5jCpYHq6KAvgNJ6oOwSoXipppI9Xyq3PKalQoEYznHUTPicJMcfcFc3Wyc/DoRIAnooMaGQB4yuCydwNNo4545731sSuTiCp3b6I"
+      + "J2B3UKblBlFlSKwEgpj105usgFS91+JbJJbagifLSZX7VTjzWhU7XFnMptVBAkW5H8Vjklvjw28I9IHYrmAVYK7oI39dXVog9GHnEcZBumOP8YxQqBCuFATK"
+      + "7fq/vC+9sfDa5DWWR64SfFB/pERwvm66XCJO3sCovO0uhNsT/ZJQwalWkfIHlAUu/Lfn1Yx4MLnPbuPYf/4jnWWwPbg73esbEagrEPXLPU4lq8xEGhb8QZ46"
+      + "OfUUoIcJeFjlDFQldHBrNqEwMSofDleygAW9nBjTAXg4uv585s5f673yaAaJsHH8mSU2kkZAXD/QWwbVOReJm+VJvHXMywfyBVJunQZWoqOrw5CK1oWLhWo6"
+      + "3++o6kpfxGmI9Fm3K7Kdz8pIog4w+uLlX6ubNH3Q3wiQtieNd9E+nVWE4e923ehrVylJbr+r/LYet2Beqn5SbAotT8s5CRgX1iICE1QPnuIwKte2QUKu/XJ1"
+      + "LOaN18PaRsettwqf4T86HDfrGybrRyTxNmYO0ldo9F26jv0+T/Ex4rHwXEgVsc8XKoeLWt8vhq2D+pY/3gHKM+vnNyZFHHQuvr+xj2uoywZIDFPYrMlqvSH1"
+      + "zSFWPvK5J5t3ozh/wxPxwPdQ93DC/rrhPq6oXx5ZKem7N7cAH+nBMNV0gdmNnfV4FFTR7EVRT1zlZCEdXN266o5A8i+0ISdd92AzpW5/aufUvSlBeMmge/yM"
+      + "rKDskSAvpTKjzNpDcrMOK+CWUBTCuNuM9zvulBTh/dBCx1RR8DSs0UDmFNe7KujfNRIbqRM4RiZFM0CQVBVsoRsLLchCZklz37fFCgrDSpaspD2UDOyPYWQq"
+      + "Nb7OlbMHFhwppRmplUaeikB7m/iBptJnZDxpnkjQucTbxraCrvN3kmtwBMxGVvvXMxBIeK7S8j2DIIMxqz3UkLesM02xoRb4n1KHNR6jLU5plo1shR2Vb90h"
+      + "ClGQp3cMOB1nuzEGBrhHfCozX7QDrXoPa/Zqaan2fBx46Tpv62qRbf6aVIfr+cxejNGzM5N4JzXlLKDCtLkjeWdZPKnE874d85wO9lcTvrZGPDLhDnATgwr+"
+      + "cIEyLGWyxpiQUskioxnGSgOl0chfbMJBTdYQUAdmGU+dcD5MYw0gerQHQdPtpxb/45RAmPgiSoLjyOUaNlXy2PcUW5QzgtOlVAB6sZbVQL7WJQnif56VGndA"
+      + "610cIkqSGkGzfgaoHV6WldqzCM/l0NwMfzq2bl7mqC6i43JT3VoXf0e6kck90/JFI04MvXGDZU+TpZ+gFpMoixBGgKHX+f8ee/yJdn+Tz/S9bmOeEHETg2l6"
+      + "X2zu/ZxHJsu04pZkz6qJTnNhUKQAQkw4viiKYKGXgxiC7G/BDttXyMJMNswg2puonTXzJgAEwousboEU11HMzbzP+rv96KWyDxx2ukUt6lq6wwAe4kbW8Tir"
+      + "HwpujVn62IC0ejcZIQ8lBor9a+32MUqgK+ZI3NK1jchr0yenYWDznOJE0qGl2P/lqI5TjcSdVFC4OC7vKHqmpt2kiYZESB8LxQ5dthwmUmKQNoGXjziwGaWh"
+      + "5jJLX9gxMlyjS1rVvxSD9vT6N8YGgBd3Hq79imBBLH0p6OW7plBQqVN2aeI2+GAQ5NYtkDuA3zjF8u97ZJhLCcCByB+3jEYE/nRPfSr0BHrVjNfu7K6RS51o"
+      + "9/TSmIQb72507zLuHhvWaL04JWILDcLPbFy5oi/1EX/+lIn71Vb/JEaEGDLsGOEil1EtiASByEMVVfRAk3myBhFLHLcHbk+nh+lyOkKTKpl0V4SlZi5+Ox2U"
+      + "a++OTz9fCWF1PYig6FzBGjDOy+oiQLyivk5M/4/Ta5NyC9eTl9mNQGCd+D+CO0Y1hHqmxYcaND+67CHs5ccjyHfW9w5BF140vgyWFjnnqfIQwxlajccvSUtv"
+      + "/OdEq/T8jhnT2ps3cgF6lu1LUcJeoa1NzbG7OVCneHYyTjeCYa5YVr4uiq82NCLXRmvu5CmXHwZ4+pAGOwL6k2O4Lcug7eo3xCHOW1+oyJKGb38ssIraEnL9"
+      + "14NYuI0LiMeBuXVEnX3bO0rsL59WutBdCSjOLCZrMNdB6caAVOcqq+Tp5jM9pt7a5kvg7szxL5s7XGaA/gSiFF7CqLgq2wctD71CI2lg8gW5xfKmQHi+12mn"
+      + "XyU6fqqvYVatmcr5LX8IsxJbg90zpkk/4D8CGCvvUzy1f7XWI4RraRJUAjUbfqD2Zo2JEhrjLRlAX68cyhfmsxHSW7BS9Wb2RPJO4zw2dURfbclVX/QBPwiO"
+      + "xX9XwK0Z/27mBiWux4TSkwUsGvh92qYOm99Dkz1oFLuu2ZL52wMfdKuE4QtObS+6gUQnnhyytANAacdVaVhvPGSIkOvurgdl4n/d6WrzTzj7nOuDqP5RzJhY"
+      + "PZYa9skEw+cR0PiBv367NWWumhBN8xVsSxeEayNoNv3uDGZvXTs5JZesGGsDsjSW1x1VBCSGNRy2VL9V5LWwtvOzU43jpzUZSM9/1hyrD9Ll4ZdQiQMIPCCY"
+      + "BRQDCcvT5apZOQkQrMPbbWhvI5rGZZvh5hP0ZcMrYWoW+NmoNMlPUS+Q8xieTxDp8OWkqUvDL2CsB1qz57ECA1UUe5y4J/OPliOS+nReYeS8LyqCVv5RKC3X"
+      + "p5NJSrh0qOqA29hirVWsUnIL6F4PpQ22pSnbOYMGr1Xf23B106nC0D+EO6HvAyh/oC4EjMlS8AfRLcI0VefJxI3N1xBExRTwFpVrmEoVKu/USI+qKYlE12jH"
+      + "gVaRm8FIS8lSQINQJIcLVD704Uiatft5xuYt7XbdhoViI8wR0BPkRjrw5mjhIO+tPKD9XS+fISVgBhYX80RadBhrGj+akY/7cDFPuV77ZNwF2eMV0uQNBLRB"
+      + "biJ7IyMCKj+cA0wNbydNmXegv6sICFEoI20qgjeiHtp5u6KuHPQgYELR50Im0eIK+bbOdgah1zC/Q+cH0lI+Axt6W5MOorBX9TI+wzbtJgVOFwexJG082t3S"
+      + "0/I6+OBmknmmws+hPSlSdEbLGRVchwFb66A9o7TskjaObArdt2Ia+GBJ+QUiV2qjyRP7Q3Adujw2LEgqux9FX7HIxnUWw4rbaxdFr3QbAQVbxaaBLuQ9DsI5"
+      + "NL08nPUbb/JpIjGU4nnXHiKnSRynux1AkVhRf/BIa3FFHDZX4saQ/XF0FqM1n2ZZ8iBR33m5ver82lPWcbi1h5mgiaWip1T6B/jICf/NAX/5rdby2SE7Xn+4"
+      + "TxdjhwGZgW2XCV3M8LCLlrofsA4whCqBq0MYdTbII41nHhZ0HAErEvr4JLydFnlbVEYOvykgLq+JJcHvveE8gmSc2CT83vU5MMZwX4bT+Ec/Z74d/4HarS1E"
+      + "KFwLv5XSb6jLH5pl8LzYn7Y12LZfwI3zb5UrsPcKlaXd356E9+BpYSexub2kPKdFElL3fgIbkakfX8XVE3+WDQdab7fj+KZThuez08xFTl0ycxBR4hAKCwwL"
+      + "tTvlNk/8KW6HNPPLhW9LDmGvoRLrMWM/Qx+OKUMru9S1WBc7wb0Haa1o7NjK9AZHWJ00wqDTqlb09yRXhB1KWBwSOsXviadyXYLeOgBwbyyrg6SyC5WIW3nN"
+      + "iGgJ62jHced57GgqOXcuCPVKbObkR8yYmqt2TItNKtITvqw8tH2shX6mmciP+Nw8twPIBqBVadH1rnLBxNulKngiS2u5yQIl9VVsur0WtQjcQ5V2KS7E3yr+"
+      + "qJBvE1c17Fe/hLBRbMC+c3FeEqdx+WZZUalpp0anwHHf6G4R00EDRZabF6nASNWFE3kZpj4rHgWXOcsvnO3Bc0/G16SSkzv5SYvGHTkcssa5GiZ6y99dDBjf"
+      + "9CH8Lhp40Q6MHLi8Pk5CYGeSXynwyGdyfak03zzybxYkPHcMMQtWevFvhaKxTpuSy2Xvpgt+haU3RjPRIAuq8zFBGmFsO/zYnYOGhHj9sTEs7dXIPS5MvfFc"
+      + "5Un2RyXXyH5mnzkn+ELqZWuV5YrfuWALPS5KcEc9I6wXN5JC5VqUmwbcErmeYae9MviwjbDdfZW2YUAb49Tng4ljyr4Sol7hByJLCJMGUJiRom0rkYdgnWLG"
+      + "c2mkW8zEH4GM4+bPMxN8H2SotWMqchMOxP9ivpDAfGXWjnkh4SEenjOYGAX2P3PAG3xltvRFq3FNNIRww6K7eKIMosru8+m1ZldQBdOg/0d1caoeRNa3Srxf"
+      + "fUno7fYAUl7qRejmzcHiNX9FnKVFmUHfl6VgdI+ZG1UBZrh7d+UcITYMTPaO9xVLfBR+otn2w9J3DyJoXLV7IW4Pdcl6CqZSVZegAvVvLr375hR0ODbund3Y"
+      + "4ii9KQlkRVeH/2gs+BcLkIonKLysHVZU0PXd/IvKu9y0fVcKIBYBNTIkqn1y4X9qJKrvX8/qbsRHFoCgFlvjy5tRedWo3zlRajgHbpHGd8whB66cmm2dOyhp"
+      + "pZOkOjZcQYg8ATcH46n+FRt4Sxq3I3FKv9TFJT4E3N5kiYgUVwbQUgdieYuBN84RoFCfQImDqwPciBjItE8x0y1ybeBhzHO1CnMnEuD/Q9p3wYXtvgXf+ok1"
+      + "w9rbLruhbwdp379OXKejBnhB9TYB4r7ORfqF2eoMeRr3dF9Ybva41fo3o0w8jM3PeV52nMgCiBt5GJxEXEiJ7zY+Jc40PJFdQnmgpaMUHBmOkbVNDtDS0I6S"
+      + "dZwZAfc5NUNE5fXwiFtfZg0NgXSVUrr0viTV27tEx2L71C01Ce5jsRyeSDjgXbB/IAqxCBuDtMyMsdMI8FxwSL1eq7iSIMm9fUnPCW4iEeKgBXAtwRmUBb0B"
+      + "VTTMAJgl3qXMrXPEZbVWyYuwpOL4gBPapZzwdKS7VG3vcp+OaGsoCqoa+oVc7lDcD108N/vS7XpxvqCQSSzhBaUgaD2s4aAcGLUBwhrUPKu14CzzTEtV3XxS"
+      + "jzHMo9p3/riD2mTLQ+fvls3V8WMsATcN6b5LJvGfCRjJ69+TBaeJbXZKZcaCG5+3g6f2NTWk+WxSCZ2WHWKI0s+rsXXM+Omv19hMimUjsoSvJ+rHkNQS6svl"
+      + "ZJlTf2I1VH9r4I4GTMbBKI6YKKDYITSiJUPEbO5CCEUTF+8h41ECeGWniWRAxDC8N5vhBJCkCrYF7ZjPjoJzVGwgwbvF3jDbcyuWJR5UHPdI8DOEwocfmZh0"
+      + "MFFzphskyYSeP7yVzfvwlOPda8l5t9a14PZ378J3TH3xArPeg/66uNxv9/FFs1cXqFzfPuXfNEquP2l3O7evs/Ob9rarOcc9i/BxZWGuyfhP7H3cpmdiZffC"
+      + "GeVSl4YsCmrden8+w2n2Pjx4aBCcR92p9qpgM/YGf26i1infjHp673cvIjcYVzlx3IRiOEMWBK+gGeRri+OoWHhYKwG5UOjgnmyykFTUBqgIMK4Dfp4P/5ZN"
+      + "vSJFiF9EmBJqUoivZc99BNQe0XZYqo3pAA+FXpiy0KxOTH13Lhi5yDEt7VrCssXiw/DCFSLN7UOPwVqRBlkwR7SiaFPlob93rI5jCW3A2+++G49BGr/uE9XY"
+      + "iDBujM2CNDyY2kEcqPteKVR9/A3+bLPGQn+J5r9Vl4IHIjaoE/lulKWOyCdJVuXjQXJqd+ahWinwi9BvPUlLomFCqLQZFM++q1Mym7LycI3znRr/FrVsmHus"
+      + "Vz4m+VCHNC3EVqK3LJqeGSgzNdFr8KSS2XqjIefTsMZZ9EMLadzhuQ9s/GHM80IJqXj5tsbR5cHjJtPn2HR1y1NHqbeXN2nd8E1UxmFCU9f6xNDKMt1G3IPW"
+      + "KkmIAQ6PxRWQUQ5DA5PPQyPBDgnoYILQnzP0G/3Rp904r4UznKhZmK07IuUlGMwkIjFyKNOBnRe/VdTfQtajUX8yUdyfxeUhXZz/eo+wgiPSemizfpet1h9o"
+      + "VJ0alE65hJjzwWKWw6Fb305EqTbbno+6BLTncBIhgJsQ7JEbiWfUXAGUDQII81eYXwoxWVc+b3YIJ01vSI+OmXyK8LVFcPALkrhBH+67sSMVhacOESJN88hQ"
+      + "+IJjeAj+60OZ4Muuj2vsv8BdDYNUqlYy9byi2lfgr7+qkmqVH5JqVsbB0E4r0yH8YBj+N1Dv0TxCZyUJKo2Mt2qDF8rbPP12Im/TU5x4cLMHne/WXo7A4SOp"
+      + "FHfSV7flHpFFFnZMx0jsfCylFVorxLoZio8q/S4z6FkV7FpcrIo+o95DJ1F27DRpxBX4nVArQ7x/va3jpg5PEz2Pqo5Jd59ymvFgsPlJdC3R2xejgSwArWfU"
+      + "1RHstxnDf92JuSquM4kh1fvLbXscPpeAQ9oIGKhwD8mcRFkd6O1pnf3PKftu/ZMXU504nhal4zdw61UeMnui9OXtK3ADJ3BRqXZNDXbcijDl0l2xSbO+l26m"
+      + "HREUYFF+CdHy9KvCK612LeV+27uc8kxFj2P1qgOJtSxF071eNO6pcHIENIPGbl37Qk8N+E3+/7zo96jthTu7IM9N74nHvgHJX7sA3njc/hfl+K1c3pkA6vcA"
+      + "x6gSIKyC2tdHhMI9GXqrhL8fw6C9r1AQeJeUENYr23QlcaJv2HQ+NwtTcp0H5V1wqDDXiWR4BgBL8IA1hB8ueZiQTE47kRAX0RYZlRDYIR5kyIQxJoiZpomB"
+      + "KkeG9nIzxcJik+ORI+OzATrvoKJFd+fYODqu/aH3GRXgVFkaecbWP9kIHBrwNxHCfpidX9zW+lxBLZYog4en0BaTVnOnqVOF8nuLWUfOlNuJ/qxYXc1bZH1J"
+      + "L8NjM4FywuvpwrKvvvOPk8DaO0gcyEO3HL/OkOq8EcLgwqmY5cFTHD2EccShZTpm/43Mv2W6m7sBNllb/i+4hlz2iL0D0ZiKqYmIPgjs6SRYjBCFHNHDgcvh"
+      + "/CJAJDYYh4iJAVbdcqv1ris9K1UJ7cmH53iRGkpECY4zxKRfuWwK+wUfT6/F4RL+iGONIF15ePDMVHb+5AHWPbaiwGwDfnxFGBtfSU3TQdPxrK9QyMtYgcfg"
+      + "pugohZztAhv2s117BtxAru2VGcYNEvl0YGjV+eCgGelX5l6L33TVN56v1F6uU3MtnmQe4M80Azo7mhv7cL3NOr/7ThvAYz6M3ANlUDlLf4IplMJ6dJtsLE/9"
+      + "xrLjSngE1lVuaEtLT5rUKJEeeMwS83cfq65FUv4bPF0nwAgebb3qr426274Kr1gFaciFpuwufcUaFnJM3P2GFYAmIRm3YM8acGNzwCok4z901GYId/1cnh79"
+      + "k2tJmTxeAliRfTUfJfibzu//DcR8yBi5gSKR50y4vBQjMVUYzehE/iDJneaG/rSZ8gV/f6ZxRrT1jUlXUU1sMIdy5dyrGFuK6kG4hEmXTnrHHAjgL7UzMntT"
+      + "ALWTznrpfSH9vGeQ/0wFYohGSKXfrtfL+y/NXlG4q9Ai9G4kML4IvV6DFeCfCmuIMieV2CCOfmQ0RFsLUAvj7F64g9rs9BYfUnF4a6IEkAPWaBRIn//kY7XZ"
+      + "b2EzBiqPJqfy3egwkhfs5JtuhtbWAgdYDPBQc1yKYEMdDIjHja5J+Wd9Wd/UrGUVG1bK0BN3dlqKXSvz3pRPuk/OOvxlw11VZ2rV/G6BvEZMFhFNgMwabIqL"
+      + "zk2GffQoCncwIuEbAi7KU2P6kMeh1eUUKwIKiBuQ/dEcN5XqLkRK7CKtEOKPMJeqmFJCNQQ97QFz8kmYIWY7zjBEeo9sK/dMuqxdQjgMMCtZiShE3tBoXAMD"
+      + "GFhwiasl5iTMPLhnAgR0Bm1khcwx1MtQ8tYO/Dys3t3JOTOtZXCm7gUu4C5RPSGRsubfK2gXzDuSVB9dS50SqQzJQVCB3i/hjldZygXlKXxvQ+wMQ2si4Ozu"
+      + "mPppRGyrOvtAGuBREYWeKvumZQbrPACdnhWyjEcMaBPIsbVkKy4aSsqHiimGVewYlaVowNVYBxdlnA1qEnXeNbgPAYqmWZGfANg1GbjV1BM7XlrmmGtetSBC"
+      + "8X/Tot+loQaWTqPoOQ4DA/u4XwBXJcDfLKW3/Trsvqim4eLyOTKXI/VeuUNwsxxpyX4RnYl0FxdM2GpD4RfD0fJSBnEx30Zcp2TOMPtIlqLKpD3q9VYYQSHq"
+      + "gnWo12k8pDahJX9r+1bIPK0QKg5zXjU/Z8svYHipeYMAn940AoM0fW/3/MO+K4u2pCEaOsapHGXHsZxIW8W1/6dXVm0/wibnxckIcZd42GCcMLDCqT9jBHfl"
+      + "QRBiTCqSBQwEbjSdKwcRxAHDy6nxKGoTPv2Cuv9isQYYv+0WvDCQZ+TDItm/piGF3HGhY5PAP42hmJ8UvKSBoO+os99OXB+f505B7X4ZBJLfa0ps0HvtW4jP"
+      + "1tYA8Jy5qD/49m+/qHi72G7YwOxXoy+K+U4Gh6FBiBJyXgHUlP05DoVyNjaCS4xJJlYHDEUYY1gDYoqBFtI5tPPuVYX2TnW/X78yhndhcESIUCiNjsEThFCi"
+      + "vdcdWM5/+tICtJQMmaiNeluu9qsCOyxtv8eu6ErMnNXteDb9qjmIaNqWS7HqsxFYQIywSgC3T/MxuTBm0OmbnoEc48aDROOXzYgR1gmr2uGoStLLk1t37pMy"
+      + "80GQxGCRYcNK3llxg7bKknarytD8E/kEJp+UmW2azWja8dtGy2u0Ghp0bPlpaJYCMv8uYVC9xwV52XGWf5JvkJ+y+tKHo5LKkxH/Qwe13s+M8S2jJMg5kdbc"
+      + "XoXS7y4Xz25AzR2oMgKUNmllycpNMxbzvxdW+1OLJ+Av30qfMk3pDz+0FexNPczqA2dKb24XMdN7T+2PqbJgrPUsb6k29Cszz2b5pX++QURO7R4jSktd+Uyn"
+      + "um7H2NQ4LhPcxszVD+e3xUWl/fASrGfGBHFMojJYrsNoXn1oAxqtq1p2KyJ4Yma+6vd3ZUA5gL1uUpHxOdGIVVJRQ5mwRk5TZL3u0hSsnG/1/ao/DYLOTsit"
+      + "r+dM2h2aRM8tyEu1L6gSnXZJyRxqAdi3g6rSdbH5S2LCxFp2aXckG0/adGozr9B9xagdv4CITmCL9Z/+JC6KX6FRplCXAH8h2yTYM4iyUO/ENeNvzBaT097U"
+      + "efEqxifrL8DBC++/7SaUDfHDSylmNcjOwl5R5zdr8a7ZUSz2HM9Wiq9mjpci7ciNz3QDRT8O6MSvvAS2Q2I6cj7psm7sCPeJH0+CjaLtXTsaRyKAsRrCQj5Z"
+      + "bSqaPm+qCh1gQG1zrNjs0tzrblGnQJa1eoS6gRURVumjqBywwPo/gGSu7CBrDg83Fzf1TRKWOpLvPDpWv0oONuuM2bG5I5VnQL897eWR49dJNVHpD6POzb8H"
+      + "01ZAL3Rsnoj4Pp4RZVR3bKCTvbSTd7+9dodUsRL3W1MtBzpSLRF1xsiUjB1U+A/IXvSBceKR74A5ek7pH7/iZ4ocsrYKAtykndDM9LUK8OwdV34XkCY6x8rF"
+      + "7raY6jZbF/zBGXOdrzxwxbrS+G8NZwcJmUtndra8hfKqfLyuw8jBxoMBLXUH27ufMqlLCtyTDScwgo0z6hFiMxYJUJuse8ce4tYQh2BSqXnkaoGOB5SeO8sh"
+      + "pdAEU6OjD4imFqJAuKJVV+finQ2pKxSfU2SkTNuEtVP9sTUvk4ZSo4o+tbO2iO9e90AyhFH4lBQb1g3qVVtb1Xd6xuQ3M0u+3yREucLC9Hn7K3HtyZw0urCe"
+      + "PsqV5odUqN+wbODKUC+gnlqyZLloG69kIUSawHtesQTXrh1/fAJhWU8ghb69TF01WYxtAx/0Y09Wb2b6GfkqHT3nxBP1F5znb0cABw6HwVfDyDGbpF2DhztX"
+      + "KM/KQyYY8WTPRX9pcm/3IRh9jg/51C/053SdUOU/i1iKVSbQWV3iXQhlQ/W29aww1fPe37OOZAxLcaw1pAM42FT3NNoy/lpe1JErbt1gE8Sz9Wev3Eq9pE+b"
+      + "WFiCZXJqF/vmddbFR98ttC06q/beJg7bXq9tLEQ66UyFsshbXBCLuayhoz5qTa2w9XV9LhVVKcUBbkePFALpdEXj0RNaLvcPfp3LpuDplQv4WjpnGW24S8FG"
+      + "VID9R6ltzK1Da0xtr63aJCsQslQ64gJdUlM9Qxb5mEQRhxNtWnz0RKB6XK9uMOOSvUtdz/hAqs5Rr8VPSYbC3PMQpPOwXDmXxVsDkIuvlqM98JpDecnP/Btt"
+      + "zmLnax6QAoHJlQZQxyFkydjRQCyWLJMDUWuxHR68EEu1xOs8/w+LGOZElOdjQdI62o8UrQnwWkYjdAFZkZw5Y2i2pTMgm2fpAhwF2h2e1QwcFgzVfAuNNCW5"
+      + "qx63tbGv4ftyGB8I7Zsaqf1Ii0a6A7dxFBsEyaPo0JRRjjjMGcXiGILt7hNFKmiozyvp7o+N6FBa0iGhzq70IPxzM109QR6+AmTFslUIuNKvkaCw9Pv/J61w"
+      + "uTZ6ZBMWQsEE8sGr9SxyyoiMAavSj/gAVWP0EF3EBxzk3z5L2bOVGRTQx5cGfnaOKguv52sXOzBAlaZ71pk0Oc/PusoOA1kzIxUknKEW6ZkTfJSpiGaFwEG6"
+      + "W9sIliJNloYKgqAjWCS0xC3eL5iBbybwGcLWa6I6dCUZQWT1oGlcBTacTmpieMsbeOrewWtFzic/zxi0EVu84GMCSmkcWB/9eJBzvqvMcu+2f74LiBOf+AWZ"
+      + "l+mQwmFqugX6VWlTdJMd6oB4e7Q/emsLDxTyr1m2Qcn99BdP+wum9jcDpzSxW2yQDkPsgMeQJHt1EDZUB0OMdx1Vry4CPSK7/Q0BPMYcndCvjH3x2oxVGTZn"
+      + "ofVsYVoCukcG6RdYQFheHWz05Ixihl1goWCyMPXkDMBbRWZ8SmLHSXakYYiXtyVH0jB/JRn77GVjLQYS+M48tjheO7kRDOC0UY5pN3iZPddlN6Q5+tJfVMVC"
+      + "dR1GhkRJ05o7CQSO/eM8o1XuaZaIf0FgRK+x1gIvqjBY78M8WGDVAkggBz7ajaYQ5xiVkU51ozz4N0KsgiqLzAQhM0mVsgdKvpB2osviHMwQEc1d6erMvcJ9"
+      + "3QHsQ0R8SlJIUNIQ3obEYrfc0xWetCOoi/ETY2xTA0Yu/6Dcgpub8C2GDImb42qzH/n2PxRyhNr1W8zCbxtvK5WrHUpzzJwS83ZJhndN5d2W5uge+rFyFMwk"
+      + "UPGta8CEhdUWTbEPYAPC6oAHs7CIxqyoTZBal6Mubpe/CpHKGG/ikHpThWHD2RCPGIxi4UPUJgPz7e+WhzGoXKaE8dJebqWs+iCjEilKyAuHUM66Sq11qZT7"
+      + "rdvtz+oTwA2mHjbU7peMlGl1h96bToyJmHQwR5MMRSv+dNhBAApMOSVhbwtNKC1KXd7ksAu0XRqs/AhLh5CI1vfwLKrcYsMJZnwHCHOAwZpVubLBZh0NsTmN"
+      + "ERyYr15TZn2wRE8OP56hS/jx6nNjE4wV7jcoWZhOBfjYip36HHobXrECnStlrcar+YRtk9AdGJgRJYpHUUKWDxB074YXShKiR4UFXZzKbKzBodpmi2+R4CKU"
+      + "P/IASKGjubOn1vfxWQkOO5uI6EKHM5+OqN7CRPsz9IF1i6WRIHL+qZS0NXCQrWNTqPpzahKECYrfVEVfFjIDcjYK1cYg4eEZXgf7siQxKytHp3xGiEdewnYh"
+      + "JrdjPOzSiTkjaIendpafEnXEEaxgT9DYevKp83amEE1MvKn7H9wrhgkHUbIpt0si80AsZvFE6vjBsiC6TjYWoD5pz4jfmMS9z3hXwvnGuNsFhWae+UGpjhDp"
+      + "bWqxOZrZuyHR/wo2Q9vo8hV9BUrkGyPqQozLeE95rNS4N3lliwB7kwPL1UTK8EDWfEaF62oOi5uDh/SjWovRtVSWtGF3Nl5ExpwVh9JebYmp6IxVO1Hj4Cjv"
+      + "TvJ7SSDn+uem5ByE+vhptBz7yOKZHC8htwUGrSwYMGQ99B/dWuj+OLhjns062gDsd+jHvwHXynl3k1pGT5QfIXXZlvnxZ5eJ6sSAhgoLIDKXaIK21Q1kXM4t"
+      + "bQu4yTbnhmlhp8loebI+KQ4Q2CBLihbLrEIQvkTtEgonMTuk7D5vdteEjqajwfk0dF0cXBQsqe+ftpTi5aL0j2/hl8eoS8bqDxgAVNdrP6FLDeUBqCuJFzkY"
+      + "cXXqLGfryfEQH2W02RIcqdft7eH9DpaATTP9cS1Y+M1cx02g2om+FrIjBdal+C7k3c06+a9NM3XPLCyPBsXRw7cK8XHRLapQjV7b8iWGzMbcRce8esxXvpqO"
+      + "ZWl+mRemfRPG7NR7vMuYQOXdqxzAoKch9s+t16rrGMzWiQB2tuBGFDJr6vj3R1dgHwp+VX3h79LzCqk7gGXYV800tj6z1FQ5ck4+UQSD24556c01GqhyIe8p"
+      + "z3EBvHNrnlGCcCEDFypl7XbAfiZltcLG3XB85LJn1Jipdkbvl13nHMMAChpYCnVwdflGyqtKU/SY7X0rB95j5tka4mC6rXvCdW3C58ioPRMl0NB/RbHGuUW3"
+      + "xnOH/ii/uzb+4HEmjP6ckj08bhlr8FRwHjsvvIubWFPQFALXKS7nB/AV52UU0rsJXVpZ2V9BmPtySjs/Pske6pW0r0xvxUhKDInpXGMwEtiXNnG8JLZObLnF"
+      + "r9iQ2EkY3JK050soLJlpnY1dJkzLzb8PXAW10MbkXl2ZyCVf1aVOntbGPXTa9Q96DoEltKq9eliQXm/kzSeHsGcSXDuWlZuLPCir68ag508IVV3hVVE6uRom"
+      + "CyHTKT1VDV90Jub3k+l3Zh+iLo6k0mxLMbIOGnVgWF++SjxMO7o7N9aTVIjaFMDJwjVFeCCkcdqcSyZSfi6DcVzLt5434tYD/ZwT7fs6nMYZmcRemk3m0qLK"
+      + "z9uJZtteBuMq7WThR9ad0+FQlhNERHPziJnKBJRKhSAzXeXaVkEtQCqoqAbbFYjTlz81NVbV3wW8eGmQD26DSRmvUKgoiH97/ZLMX8rAeWSj1KBqNn0oqoKs"
+      + "V9N4EzdMviRhDW1la5v7iLUfvEh8xYl4xl6EBcrRvjvedg9k7kQmCTCJITMMezU25cD3Gp/Y1bzb2crl+j+wZ/6W2Y15fUACFHuQ0fd+Der+FMqwpKu5IVZM"
+      + "/5TeNp8bND+hC9T0klV2epsueRy2F9rN9uPbugfcoUfDK2UyDcnBS4edDJ+HEwxFHdbVn9puqvgkfHUJbzzW097EYt25vzr39TbgvpRWnUQUx3J0zYTRRpcL"
+      + "MfON3COxo6AoP2grkhsdbfSEH/S9PExjaVoZ6y2bI91pgdDpG2+AGIRnOi58Uk5g30pV4BzBl4a52jnPRg0M8bRaM7MoaGeobwix2iVvqNC25fWJsXNzhT5A"
+      + "5hauXOT4no1lAuCFLpgseizfYbI1TXE6h44ELmj0xRspoiXaF2HdycgROfWeiMG+WokJW8i5vcmY5FNnwQVgSOVnV5/ptsBOaNrUoov5PFVkWW2E/C4Q4kup"
+      + "hI70O2NB+ZGRLXyM35GJ3/xhxdc2lqSdsDMWXU8jHfFINyYcxmSlxYG1NETBlEwJmg/eSKbDaqHNO7WMNuyOFcZLlT2xsFLtf5X+uRf0GdtBVOV3QxGVhfsC"
+      + "QFI7xWJJ6mm+r7SE0zoBGPKf+OOo1Pdqx08UhNslgIKUxdV5KzCZrcprVUgsC4vzgZydMOc5jV+iNrwSDRLYrPLo47Jcuuko7CKsZ3RbWHTGt+lgcRIFumP1"
+      + "2Jl8+UgG7xaoadsR/5O/HQDEq7Awg3R//gwMMi2hlSZ3YtxAtosL5L23DXblyNMx8Rr/S2T5zs6tpWgtLSu58PJyxwzxZZIctx2UEX62NMVzHh1KtQw0ALqZ"
+      + "enc0Il8RVJmvEdNhTOwYpzY3xePs5bg5/s+XcNcYKlXeUkbHhe8OK7Z2mZrz9gjRjZD+wokaM2W2Ndr6WqhvE/F1o+CGKEwNR0LzmRIm2KOUZMjTM1G2jthU"
+      + "4jQlOqq/b2EzJTQgBBucq/ykipvpddNNgdv5sQT8qoue6P/eV0HzZNP6vtocouFI+Mm5tn0z34j/Ng9YUmgJ6NOnbqCYZJdvcQMwMMISmPQ631tZu7qlv0KS"
+      + "dF5PoOM7D0dHrzdxaq9u7KXA726NBTPixSzDAKrG4FPNvENNIhJybqYkpvgobmBp3sfgEryODBGy3BiYshI9wVIVtMpYlxSonAhVb27oEPSAu+YAVeDBx3U+"
+      + "90/OEA1BBlxYRemNIdyP3H/JragkYiVCp+eC5Q8IpfIEOx0F3SUtFmtHfaWOKvxgci6+jzCEzXhrT4fAyJtdgsJ9SgvVGzXxRYvm2crMYgn6pyz02rHi3Syb"
+      + "mQB6xUkqiml9qjfpDiveiHg1RBaGzzZr382Z612RvLwWnbC9BVt2Hg1rvxMT20D2yZLPv6jCkg/DfxB99YoQO2JGotv4CxNvIyBablefe8h7IQchzAuQREp4"
+      + "G3klIR1M3UQRomTo3On6JBx2NNLNsizBppWovqWluqyW5+SXXApfg1t/HXPPZywJzxZe58PV/1qK4d7P3f7Flj/V4OZhPMU3Ht+jdc1N9yZtMFTB+Kr6ejqB"
+      + "/1anH5R6N/F3qwAldWKWS8s355GI1RnOgHXWco0g6eVn47r7l9ZrLWC8Rx9oi3nus6IyuWK9rSzWlA4lzSoqcP+VcqZG4xkkL/gQqy/EEhleHxXKxm/ts9mx"
+      + "DPF4wj1onaF5HIwINDg89Z10TqW54RxaDHxyoNFLq1gbMO7b+BQyZoWeE+Thstgvb2eo1FXOSQdl6KhgBxghJy0j6WZTPoKYPk83WZvJkUJYqQs1IJq7pRnU"
+      + "r1n+5FT7HFefVeuj+reIS7uF+ftZLe7eVxoq6GzfIF5qUWQAJEEMi8bcWQiop2J2FYWWo2EDbNHgw4BsOUZ+Umty0P62uVPDC7mc+cm7rdoDHK5vMgadHDVT"
+      + "pR55DQNQ/HAxbfgpIY8MR8ka1ai9xkCTqZ2fHZ4rT/xWvFde/j2ngwuTlLwZdk6xXbmkvwjWkeZeKdomRdMgyNLj/WSM2F+bC8FNanWbHA+f6V2dXmtbob6U"
+      + "3yUIZ3zBvXAbnEg7HJY/krNTqI8GkYAar6BlXbAMumW0iVk9Sxn5/MxMwl2ytPdT7zwZ2ER4Ldi7L+Gvqg5fTBtdgDPBQmYmQimH/U5YX0bjEqK5DBK/ynCQ"
+      + "7CyUjCxJGEdt6H+LEM43bpD+JsSiaFuwV2NLFALq+zefDy3Wt5oOBrbmAmLecuiqv/1coS+s0gya03U8CqZf3PUQaZAzfYq9uiivRjY9r5FmoiSeZxKLDDDZ"
+      + "3oBmuMIJrmJUWWgCOBPX5OY3I+3vm7zQwq9OGOvpwyfOegRM/y+lEHc1kUj3Eo1a59unVIiZy5GhQmyGFige1VSvetVju554ZTG8dDZc3Yn9nUPEqZR/Tvhs"
+      + "TmbgovT8GypfFK7EVm5t4THZPZnCKYBN+y5SJSll9rTCjB3wqX9XfMpsFRxZA84swkvR+MEPPgIQNWrv4Bx+Vi1fjdYy4oD9QyUQOGnNxShXZNDAji8ul8Qh"
+      + "OS6tF5vfYCK3ey1TPPK+kNx8vsyx9PJZxMhiw+ILN9xvBvwA2IJKFdtoqn9invgv6DH/hK8Gbiw5nfbaqjsA/ZlV7+b1fq8B4yjqEBo8O1wEEq3BtTsfwmjQ"
+      + "san6Bkzo54b4aDMMC4puywjcYyU6ONQ9wMzrsCjTHQJuztswhJx+0s66WvfcC7BveiCCwvWMtUa6XlBFgUUeqnpIoXSulmdh3CRp1ZcBsXuP6Zs/L10EAyCg"
+      + "CP6eF5nNAzjN2G9LnLFBUKF7oqPpArl/f2ZR/Nb/JxBcT2j1vxg0Ns7snLcdnAyfLJAhhNzgWMMMxlwC2kU999u8jjOPXnIOzJfaup53GV1dDsCzAaRG9fxn"
+      + "DrOi4WJLPo2HNL/6zpcBGi0sz0QeYsZOYquVukB0I+Cu4V/BAfNXjCZp9mn0Q37b7nZ5Y05ee7bKHVWj/eZOnqLtPx8umEZD9K1T+G4qE9yFjrR+hfwAYgr/"
+      + "OM4KJ/tgwM5xCMxSwt9PqACiwT8fFLQlBxJnSEbBJo7htmEmw1fmM1t3TxseH8Kc44XPYCVBQQU7fJuyw5OnMxLZmjbpPdBRDknWRsefthOGZhHa/W7Z8nsJ"
+      + "92m4kZ8ulV90DyAiLYRmSO1PlcSmmEI3ppAXtRgZiXSjGtdBwm4RxI/eTBtj2VLQxPw//6ntg+yf9CrfqlTPM94a9jmtDcbF6kV9hQ02AS/xpmlYS9o04Lu8"
+      + "fuYv8cL49au8JzDWFthQGzCNasfEKhDWEZzjUJACZcxdEDSLQWe5YCqW9CJW0VymnhRCVQX8XnQmgbts0efrO6NApxQjVHzCR07eGGkv50Az6z4mPDXYvy1s"
+      + "0NmnaCdmlG6bCHDWMg1ikUYTdBWpdUk7CUMTsPdMUunLnZZ08YXvuqJWAQyLTsIyvswcKvQPJo2XERTFKE73JctWGh5Ebky0EOd2QcMHKf1y9/p3zCa8kBLj"
+      + "XfqnJnE+YhYf3rfleMfQvs+CtKkwXDnTf9PGZPCDdFRgC2wi1AdJz54kp3r8bnom3jzRt+7CTcJ9/E3SoW3GYF0UcxPBZucVxQ0PBDBpQJmVrg88C0v7dI/8"
+      + "sCzY2nnRFuOxTaNKY56I8CDTPhjDC/mGTmVJbzqsTasKAZCeROX5kQq9Wk0KNaf+KTw3ZaJMaaRcJlUi8A8BbRhd4DrnzmYv1bqe6BfQwkcFuMUuGeXG/ulP"
+      + "6xl/XTqyEV2gNY1r5VOmiUWThyyUkyKaV7/WuJI2ladkP9RVhFl2piACtTBfQhyJfYUX+5wJZV7MoOmnMIyvm/d13PxJmmEgEUF1wcFNi9+Pp9vbNNFBDlSo"
+      + "sm1vfiiD2wBKO8nlziHM2G5Z94NEvBfmMfKJSKTKYAtgNw3xknd1QpVc0966/hupo8faSmd7vEPpYyjrbA4hMP0unLOzPAneGTrW+zNQiWGvBvnr/qNM6pOq"
+      + "FeSU+RkN9IT9xDAMJLLzI4XXL431aN8CfcQu0EzBHGYV3kygihCOdA4yCRFz7t3fKh3L1U5gpk45wKOG00aTQaX4LnBPOXPuNKb1+JiGsTmfQDwh9HM32zJ1"
+      + "6gyGuF0TvOx99QP8raXZNhAfak+IDBRGe1kO7fwskjLq54esm5zoIbJlFR72wtAq6lqt5B5ujmD8gZUqYyDtjgRw6qhnnDeCd5oth1qk5gNe5K6EuZIQHrV3"
+      + "c/HvBA4pwscWjQ8U7m7VqGZoDmaNHQ2PIGG0j/lzwOVTUUFvbQLfkoSIAwW4qnDKqdF8WJ3zVoD2mTnVo7+/RhepMaXcAPUGLrBRQmzFNqCOyytDHZwU4t0t"
+      + "4vSTcPceBIXVeln9ZcOGmzWY4w5OujUhCfy5n6AyG5RVM7250oorS/QTW3piROGOSqwE3Gn2oVla6Umf2NKr6pmoxJgcx7MayIK3p7a6kdotKpCuE6j8seNJ"
+      + "PenAGt0m719UgTHnhe/WniV5CfK93przkLYk3d8+DJmSWuCWQLKwGWKVyer7tWIx3TaU9wS6NYXQ/vJswlAQ0A3hAiYYyxjGBw6IrOYOda9WDrUClAIM0BJA"
+      + "gmhCvdxUuQz1OdPgon49MgUyNWIzffvbY2ETsn0vQ+6EWb3l/LpgnKL2mM7MIeef7rbDUYYNDrCkFcBzPHpbuOLUCEV/ZVuE6crC0+bDvgtapF77j6TgmR8g"
+      + "NigSbp04++7Sm14nXEvjOKOjWfSvBZdFUm5r0o3HI1wbj0SH9iu2hO35U/3cyklNI4zEHgynKPTUPeBqaN2jkxEHE84mML3NSqE7CwLEWx5bb8cRPgtm/s+x"
+      + "OlUlxsD4AvvX58NIk60gJPb+qWn42ZFfKTVY73sTApJIHSPx01sPZH7ex4USzJ0cmLEfJDrKkBHj/GUJYnx4QgLvFZzsJmYU+NFty0u7yv42RnKZ1PgV7qSt"
+      + "zfRpZI9nEO10hjXYbgsiDV4J3X9UJ6qIuLAi7AejZjTkUPVj/kG33PDTcx+1sCeJ5SaRHZabL0jkNenNORuSycOg0HOV75N0FWeGRql9Fdr5Hqn5KVuhT0ML"
+      + "jU/Ex7oh0KDaqKzD5kIWx7QCpGQf0XuMt8xWB81ShpXyhm1/PJqgB+qTJWOsZfNduus7+EEVuufrkEztAL7kzvPK7A2wWZgdhUosJMl7p3WL7dGCdbIZi5uf"
+      + "Fx4d3TYg4LRT8fy6wYIUVXlSdlsOrgZTUL6GXg78Wx+CKJcbTG1jnXhPbUXE/eN5OlI8BfoX1R0rtgO27R9hCWAKaTLAgPOeLrMbQh0l2PrFbtIcIjpuBPLV"
+      + "g9I6LDdY94Nyz15nuk91Q9/fZ2fbS0oiCtSid5mg+/pnP8+ysSHNMQmx+fRuOd9LGxH3hOlYdGvh71cU/6MRYp48kQ1wpPvyzRJkCWXmLnEExxF6MhCnwrXZ"
+      + "pkcuZOljmzoY4mWaBDkB7XlbPQjr0hqgdJN6GpCFYPt39HA0jpXg0MMP/6b7xDt50w5OxrxVctqIzg2GwUiuvoEvKL0a66SvF6N1bZ+vvB9U3zGDhTlUaSA9"
+      + "I/5Ufx9mBq0f6FqMnyo28WFlQSv0GdAHwKoJYL6DDw+4E4RkRj1KDQ/xRWb7RFC38pUzc4QOk4fjvtQ6TrqCY4OdFxgMnkIwpEidV52cL8muYJ1awTY9+Zq4"
+      + "S30VxqL306shbAu7/todhWOV7PhMJ9SpFYJJBo5sOBsIsOO/NK5MZnUw7/NG9+P6rTJ2DEcMUKt/wvVkBanX80SOl+EEV3HHknwTD34oCkyxJWmfm67xVhPG"
+      + "/EGs/ynZ8jiwV8/710bzEkO1p+vgxCDokwvuOU4X77HLCP5HScoXWgwo+43GMHan8pE0PiET6nAXtA4CgPfmQLjVolqOIAvVE4Y49wHN0rIQyi84guFbT/BN"
+      + "0QtA3XECB6F6JGPVLV3PIRkOuzeIVygIwJrcLTW2fhPADy6lWvN/bnEhC+5vDVPPmwgF2+6Pw7G3aoTMIZaxMM3TAdDGrbSzgsa8HBYjV1a30g/COOHzzY6V"
+      + "Kq2yHfvrehKmhfSOMkBYq/mMRiN6A43Eib9fdP7Rr66lQ+plDc/ig/GSzVFLyOiCHYMSgUxG3HHrMWtKk45J6FcygP1S6xfjToWYihm0uGuPuXn16R4OmyjB"
+      + "SOqjmyS4y9m7ZVfYIa7aertNrl8FYbtWmHlbb1lysuPHZKiGOeD894yXXD8rsDUkZ987pIQR0TJxy30bifF6cy5M23wKHP6+FDIsEnkdzC30cLY2Cqoboleo"
+      + "YZRoBDLQ72RmCowrt+JmzOn4qT4jIXV5ouoxBR/YwhlFKc2L3xVeHv6x7LPOfqWDbQvcnjjHhF4jzZgVCfiWIW45sfswqwjRvnmlKKg47Q5MG+gxfHM/cbI0"
+      + "jGKbMzYOY5JngdQfnh+KfOAuAsqMF0MyOgOzgvCfGxyXcQYRNMJuwdeo8RVqlM3GqXzg8H9NQYhutAESoIEekdOoxx8G7PhBeuacPvq5TxAvZWB0sLw6RRR9"
+      + "Se157nn96kEwMRHQMeMwnnmGKlW8fqaBOqdH1CAXJooaasHbAV2eur9fhAtORKT9RVdhfkAYIJ3Q67Z8ppSxof+w1HctxnwPwTG9mjTWUtEgEMzeV7LO/AF7"
+      + "SKvhA8w072J1ywu15JQU7o5Y5E0UvDJyG/vW2j2raXL+xyoxmvmWhhv73+yOKTNfS3zBSrNduiCAQPgAJQQtZACPUEiSUY64Dj4xUKhTfLEqyGRxb3cexxEk"
+      + "VFocr48pI0EIhpQCyBTbR1WgBEjdEFuw0U6LD6tgmUaydSid7mjE5EDrfUoku2+s/XLVUMTND7UVUKynh7lOWOPoYxSRsIw4fEbMeMFJDjHMJDPJ7GjtKNjI"
+      + "aflH9zNPLelqYHNw6Jg5DZqXd9oha6jedi1dHw1WhYJ11x5VNemkq4areQY/GZB23tXMywzusktOUMTVDueatcNjR1hSbf3HJ9lm4CwiePUTuPNmq6J0l5f/"
+      + "Xms8ZhJJ4WfnAiIPTTjeOlv7xRDjW+yMLHY9CkS/3zRQjrjdmEfLOxwF+Qgd7cr4yApK7P8GscW7Q7Wue8BVN71YZZpj4E4OMlQmf4CUKsTt+FpGlLf/xoIE"
+      + "6SBAeaq+FUdi09+Sea1JWczgo5BTNdy6f3HrvcfaGKyplPBvp/j+sNT/JK+VQ6fPikdIXpUIm4gFZmKeGS5XkvIOYfPJdlRM0nXaOVZq3DL1YhVS1mXV/9vg"
+      + "fM0Ms1OntfgqPk0tnC0yhMnqKNFps6+OVYvX/z9lA7m+jTAs4k2khC1CzpUyO2KEm8qnULrn9p5NJqjkxw7iM+s/lIojrm/MsHn2Bk60KGyeQevflbbYd2fF"
+      + "FZECiuZqgXC71urWz6W27ayOYB7gEQpU7661jVws892BEHPnjHBDdTMjhJckpp9eHrcmP7b4Deb3DbsG0ugQVvDjXdWPyKEiHhinmhV0sgFi1jsMsZZrJ3JN"
+      + "caTx5Ad+JM85SZyWvd7KmQVW/yfAAxoGTIDB4jqwwkBQNTHJDO5M9WdmGqXYtkUkj17s7kgEggvBtZ8X68ui86oPrzbUKrxagS38tfGc5d1r0aJEGHnEkGjw"
+      + "G+Uealr0m+sRuvCv22DwvMvjBnhlJzDwmf4F/DDii/7xnZDa3Z35Wvebesh+6F0E9azOKRCzeT+2Axr+4ClRpBMEefyrHcRd4P5hVhQt++COOvCycmNrQRtB"
+      + "M1ElpX0pTncECkz17t/7A9PCWAZhuWoWdl1LPVSxZPZoR3RWBNvaaPJcdKxxxzPxQN6whZgxRHW1419RWtdaudZQ7IOAUNv/smog5jyVPMP+ShTqBShzzXLf"
+      + "/YHUHuB//noWehY9cm9vc2ILYvY948strO32+UzVlWZjvmOhyvSKJMtuvt0w1gObtkUPOFi5FQJpOpohVL/u+74J+CStPsOvfg3g4OvUNqNae/mzEOPsqA6C"
+      + "5KHdewqI3yM7ysA6xKOEGGN7HS+ZSBHJ43cRFQxvQeil9o3SiNxN/+BCBHxEZieNnZr8IKkno88vsGADITvcQE2BaGERir5hC4RhWnXu5FR6L0hcejPnFh74"
+      + "ZIDJqE9IRXqpa1ruv9CEQoyhpUNfm+DdJXbfvseckFMygXXR544AfcE9joQaL4+gpV7MDv5vKH2g3fmZisWkBfI9cUPV263mngDbGMGPQxlTLFj1k7TdXXom"
+      + "DtzKjtMt6qg7kUYZW8N+RN+aIGvH5VEu3lvk4hYZisS0OdoMC0p2SzQ/fhB0R6OvnsLOMNyKqrVGXLoj8m4SYDfY3Xh3/NuFLqFfkWbH/puLT4AQyES6C4Si"
+      + "NRBesscpnsu8WFDMmM93hXBg5c+IwFSE8idiVIgcivx6IgjH462rpB0paLumY/Vj0Yn043D7FkAxgQVaq7eq+Eh2QDZNFEOuOxHJtqtnsrM9vOSBtpLy/LrK"
+      + "J7yRFKpWXp7rmdNYagMDU38n21RnUuLRUUVTPAuSGyW/5R/imJeSdc4MLMm8QZGNbBH58zQR+9fzWBj9cKXNm/82lskZtO29WocWloxB7nNbyIFVRXcEyXB3"
+      + "oZdor/PJju92zDypimsabxVBMLG+2C9x6haWyuo2M4ahMJFFTjRiHeZ3X1C+QdTGNdhi4/OoE1v/u5UAwAoGnnuhm/CODNwStq7VjptrxarkGBgFT5aZKyfJ"
+      + "3HkbkQ+5kDv+KKoR8Eo1xwA9lkWykF0Bm+oANcvHPiAJB0AWwkvjRMf9T7mwftzZF2ZGxTKaPP6a1B8CgkkiPFjHVf/hJb5N0n5vC6FPvKI/B67rJYlbcTJI"
+      + "ZVffXOoD9IZoYsgb1UFOV3zX6ElbHKbFJfYIGw6gyx5THX2/a62bF1iA+JaGicjGnkJzzdu8QMVMESmadOLOg2Mmf/oWk1kUBZVJEfgRGyFRXolc658UEuJw"
+      + "RS/2ZkSxy1Gw8nOy+JhZksNZaA8ks8UIGwmp5uiRO9myS7vRtAuhfQuPgjqv2NKz2Zz4ojL3WjaMjiGOlohldcdTuzQhg1DvycLQlRgjrK4j3rttZTPQo3e6"
+      + "0f0IpHs2L/FVtyIiTdTDckzeYcSu4I3F2uJM0NzHQtYjrx3IF9waCoxxO39Ln93Q2EY6I7azxWYg9MJDF8vTfyIyBTL0I4uwH6ybBygRCrnnqpYr+luBXX4/"
+      + "bBeLOaSfLMLGnG8a1Z02TqPENd4suuU508nIuTYZAoWxp8+bZjaR3vXiqPCOF5Jx/4Kk8WxjDt51YN2N3qROyjuyCthH/5j6SGIIFg6TaOA8YMlykCux1yHe"
+      + "UsBtA0mUkN+AKTa0quDJpBw+D1GFdeHlzldPXeKD0dRkWW+khNKT20BEPf9pM+gGgvkA75tlIlNwM1N9RWg5zYS03aVFVt9ZAsjpzol/yt1eUxEB3WNt+Isb"
+      + "I9/HDq40Vu+puoVs0YB6pn9pUIc5EJaQpX+4NSizFRSxIIUG+G0PIyBscjMsllAimj6kH082q/kTWKaKKvg9N6d1MzY+V3Rltte8QgVwoGP+aMMUM6E0BYzw"
+      + "i74BnI0et4iizVdnXg1Nl+y2QqcN8z35B5Rxouto3it3VWZOU10vA14iTpkapn5RUQFDnIdNfM1qa/MpuUvKx7IEd3vvH1LFKaCWd+NsEOb/GGxf2KHX5kos"
+      + "R3/R4SmiZ65co4iHoqA0D8SFizwcnr1XpZPnzU6cptNwmEUau6fB1xXvbU7xlJoylNmFavOUY/5+YiCfPNUQTccz94KXtbKwj46qVCnIJDIa7cy0cxrzoho7"
+      + "rEDKvjlADKvK/1v92NnMBc6zCpkAncFMIBAJJcTJHoxGYDLr96N0tC4g2gsO8nsWB0HXdjbl4dJF+ZG6G+q3hNo0SpoHcjWAw5lr7RGCCKX7PvfwME3SF13B"
+      + "iP53EOk/Lz7mw84hQcWPfnCEq90kjKp3h6q1/X9SiWpd/FOZAmp69E6WWOixfzfOny7OMK5wFuCci8iIbM/Hqo2Z8zyR6NaQ/IK+qbEUD9iatfdd5AgvO8g2"
+      + "YJxC68Pi4xl0+iVjhSLeRH4A3ZixmaLLd2QGKUiNTW1kfFO7+31kNuFydeLRvwEROdA6FCaTZO5EJp//C54B1irc99LyBxC12SLBbCQ3Ai6Z8EqQatV2imnD"
+      + "gC3pqybbs/pYkOlRkO5sS43EGj1rF62LmsKkXRwwTzsDwvp8gWxznLWmTsZw8nlaWWplzSsWrJ9wnwvC9REDzPJGLvtP1VsCam6kojsYHkLmVRZsMkzl0nOD"
+      + "XfWVr0vUqoA3mhs0aXK5spnK+xzCr2mQrqn0XfiuSmWoCHEtiPEy4C4vxFVoBtgSHZftdqhambNU5mQrQbs/XBsQjrto8IgbIyXyw62uFLrN2Fsjvf1MbXJ8"
+      + "3vPGYQ0/Rqu0MbALpFDwVTSRlKbmpcl7TNSfQWI9rOS3hwWTnTcUgXl2cXpIvorqfybwvbPAXsanc7CoZdvjYQk8bSoryDs+iaF0WWbJTiQLLJ55+yLY/9wA"
+      + "3TV+mmvo0zDa3eSWE1Sijdu06xXB6UFd39/Ej1Ugd4V9SkLyopcIJwKqUJ7m8jOopuk3RMWFT2T+CtZYFXcPiPs6wcTUIvpiY/E048yNRxLpkKZKxmuGakMZ"
+      + "hKuE14EpvGNX4CRmcAo6HDdZV44ScgXZIN4Eot5EWIQc0eURaZSfMKi9G5e0G7sp6cMQAupTESMYMbLuwI3N0NrrfXmLIyQ839Q4CfuTkyR/7reafnmcurQg"
+      + "GJFxxdkVyp43A9n19LLZLGo4soogDhmCmN9RKulE2OPF9Yhd/n0WJFWl8eWvRttCStjshnYGprfBX+hf9yO46CW1DqZ6HLx+yrpy9NiolvC0ZHJ0MIPJ94H1"
+      + "a19+B/ynSXyNwfvaVBoiWssw0rBEgiaXENdp7zJNk0CMb/7gQZs1lqTKsIJilX2w/tsJ3l5RgygmeZXZc4JM3xtfIsV922uPQ23hX/yG18q3fYHaP6mlPJ2e"
+      + "f91EpCmJr49+2prkIX1EXVPZj057Uis23X5WlMYtYWMuGO15Y+JOMOhqUMopSIgrxUHzmb7gp/Axq1nL1js9NnVzJr73KLk9XIdKjkhSZZdkK4mRwmrhy0wX"
+      + "upYaynitUD0ayzsGXsuLX4h1nL7PWSEhik9qW9SOTjOU+xwxzi2y67c+XVyk3lWVBuFfjHHSd9xjXeO01iBFZZT+6ySSM0GnzSPz3FSap1ZRyDUaSsDjZiEX"
+      + "dwfsQWCmA16CTIXif4VDSBctMnRY+znXd7nBRmuYxrIaCULDs3Mwqz/lMP0cCdI1gy4O2NBMv1es6gGLDVzwSQoU+nhD28ZZnpTW2y9uNMHMY3fzXp5GFyOA"
+      + "EUJ6hdFGHinqMWchMAmIe9d6jsFZdOmqWSFwltrexk9F7fZ//D17iO+Y9zjhmt+51ihwu4pAC1RAAhXWhQ7CAOz9phs7IN5QVVL1G/Pgw0d5AxVzIBFYTPGi"
+      + "LNYWqjr5SePfnO4nHy6U9MytrGWMaT1U6HoSKrfys2RuCNJ+VukwYSnvoAzQ71A5xWoOeBT858EjTp/Tlvby8KY8dWz00oWV7qv1+yzA4RJsMYkNUhNFOVv6"
+      + "uYYdfHG5zKv+su+SaH/8s1r99/lbNNj+FtWQU1jzrb2Ynhe2MLajBmT6U3GtJ8ObkDDqiOH4JMJS+zWIEGdiIAi//G1gRCoFBpA0iT1+OpBDVj9bQ4on6uSI"
+      + "hQCPRZysRCLQlcyZEEsiG/1wlQbNk1uF6PtKn+zS6RxxRhB5HL6nhgGuSNrRFQHMkpNj98FXVp695kkFca9hTwd0I6fYPW8GITkiQ3s1Jb3JSJsL57aer8aC"
+      + "KEgMe3YCT4fLIb7/oTbwyiBy8f3dU5uG6HFKo9l+fBeW8MMtgr2aKI/Ycg27eLDbUWSwj50vY08M8pspZV4UqLhcX0g92bXOwcZhnbC3yEPphMjdJ5rtrdkU"
+      + "o4tVtQex8M6epzm0LE6OXlrDAebnhYa5H1lynqw8KrK86BXn+Wb6ecF+NbpoSTdacOT0Pn29riQA4CWJMa6berQGmJDpnmYVsoFIwWD7LhaOlXhCbO8fG3oK"
+      + "DMt6NeSFpi1Ld6exqoGqSTLzYezqCuRcRCycx01aA3I2g+CZjzZu/uzJkDeGOAtcsK3t9XBqT/27lsd7SStJNtk76OvqZbsuK2DLiA/LLCqwdceqDDlZGS2Y"
+      + "3IjXHSgok0mifYGeeA3n+C2e2zVoo0YAtop26YU5sWu29RDhwE8AHPfZWvpk1lTbznJSf2Dzxp4zHIuuUvY7DyUCu8L64ePm16SeZPIVzxBQ3qEFbL3TW391"
+      + "L5Zq0Z+tFCME+f+omZKDDSKYE3jN/0vBUfqOKtXQ6MMckbxrTY6GfoE+rgEjJA1rqw+5rZpnmk6S6dOQpAIfOfkq9ImBLtZUqetkChQk/7dxpFgWgAwztZtz"
+      + "2pelual4JSOzBK5e6rgLGxCHI8fxaebLajuYhYp2O/RsScJg9IWLAJwqvaz60XYfRBbT/M3A8Iucyt7E47Lv/yCuWqd11HDPii1t+okC1VnMztHChfiZ7y/i"
+      + "bxn74R3KJQi62Vu7RjTSi2Luw0HBdtRA3F3XhshpODVHH6UOFhStKh2MIR4Ynd74vaAMXBZjn6pQJaGdsgYmI268BnhkahA0NK5/mjoeQgkCyM+liz8AL243"
+      + "L0p7lHrvwO3OZOGsnDtGWMMtXxtmMwywH5GAZ3JEDXqonXTqGQpNbBnPctvWHuamFcQX3lV0s5K9ErOSuasgn8ui9ayIM9XGg3aSB6Q0qJcK8qs7XcYQw7uU"
+      + "hmVmwo1sdPQS8IyhNyceF9qJqeheFV3s6ICp15jNgUtzfKwiJzdeO5IxV9JHEwwfmJGruuscDdWsCgwLD7OZCb5L0/IVX8Y4RXeEZgxm4QxjpbJq5HsF8ybG"
+      + "QLadBwOElt6fXV7lKs8i5qa+Oi1b2RcxJDNIRPv30oTM+02ikI0NyIdc54o+SAl0UaowzgmdVktc9v1+8cQtQjIC28N6Lt9TUI9CayJQzQP1xTLpBj9HLA09"
+      + "3Jo0bzZlga4lIQQDbMSRyfrEbFkaUBJb5W9WFAEy3ZchXLk031P7z41GJ4Di+hgdBCCJ9JXtiwA4gpfbaWprZj6zrddmGDImqEXO6UtDFb4/riN6xzfmuZ0J"
+      + "GsCs67HkAJce3GJJUlmsqZid8bpu0VUbhH8RwVWsMu9wuL0HEDRAPSa126C1kDSDDMChiVxrm0dLF5LN4oZqUCDGL1vkb42medpPzabnl4nHync31PvtvecF"
+      + "zOakxDGiC3HjnF4ziwWLUyvPNTTLI6rYYLhDKrSZ3wETqlO6LdYWcgprGMZOJ/KXnrIBcwa2i8wE58LNId3fVHtKcsgLm1Wrg7f3q8hNjSHNFkzjE7ioxeqO"
+      + "cEggy2aKeQRF2Lv6mg6XuHAP78u2FgmNATMdJj5ILA+FRccmFTjImS1QDyici19OX0ab/xh4weITMZzNc4mcciSSVgmkGf4cTrMzN9pHudoMwcZw+J9RI1ZT"
+      + "+ctIRJgS0QiuvdgG9XzX7OJfgz9XPGFGv5koedTIEVps1GpcqYlmFpgLP1o7UsyKTXBttyJVcljNKYqYJ7t34fThFs0+FYp3tiH6F16YWXHZPEDYSAHRDCoZ"
+      + "t9he40YsHXihg8+cp3n7c/XF02mXCadl7Mowd3NYJMD5BpLr3FNRjEKPfq+5BH82FpeoLhDLjQPb5X72VaRa814kJD2jbply2B3lfz1RFAXGp8UZlYYV/7mh"
+      + "g/LcPJTL06DGPw2xAgF5CWjV2sydCaJwMNpKwdkCm61JpdkMw6djKdrMJ3KJ8YYfEt68zUXsCJ240BrKRBX+R1au1bSdz6jZY5ytflWhMDlVTLuvUNYSLxLY"
+      + "2pt/sy3Dx8VdCmoc8C853es2ol5/jHGWcZgiH2fixrFNmtdUFHqHObjHqIypY0TvABKN/bfYFKNcrvwBoNk5maM/rOk4SEQZIJLW8AJvBzsNXDP9nXmfVGUF"
+      + "AiNmrNw/bwDd7EJbuOqhrl1xMHOsikU8WkmHH0rwBkeE+upmdZ2HMvFi7igVInIzuKJ68l/qJ4qARhsy8i25n6hxHpW8SKYQEdhsjl2xW/jH0EUy7S0d9kDz"
+      + "MzNgSM1b7eiM60x3FHneCtSgiXOgBwknJztOkN6UN39E1kz9ADZaqoilQhLkPea7GCqwhKJnuONYxsLiHk6eE3YGqzJGQhg69TOqLRhajF0ZIgyvtQpWumSb"
+      + "LOmDDhpfTdkd8IdwsYRFNa0rKV7lzckAJ/D0q2iBWO9Q0XC96lLJkaBOavdEStq34OHyivL/xNrmfwt/vDDy7/gXUltl9TC7FmBSKjAjZWO3Fcme7LGLyq6A"
+      + "N7s86bLCOYMBxyU6pPKPTCCb2b2KhimD0xvIq7euXXHUfn/ohbNTpBmo/91+UrGaVMi8UnpjUwFYRs67LbtjPZBH7YCceWAAY89x/igO7ZlOJVlEGcVN8bEK"
+      + "HVMtntluYVF1P2iW4YP8zoBHPN37F/Wi2XVRweaTAOTErvgaWoiC2vwA3slAKgWhpIP61x3xKcNHr5jXBVfw/us14hEOHFLHqXv6kD1w7E3FR8UFSAZs2KqZ"
+      + "1wbT7KstLRUjgP4QLYjkBAZFGfz+0WTvdtHHCcH4S9FXYkmQPFdll2z7g1eoUFzbFCL8Drw7KaBLZusz6PwoWNdrxiYo4PdspDN4tvqTarJgrHbwPa0Fkbee"
+      + "NBr9oQ5s/sCcOlJLRCVTq1gG3OncrC637hkFILjuN2hXom3EGKNcMqKkl4AXwBkS9R2jyujdqbI5RwUtxK4AIjYjRwAZ1kVgZIm3IPNzBcBEO+Gy8kdeEx+p"
+      + "uYZ3tzvh9zRhfv9R8BtbZg6QWoXVBOAyPw5PQLPNAVVT8FebMZZ6It2nV738rjKprhD6/WVe8GpO2c1SlBx0VmSdFMfe1blp1+6atW6Jx/1HVqwYydMO4IS8"
+      + "CYRhWUqtbcjrwlgK2qjumHUKhzTHNpaeB+OZ6hm4TAIz+d4nxmXVCulgYKJ3CeBNpO1oScenMczI3LNUIdxfNYWDCfEq0zI8MNRfGmR6NByODr/SJNmYzuE5"
+      + "EWz6SsIGiT+tvSXZuPctoPsbElcTogedNpweolGkePct12wClE9EgWKjUXecrKqYskahWy9NFSNYCi3oRCn6JgVWquqTK+9ZKX97E4ehepoW1RvDWRZPQQpm"
+      + "gnS20H3H09NHlsaw20GnKjbry7ONZOC04NJFmLMfX6BuTMBsvqr4Etpf9HFoS5Iip49CfcVoyk13e3GY+PzpB4I3KEq53GdeRW0zbb6KdMBuLxp/bhWwJYAX"
+      + "A55AejJTMoBhRiKvHMMXIVn8cIbd1bG7Zgl5+OJCGjv5cDBAa48MoagSOTe0hCUyLQO37vgitQYDtZOYMulGpGmU/+nv5XtKi//TFVItULNUSjOz/+up7ucw"
+      + "BPayWTR2+Y3jFUZtoJE0kPn/tcdCapPCUk3S7iALf5G4ffsAE2iUE/fl4l7kQceg7aGb6bTo2sYBwP1wB1+akZ7l5SpcFiA/+i7cq6lh6j2d/7z0yyjC35lh"
+      + "A/jesDIoZ2Q1Rl8eNT1QQwQbuiTNw6uwOcDZtB3kObvfxKA2l/CuPwYyNt6tOMpseuuIouZWFMxKuCdcmq/gcfKXkxtKLCPBul96PofuBFF2IVVozxhi20ae"
+      + "yMOU3VL/RD9sAOfU2E+a1rxUuw+XpHJbqhiWkg298lEcwKEweDiMy4pQDZb9Lg4d4z/ooygLW5GpTdXY/9/owUHEy//8rRk9Dxw3kXdPc/qFlgXqws/sebkQ"
+      + "GiYLWIkRVWmYki1hA4B+gz0CuEZyoCQprijMnMQrSvFe25IqdLb+z/8I807Pyaxg160xJ9qufVRJzJlzQK6SiVHqpKSKlrsL13FEwcLbHejOYSp/t+aobf+S"
+      + "AgM0BapbnBQajid4UIWKnvrbYiBdGT09xHyjsiAdjF95vatTyZx1jit0+rZvZTbvICVQVdOPIl/B/wAxEZNs26+kwqCac09DZHXU5x8C0bo1H9SHVW/0pgTE"
+      + "SraH7uZIGOPtdLzmZCwb+1wESZwl6kJZOlYnLSqzG86e3NbRTAUoZkkEEyw8OJKkjlCzw8dqp2gYepdOdZz4VEGeAMGsFE30NWTMgPJPf9PQE3YR1HV4OvfN"
+      + "OUOQGl1eDWy0tad3DBXATRzaYXgCjg2Ml7gRYt/u3UjSOxWVuu/LMHQQ+76lw5IlnhWhUZm+VgoulbngdzQf0aFA3uYuNrS95KXzF+HRFiZUSEERqnpjqBF3"
+      + "rf/Sit5g+vAMfVME0V4PpwJe8nSwzwzc1pJO+nk3JVyYOLxblig7F2s6K5dapSAw2B7b8K5ARsBqzd8V+KTQ3FkMHhDYqd8EY47urfCBLhUBBkXtzJ0t4N2O"
+      + "nq0m+dHtLh3eVK5uqF7jBMXSka4KPDMx2dTHzvwVJ69weMFurp6cc3iol69wDMMXvzL67tfsnmKEnVgkgRc0NJko2jH1mWmGNTMYWd4DJvFgu9Tw6LlpJ8q8"
+      + "91xdZHUiuv7x19B9DrE3PqUAqjazKTiTfEzdCghOePjcd1S8Sgc6lIBFBl1/G0jKStklnt6OLP28GLgDDPgFXed7tskzzR0VxvOpHOm6yH7OtwAvce/qQ20u"
+      + "frgbPh2/3mxuklBOKGP3oWZ3tSIwb1AgDZsh/Nx4RggA6o41QMQn3AsCINy7jMeVXHT+q7zoh604qUZoufJ/pD6BqU1iqI0Go69eIY5kIpMIqnVGuQorhAlD"
+      + "yyzZrYgUccJgl0IlZJc/mTaIwlLJoEERNC1/MsmThyS3w6Uvblpldzfz+27qEUT+obDef1OoOi3fhIFiArneMF83XFv42RwQ4/orJhAqcMpXZVNCCrU6+vq1"
+      + "MZJjSKjMTjGpY7Z1ibyMP6cJXi+VfX+rnqGEnYfYWabE36ElkT//mxVo2KVAfkkBwgzthklmPvIyCcVKCPyZMvpTxMECBC5N+erlWRLxj4WYWW1UH1UK/1au"
+      + "Gq4DMKoWAQ1lFGHD8VeV5+FN5xX/J2dk5Y6lt9yX2n5SoAwfFueoDLpqwadp5vXY07uci9HWzbZC3QL8xrmofikecyaR818hs+PHBW85S5Ovr2xj0DjTJgtw"
+      + "xVcfUWXEp8T2awAJhQ3nrVS+R+zD59S3a0F5WIwNRqHHwKmkGwfMDq4RHB4ENdEQvpjNL6cTXyqVt16oUQDvQi9pMz/byAmJ1PRc9q91/ydxWdyaZqyBL6fY"
+      + "tb1t1a7NOK1YdwPi4oknCfr8nRB1Z8fGOqc8plUIvZmsepwMDcSlG4cHjFktN2YKB5b7yA5iNANXlm+Iw36WxxIU34b1YsJppaYY2WISp2XByHJmiQy1rGrF"
+      + "lvD72d4MS2eCcHe4sAntlUgR36wP2Uv+VPPcv4rcqOGhnQW3My8gFtYwKCQ+gcjLgFlRQbpSi2LiRXtJmpJm64vmjGW/H0uhDMwWCUSh3BEVH2fEKq9AVAOG"
+      + "8RcyIWhZK15YrRWKYLBuZKZhNo0AM+LM4M+z27FJ3wrs3wqSIORJ9ElvnIlFXFW5p9du35qPRdwJTaEVHCqrnkWfXcZhMxCCi2zHG96upHGMHN+HZY7VgWPv"
+      + "1FHeShdjeX/Q+jFYRt/jKWLxuRfzoR2t5FVSHEwt/8ux16JqobAfAwieiH0B0HOiRW1sj9YmzivDT4u2T3py42Wy9Y4eT2Lc9Tc8pSu5hI+gIght2BWHRS35"
+      + "GFEbhEi+c6txChbdB5uIlt0XLSiUdSFWE7fNG/hME1ygKq/G2ctsn5R/MDNSIkLxa2wx5SgEfx0zJMq1bV4M1eWkmax6FMAl4wO7V+oJ96rHT7YQkpImdWwX"
+      + "dTxN0WJRZtw4MxJ0Xixt5Nx7qWSWgNgDxuepDEPQ8GacCTFwO4o3h72fJVk/gxMs+QMVHkoWLQHMLcgB4jdl3u65i1D6KFR+SWBYSIYkwLYjZ208nRvIlYDe"
+      + "bS6juXnTUABFflyHNBZtHp2jtSBCO6NCx1t8WDBfCKtyHyxomhQIohXdSgq2Qi/UkHaYAvRU4mOi5HNUkxymjkbJ7vTT+IJ8+alR2d221TExYzQ/BkxeACeG"
+      + "OMa67cxJQaN6L8eOKZgOKStMSHnO7gkrqQy0EhhTKEzFJwvC8YoMSF5xpA/nSkM/LHibtpcQ9OsUVS9kyc6Llr0VHPcrWpkuM53Wi/syKdNCWAt4wpn2y02X"
+      + "oW6Z2eQTOKKTm1gMj3f63y3dS1MT2ycjJzuzVSllE7vfIhhWImbQXFcPT3BTFi3jUAV5srcfeFmCJq061UBWNSjsbKzSvTMBZEXgj1G7JRg3kgSqtIdBNZR1"
+      + "p3vumrVE18z1g/Qdr+E5LNlANxFDfafmWVplPImxtA/g3wG5mN2vehT78p/FVHasqrXefqT5YMxP1jVKILIHsNwh6buS/+iyKkTB53NhE8ea+9kC5YWZ5QaP"
+      + "BxWs4KoLkYsL/x1AAoySSGWYwrp4y/JOQQNAnwegp0WHy/dcDkfJ+K74pcOIdsD8rNP2xKp/qlpVlAlhK1SodB5oOIZGKhppJ5DN4XI6dm+UbYtJ0qTJX9Wz"
+      + "CnfvqLjaVmxZe0lg++wTH6LJ+DcVFo5NHBwZbbuDC/VS/D9a80JJpT7JfKYwMrtmFJiW6XZiq8t0JCClLB19DvDPNd+gRv4tKpIKJFozq9hP304zChDQF/go"
+      + "7BgKdfcTzYJ45x07gJY+ngcAcla8lx7i1XVrX5Hdi+GQd88GP+cG85KEAS9gE/u6uoYBCaRPVUpXutiVqVKrpFPe6JWdRZ0Ai6dM1e2LH2q7zZ6lbM2KGw5y"
+      + "OXmCPIs0GpzlkhdbyzVvEQW5owJ511e90qk2X1PD7c/Pbv8kN0+Mj3IZpACv/7qdgZzB6YwNBXfKscV7WZMw9EVpK49SOW05za3ZCJQWcYBPJNCbB7caaa6N"
+      + "dD4nmVFK73AG39bIdBzCBKSw8ntm/Nfa9ZfFkHXPbp2xCQEE1jCVVF0w00V2Tm/YzRf7JNY/OneiGv1aLYfKI2O7Jjx7VvmcInm3kC7GnzbWaV7QSIQpYwo3"
+      + "AB4a9+DFwj9AvGhBxzl4+TVzbA3rj1B2O7a7jRaHK5RvZd1FECpOmQq5S7aEGbC0gjk4hgIPn4A7jzSvLkjR78M0wM0wmgD82wRkhHE4euvxtW2Fo81RrZFz"
+      + "tTm2w7r/tp3GxxMt/8OyA1Y+WW/Jy4DYDcCgskXCLqDk8CDhWiVnHddqkzVmAR+bjXO1brvc6MhoYAW5YVl8R4z7tvd0RLeFu/irSQEMv5B3KfW05lvm1rhX"
+      + "BZbRTgM8Jt4PxmaM9qLE6QEcxrh2+nfbmWIRNTC7oDOx1BedVH8KuUmeT56Xn7KB7FEXnN69AyF1TAR+pyQgL3hNdyYxXWekvqxLZmIYyIVDkOeS85tzWrck"
+      + "j6CHsoU28BWcnuHgnkjRb3jgrPxgdg9GUkeGvFzhceKZ2M95qEGO/EMd18eEZydP6VZy3rlgBvppcY+lemlKC5N+n6KXDqXAtF+2li31TRWvTO6SzDG2LEnt"
+      + "AblF3b/kx/DWCRlBWaSonCwePM8lubdYKSp7aZRVNbw3SdHlM2TPnD3aMvr+ribBkgHnu7H5qUDdSvp9tSXT9WLZ4X8fGm3SH1GCbb3eO35TpDAPLWyNq0mD"
+      + "Xo5HDwVmKTeAEcCCX0WrHZHsfszYrn+HgAQmUjdgt3BnDTrPyi3NbkM0g8huP4qyXgvMwW3MA1ZeF+HcScj6mSoqkH2FBopkjmNagDBv59ubMQoQZwNxrwOT"
+      + "TrwnC42AM5o7oliEjS91LqNvbNyoQu695SfYJk3D3F9sbgJgTKD8V4u48QOpD0gU4Hs8mj/qOdn0R828+WS6sIkU8jaPsDL3x/Ww+P5DUoa8DMIgK0NALXH9"
+      + "GWaM0iwtBWRfXXk/aJ4rkJMrVFIjXPfykyMTQ3cVW5xPy+X7PC1yPrUcDoKYo6uHDtLIJp6d4CC3cngbOo7on4CmBJlByRs7ctOrSUUFJa0tQrcD+UslYHrW"
+      + "mzBsIS+9YuoTBBZyUbq79mxe4OW2EewiJaunD6KUmhC+/4sbyS8mdg8XDniwv1okDV0Uo1t8bhfv88/U2f0riL4t22rmSH58FTNFC94hz9217GMX39cKbLRu"
+      + "WhCLnigfnDnt25NxFn4bLfLUBTcgw3NDXWkDkmbKkKYo3s4yTd7yH0fiMWiVR2lfpV1LRQPZthgVVklZ7pySxmDHJI2xx7SQeQV9VujgAeY48U3Bw+idk5Wm"
+      + "VHdQXojHDUUXUbVVt3D8CeBmvEdtWrlCFmLJYdCALXu6bKGYjxQLeakDvM0KtzyStVziWC1azu6ZAG7/SRp7iMdzQSBiFlQE4WLGWPm8s1FrNiZ/+Z9EC9/V"
+      + "JGBxZq6LleILkaoYaw5lyhv9bCMwjFlAg5/pTs4I7QDOulklSPuG/TdLlzGOg8ICOn82Xei8Xw1piTD2L+l9gksASekCKo9TUJ5l9b2Cg6TiDh6XvVkYdmdI"
+      + "PW2AUgL8lsUYGEMzw5aS6T7LXJ+oWMmhx4zxk+37+bpFgsreXg/kQlcMqI5TubAPBYMjkpQL7lecJc+HAHxlPBU0WN4tN55I46sujfhyKgyjII6XkMx+F/ms"
+      + "et4stmjzRxCg84F/NcbtAZXR0lEqQGpilP2/jZ5Duh72X2fl4K4J2JjRpVYY/Mdr4Vf97otagJrDG+XFjcCOFNkpYDaLJYzI8xIczvxWwaa2CrrvNVvXTmUl"
+      + "oGpRTk3vN33tMoMv3WQqHi8QMCcLBx5FkSavinoGmBA3idzxQEzO7ZufBYlDeaZLs2a7n2I5GyST33k/dggMRpvr9ghbdqppKIFzTs8bHJxTKz6Rph91xuKO"
+      + "xMjtnHVIZjNQDzGf7h5oqWA0YYW8pDSadFaFEweTcP8IEIk6ugkBwwhHz/S0uNSaIiHl1ncsWItCJY7oe5s8FQANpMhMGvLggY5kbYM+os+ynTr6+cQIlavC"
+      + "xP5Z2Pd6u9tZcAg0bQLZ0Pu4KbEluN5lGWwNRyAtgkvYVTJbtxOsDxOS59cmTesJRPDwqRPIy4rkeDPWF8LUfRUqwxzJcGrJVO/uzpM/4bGVwlKfGtrR5nMJ"
+      + "8Ot2PDxUPode1mem8xgwpuJHcMAI1mGC9fyCd/cszfZ8X7HDpzA2/aoKRqTnFe6I1qFc61qustdwdINwnTPlrAPgUa7/4U2r5pT0KJD7JJZRiIO0B15Rv+V6"
+      + "bzDT+7S+mIAkLutba/cIqBR2nn5HuVy2TwPILLwzkW+SgQSAMHCdyj4atztd2SfFx8peK5JfEzvH+hNFkfYASk48CKRC9uTzenbckre1p5FPpaXAC+gRbEKw"
+      + "JZH+3vrykeLSKokJZzfMy2q7JlDTS5bQgwGtC/P6/NrikGtbWtJ3YAzqUC1xhG+ixFpP/UWl798YRWLByG6RYkWm9e0ITlkogcUxFnFQh7Xw6jOOyWB8+CGH"
+      + "id6CKXyzI3BrTEpjcO5b79Q6YIvR6Ep+YUFK7jt70SXHbStcxhZGo0YFmQfPjjqYgmoLds0leKz9cpwYUPd9jOdy7pK2hvLUmvyBGUNYZQhxgkvwj7i7RALB"
+      + "a37DKUCokNYkAp5r76y6QZTRkUS16FAg3IS/uI7mvWCl7x7JTLOuKT4L7C2nNN+cvDu5ts4fXtM0U7/y7EnYTMHKm5PQu0/h6qMDLWwkPL1kiiTvwrsc8Vl7"
+      + "DId98yNImT7ewl/C4N8wzpp3UnGHe4lS40aYpWDt0Zu0lqQwRWGM5P6KwmfaAkGQ1nSazS3LCAZaGVH9IWADEjdpbyekOT8llapspjIrcM9lnaXZ+0Ae4r9f"
+      + "0yxlx0e8v2NxyTWOZbVlcVwJXta7ZeDjhO6BYCCNeNLYm5HlAvccyR62zhm1dizPaCXLaX/S4H5ersVmP5Zc1jKG+iieUKNJcyWxefr/IXrD4PNIDD1OZGU8"
+      + "9/jVmc/02KKly2DlVPbtifxqw1nW1KXeoKJFmBkUDc+L4jiOEic8Lr6bnzzpBbh4laSY+zT45ZXeFOCXOH0a96YSqsKwsNHbUhOI5PzEobKJ6LQCYt+2f7yp"
+      + "X3gbVSbDAKBVfO+V4pabljPCnyAVg6HeHNW3h89ptDOt7f4I7JGxfsP2VosTJYmCxvaH2w9fGaMEhci7OaVeSZfUCAxrdNh1VlXPYio9dNanj5jYJLTXin3w"
+      + "bq/NqDEXWLqk34BGun7h9fdRyj7LkC03ymjlYdnDfvOP5GY2sZA9H1ieQShe28Z5qPG96X9HFAGtHWkh9a1YYcFwIsbZz+cc1ffgCqb+xuPwTwI5YWY8ipZo"
+      + "ElWZ84hLTuSrXwcXD+2Qfz+obXqszKRXxhz3DdX8gbwMdQ0a14OHDc20zVMVNMfJLIvo7BXUS9vxKIr2yVuIR5n87SFXohPi6RXcUaQB5W4G+h3fWU42xpRZ"
+      + "QMnbdnY1vi2w4Mrf8PYLPPCZkyX/KwkB2MSU5V0ZiHTJ0//TzFQVjdSsZWRMqA/n5GTrBLNiL/s8ZijOwNBtoNJkknk+tyLU2WztGlYGicOdRml9XDdMM9fh"
+      + "zzF/gMzJrX9saofSrDMRGWSRlNjylnZBt7tb6+f6Lvwxe2KH5KjaQh6Pla8qM/sZDBDoucSArVKFByXupluPIrWAF6rlY005i6M6pDk9F8MZAfcVUWQ7hhci"
+      + "ycSlnkFy6NpFYqnakWozLuc0PInSk8ZG8F/14+3HvOYGMGRsSYNzebOhi0uwzM9pX5QiXNDJupE62ejr9f2hWTmFkr8IuoCFAZVFB9fwpFzSnPtJp3TEcyqu"
+      + "4eonFF5PJFk3KlXSBifIqmtzoF3QNkwqRl4y9RCfzVF6m6EPtEJm4GlfooSw7cVYMe9ZqjJdI8/JAmH7yny3ewe5P1tAvZxrmEd9KvDIHnAwv5mkeqG+3z0v"
+      + "fxrBbtEOtfzQp2T7di1PgBhTGF/ucXkP7JMhcq6mS5nANrpwrpSpImZTaRHHuxMD3EuXYsPZxgt1S+e652wYOn37vPkz50d084U1sPaAYrADlyHVJPRaoefW"
+      + "y+fsx6IIjDumQFRQKTyGsYTAY/S3GzkOJVNHwgp4MLbCWDaQNsJsx31Yhqy/CAXNtMnvrJu493mxYLqBEtvr+zbKgYL95kahksuW947VafdgCg2gpJHLyG28"
+      + "eEXfh+WZv0Y6XhAcP3CbKw73vPQtUx73I09zYmDDtdnh2cojbxS2ARnDIWZAuz7c2oXfIqdxEB9s2hwpwwkxTsDlF/klE2qezZjuU+BZTsdmOYDapoat7TM6"
+      + "xi95rcbJRSp58/UMDchUDVmNeEhx7xWMDJXO/f6/hFdZf2WzxVO3OgbB+MOOQqI1BYS9iL0sutIUTcBGUxsMGdQMBFVsLWGgRxYWBbhWwutQEhRmm3Tc1wIy"
+      + "mYlaCEqXqfRzAKuB6zWGEdHbiRVH1S0dhaXfQ2NKq/f99OAI2QHJPFB3ERBamQeJ0cq5zGLAj6uPiO04C6GXvQ74XYTfTbNZbuQI3Zc9IR8tCXJjGGoQ1D65"
+      + "KFtwhmMtrT6UUr1tQZqYF1WaXoFZbPgiB3By3fsFAXg52iwTHbnthcez7h/Ee3leEKOAIzJrrPiX9JI+FBJhkOkuq+ogqWWOuCT72PAXzo4L7ki3wyZSa6o1"
+      + "QVlMKfbupLlw31dFATKL2Z3ekg3D9Yez4rpJNmfJjOxE1ue/62wBcF+rcuYSGKuFSyrWYXPhzI3yekRnbKxtq9Q58o70r5SLULaAim4ZhfR3lnU0ln8cPBFN"
+      + "TWeEiXHpwSa6ANlW+q9GHBwZmtOzbj77h/Nl5Pu4f6WFavw7eICxRc6prGPJDRG2m8OpRFIw86ADAbTjgSoUIp2LGOIunfKdRqKFvgxDPAGdUEt+ikpbXT4O"
+      + "jjIFQyIhmBnqzJq/rnKLi83CjN9h2dFDZwugtw8SQO6vzuDxytBB3nUIzC3AHbSeo6ojUtLFfAODVzn1Z6HUCNjmP5twKWG13lMeLbEy0D5isUwe+qf5lNIQ"
+      + "6oj9TaBVTUeU/Zh67FTgz/AJMPFq2Es7Ze8Nl4nCO1tcc1GyyLwQARFKRBbddMbbEZ8Y3ohKW0/6P3tXn9cDyv5z8DgzcVZUGfe7fw2UsfrfWnkv5Ig+c719"
+      + "umJnnoUWOBdFF1lCbfd9FwP6IMygqlv/qEqs5Wrvs0ozR3r14FTnQo8LArC9VWC/ABpYv+sPW2dMjz3P1nHacbuFuf84QWhJMXSQzn79OLNIPxKP7597UmXD"
+      + "tcXoKRI5rWm9Q//YHrXzpyNu5KgYR1UjXIZF3SjYYTGA2Oj0X3hQvRDlOZVAFc+KAM8xCMQ3bAuymTFE/POXq0JYzUb5tR2G0KF1FX/iaRTKKfQoR5KlaNX8"
+      + "SKqzit5oGMmnfyCWlVkYVc1t2ZPkE4Y5ZzFx3zokzxZo6ZfT1LoniToPPqGMYLEjHRRTsDR3Aq7wbsZ73glgJ+SNI8OYK56Ur7SzX+K0EPV+AX6SI1mge/CZ"
+      + "hCuO4wBPXBERCSibHljh1UFacghrRmTGYiRhATbm8LPiM5dFLxmEighVNFTa1MBohXIf88zRrMAt008xlDuUOkeGwiWnj4+VHqpR2/i/bmfOFKpswuuCMfuc"
+      + "S8so5nTvCZ1FNoOyAq52VP49MWTIcIhd9+Ej4vw2HO5dKkpbyvyB3q9qy0GQ7AFnYy9B9JjQFa/9sTj2SgqDbgMsq4pBgJGOCE2Z4o0yUsyxGWvTlCQl0cZM"
+      + "1tIOy4/3CJe/0g6VB3qepbEw3Ov+iASlqlWqwCTAVy8Hs7UrFDTSCtoChJaB0VbDs63oVljlamCOzrL4pqXea/WQW8WpiML/v50N7V5RpjMMXsGSBE+yNt7c"
+      + "nGte31z3Mej02VgLfRj9ocmPb1kKvon15meS92O95z55ZlC5BNzjUtUa9Dno129H4UTyGzBnIyLmq80QxroDQpfgawlv+LP23HHEVn1SYN2odPt8M20jXAsW"
+      + "GLAY8nSi6dQ4CJkLmJ/qcH+V5QqoH5FpF1MIqgJCseNRJv4tJH6eM7IXb4ngumO4oahs43qRctDbgnFzEQicBswF02T2cyzJIqljlGw5vep+vDDRsPww+THq"
+      + "BNAtQd6lCrOLDIi26JCNbd5W4f4xm7p3kUbj9CagWMYztTAn5Ks2IQiQEsldziyoGNNG+UZwj0rkF1s1+GF9FEq2poYZ3ATfBR/+oVTGpUXoA9aCq+dRzXJR"
+      + "yRNH1J8Xii9qe4/0wsEb03QWmn//EuU5/8i1aTxRPPAfzsNvloSxN/wK2jhOuwSB7wRkgH7wP6nroqBSA+IH2mPkgOUQSBg6xQgGU3ribwxkBNSc98gv0aHy"
+      + "z83bjZQYFQgzv0fnsT/pwjgIjBPPSlcxVFDnBmnVG6y/HyGsEtaMcPZ1uKzd+jcAYqj9iRCdqE+IzzLiHjzlPYKRMjkjEE4jE5e0YRNikHhgYETpMNrQYzw9"
+      + "i4/fCPKEsgj9nzix9q0R1SNUvG1RezBBgkZDycnv/LIRyoqRCckqFEiDNpjnkXmAEcvgV2I7Fea740UFEK7ADVMZ5UtkVhu96C+50m1KwlAbRbkGTCgGjILK"
+      + "eumPt/NLjRPUP39wUiGxdRByd+mqsCmyGdQNpOGaBMLUSP4A79t3otRqxGfDG/fYogSYq8zt5SscU/ENJtIsHmU1I1oxPbwLD+HB0WP5ccUNF3qfsg7neAKA"
+      + "6R4G4d373m0UV3qMKSyaCPEE0cDJAzxFl1Pi/Y616J1baAo+dYcTkRTHno1sRT+2p+H92SYfRaL+vz8MWHH8L07JmcsXqCn4jt9AxHgNor/jNfBGdVN0wIbe"
+      + "+Ju2OBmmuJL3SuTAz4b0pHzCugauGvw+PVBGXBcU7d7MzT2i1712DaSduIVgB9apFSS6Mh5/HDGWxfa5Jjlolt4H7ZKE5uqRoLNWfiaFEnegOtfR1UA+QgEM"
+      + "Oa3TsF9WNX8PIVZF1n9MVHvAdxKmfU4AYzWOfVBNd7PmQU3PMjWawTc0wixcI6++iRnCPJNZMtUSbQTrH6ujqqyIbqjFoA/hnZeBn0umWoRivffpltaZmBjt"
+      + "r1D57Mq8ZISvs41p9uvUGdjs9AIz4f2YQhLZ4XvjkhXEUsAZBcZLGxR4gHrbanLKeXNAwF7E5vq8IYDZWSD5azWD5l6rxk1QwwnTEx7QnavNZfn7vc+Yb1eB"
+      + "FiDAp8fq6ShmE3q18xd2S73u1dUfwV2J6pkoc7LzUIMzv3kQ05mAbSFOFNPL3/8Ftgc6Xo25FbVZv/DnWZM4o4BcqE9g/MbJNGdAK5iBVYQGQSYkgCLJnowl"
+      + "v2KdZVLKdejHMqqVIKEuXGV0xmUIjMbQT4rCntNs6y4pXe2jtct1EcRARsbuqbBMZzKuCzzMIg1V96UO8IH9IMW4I+GIFQ2/OMYjdawDI9pM9Zi8m6VFjvXc"
+      + "xbk6zr9W889mq0KOLMMBHvsabFK50CqetoZfDLl7uF5JczwNpU6YA/dgbKQ7bRml2juKbyG6d6RgTm93V4F4Bv51yzPM7MWU726CD+o5jLLcKIrjcjyzPSjy"
+      + "iqAHWZJUV5UxvOyjL62ASIRC7aM0DUv+siFVZGxpvsV/9XfNAzojAajpdETnnN0LbwzqBn1Oey+lDBR8/Fol180oFa22vRCw+kYAg5rt0EduaTngpfn+MCnd"
+      + "LoI6o1vEpOE17BDv8oKUOIcwITawf8wVR506DzwWOLTv07b/JLbFQ16WfMkZkU2XR2SuawoTygBa/YYee0b7PmWvh3x8c4qFEEM5+U8DE25HlL3ncNOL3ExW"
+      + "7BwxdMkFOxsokjHBF7osfkir4tTf7b3AkYw1Oia0bLpv2tz52zGaNplFuwTSCW100B3sW787/cufu2j6PPkGivL4bI0LxK1AMAvW3qBq5PQQ9/Hcd20UPrrj"
+      + "EXPrYWIkIQv6QcPsYdPuiNuBvW0y5bBHnwV4r3FRPZYkjxlvzoyDdhVVXPqK7py3UvN1fGm5LMi7zT6pMcC9I/szeSieruDLtU/Ynls5b3JFMwYBOb22GrQF"
+      + "ka9HVaAssbICnjmivJE7yTs942PI4tC6gM5qQk+NOR98MxTuNslgg6tJxEwUqrW2LeDx6I3bZkLkZZ2ccWYUzC8YpTurLKZbxlhTUbvVV1I8baB6Bt9SXK7o"
+      + "FI/VEFlj9H2e/yEgFObfVZOVkE2mjUzxI1erPa3TFpRZtai7g/h53dlYeTQcgQwVxY5ZMOZsCQ2DR8InRfiWT59nR/eyR9ZoGAj+tlFmaZkANXNdt0O0Y2I5"
+      + "ZLynsAwqRFxBltz2hRyxTErbp4jnOE9kBH0Gxr2LMNkKDPgJfw5RELKCkbBUu8MZRljgxB7tq+EYABeSCKphqBbKSSGpzBy3LstEcnOumUpn1xw5SHUL8Pcv"
+      + "l3Rv3l6Xf0SH+6JCrUMCxXqm7DI+zbUOoZVwrU4nKALqntvKK8WCsuk9EqNmuY6wpZ+tkol/jz8UtdgqpOXvaQn5HTyXXJlPu+n9XnwQZvY/S/SpLNZGrXwT"
+      + "hbUraB9LrF0TdVEd3DKMGjV7F13Z9nZmzQeb1YHE9+bp/sufBiQ/vw09cV+xumGPf9IpnsN6TU7y5h7FGrxo3F9hJ86zgvdOmaHgkG+WLNTCrrPIGK4dQJui"
+      + "sytXlsQKaVq+GKLl/MUXAEHJ/Trgq4cQl2cDtYMUWJbEaUw363vFIK4EmpasEnsNWKh8xpsgOKrkWu3ZuzEvlTQZf0Hnv9ESy4RDzWD9ZUX6YffdeFiXjooo"
+      + "IT79m8BrkwWoaigrzMmYduHQ3RrOMLeMrg1Ip5BC5+pB7hjQ0sPR2HEG4KO6ga4Z1D2/jntBvvQD5AP7387OQyDlnhQokTAEukV9LvyCwJjsf+nIUqzCP3AU"
+      + "PNiQsYvtgXTXk6J4YUratb65a7bcYTAwCWoKNcp73fZKmmq9xim7NksjmAaUAj3Ifwgr4WPpO7WMtSUZZvTuZ6J9MYwKt6mNafinBHQ44i/5Sq6QXFVCX9/R"
+      + "37v7v/fMc5qjN1+JnqnLqEYu6OsUhT0RUO1/R1Q9d+h/pweWxtpnt0tX4cT0A2g89ZP8nJODfDxXsg96A+d9CHSFHJnQpq5nDF8Tm7A7mg8cqd0D3AZEhREf"
+      + "IPYmpFOmt+LoJzBfBcjZHUQ+Q5BCdoUMW42ORYyOab8Q1VsaCxl8QabLQCYt7YK4DxI=");
+
+    public String getName()
+    {
+        return "Sphincs256";
+    }
+
+    public void performTest()
+        throws Exception
+    {
+       // doBlakeKatTest();    TODO: we only support Blake2...
+        doSHA2KatTest();
+        doSHA2RandomTest();
+        doSHA3KatTest();
+        doSHA3RandomTest();
+    }
+     /*
+    private void doBlakeKatTest()
+    {
+        Sphincs256KeyPairGenerator generator = new Sphincs256KeyPairGenerator();
+
+        generator.init(new Sphincs256KeyGenerationParameters(new RiggedRandom(), new Blake256Digest()));
+
+        AsymmetricCipherKeyPair kp = generator.generateKeyPair();
+
+        SphincsPrivateKeyParameters priv = (SphincsPrivateKeyParameters)kp.getPrivate();
+
+        SphincsPublicKeyParameters pub = (SphincsPublicKeyParameters)kp.getPublic();
+
+        isTrue("blake pub mismatch", areEqual(expBlakePub, pub.getKeyData()));
+        isTrue("blake priv mismatch", areEqual(expBlakePriv, priv.getKeyData()));
+
+        MessageSigner sphincsSigner = new Sphincs256Signer(new Blake256Digest(), new Blake512Digest());
+
+        sphincsSigner.init(true, priv);
+
+        byte[] sig = sphincsSigner.generateSignature(msg);
+
+        isTrue("blake sig mismatch", areEqual(expBlakeSig, sig));
+
+        sphincsSigner.init(false, pub);
+
+        isTrue("blake sig verify failed", sphincsSigner.verifySignature(msg, sig));
+        isTrue("blake wrong verify failed", !sphincsSigner.verifySignature(msg, expSha2Sig));
+    }
+    */
+
+    private void doSHA2KatTest()
+    {
+        SPHINCS256KeyPairGenerator generator = new SPHINCS256KeyPairGenerator();
+
+        generator.init(new SPHINCS256KeyGenerationParameters(new RiggedRandom(), new SHA512tDigest(256)));
+
+        AsymmetricCipherKeyPair kp = generator.generateKeyPair();
+
+        SPHINCSPrivateKeyParameters priv = (SPHINCSPrivateKeyParameters)kp.getPrivate();
+
+        SPHINCSPublicKeyParameters pub = (SPHINCSPublicKeyParameters)kp.getPublic();
+
+        isTrue("sha2 pub mismatch", areEqual(expSha2Pub, pub.getKeyData()));
+        isTrue("sha2 priv mismatch", areEqual(expSha2Priv, priv.getKeyData()));
+
+        MessageSigner sphincsSigner = new SPHINCS256Signer(new SHA512tDigest(256), new SHA512Digest());
+
+        sphincsSigner.init(true, priv);
+
+        byte[] sig = sphincsSigner.generateSignature(msg);
+
+        isTrue("sha2 sig mismatch", areEqual(expSha2Sig, sig));
+
+        sphincsSigner.init(false, pub);
+
+        isTrue("sha2 sig verify failed", sphincsSigner.verifySignature(msg, sig));
+        isTrue("sha2 wrong verify failed", !sphincsSigner.verifySignature(msg, expBlakeSig));
+    }
+
+    private void doSHA3KatTest()
+    {
+        SPHINCS256KeyPairGenerator generator = new SPHINCS256KeyPairGenerator();
+
+        generator.init(new SPHINCS256KeyGenerationParameters(new RiggedRandom(), new SHA3Digest(256)));
+
+        AsymmetricCipherKeyPair kp = generator.generateKeyPair();
+
+        SPHINCSPrivateKeyParameters priv = (SPHINCSPrivateKeyParameters)kp.getPrivate();
+
+        SPHINCSPublicKeyParameters pub = (SPHINCSPublicKeyParameters)kp.getPublic();
+
+        isTrue("sha3 pub mismatch", areEqual(expSha3Pub, pub.getKeyData()));
+        isTrue("sha3 priv mismatch", areEqual(expSha3Priv, priv.getKeyData()));
+
+        MessageSigner sphincsSigner = new SPHINCS256Signer(new SHA3Digest(256), new SHA3Digest(512));
+
+        sphincsSigner.init(true, priv);
+
+        byte[] sig = sphincsSigner.generateSignature(msg);
+
+        isTrue("sha3 sig mismatch", areEqual(expSha3Sig, sig));
+
+        sphincsSigner.init(false, pub);
+
+        isTrue("sha3 sig verify failed", sphincsSigner.verifySignature(msg, sig));
+        isTrue("sha3 wrong verify failed", !sphincsSigner.verifySignature(msg, expBlakeSig));
+    }
+
+    private void doSHA2RandomTest()
+    {
+        SPHINCS256KeyPairGenerator generator = new SPHINCS256KeyPairGenerator();
+
+        generator.init(new SPHINCS256KeyGenerationParameters(new SecureRandom(), new SHA512tDigest(256)));
+
+        AsymmetricCipherKeyPair kp = generator.generateKeyPair();
+
+        SPHINCSPrivateKeyParameters priv = (SPHINCSPrivateKeyParameters)kp.getPrivate();
+
+        SPHINCSPublicKeyParameters pub = (SPHINCSPublicKeyParameters)kp.getPublic();
+
+        MessageSigner sphincsSigner = new SPHINCS256Signer(new SHA512tDigest(256), new SHA512Digest());
+
+        sphincsSigner.init(true, priv);
+
+        byte[] sig = sphincsSigner.generateSignature(msg);
+
+        sphincsSigner.init(false, pub);
+
+        isTrue("sha2 r sig verify failed", sphincsSigner.verifySignature(msg, sig));
+        isTrue("sha2 r wrong verify failed", !sphincsSigner.verifySignature(msg, expBlakeSig));
+    }
+
+    private void doSHA3RandomTest()
+    {
+        SPHINCS256KeyPairGenerator generator = new SPHINCS256KeyPairGenerator();
+
+        generator.init(new SPHINCS256KeyGenerationParameters(new SecureRandom(), new SHA3Digest(256)));
+
+        AsymmetricCipherKeyPair kp = generator.generateKeyPair();
+
+        SPHINCSPrivateKeyParameters priv = (SPHINCSPrivateKeyParameters)kp.getPrivate();
+
+        SPHINCSPublicKeyParameters pub = (SPHINCSPublicKeyParameters)kp.getPublic();
+
+        MessageSigner sphincsSigner = new SPHINCS256Signer(new SHA3Digest(256), new SHA3Digest(512));
+
+        sphincsSigner.init(true, priv);
+
+        byte[] sig = sphincsSigner.generateSignature(msg);
+
+        sphincsSigner.init(false, pub);
+
+        isTrue("sha3 r sig verify failed", sphincsSigner.verifySignature(msg, sig));
+        isTrue("sha3 r wrong verify failed", !sphincsSigner.verifySignature(msg, expBlakeSig));
+    }
+
+    private static class RiggedRandom
+        extends SecureRandom
+    {
+        public void nextBytes(byte[] bytes)
+        {
+            for (int i = 0; i != bytes.length; i++)
+            {
+                bytes[i] = (byte)(i & 0xff);
+            }
+        }
+    }
+
+    public static void main(
+        String[] args)
+    {
+        runTest(new Sphincs256Test());
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java
new file mode 100644
index 000000000..06eadf4aa
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/PrivateKeyFactory.java
@@ -0,0 +1,176 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import com.fr.third.org.bouncycastle.asn1.ASN1InputStream;
+import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.fr.third.org.bouncycastle.asn1.ASN1OctetString;
+import com.fr.third.org.bouncycastle.asn1.ASN1Primitive;
+import com.fr.third.org.bouncycastle.asn1.bc.BCObjectIdentifiers;
+import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import com.fr.third.org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSKeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSMTKeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSMTPrivateKey;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSPrivateKey;
+import com.fr.third.org.bouncycastle.pqc.crypto.newhope.NHPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLAPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.BDS;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.BDSStateMap;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSMTParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSMTPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSUtil;
+import com.fr.third.org.bouncycastle.util.Pack;
+
+/**
+ * Factory for creating private key objects from PKCS8 PrivateKeyInfo objects.
+ */
+public class PrivateKeyFactory
+{
+    /**
+     * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding.
+     * 
+     * @param privateKeyInfoData the PrivateKeyInfo encoding
+     * @return a suitable private key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(byte[] privateKeyInfoData) throws IOException
+    {
+        return createKey(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(privateKeyInfoData)));
+    }
+
+    /**
+     * Create a private key parameter from a PKCS8 PrivateKeyInfo encoding read from a
+     * stream.
+     * 
+     * @param inStr the stream to read the PrivateKeyInfo encoding from
+     * @return a suitable private key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(InputStream inStr) throws IOException
+    {
+        return createKey(PrivateKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
+    }
+
+    /**
+     * Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object.
+     * 
+     * @param keyInfo the PrivateKeyInfo object containing the key material
+     * @return a suitable private key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(PrivateKeyInfo keyInfo) throws IOException
+    {
+        AlgorithmIdentifier algId = keyInfo.getPrivateKeyAlgorithm();
+        ASN1ObjectIdentifier algOID = algId.getAlgorithm();
+
+        if (algOID.on(BCObjectIdentifiers.qTESLA))
+        {
+            ASN1OctetString qTESLAPriv = ASN1OctetString.getInstance(keyInfo.parsePrivateKey());
+
+            return new QTESLAPrivateKeyParameters(Utils.qTeslaLookupSecurityCategory(keyInfo.getPrivateKeyAlgorithm()), qTESLAPriv.getOctets());
+        }
+        else if (algOID.equals(BCObjectIdentifiers.sphincs256))
+        {
+            return new SPHINCSPrivateKeyParameters(ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets(),
+                Utils.sphincs256LookupTreeAlgName(SPHINCS256KeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters())));
+        }
+        else if (algOID.equals(BCObjectIdentifiers.newHope))
+        {
+            return new NHPrivateKeyParameters(convert(ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets()));
+        }
+        else if (algOID.equals(BCObjectIdentifiers.xmss))
+        {
+            XMSSKeyParams keyParams = XMSSKeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters());
+            ASN1ObjectIdentifier treeDigest = keyParams.getTreeDigest().getAlgorithm();
+
+            XMSSPrivateKey xmssPrivateKey = XMSSPrivateKey.getInstance(keyInfo.parsePrivateKey());
+
+            try
+            {
+                XMSSPrivateKeyParameters.Builder keyBuilder = new XMSSPrivateKeyParameters
+                    .Builder(new XMSSParameters(keyParams.getHeight(), Utils.getDigest(treeDigest)))
+                    .withIndex(xmssPrivateKey.getIndex())
+                    .withSecretKeySeed(xmssPrivateKey.getSecretKeySeed())
+                    .withSecretKeyPRF(xmssPrivateKey.getSecretKeyPRF())
+                    .withPublicSeed(xmssPrivateKey.getPublicSeed())
+                    .withRoot(xmssPrivateKey.getRoot());
+
+                if (xmssPrivateKey.getVersion() != 0)
+                {
+                    keyBuilder.withMaxIndex(xmssPrivateKey.getMaxIndex());
+                }
+
+                if (xmssPrivateKey.getBdsState() != null)
+                {
+                    BDS bds = (BDS)XMSSUtil.deserialize(xmssPrivateKey.getBdsState(), BDS.class);
+                    keyBuilder.withBDSState(bds.withWOTSDigest(treeDigest));
+                }
+
+                return keyBuilder.build();
+            }
+            catch (ClassNotFoundException e)
+            {
+                throw new IOException("ClassNotFoundException processing BDS state: " + e.getMessage());
+            }
+        }
+        else if (algOID.equals(PQCObjectIdentifiers.xmss_mt))
+        {
+            XMSSMTKeyParams keyParams = XMSSMTKeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters());
+            ASN1ObjectIdentifier treeDigest = keyParams.getTreeDigest().getAlgorithm();
+
+            try
+            {
+                XMSSMTPrivateKey xmssMtPrivateKey = XMSSMTPrivateKey.getInstance(keyInfo.parsePrivateKey());
+
+                XMSSMTPrivateKeyParameters.Builder keyBuilder = new XMSSMTPrivateKeyParameters
+                    .Builder(new XMSSMTParameters(keyParams.getHeight(), keyParams.getLayers(), Utils.getDigest(treeDigest)))
+                    .withIndex(xmssMtPrivateKey.getIndex())
+                    .withSecretKeySeed(xmssMtPrivateKey.getSecretKeySeed())
+                    .withSecretKeyPRF(xmssMtPrivateKey.getSecretKeyPRF())
+                    .withPublicSeed(xmssMtPrivateKey.getPublicSeed())
+                    .withRoot(xmssMtPrivateKey.getRoot());
+
+                if (xmssMtPrivateKey.getVersion() != 0)
+                {
+                    keyBuilder.withMaxIndex(xmssMtPrivateKey.getMaxIndex());
+                }
+
+                if (xmssMtPrivateKey.getBdsState() != null)
+                {
+                    BDSStateMap bdsState = (BDSStateMap)XMSSUtil.deserialize(xmssMtPrivateKey.getBdsState(), BDSStateMap.class);
+                    keyBuilder.withBDSState(bdsState.withWOTSDigest(treeDigest));
+                }
+
+                return keyBuilder.build();
+            }
+            catch (ClassNotFoundException e)
+            {
+                throw new IOException("ClassNotFoundException processing BDS state: " + e.getMessage());
+            }
+        }
+        else
+        {
+            throw new RuntimeException("algorithm identifier in private key not recognised");
+        }
+    }
+
+    private static short[] convert(byte[] octets)
+    {
+        short[] rv = new short[octets.length / 2];
+
+        for (int i = 0; i != rv.length; i++)
+        {
+            rv[i] = Pack.littleEndianToShort(octets, i * 2);
+        }
+
+        return rv;
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java
new file mode 100644
index 000000000..326915dcb
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/PrivateKeyInfoFactory.java
@@ -0,0 +1,213 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.util;
+
+import java.io.IOException;
+
+import com.fr.third.org.bouncycastle.asn1.ASN1Set;
+import com.fr.third.org.bouncycastle.asn1.DEROctetString;
+import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
+import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import com.fr.third.org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSKeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSMTKeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSMTPrivateKey;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSPrivateKey;
+import com.fr.third.org.bouncycastle.pqc.crypto.newhope.NHPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLAPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.BDS;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.BDSStateMap;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSMTPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSPrivateKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSUtil;
+import com.fr.third.org.bouncycastle.util.Pack;
+
+/**
+ * Factory to create ASN.1 private key info objects from lightweight private keys.
+ */
+public class PrivateKeyInfoFactory
+{
+    private PrivateKeyInfoFactory()
+    {
+
+    }
+
+    /**
+     * Create a PrivateKeyInfo representation of a private key.
+     *
+     * @param privateKey the key to be encoded into the info object.
+     * @return the appropriate PrivateKeyInfo
+     * @throws java.io.IOException on an error encoding the key
+     */
+    public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey) throws IOException
+    {
+        return createPrivateKeyInfo(privateKey, null);
+    }
+
+    /**
+     * Create a PrivateKeyInfo representation of a private key with attributes.
+     *
+     * @param privateKey the key to be encoded into the info object.
+     * @param attributes the set of attributes to be included.
+     * @return the appropriate PrivateKeyInfo
+     * @throws java.io.IOException on an error encoding the key
+     */
+    public static PrivateKeyInfo createPrivateKeyInfo(AsymmetricKeyParameter privateKey, ASN1Set attributes) throws IOException
+    {
+        if (privateKey instanceof QTESLAPrivateKeyParameters)
+        {
+            QTESLAPrivateKeyParameters keyParams = (QTESLAPrivateKeyParameters)privateKey;
+
+            AlgorithmIdentifier algorithmIdentifier = Utils.qTeslaLookupAlgID(keyParams.getSecurityCategory());
+
+            return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(keyParams.getSecret()), attributes);
+        }
+        else if (privateKey instanceof SPHINCSPrivateKeyParameters)
+        {
+            SPHINCSPrivateKeyParameters params = (SPHINCSPrivateKeyParameters)privateKey;
+            AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.sphincs256,
+                                    new SPHINCS256KeyParams(Utils.sphincs256LookupTreeAlgID(params.getTreeDigest())));
+
+            return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getKeyData()));
+        }
+        else if (privateKey instanceof NHPrivateKeyParameters)
+        {
+            NHPrivateKeyParameters params = (NHPrivateKeyParameters)privateKey;
+
+            AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.newHope);
+
+            short[] privateKeyData = params.getSecData();
+
+            byte[] octets = new byte[privateKeyData.length * 2];
+            for (int i = 0; i != privateKeyData.length; i++)
+            {
+                Pack.shortToLittleEndian(privateKeyData[i], octets, i * 2);
+            }
+
+            return new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(octets));
+        }
+        else if (privateKey instanceof XMSSPrivateKeyParameters)
+        {
+            XMSSPrivateKeyParameters keyParams = (XMSSPrivateKeyParameters)privateKey;
+            AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.xmss,
+                new XMSSKeyParams(keyParams.getParameters().getHeight(),
+                    Utils.xmssLookupTreeAlgID(keyParams.getTreeDigest())));
+
+            return new PrivateKeyInfo(algorithmIdentifier, xmssCreateKeyStructure(keyParams));
+        }
+        else if (privateKey instanceof XMSSMTPrivateKeyParameters)
+        {
+            XMSSMTPrivateKeyParameters keyParams = (XMSSMTPrivateKeyParameters)privateKey;
+            AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.xmss_mt,
+                new XMSSMTKeyParams(keyParams.getParameters().getHeight(), keyParams.getParameters().getLayers(),
+                    Utils.xmssLookupTreeAlgID(keyParams.getTreeDigest())));
+
+            return new PrivateKeyInfo(algorithmIdentifier, xmssmtCreateKeyStructure(keyParams));
+        }
+        else
+        {
+            throw new IOException("key parameters not recognized");
+        }
+    }
+
+    private static XMSSPrivateKey xmssCreateKeyStructure(XMSSPrivateKeyParameters keyParams)
+        throws IOException
+    {
+        byte[] keyData = keyParams.getEncoded();
+
+        int n = keyParams.getParameters().getTreeDigestSize();
+        int totalHeight = keyParams.getParameters().getHeight();
+        int indexSize = 4;
+        int secretKeySize = n;
+        int secretKeyPRFSize = n;
+        int publicSeedSize = n;
+        int rootSize = n;
+
+        int position = 0;
+        int index = (int)XMSSUtil.bytesToXBigEndian(keyData, position, indexSize);
+        if (!XMSSUtil.isIndexValid(totalHeight, index))
+        {
+            throw new IllegalArgumentException("index out of bounds");
+        }
+        position += indexSize;
+        byte[] secretKeySeed = XMSSUtil.extractBytesAtOffset(keyData, position, secretKeySize);
+        position += secretKeySize;
+        byte[] secretKeyPRF = XMSSUtil.extractBytesAtOffset(keyData, position, secretKeyPRFSize);
+        position += secretKeyPRFSize;
+        byte[] publicSeed = XMSSUtil.extractBytesAtOffset(keyData, position, publicSeedSize);
+        position += publicSeedSize;
+        byte[] root = XMSSUtil.extractBytesAtOffset(keyData, position, rootSize);
+        position += rootSize;
+               /* import BDS state */
+        byte[] bdsStateBinary = XMSSUtil.extractBytesAtOffset(keyData, position, keyData.length - position);
+        BDS bds = null;
+        try
+        {
+            bds = (BDS)XMSSUtil.deserialize(bdsStateBinary, BDS.class);
+        }
+        catch (ClassNotFoundException e)
+        {
+            throw new IOException("cannot parse BDS: " + e.getMessage());
+        }
+
+        if ((bds.getMaxIndex() != (1 << totalHeight) - 1))
+        {
+            return new XMSSPrivateKey(index, secretKeySeed, secretKeyPRF, publicSeed, root, bdsStateBinary, bds.getMaxIndex());
+        }
+        else
+        {
+            return new XMSSPrivateKey(index, secretKeySeed, secretKeyPRF, publicSeed, root, bdsStateBinary);
+        }
+    }
+
+    private static XMSSMTPrivateKey xmssmtCreateKeyStructure(XMSSMTPrivateKeyParameters keyParams)
+        throws IOException
+    {
+        byte[] keyData = keyParams.getEncoded();
+
+        int n = keyParams.getParameters().getTreeDigestSize();
+        int totalHeight = keyParams.getParameters().getHeight();
+        int indexSize = (totalHeight + 7) / 8;
+        int secretKeySize = n;
+        int secretKeyPRFSize = n;
+        int publicSeedSize = n;
+        int rootSize = n;
+
+        int position = 0;
+        int index = (int)XMSSUtil.bytesToXBigEndian(keyData, position, indexSize);
+        if (!XMSSUtil.isIndexValid(totalHeight, index))
+        {
+            throw new IllegalArgumentException("index out of bounds");
+        }
+        position += indexSize;
+        byte[] secretKeySeed = XMSSUtil.extractBytesAtOffset(keyData, position, secretKeySize);
+        position += secretKeySize;
+        byte[] secretKeyPRF = XMSSUtil.extractBytesAtOffset(keyData, position, secretKeyPRFSize);
+        position += secretKeyPRFSize;
+        byte[] publicSeed = XMSSUtil.extractBytesAtOffset(keyData, position, publicSeedSize);
+        position += publicSeedSize;
+        byte[] root = XMSSUtil.extractBytesAtOffset(keyData, position, rootSize);
+        position += rootSize;
+               /* import BDS state */
+        byte[] bdsStateBinary = XMSSUtil.extractBytesAtOffset(keyData, position, keyData.length - position);
+        BDSStateMap bds = null;
+        try
+        {
+            bds = (BDSStateMap)XMSSUtil.deserialize(bdsStateBinary, BDSStateMap.class);
+        }
+        catch (ClassNotFoundException e)
+        {
+            throw new IOException("cannot parse BDSStateMap: " + e.getMessage());
+        }
+
+        if ((bds.getMaxIndex() != (1L << totalHeight) - 1))
+        {
+            return new XMSSMTPrivateKey(index, secretKeySeed, secretKeyPRF, publicSeed, root, bdsStateBinary, bds.getMaxIndex());
+        }
+        else
+        {
+            return new XMSSMTPrivateKey(index, secretKeySeed, secretKeyPRF, publicSeed, root, bdsStateBinary);
+        }
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
new file mode 100644
index 000000000..a34664b39
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/PublicKeyFactory.java
@@ -0,0 +1,179 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.util;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fr.third.org.bouncycastle.asn1.ASN1InputStream;
+import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.fr.third.org.bouncycastle.asn1.ASN1Primitive;
+import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import com.fr.third.org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSKeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSMTKeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSPublicKey;
+import com.fr.third.org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLAPublicKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSMTParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSMTPublicKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSPublicKeyParameters;
+
+/**
+ * Factory to create asymmetric public key parameters for asymmetric ciphers from range of
+ * ASN.1 encoded SubjectPublicKeyInfo objects.
+ */
+public class PublicKeyFactory
+{
+    private static Map converters = new HashMap();
+
+    static
+    {
+        converters.put(PQCObjectIdentifiers.qTESLA_p_I, new QTeslaConverter());
+        converters.put(PQCObjectIdentifiers.qTESLA_p_III, new QTeslaConverter());
+        converters.put(PQCObjectIdentifiers.sphincs256, new SPHINCSConverter());
+        converters.put(PQCObjectIdentifiers.newHope, new NHConverter());
+        converters.put(PQCObjectIdentifiers.xmss, new XMSSConverter());
+        converters.put(PQCObjectIdentifiers.xmss_mt, new XMSSMTConverter());
+    }
+
+    /**
+     * Create a public key from a SubjectPublicKeyInfo encoding
+     *
+     * @param keyInfoData the SubjectPublicKeyInfo encoding
+     * @return the appropriate key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(byte[] keyInfoData)
+        throws IOException
+    {
+        return createKey(SubjectPublicKeyInfo.getInstance(ASN1Primitive.fromByteArray(keyInfoData)));
+    }
+
+    /**
+     * Create a public key from a SubjectPublicKeyInfo encoding read from a stream
+     *
+     * @param inStr the stream to read the SubjectPublicKeyInfo encoding from
+     * @return the appropriate key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(InputStream inStr)
+        throws IOException
+    {
+        return createKey(SubjectPublicKeyInfo.getInstance(new ASN1InputStream(inStr).readObject()));
+    }
+
+    /**
+     * Create a public key from the passed in SubjectPublicKeyInfo
+     *
+     * @param keyInfo the SubjectPublicKeyInfo containing the key data
+     * @return the appropriate key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo)
+        throws IOException
+    {
+        return createKey(keyInfo, null);
+    }
+
+    /**
+     * Create a public key from the passed in SubjectPublicKeyInfo
+     *
+     * @param keyInfo the SubjectPublicKeyInfo containing the key data
+     * @param defaultParams default parameters that might be needed.
+     * @return the appropriate key parameter
+     * @throws IOException on an error decoding the key
+     */
+    public static AsymmetricKeyParameter createKey(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+        throws IOException
+    {
+        AlgorithmIdentifier algId = keyInfo.getAlgorithm();
+        SubjectPublicKeyInfoConverter converter = (SubjectPublicKeyInfoConverter)converters.get(algId.getAlgorithm());
+
+        if (converter != null)
+        {
+            return converter.getPublicKeyParameters(keyInfo, defaultParams);
+        }
+        else
+        {
+            throw new IOException("algorithm identifier in public key not recognised: " + algId.getAlgorithm());
+        }
+    }
+
+    private static abstract class SubjectPublicKeyInfoConverter
+    {
+        abstract AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException;
+    }
+
+    private static class QTeslaConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            return new QTESLAPublicKeyParameters(Utils.qTeslaLookupSecurityCategory(keyInfo.getAlgorithm()), keyInfo.getPublicKeyData().getOctets());
+        }
+    }
+
+    private static class SPHINCSConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            return new SPHINCSPublicKeyParameters(keyInfo.getPublicKeyData().getBytes(),
+                            Utils.sphincs256LookupTreeAlgName(SPHINCS256KeyParams.getInstance(keyInfo.getAlgorithm().getParameters())));
+        }
+    }
+
+    private static class NHConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            return new NHPublicKeyParameters(keyInfo.getPublicKeyData().getBytes());
+        }
+    }
+
+    private static class XMSSConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            XMSSKeyParams keyParams = XMSSKeyParams.getInstance(keyInfo.getAlgorithm().getParameters());
+            ASN1ObjectIdentifier treeDigest = keyParams.getTreeDigest().getAlgorithm();
+            XMSSPublicKey xmssPublicKey = XMSSPublicKey.getInstance(keyInfo.parsePublicKey());
+
+            return new XMSSPublicKeyParameters
+                .Builder(new XMSSParameters(keyParams.getHeight(), Utils.getDigest(treeDigest)))
+                .withPublicSeed(xmssPublicKey.getPublicSeed())
+                .withRoot(xmssPublicKey.getRoot()).build();
+        }
+    }
+
+    private static class XMSSMTConverter
+        extends SubjectPublicKeyInfoConverter
+    {
+        AsymmetricKeyParameter getPublicKeyParameters(SubjectPublicKeyInfo keyInfo, Object defaultParams)
+            throws IOException
+        {
+            XMSSMTKeyParams keyParams = XMSSMTKeyParams.getInstance(keyInfo.getAlgorithm().getParameters());
+            ASN1ObjectIdentifier treeDigest = keyParams.getTreeDigest().getAlgorithm();
+
+            XMSSPublicKey xmssMtPublicKey = XMSSPublicKey.getInstance(keyInfo.parsePublicKey());
+
+            return new XMSSMTPublicKeyParameters
+                .Builder(new XMSSMTParameters(keyParams.getHeight(), keyParams.getLayers(), Utils.getDigest(treeDigest)))
+                .withPublicSeed(xmssMtPublicKey.getPublicSeed())
+                .withRoot(xmssMtPublicKey.getRoot()).build();
+        }
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
new file mode 100644
index 000000000..2919dbde1
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/SubjectPublicKeyInfoFactory.java
@@ -0,0 +1,83 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.util;
+
+import java.io.IOException;
+
+import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import com.fr.third.org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSKeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSMTKeyParams;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSMTPublicKey;
+import com.fr.third.org.bouncycastle.pqc.asn1.XMSSPublicKey;
+import com.fr.third.org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLAPublicKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSMTPublicKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSPublicKeyParameters;
+
+/**
+ * Factory to create ASN.1 subject public key info objects from lightweight public keys.
+ */
+public class SubjectPublicKeyInfoFactory
+{
+    private SubjectPublicKeyInfoFactory()
+    {
+
+    }
+
+    /**
+     * Create a SubjectPublicKeyInfo public key.
+     *
+     * @param publicKey the key to be encoded into the info object.
+     * @return a SubjectPublicKeyInfo representing the key.
+     * @throws java.io.IOException on an error encoding the key
+     */
+    public static SubjectPublicKeyInfo createSubjectPublicKeyInfo(AsymmetricKeyParameter publicKey)
+        throws IOException
+    {
+        if (publicKey instanceof QTESLAPublicKeyParameters)
+        {
+            QTESLAPublicKeyParameters keyParams = (QTESLAPublicKeyParameters)publicKey;
+            AlgorithmIdentifier algorithmIdentifier = Utils.qTeslaLookupAlgID(keyParams.getSecurityCategory());
+
+            return new SubjectPublicKeyInfo(algorithmIdentifier, keyParams.getPublicData());
+        }
+        else if (publicKey instanceof SPHINCSPublicKeyParameters)
+        {
+            SPHINCSPublicKeyParameters params = (SPHINCSPublicKeyParameters)publicKey;
+
+            AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.sphincs256,
+                new SPHINCS256KeyParams(Utils.sphincs256LookupTreeAlgID(params.getTreeDigest())));
+            return new SubjectPublicKeyInfo(algorithmIdentifier, params.getKeyData());
+        }
+        else if (publicKey instanceof NHPublicKeyParameters)
+        {
+            NHPublicKeyParameters params = (NHPublicKeyParameters)publicKey;
+
+            AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.newHope);
+            return new SubjectPublicKeyInfo(algorithmIdentifier, params.getPubData());
+        }
+        else if (publicKey instanceof XMSSPublicKeyParameters)
+        {
+            XMSSPublicKeyParameters keyParams = (XMSSPublicKeyParameters)publicKey;
+
+            AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.xmss,
+                new XMSSKeyParams(keyParams.getParameters().getHeight(), Utils.xmssLookupTreeAlgID(keyParams.getTreeDigest())));
+            return new SubjectPublicKeyInfo(algorithmIdentifier, new XMSSPublicKey(keyParams.getPublicSeed(), keyParams.getRoot()));
+        }
+        else if (publicKey instanceof XMSSMTPublicKeyParameters)
+        {
+            XMSSMTPublicKeyParameters keyParams = (XMSSMTPublicKeyParameters)publicKey;
+
+            AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.xmss_mt, new XMSSMTKeyParams(keyParams.getParameters().getHeight(), keyParams.getParameters().getLayers(),
+                Utils.xmssLookupTreeAlgID(keyParams.getTreeDigest())));
+            return new SubjectPublicKeyInfo(algorithmIdentifier, new XMSSMTPublicKey(keyParams.getPublicSeed(), keyParams.getRoot()));
+        }
+        else
+        {
+            throw new IOException("key parameters not recognized");
+        }
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/Utils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/Utils.java
new file mode 100644
index 000000000..3f89da27a
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/util/Utils.java
@@ -0,0 +1,138 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.util;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
+import com.fr.third.org.bouncycastle.crypto.Digest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest;
+import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers;
+import com.fr.third.org.bouncycastle.pqc.asn1.SPHINCS256KeyParams;
+import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLASecurityCategory;
+import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCSKeyParameters;
+import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSKeyParameters;
+import com.fr.third.org.bouncycastle.util.Integers;
+
+class Utils
+{
+   static final AlgorithmIdentifier AlgID_qTESLA_p_I = new AlgorithmIdentifier(PQCObjectIdentifiers.qTESLA_p_I);
+    static final AlgorithmIdentifier AlgID_qTESLA_p_III = new AlgorithmIdentifier(PQCObjectIdentifiers.qTESLA_p_III);
+
+    static final AlgorithmIdentifier SPHINCS_SHA3_256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha3_256);
+    static final AlgorithmIdentifier SPHINCS_SHA512_256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512_256);
+
+    static final AlgorithmIdentifier XMSS_SHA256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256);
+    static final AlgorithmIdentifier XMSS_SHA512 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha512);
+    static final AlgorithmIdentifier XMSS_SHAKE128 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake128);
+    static final AlgorithmIdentifier XMSS_SHAKE256 = new AlgorithmIdentifier(NISTObjectIdentifiers.id_shake256);
+
+    static final Map categories = new HashMap();
+
+    static
+    {
+        categories.put(PQCObjectIdentifiers.qTESLA_p_I, Integers.valueOf(QTESLASecurityCategory.PROVABLY_SECURE_I));
+        categories.put(PQCObjectIdentifiers.qTESLA_p_III, Integers.valueOf(QTESLASecurityCategory.PROVABLY_SECURE_III));
+    }
+
+    static int qTeslaLookupSecurityCategory(AlgorithmIdentifier algorithm)
+    {
+        return ((Integer)categories.get(algorithm.getAlgorithm())).intValue();
+    }
+
+    static AlgorithmIdentifier qTeslaLookupAlgID(int securityCategory)
+    {
+        switch (securityCategory)
+        {
+        case QTESLASecurityCategory.PROVABLY_SECURE_I:
+            return AlgID_qTESLA_p_I;
+        case QTESLASecurityCategory.PROVABLY_SECURE_III:
+            return AlgID_qTESLA_p_III;
+        default:
+            throw new IllegalArgumentException("unknown security category: " + securityCategory);
+        }
+    }
+
+    static AlgorithmIdentifier sphincs256LookupTreeAlgID(String treeDigest)
+    {
+        if (treeDigest.equals(SPHINCSKeyParameters.SHA3_256))
+        {
+            return SPHINCS_SHA3_256;
+        }
+        else if (treeDigest.equals(SPHINCSKeyParameters.SHA512_256))
+        {
+            return SPHINCS_SHA512_256;
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown tree digest: " + treeDigest);
+        }
+    }
+
+    static AlgorithmIdentifier xmssLookupTreeAlgID(String treeDigest)
+    {
+        if (treeDigest.equals(XMSSKeyParameters.SHA_256))
+        {
+            return XMSS_SHA256;
+        }
+        else if (treeDigest.equals(XMSSKeyParameters.SHA_512))
+        {
+            return XMSS_SHA512;
+        }
+        else if (treeDigest.equals(XMSSKeyParameters.SHAKE128))
+        {
+            return XMSS_SHAKE128;
+        }
+        else if (treeDigest.equals(XMSSKeyParameters.SHAKE256))
+        {
+            return XMSS_SHAKE256;
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown tree digest: " + treeDigest);
+        }
+    }
+
+    static String sphincs256LookupTreeAlgName(SPHINCS256KeyParams keyParams)
+    {
+        AlgorithmIdentifier treeDigest = keyParams.getTreeDigest();
+
+        if (treeDigest.getAlgorithm().equals(SPHINCS_SHA3_256.getAlgorithm()))
+        {
+            return SPHINCSKeyParameters.SHA3_256;
+        }
+        else if (treeDigest.getAlgorithm().equals(SPHINCS_SHA512_256.getAlgorithm()))
+        {
+            return SPHINCSKeyParameters.SHA512_256;
+        }
+        else
+        {
+            throw new IllegalArgumentException("unknown tree digest: " + treeDigest.getAlgorithm());
+        }
+    }
+
+    static Digest getDigest(ASN1ObjectIdentifier oid)
+    {
+        if (oid.equals(NISTObjectIdentifiers.id_sha256))
+        {
+            return new SHA256Digest();
+        }
+        if (oid.equals(NISTObjectIdentifiers.id_sha512))
+        {
+            return new SHA512Digest();
+        }
+        if (oid.equals(NISTObjectIdentifiers.id_shake128))
+        {
+            return new SHAKEDigest(128);
+        }
+        if (oid.equals(NISTObjectIdentifiers.id_shake256))
+        {
+            return new SHAKEDigest(256);
+        }
+
+        throw new IllegalArgumentException("unrecognized digest OID: " + oid);
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDS.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDS.java
index 88b701d5d..a11790aa5 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDS.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDS.java
@@ -1,13 +1,19 @@
 package com.fr.third.org.bouncycastle.pqc.crypto.xmss;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Stack;
 import java.util.TreeMap;
 
+import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+
 /**
  * BDS.
  */
@@ -30,15 +36,18 @@ public final class BDS
     private int index;
     private boolean used;
 
+    private transient int maxIndex;
+
     /**
      * Place holder BDS for when state is exhausted.
      *
      * @param params tree parameters
      * @param index the index that has been reached.
      */
-    BDS(XMSSParameters params, int index)
+    BDS(XMSSParameters params, int maxIndex, int index)
     {
-        this(params.getWOTSPlus(), params.getHeight(), params.getK());
+        this(params.getWOTSPlus(), params.getHeight(), params.getK(), index);
+        this.maxIndex = maxIndex;
         this.index = index;
         this.used = true;
     }
@@ -53,7 +62,7 @@ public final class BDS
      */
     BDS(XMSSParameters params, byte[] publicSeed, byte[] secretKeySeed, OTSHashAddress otsHashAddress)
     {
-        this(params.getWOTSPlus(), params.getHeight(), params.getK());
+        this(params.getWOTSPlus(), params.getHeight(), params.getK(), ((1 << params.getHeight()) - 1));
         this.initialize(publicSeed, secretKeySeed, otsHashAddress);
     }
 
@@ -68,7 +77,7 @@ public final class BDS
      */
     BDS(XMSSParameters params, byte[] publicSeed, byte[] secretKeySeed, OTSHashAddress otsHashAddress, int index)
     {
-        this(params.getWOTSPlus(), params.getHeight(), params.getK());
+        this(params.getWOTSPlus(), params.getHeight(), params.getK(), ((1 << params.getHeight()) - 1));
 
         this.initialize(publicSeed, secretKeySeed, otsHashAddress);
 
@@ -79,10 +88,11 @@ public final class BDS
         }
     }
 
-    private BDS(WOTSPlus wotsPlus, int treeHeight, int k)
+    private BDS(WOTSPlus wotsPlus, int treeHeight, int k, int maxIndex)
     {
         this.wotsPlus = wotsPlus;
         this.treeHeight = treeHeight;
+        this.maxIndex = maxIndex;
         this.k = k;
         if (k > treeHeight || k < 2 || ((treeHeight - k) % 2) != 0)
         {
@@ -103,24 +113,118 @@ public final class BDS
         this.used = false;
     }
 
+    BDS(BDS last)
+    {
+        this.wotsPlus = new WOTSPlus(last.wotsPlus.getParams());
+        this.treeHeight = last.treeHeight;
+        this.k = last.k;
+        this.root = last.root;
+        this.authenticationPath = new ArrayList();  // note use of addAll to avoid serialization issues
+        this.authenticationPath.addAll(last.authenticationPath);
+        this.retain = new TreeMap>();
+        for (Iterator it = last.retain.keySet().iterator(); it.hasNext();)
+        {
+            Integer key = (Integer)it.next();
+            this.retain.put(key, (LinkedList)last.retain.get(key).clone());
+        }
+        this.stack = new Stack(); // note use of addAll to avoid serialization issues
+        this.stack.addAll(last.stack);
+        this.treeHashInstances = new ArrayList();
+        for (Iterator it = last.treeHashInstances.iterator(); it.hasNext();)
+        {
+            this.treeHashInstances.add(((BDSTreeHash)it.next()).clone());
+        }
+        this.keep = new TreeMap(last.keep);
+        this.index = last.index;
+        this.maxIndex = last.maxIndex;
+        this.used = last.used;
+    }
+
     private BDS(BDS last, byte[] publicSeed, byte[] secretKeySeed, OTSHashAddress otsHashAddress)
     {
-        this.wotsPlus = last.wotsPlus;
+        this.wotsPlus = new WOTSPlus(last.wotsPlus.getParams());
         this.treeHeight = last.treeHeight;
         this.k = last.k;
         this.root = last.root;
-        this.authenticationPath = new ArrayList(last.authenticationPath);
-        this.retain = last.retain;
-        this.stack = (Stack)last.stack.clone();
-        this.treeHashInstances = last.treeHashInstances;
+        this.authenticationPath = new ArrayList();  // note use of addAll to avoid serialization issues
+        this.authenticationPath.addAll(last.authenticationPath);
+        this.retain = new TreeMap>();
+        for (Iterator it = last.retain.keySet().iterator(); it.hasNext();)
+        {
+            Integer key = (Integer)it.next();
+            this.retain.put(key, (LinkedList)last.retain.get(key).clone());
+        }
+        this.stack = new Stack(); // note use of addAll to avoid serialization issues
+        this.stack.addAll(last.stack);
+        this.treeHashInstances = new ArrayList();
+        for (Iterator it = last.treeHashInstances.iterator(); it.hasNext();)
+        {
+            this.treeHashInstances.add(((BDSTreeHash)it.next()).clone());
+        }
         this.keep = new TreeMap(last.keep);
         this.index = last.index;
+        this.maxIndex = last.maxIndex;
+        this.used = false;
 
         this.nextAuthenticationPath(publicSeed, secretKeySeed, otsHashAddress);
+    }
+
+    private BDS(BDS last, ASN1ObjectIdentifier digest)
+    {
+        this.wotsPlus = new WOTSPlus(new WOTSPlusParameters(digest));
+        this.treeHeight = last.treeHeight;
+        this.k = last.k;
+        this.root = last.root;
+        this.authenticationPath = new ArrayList();  // note use of addAll to avoid serialization issues
+        this.authenticationPath.addAll(last.authenticationPath);
+        this.retain = new TreeMap>();
+        for (Iterator it = last.retain.keySet().iterator(); it.hasNext();)
+        {
+            Integer key = (Integer)it.next();
+            this.retain.put(key, (LinkedList)last.retain.get(key).clone());
+        }
+        this.stack = new Stack();     // note use of addAll to avoid serialization issues
+        this.stack.addAll(last.stack);
+        this.treeHashInstances = new ArrayList();
+        for (Iterator it = last.treeHashInstances.iterator(); it.hasNext();)
+        {
+            this.treeHashInstances.add(((BDSTreeHash)it.next()).clone());
+        }
+        this.keep = new TreeMap(last.keep);
+        this.index = last.index;
+        this.maxIndex = last.maxIndex;
+        this.used = last.used;
+        this.validate();
+    }
 
-        last.used = true;
+    private BDS(BDS last, int maxIndex, ASN1ObjectIdentifier digest)
+    {
+        this.wotsPlus = new WOTSPlus(new WOTSPlusParameters(digest));
+        this.treeHeight = last.treeHeight;
+        this.k = last.k;
+        this.root = last.root;
+        this.authenticationPath = new ArrayList();  // note use of addAll to avoid serialization issues
+        this.authenticationPath.addAll(last.authenticationPath);
+        this.retain = new TreeMap>();
+        for (Iterator it = last.retain.keySet().iterator(); it.hasNext();)
+        {
+            Integer key = (Integer)it.next();
+            this.retain.put(key, (LinkedList)last.retain.get(key).clone());
+        }
+        this.stack = new Stack();     // note use of addAll to avoid serialization issues
+        this.stack.addAll(last.stack);
+        this.treeHashInstances = new ArrayList();
+        for (Iterator it = last.treeHashInstances.iterator(); it.hasNext();)
+        {
+            this.treeHashInstances.add(((BDSTreeHash)it.next()).clone());
+        }
+        this.keep = new TreeMap(last.keep);
+        this.index = last.index;
+        this.maxIndex = maxIndex;
+        this.used = last.used;
+        this.validate();
     }
-    
+
     public BDS getNextState(byte[] publicSeed, byte[] secretKeySeed, OTSHashAddress otsHashAddress)
     {
         return new BDS(this, publicSeed, secretKeySeed, otsHashAddress);
@@ -168,15 +272,15 @@ public final class BDS
             while (!stack.isEmpty() && stack.peek().getHeight() == node.getHeight())
             {
 				/* add to authenticationPath if leafIndex == 1 */
-                int indexOnHeight = ((int)Math.floor(indexLeaf / (1 << node.getHeight())));
+                int indexOnHeight = indexLeaf / (1 << node.getHeight());
                 if (indexOnHeight == 1)
                 {
-                    authenticationPath.add(node.clone());
+                    authenticationPath.add(node);
                 }
 				/* store next right authentication node */
                 if (indexOnHeight == 3 && node.getHeight() < (treeHeight - k))
                 {
-                    treeHashInstances.get(node.getHeight()).setNode(node.clone());
+                    treeHashInstances.get(node.getHeight()).setNode(node);
                 }
                 if (indexOnHeight >= 3 && (indexOnHeight & 1) == 1 && node.getHeight() >= (treeHeight - k)
                     && node.getHeight() <= (treeHeight - 2))
@@ -184,12 +288,12 @@ public final class BDS
                     if (retain.get(node.getHeight()) == null)
                     {
                         LinkedList queue = new LinkedList();
-                        queue.add(node.clone());
+                        queue.add(node);
                         retain.put(node.getHeight(), queue);
                     }
                     else
                     {
-                        retain.get(node.getHeight()).add(node.clone());
+                        retain.get(node.getHeight()).add(node);
                     }
                 }
                 hashTreeAddress = (HashTreeAddress)new HashTreeAddress.Builder()
@@ -223,11 +327,20 @@ public final class BDS
         {
             throw new IllegalStateException("index already used");
         }
-        if (index > ((1 << treeHeight) - 2))
+        if (index > maxIndex - 1)
         {
             throw new IllegalStateException("index out of bounds");
         }
-		/* prepare addresses */
+        
+		/* determine tau */
+        int tau = XMSSUtil.calculateTau(index, treeHeight);
+    	/* parent of leaf on height tau+1 is a left node */
+        if (((index >> (tau + 1)) & 1) == 0 && (tau < (treeHeight - 1)))
+        {
+            keep.put(tau, authenticationPath.get(tau));
+        }
+
+        /* prepare addresses */
         LTreeAddress lTreeAddress = (LTreeAddress)new LTreeAddress.Builder()
             .withLayerAddress(otsHashAddress.getLayerAddress()).withTreeAddress(otsHashAddress.getTreeAddress())
             .build();
@@ -235,13 +348,6 @@ public final class BDS
             .withLayerAddress(otsHashAddress.getLayerAddress()).withTreeAddress(otsHashAddress.getTreeAddress())
             .build();
 
-		/* determine tau */
-        int tau = XMSSUtil.calculateTau(index, treeHeight);
-    	/* parent of leaf on height tau+1 is a left node */
-        if (((index >> (tau + 1)) & 1) == 0 && (tau < (treeHeight - 1)))
-        {
-            keep.put(tau, authenticationPath.get(tau).clone());
-        }
 		/* leaf is a left node */
         if (tau == 0)
         {
@@ -270,6 +376,11 @@ public final class BDS
                 .withLayerAddress(hashTreeAddress.getLayerAddress())
                 .withTreeAddress(hashTreeAddress.getTreeAddress()).withTreeHeight(tau - 1)
                 .withTreeIndex(index >> tau).withKeyAndMask(hashTreeAddress.getKeyAndMask()).build();
+            /*
+             * import WOTSPlusSecretKey as its needed to calculate the public
+             * key on the fly
+             */
+            wotsPlus.importKeys(wotsPlus.getWOTSPlusSecretKey(secretSeed, otsHashAddress), publicSeed);
             XMSSNode node = XMSSNodeUtil.randomizeHash(wotsPlus, authenticationPath.get(tau - 1), keep.get(tau - 1), hashTreeAddress);
             node = new XMSSNode(node.getHeight() + 1, node.getValue());
             authenticationPath.set(tau, node);
@@ -318,6 +429,11 @@ public final class BDS
         return used;
     }
 
+    void markUsed()
+    {
+        this.used = true;
+    }
+
     private BDSTreeHash getBDSTreeHashInstanceForUpdate()
     {
         BDSTreeHash ret = null;
@@ -348,7 +464,7 @@ public final class BDS
         return ret;
     }
 
-    protected void validate()
+    private void validate()
     {
         if (authenticationPath == null)
         {
@@ -383,31 +499,66 @@ public final class BDS
 
     protected XMSSNode getRoot()
     {
-        return root.clone();
+        return root;
     }
 
     protected List getAuthenticationPath()
     {
         List authenticationPath = new ArrayList();
+
         for (XMSSNode node : this.authenticationPath)
         {
-            authenticationPath.add(node.clone());
+            authenticationPath.add(node);
         }
         return authenticationPath;
     }
 
-    protected void setXMSS(XMSSParameters xmss)
+    protected int getIndex()
+    {
+        return index;
+    }
+
+    public int getMaxIndex()
+    {
+        return maxIndex;
+    }
+
+    public BDS withWOTSDigest(ASN1ObjectIdentifier digestName)
+    {
+        return new BDS(this, digestName);
+    }
+
+    public BDS withMaxIndex(int maxIndex, ASN1ObjectIdentifier digestName)
+    {
+        return new BDS(this, maxIndex, digestName);
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
     {
-        if (treeHeight != xmss.getHeight())
+        in.defaultReadObject();
+
+        if (in.available() != 0)
         {
-            throw new IllegalStateException("wrong height");
+            this.maxIndex = in.readInt();
+        }
+        else
+        {
+            this.maxIndex = (1 << treeHeight) - 1;
+        }
+        if (maxIndex > ((1 << treeHeight) - 1) || index > (maxIndex + 1) || in.available() != 0)
+        {
+            throw new IOException("inconsistent BDS data detected");
         }
-
-        this.wotsPlus = xmss.getWOTSPlus();
     }
 
-    protected int getIndex()
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
     {
-        return index;
+        out.defaultWriteObject();
+
+        out.writeInt(this.maxIndex);
     }
 }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDSStateMap.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDSStateMap.java
index f74a407f6..9523c3ea0 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDSStateMap.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDSStateMap.java
@@ -1,43 +1,56 @@
 package com.fr.third.org.bouncycastle.pqc.crypto.xmss;
 
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
 import java.io.Serializable;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.TreeMap;
 
+import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import com.fr.third.org.bouncycastle.util.Integers;
 
 public class BDSStateMap
     implements Serializable
 {
+    private static final long serialVersionUID = -3464451825208522308L;
+    
     private final Map bdsState = new TreeMap();
 
-    BDSStateMap()
-    {
-
-    }
+    private transient long maxIndex;
 
-    BDSStateMap(XMSSMTParameters params, long globalIndex, byte[] publicSeed, byte[] secretKeySeed)
+    BDSStateMap(long maxIndex)
     {
-         for (long index = 0; index < globalIndex; index++)
-         {
-             updateState(params, index, publicSeed, secretKeySeed);
-         }
+        this.maxIndex = maxIndex;
     }
 
-    BDSStateMap(BDSStateMap stateMap, XMSSMTParameters params, long globalIndex, byte[] publicSeed, byte[] secretKeySeed)
+    BDSStateMap(BDSStateMap stateMap, long maxIndex)
     {
         for (Iterator it = stateMap.bdsState.keySet().iterator(); it.hasNext();)
         {
             Integer key = (Integer)it.next();
 
-            bdsState.put(key, stateMap.bdsState.get(key));
+            bdsState.put(key, new BDS(stateMap.bdsState.get(key)));
         }
+        this.maxIndex = maxIndex;
+    }
 
-        updateState(params, globalIndex, publicSeed, secretKeySeed);
+    BDSStateMap(XMSSMTParameters params, long globalIndex, byte[] publicSeed, byte[] secretKeySeed)
+    {
+        this.maxIndex = (1L << params.getHeight()) - 1;
+        for (long index = 0; index < globalIndex; index++)
+        {
+            updateState(params, index, publicSeed, secretKeySeed);
+        }
     }
 
-    private void updateState(XMSSMTParameters params, long globalIndex, byte[] publicSeed, byte[] secretKeySeed)
+    public long getMaxIndex()
+    {
+        return maxIndex;
+    }
+
+    void updateState(XMSSMTParameters params, long globalIndex, byte[] publicSeed, byte[] secretKeySeed)
     {
         XMSSParameters xmssParams = params.getXMSSParameters();
         int xmssHeight = xmssParams.getHeight();
@@ -73,48 +86,75 @@ public class BDSStateMap
                 .withTreeAddress(indexTree).withOTSAddress(indexLeaf).build();
 
                 /* prepare authentication path for next leaf */
+            if (bdsState.get(layer) == null || XMSSUtil.isNewBDSInitNeeded(globalIndex, xmssHeight, layer))
+            {
+                bdsState.put(layer, new BDS(xmssParams, publicSeed, secretKeySeed, otsHashAddress));
+            }
+
             if (indexLeaf < ((1 << xmssHeight) - 1)
                 && XMSSUtil.isNewAuthenticationPathNeeded(globalIndex, xmssHeight, layer))
             {
-                if (this.get(layer) == null)
-                {
-                    this.put(layer, new BDS(params.getXMSSParameters(), publicSeed, secretKeySeed, otsHashAddress));
-                }
-
                 this.update(layer, publicSeed, secretKeySeed, otsHashAddress);
             }
         }
     }
 
-    void setXMSS(XMSSParameters xmss)
-    {
-        for (Iterator it = bdsState.keySet().iterator(); it.hasNext();)
-        {
-            Integer key = (Integer)it.next();
-
-            BDS bds = bdsState.get(key);
-            bds.setXMSS(xmss);
-            bds.validate();
-        }
-    }
-
     public boolean isEmpty()
     {
         return bdsState.isEmpty();
     }
 
-    public BDS get(int index)
+    BDS get(int index)
     {
         return bdsState.get(Integers.valueOf(index));
     }
 
-    public BDS update(int index, byte[] publicSeed, byte[] secretKeySeed, OTSHashAddress otsHashAddress)
+    BDS update(int index, byte[] publicSeed, byte[] secretKeySeed, OTSHashAddress otsHashAddress)
     {
         return bdsState.put(Integers.valueOf(index), bdsState.get(Integers.valueOf(index)).getNextState(publicSeed, secretKeySeed, otsHashAddress));
     }
 
-    public void put(int index, BDS bds)
+    void put(int index, BDS bds)
     {
         bdsState.put(Integers.valueOf(index), bds);
     }
+
+    public BDSStateMap withWOTSDigest(ASN1ObjectIdentifier digestName)
+    {
+        BDSStateMap newStateMap = new BDSStateMap(this.maxIndex);
+
+        for (Iterator keys = bdsState.keySet().iterator(); keys.hasNext();)
+        {
+            Integer key = keys.next();
+
+            newStateMap.bdsState.put(key, bdsState.get(key).withWOTSDigest(digestName));
+        }
+        
+        return newStateMap;
+    }
+
+    private void readObject(
+        ObjectInputStream in)
+        throws IOException, ClassNotFoundException
+    {
+        in.defaultReadObject();
+
+        if (in.available() != 0)
+        {
+            this.maxIndex = in.readLong();
+        }
+        else
+        {
+            this.maxIndex = 0;
+        }
+    }
+
+    private void writeObject(
+        ObjectOutputStream out)
+        throws IOException
+    {
+        out.defaultWriteObject();
+
+        out.writeLong(this.maxIndex);
+    }
 }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDSTreeHash.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDSTreeHash.java
index f482d3b77..f47ed347b 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDSTreeHash.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/BDSTreeHash.java
@@ -5,7 +5,7 @@ import java.util.Stack;
 
 
 class BDSTreeHash
-    implements Serializable
+    implements Serializable, Cloneable
 {
     private static final long serialVersionUID = 1L;
 
@@ -156,7 +156,20 @@ class BDSTreeHash
 
     public XMSSNode getTailNode()
     {
-        return tailNode.clone();
+        return tailNode;
+    }
+
+    protected BDSTreeHash clone()
+    {
+        BDSTreeHash th = new BDSTreeHash(this.initialHeight);
+
+        th.tailNode = this.tailNode;
+        th.height = this.height;
+        th.nextIndex = this.nextIndex;
+        th.initialized = this.initialized;
+        th.finished = this.finished;
+
+        return th;
     }
 }
 
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DefaultXMSSMTOid.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DefaultXMSSMTOid.java
index d59f06fa8..5e3c60efb 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DefaultXMSSMTOid.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DefaultXMSSMTOid.java
@@ -6,155 +6,157 @@ import java.util.Map;
 
 /**
  * XMSSOid^MT class.
- *
  */
-public final class DefaultXMSSMTOid implements XMSSOid {
+public final class DefaultXMSSMTOid
+    implements XMSSOid
+{
 
-	/**
-	 * XMSS^MT OID lookup table.
-	 */
-	private static final Map oidLookupTable;
+    /**
+     * XMSS^MT OID lookup table.
+     */
+    private static final Map oidLookupTable;
 
-	static {
-		Map map = new HashMap();
-		map.put(createKey("SHA-256", 32, 16, 67, 20, 2),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-256_W16_H20_D2"));
-		map.put(createKey("SHA-256", 32, 16, 67, 20, 4),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-256_W16_H20_D4"));
-		map.put(createKey("SHA-256", 32, 16, 67, 40, 2),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-256_W16_H40_D2"));
-		map.put(createKey("SHA-256", 32, 16, 67, 40, 2),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-256_W16_H40_D4"));
-		map.put(createKey("SHA-256", 32, 16, 67, 40, 4),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-256_W16_H40_D8"));
-		map.put(createKey("SHA-256", 32, 16, 67, 60, 8),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-256_W16_H60_D3"));
-		map.put(createKey("SHA-256", 32, 16, 67, 60, 6),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-256_W16_H60_D6"));
-		map.put(createKey("SHA-256", 32, 16, 67, 60, 12),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-256_W16_H60_D12"));
-		map.put(createKey("SHA2-512", 64, 16, 131, 20, 2),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-512_W16_H20_D2"));
-		map.put(createKey("SHA2-512", 64, 16, 131, 20, 4),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-512_W16_H20_D4"));
-		map.put(createKey("SHA2-512", 64, 16, 131, 40, 2),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-512_W16_H40_D2"));
-		map.put(createKey("SHA2-512", 64, 16, 131, 40, 4),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-512_W16_H40_D4"));
-		map.put(createKey("SHA2-512", 64, 16, 131, 40, 8),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-512_W16_H40_D8"));
-		map.put(createKey("SHA2-512", 64, 16, 131, 60, 3),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-512_W16_H60_D3"));
-		map.put(createKey("SHA2-512", 64, 16, 131, 60, 6),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-512_W16_H60_D6"));
-		map.put(createKey("SHA2-512", 64, 16, 131, 60, 12),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHA2-512_W16_H60_D12"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 20, 2),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE128_W16_H20_D2"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 20, 4),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE128_W16_H20_D4"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 40, 2),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE128_W16_H40_D2"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 40, 4),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE128_W16_H40_D4"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 40, 8),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE128_W16_H40_D8"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 60, 3),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE128_W16_H60_D3"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 60, 6),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE128_W16_H60_D6"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 60, 12),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE128_W16_H60_D12"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 20, 2),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE256_W16_H20_D2"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 20, 4),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE256_W16_H20_D4"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 40, 2),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE256_W16_H40_D2"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 40, 4),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE256_W16_H40_D4"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 40, 8),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE256_W16_H40_D8"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 60, 3),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE256_W16_H60_D3"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 60, 6),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE256_W16_H60_D6"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 60, 12),
-				new DefaultXMSSMTOid(0x01000001, "XMSSMT_SHAKE256_W16_H60_D12"));
-		oidLookupTable = Collections.unmodifiableMap(map);
-	}
+    static
+    {
+        Map map = new HashMap();
+        map.put(createKey("SHA-256", 32, 16, 67, 20, 2),
+            new DefaultXMSSMTOid(0x00000001, "XMSSMT_SHA2_20/2_256"));
+        map.put(createKey("SHA-256", 32, 16, 67, 20, 4),
+            new DefaultXMSSMTOid(0x00000002, "XMSSMT_SHA2_20/4_256"));
+        map.put(createKey("SHA-256", 32, 16, 67, 40, 2),
+            new DefaultXMSSMTOid(0x00000003, "XMSSMT_SHA2_40/2_256"));
+        map.put(createKey("SHA-256", 32, 16, 67, 40, 2),
+            new DefaultXMSSMTOid(0x00000004, "XMSSMT_SHA2_40/4_256"));
+        map.put(createKey("SHA-256", 32, 16, 67, 40, 4),
+            new DefaultXMSSMTOid(0x00000005, "XMSSMT_SHA2_40/8_256"));
+        map.put(createKey("SHA-256", 32, 16, 67, 60, 8),
+            new DefaultXMSSMTOid(0x00000006, "XMSSMT_SHA2_60/3_256"));
+        map.put(createKey("SHA-256", 32, 16, 67, 60, 6),
+            new DefaultXMSSMTOid(0x00000007, "XMSSMT_SHA2_60/6_256"));
+        map.put(createKey("SHA-256", 32, 16, 67, 60, 12),
+            new DefaultXMSSMTOid(0x00000008, "XMSSMT_SHA2_60/12_256"));
+        map.put(createKey("SHA-512", 64, 16, 131, 20, 2),
+            new DefaultXMSSMTOid(0x00000009, "XMSSMT_SHA2_20/2_512"));
+        map.put(createKey("SHA-512", 64, 16, 131, 20, 4),
+            new DefaultXMSSMTOid(0x0000000a, "XMSSMT_SHA2_20/4_512"));
+        map.put(createKey("SHA-512", 64, 16, 131, 40, 2),
+            new DefaultXMSSMTOid(0x0000000b, "XMSSMT_SHA2_40/2_512"));
+        map.put(createKey("SHA-512", 64, 16, 131, 40, 4),
+            new DefaultXMSSMTOid(0x0000000c, "XMSSMT_SHA2_40/4_512"));
+        map.put(createKey("SHA-512", 64, 16, 131, 40, 8),
+            new DefaultXMSSMTOid(0x0000000d, "XMSSMT_SHA2_40/8_512"));
+        map.put(createKey("SHA-512", 64, 16, 131, 60, 3),
+            new DefaultXMSSMTOid(0x0000000e, "XMSSMT_SHA2_60/3_512"));
+        map.put(createKey("SHA-512", 64, 16, 131, 60, 6),
+            new DefaultXMSSMTOid(0x0000000f, "XMSSMT_SHA2_60/6_512"));
+        map.put(createKey("SHA-512", 64, 16, 131, 60, 12),
+            new DefaultXMSSMTOid(0x00000010, "XMSSMT_SHA2_60/12_512"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 20, 2),
+            new DefaultXMSSMTOid(0x00000011, "XMSSMT_SHAKE_20/2_256"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 20, 4),
+            new DefaultXMSSMTOid(0x00000012, "XMSSMT_SHAKE_20/4_256"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 40, 2),
+            new DefaultXMSSMTOid(0x00000013, "XMSSMT_SHAKE_40/2_256"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 40, 4),
+            new DefaultXMSSMTOid(0x00000014, "XMSSMT_SHAKE_40/4_256"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 40, 8),
+            new DefaultXMSSMTOid(0x00000015, "XMSSMT_SHAKE_40/8_256"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 60, 3),
+            new DefaultXMSSMTOid(0x00000016, "XMSSMT_SHAKE_60/3_256"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 60, 6),
+            new DefaultXMSSMTOid(0x00000017, "XMSSMT_SHAKE_60/6_256"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 60, 12),
+            new DefaultXMSSMTOid(0x00000018, "XMSSMT_SHAKE_60/12_256"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 20, 2),
+            new DefaultXMSSMTOid(0x00000019, "XMSSMT_SHAKE_20/2_512"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 20, 4),
+            new DefaultXMSSMTOid(0x0000001a, "XMSSMT_SHAKE_20/4_512"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 40, 2),
+            new DefaultXMSSMTOid(0x0000001b, "XMSSMT_SHAKE_40/2_512"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 40, 4),
+            new DefaultXMSSMTOid(0x0000001c, "XMSSMT_SHAKE_40/4_512"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 40, 8),
+            new DefaultXMSSMTOid(0x0000001d, "XMSSMT_SHAKE_40/8_512"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 60, 3),
+            new DefaultXMSSMTOid(0x0000001e, "XMSSMT_SHAKE_60/3_512"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 60, 6),
+            new DefaultXMSSMTOid(0x0000001f, "XMSSMT_SHAKE_60/6_512"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 60, 12),
+            new DefaultXMSSMTOid(0x00000020, "XMSSMT_SHAKE_60/12_512"));
+        oidLookupTable = Collections.unmodifiableMap(map);
+    }
 
-	/**
-	 * OID.
-	 */
-	private final int oid;
-	/**
-	 * String representation of OID.
-	 */
-	private final String stringRepresentation;
+    /**
+     * OID.
+     */
+    private final int oid;
+    /**
+     * String representation of OID.
+     */
+    private final String stringRepresentation;
 
-	/**
-	 * Constructor...
-	 *
-	 * @param oid
-	 *            OID.
-	 * @param stringRepresentation
-	 *            String representation of OID.
-	 */
-	private DefaultXMSSMTOid(int oid, String stringRepresentation) {
-		super();
-		this.oid = oid;
-		this.stringRepresentation = stringRepresentation;
-	}
+    /**
+     * Constructor...
+     *
+     * @param oid                  OID.
+     * @param stringRepresentation String representation of OID.
+     */
+    private DefaultXMSSMTOid(int oid, String stringRepresentation)
+    {
+        super();
+        this.oid = oid;
+        this.stringRepresentation = stringRepresentation;
+    }
 
-	/**
-	 * Lookup OID.
-	 *
-	 * @param algorithmName
-	 *            Algorithm name.
-	 * @param winternitzParameter
-	 *            Winternitz parameter.
-	 * @param height
-	 *            Binary tree height.
-	 * @return XMSS OID if parameters were found, null else.
-	 */
-	public static DefaultXMSSMTOid lookup(String algorithmName, int digestSize, int winternitzParameter, int len,
-			int height, int layers) {
-		if (algorithmName == null) {
-			throw new NullPointerException("algorithmName == null");
-		}
-		return oidLookupTable.get(createKey(algorithmName, digestSize, winternitzParameter, len, height, layers));
-	}
+    /**
+     * Lookup OID.
+     *
+     * @param algorithmName       Algorithm name.
+     * @param winternitzParameter Winternitz parameter.
+     * @param height              Binary tree height.
+     * @return XMSS OID if parameters were found, null else.
+     */
+    public static DefaultXMSSMTOid lookup(String algorithmName, int digestSize, int winternitzParameter, int len,
+                                          int height, int layers)
+    {
+        if (algorithmName == null)
+        {
+            throw new NullPointerException("algorithmName == null");
+        }
+        return oidLookupTable.get(createKey(algorithmName, digestSize, winternitzParameter, len, height, layers));
+    }
 
-	/**
-	 * Create a key based on parameters.
-	 *
-	 * @param algorithmName
-	 *            Algorithm name.
-	 * @param winternitzParameter
-	 *            Winternitz Parameter.
-	 * @param height
-	 *            Binary tree height.
-	 * @return String representation of parameters for lookup table.
-	 */
-	private static String createKey(String algorithmName, int digestSize, int winternitzParameter, int len, int height,
-			int layers) {
-		if (algorithmName == null) {
-			throw new NullPointerException("algorithmName == null");
-		}
-		return algorithmName + "-" + digestSize + "-" + winternitzParameter + "-" + len + "-" + height + "-" + layers;
-	}
+    /**
+     * Create a key based on parameters.
+     *
+     * @param algorithmName       Algorithm name.
+     * @param winternitzParameter Winternitz Parameter.
+     * @param height              Binary tree height.
+     * @return String representation of parameters for lookup table.
+     */
+    private static String createKey(String algorithmName, int digestSize, int winternitzParameter, int len, int height,
+                                    int layers)
+    {
+        if (algorithmName == null)
+        {
+            throw new NullPointerException("algorithmName == null");
+        }
+        
+        return algorithmName + "-" + digestSize + "-" + winternitzParameter + "-" + len + "-" + height + "-" + layers;
+    }
 
-	/**
-	 * Getter OID.
-	 *
-	 * @return OID.
-	 */
-	public int getOid() {
-		return oid;
-	}
+    /**
+     * Getter OID.
+     *
+     * @return OID.
+     */
+    public int getOid()
+    {
+        return oid;
+    }
 
-	public String toString() {
-		return stringRepresentation;
-	}
+    public String toString()
+    {
+        return stringRepresentation;
+    }
 }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DefaultXMSSOid.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DefaultXMSSOid.java
index a7f4b850b..09a010877 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DefaultXMSSOid.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DefaultXMSSOid.java
@@ -6,104 +6,105 @@ import java.util.Map;
 
 /**
  * XMSSOid class.
- *
  */
-public final class DefaultXMSSOid implements XMSSOid {
+public final class DefaultXMSSOid
+    implements XMSSOid
+{
 
-	/**
-	 * XMSS OID lookup table.
-	 */
-	private static final Map oidLookupTable;
+    /**
+     * XMSS OID lookup table.
+     */
+    private static final Map oidLookupTable;
 
-	static {
-		Map map = new HashMap();
-		map.put(createKey("SHA-256", 32, 16, 67, 10), new DefaultXMSSOid(0x01000001, "XMSS_SHA2-256_W16_H10"));
-		map.put(createKey("SHA-256", 32, 16, 67, 16), new DefaultXMSSOid(0x02000002, "XMSS_SHA2-256_W16_H16"));
-		map.put(createKey("SHA-256", 32, 16, 67, 20), new DefaultXMSSOid(0x03000003, "XMSS_SHA2-256_W16_H20"));
-		map.put(createKey("SHA-512", 64, 16, 131, 10), new DefaultXMSSOid(0x04000004, "XMSS_SHA2-512_W16_H10"));
-		map.put(createKey("SHA-512", 64, 16, 131, 16), new DefaultXMSSOid(0x05000005, "XMSS_SHA2-512_W16_H16"));
-		map.put(createKey("SHA-512", 64, 16, 131, 20), new DefaultXMSSOid(0x06000006, "XMSS_SHA2-512_W16_H20"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 10), new DefaultXMSSOid(0x07000007, "XMSS_SHAKE128_W16_H10"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 16), new DefaultXMSSOid(0x08000008, "XMSS_SHAKE128_W16_H16"));
-		map.put(createKey("SHAKE128", 32, 16, 67, 20), new DefaultXMSSOid(0x09000009, "XMSS_SHAKE128_W16_H20"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 10), new DefaultXMSSOid(0x0a00000a, "XMSS_SHAKE256_W16_H10"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 16), new DefaultXMSSOid(0x0b00000b, "XMSS_SHAKE256_W16_H16"));
-		map.put(createKey("SHAKE256", 64, 16, 131, 20), new DefaultXMSSOid(0x0c00000c, "XMSS_SHAKE256_W16_H20"));
-		oidLookupTable = Collections.unmodifiableMap(map);
-	}
+    static
+    {
+        Map map = new HashMap();
+        map.put(createKey("SHA-256", 32, 16, 67, 10), new DefaultXMSSOid(0x00000001, "XMSS_SHA2_10_256"));
+        map.put(createKey("SHA-256", 32, 16, 67, 16), new DefaultXMSSOid(0x00000002, "XMSS_SHA2_16_256"));
+        map.put(createKey("SHA-256", 32, 16, 67, 20), new DefaultXMSSOid(0x00000003, "XMSS_SHA2_20_256"));
+        map.put(createKey("SHA-512", 64, 16, 131, 10), new DefaultXMSSOid(0x00000004, "XMSS_SHA2_10_512"));
+        map.put(createKey("SHA-512", 64, 16, 131, 16), new DefaultXMSSOid(0x00000005, "XMSS_SHA2_16_512"));
+        map.put(createKey("SHA-512", 64, 16, 131, 20), new DefaultXMSSOid(0x00000006, "XMSS_SHA2_20_512"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 10), new DefaultXMSSOid(0x00000007, "XMSS_SHAKE_10_256"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 16), new DefaultXMSSOid(0x00000008, "XMSS_SHAKE_16_256"));
+        map.put(createKey("SHAKE128", 32, 16, 67, 20), new DefaultXMSSOid(0x00000009, "XMSS_SHAKE_20_256"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 10), new DefaultXMSSOid(0x0000000a, "XMSS_SHAKE_10_512"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 16), new DefaultXMSSOid(0x0000000b, "XMSS_SHAKE_16_512"));
+        map.put(createKey("SHAKE256", 64, 16, 131, 20), new DefaultXMSSOid(0x0000000c, "XMSS_SHAKE_20_512"));
+        oidLookupTable = Collections.unmodifiableMap(map);
+    }
 
-	/**
-	 * OID.
-	 */
-	private final int oid;
-	/**
-	 * String representation of OID.
-	 */
-	private final String stringRepresentation;
+    /**
+     * OID.
+     */
+    private final int oid;
+    /**
+     * String representation of OID.
+     */
+    private final String stringRepresentation;
 
-	/**
-	 * Constructor...
-	 *
-	 * @param oid
-	 *            OID.
-	 * @param stringRepresentation
-	 *            String representation of OID.
-	 */
-	private DefaultXMSSOid(int oid, String stringRepresentation) {
-		super();
-		this.oid = oid;
-		this.stringRepresentation = stringRepresentation;
-	}
+    /**
+     * Constructor...
+     *
+     * @param oid                  OID.
+     * @param stringRepresentation String representation of OID.
+     */
+    private DefaultXMSSOid(int oid, String stringRepresentation)
+    {
+        super();
+        this.oid = oid;
+        this.stringRepresentation = stringRepresentation;
+    }
 
-	/**
-	 * Lookup OID.
-	 *
-	 * @param algorithmName
-	 *            Algorithm name.
-	 * @param winternitzParameter
-	 *            Winternitz parameter.
-	 * @param height
-	 *            Binary tree height.
-	 * @return XMSS OID if parameters were found, null else.
-	 */
-	public static DefaultXMSSOid lookup(String algorithmName, int digestSize, int winternitzParameter, int len,
-			int height) {
-		if (algorithmName == null) {
-			throw new NullPointerException("algorithmName == null");
-		}
-		return oidLookupTable.get(createKey(algorithmName, digestSize, winternitzParameter, len, height));
-	}
+    /**
+     * Lookup OID.
+     *
+     * @param algorithmName       Algorithm name.
+     * @param winternitzParameter Winternitz parameter.
+     * @param height              Binary tree height.
+     * @return XMSS OID if parameters were found, null else.
+     */
+    public static DefaultXMSSOid lookup(String algorithmName, int digestSize, int winternitzParameter, int len,
+                                        int height)
+    {
+        if (algorithmName == null)
+        {
+            throw new NullPointerException("algorithmName == null");
+        }
+        return oidLookupTable.get(createKey(algorithmName, digestSize, winternitzParameter, len, height));
+    }
 
-	/**
-	 * Create a key based on parameters.
-	 *
-	 * @param algorithmName
-	 *            Algorithm name.
-	 * @param winternitzParameter
-	 *            Winternitz Parameter.
-	 * @param height
-	 *            Binary tree height.
-	 * @return String representation of parameters for lookup table.
-	 */
-	private static String createKey(String algorithmName, int digestSize, int winternitzParameter, int len,
-			int height) {
-		if (algorithmName == null) {
-			throw new NullPointerException("algorithmName == null");
-		}
-		return algorithmName + "-" + digestSize + "-" + winternitzParameter + "-" + len + "-" + height;
-	}
+    /**
+     * Create a key based on parameters.
+     *
+     * @param algorithmName       Algorithm name.
+     * @param winternitzParameter Winternitz Parameter.
+     * @param height              Binary tree height.
+     * @return String representation of parameters for lookup table.
+     */
+    private static String createKey(String algorithmName, int digestSize, int winternitzParameter, int len,
+                                    int height)
+    {
+        if (algorithmName == null)
+        {
+            throw new NullPointerException("algorithmName == null");
+        }
+        return algorithmName + "-" + digestSize + "-" + winternitzParameter + "-" + len + "-" + height;
+    }
 
-	/**
-	 * Getter OID.
-	 *
-	 * @return OID.
-	 */
-	public int getOid() {
-		return oid;
-	}
+    /**
+     * Getter OID.
+     *
+     * @return OID.
+     */
+    public int getOid()
+    {
+        return oid;
+    }
 
-	@Override
-	public String toString() {
-		return stringRepresentation;
-	}
+    @Override
+    public String toString()
+    {
+        return stringRepresentation;
+    }
 }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DigestUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DigestUtil.java
new file mode 100644
index 000000000..4e4a7f2ca
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/DigestUtil.java
@@ -0,0 +1,68 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.xmss;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
+import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
+import com.fr.third.org.bouncycastle.crypto.Digest;
+import com.fr.third.org.bouncycastle.crypto.Xof;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest;
+import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest;
+
+class DigestUtil
+{
+    private static Map nameToOid = new HashMap();
+
+    static
+    {
+        nameToOid.put("SHA-256", NISTObjectIdentifiers.id_sha256);
+        nameToOid.put("SHA-512", NISTObjectIdentifiers.id_sha512);
+        nameToOid.put("SHAKE128", NISTObjectIdentifiers.id_shake128);
+        nameToOid.put("SHAKE256", NISTObjectIdentifiers.id_shake256);
+    }
+
+    static Digest getDigest(ASN1ObjectIdentifier oid)
+    {
+        if (oid.equals(NISTObjectIdentifiers.id_sha256))
+        {
+            return new SHA256Digest();
+        }
+        if (oid.equals(NISTObjectIdentifiers.id_sha512))
+        {
+            return new SHA512Digest();
+        }
+        if (oid.equals(NISTObjectIdentifiers.id_shake128))
+        {
+            return new SHAKEDigest(128);
+        }
+        if (oid.equals(NISTObjectIdentifiers.id_shake256))
+        {
+            return new SHAKEDigest(256);
+        }
+
+        throw new IllegalArgumentException("unrecognized digest OID: " + oid);
+    }
+
+    static ASN1ObjectIdentifier getDigestOID(String name)
+    {
+        ASN1ObjectIdentifier oid = nameToOid.get(name);
+        if (oid != null)
+        {
+            return oid;
+        }
+
+        throw new IllegalArgumentException("unrecognized digest name: " + name);
+    }
+
+    public static int getDigestSize(Digest digest)
+    {
+        if (digest instanceof Xof)
+        {
+            return digest.getDigestSize() * 2;
+        }
+
+        return digest.getDigestSize();
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/KeyedHashFunctions.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/KeyedHashFunctions.java
index 1a8dc63ee..868dd64c1 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/KeyedHashFunctions.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/KeyedHashFunctions.java
@@ -1,5 +1,6 @@
 package com.fr.third.org.bouncycastle.pqc.crypto.xmss;
 
+import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import com.fr.third.org.bouncycastle.crypto.Digest;
 import com.fr.third.org.bouncycastle.crypto.Xof;
 
@@ -8,18 +9,17 @@ import com.fr.third.org.bouncycastle.crypto.Xof;
  */
 final class KeyedHashFunctions
 {
-
     private final Digest digest;
     private final int digestSize;
 
-    protected KeyedHashFunctions(Digest digest, int digestSize)
+    protected KeyedHashFunctions(ASN1ObjectIdentifier treeDigest, int digestSize)
     {
         super();
-        if (digest == null)
+        if (treeDigest == null)
         {
             throw new NullPointerException("digest == null");
         }
-        this.digest = digest;
+        this.digest = DigestUtil.getDigest(treeDigest);
         this.digestSize = digestSize;
     }
 
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlus.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlus.java
index d2521ac4e..6684bbedc 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlus.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlus.java
@@ -3,6 +3,8 @@ package com.fr.third.org.bouncycastle.pqc.crypto.xmss;
 import java.util.ArrayList;
 import java.util.List;
 
+import com.fr.third.org.bouncycastle.util.Arrays;
+
 /**
  * WOTS+.
  */
@@ -40,8 +42,8 @@ final class WOTSPlus
             throw new NullPointerException("params == null");
         }
         this.params = params;
-        int n = params.getDigestSize();
-        khf = new KeyedHashFunctions(params.getDigest(), n);
+        int n = params.getTreeDigestSize();
+        khf = new KeyedHashFunctions(params.getTreeDigest(), n);
         secretKeySeed = new byte[n];
         publicSeed = new byte[n];
     }
@@ -58,7 +60,7 @@ final class WOTSPlus
         {
             throw new NullPointerException("secretKeySeed == null");
         }
-        if (secretKeySeed.length != params.getDigestSize())
+        if (secretKeySeed.length != params.getTreeDigestSize())
         {
             throw new IllegalArgumentException("size of secretKeySeed needs to be equal to size of digest");
         }
@@ -66,7 +68,7 @@ final class WOTSPlus
         {
             throw new NullPointerException("publicSeed == null");
         }
-        if (publicSeed.length != params.getDigestSize())
+        if (publicSeed.length != params.getTreeDigestSize())
         {
             throw new IllegalArgumentException("size of publicSeed needs to be equal to size of digest");
         }
@@ -87,7 +89,7 @@ final class WOTSPlus
         {
             throw new NullPointerException("messageDigest == null");
         }
-        if (messageDigest.length != params.getDigestSize())
+        if (messageDigest.length != params.getTreeDigestSize())
         {
             throw new IllegalArgumentException("size of messageDigest needs to be equal to size of digest");
         }
@@ -140,7 +142,7 @@ final class WOTSPlus
         {
             throw new NullPointerException("messageDigest == null");
         }
-        if (messageDigest.length != params.getDigestSize())
+        if (messageDigest.length != params.getTreeDigestSize())
         {
             throw new IllegalArgumentException("size of messageDigest needs to be equal to size of digest");
         }
@@ -172,7 +174,7 @@ final class WOTSPlus
         {
             throw new NullPointerException("messageDigest == null");
         }
-        if (messageDigest.length != params.getDigestSize())
+        if (messageDigest.length != params.getTreeDigestSize())
         {
             throw new IllegalArgumentException("size of messageDigest needs to be equal to size of digest");
         }
@@ -226,7 +228,7 @@ final class WOTSPlus
      */
     private byte[] chain(byte[] startHash, int startIndex, int steps, OTSHashAddress otsHashAddress)
     {
-        int n = params.getDigestSize();
+        int n = params.getTreeDigestSize();
         if (startHash == null)
         {
             throw new NullPointerException("startHash == null");
@@ -369,7 +371,7 @@ final class WOTSPlus
      */
     protected byte[] getSecretKeySeed()
     {
-        return XMSSUtil.cloneArray(getSecretKeySeed());
+        return Arrays.clone(secretKeySeed);
     }
 
     /**
@@ -379,7 +381,7 @@ final class WOTSPlus
      */
     protected byte[] getPublicSeed()
     {
-        return XMSSUtil.cloneArray(publicSeed);
+        return Arrays.clone(publicSeed);
     }
 
     /**
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusParameters.java
index 97c89af73..fac60b4f1 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusParameters.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusParameters.java
@@ -1,5 +1,6 @@
 package com.fr.third.org.bouncycastle.pqc.crypto.xmss;
 
+import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier;
 import com.fr.third.org.bouncycastle.crypto.Digest;
 
 /**
@@ -12,10 +13,7 @@ final class WOTSPlusParameters
      * OID.
      */
     private final XMSSOid oid;
-    /**
-     * Digest used in WOTS+.
-     */
-    private final Digest digest;
+
     /**
      * The message digest size.
      */
@@ -37,25 +35,26 @@ final class WOTSPlusParameters
      * len2.
      */
     private final int len2;
+    private final ASN1ObjectIdentifier treeDigest;
 
     /**
      * Constructor...
      *
-     * @param digest The digest used for WOTS+.
+     * @param treeDigest The digest used for WOTS+.
      */
-    protected WOTSPlusParameters(Digest digest)
+    protected WOTSPlusParameters(ASN1ObjectIdentifier treeDigest)
     {
         super();
-        if (digest == null)
+        if (treeDigest == null)
         {
-            throw new NullPointerException("digest == null");
+            throw new NullPointerException("treeDigest == null");
         }
-        this.digest = digest;
+        this.treeDigest = treeDigest;
+        Digest digest = DigestUtil.getDigest(treeDigest);
         digestSize = XMSSUtil.getDigestSize(digest);
         winternitzParameter = 16;
         len1 = (int)Math.ceil((double)(8 * digestSize) / XMSSUtil.log2(winternitzParameter));
-        len2 = (int)Math.floor(XMSSUtil.log2(len1 * (winternitzParameter - 1)) / XMSSUtil.log2(winternitzParameter))
-            + 1;
+        len2 = (int)Math.floor(XMSSUtil.log2(len1 * (winternitzParameter - 1)) / XMSSUtil.log2(winternitzParameter)) + 1;
         len = len1 + len2;
         oid = WOTSPlusOid.lookup(digest.getAlgorithmName(), digestSize, winternitzParameter, len);
         if (oid == null)
@@ -73,23 +72,13 @@ final class WOTSPlusParameters
     {
         return oid;
     }
-
-    /**
-     * Getter digest.
-     *
-     * @return digest.
-     */
-    protected Digest getDigest()
-    {
-        return digest;
-    }
-
+    
     /**
      * Getter digestSize.
      *
      * @return digestSize.
      */
-    protected int getDigestSize()
+    protected int getTreeDigestSize()
     {
         return digestSize;
     }
@@ -133,4 +122,9 @@ final class WOTSPlusParameters
     {
         return len2;
     }
+
+    public ASN1ObjectIdentifier getTreeDigest()
+    {
+        return treeDigest;
+    }
 }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusPrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusPrivateKeyParameters.java
index 36a667617..d104d47af 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusPrivateKeyParameters.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusPrivateKeyParameters.java
@@ -29,7 +29,7 @@ final class WOTSPlusPrivateKeyParameters
         }
         for (int i = 0; i < privateKey.length; i++)
         {
-            if (privateKey[i].length != params.getDigestSize())
+            if (privateKey[i].length != params.getTreeDigestSize())
             {
                 throw new IllegalArgumentException("wrong privateKey format");
             }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusPublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusPublicKeyParameters.java
index c5edb1d4e..3ae97133a 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusPublicKeyParameters.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusPublicKeyParameters.java
@@ -29,7 +29,7 @@ final class WOTSPlusPublicKeyParameters
         }
         for (int i = 0; i < publicKey.length; i++)
         {
-            if (publicKey[i].length != params.getDigestSize())
+            if (publicKey[i].length != params.getTreeDigestSize())
             {
                 throw new IllegalArgumentException("wrong publicKey format");
             }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusSignature.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusSignature.java
index 5cbe4b5a4..e15177f08 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusSignature.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/WOTSPlusSignature.java
@@ -29,7 +29,7 @@ final class WOTSPlusSignature
         }
         for (int i = 0; i < signature.length; i++)
         {
-            if (signature[i].length != params.getDigestSize())
+            if (signature[i].length != params.getTreeDigestSize())
             {
                 throw new IllegalArgumentException("wrong signature format");
             }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSS.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSS.java
index 5b77db81b..c916192eb 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSS.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSS.java
@@ -109,10 +109,10 @@ public class XMSS
         privateKey = (XMSSPrivateKeyParameters)kp.getPrivate();
         publicKey = (XMSSPublicKeyParameters)kp.getPublic();
 
-        wotsPlus.importKeys(new byte[params.getDigestSize()], this.privateKey.getPublicSeed());
+        wotsPlus.importKeys(new byte[params.getTreeDigestSize()], this.privateKey.getPublicSeed());
     }
 
-    void importState(XMSSPrivateKeyParameters privateKey, XMSSPublicKeyParameters publicKey)
+    public void importState(XMSSPrivateKeyParameters privateKey, XMSSPublicKeyParameters publicKey)
     {
         if (!Arrays.areEqual(privateKey.getRoot(), publicKey.getRoot()))
         {
@@ -126,7 +126,7 @@ public class XMSS
         this.privateKey = privateKey;
         this.publicKey = publicKey;
 
-        wotsPlus.importKeys(new byte[params.getDigestSize()], this.privateKey.getPublicSeed());
+        wotsPlus.importKeys(new byte[params.getTreeDigestSize()], this.privateKey.getPublicSeed());
     }
 
     /**
@@ -147,7 +147,7 @@ public class XMSS
         }
         /* import keys */
         XMSSPrivateKeyParameters tmpPrivateKey = new XMSSPrivateKeyParameters.Builder(params)
-            .withPrivateKey(privateKey, this.getParams()).build();
+            .withPrivateKey(privateKey).build();
         XMSSPublicKeyParameters tmpPublicKey = new XMSSPublicKeyParameters.Builder(params).withPublicKey(publicKey)
             .build();
         if (!Arrays.areEqual(tmpPrivateKey.getRoot(), tmpPublicKey.getRoot()))
@@ -161,7 +161,7 @@ public class XMSS
 		/* import */
         this.privateKey = tmpPrivateKey;
         this.publicKey = tmpPublicKey;
-        wotsPlus.importKeys(new byte[params.getDigestSize()], this.privateKey.getPublicSeed());
+        wotsPlus.importKeys(new byte[params.getTreeDigestSize()], this.privateKey.getPublicSeed());
     }
 
     /**
@@ -226,9 +226,9 @@ public class XMSS
      *
      * @return XMSS private key.
      */
-    public byte[] exportPrivateKey()
+    public XMSSPrivateKeyParameters exportPrivateKey()
     {
-        return privateKey.toByteArray();
+        return privateKey;
     }
 
     /**
@@ -236,9 +236,9 @@ public class XMSS
      *
      * @return XMSS public key.
      */
-    public byte[] exportPublicKey()
+    public XMSSPublicKeyParameters exportPublicKey()
     {
-        return publicKey.toByteArray();
+        return publicKey;
     }
 
     /**
@@ -251,7 +251,7 @@ public class XMSS
      */
     protected WOTSPlusSignature wotsSign(byte[] messageDigest, OTSHashAddress otsHashAddress)
     {
-        if (messageDigest.length != params.getDigestSize())
+        if (messageDigest.length != params.getTreeDigestSize())
         {
             throw new IllegalArgumentException("size of messageDigest needs to be equal to size of digest");
         }
@@ -340,7 +340,7 @@ public class XMSS
         publicKey = new XMSSPublicKeyParameters.Builder(params).withRoot(getRoot()).withPublicSeed(publicSeed)
             .build();
 
-        wotsPlus.importKeys(new byte[params.getDigestSize()], publicSeed);
+        wotsPlus.importKeys(new byte[params.getTreeDigestSize()], publicSeed);
     }
 
     public XMSSPrivateKeyParameters getPrivateKey()
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSKeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSKeyPairGenerator.java
index 1d3ef41b3..555a4b785 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSKeyPairGenerator.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSKeyPairGenerator.java
@@ -56,7 +56,7 @@ public final class XMSSKeyPairGenerator
      */
     private XMSSPrivateKeyParameters generatePrivateKey(XMSSParameters params, SecureRandom prng)
     {
-        int n = params.getDigestSize();
+        int n = params.getTreeDigestSize();
         byte[] secretKeySeed = new byte[n];
         prng.nextBytes(secretKeySeed);
         byte[] secretKeyPRF = new byte[n];
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSKeyParameters.java
new file mode 100644
index 000000000..c1322cb57
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSKeyParameters.java
@@ -0,0 +1,25 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.xmss;
+
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+
+public class XMSSKeyParameters
+    extends AsymmetricKeyParameter
+{
+    public static final String SHA_256 = "SHA-256";
+    public static final String SHA_512 = "SHA-512";
+    public static final String SHAKE128 = "SHAKE128";
+    public static final String SHAKE256 = "SHAKE256";
+
+    private final String treeDigest;
+
+    public XMSSKeyParameters(boolean isPrivateKey, String treeDigest)
+    {
+        super(isPrivateKey);
+        this.treeDigest = treeDigest;
+    }
+
+    public String getTreeDigest()
+    {
+        return treeDigest;
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMT.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMT.java
index b3569260b..797dfc3f8 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMT.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMT.java
@@ -58,7 +58,7 @@ public final class XMSSMT
     private void importState(XMSSMTPrivateKeyParameters privateKey, XMSSMTPublicKeyParameters publicKey)
     {
 		/* import to xmss */
-        xmssParams.getWOTSPlus().importKeys(new byte[params.getDigestSize()], this.privateKey.getPublicSeed());
+        xmssParams.getWOTSPlus().importKeys(new byte[params.getTreeDigestSize()], this.privateKey.getPublicSeed());
 
         this.privateKey = privateKey;
         this.publicKey = publicKey;
@@ -81,7 +81,7 @@ public final class XMSSMT
             throw new NullPointerException("publicKey == null");
         }
         XMSSMTPrivateKeyParameters xmssMTPrivateKey = new XMSSMTPrivateKeyParameters.Builder(params)
-            .withPrivateKey(privateKey, xmssParams).build();
+            .withPrivateKey(privateKey).build();
         XMSSMTPublicKeyParameters xmssMTPublicKey = new XMSSMTPublicKeyParameters.Builder(params)
             .withPublicKey(publicKey).build();
         if (!Arrays.areEqual(xmssMTPrivateKey.getRoot(), xmssMTPublicKey.getRoot()))
@@ -94,7 +94,7 @@ public final class XMSSMT
         }
         
 		/* import to xmss */
-        xmssParams.getWOTSPlus().importKeys(new byte[params.getDigestSize()], xmssMTPrivateKey.getPublicSeed());
+        xmssParams.getWOTSPlus().importKeys(new byte[params.getTreeDigestSize()], xmssMTPrivateKey.getPublicSeed());
 
         this.privateKey = xmssMTPrivateKey;
         this.publicKey = xmssMTPublicKey;
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTKeyPairGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTKeyPairGenerator.java
index ef0641438..80c200db6 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTKeyPairGenerator.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTKeyPairGenerator.java
@@ -45,7 +45,7 @@ public final class XMSSMTKeyPairGenerator
         privateKey = generatePrivateKey(new XMSSMTPrivateKeyParameters.Builder(params).build().getBDSState());
 
             /* import to xmss */
-        xmssParams.getWOTSPlus().importKeys(new byte[params.getDigestSize()], privateKey.getPublicSeed());
+        xmssParams.getWOTSPlus().importKeys(new byte[params.getTreeDigestSize()], privateKey.getPublicSeed());
 
             /* get root */
         int rootLayerIndex = params.getLayers() - 1;
@@ -69,7 +69,7 @@ public final class XMSSMTKeyPairGenerator
 
     private XMSSMTPrivateKeyParameters generatePrivateKey(BDSStateMap bdsState)
     {
-        int n = params.getDigestSize();
+        int n = params.getTreeDigestSize();
         byte[] secretKeySeed = new byte[n];
         prng.nextBytes(secretKeySeed);
         byte[] secretKeyPRF = new byte[n];
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTKeyParameters.java
new file mode 100644
index 000000000..f92dc8b8e
--- /dev/null
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTKeyParameters.java
@@ -0,0 +1,20 @@
+package com.fr.third.org.bouncycastle.pqc.crypto.xmss;
+
+import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
+
+public class XMSSMTKeyParameters
+    extends AsymmetricKeyParameter
+{
+    private final String treeDigest;
+
+    public XMSSMTKeyParameters(boolean isPrivateKey, String treeDigest)
+    {
+        super(isPrivateKey);
+        this.treeDigest = treeDigest;
+    }
+
+    public String getTreeDigest()
+    {
+        return treeDigest;
+    }
+}
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTParameters.java
index 7d62d5d03..0531616d4 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTParameters.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTParameters.java
@@ -7,7 +7,6 @@ import com.fr.third.org.bouncycastle.crypto.Digest;
  */
 public final class XMSSMTParameters
 {
-
     private final XMSSOid oid;
     private final XMSSParameters xmssParams;
     private final int height;
@@ -26,7 +25,7 @@ public final class XMSSMTParameters
         this.height = height;
         this.layers = layers;
         this.xmssParams = new XMSSParameters(xmssTreeHeight(height, layers), digest);
-        oid = DefaultXMSSMTOid.lookup(getDigest().getAlgorithmName(), getDigestSize(), getWinternitzParameter(),
+        oid = DefaultXMSSMTOid.lookup(getTreeDigest(), getTreeDigestSize(), getWinternitzParameter(),
             getLen(), getHeight(), layers);
         /*
 		 * if (oid == null) { throw new InvalidParameterException(); }
@@ -81,9 +80,9 @@ public final class XMSSMTParameters
         return xmssParams.getWOTSPlus();
     }
 
-    protected Digest getDigest()
+    protected String getTreeDigest()
     {
-        return xmssParams.getDigest();
+        return xmssParams.getTreeDigest();
     }
 
     /**
@@ -91,9 +90,9 @@ public final class XMSSMTParameters
      *
      * @return Digest size.
      */
-    public int getDigestSize()
+    public int getTreeDigestSize()
     {
-        return xmssParams.getDigestSize();
+        return xmssParams.getTreeDigestSize();
     }
 
     /**
@@ -101,13 +100,18 @@ public final class XMSSMTParameters
      *
      * @return Winternitz parameter.
      */
-    public int getWinternitzParameter()
+    int getWinternitzParameter()
     {
         return xmssParams.getWinternitzParameter();
     }
 
     protected int getLen()
     {
-        return xmssParams.getWOTSPlus().getParams().getLen();
+        return xmssParams.getLen();
+    }
+
+    protected XMSSOid getOid()
+    {
+        return oid;
     }
 }
diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTPrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTPrivateKeyParameters.java
index 4075ae2eb..4b38bf839 100644
--- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTPrivateKeyParameters.java
+++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTPrivateKeyParameters.java
@@ -2,34 +2,36 @@ package com.fr.third.org.bouncycastle.pqc.crypto.xmss;
 
 import java.io.IOException;
 
-import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter;
 import com.fr.third.org.bouncycastle.util.Arrays;
+import com.fr.third.org.bouncycastle.util.Encodable;
 
 /**
  * XMSS^MT Private Key.
  */
 public final class XMSSMTPrivateKeyParameters
-    extends AsymmetricKeyParameter
-    implements XMSSStoreableObjectInterface
+    extends XMSSMTKeyParameters
+    implements XMSSStoreableObjectInterface, Encodable
 {
-
     private final XMSSMTParameters params;
-    private final long index;
     private final byte[] secretKeySeed;
     private final byte[] secretKeyPRF;
     private final byte[] publicSeed;
     private final byte[] root;
-    private final BDSStateMap bdsState;
+
+    private volatile long index;
+    private volatile BDSStateMap bdsState;
+    private volatile boolean used;
 
     private XMSSMTPrivateKeyParameters(Builder builder)
     {
-        super(true);
+        super(true, builder.params.getTreeDigest());
         params = builder.params;
+
         if (params == null)
         {
             throw new NullPointerException("params == null");
         }
-        int n = params.getDigestSize();
+        int n = params.getTreeDigestSize();
         byte[] privateKey = builder.privateKey;
         if (privateKey != null)
         {
@@ -72,8 +74,7 @@ public final class XMSSMTPrivateKeyParameters
             {
                 BDSStateMap bdsImport = (BDSStateMap)XMSSUtil.deserialize(bdsStateBinary, BDSStateMap.class);
 
-                bdsImport.setXMSS(builder.xmss);
-                bdsState = bdsImport;
+                bdsState = bdsImport.withWOTSDigest(builder.xmss.getTreeDigestOID());
             }
             catch (IOException e)
             {
@@ -86,7 +87,7 @@ public final class XMSSMTPrivateKeyParameters
         }
         else
         {
-			/* set */
+            /* set */
             index = builder.index;
             byte[] tmpSecretKeySeed = builder.secretKeySeed;
             if (tmpSecretKeySeed != null)
@@ -156,19 +157,32 @@ public final class XMSSMTPrivateKeyParameters
                 }
                 else
                 {
-                    bdsState = new BDSStateMap();
+                    bdsState = new BDSStateMap(builder.maxIndex + 1);
                 }
             }
+            if (builder.maxIndex >= 0 && builder.maxIndex != bdsState.getMaxIndex())
+            {
+                throw new IllegalArgumentException("maxIndex set but not reflected in state");
+            }
         }
     }
 
-    public static class Builder
+    public byte[] getEncoded()
+        throws IOException
     {
+        synchronized (this)
+        {
+            return toByteArray();
+        }
+    }
 
+    public static class Builder
+    {
         /* mandatory */
         private final XMSSMTParameters params;
         /* optional */
         private long index = 0L;
+        private long maxIndex = -1L;
         private byte[] secretKeySeed = null;
         private byte[] secretKeyPRF = null;
         private byte[] publicSeed = null;
@@ -189,6 +203,12 @@ public final class XMSSMTPrivateKeyParameters
             return this;
         }
 
+        public Builder withMaxIndex(long val)
+        {
+            maxIndex = val;
+            return this;
+        }
+
         public Builder withSecretKeySeed(byte[] val)
         {
             secretKeySeed = XMSSUtil.cloneArray(val);
@@ -215,14 +235,21 @@ public final class XMSSMTPrivateKeyParameters
 
         public Builder withBDSState(BDSStateMap val)
         {
-            bdsState = val;
+            if (val.getMaxIndex() == 0)   // check for legacy state maps
+            {
+                bdsState = new BDSStateMap(val, (1L << params.getHeight()) - 1);
+            }
+            else
+            {
+                bdsState = val;
+            }
             return this;
         }
 
-        public Builder withPrivateKey(byte[] privateKeyVal, XMSSParameters xmssVal)
+        public Builder withPrivateKey(byte[] privateKeyVal)
         {
             privateKey = XMSSUtil.cloneArray(privateKeyVal);
-            xmss = xmssVal;
+            xmss = params.getXMSSParameters();
             return this;
         }
 
@@ -232,41 +259,47 @@ public final class XMSSMTPrivateKeyParameters
         }
     }
 
+    /**
+     * @deprecated use getEncoded() - this method will become private.
+     */
     public byte[] toByteArray()
     {
-		/* index || secretKeySeed || secretKeyPRF || publicSeed || root */
-        int n = params.getDigestSize();
-        int indexSize = (params.getHeight() + 7) / 8;
-        int secretKeySize = n;
-        int secretKeyPRFSize = n;
-        int publicSeedSize = n;
-        int rootSize = n;
-        int totalSize = indexSize + secretKeySize + secretKeyPRFSize + publicSeedSize + rootSize;
-        byte[] out = new byte[totalSize];
-        int position = 0;
-		/* copy index */
-        byte[] indexBytes = XMSSUtil.toBytesBigEndian(index, indexSize);
-        XMSSUtil.copyBytesAtOffset(out, indexBytes, position);
-        position += indexSize;
-		/* copy secretKeySeed */
-        XMSSUtil.copyBytesAtOffset(out, secretKeySeed, position);
-        position += secretKeySize;
-		/* copy secretKeyPRF */
-        XMSSUtil.copyBytesAtOffset(out, secretKeyPRF, position);
-        position += secretKeyPRFSize;
-		/* copy publicSeed */
-        XMSSUtil.copyBytesAtOffset(out, publicSeed, position);
-        position += publicSeedSize;
-		/* copy root */
-        XMSSUtil.copyBytesAtOffset(out, root, position);
-		/* concatenate bdsState */
-        try
+        synchronized (this)
         {
-            return Arrays.concatenate(out, XMSSUtil.serialize(bdsState));
-        }
-        catch (IOException e)
-        {
-            throw new IllegalStateException("error serializing bds state: " + e.getMessage(), e);
+            /* index || secretKeySeed || secretKeyPRF || publicSeed || root */
+            int n = params.getTreeDigestSize();
+            int indexSize = (params.getHeight() + 7) / 8;
+            int secretKeySize = n;
+            int secretKeyPRFSize = n;
+            int publicSeedSize = n;
+            int rootSize = n;
+            int totalSize = indexSize + secretKeySize + secretKeyPRFSize + publicSeedSize + rootSize;
+            byte[] out = new byte[totalSize];
+            int position = 0;
+            /* copy index */
+            byte[] indexBytes = XMSSUtil.toBytesBigEndian(index, indexSize);
+            XMSSUtil.copyBytesAtOffset(out, indexBytes, position);
+            position += indexSize;
+            /* copy secretKeySeed */
+            XMSSUtil.copyBytesAtOffset(out, secretKeySeed, position);
+            position += secretKeySize;
+            /* copy secretKeyPRF */
+            XMSSUtil.copyBytesAtOffset(out, secretKeyPRF, position);
+            position += secretKeyPRFSize;
+            /* copy publicSeed */
+            XMSSUtil.copyBytesAtOffset(out, publicSeed, position);
+            position += publicSeedSize;
+            /* copy root */
+            XMSSUtil.copyBytesAtOffset(out, root, position);
+            /* concatenate bdsState */
+            try
+            {
+                return Arrays.concatenate(out, XMSSUtil.serialize(bdsState));
+            }
+            catch (IOException e)
+            {
+                throw new IllegalStateException("error serializing bds state: " + e.getMessage(), e);
+            }
         }
     }
 
@@ -275,6 +308,14 @@ public final class XMSSMTPrivateKeyParameters
         return index;
     }
 
+    public long getUsagesRemaining()
+    {
+        synchronized (this)
+        {
+            return this.bdsState.getMaxIndex() - this.getIndex() + 1;
+        }
+    }
+
     public byte[] getSecretKeySeed()
     {
         return XMSSUtil.cloneArray(secretKeySeed);
@@ -307,11 +348,69 @@ public final class XMSSMTPrivateKeyParameters
 
     public XMSSMTPrivateKeyParameters getNextKey()
     {
-        BDSStateMap newState = new BDSStateMap(bdsState, params, this.getIndex(), publicSeed, secretKeySeed);
+        synchronized (this)
+        {
+            return this.extractKeyShard(1);
+        }
+    }
+
+    XMSSMTPrivateKeyParameters rollKey()
+    {
+        synchronized (this)
+        {
+            if (this.getIndex() < bdsState.getMaxIndex())
+            {
+                bdsState.updateState(params, index, publicSeed, secretKeySeed);
+                index = index + 1;
+                used = false;
+            }
+            else
+            {
+                index = bdsState.getMaxIndex() + 1;
+                bdsState = new BDSStateMap(bdsState.getMaxIndex());
+                used = false;
+            }
+
+            return this;
+        }
+    }
+
+    /**
+     * Return a key that can be used usageCount times.
+     * 

+ * Note: this will use the range [index...index + usageCount) for the current key. + *

+ * @param usageCount the number of usages the key should have. + * @return a key based on the current key that can be used usageCount times. + */ + public XMSSMTPrivateKeyParameters extractKeyShard(int usageCount) + { + if (usageCount < 1) + { + throw new IllegalArgumentException("cannot ask for a shard with 0 keys"); + } + synchronized (this) + { + /* prepare authentication path for next leaf */ + if (usageCount <= this.getUsagesRemaining()) + { + XMSSMTPrivateKeyParameters keyParams = new XMSSMTPrivateKeyParameters.Builder(params) + .withSecretKeySeed(secretKeySeed).withSecretKeyPRF(secretKeyPRF) + .withPublicSeed(publicSeed).withRoot(root) + .withIndex(getIndex()) + .withBDSState(new BDSStateMap(this.bdsState, getIndex() + usageCount - 1)).build(); - return new XMSSMTPrivateKeyParameters.Builder(params).withIndex(index + 1) - .withSecretKeySeed(secretKeySeed).withSecretKeyPRF(secretKeyPRF) - .withPublicSeed(publicSeed).withRoot(root) - .withBDSState(newState).build(); + for (int i = 0; i != usageCount; i++) + { + this.rollKey(); + } + + return keyParams; + } + else + { + throw new IllegalArgumentException("usageCount exceeds usages remaining"); + } + } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTPublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTPublicKeyParameters.java index 2a0a964bb..bdf7dd665 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTPublicKeyParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTPublicKeyParameters.java @@ -1,54 +1,71 @@ package com.fr.third.org.bouncycastle.pqc.crypto.xmss; -import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import java.io.IOException; + +import com.fr.third.org.bouncycastle.util.Encodable; +import com.fr.third.org.bouncycastle.util.Pack; /** * XMSS^MT Public Key. */ public final class XMSSMTPublicKeyParameters - extends AsymmetricKeyParameter - implements XMSSStoreableObjectInterface + extends XMSSMTKeyParameters + implements XMSSStoreableObjectInterface, Encodable { - private final XMSSMTParameters params; - // private final int oid; + private final int oid; private final byte[] root; private final byte[] publicSeed; private XMSSMTPublicKeyParameters(Builder builder) { - super(false); + super(false, builder.params.getTreeDigest()); params = builder.params; if (params == null) { throw new NullPointerException("params == null"); } - int n = params.getDigestSize(); + int n = params.getTreeDigestSize(); byte[] publicKey = builder.publicKey; if (publicKey != null) { /* import */ - // int oidSize = 4; + int oidSize = 4; int rootSize = n; int publicSeedSize = n; - int totalSize = rootSize + publicSeedSize; - if (publicKey.length != totalSize) + int position = 0; + // pre-rfc final key without OID. + if (publicKey.length == rootSize + publicSeedSize) + { + oid = 0; + root = XMSSUtil.extractBytesAtOffset(publicKey, position, rootSize); + position += rootSize; + publicSeed = XMSSUtil.extractBytesAtOffset(publicKey, position, publicSeedSize); + } + else if (publicKey.length == oidSize + rootSize + publicSeedSize) + { + oid = Pack.bigEndianToInt(publicKey, 0); + position += oidSize; + root = XMSSUtil.extractBytesAtOffset(publicKey, position, rootSize); + position += rootSize; + publicSeed = XMSSUtil.extractBytesAtOffset(publicKey, position, publicSeedSize); + } + else { throw new IllegalArgumentException("public key has wrong size"); } - int position = 0; - /* - * oid = XMSSUtil.bytesToIntBigEndian(in, position); if (oid != - * params.getOid().getOid()) { throw new ParseException("wrong oid", - * 0); } position += oidSize; - */ - root = XMSSUtil.extractBytesAtOffset(publicKey, position, rootSize); - position += rootSize; - publicSeed = XMSSUtil.extractBytesAtOffset(publicKey, position, publicSeedSize); } else { /* set */ + if (params.getOid() != null) + { + this.oid = params.getOid().getOid(); + } + else + { + this.oid = 0; + } byte[] tmpRoot = builder.root; if (tmpRoot != null) { @@ -78,6 +95,12 @@ public final class XMSSMTPublicKeyParameters } } + public byte[] getEncoded() + throws IOException + { + return toByteArray(); + } + public static class Builder { @@ -118,22 +141,29 @@ public final class XMSSMTPublicKeyParameters } } + /** + * @deprecated use getEncoded() - this method will become private. + */ public byte[] toByteArray() { /* oid || root || seed */ - int n = params.getDigestSize(); - // int oidSize = 4; + int n = params.getTreeDigestSize(); + int oidSize = 4; int rootSize = n; int publicSeedSize = n; - int totalSize = rootSize + publicSeedSize; - // int totalSize = oidSize + rootSize + publicSeedSize; - byte[] out = new byte[totalSize]; + byte[] out; int position = 0; - /* copy oid */ - /* - * XMSSUtil.intToBytesBigEndianOffset(out, oid, position); position += - * oidSize; - */ + /* copy oid */ + if (oid != 0) + { + out = new byte[oidSize + rootSize + publicSeedSize]; + Pack.intToBigEndian(oid, out, position); + position += oidSize; + } + else + { + out = new byte[rootSize + publicSeedSize]; + } /* copy root */ XMSSUtil.copyBytesAtOffset(out, root, position); position += rootSize; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTSignature.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTSignature.java index 089345c1b..0921250e4 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTSignature.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTSignature.java @@ -1,13 +1,17 @@ package com.fr.third.org.bouncycastle.pqc.crypto.xmss; +import java.io.IOException; import java.util.ArrayList; import java.util.List; +import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Encodable; + /** * XMSS^MT Signature. */ public final class XMSSMTSignature - implements XMSSStoreableObjectInterface + implements XMSSStoreableObjectInterface, Encodable { private final XMSSMTParameters params; @@ -23,7 +27,7 @@ public final class XMSSMTSignature { throw new NullPointerException("params == null"); } - int n = params.getDigestSize(); + int n = params.getTreeDigestSize(); byte[] signature = builder.signature; if (signature != null) { @@ -40,6 +44,7 @@ public final class XMSSMTSignature } int position = 0; index = XMSSUtil.bytesToXBigEndian(signature, position, indexSize); + if (!XMSSUtil.isIndexValid(params.getHeight(), index)) { throw new IllegalArgumentException("index out of bounds"); @@ -86,6 +91,12 @@ public final class XMSSMTSignature } } + public byte[] getEncoded() + throws IOException + { + return toByteArray(); + } + public static class Builder { @@ -123,7 +134,7 @@ public final class XMSSMTSignature public Builder withSignature(byte[] val) { - signature = val; + signature = Arrays.clone(val); return this; } @@ -136,7 +147,7 @@ public final class XMSSMTSignature public byte[] toByteArray() { /* index || random || reduced signatures */ - int n = params.getDigestSize(); + int n = params.getTreeDigestSize(); int len = params.getWOTSPlus().getParams().getLen(); int indexSize = (int)Math.ceil(params.getHeight() / (double)8); int randomSize = n; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTSigner.java index e8e7d01c8..723a6d9d8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTSigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSMTSigner.java @@ -12,7 +12,6 @@ public class XMSSMTSigner implements StateAwareMessageSigner { private XMSSMTPrivateKeyParameters privateKey; - private XMSSMTPrivateKeyParameters nextKeyGenerator; private XMSSMTPublicKeyParameters publicKey; private XMSSMTParameters params; private XMSSParameters xmssParams; @@ -29,7 +28,6 @@ public class XMSSMTSigner initSign = true; hasGenerated = false; privateKey = (XMSSMTPrivateKeyParameters)param; - nextKeyGenerator = privateKey; params = privateKey.getParameters(); xmssParams = params.getXMSSParameters(); @@ -43,7 +41,7 @@ public class XMSSMTSigner xmssParams = params.getXMSSParameters(); } - wotsPlus = new WOTSPlus(new WOTSPlusParameters(params.getDigest())); + wotsPlus = params.getWOTSPlus(); } public byte[] generateSignature(byte[] message) @@ -52,6 +50,7 @@ public class XMSSMTSigner { throw new NullPointerException("message == null"); } + if (initSign) { if (privateKey == null) @@ -63,98 +62,104 @@ public class XMSSMTSigner { throw new IllegalStateException("signer not initialized for signature generation"); } - if (privateKey.getBDSState().isEmpty()) - { - throw new IllegalStateException("not initialized"); - } - - BDSStateMap bdsState = privateKey.getBDSState(); - // privateKey.increaseIndex(this); - final long globalIndex = privateKey.getIndex(); - final int totalHeight = params.getHeight(); - final int xmssHeight = xmssParams.getHeight(); - if (!XMSSUtil.isIndexValid(totalHeight, globalIndex)) + synchronized (privateKey) { - throw new IllegalStateException("index out of bounds"); - } - - /* compress message */ - byte[] random = wotsPlus.getKhf().PRF(privateKey.getSecretKeyPRF(), XMSSUtil.toBytesBigEndian(globalIndex, 32)); - byte[] concatenated = Arrays.concatenate(random, privateKey.getRoot(), - XMSSUtil.toBytesBigEndian(globalIndex, params.getDigestSize())); - byte[] messageDigest = wotsPlus.getKhf().HMsg(concatenated, message); - - XMSSMTSignature signature = new XMSSMTSignature.Builder(params).withIndex(globalIndex).withRandom(random).build(); - - - /* layer 0 */ - long indexTree = XMSSUtil.getTreeIndex(globalIndex, xmssHeight); - int indexLeaf = XMSSUtil.getLeafIndex(globalIndex, xmssHeight); - - /* reset xmss */ - wotsPlus.importKeys(new byte[params.getDigestSize()], privateKey.getPublicSeed()); - /* create signature with XMSS tree on layer 0 */ - - /* adjust addresses */ - OTSHashAddress otsHashAddress = (OTSHashAddress)new OTSHashAddress.Builder().withTreeAddress(indexTree) - .withOTSAddress(indexLeaf).build(); - - /* get authentication path from BDS */ - if (bdsState.get(0) == null || indexLeaf == 0) - { - bdsState.put(0, new BDS(xmssParams, privateKey.getPublicSeed(), privateKey.getSecretKeySeed(), otsHashAddress)); - } - - /* sign message digest */ - WOTSPlusSignature wotsPlusSignature = wotsSign(messageDigest, otsHashAddress); - - XMSSReducedSignature reducedSignature = new XMSSReducedSignature.Builder(xmssParams) - .withWOTSPlusSignature(wotsPlusSignature).withAuthPath(bdsState.get(0).getAuthenticationPath()) - .build(); - - signature.getReducedSignatures().add(reducedSignature); - /* loop over remaining layers */ - for (int layer = 1; layer < params.getLayers(); layer++) - { - /* get root of layer - 1 */ - XMSSNode root = bdsState.get(layer - 1).getRoot(); - - indexLeaf = XMSSUtil.getLeafIndex(indexTree, xmssHeight); - indexTree = XMSSUtil.getTreeIndex(indexTree, xmssHeight); - - /* adjust addresses */ - otsHashAddress = (OTSHashAddress)new OTSHashAddress.Builder().withLayerAddress(layer) - .withTreeAddress(indexTree).withOTSAddress(indexLeaf).build(); - - /* sign root digest of layer - 1 */ - wotsPlusSignature = wotsSign(root.getValue(), otsHashAddress); - /* get authentication path from BDS */ - if (bdsState.get(layer) == null || XMSSUtil.isNewBDSInitNeeded(globalIndex, xmssHeight, layer)) - { - bdsState.put(layer, new BDS(xmssParams, privateKey.getPublicSeed(), privateKey.getSecretKeySeed(), otsHashAddress)); + if (privateKey.getUsagesRemaining() <= 0) + { + throw new IllegalStateException("no usages of private key remaining"); + } + if (privateKey.getBDSState().isEmpty()) + { + throw new IllegalStateException("not initialized"); } - reducedSignature = new XMSSReducedSignature.Builder(xmssParams) - .withWOTSPlusSignature(wotsPlusSignature) - .withAuthPath(bdsState.get(layer).getAuthenticationPath()).build(); - - signature.getReducedSignatures().add(reducedSignature); - } - - hasGenerated = true; + try + { - if (nextKeyGenerator != null) - { - privateKey = nextKeyGenerator.getNextKey(); - nextKeyGenerator = privateKey; - } - else - { - privateKey = null; + BDSStateMap bdsState = privateKey.getBDSState(); + + // privateKey.increaseIndex(this); + final long globalIndex = privateKey.getIndex(); + final int totalHeight = params.getHeight(); + final int xmssHeight = xmssParams.getHeight(); + if (privateKey.getUsagesRemaining() <= 0) + { + throw new IllegalStateException("index out of bounds"); + } + + /* compress message */ + byte[] random = wotsPlus.getKhf().PRF(privateKey.getSecretKeyPRF(), XMSSUtil.toBytesBigEndian(globalIndex, 32)); + byte[] concatenated = Arrays.concatenate(random, privateKey.getRoot(), + XMSSUtil.toBytesBigEndian(globalIndex, params.getTreeDigestSize())); + byte[] messageDigest = wotsPlus.getKhf().HMsg(concatenated, message); + + hasGenerated = true; + + XMSSMTSignature signature = new XMSSMTSignature.Builder(params).withIndex(globalIndex).withRandom(random).build(); + + + /* layer 0 */ + long indexTree = XMSSUtil.getTreeIndex(globalIndex, xmssHeight); + int indexLeaf = XMSSUtil.getLeafIndex(globalIndex, xmssHeight); + + /* reset xmss */ + wotsPlus.importKeys(new byte[params.getTreeDigestSize()], privateKey.getPublicSeed()); + /* create signature with XMSS tree on layer 0 */ + + /* adjust addresses */ + OTSHashAddress otsHashAddress = (OTSHashAddress)new OTSHashAddress.Builder().withTreeAddress(indexTree) + .withOTSAddress(indexLeaf).build(); + + /* get authentication path from BDS */ + if (bdsState.get(0) == null || indexLeaf == 0) + { + bdsState.put(0, new BDS(xmssParams, privateKey.getPublicSeed(), privateKey.getSecretKeySeed(), otsHashAddress)); + } + + /* sign message digest */ + WOTSPlusSignature wotsPlusSignature = wotsSign(messageDigest, otsHashAddress); + + XMSSReducedSignature reducedSignature = new XMSSReducedSignature.Builder(xmssParams) + .withWOTSPlusSignature(wotsPlusSignature).withAuthPath(bdsState.get(0).getAuthenticationPath()) + .build(); + + signature.getReducedSignatures().add(reducedSignature); + /* loop over remaining layers */ + for (int layer = 1; layer < params.getLayers(); layer++) + { + /* get root of layer - 1 */ + XMSSNode root = bdsState.get(layer - 1).getRoot(); + + indexLeaf = XMSSUtil.getLeafIndex(indexTree, xmssHeight); + indexTree = XMSSUtil.getTreeIndex(indexTree, xmssHeight); + + /* adjust addresses */ + otsHashAddress = (OTSHashAddress)new OTSHashAddress.Builder().withLayerAddress(layer) + .withTreeAddress(indexTree).withOTSAddress(indexLeaf).build(); + + /* sign root digest of layer - 1 */ + wotsPlusSignature = wotsSign(root.getValue(), otsHashAddress); + /* get authentication path from BDS */ + if (bdsState.get(layer) == null || XMSSUtil.isNewBDSInitNeeded(globalIndex, xmssHeight, layer)) + { + bdsState.put(layer, new BDS(xmssParams, privateKey.getPublicSeed(), privateKey.getSecretKeySeed(), otsHashAddress)); + } + + reducedSignature = new XMSSReducedSignature.Builder(xmssParams) + .withWOTSPlusSignature(wotsPlusSignature) + .withAuthPath(bdsState.get(layer).getAuthenticationPath()).build(); + + signature.getReducedSignatures().add(reducedSignature); + } + + return signature.toByteArray(); + } + finally + { + privateKey.rollKey(); + } } - - return signature.toByteArray(); } public boolean verifySignature(byte[] message, byte[] signature) @@ -175,7 +180,7 @@ public class XMSSMTSigner XMSSMTSignature sig = new XMSSMTSignature.Builder(params).withSignature(signature).build(); byte[] concatenated = Arrays.concatenate(sig.getRandom(), publicKey.getRoot(), - XMSSUtil.toBytesBigEndian(sig.getIndex(), params.getDigestSize())); + XMSSUtil.toBytesBigEndian(sig.getIndex(), params.getTreeDigestSize())); byte[] messageDigest = wotsPlus.getKhf().HMsg(concatenated, message); long globalIndex = sig.getIndex(); @@ -184,7 +189,7 @@ public class XMSSMTSigner int indexLeaf = XMSSUtil.getLeafIndex(globalIndex, xmssHeight); /* adjust xmss */ - wotsPlus.importKeys(new byte[params.getDigestSize()], publicKey.getPublicSeed()); + wotsPlus.importKeys(new byte[params.getTreeDigestSize()], publicKey.getPublicSeed()); /* prepare addresses */ OTSHashAddress otsHashAddress = (OTSHashAddress)new OTSHashAddress.Builder().withTreeAddress(indexTree) @@ -213,7 +218,7 @@ public class XMSSMTSigner private WOTSPlusSignature wotsSign(byte[] messageDigest, OTSHashAddress otsHashAddress) { - if (messageDigest.length != params.getDigestSize()) + if (messageDigest.length != params.getTreeDigestSize()) { throw new IllegalArgumentException("size of messageDigest needs to be equal to size of digest"); } @@ -227,6 +232,11 @@ public class XMSSMTSigner return wotsPlus.sign(messageDigest, otsHashAddress); } + public long getUsagesRemaining() + { + return privateKey.getUsagesRemaining(); + } + public AsymmetricKeyParameter getUpdatedPrivateKey() { // if we've generated a signature return the last private key generated @@ -236,15 +246,17 @@ public class XMSSMTSigner XMSSMTPrivateKeyParameters privKey = privateKey; privateKey = null; - nextKeyGenerator = null; return privKey; } else { - XMSSMTPrivateKeyParameters privKey = nextKeyGenerator.getNextKey(); + XMSSMTPrivateKeyParameters privKey = privateKey; - nextKeyGenerator = null; + if (privKey != null) + { + privateKey = privateKey.getNextKey(); + } return privKey; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSNode.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSNode.java index 5579a4d4c..b45b629ed 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSNode.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSNode.java @@ -8,7 +8,6 @@ import java.io.Serializable; public final class XMSSNode implements Serializable { - private static final long serialVersionUID = 1L; private final int height; @@ -30,9 +29,4 @@ public final class XMSSNode { return XMSSUtil.cloneArray(value); } - - protected XMSSNode clone() - { - return new XMSSNode(getHeight(), getValue()); - } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSNodeUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSNodeUtil.java index 4a0c68267..38f89ba31 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSNodeUtil.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSNodeUtil.java @@ -134,7 +134,7 @@ class XMSSNodeUtil } byte[] bitmask1 = wotsPlus.getKhf().PRF(publicSeed, address.toByteArray()); - int n = wotsPlus.getParams().getDigestSize(); + int n = wotsPlus.getParams().getTreeDigestSize(); byte[] tmpMask = new byte[2 * n]; for (int i = 0; i < n; i++) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSOid.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSOid.java index 492031f25..cde35715c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSOid.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSOid.java @@ -1,6 +1,7 @@ package com.fr.third.org.bouncycastle.pqc.crypto.xmss; -public interface XMSSOid { +public interface XMSSOid +{ int getOid(); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSParameters.java index 8167c94be..9e16a2932 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSParameters.java @@ -1,5 +1,6 @@ package com.fr.third.org.bouncycastle.pqc.crypto.xmss; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.crypto.Digest; /** @@ -7,36 +8,42 @@ import com.fr.third.org.bouncycastle.crypto.Digest; */ public final class XMSSParameters { - private final XMSSOid oid; - private final WOTSPlus wotsPlus; - //private final SecureRandom prng; private final int height; private final int k; + private final ASN1ObjectIdentifier treeDigestOID; + private final int winternitzParameter; + private final String treeDigest; + private final int treeDigestSize; + private final WOTSPlusParameters wotsPlusParams; /** * XMSS Constructor... * * @param height Height of tree. - * @param digest Digest to use. + * @param treeDigest Digest to use. */ - public XMSSParameters(int height, Digest digest) + public XMSSParameters(int height, Digest treeDigest) { super(); if (height < 2) { throw new IllegalArgumentException("height must be >= 2"); } - if (digest == null) + if (treeDigest == null) { throw new NullPointerException("digest == null"); } - wotsPlus = new WOTSPlus(new WOTSPlusParameters(digest)); this.height = height; this.k = determineMinK(); - oid = DefaultXMSSOid.lookup(getDigest().getAlgorithmName(), getDigestSize(), getWinternitzParameter(), - wotsPlus.getParams().getLen(), height); + this.treeDigest = treeDigest.getAlgorithmName(); + this.treeDigestOID = DigestUtil.getDigestOID(treeDigest.getAlgorithmName()); + + this.wotsPlusParams = new WOTSPlusParameters(treeDigestOID); + this.treeDigestSize = wotsPlusParams.getTreeDigestSize(); + this.winternitzParameter = wotsPlusParams.getWinternitzParameter(); + this.oid = DefaultXMSSOid.lookup(this.treeDigest, this.treeDigestSize, this.winternitzParameter, wotsPlusParams.getLen(), height); /* * if (oid == null) { throw new InvalidParameterException(); } */ @@ -54,44 +61,59 @@ public final class XMSSParameters throw new IllegalStateException("should never happen..."); } - protected Digest getDigest() - { - return wotsPlus.getParams().getDigest(); - } - /** * Getter digest size. * * @return Digest size. */ - public int getDigestSize() + public int getTreeDigestSize() { - return wotsPlus.getParams().getDigestSize(); + return treeDigestSize; } /** - * Getter Winternitz parameter. + * Getter height. * - * @return Winternitz parameter. + * @return XMSS tree height. */ - public int getWinternitzParameter() + public int getHeight() { - return wotsPlus.getParams().getWinternitzParameter(); + return height; + } + + String getTreeDigest() + { + return treeDigest; + } + + ASN1ObjectIdentifier getTreeDigestOID() + { + return treeDigestOID; + } + + int getLen() + { + return wotsPlusParams.getLen(); } /** - * Getter height. + * Getter Winternitz parameter. * - * @return XMSS height. + * @return Winternitz parameter. */ - public int getHeight() + int getWinternitzParameter() { - return height; + return winternitzParameter; } WOTSPlus getWOTSPlus() { - return wotsPlus; + return new WOTSPlus(wotsPlusParams); + } + + XMSSOid getOid() + { + return oid; } int getK() diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSPrivateKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSPrivateKeyParameters.java index e1efd4253..7c3512240 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSPrivateKeyParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSPrivateKeyParameters.java @@ -2,16 +2,16 @@ package com.fr.third.org.bouncycastle.pqc.crypto.xmss; import java.io.IOException; -import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; import com.fr.third.org.bouncycastle.util.Arrays; +import com.fr.third.org.bouncycastle.util.Encodable; import com.fr.third.org.bouncycastle.util.Pack; /** * XMSS Private Key. */ public final class XMSSPrivateKeyParameters - extends AsymmetricKeyParameter - implements XMSSStoreableObjectInterface + extends XMSSKeyParameters + implements XMSSStoreableObjectInterface, Encodable { /** @@ -38,24 +38,20 @@ public final class XMSSPrivateKeyParameters /** * BDS state. */ - private final BDS bdsState; + private volatile BDS bdsState; private XMSSPrivateKeyParameters(Builder builder) { - super(true); + super(true, builder.params.getTreeDigest()); params = builder.params; if (params == null) { throw new NullPointerException("params == null"); } - int n = params.getDigestSize(); + int n = params.getTreeDigestSize(); byte[] privateKey = builder.privateKey; if (privateKey != null) { - if (builder.xmss == null) - { - throw new NullPointerException("xmss == null"); - } /* import */ int height = params.getHeight(); int indexSize = 4; @@ -89,13 +85,11 @@ public final class XMSSPrivateKeyParameters try { BDS bdsImport = (BDS)XMSSUtil.deserialize(bdsStateBinary, BDS.class); - bdsImport.setXMSS(builder.xmss); - bdsImport.validate(); if (bdsImport.getIndex() != index) { throw new IllegalStateException("serialized BDS has wrong index"); } - bdsState = bdsImport; + bdsState = bdsImport.withWOTSDigest(builder.params.getTreeDigestOID()); } catch (IOException e) { @@ -174,8 +168,106 @@ public final class XMSSPrivateKeyParameters } else { - bdsState = new BDS(params, builder.index); + bdsState = new BDS(params, (1 << params.getHeight()) - 1, builder.index); + } + } + if (builder.maxIndex >= 0 && builder.maxIndex != bdsState.getMaxIndex()) + { + throw new IllegalArgumentException("maxIndex set but not reflected in state"); + } + } + } + + public long getUsagesRemaining() + { + synchronized (this) + { + return this.bdsState.getMaxIndex() - this.getIndex() + 1; + } + } + + public byte[] getEncoded() + throws IOException + { + synchronized (this) + { + return toByteArray(); + } + } + + XMSSPrivateKeyParameters rollKey() + { + synchronized (this) + { + /* prepare authentication path for next leaf */ + if (bdsState.getIndex() < bdsState.getMaxIndex()) + { + bdsState = bdsState.getNextState(publicSeed, secretKeySeed, (OTSHashAddress)new OTSHashAddress.Builder().build()); + } + else + { + bdsState = new BDS(params, bdsState.getMaxIndex(), bdsState.getMaxIndex() + 1); // no more nodes left. + } + + return this; + } + } + + public XMSSPrivateKeyParameters getNextKey() + { + synchronized (this) + { + XMSSPrivateKeyParameters keyParameters = this.extractKeyShard(1); + + return keyParameters; + } + } + + /** + * Return a key that can be used usageCount times. + *

+ * Note: this will use the range [index...index + usageCount) for the current key. + *

+ * @param usageCount the number of usages the key should have. + * @return a key based on the current key that can be used usageCount times. + */ + public XMSSPrivateKeyParameters extractKeyShard(int usageCount) + { + if (usageCount < 1) + { + throw new IllegalArgumentException("cannot ask for a shard with 0 keys"); + } + synchronized (this) + { + /* prepare authentication path for next leaf */ + if (usageCount <= this.getUsagesRemaining()) + { + XMSSPrivateKeyParameters keyParams = new XMSSPrivateKeyParameters.Builder(params) + .withSecretKeySeed(secretKeySeed).withSecretKeyPRF(secretKeyPRF) + .withPublicSeed(publicSeed).withRoot(root) + .withIndex(getIndex()) + .withBDSState(bdsState.withMaxIndex(bdsState.getIndex() + usageCount - 1, + params.getTreeDigestOID())).build(); + + if (usageCount == this.getUsagesRemaining()) + { + this.bdsState = new BDS(params, bdsState.getMaxIndex(), getIndex() + usageCount); // we're finished. + } + else + { + // update the tree to the new index. + OTSHashAddress hashAddress = (OTSHashAddress)new OTSHashAddress.Builder().build(); + for (int i = 0; i != usageCount; i++) + { + this.bdsState = bdsState.getNextState(publicSeed, secretKeySeed, hashAddress); + } } + + return keyParams; + } + else + { + throw new IllegalArgumentException("usageCount exceeds usages remaining"); } } } @@ -187,13 +279,13 @@ public final class XMSSPrivateKeyParameters private final XMSSParameters params; /* optional */ private int index = 0; + private int maxIndex = -1; private byte[] secretKeySeed = null; private byte[] secretKeyPRF = null; private byte[] publicSeed = null; private byte[] root = null; private BDS bdsState = null; private byte[] privateKey = null; - private XMSSParameters xmss = null; public Builder(XMSSParameters params) { @@ -207,6 +299,12 @@ public final class XMSSPrivateKeyParameters return this; } + public Builder withMaxIndex(int val) + { + maxIndex = val; + return this; + } + public Builder withSecretKeySeed(byte[] val) { secretKeySeed = XMSSUtil.cloneArray(val); @@ -237,10 +335,9 @@ public final class XMSSPrivateKeyParameters return this; } - public Builder withPrivateKey(byte[] privateKeyVal, XMSSParameters xmssParameters) + public Builder withPrivateKey(byte[] privateKeyVal) { privateKey = XMSSUtil.cloneArray(privateKeyVal); - xmss = xmssParameters; return this; } @@ -250,44 +347,50 @@ public final class XMSSPrivateKeyParameters } } + /** + * @deprecated use getEncoded() - this method will become private. + */ public byte[] toByteArray() { - /* index || secretKeySeed || secretKeyPRF || publicSeed || root */ - int n = params.getDigestSize(); - int indexSize = 4; - int secretKeySize = n; - int secretKeyPRFSize = n; - int publicSeedSize = n; - int rootSize = n; - int totalSize = indexSize + secretKeySize + secretKeyPRFSize + publicSeedSize + rootSize; - byte[] out = new byte[totalSize]; - int position = 0; - /* copy index */ - Pack.intToBigEndian(bdsState.getIndex(), out, position); - position += indexSize; - /* copy secretKeySeed */ - XMSSUtil.copyBytesAtOffset(out, secretKeySeed, position); - position += secretKeySize; - /* copy secretKeyPRF */ - XMSSUtil.copyBytesAtOffset(out, secretKeyPRF, position); - position += secretKeyPRFSize; - /* copy publicSeed */ - XMSSUtil.copyBytesAtOffset(out, publicSeed, position); - position += publicSeedSize; - /* copy root */ - XMSSUtil.copyBytesAtOffset(out, root, position); - /* concatenate bdsState */ - byte[] bdsStateOut = null; - try + synchronized (this) { - bdsStateOut = XMSSUtil.serialize(bdsState); - } - catch (IOException e) - { - throw new RuntimeException("error serializing bds state: " + e.getMessage()); - } + /* index || secretKeySeed || secretKeyPRF || publicSeed || root */ + int n = params.getTreeDigestSize(); + int indexSize = 4; + int secretKeySize = n; + int secretKeyPRFSize = n; + int publicSeedSize = n; + int rootSize = n; + int totalSize = indexSize + secretKeySize + secretKeyPRFSize + publicSeedSize + rootSize; + byte[] out = new byte[totalSize]; + int position = 0; + /* copy index */ + Pack.intToBigEndian(bdsState.getIndex(), out, position); + position += indexSize; + /* copy secretKeySeed */ + XMSSUtil.copyBytesAtOffset(out, secretKeySeed, position); + position += secretKeySize; + /* copy secretKeyPRF */ + XMSSUtil.copyBytesAtOffset(out, secretKeyPRF, position); + position += secretKeyPRFSize; + /* copy publicSeed */ + XMSSUtil.copyBytesAtOffset(out, publicSeed, position); + position += publicSeedSize; + /* copy root */ + XMSSUtil.copyBytesAtOffset(out, root, position); + /* concatenate bdsState */ + byte[] bdsStateOut = null; + try + { + bdsStateOut = XMSSUtil.serialize(bdsState); + } + catch (IOException e) + { + throw new RuntimeException("error serializing bds state: " + e.getMessage()); + } - return Arrays.concatenate(out, bdsStateOut); + return Arrays.concatenate(out, bdsStateOut); + } } public int getIndex() @@ -324,25 +427,4 @@ public final class XMSSPrivateKeyParameters { return params; } - - public XMSSPrivateKeyParameters getNextKey() - { - /* prepare authentication path for next leaf */ - int treeHeight = this.params.getHeight(); - if (this.getIndex() < ((1 << treeHeight) - 1)) - { - return new XMSSPrivateKeyParameters.Builder(params) - .withSecretKeySeed(secretKeySeed).withSecretKeyPRF(secretKeyPRF) - .withPublicSeed(publicSeed).withRoot(root) - .withBDSState(bdsState.getNextState(publicSeed, secretKeySeed, (OTSHashAddress)new OTSHashAddress.Builder().build())).build(); - } - else - { - return new XMSSPrivateKeyParameters.Builder(params) - .withSecretKeySeed(secretKeySeed).withSecretKeyPRF(secretKeyPRF) - .withPublicSeed(publicSeed).withRoot(root) - .withBDSState(new BDS(params, getIndex() + 1)).build(); // no more nodes left. - } - } - } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSPublicKeyParameters.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSPublicKeyParameters.java index 52de1126e..d5a052c5b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSPublicKeyParameters.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSPublicKeyParameters.java @@ -1,59 +1,76 @@ package com.fr.third.org.bouncycastle.pqc.crypto.xmss; -import com.fr.third.org.bouncycastle.crypto.params.AsymmetricKeyParameter; +import java.io.IOException; + +import com.fr.third.org.bouncycastle.util.Encodable; +import com.fr.third.org.bouncycastle.util.Pack; /** * XMSS Public Key. */ public final class XMSSPublicKeyParameters - extends AsymmetricKeyParameter - implements XMSSStoreableObjectInterface + extends XMSSKeyParameters + implements XMSSStoreableObjectInterface, Encodable { /** * XMSS parameters object. */ private final XMSSParameters params; - //private final int oid; + private final int oid; private final byte[] root; private final byte[] publicSeed; private XMSSPublicKeyParameters(Builder builder) { - super(false); + super(false, builder.params.getTreeDigest()); params = builder.params; if (params == null) { throw new NullPointerException("params == null"); } - int n = params.getDigestSize(); + int n = params.getTreeDigestSize(); byte[] publicKey = builder.publicKey; if (publicKey != null) { /* import */ - // int oidSize = 4; + int oidSize = 4; int rootSize = n; int publicSeedSize = n; - // int totalSize = oidSize + rootSize + publicSeedSize; - int totalSize = rootSize + publicSeedSize; - if (publicKey.length != totalSize) + // updated key + int position = 0; + // pre-rfc final key without OID. + if (publicKey.length == rootSize + publicSeedSize) + { + oid = 0; + root = XMSSUtil.extractBytesAtOffset(publicKey, position, rootSize); + position += rootSize; + publicSeed = XMSSUtil.extractBytesAtOffset(publicKey, position, publicSeedSize); + } + else if (publicKey.length == oidSize + rootSize + publicSeedSize) + { + oid = Pack.bigEndianToInt(publicKey, 0); + position += oidSize; + root = XMSSUtil.extractBytesAtOffset(publicKey, position, rootSize); + position += rootSize; + publicSeed = XMSSUtil.extractBytesAtOffset(publicKey, position, publicSeedSize); + } + else { throw new IllegalArgumentException("public key has wrong size"); } - int position = 0; - /* - * oid = XMSSUtil.bytesToIntBigEndian(publicKey, position); if (oid != - * xmss.getParams().getOid().getOid()) { throw new - * ParseException("public key not compatible with current instance parameters" - * , 0); } position += oidSize; - */ - root = XMSSUtil.extractBytesAtOffset(publicKey, position, rootSize); - position += rootSize; - publicSeed = XMSSUtil.extractBytesAtOffset(publicKey, position, publicSeedSize); } else { - /* set */ + /* set */ + if (params.getOid() != null) + { + this.oid = params.getOid().getOid(); + } + else + { + this.oid = 0; + } byte[] tmpRoot = builder.root; if (tmpRoot != null) { @@ -83,6 +100,12 @@ public final class XMSSPublicKeyParameters } } + public byte[] getEncoded() + throws IOException + { + return toByteArray(); + } + public static class Builder { @@ -123,26 +146,34 @@ public final class XMSSPublicKeyParameters } } + /** + * @deprecated use getEncoded() - this method will become private. + */ public byte[] toByteArray() { - /* oid || root || seed */ - int n = params.getDigestSize(); - // int oidSize = 4; + /* oid || root || seed */ + int n = params.getTreeDigestSize(); + int oidSize = 4; int rootSize = n; int publicSeedSize = n; - // int totalSize = oidSize + rootSize + publicSeedSize; - int totalSize = rootSize + publicSeedSize; - byte[] out = new byte[totalSize]; + + byte[] out; int position = 0; - /* copy oid */ - /* - * XMSSUtil.intToBytesBigEndianOffset(out, oid, position); position += - * oidSize; - */ - /* copy root */ + /* copy oid */ + if (oid != 0) + { + out = new byte[oidSize + rootSize + publicSeedSize]; + Pack.intToBigEndian(oid, out, position); + position += oidSize; + } + else + { + out = new byte[rootSize + publicSeedSize]; + } + /* copy root */ XMSSUtil.copyBytesAtOffset(out, root, position); position += rootSize; - /* copy public seed */ + /* copy public seed */ XMSSUtil.copyBytesAtOffset(out, publicSeed, position); return out; } @@ -158,7 +189,7 @@ public final class XMSSPublicKeyParameters } public XMSSParameters getParameters() - { - return params; - } + { + return params; + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSReducedSignature.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSReducedSignature.java index 017aacbe9..d3fdedcff 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSReducedSignature.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSReducedSignature.java @@ -22,7 +22,7 @@ public class XMSSReducedSignature { throw new NullPointerException("params == null"); } - int n = params.getDigestSize(); + int n = params.getTreeDigestSize(); int len = params.getWOTSPlus().getParams().getLen(); int height = params.getHeight(); byte[] reducedSignature = builder.reducedSignature; @@ -124,7 +124,7 @@ public class XMSSReducedSignature public byte[] toByteArray() { /* signature || authentication path */ - int n = params.getDigestSize(); + int n = params.getTreeDigestSize(); int signatureSize = params.getWOTSPlus().getParams().getLen() * n; int authPathSize = params.getHeight() * n; int totalSize = signatureSize + authPathSize; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSSignature.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSSignature.java index 999ce3cb6..418fd7ed8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSSignature.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSSignature.java @@ -1,5 +1,8 @@ package com.fr.third.org.bouncycastle.pqc.crypto.xmss; +import java.io.IOException; + +import com.fr.third.org.bouncycastle.util.Encodable; import com.fr.third.org.bouncycastle.util.Pack; /** @@ -7,7 +10,7 @@ import com.fr.third.org.bouncycastle.util.Pack; */ public final class XMSSSignature extends XMSSReducedSignature - implements XMSSStoreableObjectInterface + implements XMSSStoreableObjectInterface, Encodable { private final int index; @@ -17,7 +20,7 @@ public final class XMSSSignature { super(builder); index = builder.index; - int n = getParams().getDigestSize(); + int n = getParams().getTreeDigestSize(); byte[] tmpRandom = builder.random; if (tmpRandom != null) { @@ -33,6 +36,12 @@ public final class XMSSSignature } } + public byte[] getEncoded() + throws IOException + { + return toByteArray(); + } + public static class Builder extends XMSSReducedSignature.Builder { @@ -66,7 +75,7 @@ public final class XMSSSignature { throw new NullPointerException("signature == null"); } - int n = params.getDigestSize(); + int n = params.getTreeDigestSize(); int len = params.getWOTSPlus().getParams().getLen(); int height = params.getHeight(); int indexSize = 4; @@ -90,10 +99,14 @@ public final class XMSSSignature } } + /** + * @deprecated use getEncoded() this method will become private. + * @return + */ public byte[] toByteArray() { /* index || random || signature || authentication path */ - int n = getParams().getDigestSize(); + int n = getParams().getTreeDigestSize(); int indexSize = 4; int randomSize = n; int signatureSize = getParams().getWOTSPlus().getParams().getLen() * n; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSSigner.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSSigner.java index 4b80b8bfe..777c0b3fa 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSSigner.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSSigner.java @@ -9,9 +9,9 @@ public class XMSSSigner implements StateAwareMessageSigner { private XMSSPrivateKeyParameters privateKey; - private XMSSPrivateKeyParameters nextKeyGenerator; private XMSSPublicKeyParameters publicKey; private XMSSParameters params; + private WOTSPlus wotsPlus; private KeyedHashFunctions khf; private boolean initSign; @@ -24,10 +24,7 @@ public class XMSSSigner initSign = true; hasGenerated = false; privateKey = (XMSSPrivateKeyParameters)param; - nextKeyGenerator = privateKey; - params = privateKey.getParameters(); - khf = params.getWOTSPlus().getKhf(); } else { @@ -35,8 +32,10 @@ public class XMSSSigner publicKey = (XMSSPublicKeyParameters)param; params = publicKey.getParameters(); - khf = params.getWOTSPlus().getKhf(); } + + wotsPlus = params.getWOTSPlus(); + khf = wotsPlus.getKhf(); } public byte[] generateSignature(byte[] message) @@ -56,42 +55,49 @@ public class XMSSSigner { throw new IllegalStateException("signer not initialized for signature generation"); } - if (privateKey.getBDSState().getAuthenticationPath().isEmpty()) - { - throw new IllegalStateException("not initialized"); - } - int index = privateKey.getIndex(); - if (!XMSSUtil.isIndexValid(params.getHeight(), index)) - { - throw new IllegalStateException("index out of bounds"); - } - - /* create (randomized keyed) messageDigest of message */ - byte[] random = khf.PRF(privateKey.getSecretKeyPRF(), XMSSUtil.toBytesBigEndian(index, 32)); - byte[] concatenated = Arrays.concatenate(random, privateKey.getRoot(), - XMSSUtil.toBytesBigEndian(index, params.getDigestSize())); - byte[] messageDigest = khf.HMsg(concatenated, message); - /* create signature for messageDigest */ - OTSHashAddress otsHashAddress = (OTSHashAddress)new OTSHashAddress.Builder().withOTSAddress(index).build(); - WOTSPlusSignature wotsPlusSignature = wotsSign(messageDigest, otsHashAddress); - XMSSSignature signature = (XMSSSignature)new XMSSSignature.Builder(params).withIndex(index).withRandom(random) - .withWOTSPlusSignature(wotsPlusSignature).withAuthPath(privateKey.getBDSState().getAuthenticationPath()) - .build(); - - hasGenerated = true; - - if (nextKeyGenerator != null) - { - privateKey = nextKeyGenerator.getNextKey(); - nextKeyGenerator = privateKey; - } - else + synchronized (privateKey) { - privateKey = null; + if (privateKey.getUsagesRemaining() <= 0) + { + throw new IllegalStateException("no usages of private key remaining"); + } + if (privateKey.getBDSState().getAuthenticationPath().isEmpty()) + { + throw new IllegalStateException("not initialized"); + } + + try + { + int index = privateKey.getIndex(); + + hasGenerated = true; + + /* create (randomized keyed) messageDigest of message */ + byte[] random = khf.PRF(privateKey.getSecretKeyPRF(), XMSSUtil.toBytesBigEndian(index, 32)); + byte[] concatenated = Arrays.concatenate(random, privateKey.getRoot(), + XMSSUtil.toBytesBigEndian(index, params.getTreeDigestSize())); + byte[] messageDigest = khf.HMsg(concatenated, message); + + /* create signature for messageDigest */ + OTSHashAddress otsHashAddress = (OTSHashAddress)new OTSHashAddress.Builder().withOTSAddress(index).build(); + WOTSPlusSignature wotsPlusSignature = wotsSign(messageDigest, otsHashAddress); + return new XMSSSignature.Builder(params).withIndex(index).withRandom(random) + .withWOTSPlusSignature(wotsPlusSignature) + .withAuthPath(privateKey.getBDSState().getAuthenticationPath()) + .build().toByteArray(); + } + finally + { + privateKey.getBDSState().markUsed(); + privateKey.rollKey(); + } } + } - return signature.toByteArray(); + public long getUsagesRemaining() + { + return privateKey.getUsagesRemaining(); } public boolean verifySignature(byte[] message, byte[] signature) @@ -102,11 +108,11 @@ public class XMSSSigner int index = sig.getIndex(); /* reinitialize WOTS+ object */ - params.getWOTSPlus().importKeys(new byte[params.getDigestSize()], publicKey.getPublicSeed()); + wotsPlus.importKeys(new byte[params.getTreeDigestSize()], publicKey.getPublicSeed()); /* create message digest */ byte[] concatenated = Arrays.concatenate(sig.getRandom(), publicKey.getRoot(), - XMSSUtil.toBytesBigEndian(index, params.getDigestSize())); + XMSSUtil.toBytesBigEndian(index, params.getTreeDigestSize())); byte[] messageDigest = khf.HMsg(concatenated, message); int xmssHeight = params.getHeight(); @@ -114,7 +120,7 @@ public class XMSSSigner /* get root from signature */ OTSHashAddress otsHashAddress = (OTSHashAddress)new OTSHashAddress.Builder().withOTSAddress(index).build(); - XMSSNode rootNodeFromSignature = XMSSVerifierUtil.getRootNodeFromSignature(params.getWOTSPlus(), xmssHeight, messageDigest, sig, otsHashAddress, indexLeaf); + XMSSNode rootNodeFromSignature = XMSSVerifierUtil.getRootNodeFromSignature(wotsPlus, xmssHeight, messageDigest, sig, otsHashAddress, indexLeaf); return Arrays.constantTimeAreEqual(rootNodeFromSignature.getValue(), publicKey.getRoot()); } @@ -123,28 +129,33 @@ public class XMSSSigner { // if we've generated a signature return the last private key generated // if we've only initialised leave it in place and return the next one instead. - if (hasGenerated) + synchronized (privateKey) { - XMSSPrivateKeyParameters privKey = privateKey; + if (hasGenerated) + { + XMSSPrivateKeyParameters privKey = privateKey; - privateKey = null; - nextKeyGenerator = null; + privateKey = null; - return privKey; - } - else - { - XMSSPrivateKeyParameters privKey = nextKeyGenerator.getNextKey(); + return privKey; + } + else + { + XMSSPrivateKeyParameters privKey = privateKey; - nextKeyGenerator = null; + if (privKey != null) + { + privateKey = privateKey.getNextKey(); + } - return privKey; + return privKey; + } } } private WOTSPlusSignature wotsSign(byte[] messageDigest, OTSHashAddress otsHashAddress) { - if (messageDigest.length != params.getDigestSize()) + if (messageDigest.length != params.getTreeDigestSize()) { throw new IllegalArgumentException("size of messageDigest needs to be equal to size of digest"); } @@ -153,8 +164,8 @@ public class XMSSSigner throw new NullPointerException("otsHashAddress == null"); } /* (re)initialize WOTS+ instance */ - params.getWOTSPlus().importKeys(params.getWOTSPlus().getWOTSPlusSecretKey(privateKey.getSecretKeySeed(), otsHashAddress), privateKey.getPublicSeed()); + wotsPlus.importKeys(wotsPlus.getWOTSPlusSecretKey(privateKey.getSecretKeySeed(), otsHashAddress), privateKey.getPublicSeed()); /* create WOTS+ signature */ - return params.getWOTSPlus().sign(messageDigest, otsHashAddress); + return wotsPlus.sign(messageDigest, otsHashAddress); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSStoreableObjectInterface.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSStoreableObjectInterface.java index cb758ab97..0161a69a9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSStoreableObjectInterface.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSStoreableObjectInterface.java @@ -3,13 +3,15 @@ package com.fr.third.org.bouncycastle.pqc.crypto.xmss; /** * Interface for XMSS objects that need to be storeable as a byte array. * + * @deprecated use Encodable */ -public interface XMSSStoreableObjectInterface { +public interface XMSSStoreableObjectInterface +{ - /** - * Create byte representation of object. - * - * @return Byte representation of object. - */ - public byte[] toByteArray(); + /** + * Create byte representation of object. + * + * @return Byte representation of object. + */ + public byte[] toByteArray(); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSVerifierUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSVerifierUtil.java index 0d090ce76..1ead6771c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSVerifierUtil.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/crypto/xmss/XMSSVerifierUtil.java @@ -12,7 +12,7 @@ class XMSSVerifierUtil static XMSSNode getRootNodeFromSignature(WOTSPlus wotsPlus, int height, byte[] messageDigest, XMSSReducedSignature signature, OTSHashAddress otsHashAddress, int indexLeaf) { - if (messageDigest.length != wotsPlus.getParams().getDigestSize()) + if (messageDigest.length != wotsPlus.getParams().getTreeDigestSize()) { throw new IllegalArgumentException("size of messageDigest needs to be equal to size of digest"); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/QTESLAKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/QTESLAKey.java new file mode 100644 index 000000000..1dbff9764 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/QTESLAKey.java @@ -0,0 +1,16 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.interfaces; + +import com.fr.third.org.bouncycastle.pqc.jcajce.spec.QTESLAParameterSpec; + +/** + * Base interface for a qTESLA key. + */ +public interface QTESLAKey +{ + /** + * Return the parameters for this key - in this case the security category. + * + * @return a QTESLAParameterSpec + */ + QTESLAParameterSpec getParams(); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/StateAwareSignature.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/StateAwareSignature.java index 42c89dd72..99bd8f1e8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/StateAwareSignature.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/StateAwareSignature.java @@ -12,6 +12,7 @@ import java.security.cert.Certificate; * This interface is implemented by Signature classes returned by the PQC provider where the signature * algorithm is one where the private key is updated for each signature generated. Examples of these * are algorithms such as GMSS, XMSS, and XMSS^MT. + * @deprecated it's better to avoid this and use extractKeyShard methods where possible. */ public interface StateAwareSignature { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/XMSSMTPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/XMSSMTPrivateKey.java new file mode 100644 index 000000000..eae419164 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/XMSSMTPrivateKey.java @@ -0,0 +1,27 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.interfaces; + +import java.security.PrivateKey; + +/** + * Base interface for an XMSSMT private key + */ +public interface XMSSMTPrivateKey + extends XMSSMTKey, PrivateKey +{ + /** + * Return the number of usages left for the private key. + * + * @return the number of times the key can be used before it is exhausted. + */ + long getUsagesRemaining(); + + /** + * Return a key representing a shard of the key space that can be used usageCount times. + *

+ * Note: this will use the range [index...index + usageCount) for the current key. + *

+ * @param usageCount the number of usages the key should have. + * @return a key based on the current key that can be used usageCount times. + */ + XMSSMTPrivateKey extractKeyShard(int usageCount); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/XMSSPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/XMSSPrivateKey.java new file mode 100644 index 000000000..e48f7b41d --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/interfaces/XMSSPrivateKey.java @@ -0,0 +1,27 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.interfaces; + +import java.security.PrivateKey; + +/** + * Base interface for an XMSS private key + */ +public interface XMSSPrivateKey + extends XMSSKey, PrivateKey +{ + /** + * Return the number of usages left for the private key. + * + * @return the number of times the key can be used before it is exhausted. + */ + long getUsagesRemaining(); + + /** + * Return a key representing a shard of the key space that can be used usageCount times. + *

+ * Note: this will use the range [index...index + usageCount) for the current key. + *

+ * @param usageCount the number of usages the key should have. + * @return a key based on the current key that can be used usageCount times. + */ + XMSSPrivateKey extractKeyShard(int usageCount); +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java index dc5dd7ba8..b21cf1084 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/BouncyCastlePQCProvider.java @@ -22,7 +22,7 @@ public class BouncyCastlePQCProvider extends Provider implements ConfigurableProvider { - private static String info = "BouncyCastle Post-Quantum Security Provider v1.60"; + private static String info = "BouncyCastle Post-Quantum Security Provider v1.64"; public static String PROVIDER_NAME = "BCPQC"; @@ -37,7 +37,7 @@ public class BouncyCastlePQCProvider private static final String ALGORITHM_PACKAGE = "com.fr.third.org.bouncycastle.pqc.jcajce.provider."; private static final String[] ALGORITHMS = { - "Rainbow", "McEliece", "SPHINCS", "NH", "XMSS" + "Rainbow", "McEliece", "SPHINCS", "NH", "XMSS", "QTESLA" }; /** @@ -47,7 +47,7 @@ public class BouncyCastlePQCProvider */ public BouncyCastlePQCProvider() { - super(PROVIDER_NAME, 1.60, info); + super(PROVIDER_NAME, 1.64, info); AccessController.doPrivileged(new PrivilegedAction() { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/QTESLA.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/QTESLA.java new file mode 100644 index 000000000..dbc72188b --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/QTESLA.java @@ -0,0 +1,34 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.provider; + +import com.fr.third.org.bouncycastle.jcajce.provider.config.ConfigurableProvider; +import com.fr.third.org.bouncycastle.jcajce.provider.util.AsymmetricAlgorithmProvider; +import com.fr.third.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; +import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; +import com.fr.third.org.bouncycastle.pqc.jcajce.provider.qtesla.QTESLAKeyFactorySpi; + +public class QTESLA +{ + private static final String PREFIX = "com.fr.third.org.bouncycastle.pqc.jcajce.provider" + ".qtesla."; + + public static class Mappings + extends AsymmetricAlgorithmProvider + { + public Mappings() + { + } + + public void configure(ConfigurableProvider provider) + { + provider.addAlgorithm("KeyFactory.QTESLA", PREFIX + "QTESLAKeyFactorySpi"); + provider.addAlgorithm("KeyPairGenerator.QTESLA", PREFIX + "KeyPairGeneratorSpi"); + + provider.addAlgorithm("Signature.QTESLA", PREFIX + "SignatureSpi$qTESLA"); + addSignatureAlgorithm(provider,"QTESLA-P-I", PREFIX + "SignatureSpi$PI", PQCObjectIdentifiers.qTESLA_p_I); + addSignatureAlgorithm(provider,"QTESLA-P-III", PREFIX + "SignatureSpi$PIII", PQCObjectIdentifiers.qTESLA_p_III); + + AsymmetricKeyInfoConverter keyFact = new QTESLAKeyFactorySpi(); + registerOid(provider, PQCObjectIdentifiers.qTESLA_p_I, "QTESLA-P-I", keyFact); + registerOid(provider, PQCObjectIdentifiers.qTESLA_p_III, "QTESLA-P-III", keyFact); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/XMSS.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/XMSS.java index e57e0f236..631b787f0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/XMSS.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/XMSS.java @@ -23,18 +23,36 @@ public class XMSS provider.addAlgorithm("KeyFactory.XMSS", PREFIX + "XMSSKeyFactorySpi"); provider.addAlgorithm("KeyPairGenerator.XMSS", PREFIX + "XMSSKeyPairGeneratorSpi"); - addSignatureAlgorithm(provider, "SHA256", "XMSS", PREFIX + "XMSSSignatureSpi$withSha256", BCObjectIdentifiers.xmss_with_SHA256); - addSignatureAlgorithm(provider, "SHAKE128", "XMSS", PREFIX + "XMSSSignatureSpi$withShake128", BCObjectIdentifiers.xmss_with_SHAKE128); - addSignatureAlgorithm(provider, "SHA512", "XMSS", PREFIX + "XMSSSignatureSpi$withSha512", BCObjectIdentifiers.xmss_with_SHA512); - addSignatureAlgorithm(provider, "SHAKE256", "XMSS", PREFIX + "XMSSSignatureSpi$withShake256", BCObjectIdentifiers.xmss_with_SHAKE256); + addSignatureAlgorithm(provider, "XMSS-SHA256", PREFIX + "XMSSSignatureSpi$withSha256", BCObjectIdentifiers.xmss_SHA256); + addSignatureAlgorithm(provider, "XMSS-SHAKE128", PREFIX + "XMSSSignatureSpi$withShake128", BCObjectIdentifiers.xmss_SHAKE128); + addSignatureAlgorithm(provider, "XMSS-SHA512", PREFIX + "XMSSSignatureSpi$withSha512", BCObjectIdentifiers.xmss_SHA512); + addSignatureAlgorithm(provider, "XMSS-SHAKE256", PREFIX + "XMSSSignatureSpi$withShake256", BCObjectIdentifiers.xmss_SHAKE256); + + addSignatureAlgorithm(provider, "SHA256", "XMSS-SHA256", PREFIX + "XMSSSignatureSpi$withSha256andPrehash", BCObjectIdentifiers.xmss_SHA256ph); + addSignatureAlgorithm(provider, "SHAKE128", "XMSS-SHAKE128", PREFIX + "XMSSSignatureSpi$withShake128andPrehash", BCObjectIdentifiers.xmss_SHAKE128ph); + addSignatureAlgorithm(provider, "SHA512", "XMSS-SHA512", PREFIX + "XMSSSignatureSpi$withSha512andPrehash", BCObjectIdentifiers.xmss_SHA512ph); + addSignatureAlgorithm(provider, "SHAKE256", "XMSS-SHAKE256", PREFIX + "XMSSSignatureSpi$withShake256andPrehash", BCObjectIdentifiers.xmss_SHAKE256ph); + provider.addAlgorithm("Alg.Alias.Signature.SHA256WITHXMSS", "SHA256WITHXMSS-SHA256"); + provider.addAlgorithm("Alg.Alias.Signature.SHAKE128WITHXMSS", "SHAKE128WITHXMSS-SHAKE128"); + provider.addAlgorithm("Alg.Alias.Signature.SHA512WITHXMSS", "SHA512WITHXMSS-SHA512"); + provider.addAlgorithm("Alg.Alias.Signature.SHAKE256WITHXMSS", "SHAKE256WITHXMSS-SHAKE256"); provider.addAlgorithm("KeyFactory.XMSSMT", PREFIX + "XMSSMTKeyFactorySpi"); provider.addAlgorithm("KeyPairGenerator.XMSSMT", PREFIX + "XMSSMTKeyPairGeneratorSpi"); - addSignatureAlgorithm(provider, "SHA256", "XMSSMT", PREFIX + "XMSSMTSignatureSpi$withSha256", BCObjectIdentifiers.xmss_mt_with_SHA256); - addSignatureAlgorithm(provider, "SHAKE128", "XMSSMT", PREFIX + "XMSSMTSignatureSpi$withShake128", BCObjectIdentifiers.xmss_mt_with_SHAKE128); - addSignatureAlgorithm(provider, "SHA512", "XMSSMT", PREFIX + "XMSSMTSignatureSpi$withSha512", BCObjectIdentifiers.xmss_mt_with_SHA512); - addSignatureAlgorithm(provider, "SHAKE256", "XMSSMT", PREFIX + "XMSSMTSignatureSpi$withShake256", BCObjectIdentifiers.xmss_mt_with_SHAKE256); + addSignatureAlgorithm(provider, "XMSSMT-SHA256", PREFIX + "XMSSMTSignatureSpi$withSha256", BCObjectIdentifiers.xmss_mt_SHA256); + addSignatureAlgorithm(provider, "XMSSMT-SHAKE128", PREFIX + "XMSSMTSignatureSpi$withShake128", BCObjectIdentifiers.xmss_mt_SHAKE128); + addSignatureAlgorithm(provider, "XMSSMT-SHA512", PREFIX + "XMSSMTSignatureSpi$withSha512", BCObjectIdentifiers.xmss_mt_SHA512); + addSignatureAlgorithm(provider, "XMSSMT-SHAKE256", PREFIX + "XMSSMTSignatureSpi$withShake256", BCObjectIdentifiers.xmss_mt_SHAKE256); + + addSignatureAlgorithm(provider, "SHA256", "XMSSMT-SHA256", PREFIX + "XMSSMTSignatureSpi$withSha256andPrehash", BCObjectIdentifiers.xmss_mt_SHA256ph); + addSignatureAlgorithm(provider, "SHAKE128", "XMSSMT-SHAKE128", PREFIX + "XMSSMTSignatureSpi$withShake128andPrehash", BCObjectIdentifiers.xmss_mt_SHAKE128ph); + addSignatureAlgorithm(provider, "SHA512", "XMSSMT-SHA512", PREFIX + "XMSSMTSignatureSpi$withSha512andPrehash", BCObjectIdentifiers.xmss_mt_SHA512ph); + addSignatureAlgorithm(provider, "SHAKE256", "XMSSMT-SHAKE256", PREFIX + "XMSSMTSignatureSpi$withShake256andPrehash", BCObjectIdentifiers.xmss_mt_SHAKE256ph); + provider.addAlgorithm("Alg.Alias.Signature.SHA256WITHXMSSMT", "SHA256WITHXMSSMT-SHA256"); + provider.addAlgorithm("Alg.Alias.Signature.SHAKE128WITHXMSSMT", "SHAKE128WITHXMSSMT-SHAKE128"); + provider.addAlgorithm("Alg.Alias.Signature.SHA512WITHXMSSMT", "SHA512WITHXMSSMT-SHA512"); + provider.addAlgorithm("Alg.Alias.Signature.SHAKE256WITHXMSSMT", "SHAKE256WITHXMSSMT-SHAKE256"); registerOid(provider, PQCObjectIdentifiers.xmss, "XMSS", new XMSSKeyFactorySpi()); registerOid(provider, PQCObjectIdentifiers.xmss_mt, "XMSSMT", new XMSSMTKeyFactorySpi()); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java index a47f1ac1b..a54bd52b9 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceCCA2KeyPairGeneratorSpi.java @@ -25,14 +25,27 @@ public class McElieceCCA2KeyPairGeneratorSpi super("McEliece-CCA2"); } + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + kpg = new McElieceCCA2KeyPairGenerator(); + + McElieceCCA2KeyGenParameterSpec ecc = (McElieceCCA2KeyGenParameterSpec)params; + + McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters( + random, new McElieceCCA2Parameters(ecc.getM(), ecc.getT(), ecc.getDigest())); + kpg.init(mccca2KGParams); + } + public void initialize(AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException { kpg = new McElieceCCA2KeyPairGenerator(); - super.initialize(params); + McElieceCCA2KeyGenParameterSpec ecc = (McElieceCCA2KeyGenParameterSpec)params; - McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters(CryptoServicesRegistrar.getSecureRandom(), new McElieceCCA2Parameters(ecc.getM(), ecc.getT(), ecc.getDigest())); + McElieceCCA2KeyGenerationParameters mccca2KGParams = new McElieceCCA2KeyGenerationParameters( + CryptoServicesRegistrar.getSecureRandom(), new McElieceCCA2Parameters(ecc.getM(), ecc.getT(), ecc.getDigest())); kpg.init(mccca2KGParams); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java index 2f5900f5c..f15a8cb85 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/mceliece/McElieceKeyPairGeneratorSpi.java @@ -7,7 +7,6 @@ import java.security.SecureRandom; import java.security.spec.AlgorithmParameterSpec; import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; -import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceKeyGenerationParameters; import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceKeyPairGenerator; import com.fr.third.org.bouncycastle.pqc.crypto.mceliece.McElieceParameters; @@ -24,15 +23,15 @@ public class McElieceKeyPairGeneratorSpi { super("McEliece"); } - - public void initialize(AlgorithmParameterSpec params) + + public void initialize(AlgorithmParameterSpec params, SecureRandom random) throws InvalidAlgorithmParameterException { kpg = new McElieceKeyPairGenerator(); - super.initialize(params); McElieceKeyGenParameterSpec ecc = (McElieceKeyGenParameterSpec)params; - McElieceKeyGenerationParameters mccKGParams = new McElieceKeyGenerationParameters(CryptoServicesRegistrar.getSecureRandom(), new McElieceParameters(ecc.getM(), ecc.getT())); + McElieceKeyGenerationParameters mccKGParams = new McElieceKeyGenerationParameters( + random, new McElieceParameters(ecc.getM(), ecc.getT())); kpg.init(mccKGParams); } @@ -43,7 +42,7 @@ public class McElieceKeyPairGeneratorSpi // call the initializer with the chosen parameters try { - this.initialize(paramSpec); + this.initialize(paramSpec, random); } catch (InvalidAlgorithmParameterException ae) { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPrivateKey.java index b5752e438..b336a9d04 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPrivateKey.java @@ -1,24 +1,25 @@ package com.fr.third.org.bouncycastle.pqc.jcajce.provider.newhope; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; -import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; -import com.fr.third.org.bouncycastle.asn1.DEROctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Set; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import com.fr.third.org.bouncycastle.pqc.crypto.newhope.NHPrivateKeyParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.NHPrivateKey; import com.fr.third.org.bouncycastle.util.Arrays; -import com.fr.third.org.bouncycastle.util.Pack; public class BCNHPrivateKey implements NHPrivateKey { private static final long serialVersionUID = 1L; - ; - private final NHPrivateKeyParameters params; + + private transient NHPrivateKeyParameters params; + private transient ASN1Set attributes; public BCNHPrivateKey( NHPrivateKeyParameters params) @@ -29,7 +30,14 @@ public class BCNHPrivateKey public BCNHPrivateKey(PrivateKeyInfo keyInfo) throws IOException { - this.params = new NHPrivateKeyParameters(convert(ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets())); + init(keyInfo); + } + + private void init(PrivateKeyInfo keyInfo) + throws IOException + { + this.attributes = keyInfo.getAttributes(); + this.params = (NHPrivateKeyParameters)PrivateKeyFactory.createKey(keyInfo); } /** @@ -40,7 +48,7 @@ public class BCNHPrivateKey */ public boolean equals(Object o) { - if (o == null || !(o instanceof BCNHPrivateKey)) + if (!(o instanceof BCNHPrivateKey)) { return false; } @@ -64,20 +72,9 @@ public class BCNHPrivateKey public byte[] getEncoded() { - PrivateKeyInfo pki; try { - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.newHope); - - short[] privateKeyData = params.getSecData(); - - byte[] octets = new byte[privateKeyData.length * 2]; - for (int i = 0; i != privateKeyData.length; i++) - { - Pack.shortToLittleEndian(privateKeyData[i], octets, i * 2); - } - - pki = new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(octets)); + PrivateKeyInfo pki = PrivateKeyInfoFactory.createPrivateKeyInfo(params, attributes); return pki.getEncoded(); } @@ -102,15 +99,23 @@ public class BCNHPrivateKey return params; } - private static short[] convert(byte[] octets) + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException { - short[] rv = new short[octets.length / 2]; + in.defaultReadObject(); - for (int i = 0; i != rv.length; i++) - { - rv[i] = Pack.littleEndianToShort(octets, i * 2); - } + byte[] enc = (byte[])in.readObject(); + + init(PrivateKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); - return rv; + out.writeObject(this.getEncoded()); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPublicKey.java index b7e481c06..39be03a26 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/newhope/BCNHPublicKey.java @@ -1,12 +1,14 @@ package com.fr.third.org.bouncycastle.pqc.jcajce.provider.newhope; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; -import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import com.fr.third.org.bouncycastle.pqc.crypto.newhope.NHPublicKeyParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PublicKeyFactory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.NHPublicKey; import com.fr.third.org.bouncycastle.util.Arrays; @@ -15,7 +17,7 @@ public class BCNHPublicKey { private static final long serialVersionUID = 1L; - private final NHPublicKeyParameters params; + private transient NHPublicKeyParameters params; public BCNHPublicKey( NHPublicKeyParameters params) @@ -24,8 +26,15 @@ public class BCNHPublicKey } public BCNHPublicKey(SubjectPublicKeyInfo keyInfo) + throws IOException { - this.params = new NHPublicKeyParameters(keyInfo.getPublicKeyData().getBytes()); + init(keyInfo); + } + + private void init(SubjectPublicKeyInfo keyInfo) + throws IOException + { + this.params = (NHPublicKeyParameters)PublicKeyFactory.createKey(keyInfo); } /** @@ -60,11 +69,9 @@ public class BCNHPublicKey public byte[] getEncoded() { - SubjectPublicKeyInfo pki; try { - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.newHope); - pki = new SubjectPublicKeyInfo(algorithmIdentifier, params.getPubData()); + SubjectPublicKeyInfo pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(params); return pki.getEncoded(); } @@ -88,4 +95,24 @@ public class BCNHPublicKey { return params; } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(SubjectPublicKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/BCqTESLAPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/BCqTESLAPrivateKey.java new file mode 100644 index 000000000..99cfc7f75 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/BCqTESLAPrivateKey.java @@ -0,0 +1,126 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.provider.qtesla; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PrivateKey; + +import com.fr.third.org.bouncycastle.asn1.ASN1Set; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLAPrivateKeyParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLASecurityCategory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; +import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.QTESLAKey; +import com.fr.third.org.bouncycastle.pqc.jcajce.spec.QTESLAParameterSpec; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class BCqTESLAPrivateKey + implements PrivateKey, QTESLAKey +{ + private static final long serialVersionUID = 1L; + + private transient QTESLAPrivateKeyParameters keyParams; + private transient ASN1Set attributes; + + public BCqTESLAPrivateKey( + QTESLAPrivateKeyParameters keyParams) + { + this.keyParams = keyParams; + } + + public BCqTESLAPrivateKey(PrivateKeyInfo keyInfo) + throws IOException + { + init(keyInfo); + } + + private void init(PrivateKeyInfo keyInfo) + throws IOException + { + this.attributes = keyInfo.getAttributes(); + this.keyParams = (QTESLAPrivateKeyParameters)PrivateKeyFactory.createKey(keyInfo); + } + + /** + * @return name of the algorithm + */ + public final String getAlgorithm() + { + return QTESLASecurityCategory.getName(keyParams.getSecurityCategory()); + } + + public String getFormat() + { + return "PKCS#8"; + } + + public QTESLAParameterSpec getParams() + { + return new QTESLAParameterSpec(getAlgorithm()); + } + + public byte[] getEncoded() + { + PrivateKeyInfo pki; + try + { + pki = PrivateKeyInfoFactory.createPrivateKeyInfo(keyParams, attributes); + + return pki.getEncoded(); + } + catch (IOException e) + { + return null; + } + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof BCqTESLAPrivateKey) + { + BCqTESLAPrivateKey otherKey = (BCqTESLAPrivateKey)o; + + return keyParams.getSecurityCategory() == otherKey.keyParams.getSecurityCategory() + && Arrays.areEqual(keyParams.getSecret(), otherKey.keyParams.getSecret()); + } + + return false; + } + + public int hashCode() + { + return keyParams.getSecurityCategory() + 37 * Arrays.hashCode(keyParams.getSecret()); + } + + CipherParameters getKeyParams() + { + return keyParams; + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(PrivateKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/BCqTESLAPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/BCqTESLAPublicKey.java new file mode 100644 index 000000000..52e25ca86 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/BCqTESLAPublicKey.java @@ -0,0 +1,122 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.provider.qtesla; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.security.PublicKey; + +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLAPublicKeyParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLASecurityCategory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PublicKeyFactory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; +import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.QTESLAKey; +import com.fr.third.org.bouncycastle.pqc.jcajce.spec.QTESLAParameterSpec; +import com.fr.third.org.bouncycastle.util.Arrays; + +public class BCqTESLAPublicKey + implements PublicKey, QTESLAKey +{ + private static final long serialVersionUID = 1L; + + private transient QTESLAPublicKeyParameters keyParams; + + public BCqTESLAPublicKey( + QTESLAPublicKeyParameters keyParams) + { + this.keyParams = keyParams; + } + + public BCqTESLAPublicKey(SubjectPublicKeyInfo keyInfo) + throws IOException + { + init(keyInfo); + } + + private void init(SubjectPublicKeyInfo keyInfo) + throws IOException + { + this.keyParams = (QTESLAPublicKeyParameters)PublicKeyFactory.createKey(keyInfo); + } + + /** + * @return name of the algorithm + */ + public final String getAlgorithm() + { + return QTESLASecurityCategory.getName(keyParams.getSecurityCategory()); + } + + public byte[] getEncoded() + { + try + { + SubjectPublicKeyInfo pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(keyParams); + + return pki.getEncoded(); + } + catch (IOException e) + { + return null; + } + } + + public String getFormat() + { + return "X.509"; + } + + public QTESLAParameterSpec getParams() + { + return new QTESLAParameterSpec(getAlgorithm()); + } + + CipherParameters getKeyParams() + { + return keyParams; + } + + public boolean equals(Object o) + { + if (o == this) + { + return true; + } + + if (o instanceof BCqTESLAPublicKey) + { + BCqTESLAPublicKey otherKey = (BCqTESLAPublicKey)o; + + return keyParams.getSecurityCategory() == otherKey.keyParams.getSecurityCategory() + && Arrays.areEqual(keyParams.getPublicData(), otherKey.keyParams.getPublicData()); + } + + return false; + } + + public int hashCode() + { + return keyParams.getSecurityCategory() + 37 * Arrays.hashCode(keyParams.getPublicData()); + } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(SubjectPublicKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/DigestUtil.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/DigestUtil.java new file mode 100644 index 000000000..35d95c7e9 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/DigestUtil.java @@ -0,0 +1,60 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.provider.qtesla; + +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.Xof; +import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; +import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest; + +class DigestUtil +{ + static Digest getDigest(ASN1ObjectIdentifier oid) + { + if (oid.equals(NISTObjectIdentifiers.id_sha256)) + { + return new SHA256Digest(); + } + if (oid.equals(NISTObjectIdentifiers.id_sha512)) + { + return new SHA512Digest(); + } + if (oid.equals(NISTObjectIdentifiers.id_shake128)) + { + return new SHAKEDigest(128); + } + if (oid.equals(NISTObjectIdentifiers.id_shake256)) + { + return new SHAKEDigest(256); + } + + throw new IllegalArgumentException("unrecognized digest OID: " + oid); + } + + public static byte[] getDigestResult(Digest digest) + { + byte[] hash = new byte[DigestUtil.getDigestSize(digest)]; + + if (digest instanceof Xof) + { + ((Xof)digest).doFinal(hash, 0, hash.length); + } + else + { + digest.doFinal(hash, 0); + } + + return hash; + } + + public static int getDigestSize(Digest digest) + { + if (digest instanceof Xof) + { + return digest.getDigestSize() * 2; + } + + return digest.getDigestSize(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/KeyPairGeneratorSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/KeyPairGeneratorSpi.java new file mode 100644 index 000000000..f6aebafed --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/KeyPairGeneratorSpi.java @@ -0,0 +1,83 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.provider.qtesla; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.Map; + +import com.fr.third.org.bouncycastle.crypto.AsymmetricCipherKeyPair; +import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLAKeyGenerationParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLAKeyPairGenerator; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLAPrivateKeyParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLAPublicKeyParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLASecurityCategory; +import com.fr.third.org.bouncycastle.pqc.jcajce.spec.QTESLAParameterSpec; +import com.fr.third.org.bouncycastle.util.Integers; + +public class KeyPairGeneratorSpi + extends java.security.KeyPairGenerator +{ + private static final Map catLookup = new HashMap(); + + static + { + catLookup.put(QTESLASecurityCategory.getName(QTESLASecurityCategory.PROVABLY_SECURE_I), Integers.valueOf(QTESLASecurityCategory.PROVABLY_SECURE_I)); + catLookup.put(QTESLASecurityCategory.getName(QTESLASecurityCategory.PROVABLY_SECURE_III), Integers.valueOf(QTESLASecurityCategory.PROVABLY_SECURE_III)); + } + + private QTESLAKeyGenerationParameters param; + private QTESLAKeyPairGenerator engine = new QTESLAKeyPairGenerator(); + + private SecureRandom random = CryptoServicesRegistrar.getSecureRandom(); + private boolean initialised = false; + + public KeyPairGeneratorSpi() + { + super("qTESLA"); + } + + public void initialize( + int strength, + SecureRandom random) + { + throw new IllegalArgumentException("use AlgorithmParameterSpec"); + } + + public void initialize( + AlgorithmParameterSpec params, + SecureRandom random) + throws InvalidAlgorithmParameterException + { + if (!(params instanceof QTESLAParameterSpec)) + { + throw new InvalidAlgorithmParameterException("parameter object not a QTESLAParameterSpec"); + } + + QTESLAParameterSpec qteslaParams = (QTESLAParameterSpec)params; + + param = new QTESLAKeyGenerationParameters(((Integer)catLookup.get(qteslaParams.getSecurityCategory())).intValue(), random); + + engine.init(param); + initialised = true; + } + + public KeyPair generateKeyPair() + { + if (!initialised) + { + param = new QTESLAKeyGenerationParameters(QTESLASecurityCategory.PROVABLY_SECURE_III, random); + + engine.init(param); + initialised = true; + } + + AsymmetricCipherKeyPair pair = engine.generateKeyPair(); + QTESLAPublicKeyParameters pub = (QTESLAPublicKeyParameters)pair.getPublic(); + QTESLAPrivateKeyParameters priv = (QTESLAPrivateKeyParameters)pair.getPrivate(); + + return new KeyPair(new BCqTESLAPublicKey(pub), new BCqTESLAPrivateKey(priv)); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/QTESLAKeyFactorySpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/QTESLAKeyFactorySpi.java new file mode 100644 index 000000000..235bb59d6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/QTESLAKeyFactorySpi.java @@ -0,0 +1,116 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.provider.qtesla; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +import com.fr.third.org.bouncycastle.asn1.ASN1Primitive; +import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import com.fr.third.org.bouncycastle.jcajce.provider.util.AsymmetricKeyInfoConverter; + +public class QTESLAKeyFactorySpi + extends KeyFactorySpi + implements AsymmetricKeyInfoConverter +{ + public PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof PKCS8EncodedKeySpec) + { + // get the DER-encoded Key according to PKCS#8 from the spec + byte[] encKey = ((PKCS8EncodedKeySpec)keySpec).getEncoded(); + + try + { + return generatePrivate(PrivateKeyInfo.getInstance(ASN1Primitive.fromByteArray(encKey))); + } + catch (Exception e) + { + throw new InvalidKeySpecException(e.toString()); + } + } + + throw new InvalidKeySpecException("Unsupported key specification: " + + keySpec.getClass() + "."); + } + + public PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof X509EncodedKeySpec) + { + // get the DER-encoded Key according to X.509 from the spec + byte[] encKey = ((X509EncodedKeySpec)keySpec).getEncoded(); + + // decode the SubjectPublicKeyInfo data structure to the pki object + try + { + return generatePublic(SubjectPublicKeyInfo.getInstance(encKey)); + } + catch (Exception e) + { + throw new InvalidKeySpecException(e.toString()); + } + } + + throw new InvalidKeySpecException("Unknown key specification: " + keySpec + "."); + } + + public final KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof BCqTESLAPrivateKey) + { + if (PKCS8EncodedKeySpec.class.isAssignableFrom(keySpec)) + { + return new PKCS8EncodedKeySpec(key.getEncoded()); + } + } + else if (key instanceof BCqTESLAPublicKey) + { + if (X509EncodedKeySpec.class.isAssignableFrom(keySpec)) + { + return new X509EncodedKeySpec(key.getEncoded()); + } + } + else + { + throw new InvalidKeySpecException("Unsupported key type: " + + key.getClass() + "."); + } + + throw new InvalidKeySpecException("Unknown key specification: " + + keySpec + "."); + } + + public final Key engineTranslateKey(Key key) + throws InvalidKeyException + { + if (key instanceof BCqTESLAPrivateKey || key instanceof BCqTESLAPublicKey) + { + return key; + } + + throw new InvalidKeyException("Unsupported key type"); + } + + public PrivateKey generatePrivate(PrivateKeyInfo keyInfo) + throws IOException + { + return new BCqTESLAPrivateKey(keyInfo); + } + + public PublicKey generatePublic(SubjectPublicKeyInfo keyInfo) + throws IOException + { + return new BCqTESLAPublicKey(keyInfo); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/SignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/SignatureSpi.java new file mode 100644 index 000000000..84b7c8a00 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/qtesla/SignatureSpi.java @@ -0,0 +1,168 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.provider.qtesla; + +import java.security.InvalidKeyException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.AlgorithmParameterSpec; + +import com.fr.third.org.bouncycastle.crypto.CipherParameters; +import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.NullDigest; +import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLASecurityCategory; +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLASigner; + +public class SignatureSpi + extends Signature +{ + protected SignatureSpi(String algorithm) + { + super(algorithm); + } + + private Digest digest; + private QTESLASigner signer; + private SecureRandom random; + + protected SignatureSpi(String sigName, Digest digest, QTESLASigner signer) + { + super(sigName); + + this.digest = digest; + this.signer = signer; + } + + protected void engineInitVerify(PublicKey publicKey) + throws InvalidKeyException + { + if (publicKey instanceof BCqTESLAPublicKey) + { + CipherParameters param = ((BCqTESLAPublicKey)publicKey).getKeyParams(); + + digest.reset(); + signer.init(false, param); + } + else + { + throw new InvalidKeyException("unknown public key passed to qTESLA"); + } + } + + protected void engineInitSign(PrivateKey privateKey, SecureRandom random) + throws InvalidKeyException + { + this.random = random; + engineInitSign(privateKey); + } + + protected void engineInitSign(PrivateKey privateKey) + throws InvalidKeyException + { + if (privateKey instanceof BCqTESLAPrivateKey) + { + CipherParameters param = ((BCqTESLAPrivateKey)privateKey).getKeyParams(); + + if (random != null) + { + param = new ParametersWithRandom(param, random); + } + + signer.init(true, param); + } + else + { + throw new InvalidKeyException("unknown private key passed to qTESLA"); + } + } + + protected void engineUpdate(byte b) + throws SignatureException + { + digest.update(b); + } + + protected void engineUpdate(byte[] b, int off, int len) + throws SignatureException + { + digest.update(b, off, len); + } + + protected byte[] engineSign() + throws SignatureException + { + try + { + byte[] hash = DigestUtil.getDigestResult(digest); + + return signer.generateSignature(hash); + } + catch (Exception e) + { + if (e instanceof IllegalStateException) + { + throw new SignatureException(e.getMessage()); + } + throw new SignatureException(e.toString()); + } + } + + protected boolean engineVerify(byte[] sigBytes) + throws SignatureException + { + byte[] hash = DigestUtil.getDigestResult(digest); + + return signer.verifySignature(hash, sigBytes); + } + + protected void engineSetParameter(AlgorithmParameterSpec params) + { + throw new UnsupportedOperationException("engineSetParameter unsupported"); + } + + /** + * @deprecated replaced with #engineSetParameter(java.security.spec.AlgorithmParameterSpec) + */ + protected void engineSetParameter(String param, Object value) + { + throw new UnsupportedOperationException("engineSetParameter unsupported"); + } + + /** + * @deprecated + */ + protected Object engineGetParameter(String param) + { + throw new UnsupportedOperationException("engineSetParameter unsupported"); + } + + static public class qTESLA + extends SignatureSpi + { + public qTESLA() + { + super("qTESLA", new NullDigest(), new QTESLASigner()); + } + } + + + static public class PI + extends SignatureSpi + { + public PI() + { + super(QTESLASecurityCategory.getName(QTESLASecurityCategory.PROVABLY_SECURE_I), new NullDigest(), new QTESLASigner()); + } + } + + static public class PIII + extends SignatureSpi + { + public PIII() + { + super(QTESLASecurityCategory.getName(QTESLASecurityCategory.PROVABLY_SECURE_III), new NullDigest(), new QTESLASigner()); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PrivateKey.java index 1ba6e8c20..d56b54003 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PrivateKey.java @@ -1,10 +1,12 @@ package com.fr.third.org.bouncycastle.pqc.jcajce.provider.sphincs; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.security.PrivateKey; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; -import com.fr.third.org.bouncycastle.asn1.ASN1OctetString; +import com.fr.third.org.bouncycastle.asn1.ASN1Set; import com.fr.third.org.bouncycastle.asn1.DEROctetString; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; @@ -12,6 +14,8 @@ import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import com.fr.third.org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCSPrivateKeyParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.SPHINCSKey; import com.fr.third.org.bouncycastle.util.Arrays; @@ -20,8 +24,9 @@ public class BCSphincs256PrivateKey { private static final long serialVersionUID = 1L; - private final ASN1ObjectIdentifier treeDigest; - private final SPHINCSPrivateKeyParameters params; + private transient ASN1ObjectIdentifier treeDigest; + private transient SPHINCSPrivateKeyParameters params; + private transient ASN1Set attributes; public BCSphincs256PrivateKey( ASN1ObjectIdentifier treeDigest, @@ -34,8 +39,15 @@ public class BCSphincs256PrivateKey public BCSphincs256PrivateKey(PrivateKeyInfo keyInfo) throws IOException { + init(keyInfo); + } + + private void init(PrivateKeyInfo keyInfo) + throws IOException + { + this.attributes = keyInfo.getAttributes(); this.treeDigest = SPHINCS256KeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters()).getTreeDigest().getAlgorithm(); - this.params = new SPHINCSPrivateKeyParameters(ASN1OctetString.getInstance(keyInfo.parsePrivateKey()).getOctets()); + this.params = (SPHINCSPrivateKeyParameters)PrivateKeyFactory.createKey(keyInfo); } /** @@ -76,11 +88,20 @@ public class BCSphincs256PrivateKey public byte[] getEncoded() { - PrivateKeyInfo pki; + try { - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.sphincs256, new SPHINCS256KeyParams(new AlgorithmIdentifier(treeDigest))); - pki = new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getKeyData())); + PrivateKeyInfo pki; + if (params.getTreeDigest() != null) + { + pki = PrivateKeyInfoFactory.createPrivateKeyInfo(params, attributes); + } + else + { + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.sphincs256, + new SPHINCS256KeyParams(new AlgorithmIdentifier(treeDigest))); + pki = new PrivateKeyInfo(algorithmIdentifier, new DEROctetString(params.getKeyData()), attributes); + } return pki.getEncoded(); } @@ -95,6 +116,11 @@ public class BCSphincs256PrivateKey return "PKCS#8"; } + ASN1ObjectIdentifier getTreeDigest() + { + return treeDigest; + } + public byte[] getKeyData() { return params.getKeyData(); @@ -104,4 +130,24 @@ public class BCSphincs256PrivateKey { return params; } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(PrivateKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PublicKey.java index edcf00bf5..fd1003a90 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/BCSphincs256PublicKey.java @@ -1,6 +1,8 @@ package com.fr.third.org.bouncycastle.pqc.jcajce.provider.sphincs; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.security.PublicKey; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; @@ -10,6 +12,8 @@ import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import com.fr.third.org.bouncycastle.pqc.asn1.SPHINCS256KeyParams; import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCSPublicKeyParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PublicKeyFactory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.SPHINCSKey; import com.fr.third.org.bouncycastle.util.Arrays; @@ -18,8 +22,8 @@ public class BCSphincs256PublicKey { private static final long serialVersionUID = 1L; - private final ASN1ObjectIdentifier treeDigest; - private final SPHINCSPublicKeyParameters params; + private transient ASN1ObjectIdentifier treeDigest; + private transient SPHINCSPublicKeyParameters params; public BCSphincs256PublicKey( ASN1ObjectIdentifier treeDigest, @@ -30,11 +34,18 @@ public class BCSphincs256PublicKey } public BCSphincs256PublicKey(SubjectPublicKeyInfo keyInfo) + throws IOException { - this.treeDigest = SPHINCS256KeyParams.getInstance(keyInfo.getAlgorithm().getParameters()).getTreeDigest().getAlgorithm(); - this.params = new SPHINCSPublicKeyParameters(keyInfo.getPublicKeyData().getBytes()); + init(keyInfo); } + private void init(SubjectPublicKeyInfo keyInfo) + throws IOException + { + this.treeDigest = SPHINCS256KeyParams.getInstance(keyInfo.getAlgorithm().getParameters()).getTreeDigest().getAlgorithm(); + this.params = (SPHINCSPublicKeyParameters)PublicKeyFactory.createKey(keyInfo); + } + /** * Compare this SPHINCS-256 public key with another object. * @@ -73,11 +84,19 @@ public class BCSphincs256PublicKey public byte[] getEncoded() { - SubjectPublicKeyInfo pki; try { - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.sphincs256, new SPHINCS256KeyParams(new AlgorithmIdentifier(treeDigest))); - pki = new SubjectPublicKeyInfo(algorithmIdentifier, params.getKeyData()); + SubjectPublicKeyInfo pki; + + if (params.getTreeDigest() != null) + { + pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(params); + } + else + { + AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.sphincs256, new SPHINCS256KeyParams(new AlgorithmIdentifier(treeDigest))); + pki = new SubjectPublicKeyInfo(algorithmIdentifier, params.getKeyData()); + } return pki.getEncoded(); } @@ -97,8 +116,33 @@ public class BCSphincs256PublicKey return params.getKeyData(); } + ASN1ObjectIdentifier getTreeDigest() + { + return treeDigest; + } + CipherParameters getKeyParams() { return params; } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(SubjectPublicKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/SignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/SignatureSpi.java index 658140453..2816ca8d7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/SignatureSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/sphincs/SignatureSpi.java @@ -7,24 +7,27 @@ import java.security.SecureRandom; import java.security.SignatureException; import java.security.spec.AlgorithmParameterSpec; +import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.nist.NISTObjectIdentifiers; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.Digest; import com.fr.third.org.bouncycastle.crypto.digests.SHA3Digest; import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; import com.fr.third.org.bouncycastle.crypto.digests.SHA512tDigest; -import com.fr.third.org.bouncycastle.crypto.params.ParametersWithRandom; import com.fr.third.org.bouncycastle.pqc.crypto.sphincs.SPHINCS256Signer; public class SignatureSpi extends java.security.SignatureSpi { + private final ASN1ObjectIdentifier treeDigest; private Digest digest; private SPHINCS256Signer signer; private SecureRandom random; - protected SignatureSpi(Digest digest, SPHINCS256Signer signer) + protected SignatureSpi(Digest digest, ASN1ObjectIdentifier treeDigest, SPHINCS256Signer signer) { this.digest = digest; + this.treeDigest = treeDigest; this.signer = signer; } @@ -33,7 +36,12 @@ public class SignatureSpi { if (publicKey instanceof BCSphincs256PublicKey) { - CipherParameters param = ((BCSphincs256PublicKey)publicKey).getKeyParams(); + BCSphincs256PublicKey key = (BCSphincs256PublicKey)publicKey; + if (!treeDigest.equals(key.getTreeDigest())) + { + throw new InvalidKeyException("SPHINCS-256 signature for tree digest: " + key.getTreeDigest()); + } + CipherParameters param = key.getKeyParams(); digest.reset(); signer.init(false, param); @@ -56,13 +64,20 @@ public class SignatureSpi { if (privateKey instanceof BCSphincs256PrivateKey) { - CipherParameters param = ((BCSphincs256PrivateKey)privateKey).getKeyParams(); - - if (random != null) + BCSphincs256PrivateKey key = (BCSphincs256PrivateKey)privateKey; + if (!treeDigest.equals(key.getTreeDigest())) { - param = new ParametersWithRandom(param, random); + throw new InvalidKeyException("SPHINCS-256 signature for tree digest: " + key.getTreeDigest()); } + CipherParameters param = key.getKeyParams(); + + // random not required for SPHINCS. +// if (random != null) +// { +// param = new ParametersWithRandom(param, random); +// } + digest.reset(); signer.init(true, param); } @@ -106,6 +121,7 @@ public class SignatureSpi { byte[] hash = new byte[digest.getDigestSize()]; digest.doFinal(hash, 0); + return signer.verifySignature(hash, sigBytes); } @@ -136,7 +152,7 @@ public class SignatureSpi { public withSha512() { - super(new SHA512Digest(), new SPHINCS256Signer(new SHA512tDigest(256), new SHA512Digest())); + super(new SHA512Digest(), NISTObjectIdentifiers.id_sha512_256, new SPHINCS256Signer(new SHA512tDigest(256), new SHA512Digest())); } } @@ -145,7 +161,7 @@ public class SignatureSpi { public withSha3_512() { - super(new SHA3Digest(512), new SPHINCS256Signer(new SHA3Digest(256), new SHA3Digest(512))); + super(new SHA3Digest(512), NISTObjectIdentifiers.id_sha3_256, new SPHINCS256Signer(new SHA3Digest(256), new SHA3Digest(512))); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/test/PQCSigUtils.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/test/PQCSigUtils.java new file mode 100644 index 000000000..e022ee48f --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/test/PQCSigUtils.java @@ -0,0 +1,33 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.provider.test; + +import com.fr.third.org.bouncycastle.util.Arrays; + +public class PQCSigUtils +{ + static class SigWrapper + { + private final byte[] sig; + + SigWrapper(byte[] sig) + { + this.sig = sig; + } + + public boolean equals(Object o) + { + if (o instanceof SigWrapper) + { + SigWrapper other = (SigWrapper)o; + + return Arrays.areEqual(other.sig, this.sig); + } + + return false; + } + + public int hashCode() + { + return Arrays.hashCode(this.sig); + } + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/test/QTESLASecureRandomFactory.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/test/QTESLASecureRandomFactory.java new file mode 100644 index 000000000..b884ff3e8 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/test/QTESLASecureRandomFactory.java @@ -0,0 +1,181 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.provider.test; + +import javax.crypto.Cipher; +import javax.crypto.spec.SecretKeySpec; + +import com.fr.third.org.bouncycastle.util.test.FixedSecureRandom; + +/** + * Factory for producing FixedSecureRandom objects for use with testsing + */ +class QTESLASecureRandomFactory +{ + private byte[] seed; + private byte[] personalization; + private byte[] key; + private byte[] v; + int reseed_counuter = 1; + + + /** + * Return a seeded FixedSecureRandom representing the result of processing a + * qTESLA test seed with the qTESLA RandomNumberGenerator. + * + * @param seed original qTESLA seed + * @param strength bit-strength of the RNG required. + * @return a FixedSecureRandom containing the correct amount of seed material for use with Java. + */ + public static FixedSecureRandom getFixed(byte[] seed, int strength) + { + return getFixed(seed,null, strength, strength / 8, strength / 8); + } + + public static FixedSecureRandom getFixed(byte[] seed, byte[] personalization, int strength, int discard, int size) + { + QTESLASecureRandomFactory teslaRNG = new QTESLASecureRandomFactory(seed, personalization); + teslaRNG.init(strength); + byte[] burn = new byte[discard]; + teslaRNG.nextBytes(burn); + if (discard != size) + { + burn = new byte[size]; + } + teslaRNG.nextBytes(burn); + return new FixedSecureRandom(burn); + } + + + private QTESLASecureRandomFactory(byte[] seed, byte[] personalization) + { + this.seed = seed; + this.personalization = personalization; + } + + + private void init(int strength) + { + randombytes_init(seed, personalization, strength); + reseed_counuter = 1; + } + + private void nextBytes(byte[] x) + { + byte[] block = new byte[16]; + int i = 0; + + int xlen = x.length; + + while (xlen > 0) + { + for (int j = 15; j >= 0; j--) + { + if ((v[j] & 0xFF) == 0xff) + { + v[j] = 0x00; + } + else + { + v[j]++; + break; + } + } + + AES256_ECB(key, v, block, 0); + + if (xlen > 15) + { + System.arraycopy(block, 0, x, i, block.length); + i += 16; + xlen -= 16; + } + else + { + System.arraycopy(block, 0, x, i, xlen); + xlen = 0; + } + } + + AES256_CTR_DRBG_Update(null, key, v); + reseed_counuter++; + } + + + private void AES256_ECB(byte[] key, byte[] ctr, byte[] buffer, int startPosition) + { + try + { + Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding"); + + cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key, "AES")); + + cipher.doFinal(ctr, 0, ctr.length, buffer, startPosition); + } + catch (Throwable ex) + { + ex.printStackTrace(); + } + } + + + private void AES256_CTR_DRBG_Update(byte[] entropy_input, byte[] key, byte[] v) + { + + byte[] tmp = new byte[48]; + + for (int i = 0; i < 3; i++) + { + //increment V + for (int j = 15; j >= 0; j--) + { + if ((v[j] & 0xFF) == 0xff) + { + v[j] = 0x00; + } + else + { + v[j]++; + break; + } + } + + AES256_ECB(key, v, tmp, 16 * i); + } + + if (entropy_input != null) + { + for (int i = 0; i < 48; i++) + { + tmp[i] ^= entropy_input[i]; + } + } + + System.arraycopy(tmp, 0, key, 0, key.length); + System.arraycopy(tmp, 32, v, 0, v.length); + + + } + + + private void randombytes_init(byte[] entropyInput, byte[] personalization, int strength) + { + byte[] seedMaterial = new byte[48]; + + System.arraycopy(entropyInput, 0, seedMaterial, 0, seedMaterial.length); + if (personalization != null) + { + for (int i = 0; i < 48; i++) + { + seedMaterial[i] ^= personalization[i]; + } + } + + key = new byte[32]; + v = new byte[16]; + + + AES256_CTR_DRBG_Update(seedMaterial, key, v); + + reseed_counuter = 1; + + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java index 33d2d704c..d11cf6f38 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/util/AsymmetricBlockCipher.java @@ -104,7 +104,7 @@ public abstract class AsymmetricBlockCipher return 0; } - return maxLen; + return opMode == ENCRYPT_MODE ? cipherTextSize : maxPlainTextSize; } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSMTPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSMTPrivateKey.java index 9aa683b97..9490b312b 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSMTPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSMTPrivateKey.java @@ -1,28 +1,29 @@ package com.fr.third.org.bouncycastle.pqc.jcajce.provider.xmss; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.security.PrivateKey; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Set; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import com.fr.third.org.bouncycastle.pqc.asn1.XMSSMTKeyParams; -import com.fr.third.org.bouncycastle.pqc.asn1.XMSSMTPrivateKey; -import com.fr.third.org.bouncycastle.pqc.asn1.XMSSPrivateKey; -import com.fr.third.org.bouncycastle.pqc.crypto.xmss.BDSStateMap; -import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSMTParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSMTPrivateKeyParameters; -import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSUtil; -import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.XMSSMTKey; +import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.XMSSMTPrivateKey; import com.fr.third.org.bouncycastle.util.Arrays; public class BCXMSSMTPrivateKey - implements PrivateKey, XMSSMTKey + implements PrivateKey, XMSSMTPrivateKey { - private final ASN1ObjectIdentifier treeDigest; - private final XMSSMTPrivateKeyParameters keyParams; + private static final long serialVersionUID = 7682140473044521395L; + + private transient ASN1ObjectIdentifier treeDigest; + private transient XMSSMTPrivateKeyParameters keyParams; + private transient ASN1Set attributes; public BCXMSSMTPrivateKey( ASN1ObjectIdentifier treeDigest, @@ -35,32 +36,26 @@ public class BCXMSSMTPrivateKey public BCXMSSMTPrivateKey(PrivateKeyInfo keyInfo) throws IOException { + init(keyInfo); + } + + private void init(PrivateKeyInfo keyInfo) + throws IOException + { + this.attributes = keyInfo.getAttributes(); XMSSMTKeyParams keyParams = XMSSMTKeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters()); this.treeDigest = keyParams.getTreeDigest().getAlgorithm(); + this.keyParams = (XMSSMTPrivateKeyParameters)PrivateKeyFactory.createKey(keyInfo); + } - XMSSPrivateKey xmssMtPrivateKey = XMSSPrivateKey.getInstance(keyInfo.parsePrivateKey()); + public long getUsagesRemaining() + { + return keyParams.getUsagesRemaining(); + } - try - { - XMSSMTPrivateKeyParameters.Builder keyBuilder = new XMSSMTPrivateKeyParameters - .Builder(new XMSSMTParameters(keyParams.getHeight(), keyParams.getLayers(), DigestUtil.getDigest(treeDigest))) - .withIndex(xmssMtPrivateKey.getIndex()) - .withSecretKeySeed(xmssMtPrivateKey.getSecretKeySeed()) - .withSecretKeyPRF(xmssMtPrivateKey.getSecretKeyPRF()) - .withPublicSeed(xmssMtPrivateKey.getPublicSeed()) - .withRoot(xmssMtPrivateKey.getRoot()); - - if (xmssMtPrivateKey.getBdsState() != null) - { - keyBuilder.withBDSState((BDSStateMap)XMSSUtil.deserialize(xmssMtPrivateKey.getBdsState(), BDSStateMap.class)); - } - - this.keyParams = keyBuilder.build(); - } - catch (ClassNotFoundException e) - { - throw new IOException("ClassNotFoundException processing BDS state: " + e.getMessage()); - } + public XMSSMTPrivateKey extractKeyShard(int usageCount) + { + return new BCXMSSMTPrivateKey(this.treeDigest, keyParams.extractKeyShard(usageCount)); } public String getAlgorithm() @@ -75,11 +70,9 @@ public class BCXMSSMTPrivateKey public byte[] getEncoded() { - PrivateKeyInfo pki; try { - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.xmss_mt, new XMSSMTKeyParams(keyParams.getParameters().getHeight(), keyParams.getParameters().getLayers(), new AlgorithmIdentifier(treeDigest))); - pki = new PrivateKeyInfo(algorithmIdentifier, createKeyStructure()); + PrivateKeyInfo pki = PrivateKeyInfoFactory.createPrivateKeyInfo(keyParams, attributes); return pki.getEncoded(); } @@ -116,39 +109,6 @@ public class BCXMSSMTPrivateKey return treeDigest.hashCode() + 37 * Arrays.hashCode(keyParams.toByteArray()); } - private XMSSMTPrivateKey createKeyStructure() - { - byte[] keyData = keyParams.toByteArray(); - - int n = keyParams.getParameters().getDigestSize(); - int totalHeight = keyParams.getParameters().getHeight(); - int indexSize = (totalHeight + 7) / 8; - int secretKeySize = n; - int secretKeyPRFSize = n; - int publicSeedSize = n; - int rootSize = n; - - int position = 0; - int index = (int)XMSSUtil.bytesToXBigEndian(keyData, position, indexSize); - if (!XMSSUtil.isIndexValid(totalHeight, index)) - { - throw new IllegalArgumentException("index out of bounds"); - } - position += indexSize; - byte[] secretKeySeed = XMSSUtil.extractBytesAtOffset(keyData, position, secretKeySize); - position += secretKeySize; - byte[] secretKeyPRF = XMSSUtil.extractBytesAtOffset(keyData, position, secretKeyPRFSize); - position += secretKeyPRFSize; - byte[] publicSeed = XMSSUtil.extractBytesAtOffset(keyData, position, publicSeedSize); - position += publicSeedSize; - byte[] root = XMSSUtil.extractBytesAtOffset(keyData, position, rootSize); - position += rootSize; - /* import BDS state */ - byte[] bdsStateBinary = XMSSUtil.extractBytesAtOffset(keyData, position, keyData.length - position); - - return new XMSSMTPrivateKey(index, secretKeySeed, secretKeyPRF, publicSeed, root, bdsStateBinary); - } - ASN1ObjectIdentifier getTreeDigestOID() { return treeDigest; @@ -168,4 +128,24 @@ public class BCXMSSMTPrivateKey { return DigestUtil.getXMSSDigestName(treeDigest); } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(PrivateKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSMTPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSMTPublicKey.java index 4877cc631..79652ea7c 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSMTPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSMTPublicKey.java @@ -1,16 +1,16 @@ package com.fr.third.org.bouncycastle.pqc.jcajce.provider.xmss; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.security.PublicKey; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; -import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import com.fr.third.org.bouncycastle.pqc.asn1.XMSSMTKeyParams; -import com.fr.third.org.bouncycastle.pqc.asn1.XMSSPublicKey; -import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSMTParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PublicKeyFactory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSMTPublicKeyParameters; import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.XMSSMTKey; import com.fr.third.org.bouncycastle.util.Arrays; @@ -18,8 +18,10 @@ import com.fr.third.org.bouncycastle.util.Arrays; public class BCXMSSMTPublicKey implements PublicKey, XMSSMTKey { - private final ASN1ObjectIdentifier treeDigest; - private final XMSSMTPublicKeyParameters keyParams; + private static final long serialVersionUID = 3230324130542413475L; + + private transient ASN1ObjectIdentifier treeDigest; + private transient XMSSMTPublicKeyParameters keyParams; public BCXMSSMTPublicKey(ASN1ObjectIdentifier treeDigest, XMSSMTPublicKeyParameters keyParams) { @@ -29,16 +31,16 @@ public class BCXMSSMTPublicKey public BCXMSSMTPublicKey(SubjectPublicKeyInfo keyInfo) throws IOException + { + init(keyInfo); + } + + private void init(SubjectPublicKeyInfo keyInfo) + throws IOException { XMSSMTKeyParams keyParams = XMSSMTKeyParams.getInstance(keyInfo.getAlgorithm().getParameters()); this.treeDigest = keyParams.getTreeDigest().getAlgorithm(); - - XMSSPublicKey xmssMtPublicKey = XMSSPublicKey.getInstance(keyInfo.parsePublicKey()); - - this.keyParams = new XMSSMTPublicKeyParameters - .Builder(new XMSSMTParameters(keyParams.getHeight(), keyParams.getLayers(), DigestUtil.getDigest(treeDigest))) - .withPublicSeed(xmssMtPublicKey.getPublicSeed()) - .withRoot(xmssMtPublicKey.getRoot()).build(); + this.keyParams = (XMSSMTPublicKeyParameters)PublicKeyFactory.createKey(keyInfo); } public boolean equals(Object o) @@ -73,11 +75,9 @@ public class BCXMSSMTPublicKey public byte[] getEncoded() { - SubjectPublicKeyInfo pki; try { - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.xmss_mt, new XMSSMTKeyParams(keyParams.getParameters().getHeight(), keyParams.getParameters().getLayers(), new AlgorithmIdentifier(treeDigest))); - pki = new SubjectPublicKeyInfo(algorithmIdentifier, new XMSSPublicKey(keyParams.getPublicSeed(), keyParams.getRoot())); + SubjectPublicKeyInfo pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(keyParams); return pki.getEncoded(); } @@ -111,4 +111,24 @@ public class BCXMSSMTPublicKey { return DigestUtil.getXMSSDigestName(treeDigest); } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(SubjectPublicKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSPrivateKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSPrivateKey.java index d444209ef..e55ddb40f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSPrivateKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSPrivateKey.java @@ -1,27 +1,29 @@ package com.fr.third.org.bouncycastle.pqc.jcajce.provider.xmss; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.security.PrivateKey; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; +import com.fr.third.org.bouncycastle.asn1.ASN1Set; import com.fr.third.org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import com.fr.third.org.bouncycastle.pqc.asn1.XMSSKeyParams; -import com.fr.third.org.bouncycastle.pqc.asn1.XMSSPrivateKey; -import com.fr.third.org.bouncycastle.pqc.crypto.xmss.BDS; -import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PrivateKeyFactory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PrivateKeyInfoFactory; import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSPrivateKeyParameters; -import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSUtil; -import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.XMSSKey; +import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.XMSSPrivateKey; import com.fr.third.org.bouncycastle.util.Arrays; public class BCXMSSPrivateKey - implements PrivateKey, XMSSKey + implements PrivateKey, XMSSPrivateKey { - private final XMSSPrivateKeyParameters keyParams; - private final ASN1ObjectIdentifier treeDigest; + private static final long serialVersionUID = 8568701712864512338L; + + private transient XMSSPrivateKeyParameters keyParams; + private transient ASN1ObjectIdentifier treeDigest; + private transient ASN1Set attributes; public BCXMSSPrivateKey( ASN1ObjectIdentifier treeDigest, @@ -34,32 +36,26 @@ public class BCXMSSPrivateKey public BCXMSSPrivateKey(PrivateKeyInfo keyInfo) throws IOException { + init(keyInfo); + } + + private void init(PrivateKeyInfo keyInfo) + throws IOException + { + this.attributes = keyInfo.getAttributes(); XMSSKeyParams keyParams = XMSSKeyParams.getInstance(keyInfo.getPrivateKeyAlgorithm().getParameters()); this.treeDigest = keyParams.getTreeDigest().getAlgorithm(); + this.keyParams = (XMSSPrivateKeyParameters)PrivateKeyFactory.createKey(keyInfo); + } - XMSSPrivateKey xmssPrivateKey = XMSSPrivateKey.getInstance(keyInfo.parsePrivateKey()); + public long getUsagesRemaining() + { + return keyParams.getUsagesRemaining(); + } - try - { - XMSSPrivateKeyParameters.Builder keyBuilder = new XMSSPrivateKeyParameters - .Builder(new XMSSParameters(keyParams.getHeight(), DigestUtil.getDigest(treeDigest))) - .withIndex(xmssPrivateKey.getIndex()) - .withSecretKeySeed(xmssPrivateKey.getSecretKeySeed()) - .withSecretKeyPRF(xmssPrivateKey.getSecretKeyPRF()) - .withPublicSeed(xmssPrivateKey.getPublicSeed()) - .withRoot(xmssPrivateKey.getRoot()); - - if (xmssPrivateKey.getBdsState() != null) - { - keyBuilder.withBDSState((BDS)XMSSUtil.deserialize(xmssPrivateKey.getBdsState(), BDS.class)); - } - - this.keyParams = keyBuilder.build(); - } - catch (ClassNotFoundException e) - { - throw new IOException("ClassNotFoundException processing BDS state: " + e.getMessage()); - } + public XMSSPrivateKey extractKeyShard(int usageCount) + { + return new BCXMSSPrivateKey(this.treeDigest, keyParams.extractKeyShard(usageCount)); } public String getAlgorithm() @@ -74,11 +70,9 @@ public class BCXMSSPrivateKey public byte[] getEncoded() { - PrivateKeyInfo pki; try { - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.xmss, new XMSSKeyParams(keyParams.getParameters().getHeight(), new AlgorithmIdentifier(treeDigest))); - pki = new PrivateKeyInfo(algorithmIdentifier, createKeyStructure()); + PrivateKeyInfo pki = PrivateKeyInfoFactory.createPrivateKeyInfo(keyParams, attributes); return pki.getEncoded(); } @@ -115,39 +109,6 @@ public class BCXMSSPrivateKey return keyParams; } - private XMSSPrivateKey createKeyStructure() - { - byte[] keyData = keyParams.toByteArray(); - - int n = keyParams.getParameters().getDigestSize(); - int totalHeight = keyParams.getParameters().getHeight(); - int indexSize = 4; - int secretKeySize = n; - int secretKeyPRFSize = n; - int publicSeedSize = n; - int rootSize = n; - - int position = 0; - int index = (int)XMSSUtil.bytesToXBigEndian(keyData, position, indexSize); - if (!XMSSUtil.isIndexValid(totalHeight, index)) - { - throw new IllegalArgumentException("index out of bounds"); - } - position += indexSize; - byte[] secretKeySeed = XMSSUtil.extractBytesAtOffset(keyData, position, secretKeySize); - position += secretKeySize; - byte[] secretKeyPRF = XMSSUtil.extractBytesAtOffset(keyData, position, secretKeyPRFSize); - position += secretKeyPRFSize; - byte[] publicSeed = XMSSUtil.extractBytesAtOffset(keyData, position, publicSeedSize); - position += publicSeedSize; - byte[] root = XMSSUtil.extractBytesAtOffset(keyData, position, rootSize); - position += rootSize; - /* import BDS state */ - byte[] bdsStateBinary = XMSSUtil.extractBytesAtOffset(keyData, position, keyData.length - position); - - return new XMSSPrivateKey(index, secretKeySeed, secretKeyPRF, publicSeed, root, bdsStateBinary); - } - ASN1ObjectIdentifier getTreeDigestOID() { return treeDigest; @@ -162,4 +123,24 @@ public class BCXMSSPrivateKey { return DigestUtil.getXMSSDigestName(treeDigest); } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(PrivateKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSPublicKey.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSPublicKey.java index b9e50efdb..23cb10371 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSPublicKey.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/BCXMSSPublicKey.java @@ -1,16 +1,16 @@ package com.fr.third.org.bouncycastle.pqc.jcajce.provider.xmss; import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.security.PublicKey; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; -import com.fr.third.org.bouncycastle.asn1.x509.AlgorithmIdentifier; import com.fr.third.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; import com.fr.third.org.bouncycastle.crypto.CipherParameters; -import com.fr.third.org.bouncycastle.pqc.asn1.PQCObjectIdentifiers; import com.fr.third.org.bouncycastle.pqc.asn1.XMSSKeyParams; -import com.fr.third.org.bouncycastle.pqc.asn1.XMSSPublicKey; -import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSParameters; +import com.fr.third.org.bouncycastle.pqc.crypto.util.PublicKeyFactory; +import com.fr.third.org.bouncycastle.pqc.crypto.util.SubjectPublicKeyInfoFactory; import com.fr.third.org.bouncycastle.pqc.crypto.xmss.XMSSPublicKeyParameters; import com.fr.third.org.bouncycastle.pqc.jcajce.interfaces.XMSSKey; import com.fr.third.org.bouncycastle.util.Arrays; @@ -18,8 +18,10 @@ import com.fr.third.org.bouncycastle.util.Arrays; public class BCXMSSPublicKey implements PublicKey, XMSSKey { - private final XMSSPublicKeyParameters keyParams; - private final ASN1ObjectIdentifier treeDigest; + private static final long serialVersionUID = -5617456225328969766L; + + private transient XMSSPublicKeyParameters keyParams; + private transient ASN1ObjectIdentifier treeDigest; public BCXMSSPublicKey( ASN1ObjectIdentifier treeDigest, @@ -31,16 +33,16 @@ public class BCXMSSPublicKey public BCXMSSPublicKey(SubjectPublicKeyInfo keyInfo) throws IOException + { + init(keyInfo); + } + + private void init(SubjectPublicKeyInfo keyInfo) + throws IOException { XMSSKeyParams keyParams = XMSSKeyParams.getInstance(keyInfo.getAlgorithm().getParameters()); this.treeDigest = keyParams.getTreeDigest().getAlgorithm(); - - XMSSPublicKey xmssPublicKey = XMSSPublicKey.getInstance(keyInfo.parsePublicKey()); - - this.keyParams = new XMSSPublicKeyParameters - .Builder(new XMSSParameters(keyParams.getHeight(), DigestUtil.getDigest(treeDigest))) - .withPublicSeed(xmssPublicKey.getPublicSeed()) - .withRoot(xmssPublicKey.getRoot()).build(); + this.keyParams = (XMSSPublicKeyParameters)PublicKeyFactory.createKey(keyInfo); } /** @@ -53,12 +55,9 @@ public class BCXMSSPublicKey public byte[] getEncoded() { - SubjectPublicKeyInfo pki; try { - AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PQCObjectIdentifiers.xmss, new XMSSKeyParams(keyParams.getParameters().getHeight(), new AlgorithmIdentifier(treeDigest))); - pki = new SubjectPublicKeyInfo(algorithmIdentifier, new XMSSPublicKey(keyParams.getPublicSeed(), keyParams.getRoot())); - + SubjectPublicKeyInfo pki = SubjectPublicKeyInfoFactory.createSubjectPublicKeyInfo(keyParams); return pki.getEncoded(); } catch (IOException e) @@ -108,4 +107,24 @@ public class BCXMSSPublicKey { return DigestUtil.getXMSSDigestName(treeDigest); } + + private void readObject( + ObjectInputStream in) + throws IOException, ClassNotFoundException + { + in.defaultReadObject(); + + byte[] enc = (byte[])in.readObject(); + + init(SubjectPublicKeyInfo.getInstance(enc)); + } + + private void writeObject( + ObjectOutputStream out) + throws IOException + { + out.defaultWriteObject(); + + out.writeObject(this.getEncoded()); + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/XMSSMTSignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/XMSSMTSignatureSpi.java index 6ad5e07bc..6a5e6955f 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/XMSSMTSignatureSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/XMSSMTSignatureSpi.java @@ -11,6 +11,7 @@ import java.security.spec.AlgorithmParameterSpec; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.NullDigest; import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest; @@ -114,7 +115,7 @@ public class XMSSMTSignatureSpi { if (e instanceof IllegalStateException) { - throw new SignatureException(e.getMessage()); + throw new SignatureException(e.getMessage(), e); } throw new SignatureException(e.toString()); } @@ -151,9 +152,10 @@ public class XMSSMTSignatureSpi public boolean isSigningCapable() { - return treeDigest != null; + return treeDigest != null && signer.getUsagesRemaining() != 0; } + public PrivateKey getUpdatedPrivateKey() { if (treeDigest == null) @@ -172,7 +174,7 @@ public class XMSSMTSignatureSpi { public withSha256() { - super("SHA256withXMSSMT", new SHA256Digest(), new XMSSMTSigner()); + super("XMSSMT-SHA256", new NullDigest(), new XMSSMTSigner()); } } @@ -181,7 +183,7 @@ public class XMSSMTSignatureSpi { public withShake128() { - super("SHAKE128withXMSSMT", new SHAKEDigest(128), new XMSSMTSigner()); + super("XMSSMT-SHAKE128", new NullDigest(), new XMSSMTSigner()); } } @@ -190,7 +192,7 @@ public class XMSSMTSignatureSpi { public withSha512() { - super("SHA512withXMSSMT", new SHA512Digest(), new XMSSMTSigner()); + super("XMSSMT-SHA512", new NullDigest(), new XMSSMTSigner()); } } @@ -199,7 +201,43 @@ public class XMSSMTSignatureSpi { public withShake256() { - super("SHAKE256withXMSSMT", new SHAKEDigest(256), new XMSSMTSigner()); + super("XMSSMT-SHAKE256", new NullDigest(), new XMSSMTSigner()); + } + } + + static public class withSha256andPrehash + extends XMSSMTSignatureSpi + { + public withSha256andPrehash() + { + super("SHA256withXMSSMT-SHA256", new SHA256Digest(), new XMSSMTSigner()); + } + } + + static public class withShake128andPrehash + extends XMSSMTSignatureSpi + { + public withShake128andPrehash() + { + super("SHAKE128withXMSSMT-SHAKE128", new SHAKEDigest(128), new XMSSMTSigner()); + } + } + + static public class withSha512andPrehash + extends XMSSMTSignatureSpi + { + public withSha512andPrehash() + { + super("SHA512withXMSSMT-SHA512", new SHA512Digest(), new XMSSMTSigner()); + } + } + + static public class withShake256andPrehash + extends XMSSMTSignatureSpi + { + public withShake256andPrehash() + { + super("SHAKE256withXMSSMT-SHAKE256", new SHAKEDigest(256), new XMSSMTSigner()); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/XMSSSignatureSpi.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/XMSSSignatureSpi.java index 5cfe986c2..23b7ec8ac 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/XMSSSignatureSpi.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/provider/xmss/XMSSSignatureSpi.java @@ -11,6 +11,7 @@ import java.security.spec.AlgorithmParameterSpec; import com.fr.third.org.bouncycastle.asn1.ASN1ObjectIdentifier; import com.fr.third.org.bouncycastle.crypto.CipherParameters; import com.fr.third.org.bouncycastle.crypto.Digest; +import com.fr.third.org.bouncycastle.crypto.digests.NullDigest; import com.fr.third.org.bouncycastle.crypto.digests.SHA256Digest; import com.fr.third.org.bouncycastle.crypto.digests.SHA512Digest; import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest; @@ -114,9 +115,9 @@ public class XMSSSignatureSpi { if (e instanceof IllegalStateException) { - throw new SignatureException(e.getMessage()); + throw new SignatureException(e.getMessage(), e); } - throw new SignatureException(e.toString()); + throw new SignatureException(e.toString(), e); } } @@ -130,7 +131,6 @@ public class XMSSSignatureSpi protected void engineSetParameter(AlgorithmParameterSpec params) { - // TODO throw new UnsupportedOperationException("engineSetParameter unsupported"); } @@ -152,7 +152,7 @@ public class XMSSSignatureSpi public boolean isSigningCapable() { - return treeDigest != null; + return treeDigest != null && signer.getUsagesRemaining() != 0; } public PrivateKey getUpdatedPrivateKey() @@ -173,7 +173,7 @@ public class XMSSSignatureSpi { public withSha256() { - super("SHA256withXMSS", new SHA256Digest(), new XMSSSigner()); + super("XMSS-SHA256", new NullDigest(), new XMSSSigner()); } } @@ -182,7 +182,7 @@ public class XMSSSignatureSpi { public withShake128() { - super("SHAKE128withXMSSMT", new SHAKEDigest(128), new XMSSSigner()); + super("XMSS-SHAKE128", new NullDigest(), new XMSSSigner()); } } @@ -191,7 +191,7 @@ public class XMSSSignatureSpi { public withSha512() { - super("SHA512withXMSS", new SHA512Digest(), new XMSSSigner()); + super("XMSS-SHA512", new NullDigest(), new XMSSSigner()); } } @@ -200,7 +200,43 @@ public class XMSSSignatureSpi { public withShake256() { - super("SHAKE256withXMSS", new SHAKEDigest(256), new XMSSSigner()); + super("XMSS-SHAKE256", new NullDigest(), new XMSSSigner()); + } + } + + static public class withSha256andPrehash + extends XMSSSignatureSpi + { + public withSha256andPrehash() + { + super("SHA256withXMSS-SHA256", new SHA256Digest(), new XMSSSigner()); + } + } + + static public class withShake128andPrehash + extends XMSSSignatureSpi + { + public withShake128andPrehash() + { + super("SHAKE128withXMSSMT-SHAKE128", new SHAKEDigest(128), new XMSSSigner()); + } + } + + static public class withSha512andPrehash + extends XMSSSignatureSpi + { + public withSha512andPrehash() + { + super("SHA512withXMSS-SHA512", new SHA512Digest(), new XMSSSigner()); + } + } + + static public class withShake256andPrehash + extends XMSSSignatureSpi + { + public withShake256andPrehash() + { + super("SHAKE256withXMSS-SHAKE256", new SHAKEDigest(256), new XMSSSigner()); } } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/spec/QTESLAParameterSpec.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/spec/QTESLAParameterSpec.java new file mode 100644 index 000000000..fafe51cb3 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/jcajce/spec/QTESLAParameterSpec.java @@ -0,0 +1,41 @@ +package com.fr.third.org.bouncycastle.pqc.jcajce.spec; + +import java.security.spec.AlgorithmParameterSpec; + +import com.fr.third.org.bouncycastle.pqc.crypto.qtesla.QTESLASecurityCategory; + +/** + * qTESLA parameter details. These are divided up on the basis of the security categories for each + * individual parameter set. + */ +public class QTESLAParameterSpec + implements AlgorithmParameterSpec +{ + /** + * Available security categories. + */ + public static final String PROVABLY_SECURE_I = QTESLASecurityCategory.getName(QTESLASecurityCategory.PROVABLY_SECURE_I); + public static final String PROVABLY_SECURE_III = QTESLASecurityCategory.getName(QTESLASecurityCategory.PROVABLY_SECURE_III); + + private String securityCategory; + + /** + * Base constructor. + * + * @param securityCategory the security category we want this parameterSpec to match. + */ + public QTESLAParameterSpec(String securityCategory) + { + this.securityCategory = securityCategory; + } + + /** + * Return the security category. + * + * @return the security category. + */ + public String getSecurityCategory() + { + return securityCategory; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Matrix.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Matrix.java index c4583f6f7..b8589c839 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Matrix.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Matrix.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.pqc.math.linearalgebra; import java.security.SecureRandom; +import com.fr.third.org.bouncycastle.util.Arrays; + /** * This class describes some operations with matrices over finite field GF(2) * and is used in ecc and MQ-PKC (also has some specific methods and @@ -1230,7 +1232,7 @@ public class GF2Matrix int hash = (numRows * 31 + numColumns) * 31 + length; for (int i = 0; i < numRows; i++) { - hash = hash * 31 + matrix[i].hashCode(); + hash = hash * 31 + Arrays.hashCode(matrix[i]); } return hash; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Polynomial.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Polynomial.java index 4d6884ef1..e80b999b0 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Polynomial.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Polynomial.java @@ -4,6 +4,8 @@ package com.fr.third.org.bouncycastle.pqc.math.linearalgebra; import java.math.BigInteger; import java.util.Random; +import com.fr.third.org.bouncycastle.util.Arrays; + /** * This class stores very long strings of bits and does some basic arithmetics. @@ -572,7 +574,7 @@ public class GF2Polynomial */ public int hashCode() { - return len + value.hashCode(); + return len + Arrays.hashCode(value); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Vector.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Vector.java index 3d479665f..12c1670b8 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Vector.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2Vector.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.pqc.math.linearalgebra; import java.security.SecureRandom; +import com.fr.third.org.bouncycastle.util.Arrays; + /** * This class implements the abstract class Vector for the case of * vectors over the finite field GF(2).
@@ -505,7 +507,7 @@ public class GF2Vector public int hashCode() { int hash = length; - hash = hash * 31 + v.hashCode(); + hash = hash * 31 + Arrays.hashCode(v); return hash; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2mVector.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2mVector.java index 1736e1323..1405fc3d6 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2mVector.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2mVector.java @@ -1,6 +1,8 @@ package com.fr.third.org.bouncycastle.pqc.math.linearalgebra; +import com.fr.third.org.bouncycastle.util.Arrays; + /** * This class implements vectors over the finite field * GF(2m) for small m (i.e., @@ -222,7 +224,7 @@ public class GF2mVector public int hashCode() { int hash = this.field.hashCode(); - hash = hash * 31 + vector.hashCode(); + hash = hash * 31 + Arrays.hashCode(vector); return hash; } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2nONBElement.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2nONBElement.java index f143e88da..48e223c50 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2nONBElement.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/GF2nONBElement.java @@ -4,6 +4,8 @@ package com.fr.third.org.bouncycastle.pqc.math.linearalgebra; import java.math.BigInteger; import java.security.SecureRandom; +import com.fr.third.org.bouncycastle.util.Arrays; + /** * This class implements an element of the finite field GF(2n ). * It is represented in an optimal normal basis representation and holds the @@ -403,7 +405,7 @@ public class GF2nONBElement */ public int hashCode() { - return mPol.hashCode(); + return Arrays.hashCode(mPol); } // ///////////////////////////////////////////////////////////////////// diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/IntegerFunctions.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/IntegerFunctions.java index f745318e2..9656b0953 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/IntegerFunctions.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/IntegerFunctions.java @@ -4,6 +4,7 @@ import java.math.BigInteger; import java.security.SecureRandom; import com.fr.third.org.bouncycastle.crypto.CryptoServicesRegistrar; +import com.fr.third.org.bouncycastle.util.BigIntegers; /** * Class of number-theory related functions for use with integers represented as @@ -889,7 +890,7 @@ public final class IntegerFunctions n -= 2; } - while (n > 3 & !isPrime(n)) + while (n > 3 && !isPrime(n)) { n -= 2; } @@ -1071,7 +1072,7 @@ public final class IntegerFunctions for (int i = 0; i < 20; i++) { - randomNum = new BigInteger(blen, prng); + randomNum = BigIntegers.createRandomBigInteger(blen, prng); if (randomNum.compareTo(upperBound) < 0) { return randomNum; diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/Permutation.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/Permutation.java index 04daba6fa..ef6381ce7 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/Permutation.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/linearalgebra/Permutation.java @@ -2,6 +2,8 @@ package com.fr.third.org.bouncycastle.pqc.math.linearalgebra; import java.security.SecureRandom; +import com.fr.third.org.bouncycastle.util.Arrays; + /** * This class implements permutations of the set {0,1,...,n-1} for some given n * > 0, i.e., ordered sequences containing each number m (0 <= @@ -217,7 +219,7 @@ public class Permutation */ public int hashCode() { - return perm.hashCode(); + return Arrays.hashCode(perm); } /** diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/ntru/polynomial/test/PolynomialGenerator.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/ntru/polynomial/test/PolynomialGenerator.java new file mode 100644 index 000000000..5c71f93f2 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/pqc/math/ntru/polynomial/test/PolynomialGenerator.java @@ -0,0 +1,27 @@ +package com.fr.third.org.bouncycastle.pqc.math.ntru.polynomial.test; + +import java.util.Random; + +import com.fr.third.org.bouncycastle.pqc.math.ntru.polynomial.IntegerPolynomial; + +public class PolynomialGenerator +{ + /** + * Creates a random polynomial with N coefficients + * between 0 and q-1. + * + * @param N length of the polynomial + * @param q coefficients will all be below this number + * @return a random polynomial + */ + public static IntegerPolynomial generateRandom(int N, int q) + { + Random rng = new Random(); + int[] coeffs = new int[N]; + for (int i = 0; i < N; i++) + { + coeffs[i] = rng.nextInt(q); + } + return new IntegerPolynomial(coeffs); + } +} \ No newline at end of file diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Arrays.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Arrays.java index 907eae91a..d319a7096 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Arrays.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Arrays.java @@ -13,124 +13,49 @@ public final class Arrays // static class, hide constructor } - public static boolean areEqual( - boolean[] a, - boolean[] b) + public static boolean areAllZeroes(byte[] buf, int off, int len) { - if (a == b) - { - return true; - } - - if (a == null || b == null) - { - return false; - } - - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) + int bits = 0; + for (int i = 0; i < len; ++i) { - if (a[i] != b[i]) - { - return false; - } + bits |= buf[off + i]; } - - return true; + return bits == 0; } - public static boolean areEqual( - char[] a, - char[] b) + public static boolean areEqual(boolean[] a, boolean[] b) { - if (a == b) - { - return true; - } - - if (a == null || b == null) - { - return false; - } - - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; + return java.util.Arrays.equals(a, b); } - public static boolean areEqual( - byte[] a, - byte[] b) + public static boolean areEqual(byte[] a, byte[] b) { - if (a == b) - { - return true; - } - - if (a == null || b == null) - { - return false; - } - - if (a.length != b.length) - { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } - - return true; + return java.util.Arrays.equals(a, b); } - public static boolean areEqual( - short[] a, - short[] b) + public static boolean areEqual(char[] a, char[] b) { - if (a == b) - { - return true; - } + return java.util.Arrays.equals(a, b); + } - if (a == null || b == null) - { - return false; - } + public static boolean areEqual(int[] a, int[] b) + { + return java.util.Arrays.equals(a, b); + } - if (a.length != b.length) - { - return false; - } + public static boolean areEqual(long[] a, long[] b) + { + return java.util.Arrays.equals(a, b); + } - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } - } + public static boolean areEqual(Object[] a, Object[] b) + { + return java.util.Arrays.equals(a, b); + } - return true; + public static boolean areEqual(short[] a, short[] b) + { + return java.util.Arrays.equals(a, b); } /** @@ -146,121 +71,61 @@ public final class Arrays byte[] expected, byte[] supplied) { - if (expected == supplied) - { - return true; - } - if (expected == null || supplied == null) { return false; } - if (expected.length != supplied.length) - { - return !Arrays.constantTimeAreEqual(expected, expected); - } - - int nonEqual = 0; - - for (int i = 0; i != expected.length; i++) - { - nonEqual |= (expected[i] ^ supplied[i]); - } - - return nonEqual == 0; - } - - public static boolean areEqual( - int[] a, - int[] b) - { - if (a == b) + if (expected == supplied) { return true; } - if (a == null || b == null) - { - return false; - } + int len = (expected.length < supplied.length) ? expected.length : supplied.length; + + int nonEqual = expected.length ^ supplied.length; - if (a.length != b.length) + for (int i = 0; i != len; i++) { - return false; + nonEqual |= (expected[i] ^ supplied[i]); } - - for (int i = 0; i != a.length; i++) + for (int i = len; i < supplied.length; i++) { - if (a[i] != b[i]) - { - return false; - } + nonEqual |= (supplied[i] ^ ~supplied[i]); } - return true; + return nonEqual == 0; } - public static boolean areEqual( - long[] a, - long[] b) + public static boolean constantTimeAreEqual(int len, byte[] a, int aOff, byte[] b, int bOff) { - if (a == b) + if (null == a) { - return true; + throw new NullPointerException("'a' cannot be null"); } - - if (a == null || b == null) - { - return false; - } - - if (a.length != b.length) + if (null == b) { - return false; - } - - for (int i = 0; i != a.length; i++) - { - if (a[i] != b[i]) - { - return false; - } + throw new NullPointerException("'b' cannot be null"); } - - return true; - } - - public static boolean areEqual(Object[] a, Object[] b) - { - if (a == b) + if (len < 0) { - return true; + throw new IllegalArgumentException("'len' cannot be negative"); } - if (a == null || b == null) + if (aOff > (a.length - len)) { - return false; + throw new IndexOutOfBoundsException("'aOff' value invalid for specified length"); } - if (a.length != b.length) + if (bOff > (b.length - len)) { - return false; + throw new IndexOutOfBoundsException("'bOff' value invalid for specified length"); } - for (int i = 0; i != a.length; i++) + + int d = 0; + for (int i = 0; i < len; ++i) { - Object objA = a[i], objB = b[i]; - if (objA == null) - { - if (objB != null) - { - return false; - } - } - else if (!objA.equals(objB)) - { - return false; - } + d |= (a[aOff + i] ^ b[bOff + i]); } - return true; + return 0 == d; } public static int compareUnsigned(byte[] a, byte[] b) @@ -301,11 +166,11 @@ public final class Arrays return 0; } - public static boolean contains(short[] a, short n) + public static boolean contains(boolean[] a, boolean val) { for (int i = 0; i < a.length; ++i) { - if (a[i] == n) + if (a[i] == val) { return true; } @@ -313,11 +178,11 @@ public final class Arrays return false; } - public static boolean contains(int[] a, int n) + public static boolean contains(byte[] a, byte val) { for (int i = 0; i < a.length; ++i) { - if (a[i] == n) + if (a[i] == val) { return true; } @@ -325,110 +190,154 @@ public final class Arrays return false; } - public static void fill( - byte[] array, - byte value) + public static boolean contains(char[] a, char val) { - for (int i = 0; i < array.length; i++) + for (int i = 0; i < a.length; ++i) { - array[i] = value; + if (a[i] == val) + { + return true; + } } + return false; } - public static void fill( - char[] array, - char value) + public static boolean contains(int[] a, int val) { - for (int i = 0; i < array.length; i++) + for (int i = 0; i < a.length; ++i) { - array[i] = value; + if (a[i] == val) + { + return true; + } } + return false; } - public static void fill( - long[] array, - long value) + public static boolean contains(long[] a, long val) { - for (int i = 0; i < array.length; i++) + for (int i = 0; i < a.length; ++i) { - array[i] = value; + if (a[i] == val) + { + return true; + } } + return false; } - public static void fill( - short[] array, - short value) + public static boolean contains(short[] a, short val) { - for (int i = 0; i < array.length; i++) + for (int i = 0; i < a.length; ++i) { - array[i] = value; + if (a[i] == val) + { + return true; + } } + return false; } - public static void fill( - int[] array, - int value) + public static void fill(boolean[] a, boolean val) { - for (int i = 0; i < array.length; i++) - { - array[i] = value; - } + java.util.Arrays.fill(a, val); } - public static void fill( - byte[] array, - int out, - byte value) + public static void fill(boolean[] a, int fromIndex, int toIndex, boolean val) { - if(out < array.length) - { - for (int i = out; i < array.length; i++) - { - array[i] = value; - } - } + java.util.Arrays.fill(a, fromIndex, toIndex, val); } - public static void fill( - int[] array, - int out, - int value) + public static void fill(byte[] a, byte val) { - if(out < array.length) - { - for (int i = out; i < array.length; i++) - { - array[i] = value; - } - } + java.util.Arrays.fill(a, val); } - public static void fill( - short[] array, - int out, - short value) + /** + * @deprecated Use {@link #fill(byte[], int, int, byte)} instead. + */ + public static void fill(byte[] a, int fromIndex, byte val) { - if(out < array.length) - { - for (int i = out; i < array.length; i++) - { - array[i] = value; - } - } + fill(a, fromIndex, a.length, val); } - public static void fill( - long[] array, - int out, - long value) + public static void fill(byte[] a, int fromIndex, int toIndex, byte val) { - if(out < array.length) - { - for (int i = out; i < array.length; i++) - { - array[i] = value; - } - } + java.util.Arrays.fill(a, fromIndex, toIndex, val); + } + + public static void fill(char[] a, char val) + { + java.util.Arrays.fill(a, val); + } + + public static void fill(char[] a, int fromIndex, int toIndex, char val) + { + java.util.Arrays.fill(a, fromIndex, toIndex, val); + } + + public static void fill(int[] a, int val) + { + java.util.Arrays.fill(a, val); + } + + /** + * @deprecated Use {@link #fill(int[], int, int, int)} instead. + */ + public static void fill(int[] a, int fromIndex, int val) + { + java.util.Arrays.fill(a, fromIndex, a.length, val); + } + + public static void fill(int[] a, int fromIndex, int toIndex, int val) + { + java.util.Arrays.fill(a, fromIndex, toIndex, val); + } + + public static void fill(long[] a, long val) + { + java.util.Arrays.fill(a, val); + } + + /** + * @deprecated Use {@link #fill(long[], int, int, long)} instead. + */ + public static void fill(long[] a, int fromIndex, long val) + { + java.util.Arrays.fill(a, fromIndex, a.length, val); + } + + public static void fill(long[] a, int fromIndex, int toIndex, long val) + { + java.util.Arrays.fill(a, fromIndex, toIndex, val); + } + + public static void fill(Object[] a, Object val) + { + java.util.Arrays.fill(a, val); + } + + public static void fill(Object[] a, int fromIndex, int toIndex, Object val) + { + java.util.Arrays.fill(a, fromIndex, toIndex, val); + } + + public static void fill(short[] a, short val) + { + java.util.Arrays.fill(a, val); + } + + /** + * @deprecated Use {@link #fill(short[], int, int, short)} instead. + */ + public static void fill(short[] a, int fromIndex, short val) + { + java.util.Arrays.fill(a, fromIndex, a.length, val); + } + + public static void fill(short[] a, int fromIndex, int toIndex, short val) + { + java.util.Arrays.fill(a, fromIndex, toIndex, val); } public static int hashCode(byte[] data) @@ -638,36 +547,45 @@ public final class Arrays while (--i >= 0) { hc *= 257; - hc ^= data[i].hashCode(); + hc ^= Objects.hashCode(data[i]); } return hc; } + public static boolean[] clone(boolean[] data) + { + return null == data ? null : data.clone(); + } + public static byte[] clone(byte[] data) { - if (data == null) - { - return null; - } - byte[] copy = new byte[data.length]; + return null == data ? null : data.clone(); + } - System.arraycopy(data, 0, copy, 0, data.length); + public static char[] clone(char[] data) + { + return null == data ? null : data.clone(); + } - return copy; + public static int[] clone(int[] data) + { + return null == data ? null : data.clone(); } - public static char[] clone(char[] data) + public static long[] clone(long[] data) { - if (data == null) - { - return null; - } - char[] copy = new char[data.length]; + return null == data ? null : data.clone(); + } - System.arraycopy(data, 0, copy, 0, data.length); + public static short[] clone(short[] data) + { + return null == data ? null : data.clone(); + } - return copy; + public static BigInteger[] clone(BigInteger[] data) + { + return null == data ? null : data.clone(); } public static byte[] clone(byte[] data, byte[] existing) @@ -684,31 +602,28 @@ public final class Arrays return existing; } - public static byte[][] clone(byte[][] data) + public static long[] clone(long[] data, long[] existing) { if (data == null) { return null; } - - byte[][] copy = new byte[data.length][]; - - for (int i = 0; i != copy.length; i++) + if ((existing == null) || (existing.length != data.length)) { - copy[i] = clone(data[i]); + return clone(data); } - - return copy; + System.arraycopy(data, 0, existing, 0, existing.length); + return existing; } - public static byte[][][] clone(byte[][][] data) + public static byte[][] clone(byte[][] data) { if (data == null) { return null; } - byte[][][] copy = new byte[data.length][][]; + byte[][] copy = new byte[data.length][]; for (int i = 0; i != copy.length; i++) { @@ -718,233 +633,139 @@ public final class Arrays return copy; } - public static int[] clone(int[] data) + public static byte[][][] clone(byte[][][] data) { if (data == null) { return null; } - int[] copy = new int[data.length]; - - System.arraycopy(data, 0, copy, 0, data.length); - return copy; - } + byte[][][] copy = new byte[data.length][][]; - public static long[] clone(long[] data) - { - if (data == null) + for (int i = 0; i != copy.length; i++) { - return null; + copy[i] = clone(data[i]); } - long[] copy = new long[data.length]; - - System.arraycopy(data, 0, copy, 0, data.length); return copy; } - public static long[] clone(long[] data, long[] existing) + public static boolean[] copyOf(boolean[] original, int newLength) { - if (data == null) - { - return null; - } - if ((existing == null) || (existing.length != data.length)) - { - return clone(data); - } - System.arraycopy(data, 0, existing, 0, existing.length); - return existing; + boolean[] copy = new boolean[newLength]; + System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); + return copy; } - public static short[] clone(short[] data) + public static byte[] copyOf(byte[] original, int newLength) { - if (data == null) - { - return null; - } - short[] copy = new short[data.length]; - - System.arraycopy(data, 0, copy, 0, data.length); - + byte[] copy = new byte[newLength]; + System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } - public static BigInteger[] clone(BigInteger[] data) + public static char[] copyOf(char[] original, int newLength) { - if (data == null) - { - return null; - } - BigInteger[] copy = new BigInteger[data.length]; - - System.arraycopy(data, 0, copy, 0, data.length); - + char[] copy = new char[newLength]; + System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); return copy; } - public static byte[] copyOf(byte[] data, int newLength) + public static int[] copyOf(int[] original, int newLength) { - byte[] tmp = new byte[newLength]; - - if (newLength < data.length) - { - System.arraycopy(data, 0, tmp, 0, newLength); - } - else - { - System.arraycopy(data, 0, tmp, 0, data.length); - } - - return tmp; + int[] copy = new int[newLength]; + System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); + return copy; } - public static char[] copyOf(char[] data, int newLength) + public static long[] copyOf(long[] original, int newLength) { - char[] tmp = new char[newLength]; - - if (newLength < data.length) - { - System.arraycopy(data, 0, tmp, 0, newLength); - } - else - { - System.arraycopy(data, 0, tmp, 0, data.length); - } - - return tmp; + long[] copy = new long[newLength]; + System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); + return copy; } - public static int[] copyOf(int[] data, int newLength) + public static short[] copyOf(short[] original, int newLength) { - int[] tmp = new int[newLength]; - - if (newLength < data.length) - { - System.arraycopy(data, 0, tmp, 0, newLength); - } - else - { - System.arraycopy(data, 0, tmp, 0, data.length); - } - - return tmp; + short[] copy = new short[newLength]; + System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); + return copy; } - public static long[] copyOf(long[] data, int newLength) + public static BigInteger[] copyOf(BigInteger[] original, int newLength) { - long[] tmp = new long[newLength]; - - if (newLength < data.length) - { - System.arraycopy(data, 0, tmp, 0, newLength); - } - else - { - System.arraycopy(data, 0, tmp, 0, data.length); - } - - return tmp; + BigInteger[] copy = new BigInteger[newLength]; + System.arraycopy(original, 0, copy, 0, Math.min(original.length, newLength)); + return copy; } - public static BigInteger[] copyOf(BigInteger[] data, int newLength) + public static boolean[] copyOfRange(boolean[] original, int from, int to) { - BigInteger[] tmp = new BigInteger[newLength]; - - if (newLength < data.length) - { - System.arraycopy(data, 0, tmp, 0, newLength); - } - else - { - System.arraycopy(data, 0, tmp, 0, data.length); - } - - return tmp; + int newLength = getLength(from, to); + boolean[] copy = new boolean[newLength]; + System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); + return copy; } /** - * Make a copy of a range of bytes from the passed in data array. The range can - * extend beyond the end of the input array, in which case the return array will - * be padded with zeroes. + * Make a copy of a range of bytes from the passed in array. The range can extend beyond the end + * of the input array, in which case the returned array will be padded with zeroes. * - * @param data the array from which the data is to be copied. - * @param from the start index at which the copying should take place. - * @param to the final index of the range (exclusive). + * @param original + * the array from which the data is to be copied. + * @param from + * the start index at which the copying should take place. + * @param to + * the final index of the range (exclusive). * * @return a new byte array containing the range given. */ - public static byte[] copyOfRange(byte[] data, int from, int to) + public static byte[] copyOfRange(byte[] original, int from, int to) { int newLength = getLength(from, to); - - byte[] tmp = new byte[newLength]; - - if (data.length - from < newLength) - { - System.arraycopy(data, from, tmp, 0, data.length - from); - } - else - { - System.arraycopy(data, from, tmp, 0, newLength); - } - - return tmp; + byte[] copy = new byte[newLength]; + System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); + return copy; } - public static int[] copyOfRange(int[] data, int from, int to) + public static char[] copyOfRange(char[] original, int from, int to) { int newLength = getLength(from, to); - - int[] tmp = new int[newLength]; - - if (data.length - from < newLength) - { - System.arraycopy(data, from, tmp, 0, data.length - from); - } - else - { - System.arraycopy(data, from, tmp, 0, newLength); - } - - return tmp; + char[] copy = new char[newLength]; + System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); + return copy; } - public static long[] copyOfRange(long[] data, int from, int to) + public static int[] copyOfRange(int[] original, int from, int to) { int newLength = getLength(from, to); - - long[] tmp = new long[newLength]; - - if (data.length - from < newLength) - { - System.arraycopy(data, from, tmp, 0, data.length - from); - } - else - { - System.arraycopy(data, from, tmp, 0, newLength); - } - - return tmp; + int[] copy = new int[newLength]; + System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); + return copy; } - public static BigInteger[] copyOfRange(BigInteger[] data, int from, int to) + public static long[] copyOfRange(long[] original, int from, int to) { int newLength = getLength(from, to); + long[] copy = new long[newLength]; + System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); + return copy; + } - BigInteger[] tmp = new BigInteger[newLength]; - - if (data.length - from < newLength) - { - System.arraycopy(data, from, tmp, 0, data.length - from); - } - else - { - System.arraycopy(data, from, tmp, 0, newLength); - } + public static short[] copyOfRange(short[] original, int from, int to) + { + int newLength = getLength(from, to); + short[] copy = new short[newLength]; + System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); + return copy; + } - return tmp; + public static BigInteger[] copyOfRange(BigInteger[] original, int from, int to) + { + int newLength = getLength(from, to); + BigInteger[] copy = new BigInteger[newLength]; + System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); + return copy; } private static int getLength(int from, int to) @@ -1015,84 +836,72 @@ public final class Arrays return result; } - - public static byte[] concatenate(byte[] a, byte[] b) { - if (a != null && b != null) + if (null == a) { - byte[] rv = new byte[a.length + b.length]; - - System.arraycopy(a, 0, rv, 0, a.length); - System.arraycopy(b, 0, rv, a.length, b.length); - - return rv; - } - else if (b != null) - { - return clone(b); + return b.clone(); } - else + if (null == b) { - return clone(a); + return a.clone(); } + + byte[] r = new byte[a.length + b.length]; + System.arraycopy(a, 0, r, 0, a.length); + System.arraycopy(b, 0, r, a.length, b.length); + return r; } public static byte[] concatenate(byte[] a, byte[] b, byte[] c) { - if (a != null && b != null && c != null) - { - byte[] rv = new byte[a.length + b.length + c.length]; - - System.arraycopy(a, 0, rv, 0, a.length); - System.arraycopy(b, 0, rv, a.length, b.length); - System.arraycopy(c, 0, rv, a.length + b.length, c.length); - - return rv; - } - else if (a == null) + if (null == a) { return concatenate(b, c); } - else if (b == null) + if (null == b) { return concatenate(a, c); } - else + if (null == c) { return concatenate(a, b); } + + byte[] r = new byte[a.length + b.length + c.length]; + int pos = 0; + System.arraycopy(a, 0, r, pos, a.length); pos += a.length; + System.arraycopy(b, 0, r, pos, b.length); pos += b.length; + System.arraycopy(c, 0, r, pos, c.length); + return r; } public static byte[] concatenate(byte[] a, byte[] b, byte[] c, byte[] d) { - if (a != null && b != null && c != null && d != null) + if (null == a) { - byte[] rv = new byte[a.length + b.length + c.length + d.length]; - - System.arraycopy(a, 0, rv, 0, a.length); - System.arraycopy(b, 0, rv, a.length, b.length); - System.arraycopy(c, 0, rv, a.length + b.length, c.length); - System.arraycopy(d, 0, rv, a.length + b.length + c.length, d.length); - - return rv; + return concatenate(b, c, d); } - else if (d == null) + if (null == b) { - return concatenate(a, b, c); + return concatenate(a, c, d); } - else if (c == null) + if (null == c) { return concatenate(a, b, d); } - else if (b == null) + if (null == d) { - return concatenate(a, c, d); - } - else - { - return concatenate(b, c, d); + return concatenate(a, b, c); } + + byte[] r = new byte[a.length + b.length + c.length + d.length]; + int pos = 0; + System.arraycopy(a, 0, r, pos, a.length); pos += a.length; + System.arraycopy(b, 0, r, pos, b.length); pos += b.length; + System.arraycopy(c, 0, r, pos, c.length); pos += c.length; + System.arraycopy(d, 0, r, pos, d.length); + return r; } public static byte[] concatenate(byte[][] arrays) @@ -1117,19 +926,19 @@ public final class Arrays public static int[] concatenate(int[] a, int[] b) { - if (a == null) + if (null == a) { - return clone(b); + return b.clone(); } - if (b == null) + if (null == b) { - return clone(a); + return a.clone(); } - int[] c = new int[a.length + b.length]; - System.arraycopy(a, 0, c, 0, a.length); - System.arraycopy(b, 0, c, a.length, b.length); - return c; + int[] r = new int[a.length + b.length]; + System.arraycopy(a, 0, r, 0, a.length); + System.arraycopy(b, 0, r, a.length, b.length); + return r; } public static byte[] prepend(byte[] a, byte b) @@ -1257,16 +1066,38 @@ public final class Arrays /** * Fill input array by zeros * - * @param array input array + * @param data input array */ - public static void clear(byte[] array) + public static void clear(byte[] data) { - if (array != null) + if (null != data) { - for (int i = 0; i < array.length; i++) + java.util.Arrays.fill(data, (byte)0x00); + } + } + + public static void clear(int[] data) + { + if (null != data) + { + java.util.Arrays.fill(data, 0); + } + } + + public static boolean isNullOrContainsNull(Object[] array) + { + if (null == array) + { + return true; + } + int count = array.length; + for (int i = 0; i < count; ++i) + { + if (null == array[i]) { - array[i] = 0; + return true; } } + return false; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/BigIntegers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/BigIntegers.java index 1fd4ece5a..33e7e5d91 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/BigIntegers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/BigIntegers.java @@ -8,8 +8,13 @@ import java.security.SecureRandom; */ public final class BigIntegers { + public static final BigInteger ZERO = BigInteger.valueOf(0); + public static final BigInteger ONE = BigInteger.valueOf(1); + + private static final BigInteger TWO = BigInteger.valueOf(2); + private static final BigInteger THREE = BigInteger.valueOf(3); + private static final int MAX_ITERATIONS = 1000; - private static final BigInteger ZERO = BigInteger.valueOf(0); /** * Return the passed in value as an unsigned byte array. @@ -92,7 +97,7 @@ public final class BigIntegers for (int i = 0; i < MAX_ITERATIONS; ++i) { - BigInteger x = new BigInteger(max.bitLength(), random); + BigInteger x = createRandomBigInteger(max.bitLength(), random); if (x.compareTo(min) >= 0 && x.compareTo(max) <= 0) { return x; @@ -100,7 +105,7 @@ public final class BigIntegers } // fall back to a faster (restricted) method - return new BigInteger(max.subtract(min).bitLength() - 1, random).add(min); + return createRandomBigInteger(max.subtract(min).bitLength() - 1, random).add(min); } public static BigInteger fromUnsignedByteArray(byte[] buf) @@ -118,4 +123,119 @@ public final class BigIntegers } return new BigInteger(1, mag); } + + public static int intValueExact(BigInteger x) + { + // Since Java 1.8 could use BigInteger.intValueExact instead + if (x.bitLength() > 31) + { + throw new ArithmeticException("BigInteger out of int range"); + } + + return x.intValue(); + } + + public static long longValueExact(BigInteger x) + { + // Since Java 1.8 could use BigInteger.longValueExact instead + if (x.bitLength() > 63) + { + throw new ArithmeticException("BigInteger out of long range"); + } + + return x.longValue(); + } + + public static int getUnsignedByteLength(BigInteger n) + { + return (n.bitLength() + 7) / 8; + } + + /** + * Return a positive BigInteger in the range of 0 to 2**bitLength - 1. + * + * @param bitLength maximum bit length for the generated BigInteger. + * @param random a source of randomness. + * @return a positive BigInteger + */ + public static BigInteger createRandomBigInteger(int bitLength, SecureRandom random) + { + return new BigInteger(1, createRandom(bitLength, random)); + } + + // Hexadecimal value of the product of the 131 smallest odd primes from 3 to 743 + private static final BigInteger SMALL_PRIMES_PRODUCT = new BigInteger( + "8138e8a0fcf3a4e84a771d40fd305d7f4aa59306d7251de54d98af8fe95729a1f" + + "73d893fa424cd2edc8636a6c3285e022b0e3866a565ae8108eed8591cd4fe8d2" + + "ce86165a978d719ebf647f362d33fca29cd179fb42401cbaf3df0c614056f9c8" + + "f3cfd51e474afb6bc6974f78db8aba8e9e517fded658591ab7502bd41849462f", + 16); + private static final int MAX_SMALL = BigInteger.valueOf(743).bitLength(); // bitlength of 743 * 743 + + /** + * Return a prime number candidate of the specified bit length. + * + * @param bitLength bit length for the generated BigInteger. + * @param random a source of randomness. + * @return a positive BigInteger of numBits length + */ + public static BigInteger createRandomPrime(int bitLength, int certainty, SecureRandom random) + { + if (bitLength < 2) + { + throw new IllegalArgumentException("bitLength < 2"); + } + + BigInteger rv; + + if (bitLength == 2) + { + return (random.nextInt() < 0) ? TWO : THREE; + } + + do + { + byte[] base = createRandom(bitLength, random); + + int xBits = 8 * base.length - bitLength; + byte lead = (byte)(1 << (7 - xBits)); + + // ensure top and bottom bit set + base[0] |= lead; + base[base.length - 1] |= 0x01; + + rv = new BigInteger(1, base); + if (bitLength > MAX_SMALL) + { + while (!rv.gcd(SMALL_PRIMES_PRODUCT).equals(ONE)) + { + rv = rv.add(TWO); + } + } + } + while (!rv.isProbablePrime(certainty)); + + return rv; + } + + private static byte[] createRandom(int bitLength, SecureRandom random) + throws IllegalArgumentException + { + if (bitLength < 1) + { + throw new IllegalArgumentException("bitLength must be at least 1"); + } + + int nBytes = (bitLength + 7) / 8; + + byte[] rv = new byte[nBytes]; + + random.nextBytes(rv); + + // strip off any excess bits in the MSB + int xBits = 8 * nBytes - bitLength; + rv[0] &= (byte)(255 >>> xBits); + + return rv; + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Fingerprint.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Fingerprint.java index 22cb2a5ab..39e6b3d56 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Fingerprint.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Fingerprint.java @@ -1,7 +1,11 @@ package com.fr.third.org.bouncycastle.util; import com.fr.third.org.bouncycastle.crypto.digests.SHA512tDigest; +import com.fr.third.org.bouncycastle.crypto.digests.SHAKEDigest; +/** + * Basic 20 byte finger print class. + */ public class Fingerprint { private static char[] encodingTable = @@ -12,9 +16,45 @@ public class Fingerprint private final byte[] fingerprint; + /** + * Base constructor - use SHAKE-256 (160 bits). This is the recommended one as it is also + * produced by the FIPS API. + * + * @param source original data to calculate the fingerprint from. + */ public Fingerprint(byte[] source) { - this.fingerprint = calculateFingerprint(source); + this(source, 160); + } + + /** + * Constructor with length - use SHAKE-256 (bitLength bits). This is the recommended one as it is also + * produced by the FIPS API. + * + * @param source original data to calculate the fingerprint from. + */ + public Fingerprint(byte[] source, int bitLength) + { + this.fingerprint = calculateFingerprint(source, bitLength); + } + + /** + * Base constructor - for backwards compatibility. + * + * @param source original data to calculate the fingerprint from. + * @param useSHA512t use the old SHA512/160 calculation. + * @deprecated use the SHAKE only version. + */ + public Fingerprint(byte[] source, boolean useSHA512t) + { + if (useSHA512t) + { + this.fingerprint = calculateFingerprintSHA512_160(source); + } + else + { + this.fingerprint = calculateFingerprint(source); + } } public byte[] getFingerprint() @@ -57,7 +97,53 @@ public class Fingerprint return Arrays.hashCode(fingerprint); } + /** + * Return a byte array containing a calculated fingerprint for the passed in input data. + * This calculation is compatible with the BC FIPS API. + * + * @param input data to base the fingerprint on. + * @return a byte array containing a 160 bit fingerprint. + */ public static byte[] calculateFingerprint(byte[] input) + { + return calculateFingerprint(input, 160); + } + + /** + * Return a byte array containing a calculated fingerprint for the passed in input data. + * This calculation is compatible with the BC FIPS API. + * + * @param input data to base the fingerprint on. + * @param bitLength bit length of finger print to be produced. + * @return a byte array containing a 20 byte fingerprint. + */ + public static byte[] calculateFingerprint(byte[] input, int bitLength) + { + if (bitLength % 8 != 0) + { + throw new IllegalArgumentException("bitLength must be a multiple of 8"); + } + + SHAKEDigest digest = new SHAKEDigest(256); + + digest.update(input, 0, input.length); + + byte[] rv = new byte[bitLength / 8]; + + digest.doFinal(rv, 0, bitLength / 8); + + return rv; + } + + /** + * Return a byte array containing a calculated fingerprint for the passed in input data. + * The fingerprint is based on SHA512/160. + * + * @param input data to base the fingerprint on. + * @return a byte array containing a 20 byte fingerprint. + * @deprecated use the SHAKE based version. + */ + public static byte[] calculateFingerprintSHA512_160(byte[] input) { SHA512tDigest digest = new SHA512tDigest(160); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/IPAddress.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/IPAddress.java index c2b53f80c..b09cc166e 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/IPAddress.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/IPAddress.java @@ -118,7 +118,7 @@ public class IPAddress * * @param address the IP address as a String. * - * @return true if a valid IPv4 address, false otherwise + * @return true if a valid IPv6 address, false otherwise */ public static boolean isValidIPv6( String address) diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Integers.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Integers.java index a07801f2d..e59173447 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Integers.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Integers.java @@ -5,6 +5,11 @@ package com.fr.third.org.bouncycastle.util; */ public class Integers { + public static int numberOfLeadingZeros(int i) + { + return Integer.numberOfLeadingZeros(i); + } + public static int rotateLeft(int i, int distance) { return Integer.rotateLeft(i, distance); diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Longs.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Longs.java new file mode 100644 index 000000000..3f71931a6 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Longs.java @@ -0,0 +1,9 @@ +package com.fr.third.org.bouncycastle.util; + +public class Longs +{ + public static Long valueOf(long value) + { + return Long.valueOf(value); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Objects.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Objects.java new file mode 100644 index 000000000..ba58de3b7 --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Objects.java @@ -0,0 +1,14 @@ +package com.fr.third.org.bouncycastle.util; + +public class Objects +{ + public static boolean areEqual(Object a, Object b) + { + return a == b || (null != a && null != b && a.equals(b)); + } + + public static int hashCode(Object obj) + { + return null == obj ? 0 : obj.hashCode(); + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Properties.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Properties.java index 61388ffe8..67624e89d 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Properties.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Properties.java @@ -33,7 +33,7 @@ public class Properties { try { - String p = fetchProperty(propertyName); + String p = getPropertyValue(propertyName); if (p != null) { @@ -104,7 +104,7 @@ public class Properties public static BigInteger asBigInteger(String propertyName) { - String p = fetchProperty(propertyName); + String p = getPropertyValue(propertyName); if (p != null) { @@ -118,7 +118,7 @@ public class Properties { Set set = new HashSet(); - String p = fetchProperty(propertyName); + String p = getPropertyValue(propertyName); if (p != null) { @@ -132,7 +132,7 @@ public class Properties return Collections.unmodifiableSet(set); } - private static String fetchProperty(final String propertyName) + public static String getPropertyValue(final String propertyName) { return (String)AccessController.doPrivileged(new PrivilegedAction() { diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Strings.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Strings.java index 00ced9158..7d31bc321 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Strings.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/Strings.java @@ -8,6 +8,8 @@ import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Vector; +import com.fr.third.org.bouncycastle.util.encoders.UTF8; + /** * String utilities. */ @@ -17,105 +19,41 @@ public final class Strings static { - try - { - LINE_SEPARATOR = AccessController.doPrivileged(new PrivilegedAction() - { - public String run() - { - // the easy way - return System.getProperty("line.separator"); - } - }); - - } - catch (Exception e) - { - try - { - // the harder way - LINE_SEPARATOR = String.format("%n"); - } - catch (Exception ef) - { - LINE_SEPARATOR = "\n"; // we're desperate use this... - } - } - } - - public static String fromUTF8ByteArray(byte[] bytes) - { - int i = 0; - int length = 0; - - while (i < bytes.length) + try { - length++; - if ((bytes[i] & 0xf0) == 0xf0) - { - // surrogate pair - length++; - i += 4; - } - else if ((bytes[i] & 0xe0) == 0xe0) + LINE_SEPARATOR = AccessController.doPrivileged(new PrivilegedAction() { - i += 3; - } - else if ((bytes[i] & 0xc0) == 0xc0) - { - i += 2; - } - else - { - i += 1; - } - } - - char[] cs = new char[length]; - - i = 0; - length = 0; + public String run() + { + // the easy way + return System.getProperty("line.separator"); + } + }); - while (i < bytes.length) + } + catch (Exception e) { - char ch; - - if ((bytes[i] & 0xf0) == 0xf0) - { - int codePoint = ((bytes[i] & 0x03) << 18) | ((bytes[i + 1] & 0x3F) << 12) | ((bytes[i + 2] & 0x3F) << 6) | (bytes[i + 3] & 0x3F); - int U = codePoint - 0x10000; - char W1 = (char)(0xD800 | (U >> 10)); - char W2 = (char)(0xDC00 | (U & 0x3FF)); - cs[length++] = W1; - ch = W2; - i += 4; - } - else if ((bytes[i] & 0xe0) == 0xe0) + try { - ch = (char)(((bytes[i] & 0x0f) << 12) - | ((bytes[i + 1] & 0x3f) << 6) | (bytes[i + 2] & 0x3f)); - i += 3; + // the harder way + LINE_SEPARATOR = String.format("%n"); } - else if ((bytes[i] & 0xd0) == 0xd0) - { - ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f)); - i += 2; - } - else if ((bytes[i] & 0xc0) == 0xc0) - { - ch = (char)(((bytes[i] & 0x1f) << 6) | (bytes[i + 1] & 0x3f)); - i += 2; - } - else + catch (Exception ef) { - ch = (char)(bytes[i] & 0xff); - i += 1; + LINE_SEPARATOR = "\n"; // we're desperate use this... } - - cs[length++] = ch; } + } - return new String(cs); + public static String fromUTF8ByteArray(byte[] bytes) + { + char[] chars = new char[bytes.length]; + int len = UTF8.transcodeToUTF16(bytes, chars); + if (len < 0) + { + throw new IllegalArgumentException("Invalid UTF-8 input"); + } + return new String(chars, 0, len); } public static byte[] toUTF8ByteArray(String string) @@ -263,6 +201,7 @@ public final class Strings return bytes; } + public static byte[] toByteArray(String string) { byte[] bytes = new byte[string.length()]; @@ -401,4 +340,6 @@ public final class Strings return strs; } } + + } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/Hex.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/Hex.java index d82f628a3..e8db6aa01 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/Hex.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/Hex.java @@ -11,8 +11,8 @@ import com.fr.third.org.bouncycastle.util.Strings; */ public class Hex { - private static final Encoder encoder = new HexEncoder(); - + private static final HexEncoder encoder = new HexEncoder(); + public static String toHexString( byte[] data) { @@ -38,7 +38,7 @@ public class Hex { return encode(data, 0, data.length); } - + /** * encode the input data producing a Hex encoded byte array. * @@ -50,7 +50,7 @@ public class Hex int length) { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - + try { encoder.encode(data, off, length, bOut); @@ -59,7 +59,7 @@ public class Hex { throw new EncoderException("exception encoding Hex string: " + e.getMessage(), e); } - + return bOut.toByteArray(); } @@ -75,7 +75,7 @@ public class Hex { return encoder.encode(data, 0, data.length, out); } - + /** * Hex encode the byte data writing it to the given output stream. * @@ -90,7 +90,7 @@ public class Hex { return encoder.encode(data, off, length, out); } - + /** * decode the Hex encoded input data. It is assumed the input data is valid. * @@ -100,7 +100,7 @@ public class Hex byte[] data) { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - + try { encoder.decode(data, 0, data.length, bOut); @@ -112,7 +112,7 @@ public class Hex return bOut.toByteArray(); } - + /** * decode the Hex encoded String data - whitespace will be ignored. * @@ -122,7 +122,7 @@ public class Hex String data) { ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - + try { encoder.decode(data, bOut); @@ -131,10 +131,10 @@ public class Hex { throw new DecoderException("exception decoding Hex string: " + e.getMessage(), e); } - + return bOut.toByteArray(); } - + /** * decode the Hex encoded String data writing it to the given output stream, * whitespace characters will be ignored. @@ -148,4 +148,40 @@ public class Hex { return encoder.decode(data, out); } + + /** + * Decode the hexadecimal-encoded string strictly i.e. any non-hexadecimal characters will be + * considered an error. + * + * @return a byte array representing the decoded data. + */ + public static byte[] decodeStrict(String str) + { + try + { + return encoder.decodeStrict(str, 0, str.length()); + } + catch (Exception e) + { + throw new DecoderException("exception decoding Hex string: " + e.getMessage(), e); + } + } + + /** + * Decode the hexadecimal-encoded string strictly i.e. any non-hexadecimal characters will be + * considered an error. + * + * @return a byte array representing the decoded data. + */ + public static byte[] decodeStrict(String str, int off, int len) + { + try + { + return encoder.decodeStrict(str, off, len); + } + catch (Exception e) + { + throw new DecoderException("exception decoding Hex string: " + e.getMessage(), e); + } + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/HexEncoder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/HexEncoder.java index 16842d54a..5dda92dff 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/HexEncoder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/HexEncoder.java @@ -31,7 +31,7 @@ public class HexEncoder { decodingTable[encodingTable[i]] = (byte)i; } - + decodingTable['A'] = decodingTable['a']; decodingTable['B'] = decodingTable['b']; decodingTable['C'] = decodingTable['c']; @@ -39,12 +39,12 @@ public class HexEncoder decodingTable['E'] = decodingTable['e']; decodingTable['F'] = decodingTable['f']; } - + public HexEncoder() { initialiseDecodingTable(); } - + /** * encode the input data producing a Hex output stream. * @@ -89,19 +89,19 @@ public class HexEncoder { byte b1, b2; int outLen = 0; - + int end = off + length; - + while (end > off) { if (!ignore((char)data[end - 1])) { break; } - + end--; } - + int i = off; while (i < end) { @@ -109,14 +109,14 @@ public class HexEncoder { i++; } - + b1 = decodingTable[data[i++]]; - + while (i < end && ignore((char)data[i])) { i++; } - + b2 = decodingTable[data[i++]]; if ((b1 | b2) < 0) @@ -125,13 +125,13 @@ public class HexEncoder } out.write((b1 << 4) | b2); - + outLen++; } return outLen; } - + /** * decode the Hex encoded String data writing it to the given output stream, * whitespace characters will be ignored. @@ -145,19 +145,19 @@ public class HexEncoder { byte b1, b2; int length = 0; - + int end = data.length(); - + while (end > 0) { if (!ignore(data.charAt(end - 1))) { break; } - + end--; } - + int i = 0; while (i < end) { @@ -165,14 +165,14 @@ public class HexEncoder { i++; } - + b1 = decodingTable[data.charAt(i++)]; - + while (i < end && ignore(data.charAt(i))) { i++; } - + b2 = decodingTable[data.charAt(i++)]; if ((b1 | b2) < 0) @@ -181,10 +181,45 @@ public class HexEncoder } out.write((b1 << 4) | b2); - + length++; } return length; } + + byte[] decodeStrict(String str, int off, int len) throws IOException + { + if (null == str) + { + throw new NullPointerException("'str' cannot be null"); + } + if (off < 0 || len < 0 || off > (str.length() - len)) + { + throw new IndexOutOfBoundsException("invalid offset and/or length specified"); + } + if (0 != (len & 1)) + { + throw new IOException("a hexadecimal encoding must have an even number of characters"); + } + + int resultLen = len >>> 1; + byte[] result = new byte[resultLen]; + + int strPos = off; + for (int i = 0; i < resultLen; ++i) + { + byte b1 = decodingTable[str.charAt(strPos++)]; + byte b2 = decodingTable[str.charAt(strPos++)]; + + int n = (b1 << 4) | b2; + if (n < 0) + { + throw new IOException("invalid characters encountered in Hex string"); + } + + result[i] = (byte)n; + } + return result; + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/UTF8.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/UTF8.java new file mode 100644 index 000000000..7a30f59fb --- /dev/null +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/encoders/UTF8.java @@ -0,0 +1,156 @@ +package com.fr.third.org.bouncycastle.util.encoders; + +/** + * Utilities for working with UTF-8 encodings. + * + * Decoding of UTF-8 is based on a presentation by Bob Steagall at CppCon2018 (see + * https://github.com/BobSteagall/CppCon2018). It uses a Deterministic Finite Automaton (DFA) to + * recognize and decode multi-byte code points. + */ +public class UTF8 +{ + // Constants for the categorization of code units + private static final byte C_ILL = 0; //- C0..C1, F5..FF ILLEGAL octets that should never appear in a UTF-8 sequence + private static final byte C_CR1 = 1; //- 80..8F Continuation range 1 + private static final byte C_CR2 = 2; //- 90..9F Continuation range 2 + private static final byte C_CR3 = 3; //- A0..BF Continuation range 3 + private static final byte C_L2A = 4; //- C2..DF Leading byte range A / 2-byte sequence + private static final byte C_L3A = 5; //- E0 Leading byte range A / 3-byte sequence + private static final byte C_L3B = 6; //- E1..EC, EE..EF Leading byte range B / 3-byte sequence + private static final byte C_L3C = 7; //- ED Leading byte range C / 3-byte sequence + private static final byte C_L4A = 8; //- F0 Leading byte range A / 4-byte sequence + private static final byte C_L4B = 9; //- F1..F3 Leading byte range B / 4-byte sequence + private static final byte C_L4C = 10; //- F4 Leading byte range C / 4-byte sequence +// private static final byte C_ASC = 11; //- 00..7F ASCII leading byte range + + // Constants for the states of a DFA + private static final byte S_ERR = -2; //- Error state + private static final byte S_END = -1; //- End (or Accept) state + private static final byte S_CS1 = 0x00; //- Continuation state 1 + private static final byte S_CS2 = 0x10; //- Continuation state 2 + private static final byte S_CS3 = 0x20; //- Continuation state 3 + private static final byte S_P3A = 0x30; //- Partial 3-byte sequence state A + private static final byte S_P3B = 0x40; //- Partial 3-byte sequence state B + private static final byte S_P4A = 0x50; //- Partial 4-byte sequence state A + private static final byte S_P4B = 0x60; //- Partial 4-byte sequence state B + + private static final short[] firstUnitTable = new short[128]; + private static final byte[] transitionTable = new byte[S_P4B + 16]; + + private static void fill(byte[] table, int first, int last, byte b) + { + for (int i = first; i <= last; ++i) + { + table[i] = b; + } + } + + static + { + byte[] categories = new byte[128]; + fill(categories, 0x00, 0x0F, C_CR1); + fill(categories, 0x10, 0x1F, C_CR2); + fill(categories, 0x20, 0x3F, C_CR3); + fill(categories, 0x40, 0x41, C_ILL); + fill(categories, 0x42, 0x5F, C_L2A); + fill(categories, 0x60, 0x60, C_L3A); + fill(categories, 0x61, 0x6C, C_L3B); + fill(categories, 0x6D, 0x6D, C_L3C); + fill(categories, 0x6E, 0x6F, C_L3B); + fill(categories, 0x70, 0x70, C_L4A); + fill(categories, 0x71, 0x73, C_L4B); + fill(categories, 0x74, 0x74, C_L4C); + fill(categories, 0x75, 0x7F, C_ILL); + + fill(transitionTable, 0, transitionTable.length - 1, S_ERR); + fill(transitionTable, S_CS1 + 0x8, S_CS1 + 0xB, S_END); + fill(transitionTable, S_CS2 + 0x8, S_CS2 + 0xB, S_CS1); + fill(transitionTable, S_CS3 + 0x8, S_CS3 + 0xB, S_CS2); + fill(transitionTable, S_P3A + 0xA, S_P3A + 0xB, S_CS1); + fill(transitionTable, S_P3B + 0x8, S_P3B + 0x9, S_CS1); + fill(transitionTable, S_P4A + 0x9, S_P4A + 0xB, S_CS2); + fill(transitionTable, S_P4B + 0x8, S_P4B + 0x8, S_CS2); + + byte[] firstUnitMasks = { 0x00, 0x00, 0x00, 0x00, 0x1F, 0x0F, 0x0F, 0x0F, 0x07, 0x07, 0x07 }; + byte[] firstUnitTransitions = { S_ERR, S_ERR, S_ERR, S_ERR, S_CS1, S_P3A, S_CS2, S_P3B, S_P4A, S_CS3, S_P4B }; + + for (int i = 0x00; i < 0x80; ++i) + { + byte category = categories[i]; + + int codePoint = i & firstUnitMasks[category]; + byte state = firstUnitTransitions[category]; + + firstUnitTable[i] = (short)((codePoint << 8) | state); + } + } + + /** + * Transcode a UTF-8 encoding into a UTF-16 representation. In the general case the output + * {@code utf16} array should be at least as long as the input {@code utf8} one to handle + * arbitrary inputs. The number of output UTF-16 code units is returned, or -1 if any errors are + * encountered (in which case an arbitrary amount of data may have been written into the output + * array). Errors that will be detected are malformed UTF-8, including incomplete, truncated or + * "overlong" encodings, and unmappable code points. In particular, no unmatched surrogates will + * be produced. An error will also result if {@code utf16} is found to be too small to store the + * complete output. + * + * @param utf8 + * A non-null array containing a well-formed UTF-8 encoding. + * @param utf16 + * A non-null array, at least as long as the {@code utf8} array in order to ensure + * the output will fit. + * @return The number of UTF-16 code units written to {@code utf16} (beginning from index 0), or + * else -1 if the input was either malformed or encoded any unmappable characters, or if + * the {@code utf16} is too small. + */ + public static int transcodeToUTF16(byte[] utf8, char[] utf16) + { + int i = 0, j = 0; + + while (i < utf8.length) + { + byte codeUnit = utf8[i++]; + if (codeUnit >= 0) + { + if (j >= utf16.length) { return -1; } + + utf16[j++] = (char)codeUnit; + continue; + } + + short first = firstUnitTable[codeUnit & 0x7F]; + int codePoint = first >>> 8; + byte state = (byte)first; + + while (state >= 0) + { + if (i >= utf8.length) { return -1; } + + codeUnit = utf8[i++]; + codePoint = (codePoint << 6) | (codeUnit & 0x3F); + state = transitionTable[state + ((codeUnit & 0xFF) >>> 4)]; + } + + if (state == S_ERR) { return -1; } + + if (codePoint <= 0xFFFF) + { + if (j >= utf16.length) { return -1; } + + // Code points from U+D800 to U+DFFF are caught by the DFA + utf16[j++] = (char)codePoint; + } + else + { + if (j >= utf16.length - 1) { return -1; } + + // Code points above U+10FFFF are caught by the DFA + utf16[j++] = (char)(0xD7C0 + (codePoint >>> 10)); + utf16[j++] = (char)(0xDC00 | (codePoint & 0x3FF)); + } + } + + return j; + } +} diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/io/pem/PemReader.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/io/pem/PemReader.java index 2f83413be..98d6a10fb 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/io/pem/PemReader.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/io/pem/PemReader.java @@ -42,10 +42,11 @@ public class PemReader { line = line.substring(BEGIN.length()); int index = line.indexOf('-'); - String type = line.substring(0, index); - if (index > 0) + if (index > 0 && line.endsWith("-----") && (line.length() - index) == 5) { + String type = line.substring(0, index); + return loadObject(type); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/test/SimpleTest.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/test/SimpleTest.java index c206580dc..bd2b9bd25 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/test/SimpleTest.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/util/test/SimpleTest.java @@ -1,6 +1,8 @@ package com.fr.third.org.bouncycastle.util.test; import java.io.PrintStream; +import java.util.Enumeration; +import java.util.Vector; import com.fr.third.org.bouncycastle.util.Arrays; @@ -183,25 +185,65 @@ public abstract class SimpleTest } } - protected static void runTest( - Test test) + public abstract void performTest() + throws Exception; + + public static void runTest(Test test) { runTest(test, System.out); } - protected static void runTest( - Test test, - PrintStream out) + public static void runTest(Test test, PrintStream out) { TestResult result = test.perform(); - out.println(result.toString()); if (result.getException() != null) { result.getException().printStackTrace(out); } + + out.println(result); } - public abstract void performTest() - throws Exception; + public static void runTests(Test[] tests) + { + runTests(tests, System.out); + } + + public static void runTests(Test[] tests, PrintStream out) + { + Vector failures = new Vector(); + for (int i = 0; i != tests.length; i++) + { + TestResult result = tests[i].perform(); + if (!result.isSuccessful()) + { + failures.addElement(result); + } + + if (result.getException() != null) + { + result.getException().printStackTrace(out); + } + + out.println(result); + } + + out.println("-----"); + if (failures.isEmpty()) + { + out.println("All tests successful."); + } + else + { + out.println("Completed with " + failures.size() + " FAILURES:"); + + Enumeration e = failures.elements(); + while (e.hasMoreElements()) + { + System.out.println("=> " + (TestResult)e.nextElement()); + } + } + + } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/AttributeCertificateHolder.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/AttributeCertificateHolder.java index 5c4a96226..5afd4fc87 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/AttributeCertificateHolder.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/AttributeCertificateHolder.java @@ -148,8 +148,7 @@ public class AttributeCertificateHolder { if (holder.getObjectDigestInfo() != null) { - return holder.getObjectDigestInfo().getDigestedObjectType() - .getValue().intValue(); + return holder.getObjectDigestInfo().getDigestedObjectType().intValueExact(); } return -1; } @@ -338,7 +337,7 @@ public class AttributeCertificateHolder { if (holder.getBaseCertificateID() != null) { - return holder.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber()) + return holder.getBaseCertificateID().getSerial().hasValue(x509Cert.getSerialNumber()) && matchesDN(PrincipalUtil.getIssuerX509Principal(x509Cert), holder.getBaseCertificateID().getIssuer()); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/AttributeCertificateIssuer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/AttributeCertificateIssuer.java index 620f13620..150826724 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/AttributeCertificateIssuer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/AttributeCertificateIssuer.java @@ -152,7 +152,7 @@ public class AttributeCertificateIssuer V2Form issuer = (V2Form)form; if (issuer.getBaseCertificateID() != null) { - return issuer.getBaseCertificateID().getSerial().getValue().equals(x509Cert.getSerialNumber()) + return issuer.getBaseCertificateID().getSerial().hasValue(x509Cert.getSerialNumber()) && matchesDN(x509Cert.getIssuerX500Principal(), issuer.getBaseCertificateID().getIssuer()); } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/CertPathValidatorUtilities.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/CertPathValidatorUtilities.java index dc47775c2..4d1187367 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/CertPathValidatorUtilities.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/CertPathValidatorUtilities.java @@ -226,7 +226,7 @@ class CertPathValidatorUtilities } ByteArrayOutputStream bOut = new ByteArrayOutputStream(); - ASN1OutputStream aOut = new ASN1OutputStream(bOut); + ASN1OutputStream aOut = ASN1OutputStream.create(bOut); Enumeration e = qualifiers.getObjects(); @@ -733,26 +733,19 @@ class CertPathValidatorUtilities } } - // for reason keyCompromise, caCompromise, aACompromise or - // unspecified + int reasonCodeValue = (null == reasonCode) + ? CRLReason.unspecified + : reasonCode.intValueExact(); + + // for reason keyCompromise, caCompromise, aACompromise or unspecified if (!(validDate.getTime() < crl_entry.getRevocationDate().getTime()) - || reasonCode == null - || reasonCode.getValue().intValue() == 0 - || reasonCode.getValue().intValue() == 1 - || reasonCode.getValue().intValue() == 2 - || reasonCode.getValue().intValue() == 8) + || reasonCodeValue == CRLReason.unspecified + || reasonCodeValue == CRLReason.keyCompromise + || reasonCodeValue == CRLReason.cACompromise + || reasonCodeValue == CRLReason.aACompromise) { - - // (i) or (j) (1) - if (reasonCode != null) - { - certStatus.setCertStatus(reasonCode.getValue().intValue()); - } - // (i) or (j) (2) - else - { - certStatus.setCertStatus(CRLReason.unspecified); - } + // (i) or (j) + certStatus.setCertStatus(reasonCodeValue); certStatus.setRevocationDate(crl_entry.getRevocationDate()); } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/PKIXCertPathReviewer.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/PKIXCertPathReviewer.java index d960f40ec..ad8cbbfe2 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/PKIXCertPathReviewer.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/PKIXCertPathReviewer.java @@ -1545,14 +1545,14 @@ public class PKIXCertPathReviewer extends CertPathValidatorUtilities switch (constraint.getTagNo()) { case 0: - tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); + tmpInt = ASN1Integer.getInstance(constraint, false).intValueExact(); if (tmpInt < explicitPolicy) { explicitPolicy = tmpInt; } break; case 1: - tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); + tmpInt = ASN1Integer.getInstance(constraint, false).intValueExact(); if (tmpInt < policyMapping) { policyMapping = tmpInt; @@ -1578,7 +1578,7 @@ public class PKIXCertPathReviewer extends CertPathValidatorUtilities if (iap != null) { - int _inhibitAnyPolicy = iap.getValue().intValue(); + int _inhibitAnyPolicy = iap.intValueExact(); if (_inhibitAnyPolicy < inhibitAnyPolicy) { @@ -1625,7 +1625,7 @@ public class PKIXCertPathReviewer extends CertPathValidatorUtilities switch (constraint.getTagNo()) { case 0: - int tmpInt = ASN1Integer.getInstance(constraint, false).getValue().intValue(); + int tmpInt = ASN1Integer.getInstance(constraint, false).intValueExact(); if (tmpInt == 0) { explicitPolicy = 0; @@ -2209,7 +2209,7 @@ public class PKIXCertPathReviewer extends CertPathValidatorUtilities } if (reasonCode != null) { - reason = crlReasons[reasonCode.getValue().intValue()]; + reason = crlReasons[reasonCode.intValueExact()]; } } diff --git a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/X509V2AttributeCertificate.java b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/X509V2AttributeCertificate.java index 766970a31..8f7171da1 100644 --- a/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/X509V2AttributeCertificate.java +++ b/fine-bouncycastle/src/main/java/com/fr/third/org/bouncycastle/x509/X509V2AttributeCertificate.java @@ -93,7 +93,7 @@ public class X509V2AttributeCertificate public int getVersion() { - return cert.getAcinfo().getVersion().getValue().intValue() + 1; + return cert.getAcinfo().getVersion().intValueExact() + 1; } public BigInteger getSerialNumber()